14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 //#define DND_DEBUG TRUE
27
28 #import "CDropTarget.h"
29 #import "AWTView.h"
30
31 #import "sun_lwawt_macosx_CDropTarget.h"
32 #import "java_awt_dnd_DnDConstants.h"
33
34 #import <JavaNativeFoundation/JavaNativeFoundation.h>
35 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
36 #include <objc/objc-runtime.h>
37
38
39 #import "CDragSource.h"
40 #import "CDataTransferer.h"
41 #import "DnDUtilities.h"
42 #import "ThreadUtilities.h"
43
44
45 static NSInteger sDraggingSequenceNumber = -1;
46 static NSDragOperation sDragOperation;
47 static NSDragOperation sUpdateOperation;
48 static jint sJavaDropOperation;
49 static NSPoint sDraggingLocation;
50 static BOOL sDraggingExited;
51 static BOOL sDraggingError;
52
53 static NSUInteger sPasteboardItemsCount = 0;
54 static NSArray* sPasteboardTypes = nil;
55 static NSArray* sPasteboardData = nil;
56 static jlongArray sDraggingFormats = nil;
57
58 static CDropTarget* sCurrentDropTarget;
59
60 extern JNFClassInfo jc_CDropTargetContextPeer;
61
62 @implementation CDropTarget
63
64 + (CDropTarget *) currentDropTarget {
65 return sCurrentDropTarget;
66 }
67
68 - (id)init:(jobject)jdropTarget component:(jobject)jcomponent control:(id)control
69 {
70 self = [super init];
71 DLog2(@"[CDropTarget init]: %@\n", self);
72
73 fView = nil;
74 fComponent = nil;
75 fDropTarget = nil;
76 fDropTargetContextPeer = nil;
77
78
79 if (control != nil) {
80 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
81 fComponent = JNFNewGlobalRef(env, jcomponent);
82 fDropTarget = JNFNewGlobalRef(env, jdropTarget);
83
84 fView = [((AWTView *) control) retain];
85 [fView setDropTarget:self];
86
87
88 } else {
89 // This would be an error.
90 [self release];
91 self = nil;
92 }
93 return self;
94 }
95
96 // When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel
97 // (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget,
98 // to let it know it's been set up now.
99 - (void)controlModelControlValid
100 {
101 // 9-30-02 Note: [Radar 3065621]
102 // List all known pasteboard types here (see AppKit's NSPasteboard.h)
125
126 // Enable dragging events over this object:
127 [fView registerForDraggedTypes:dataTypes];
128
129 [dataTypes release];
130 }
131
132 - (void)releaseDraggingData
133 {
134 DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self);
135
136 // Release any old pasteboard types, data and properties:
137 [sPasteboardTypes release];
138 sPasteboardTypes = nil;
139
140 [sPasteboardData release];
141 sPasteboardData = nil;
142
143 if (sDraggingFormats != NULL) {
144 JNIEnv *env = [ThreadUtilities getJNIEnv];
145 JNFDeleteGlobalRef(env, sDraggingFormats);
146 sDraggingFormats = NULL;
147 }
148
149 sPasteboardItemsCount = 0;
150 sDraggingSequenceNumber = -1;
151 }
152
153 - (void)removeFromView:(JNIEnv *)env
154 {
155 DLog2(@"[CDropTarget removeFromView]: %@\n", self);
156
157 // Remove this dragging destination from the view:
158 [((AWTView *) fView) setDropTarget:nil];
159
160 // Clean up JNI refs
161 if (fComponent != NULL) {
162 JNFDeleteGlobalRef(env, fComponent);
163 fComponent = NULL;
164 }
165 if (fDropTarget != NULL) {
166 JNFDeleteGlobalRef(env, fDropTarget);
167 fDropTarget = NULL;
168 }
169 if (fDropTargetContextPeer != NULL) {
170 JNFDeleteGlobalRef(env, fDropTargetContextPeer);
171 fDropTargetContextPeer = NULL;
172 }
173
174 [self release];
175 }
176
177 - (void)dealloc
178 {
179 DLog2(@"[CDropTarget dealloc]: %@\n", self);
180
181 if(sCurrentDropTarget == self) {
182 sCurrentDropTarget = nil;
183 }
184
185 [fView release];
186 fView = nil;
187
188 [super dealloc];
189 }
190
216 }
217
218 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
219 {
220 DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
221 JNIEnv* env = [ThreadUtilities getJNIEnv];
222
223 // Release any old pasteboard data:
224 [self releaseDraggingData];
225
226 NSPasteboard* pb = [sender draggingPasteboard];
227 sPasteboardTypes = [[pb types] retain];
228 sPasteboardItemsCount = [sPasteboardTypes count];
229 if (sPasteboardItemsCount == 0)
230 return FALSE;
231
232 jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
233 if (formats == nil)
234 return FALSE;
235
236 sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats);
237 (*env)->DeleteLocalRef(env, formats);
238 if (sDraggingFormats == nil)
239 return FALSE;
240
241 jboolean isCopy;
242 jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
243 if (jformats == nil) {
244 return FALSE;
245 }
246
247 // Copy all data formats and properties. In case of properties, if they are nil, we need to use
248 // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
249 DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
250 NSUInteger i;
251 for (i = 0; i < sPasteboardItemsCount; i++) {
252 NSString* pbType = [sPasteboardTypes objectAtIndex:i];
253 DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
254
255 // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
256 // They're often copies of their flavor's data and copying them for all available pasteboard flavors
333 if ([sPasteboardTypes containsObject:pbType]) {
334 NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
335 data = [sPasteboardData objectAtIndex:dataIndex];
336
337 if ((id) data == [NSNull null])
338 data = nil;
339
340 // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
341 else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
342 data = [self getDraggingDataForURL:data];
343 }
344
345 // Get NS data:
346 char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
347 NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
348
349 // Create a global byte array:
350 jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
351 if (lbyteArray == nil)
352 return nil;
353 jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray);
354 (*env)->DeleteLocalRef(env, lbyteArray);
355 if (gbyteArray == nil)
356 return nil;
357
358 // Get byte array elements:
359 jboolean isCopy;
360 jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
361 if (jbytes == nil)
362 return nil;
363
364 // Copy data to byte array and release elements:
365 memcpy(jbytes, dataBytes, dataLength);
366 (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
367
368 // In case of an error make sure to return nil:
369 if ((*env)->ExceptionOccurred(env)) {
370 (*env)->ExceptionDescribe(env);
371 gbyteArray = nil;
372 }
373
436 DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
437
438 sCurrentDropTarget = self;
439
440 JNIEnv* env = [ThreadUtilities getJNIEnv];
441 NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
442
443 // Set the initial drag operation return value:
444 NSDragOperation dragOp = NSDragOperationNone;
445 sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
446
447 // We could probably special-case some stuff if drag and drop objects match:
448 //if ([sender dragSource] == fView)
449
450 if (draggingSequenceNumber != sDraggingSequenceNumber) {
451 sDraggingSequenceNumber = draggingSequenceNumber;
452 sDraggingError = FALSE;
453
454 // Delete any drop target context peer left over from a previous drag:
455 if (fDropTargetContextPeer != NULL) {
456 JNFDeleteGlobalRef(env, fDropTargetContextPeer);
457 fDropTargetContextPeer = NULL;
458 }
459
460 // Look up the CDropTargetContextPeer class:
461 JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
462 if (sDraggingError == FALSE) {
463 // Create a new drop target context peer:
464 jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod);
465
466 if (dropTargetContextPeer != nil) {
467 fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer);
468 (*env)->DeleteLocalRef(env, dropTargetContextPeer);
469 }
470 }
471
472 // Get dragging types (dragging data is only copied if dropped):
473 if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
474 sDraggingError = TRUE;
475 }
476
477 if (sDraggingError == FALSE) {
478 sDraggingExited = FALSE;
479 sDraggingLocation = [sender draggingLocation];
480 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
481 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
482
483 DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
484
485 ////////// BEGIN Calculate the current drag actions //////////
486 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
487 jint dropAction = actions;
488
489 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
490
491 sJavaDropOperation = dropAction;
492 ////////// END Calculate the current drag actions //////////
493
494 jlongArray formats = sDraggingFormats;
495
496 JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
497 if (sDraggingError == FALSE) {
498 // Double-casting self gets rid of 'different size' compiler warning:
499 // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
500 actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod,
501 fComponent, (jint) javaLocation.x, (jint) javaLocation.y,
502 dropAction, actions, formats, ptr_to_jlong(self));
503 }
504
505 if (sDraggingError == FALSE) {
506 // Initialize drag operation:
507 sDragOperation = NSDragOperationNone;
508
509 // Map Java actions back to NSDragOperation.
510 // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
511 // (as can be the case with lightweight children) we must not return NSDragOperationNone
512 // since that would prevent dropping into any of the contained drop targets.
513 // Unfortunately there is no easy way to test this so we just test actions and override them
514 // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
515 // called right away, taking care of setting the right cursor and snap-back action.
516 dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
517 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
518
519 // Remember the dragOp for no-op'd update messages:
520 sUpdateOperation = dragOp;
521 }
522 }
561 jint dropAction = actions;
562
563 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
564
565 if (sJavaDropOperation != dropAction) {
566 sJavaDropOperation = dropAction;
567 notifyJava = TRUE;
568 }
569 ////////// END Calculate the current drag actions //////////
570
571 jint userAction = dropAction;
572
573 // Should we notify Java things have changed?
574 if (sDraggingError == FALSE && notifyJava) {
575 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
576 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
577 //DLog5(@" : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
578
579 jlongArray formats = sDraggingFormats;
580
581 JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
582 if (sDraggingError == FALSE) {
583 DLog3(@" >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
584 userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
585 }
586
587 if (sDraggingError == FALSE) {
588 dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
589
590 // Remember the dragOp for no-op'd update messages:
591 sUpdateOperation = dragOp;
592 } else {
593 dragOp = NSDragOperationNone;
594 }
595 }
596
597 DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
598
599 return dragOp;
600 }
601
602 - (void)draggingExited:(id<NSDraggingInfo>)sender
603 {
604 DLog2(@"[CDropTarget draggingExited]: %@\n", self);
605
606 sCurrentDropTarget = nil;
607
608 JNIEnv* env = [ThreadUtilities getJNIEnv];
609
610 if (sDraggingExited == FALSE && sDraggingError == FALSE) {
611 JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
612 if (sDraggingError == FALSE) {
613 DLog3(@" - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
614 // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
615 JNFCallVoidMethod(env, fDropTargetContextPeer,
616 handleExitMessageMethod, fComponent, ptr_to_jlong(self));
617 }
618
619 // 5-27-03 Note: [Radar 3270455]
620 // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
621 // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
622 sDraggingExited = TRUE;
623 }
624
625 DLog(@"[CDropTarget draggingExited]: returning.\n");
626 }
627
628 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
629 {
630 DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
631 DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
632
633 return sDraggingError ? NO : YES;
634 }
635
636 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
641
642 JNIEnv* env = [ThreadUtilities getJNIEnv];
643
644 // Now copy dragging data:
645 if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
646 sDraggingError = TRUE;
647
648 if (sDraggingError == FALSE) {
649 sDraggingLocation = [sender draggingLocation];
650 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
651 // The y coordinate that comes in the NSDraggingInfo seems to be reversed - probably
652 // has to do something with the type of view it comes to.
653 // This is the earliest place where we can correct it.
654 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
655
656 jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
657 jint dropAction = sJavaDropOperation;
658
659 jlongArray formats = sDraggingFormats;
660
661 JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
662
663 if (sDraggingError == FALSE) {
664 JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
665 }
666 } else {
667 // 8-19-03 Note: [Radar 3368754]
668 // draggingExited: is not called after a drop - we must do that here ... but only in case
669 // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
670 [self draggingExited:sender];
671 }
672
673 // TODO:BG
674 // [(id)sender _setLastDragDestinationOperation:sDragOperation];
675
676
677 DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
678
679 return !sDraggingError;
680 }
681
682 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender
683 {
684 sCurrentDropTarget = nil;
694
695 DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
696 DLog(@"[CDropTarget draggingEnded]: returning.\n");
697 }
698
699 /******************************** END NSDraggingDestination Interface ********************************/
700
701 @end
702
703
704 /*
705 * Class: sun_lwawt_macosx_CDropTarget
706 * Method: createNativeDropTarget
707 * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
708 */
709 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
710 (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jlong jnativepeer)
711 {
712 CDropTarget* dropTarget = nil;
713
714 JNF_COCOA_ENTER(env);
715 id controlObj = (id) jlong_to_ptr(jnativepeer);
716 dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent control:controlObj];
717 JNF_COCOA_EXIT(env);
718
719 return ptr_to_jlong(dropTarget);
720 }
721
722 /*
723 * Class: sun_lwawt_macosx_CDropTarget
724 * Method: releaseNativeDropTarget
725 * Signature: (J)V
726 */
727 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
728 (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
729 {
730 id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
731
732 JNF_COCOA_ENTER(env);
733 [dropTarget removeFromView:env];
734 JNF_COCOA_EXIT(env);
735 }
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 //#define DND_DEBUG TRUE
27
28 #import "CDropTarget.h"
29 #import "AWTView.h"
30
31 #import "sun_lwawt_macosx_CDropTarget.h"
32 #import "java_awt_dnd_DnDConstants.h"
33
34 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
35 #include <objc/objc-runtime.h>
36
37
38 #import "CDragSource.h"
39 #import "CDataTransferer.h"
40 #import "DnDUtilities.h"
41 #import "ThreadUtilities.h"
42 #import "JNIUtilities.h"
43
44
45 static NSInteger sDraggingSequenceNumber = -1;
46 static NSDragOperation sDragOperation;
47 static NSDragOperation sUpdateOperation;
48 static jint sJavaDropOperation;
49 static NSPoint sDraggingLocation;
50 static BOOL sDraggingExited;
51 static BOOL sDraggingError;
52
53 static NSUInteger sPasteboardItemsCount = 0;
54 static NSArray* sPasteboardTypes = nil;
55 static NSArray* sPasteboardData = nil;
56 static jlongArray sDraggingFormats = nil;
57
58 static CDropTarget* sCurrentDropTarget;
59
60 extern jclass jc_CDropTargetContextPeer;
61 #define GET_DTCP_CLASS() \
62 GET_CLASS(jc_CDropTargetContextPeer, "sun/lwawt/macosx/CDropTargetContextPeer");
63
64 #define GET_DTCP_CLASS_RETURN(ret) \
65 GET_CLASS_RETURN(jc_CDropTargetContextPeer, "sun/lwawt/macosx/CDropTargetContextPeer", ret);
66
67 @implementation CDropTarget
68
69 + (CDropTarget *) currentDropTarget {
70 return sCurrentDropTarget;
71 }
72
73 - (id)init:(jobject)jdropTarget component:(jobject)jcomponent control:(id)control
74 {
75 self = [super init];
76 DLog2(@"[CDropTarget init]: %@\n", self);
77
78 fView = nil;
79 fComponent = nil;
80 fDropTarget = nil;
81 fDropTargetContextPeer = nil;
82
83
84 if (control != nil) {
85 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
86 fComponent = (*env)->NewGlobalRef(env, jcomponent);
87 fDropTarget = (*env)->NewGlobalRef(env, jdropTarget);
88
89 fView = [((AWTView *) control) retain];
90 [fView setDropTarget:self];
91
92
93 } else {
94 // This would be an error.
95 [self release];
96 self = nil;
97 }
98 return self;
99 }
100
101 // When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel
102 // (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget,
103 // to let it know it's been set up now.
104 - (void)controlModelControlValid
105 {
106 // 9-30-02 Note: [Radar 3065621]
107 // List all known pasteboard types here (see AppKit's NSPasteboard.h)
130
131 // Enable dragging events over this object:
132 [fView registerForDraggedTypes:dataTypes];
133
134 [dataTypes release];
135 }
136
137 - (void)releaseDraggingData
138 {
139 DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self);
140
141 // Release any old pasteboard types, data and properties:
142 [sPasteboardTypes release];
143 sPasteboardTypes = nil;
144
145 [sPasteboardData release];
146 sPasteboardData = nil;
147
148 if (sDraggingFormats != NULL) {
149 JNIEnv *env = [ThreadUtilities getJNIEnv];
150 (*env)->DeleteGlobalRef(env, sDraggingFormats);
151 sDraggingFormats = NULL;
152 }
153
154 sPasteboardItemsCount = 0;
155 sDraggingSequenceNumber = -1;
156 }
157
158 - (void)removeFromView:(JNIEnv *)env
159 {
160 DLog2(@"[CDropTarget removeFromView]: %@\n", self);
161
162 // Remove this dragging destination from the view:
163 [((AWTView *) fView) setDropTarget:nil];
164
165 // Clean up JNI refs
166 if (fComponent != NULL) {
167 (*env)->DeleteGlobalRef(env, fComponent);
168 fComponent = NULL;
169 }
170 if (fDropTarget != NULL) {
171 (*env)->DeleteGlobalRef(env, fDropTarget);
172 fDropTarget = NULL;
173 }
174 if (fDropTargetContextPeer != NULL) {
175 (*env)->DeleteGlobalRef(env, fDropTargetContextPeer);
176 fDropTargetContextPeer = NULL;
177 }
178
179 [self release];
180 }
181
182 - (void)dealloc
183 {
184 DLog2(@"[CDropTarget dealloc]: %@\n", self);
185
186 if(sCurrentDropTarget == self) {
187 sCurrentDropTarget = nil;
188 }
189
190 [fView release];
191 fView = nil;
192
193 [super dealloc];
194 }
195
221 }
222
223 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
224 {
225 DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
226 JNIEnv* env = [ThreadUtilities getJNIEnv];
227
228 // Release any old pasteboard data:
229 [self releaseDraggingData];
230
231 NSPasteboard* pb = [sender draggingPasteboard];
232 sPasteboardTypes = [[pb types] retain];
233 sPasteboardItemsCount = [sPasteboardTypes count];
234 if (sPasteboardItemsCount == 0)
235 return FALSE;
236
237 jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
238 if (formats == nil)
239 return FALSE;
240
241 sDraggingFormats = (jlongArray) (*env)->NewGlobalRef(env, formats);
242 (*env)->DeleteLocalRef(env, formats);
243 if (sDraggingFormats == nil)
244 return FALSE;
245
246 jboolean isCopy;
247 jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
248 if (jformats == nil) {
249 return FALSE;
250 }
251
252 // Copy all data formats and properties. In case of properties, if they are nil, we need to use
253 // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
254 DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
255 NSUInteger i;
256 for (i = 0; i < sPasteboardItemsCount; i++) {
257 NSString* pbType = [sPasteboardTypes objectAtIndex:i];
258 DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
259
260 // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
261 // They're often copies of their flavor's data and copying them for all available pasteboard flavors
338 if ([sPasteboardTypes containsObject:pbType]) {
339 NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
340 data = [sPasteboardData objectAtIndex:dataIndex];
341
342 if ((id) data == [NSNull null])
343 data = nil;
344
345 // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
346 else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
347 data = [self getDraggingDataForURL:data];
348 }
349
350 // Get NS data:
351 char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
352 NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
353
354 // Create a global byte array:
355 jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
356 if (lbyteArray == nil)
357 return nil;
358 jbyteArray gbyteArray = (jbyteArray) (*env)->NewGlobalRef(env, lbyteArray);
359 (*env)->DeleteLocalRef(env, lbyteArray);
360 if (gbyteArray == nil)
361 return nil;
362
363 // Get byte array elements:
364 jboolean isCopy;
365 jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
366 if (jbytes == nil)
367 return nil;
368
369 // Copy data to byte array and release elements:
370 memcpy(jbytes, dataBytes, dataLength);
371 (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
372
373 // In case of an error make sure to return nil:
374 if ((*env)->ExceptionOccurred(env)) {
375 (*env)->ExceptionDescribe(env);
376 gbyteArray = nil;
377 }
378
441 DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
442
443 sCurrentDropTarget = self;
444
445 JNIEnv* env = [ThreadUtilities getJNIEnv];
446 NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
447
448 // Set the initial drag operation return value:
449 NSDragOperation dragOp = NSDragOperationNone;
450 sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
451
452 // We could probably special-case some stuff if drag and drop objects match:
453 //if ([sender dragSource] == fView)
454
455 if (draggingSequenceNumber != sDraggingSequenceNumber) {
456 sDraggingSequenceNumber = draggingSequenceNumber;
457 sDraggingError = FALSE;
458
459 // Delete any drop target context peer left over from a previous drag:
460 if (fDropTargetContextPeer != NULL) {
461 (*env)->DeleteGlobalRef(env, fDropTargetContextPeer);
462 fDropTargetContextPeer = NULL;
463 }
464
465 // Look up the CDropTargetContextPeer class:
466 GET_DTCP_CLASS_RETURN(dragOp);
467 DECLARE_STATIC_METHOD_RETURN(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer,
468 "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;", dragOp)
469 if (sDraggingError == FALSE) {
470 // Create a new drop target context peer:
471 jobject dropTargetContextPeer = (*env)->CallStaticObjectMethod(env, jc_CDropTargetContextPeer, getDropTargetContextPeerMethod);
472 CHECK_EXCEPTION();
473
474 if (dropTargetContextPeer != nil) {
475 fDropTargetContextPeer = (*env)->NewGlobalRef(env, dropTargetContextPeer);
476 (*env)->DeleteLocalRef(env, dropTargetContextPeer);
477 }
478 }
479
480 // Get dragging types (dragging data is only copied if dropped):
481 if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
482 sDraggingError = TRUE;
483 }
484
485 if (sDraggingError == FALSE) {
486 sDraggingExited = FALSE;
487 sDraggingLocation = [sender draggingLocation];
488 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
489 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
490
491 DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
492
493 ////////// BEGIN Calculate the current drag actions //////////
494 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
495 jint dropAction = actions;
496
497 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
498
499 sJavaDropOperation = dropAction;
500 ////////// END Calculate the current drag actions //////////
501
502 jlongArray formats = sDraggingFormats;
503
504 GET_DTCP_CLASS_RETURN(dragOp);
505 DECLARE_METHOD_RETURN(handleEnterMessageMethod, jc_CDropTargetContextPeer,
506 "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I", dragOp);
507 if (sDraggingError == FALSE) {
508 // Double-casting self gets rid of 'different size' compiler warning:
509 // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
510 actions = (*env)->CallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod,
511 fComponent, (jint) javaLocation.x, (jint) javaLocation.y,
512 dropAction, actions, formats, ptr_to_jlong(self));
513 CHECK_EXCEPTION();
514 }
515
516 if (sDraggingError == FALSE) {
517 // Initialize drag operation:
518 sDragOperation = NSDragOperationNone;
519
520 // Map Java actions back to NSDragOperation.
521 // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
522 // (as can be the case with lightweight children) we must not return NSDragOperationNone
523 // since that would prevent dropping into any of the contained drop targets.
524 // Unfortunately there is no easy way to test this so we just test actions and override them
525 // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
526 // called right away, taking care of setting the right cursor and snap-back action.
527 dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
528 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
529
530 // Remember the dragOp for no-op'd update messages:
531 sUpdateOperation = dragOp;
532 }
533 }
572 jint dropAction = actions;
573
574 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
575
576 if (sJavaDropOperation != dropAction) {
577 sJavaDropOperation = dropAction;
578 notifyJava = TRUE;
579 }
580 ////////// END Calculate the current drag actions //////////
581
582 jint userAction = dropAction;
583
584 // Should we notify Java things have changed?
585 if (sDraggingError == FALSE && notifyJava) {
586 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
587 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
588 //DLog5(@" : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
589
590 jlongArray formats = sDraggingFormats;
591
592 GET_DTCP_CLASS_RETURN(dragOp);
593 DECLARE_METHOD_RETURN(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I", dragOp);
594 if (sDraggingError == FALSE) {
595 DLog3(@" >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
596 userAction = (*env)->CallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent,
597 (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
598 CHECK_EXCEPTION();
599 }
600
601 if (sDraggingError == FALSE) {
602 dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
603
604 // Remember the dragOp for no-op'd update messages:
605 sUpdateOperation = dragOp;
606 } else {
607 dragOp = NSDragOperationNone;
608 }
609 }
610
611 DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
612
613 return dragOp;
614 }
615
616 - (void)draggingExited:(id<NSDraggingInfo>)sender
617 {
618 DLog2(@"[CDropTarget draggingExited]: %@\n", self);
619
620 sCurrentDropTarget = nil;
621
622 JNIEnv* env = [ThreadUtilities getJNIEnv];
623
624 if (sDraggingExited == FALSE && sDraggingError == FALSE) {
625 GET_DTCP_CLASS();
626 DECLARE_METHOD(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
627 if (sDraggingError == FALSE) {
628 DLog3(@" - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
629 // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
630 (*env)->CallVoidMethod(env, fDropTargetContextPeer,
631 handleExitMessageMethod, fComponent, ptr_to_jlong(self));
632 CHECK_EXCEPTION();
633 }
634
635 // 5-27-03 Note: [Radar 3270455]
636 // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
637 // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
638 sDraggingExited = TRUE;
639 }
640
641 DLog(@"[CDropTarget draggingExited]: returning.\n");
642 }
643
644 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
645 {
646 DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
647 DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
648
649 return sDraggingError ? NO : YES;
650 }
651
652 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
657
658 JNIEnv* env = [ThreadUtilities getJNIEnv];
659
660 // Now copy dragging data:
661 if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
662 sDraggingError = TRUE;
663
664 if (sDraggingError == FALSE) {
665 sDraggingLocation = [sender draggingLocation];
666 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
667 // The y coordinate that comes in the NSDraggingInfo seems to be reversed - probably
668 // has to do something with the type of view it comes to.
669 // This is the earliest place where we can correct it.
670 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
671
672 jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
673 jint dropAction = sJavaDropOperation;
674
675 jlongArray formats = sDraggingFormats;
676
677 GET_DTCP_CLASS_RETURN(NO);
678 DECLARE_METHOD_RETURN(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V", NO);
679
680 if (sDraggingError == FALSE) {
681 (*env)->CallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent,
682 (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
683 CHECK_EXCEPTION();
684 }
685 } else {
686 // 8-19-03 Note: [Radar 3368754]
687 // draggingExited: is not called after a drop - we must do that here ... but only in case
688 // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
689 [self draggingExited:sender];
690 }
691
692 // TODO:BG
693 // [(id)sender _setLastDragDestinationOperation:sDragOperation];
694
695
696 DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
697
698 return !sDraggingError;
699 }
700
701 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender
702 {
703 sCurrentDropTarget = nil;
713
714 DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
715 DLog(@"[CDropTarget draggingEnded]: returning.\n");
716 }
717
718 /******************************** END NSDraggingDestination Interface ********************************/
719
720 @end
721
722
723 /*
724 * Class: sun_lwawt_macosx_CDropTarget
725 * Method: createNativeDropTarget
726 * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
727 */
728 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
729 (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jlong jnativepeer)
730 {
731 CDropTarget* dropTarget = nil;
732
733 JNI_COCOA_ENTER(env);
734 id controlObj = (id) jlong_to_ptr(jnativepeer);
735 dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent control:controlObj];
736 JNI_COCOA_EXIT(env);
737
738 return ptr_to_jlong(dropTarget);
739 }
740
741 /*
742 * Class: sun_lwawt_macosx_CDropTarget
743 * Method: releaseNativeDropTarget
744 * Signature: (J)V
745 */
746 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
747 (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
748 {
749 id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
750
751 JNI_COCOA_ENTER(env);
752 [dropTarget removeFromView:env];
753 JNI_COCOA_EXIT(env);
754 }
|