11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
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 "java_awt_dnd_DnDConstants.h"
29
30 #import <Cocoa/Cocoa.h>
31 #import <JavaNativeFoundation/JavaNativeFoundation.h>
32
33 #import "AWTEvent.h"
34 #import "AWTView.h"
35 #import "CDataTransferer.h"
36 #import "CDropTarget.h"
37 #import "CDragSource.h"
38 #import "DnDUtilities.h"
39 #import "ThreadUtilities.h"
40 #import "LWCToolkit.h"
41
42
43 // When sIsJavaDragging is true Java drag gesture has been recognized and a drag is/has been initialized.
44 // We must stop posting MouseEvent.MOUSE_DRAGGED events for the duration of the drag or all hell will break
45 // loose in shared code - tracking state going haywire.
46 static BOOL sIsJavaDragging;
47
48
49 @interface NSEvent(AWTAdditions)
50
51 + (void)javaDraggingBegin;
52 + (void)javaDraggingEnd;
53
54 @end
55
56
57 @implementation NSEvent(AWTAdditions)
58
59
60 + (void)javaDraggingBegin
61 {
62 sIsJavaDragging = YES;
63 }
64
65 + (void)javaDraggingEnd
66 {
67 // sIsJavaDragging is reset on mouseDown as well.
68 sIsJavaDragging = NO;
69 }
70 @end
71
72 JNF_CLASS_CACHE(DataTransfererClass, "sun/awt/datatransfer/DataTransferer");
73 JNF_CLASS_CACHE(CDragSourceContextPeerClass, "sun/lwawt/macosx/CDragSourceContextPeer");
74 JNF_CLASS_CACHE(CImageClass, "sun/lwawt/macosx/CImage");
75
76 static NSDragOperation sDragOperation;
77 static NSPoint sDraggingLocation;
78
79 static BOOL sNeedsEnter;
80
81 @interface CDragSource ()
82 // Updates from the destination to the source
83 - (void) postDragEnter;
84 - (void) postDragExit;
85 // Utility
86 - (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint) point;
87 @end
88
89 @implementation CDragSource
90
91 - (id) init:(jobject)jDragSourceContextPeer
92 component:(jobject)jComponent
93 control:(id)control
94 transferable:(jobject)jTransferable
143 [NSEvent javaDraggingBegin];
144 }
145
146 else {
147 [self release];
148 self = nil;
149 }
150
151 return self;
152 }
153
154 - (void)removeFromView:(JNIEnv *)env
155 {
156 DLog2(@"[CDragSource removeFromView]: %@\n", self);
157
158 // Remove this dragging source from the view:
159 [((AWTView *) fView) setDragSource:nil];
160
161 // Clean up JNI refs
162 if (fComponent != NULL) {
163 JNFDeleteGlobalRef(env, fComponent);
164 fComponent = NULL;
165 }
166
167 if (fDragSourceContextPeer != NULL) {
168 JNFDeleteGlobalRef(env, fDragSourceContextPeer);
169 fDragSourceContextPeer = NULL;
170 }
171
172 if (fTransferable != NULL) {
173 JNFDeleteGlobalRef(env, fTransferable);
174 fTransferable = NULL;
175 }
176
177 if (fTriggerEvent != NULL) {
178 JNFDeleteGlobalRef(env, fTriggerEvent);
179 fTriggerEvent = NULL;
180 }
181
182 if (fFormats != NULL) {
183 JNFDeleteGlobalRef(env, fFormats);
184 fFormats = NULL;
185 }
186
187 if (fFormatMap != NULL) {
188 JNFDeleteGlobalRef(env, fFormatMap);
189 fFormatMap = NULL;
190 }
191
192 [self release];
193 }
194
195 - (void)dealloc
196 {
197 DLog2(@"[CDragSource dealloc]: %@\n", self);
198
199 // Delete or release local data:
200 [fView release];
201 fView = nil;
202
203 [fDragImage release];
204 fDragImage = nil;
205
206 [super dealloc];
207 }
208
209 // Appropriated from Windows' awt_DataTransferer.cpp:
210 //
211 // * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
212 //
213 - (jobject)dataTransferer:(JNIEnv*)env
214 {
215 JNF_STATIC_MEMBER_CACHE(getInstanceMethod, DataTransfererClass, "getInstance", "()Lsun/awt/datatransfer/DataTransferer;");
216 return JNFCallStaticObjectMethod(env, getInstanceMethod);
217 }
218
219 // Appropriated from Windows' awt_DataTransferer.cpp:
220 //
221 // * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
222 //
223 - (jbyteArray)convertData:(jlong)format
224 {
225 JNIEnv* env = [ThreadUtilities getJNIEnv];
226 jobject transferer = [self dataTransferer:env];
227 jbyteArray data = nil;
228
229 if (transferer != NULL) {
230 JNF_MEMBER_CACHE(convertDataMethod, DataTransfererClass, "convertData", "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B");
231 data = JNFCallObjectMethod(env, transferer, convertDataMethod, fComponent, fTransferable, format, fFormatMap, (jboolean) TRUE);
232 }
233
234 return data;
235 }
236
237
238 // Encodes a byte array of zero-terminated filenames into an NSArray of NSStrings representing them.
239 // Borrowed and adapted from awt_DataTransferer.c, convertFileType().
240 - (id)getFileList:(jbyte *)jbytes dataLength:(jsize)jbytesLength
241 {
242 jsize strings = 0;
243 jsize i;
244
245 // Get number of filenames while making sure to skip over empty strings.
246 for (i = 1; i < jbytesLength; i++) {
247 if (jbytes[i] == '\0' && jbytes[i - 1] != '\0')
248 strings++;
249 }
250
251 // Create the file list to return:
252 NSMutableArray* fileList = [NSMutableArray arrayWithCapacity:strings];
538 }
539 }
540
541 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
542
543 // Convert drag operation to Java:
544 jint dragOp = [DnDUtilities mapNSDragOperationToJava:sDragOperation];
545
546 // Drag success must acount for DragOperationNone:
547 jboolean success = (dragOp != java_awt_dnd_DnDConstants_ACTION_NONE);
548
549 // We have a problem here... we don't send DragSource dragEnter/Exit messages outside of our own process
550 // because we don't get anything from AppKit/CoreDrag
551 // This means that if you drag outside of the app and drop, even if it's valid, a dragDropFinished is posted without dragEnter
552 // I'm worried that this might confuse Java, so we're going to send a "bogus" dragEnter if necessary (only if the drag succeeded)
553 if (success && sNeedsEnter) {
554 [self postDragEnter];
555 }
556
557 // DragSourceContextPeer.dragDropFinished() should be called even if there was an error:
558 JNF_MEMBER_CACHE(dragDropFinishedMethod, CDragSourceContextPeerClass, "dragDropFinished", "(ZIII)V");
559 DLog3(@" -> posting dragDropFinished, point %f, %f", point.x, point.y);
560 JNFCallVoidMethod(env, fDragSourceContextPeer, dragDropFinishedMethod, success, dragOp, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
561 JNF_MEMBER_CACHE(resetHoveringMethod, CDragSourceContextPeerClass, "resetHovering", "()V");
562 JNFCallVoidMethod(env, fDragSourceContextPeer, resetHoveringMethod); // Hust reset static variable
563 } @finally {
564 sNeedsEnter = NO;
565 AWTToolkit.inDoDragDropLoop = NO;
566 }
567
568 // We have to do this, otherwise AppKit doesn't know we're finished dragging. Yup, it's that bad.
569 if ([[[NSRunLoop currentRunLoop] currentMode] isEqualTo:NSEventTrackingRunLoopMode]) {
570 [NSApp postEvent:[self nsDragEvent:NO] atStart:YES];
571 }
572
573 DLog2(@"[CDragSource doDrag] end: %@\n", self);
574 }
575
576 - (void)drag
577 {
578 AWT_ASSERT_NOT_APPKIT_THREAD;
579
580 [self performSelectorOnMainThread:@selector(doDrag) withObject:nil waitUntilDone:YES]; // AWT_THREADING Safe (called from unique asynchronous thread)
581 }
582
583 /******************************** BEGIN NSDraggingSource Interface ********************************/
584
585 - (void)draggingOperationChanged:(NSDragOperation)dragOp {
586 //DLog2(@"[CDragSource draggingOperationChanged]: %@\n", self);
587
588 JNIEnv* env = [ThreadUtilities getJNIEnv];
589
590 jint targetActions = fSourceActions;
591 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
592
593 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
594 DLog3(@" -> posting operationChanged, point %f, %f", point.x, point.y);
595 jint modifiedModifiers = fDragKeyModifiers | fDragMouseModifiers | [DnDUtilities javaKeyModifiersForNSDragOperation:dragOp];
596
597 JNF_MEMBER_CACHE(operationChangedMethod, CDragSourceContextPeerClass, "operationChanged", "(IIII)V");
598 JNFCallVoidMethod(env, fDragSourceContextPeer, operationChangedMethod, targetActions, modifiedModifiers, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
599 }
600
601 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)localDrag {
602 //DLog2(@"[CDragSource draggingSourceOperationMaskForLocal]: %@\n", self);
603 return [DnDUtilities mapJavaDragOperationToNS:fSourceActions];
604 }
605
606 /* 9-16-02 Note: we don't support promises yet.
607 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination {
608 }*/
609
610 - (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint {
611 DLog4(@"[CDragSource draggedImage beganAt]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
612 [AWTToolkit eventCountPlusPlus];
613 // Initialize static variables:
614 sDragOperation = NSDragOperationNone;
615 sDraggingLocation = screenPoint;
616 }
617
618 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation {
619 DLog4(@"[CDragSource draggedImage endedAt:]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
620 [AWTToolkit eventCountPlusPlus];
621 sDraggingLocation = screenPoint;
622 sDragOperation = operation;
623 }
624
625 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint {
626 //DLog4(@"[CDragSource draggedImage moved]: (%d, %d) %@\n", (int) screenPoint.x, (int) screenPoint.y, self);
627 JNIEnv* env = [ThreadUtilities getJNIEnv];
628
629 JNF_COCOA_ENTER(env);
630 [AWTToolkit eventCountPlusPlus];
631 // There are two things we would be interested in:
632 // a) mouse pointer has moved
633 // b) drag actions (key modifiers) have changed
634
635 BOOL notifyJava = FALSE;
636
637 // a) mouse pointer has moved:
638 if (NSEqualPoints(screenPoint, sDraggingLocation) == FALSE) {
639 //DLog2(@"[CDragSource draggedImage:movedTo]: mouse moved, %@\n", self);
640 notifyJava = TRUE;
641 }
642
643 // b) drag actions (key modifiers) have changed:
644 jint modifiers = NsKeyModifiersToJavaModifiers([NSEvent modifierFlags], YES);
645 if (fDragKeyModifiers != modifiers) {
646 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:[NSEvent modifierFlags]];
647 NSDragOperation allowedOp = [DnDUtilities mapJavaDragOperationToNS:fSourceActions] & currentOp;
648
649 fDragKeyModifiers = modifiers;
650
651 if (sDragOperation != allowedOp) {
652 sDragOperation = allowedOp;
653 [self draggingOperationChanged:allowedOp];
654 }
655 }
656
657 // Should we notify Java things have changed?
658 if (notifyJava) {
659 sDraggingLocation = screenPoint;
660
661 NSPoint point = [self mapNSScreenPointToJavaWithOffset:screenPoint];
662
663 jint targetActions = fSourceActions;
664 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
665
666 // Motion: dragMotion, dragMouseMoved
667 DLog4(@"[CDragSource draggedImage moved]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
668
669 DLog3(@" -> posting dragMotion, point %f, %f", point.x, point.y);
670 JNF_MEMBER_CACHE(dragMotionMethod, CDragSourceContextPeerClass, "dragMotion", "(IIII)V");
671 JNFCallVoidMethod(env, fDragSourceContextPeer, dragMotionMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
672
673 DLog3(@" -> posting dragMouseMoved, point %f, %f", point.x, point.y);
674 JNF_MEMBER_CACHE(dragMouseMovedMethod, CDragSourceContextPeerClass, "dragMouseMoved", "(IIII)V");
675 JNFCallVoidMethod(env, fDragSourceContextPeer, dragMouseMovedMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
676 }
677 JNF_COCOA_EXIT(env);
678 }
679
680 - (BOOL)ignoreModifierKeysWhileDragging {
681 //DLog2(@"[CDragSource ignoreModifierKeysWhileDragging]: %@\n", self);
682 return NO;
683 }
684
685 /******************************** END NSDraggingSource Interface ********************************/
686
687
688 // postDragEnter and postDragExit are called from CDropTarget when possible and appropriate
689 // Currently only possible if source and target are in the same process
690 - (void) postDragEnter {
691 JNIEnv *env = [ThreadUtilities getJNIEnv];
692 sNeedsEnter = NO;
693
694 jint targetActions = fSourceActions;
695 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
696
697 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
698 DLog3(@" -> posting dragEnter, point %f, %f", point.x, point.y);
699 JNF_MEMBER_CACHE(dragEnterMethod, CDragSourceContextPeerClass, "dragEnter", "(IIII)V");
700 JNFCallVoidMethod(env, fDragSourceContextPeer, dragEnterMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
701 }
702
703 - (void) postDragExit {
704 JNIEnv *env = [ThreadUtilities getJNIEnv];
705 sNeedsEnter = YES;
706
707 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
708 DLog3(@" -> posting dragExit, point %f, %f", point.x, point.y);
709 JNF_MEMBER_CACHE(dragExitMethod, CDragSourceContextPeerClass, "dragExit", "(II)V");
710 JNFCallVoidMethod(env, fDragSourceContextPeer, dragExitMethod, (jint) point.x, (jint) point.y); // AWT_THREADING Safe (event)
711 }
712
713
714 // Java assumes that the origin is the top-left corner of the screen.
715 // Cocoa assumes that the origin is the bottom-left corner of the screen.
716 // Adjust the y coordinate to account for this.
717 // NOTE: Also need to take into account the 0 screen relative screen coords.
718 // This is because all screen coords in Cocoa are relative to the 0 screen.
719 // Also see +[CWindow convertAWTToCocoaScreenRect]
720 // NSScreen-to-JavaScreen mapping:
721 - (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint)screenPoint {
722 NSRect mainR = [[[NSScreen screens] objectAtIndex:0] frame];
723 NSPoint point = NSMakePoint(screenPoint.x, mainR.size.height - (screenPoint.y));
724
725 // Adjust the point with the drag image offset to get the real mouse hotspot:
726 // The point should remain in screen coordinates (as per DragSourceEvent.getLocation() documentation)
727 point.x -= fDragImageOffset.x;
728 point.y -= ([fDragImage size].height + fDragImageOffset.y);
729
730 return point;
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
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 "java_awt_dnd_DnDConstants.h"
29
30 #import <Cocoa/Cocoa.h>
31
32 #import "AWTEvent.h"
33 #import "AWTView.h"
34 #import "CDataTransferer.h"
35 #import "CDropTarget.h"
36 #import "CDragSource.h"
37 #import "DnDUtilities.h"
38 #import "ThreadUtilities.h"
39 #import "LWCToolkit.h"
40 #import "JNIUtilities.h"
41
42
43 // When sIsJavaDragging is true Java drag gesture has been recognized and a drag is/has been initialized.
44 // We must stop posting MouseEvent.MOUSE_DRAGGED events for the duration of the drag or all hell will break
45 // loose in shared code - tracking state going haywire.
46 static BOOL sIsJavaDragging;
47
48
49 @interface NSEvent(AWTAdditions)
50
51 + (void)javaDraggingBegin;
52 + (void)javaDraggingEnd;
53
54 @end
55
56
57 @implementation NSEvent(AWTAdditions)
58
59
60 + (void)javaDraggingBegin
61 {
62 sIsJavaDragging = YES;
63 }
64
65 + (void)javaDraggingEnd
66 {
67 // sIsJavaDragging is reset on mouseDown as well.
68 sIsJavaDragging = NO;
69 }
70 @end
71
72 static jclass DataTransfererClass = NULL;
73 static jclass CDragSourceContextPeerClass = NULL;
74
75 #define GET_DT_CLASS() \
76 GET_CLASS(DataTransfererClass, "sun/awt/datatransfer/DataTransferer");
77
78 #define GET_DT_CLASS_RETURN(ret) \
79 GET_CLASS_RETURN(DataTransfererClass, "sun/awt/datatransfer/DataTransferer", ret);
80
81 #define GET_DSCP_CLASS() \
82 GET_CLASS(CDragSourceContextPeerClass, "sun/lwawt/macosx/CDragSourceContextPeer");
83
84 static NSDragOperation sDragOperation;
85 static NSPoint sDraggingLocation;
86
87 static BOOL sNeedsEnter;
88
89 @interface CDragSource ()
90 // Updates from the destination to the source
91 - (void) postDragEnter;
92 - (void) postDragExit;
93 // Utility
94 - (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint) point;
95 @end
96
97 @implementation CDragSource
98
99 - (id) init:(jobject)jDragSourceContextPeer
100 component:(jobject)jComponent
101 control:(id)control
102 transferable:(jobject)jTransferable
151 [NSEvent javaDraggingBegin];
152 }
153
154 else {
155 [self release];
156 self = nil;
157 }
158
159 return self;
160 }
161
162 - (void)removeFromView:(JNIEnv *)env
163 {
164 DLog2(@"[CDragSource removeFromView]: %@\n", self);
165
166 // Remove this dragging source from the view:
167 [((AWTView *) fView) setDragSource:nil];
168
169 // Clean up JNI refs
170 if (fComponent != NULL) {
171 (*env)->DeleteGlobalRef(env, fComponent);
172 fComponent = NULL;
173 }
174
175 if (fDragSourceContextPeer != NULL) {
176 (*env)->DeleteGlobalRef(env, fDragSourceContextPeer);
177 fDragSourceContextPeer = NULL;
178 }
179
180 if (fTransferable != NULL) {
181 (*env)->DeleteGlobalRef(env, fTransferable);
182 fTransferable = NULL;
183 }
184
185 if (fTriggerEvent != NULL) {
186 (*env)->DeleteGlobalRef(env, fTriggerEvent);
187 fTriggerEvent = NULL;
188 }
189
190 if (fFormats != NULL) {
191 (*env)->DeleteGlobalRef(env, fFormats);
192 fFormats = NULL;
193 }
194
195 if (fFormatMap != NULL) {
196 (*env)->DeleteGlobalRef(env, fFormatMap);
197 fFormatMap = NULL;
198 }
199
200 [self release];
201 }
202
203 - (void)dealloc
204 {
205 DLog2(@"[CDragSource dealloc]: %@\n", self);
206
207 // Delete or release local data:
208 [fView release];
209 fView = nil;
210
211 [fDragImage release];
212 fDragImage = nil;
213
214 [super dealloc];
215 }
216
217 // Appropriated from Windows' awt_DataTransferer.cpp:
218 //
219 // * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
220 //
221 - (jobject)dataTransferer:(JNIEnv*)env
222 {
223 GET_DT_CLASS_RETURN(NULL);
224 DECLARE_STATIC_METHOD_RETURN(getInstanceMethod, DataTransfererClass, "getInstance", "()Lsun/awt/datatransfer/DataTransferer;", NULL);
225 jobject o = (*env)->CallStaticObjectMethod(env, DataTransfererClass, getInstanceMethod);
226 CHECK_EXCEPTION();
227 return o;
228 }
229
230 // Appropriated from Windows' awt_DataTransferer.cpp:
231 //
232 // * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
233 //
234 - (jbyteArray)convertData:(jlong)format
235 {
236 JNIEnv* env = [ThreadUtilities getJNIEnv];
237 jobject transferer = [self dataTransferer:env];
238 jbyteArray data = nil;
239
240 if (transferer != NULL) {
241 GET_DT_CLASS_RETURN(NULL);
242 DECLARE_METHOD_RETURN(convertDataMethod, DataTransfererClass, "convertData", "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B", NULL);
243 data = (*env)->CallObjectMethod(env, transferer, convertDataMethod, fComponent, fTransferable, format, fFormatMap, (jboolean) TRUE);
244 }
245 CHECK_EXCEPTION();
246
247 return data;
248 }
249
250
251 // Encodes a byte array of zero-terminated filenames into an NSArray of NSStrings representing them.
252 // Borrowed and adapted from awt_DataTransferer.c, convertFileType().
253 - (id)getFileList:(jbyte *)jbytes dataLength:(jsize)jbytesLength
254 {
255 jsize strings = 0;
256 jsize i;
257
258 // Get number of filenames while making sure to skip over empty strings.
259 for (i = 1; i < jbytesLength; i++) {
260 if (jbytes[i] == '\0' && jbytes[i - 1] != '\0')
261 strings++;
262 }
263
264 // Create the file list to return:
265 NSMutableArray* fileList = [NSMutableArray arrayWithCapacity:strings];
551 }
552 }
553
554 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
555
556 // Convert drag operation to Java:
557 jint dragOp = [DnDUtilities mapNSDragOperationToJava:sDragOperation];
558
559 // Drag success must acount for DragOperationNone:
560 jboolean success = (dragOp != java_awt_dnd_DnDConstants_ACTION_NONE);
561
562 // We have a problem here... we don't send DragSource dragEnter/Exit messages outside of our own process
563 // because we don't get anything from AppKit/CoreDrag
564 // This means that if you drag outside of the app and drop, even if it's valid, a dragDropFinished is posted without dragEnter
565 // I'm worried that this might confuse Java, so we're going to send a "bogus" dragEnter if necessary (only if the drag succeeded)
566 if (success && sNeedsEnter) {
567 [self postDragEnter];
568 }
569
570 // DragSourceContextPeer.dragDropFinished() should be called even if there was an error:
571 GET_DSCP_CLASS();
572 DECLARE_METHOD(dragDropFinishedMethod, CDragSourceContextPeerClass, "dragDropFinished", "(ZIII)V");
573 DLog3(@" -> posting dragDropFinished, point %f, %f", point.x, point.y);
574 (*env)->CallVoidMethod(env, fDragSourceContextPeer, dragDropFinishedMethod, success, dragOp, (jint) point.x, (jint) point.y);
575 CHECK_EXCEPTION();
576 DECLARE_METHOD(resetHoveringMethod, CDragSourceContextPeerClass, "resetHovering", "()V");
577 (*env)->CallVoidMethod(env, fDragSourceContextPeer, resetHoveringMethod); // Hust reset static variable
578 CHECK_EXCEPTION();
579 } @finally {
580 sNeedsEnter = NO;
581 AWTToolkit.inDoDragDropLoop = NO;
582 }
583
584 // We have to do this, otherwise AppKit doesn't know we're finished dragging. Yup, it's that bad.
585 if ([[[NSRunLoop currentRunLoop] currentMode] isEqualTo:NSEventTrackingRunLoopMode]) {
586 [NSApp postEvent:[self nsDragEvent:NO] atStart:YES];
587 }
588
589 DLog2(@"[CDragSource doDrag] end: %@\n", self);
590 }
591
592 - (void)drag
593 {
594 AWT_ASSERT_NOT_APPKIT_THREAD;
595
596 [self performSelectorOnMainThread:@selector(doDrag) withObject:nil waitUntilDone:YES];
597 }
598
599 /******************************** BEGIN NSDraggingSource Interface ********************************/
600
601 - (void)draggingOperationChanged:(NSDragOperation)dragOp {
602 //DLog2(@"[CDragSource draggingOperationChanged]: %@\n", self);
603
604 JNIEnv* env = [ThreadUtilities getJNIEnv];
605
606 jint targetActions = fSourceActions;
607 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
608
609 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
610 DLog3(@" -> posting operationChanged, point %f, %f", point.x, point.y);
611 jint modifiedModifiers = fDragKeyModifiers | fDragMouseModifiers | [DnDUtilities javaKeyModifiersForNSDragOperation:dragOp];
612
613 GET_DSCP_CLASS();
614 DECLARE_METHOD(operationChangedMethod, CDragSourceContextPeerClass, "operationChanged", "(IIII)V");
615 (*env)->CallVoidMethod(env, fDragSourceContextPeer, operationChangedMethod, targetActions, modifiedModifiers, (jint) point.x, (jint) point.y);
616 CHECK_EXCEPTION();
617 }
618
619 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)localDrag {
620 //DLog2(@"[CDragSource draggingSourceOperationMaskForLocal]: %@\n", self);
621 return [DnDUtilities mapJavaDragOperationToNS:fSourceActions];
622 }
623
624 /* 9-16-02 Note: we don't support promises yet.
625 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination {
626 }*/
627
628 - (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint {
629 DLog4(@"[CDragSource draggedImage beganAt]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
630 [AWTToolkit eventCountPlusPlus];
631 // Initialize static variables:
632 sDragOperation = NSDragOperationNone;
633 sDraggingLocation = screenPoint;
634 }
635
636 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation {
637 DLog4(@"[CDragSource draggedImage endedAt:]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
638 [AWTToolkit eventCountPlusPlus];
639 sDraggingLocation = screenPoint;
640 sDragOperation = operation;
641 }
642
643 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint {
644 //DLog4(@"[CDragSource draggedImage moved]: (%d, %d) %@\n", (int) screenPoint.x, (int) screenPoint.y, self);
645 JNIEnv* env = [ThreadUtilities getJNIEnv];
646
647 JNI_COCOA_ENTER(env);
648 [AWTToolkit eventCountPlusPlus];
649 // There are two things we would be interested in:
650 // a) mouse pointer has moved
651 // b) drag actions (key modifiers) have changed
652
653 BOOL notifyJava = FALSE;
654
655 // a) mouse pointer has moved:
656 if (NSEqualPoints(screenPoint, sDraggingLocation) == FALSE) {
657 //DLog2(@"[CDragSource draggedImage:movedTo]: mouse moved, %@\n", self);
658 notifyJava = TRUE;
659 }
660
661 // b) drag actions (key modifiers) have changed:
662 jint modifiers = NsKeyModifiersToJavaModifiers([NSEvent modifierFlags], YES);
663 if (fDragKeyModifiers != modifiers) {
664 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:[NSEvent modifierFlags]];
665 NSDragOperation allowedOp = [DnDUtilities mapJavaDragOperationToNS:fSourceActions] & currentOp;
666
667 fDragKeyModifiers = modifiers;
668
669 if (sDragOperation != allowedOp) {
670 sDragOperation = allowedOp;
671 [self draggingOperationChanged:allowedOp];
672 }
673 }
674
675 // Should we notify Java things have changed?
676 if (notifyJava) {
677 sDraggingLocation = screenPoint;
678
679 NSPoint point = [self mapNSScreenPointToJavaWithOffset:screenPoint];
680
681 jint targetActions = fSourceActions;
682 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
683
684 // Motion: dragMotion, dragMouseMoved
685 DLog4(@"[CDragSource draggedImage moved]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
686
687 DLog3(@" -> posting dragMotion, point %f, %f", point.x, point.y);
688 GET_DSCP_CLASS();
689 DECLARE_METHOD(dragMotionMethod, CDragSourceContextPeerClass, "dragMotion", "(IIII)V");
690 (*env)->CallVoidMethod(env, fDragSourceContextPeer, dragMotionMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
691 CHECK_EXCEPTION();
692 DLog3(@" -> posting dragMouseMoved, point %f, %f", point.x, point.y);
693 DECLARE_METHOD(dragMouseMovedMethod, CDragSourceContextPeerClass, "dragMouseMoved", "(IIII)V");
694 (*env)->CallVoidMethod(env, fDragSourceContextPeer, dragMouseMovedMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
695 CHECK_EXCEPTION();
696 }
697 JNI_COCOA_EXIT(env);
698 }
699
700 - (BOOL)ignoreModifierKeysWhileDragging {
701 //DLog2(@"[CDragSource ignoreModifierKeysWhileDragging]: %@\n", self);
702 return NO;
703 }
704
705 /******************************** END NSDraggingSource Interface ********************************/
706
707
708 // postDragEnter and postDragExit are called from CDropTarget when possible and appropriate
709 // Currently only possible if source and target are in the same process
710 - (void) postDragEnter {
711 JNIEnv *env = [ThreadUtilities getJNIEnv];
712 sNeedsEnter = NO;
713
714 jint targetActions = fSourceActions;
715 if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
716
717 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
718 DLog3(@" -> posting dragEnter, point %f, %f", point.x, point.y);
719 GET_DSCP_CLASS();
720 DECLARE_METHOD(dragEnterMethod, CDragSourceContextPeerClass, "dragEnter", "(IIII)V");
721 (*env)->CallVoidMethod(env, fDragSourceContextPeer, dragEnterMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
722 CHECK_EXCEPTION();
723 }
724
725 - (void) postDragExit {
726 JNIEnv *env = [ThreadUtilities getJNIEnv];
727 sNeedsEnter = YES;
728
729 NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
730 DLog3(@" -> posting dragExit, point %f, %f", point.x, point.y);
731 GET_DSCP_CLASS();
732 DECLARE_METHOD(dragExitMethod, CDragSourceContextPeerClass, "dragExit", "(II)V");
733 (*env)->CallVoidMethod(env, fDragSourceContextPeer, dragExitMethod, (jint) point.x, (jint) point.y);
734 CHECK_EXCEPTION();
735
736 }
737
738
739 // Java assumes that the origin is the top-left corner of the screen.
740 // Cocoa assumes that the origin is the bottom-left corner of the screen.
741 // Adjust the y coordinate to account for this.
742 // NOTE: Also need to take into account the 0 screen relative screen coords.
743 // This is because all screen coords in Cocoa are relative to the 0 screen.
744 // Also see +[CWindow convertAWTToCocoaScreenRect]
745 // NSScreen-to-JavaScreen mapping:
746 - (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint)screenPoint {
747 NSRect mainR = [[[NSScreen screens] objectAtIndex:0] frame];
748 NSPoint point = NSMakePoint(screenPoint.x, mainR.size.height - (screenPoint.y));
749
750 // Adjust the point with the drag image offset to get the real mouse hotspot:
751 // The point should remain in screen coordinates (as per DragSourceEvent.getLocation() documentation)
752 point.x -= fDragImageOffset.x;
753 point.y -= ([fDragImage size].height + fDragImageOffset.y);
754
755 return point;
|