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