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