1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  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 "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 peer:(jobject)jpeer 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)
 103     // How to register for non-standard data types remains to be determined.
 104     NSArray* dataTypes = [[NSArray alloc] initWithObjects:
 105         NSStringPboardType,
 106         NSFilenamesPboardType,
 107         NSPostScriptPboardType,
 108         NSTIFFPboardType,
 109         NSPasteboardTypePNG,
 110         NSRTFPboardType,
 111         NSTabularTextPboardType,
 112         NSFontPboardType,
 113         NSRulerPboardType,
 114         NSFileContentsPboardType,
 115         NSColorPboardType,
 116         NSRTFDPboardType,
 117         NSHTMLPboardType,
 118         NSURLPboardType,
 119         NSPDFPboardType,
 120         NSVCardPboardType,
 121         NSFilesPromisePboardType,
 122         [DnDUtilities javaPboardType],
 123         (NSString*)kUTTypeJPEG,
 124         nil];
 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     CFRelease(self);
 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 //- (void)finalize { [super finalize]; }
 191 
 192 - (NSInteger) getDraggingSequenceNumber
 193 {
 194     return sDraggingSequenceNumber;
 195 }
 196 
 197 // Debugging help:
 198 - (void)dumpPasteboard:(NSPasteboard*)pasteboard
 199 {
 200     NSArray* pasteboardTypes = [pasteboard types];
 201     NSUInteger pasteboardItemsCount = [pasteboardTypes count];
 202     NSUInteger i;
 203 
 204     // For each flavor on the pasteboard show the type, its data, and its property if there is one:
 205     for (i = 0; i < pasteboardItemsCount; i++) {
 206         NSString* pbType = [pasteboardTypes objectAtIndex:i];
 207         CFShow(pbType);
 208 
 209         NSData*    pbData = [pasteboard dataForType:pbType];
 210         CFShow(pbData);
 211 
 212         if ([pbType hasPrefix:@"CorePasteboardFlavorType"] == NO) {
 213             id pbDataProperty = [pasteboard propertyListForType:pbType];
 214             CFShow(pbDataProperty);
 215         }
 216     }
 217 }
 218 
 219 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
 220 {
 221     DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
 222     JNIEnv*    env = [ThreadUtilities getJNIEnv];
 223 
 224     // Release any old pasteboard data:
 225     [self releaseDraggingData];
 226 
 227     NSPasteboard* pb = [sender draggingPasteboard];
 228     sPasteboardTypes = [[pb types] retain];
 229     sPasteboardItemsCount = [sPasteboardTypes count];
 230     if (sPasteboardItemsCount == 0)
 231         return FALSE;
 232 
 233     jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
 234     if (formats == nil)
 235         return FALSE;
 236 
 237     sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats);
 238     (*env)->DeleteLocalRef(env, formats);
 239     if (sDraggingFormats == nil)
 240         return FALSE;
 241 
 242     jboolean isCopy;
 243     jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
 244     if (jformats == nil) {
 245         return FALSE;
 246     }
 247 
 248     // Copy all data formats and properties. In case of properties, if they are nil, we need to use
 249     // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
 250     DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
 251     NSUInteger i;
 252     for (i = 0; i < sPasteboardItemsCount; i++) {
 253         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
 254         DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
 255 
 256         // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
 257         // They're often copies of their flavor's data and copying them for all available pasteboard flavors
 258         // (which are often auto-translation of one another) can be a significant time/space hit.
 259 
 260         // If this is a remote object type (not a pre-defined format) register it with the pasteboard:
 261         jformats[i] = indexForFormat(pbType);
 262         if (jformats[i] == -1 && [pbType hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-remote-object;"])
 263             jformats[i] = registerFormatWithPasteboard(pbType);
 264     }
 265 
 266     (*env)->ReleaseLongArrayElements(env, sDraggingFormats, jformats, JNI_COMMIT);
 267 
 268     return TRUE;
 269 }
 270 
 271 - (BOOL)copyDraggingData:(id<NSDraggingInfo>)sender
 272 {
 273     DLog2(@"[CDropTarget copyDraggingData]: %@\n", self);
 274 
 275     sPasteboardData = [[NSMutableArray alloc] init];
 276     if (sPasteboardData == nil)
 277         return FALSE;
 278 
 279     // Copy all data items to a safe place since the pasteboard may go away before we'll need them:
 280     NSPasteboard* pb = [sender draggingPasteboard];
 281     NSUInteger i;
 282     for (i = 0; i < sPasteboardItemsCount; i++) {
 283         // Get a type and its data and save the data:
 284         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
 285         // 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit)
 286         // would be a good idea since we can't do anything with those CoreFoundation unknown types anyway.
 287         // But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder,
 288         // to be evaluated later.
 289         //id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data!
 290         id pbData = [pb dataForType:pbType];
 291 
 292         // If the data is null we can't store it in the array - an exception would be thrown.
 293         // We use the special object NSNull instead which is kosher.
 294         if (pbData == nil)
 295             pbData = [NSNull null];
 296 
 297         [((NSMutableArray*) sPasteboardData) addObject:pbData];
 298     }
 299 
 300     return TRUE;
 301 }
 302 
 303 - (NSData*) getDraggingDataForURL:(NSData*)data
 304 {
 305     NSData* result = nil;
 306 
 307     // Convert data into a property list if possible:
 308     NSPropertyListFormat propertyListFormat;
 309     NSString* errorString = nil;
 310     id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable
 311         format:&propertyListFormat errorDescription:&errorString];
 312 
 313     // URL types have only a single URL string in an array:
 314     if (propertyList != nil && errorString == nil && [propertyList isKindOfClass:[NSArray class]]) {
 315         NSArray*  array = (NSArray*) propertyList;
 316         if ([array count] > 0) {
 317             NSString* url = (NSString*) [array objectAtIndex:0];
 318             if (url != nil && [url length] > 0)
 319                 result = [url dataUsingEncoding:[url fastestEncoding]];
 320         }
 321     }
 322 
 323     return result;
 324 }
 325 
 326 - (jobject) copyDraggingDataForFormat:(jlong)format
 327 {
 328     JNIEnv*      env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment
 329 
 330     NSData*      data = nil;
 331 
 332     // Convert the Java format (datatransferer int index) to a pasteboard format (NSString):
 333     NSString* pbType = formatForIndex(format);
 334     if ([sPasteboardTypes containsObject:pbType]) {
 335         NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
 336         data = [sPasteboardData objectAtIndex:dataIndex];
 337 
 338         if ((id) data == [NSNull null])
 339             data = nil;
 340 
 341         // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
 342         else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
 343             data = [self getDraggingDataForURL:data];
 344     }
 345 
 346     // Get NS data:
 347     char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
 348     NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
 349 
 350     // Create a global byte array:
 351     jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
 352     if (lbyteArray == nil)
 353         return nil;
 354     jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray);
 355     (*env)->DeleteLocalRef(env, lbyteArray);
 356     if (gbyteArray == nil)
 357         return nil;
 358 
 359     // Get byte array elements:
 360     jboolean isCopy;
 361     jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
 362     if (jbytes == nil)
 363         return nil;
 364 
 365     // Copy data to byte array and release elements:
 366     memcpy(jbytes, dataBytes, dataLength);
 367     (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
 368 
 369     // In case of an error make sure to return nil:
 370     if ((*env)->ExceptionOccurred(env)) {
 371                 (*env)->ExceptionDescribe(env);
 372         gbyteArray = nil;
 373         }
 374 
 375     return gbyteArray;
 376 }
 377 
 378 - (void)safeReleaseDraggingData:(NSNumber *)arg
 379 {
 380     jlong draggingSequenceNumber = [arg longLongValue];
 381 
 382     // Make sure dragging data is released only if no new drag is under way. If a new drag
 383     // has been initiated it has released the old dragging data already. This has to be called
 384     // on the native event thread - otherwise we'd need to start synchronizing.
 385     if (draggingSequenceNumber == sDraggingSequenceNumber)
 386         [self releaseDraggingData];
 387 }
 388 
 389 - (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction
 390 {
 391     NSNumber *draggingSequenceNumberID = [NSNumber numberWithLongLong:draggingSequenceNumber];
 392         // Report back actual Swing success, not what AppKit thinks
 393         sDraggingError = !jsuccess;
 394         sDragOperation = [DnDUtilities mapJavaDragOperationToNS:jdropaction];
 395 
 396     // Release dragging data if any when Java's AWT event thread is all finished.
 397     // Make sure dragging data is released on the native event thread.
 398     [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) on:self withObject:draggingSequenceNumberID waitUntilDone:NO];
 399 }
 400 
 401 - (jint)currentJavaActions {
 402     return [DnDUtilities mapNSDragOperationToJava:sUpdateOperation];
 403 }
 404 
 405 /********************************  BEGIN NSDraggingDestination Interface  ********************************/
 406 
 407 
 408 // Private API to calculate the current Java actions
 409 - (void) calculateCurrentSourceActions:(jint *)actions dropAction:(jint *)dropAction
 410 {
 411     // Get the raw (unmodified by keys) source actions
 412     id jrsDrag = objc_lookUpClass("JRSDrag");
 413     if (jrsDrag != nil) {
 414         NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)];
 415         if (rawDragActions != NSDragOperationNone) {
 416             // Both actions and dropAction default to the rawActions
 417             *actions = [DnDUtilities mapNSDragOperationMaskToJava:rawDragActions];
 418             *dropAction = *actions;
 419 
 420             // Get the current key modifiers.
 421             NSUInteger dragModifiers = (NSUInteger) [jrsDrag performSelector:@selector(currentModifiers)];
 422             // Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers
 423             if (dragModifiers) {
 424                 // Get the user selected operation based on the drag modifiers, then return the intersection
 425                 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:dragModifiers];
 426                 NSDragOperation allowedOp = rawDragActions & currentOp;
 427 
 428                 *dropAction = [DnDUtilities mapNSDragOperationToJava:allowedOp];
 429             }
 430         }
 431     }
 432     *dropAction = [DnDUtilities narrowJavaDropActions:*dropAction];
 433 }
 434 
 435 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
 436 {
 437     DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
 438 
 439     sCurrentDropTarget = self;
 440 
 441     JNIEnv* env = [ThreadUtilities getJNIEnv];
 442     NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
 443 
 444     // Set the initial drag operation return value:
 445     NSDragOperation dragOp = NSDragOperationNone;
 446         sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
 447 
 448     // We could probably special-case some stuff if drag and drop objects match:
 449     //if ([sender dragSource] == fView)
 450 
 451     if (draggingSequenceNumber != sDraggingSequenceNumber) {
 452         sDraggingSequenceNumber = draggingSequenceNumber;
 453         sDraggingError = FALSE;
 454 
 455         // Delete any drop target context peer left over from a previous drag:
 456         if (fDropTargetContextPeer != NULL) {
 457             JNFDeleteGlobalRef(env, fDropTargetContextPeer);
 458             fDropTargetContextPeer = NULL;
 459         }
 460 
 461         // Look up the CDropTargetContextPeer class:
 462         JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
 463         if (sDraggingError == FALSE) {
 464             // Create a new drop target context peer:
 465             jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod);
 466 
 467             if (dropTargetContextPeer != nil) {
 468                 fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer);
 469                 (*env)->DeleteLocalRef(env, dropTargetContextPeer);
 470             }
 471         }
 472 
 473         // Get dragging types (dragging data is only copied if dropped):
 474         if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
 475             sDraggingError = TRUE;
 476     }
 477 
 478     if (sDraggingError == FALSE) {
 479         sDraggingExited = FALSE;
 480         sDraggingLocation = [sender draggingLocation];
 481         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 482         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 483 
 484         DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 485 
 486                 ////////// BEGIN Calculate the current drag actions //////////
 487                 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 488         jint dropAction = actions;
 489 
 490                 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 491 
 492                 sJavaDropOperation = dropAction;
 493                 ////////// END Calculate the current drag actions //////////
 494 
 495         jlongArray formats = sDraggingFormats;
 496 
 497         JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
 498         if (sDraggingError == FALSE) {
 499             // Double-casting self gets rid of 'different size' compiler warning:
 500             // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 501             actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod,
 502                                        fComponent, (jint) javaLocation.x, (jint) javaLocation.y,
 503                                        dropAction, actions, formats, ptr_to_jlong(self));
 504         }
 505 
 506         if (sDraggingError == FALSE) {
 507             // Initialize drag operation:
 508             sDragOperation = NSDragOperationNone;
 509 
 510             // Map Java actions back to NSDragOperation.
 511             // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
 512             // (as can be the case with lightweight children) we must not return NSDragOperationNone
 513             // since that would prevent dropping into any of the contained drop targets.
 514             // Unfortunately there is no easy way to test this so we just test actions and override them
 515             // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
 516             // called right away, taking care of setting the right cursor and snap-back action.
 517             dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
 518                 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
 519 
 520             // Remember the dragOp for no-op'd update messages:
 521             sUpdateOperation = dragOp;
 522         }
 523     }
 524 
 525     // 9-11-02 Note: the native event thread would not handle an exception gracefully:
 526     //if (sDraggingError == TRUE)
 527     //    [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."];
 528 
 529     DLog2(@"[CDropTarget draggingEntered]: returning %lu\n", (unsigned long) dragOp);
 530 
 531     return dragOp;
 532 }
 533 
 534 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
 535 {
 536     //DLog2(@"[CDropTarget draggingUpdated]: %@\n", self);
 537 
 538     sCurrentDropTarget = self;
 539 
 540     // Set the initial drag operation return value:
 541     NSDragOperation dragOp = (sDraggingError == FALSE ? sUpdateOperation : NSDragOperationNone);
 542 
 543     // There are two things we would be interested in:
 544     // a) mouse pointer has moved
 545     // b) drag actions (key modifiers) have changed
 546 
 547     NSPoint draggingLocation = [sender draggingLocation];
 548     JNIEnv* env = [ThreadUtilities getJNIEnv];
 549 
 550     BOOL notifyJava = FALSE;
 551 
 552     // a) mouse pointer has moved:
 553     if (NSEqualPoints(draggingLocation, sDraggingLocation) == FALSE) {
 554         //DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self);
 555         sDraggingLocation = draggingLocation;
 556         notifyJava = TRUE;
 557     }
 558 
 559     // b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications):
 560         ////////// BEGIN Calculate the current drag actions //////////
 561         jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 562         jint dropAction = actions;
 563 
 564         [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 565 
 566         if (sJavaDropOperation != dropAction) {
 567             sJavaDropOperation = dropAction;
 568             notifyJava = TRUE;
 569         }
 570         ////////// END Calculate the current drag actions //////////
 571 
 572     jint userAction = dropAction;
 573 
 574     // Should we notify Java things have changed?
 575     if (sDraggingError == FALSE && notifyJava) {
 576         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 577         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 578         //DLog5(@"  : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 579 
 580         jlongArray formats = sDraggingFormats;
 581 
 582         JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
 583         if (sDraggingError == FALSE) {
 584             DLog3(@"  >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
 585             userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 586         }
 587 
 588         if (sDraggingError == FALSE) {
 589             dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
 590 
 591             // Remember the dragOp for no-op'd update messages:
 592             sUpdateOperation = dragOp;
 593         } else {
 594             dragOp = NSDragOperationNone;
 595         }
 596     }
 597 
 598     DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
 599 
 600     return dragOp;
 601 }
 602 
 603 - (void)draggingExited:(id<NSDraggingInfo>)sender
 604 {
 605     DLog2(@"[CDropTarget draggingExited]: %@\n", self);
 606 
 607     sCurrentDropTarget = nil;
 608 
 609     JNIEnv* env = [ThreadUtilities getJNIEnv];
 610 
 611     if (sDraggingExited == FALSE && sDraggingError == FALSE) {
 612         JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
 613         if (sDraggingError == FALSE) {
 614             DLog3(@"  - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
 615              // AWT_THREADING Safe (CToolkitThreadBlockedHandler) 
 616             JNFCallVoidMethod(env, fDropTargetContextPeer,
 617                               handleExitMessageMethod, fComponent, ptr_to_jlong(self));
 618         }
 619 
 620         // 5-27-03 Note: [Radar 3270455]
 621         // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
 622         // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
 623         sDraggingExited = TRUE;
 624     }
 625 
 626     DLog(@"[CDropTarget draggingExited]: returning.\n");
 627 }
 628 
 629 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
 630 {
 631     DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
 632     DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
 633 
 634     return sDraggingError ? NO : YES;
 635 }
 636 
 637 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
 638 {
 639     DLog2(@"[CDropTarget performDragOperation]: %@\n", self);
 640 
 641     sCurrentDropTarget = nil;
 642 
 643     JNIEnv* env = [ThreadUtilities getJNIEnv];
 644 
 645     // Now copy dragging data:
 646     if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
 647         sDraggingError = TRUE;
 648 
 649     if (sDraggingError == FALSE) {
 650         sDraggingLocation = [sender draggingLocation];
 651         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 652         // The y coordinate that comes in the NSDraggingInfo seems to be reversed - probably
 653         // has to do something with the type of view it comes to.
 654         // This is the earliest place where we can correct it.
 655         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 656 
 657         jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
 658         jint dropAction = sJavaDropOperation;
 659 
 660         jlongArray formats = sDraggingFormats;
 661 
 662         JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
 663 
 664         if (sDraggingError == FALSE) {
 665             JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
 666         }
 667 
 668         if (sDraggingError == FALSE) {
 669             JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V");
 670             if (sDraggingError == FALSE) {
 671                 JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode)
 672             }
 673         }
 674     } else {
 675         // 8-19-03 Note: [Radar 3368754]
 676         // draggingExited: is not called after a drop - we must do that here ... but only in case
 677         // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
 678         [self draggingExited:sender];
 679     }
 680 
 681 // TODO:BG
 682 //   [(id)sender _setLastDragDestinationOperation:sDragOperation];
 683 
 684 
 685     DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
 686 
 687     return !sDraggingError;
 688 }
 689 
 690 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender
 691 {
 692     sCurrentDropTarget = nil;
 693 
 694     DLog2(@"[CDropTarget concludeDragOperation]: %@\n", self);
 695     DLog(@"[CDropTarget concludeDragOperation]: returning.\n");
 696 }
 697 
 698 // 9-11-02 Note: draggingEnded is not yet implemented by the AppKit.
 699 - (void)draggingEnded:(id<NSDraggingInfo>)sender
 700 {
 701     sCurrentDropTarget = nil;
 702 
 703     DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
 704     DLog(@"[CDropTarget draggingEnded]: returning.\n");
 705 }
 706 
 707 /********************************  END NSDraggingDestination Interface  ********************************/
 708 
 709 @end
 710 
 711 
 712 /*
 713  * Class:     sun_lwawt_macosx_CDropTarget
 714  * Method:    createNativeDropTarget
 715  * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
 716  */
 717 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
 718   (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer)
 719 {
 720     CDropTarget* dropTarget = nil;
 721 
 722 JNF_COCOA_ENTER(env);
 723     id controlObj = (id) jlong_to_ptr(jnativepeer);
 724     dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj];
 725 JNF_COCOA_EXIT(env);
 726 
 727     if (dropTarget) {
 728         CFRetain(dropTarget); // GC
 729         [dropTarget release];
 730     }
 731     return ptr_to_jlong(dropTarget);
 732 }
 733 
 734 /*
 735  * Class:     sun_lwawt_macosx_CDropTarget
 736  * Method:    releaseNativeDropTarget
 737  * Signature: (J)V
 738  */
 739 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
 740   (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
 741 {
 742     id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
 743 
 744 JNF_COCOA_ENTER(env);
 745     [dropTarget removeFromView:env];
 746 JNF_COCOA_EXIT(env);
 747 }