< prev index next >

src/java.desktop/macosx/native/libawt_lwawt/awt/CDragSource.m

Print this page
rev 54094 : 8257853: Remove dependencies on JNF's JNI utility functions in AWT and 2D code
rev 54096 : 8259651: [macOS] Replace JNF_COCOA_ENTER/EXIT macros
rev 54097 : 8259869: [macOS] Remove desktop module dependencies on JNF Reference APIs
rev 54098 : 8260616: Removing remaining JNF dependencies in the java.desktop module
8259729: Missed JNFInstanceOf -> IsInstanceOf conversion


  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;
< prev index next >