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         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         NSRTFPboardType,
 110         NSTabularTextPboardType,
 111         NSFontPboardType,
 112         NSRulerPboardType,
 113         NSFileContentsPboardType,
 114         NSColorPboardType,
 115         NSRTFDPboardType,
 116         NSHTMLPboardType,
 117         NSURLPboardType,
 118         NSPDFPboardType,
 119         NSVCardPboardType,
 120         NSFilesPromisePboardType,
 121         [DnDUtilities javaPboardType],
 122         nil];
 123 
 124     // Enable dragging events over this object:
 125     [fView registerForDraggedTypes:dataTypes];
 126 
 127     [dataTypes release];
 128 }
 129 
 130 - (void)releaseDraggingData
 131 {
 132     DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self);
 133 
 134     // Release any old pasteboard types, data and properties:
 135     [sPasteboardTypes release];
 136     sPasteboardTypes = nil;
 137 
 138     [sPasteboardData release];
 139     sPasteboardData = nil;
 140 
 141     if (sDraggingFormats != NULL) {
 142         JNIEnv *env = [ThreadUtilities getJNIEnv];
 143         JNFDeleteGlobalRef(env, sDraggingFormats);
 144         sDraggingFormats = NULL;
 145     }
 146 
 147     sPasteboardItemsCount = 0;
 148     sDraggingSequenceNumber = -1;
 149 }
 150 
 151 - (void)removeFromView:(JNIEnv *)env
 152 {
 153     DLog2(@"[CDropTarget removeFromView]: %@\n", self);
 154 
 155     // Remove this dragging destination from the view:
 156     [((AWTView *) fView) setDropTarget:nil];
 157 
 158     // Clean up JNI refs
 159     if (fComponent != NULL) {
 160         JNFDeleteGlobalRef(env, fComponent);
 161         fComponent = NULL;
 162     }
 163     if (fDropTarget != NULL) {
 164         JNFDeleteGlobalRef(env, fDropTarget);
 165         fDropTarget = NULL;
 166     }
 167     if (fDropTargetContextPeer != NULL) {
 168         JNFDeleteGlobalRef(env, fDropTargetContextPeer);
 169         fDropTargetContextPeer = NULL;
 170     }
 171 
 172     CFRelease(self);
 173 }
 174 
 175 - (void)dealloc
 176 {
 177     DLog2(@"[CDropTarget dealloc]: %@\n", self);
 178 
 179     if(sCurrentDropTarget == self) {
 180         sCurrentDropTarget = nil;
 181     }
 182 
 183     [fView release];
 184     fView = nil;
 185 
 186     [super dealloc];
 187 }
 188 //- (void)finalize { [super finalize]; }
 189 
 190 - (NSInteger) getDraggingSequenceNumber
 191 {
 192     return sDraggingSequenceNumber;
 193 }
 194 
 195 // Debugging help:
 196 - (void)dumpPasteboard:(NSPasteboard*)pasteboard
 197 {
 198     NSArray* pasteboardTypes = [pasteboard types];
 199     NSUInteger pasteboardItemsCount = [pasteboardTypes count];
 200     NSUInteger i;
 201 
 202     // For each flavor on the pasteboard show the type, its data, and its property if there is one:
 203     for (i = 0; i < pasteboardItemsCount; i++) {
 204         NSString* pbType = [pasteboardTypes objectAtIndex:i];
 205         CFShow(pbType);
 206 
 207         NSData*    pbData = [pasteboard dataForType:pbType];
 208         CFShow(pbData);
 209 
 210         if ([pbType hasPrefix:@"CorePasteboardFlavorType"] == NO) {
 211             id pbDataProperty = [pasteboard propertyListForType:pbType];
 212             CFShow(pbDataProperty);
 213         }
 214     }
 215 }
 216 
 217 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
 218 {
 219     DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
 220     JNIEnv*    env = [ThreadUtilities getJNIEnv];
 221 
 222     // Release any old pasteboard data:
 223     [self releaseDraggingData];
 224 
 225     NSPasteboard* pb = [sender draggingPasteboard];
 226     sPasteboardTypes = [[pb types] retain];
 227     sPasteboardItemsCount = [sPasteboardTypes count];
 228     if (sPasteboardItemsCount == 0)
 229         return FALSE;
 230 
 231     jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
 232     if (formats == nil)
 233         return FALSE;
 234 
 235     sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats);
 236     (*env)->DeleteLocalRef(env, formats);
 237     if (sDraggingFormats == nil)
 238         return FALSE;
 239 
 240     jboolean isCopy;
 241     jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
 242     if (jformats == nil) {
 243         return FALSE;
 244     }
 245 
 246     // Copy all data formats and properties. In case of properties, if they are nil, we need to use
 247     // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
 248     DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
 249     NSUInteger i;
 250     for (i = 0; i < sPasteboardItemsCount; i++) {
 251         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
 252         DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
 253 
 254         // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
 255         // They're often copies of their flavor's data and copying them for all available pasteboard flavors
 256         // (which are often auto-translation of one another) can be a significant time/space hit.
 257 
 258         // If this is a remote object type (not a pre-defined format) register it with the pasteboard:
 259         jformats[i] = indexForFormat(pbType);
 260         if (jformats[i] == -1 && [pbType hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-remote-object;"])
 261             jformats[i] = registerFormatWithPasteboard(pbType);
 262     }
 263 
 264     (*env)->ReleaseLongArrayElements(env, sDraggingFormats, jformats, JNI_COMMIT);
 265 
 266     return TRUE;
 267 }
 268 
 269 - (BOOL)copyDraggingData:(id<NSDraggingInfo>)sender
 270 {
 271     DLog2(@"[CDropTarget copyDraggingData]: %@\n", self);
 272 
 273     sPasteboardData = [[NSMutableArray alloc] init];
 274     if (sPasteboardData == nil)
 275         return FALSE;
 276 
 277     // Copy all data items to a safe place since the pasteboard may go away before we'll need them:
 278     NSPasteboard* pb = [sender draggingPasteboard];
 279     NSUInteger i;
 280     for (i = 0; i < sPasteboardItemsCount; i++) {
 281         // Get a type and its data and save the data:
 282         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
 283         // 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit)
 284         // would be a good idea since we can't do anything with those CoreFoundation unknown types anyway.
 285         // But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder,
 286         // to be evaluated later.
 287         //id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data!
 288         id pbData = [pb dataForType:pbType];
 289 
 290         // If the data is null we can't store it in the array - an exception would be thrown.
 291         // We use the special object NSNull instead which is kosher.
 292         if (pbData == nil)
 293             pbData = [NSNull null];
 294 
 295         [((NSMutableArray*) sPasteboardData) addObject:pbData];
 296     }
 297 
 298     return TRUE;
 299 }
 300 
 301 - (NSData*) getDraggingDataForURL:(NSData*)data
 302 {
 303     NSData* result = nil;
 304 
 305     // Convert data into a property list if possible:
 306     NSPropertyListFormat propertyListFormat;
 307     NSString* errorString = nil;
 308     id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable
 309         format:&propertyListFormat errorDescription:&errorString];
 310 
 311     // URL types have only a single URL string in an array:
 312     if (propertyList != nil && errorString == nil && [propertyList isKindOfClass:[NSArray class]]) {
 313         NSArray*  array = (NSArray*) propertyList;
 314         if ([array count] > 0) {
 315             NSString* url = (NSString*) [array objectAtIndex:0];
 316             if (url != nil && [url length] > 0)
 317                 result = [url dataUsingEncoding:[url fastestEncoding]];
 318         }
 319     }
 320 
 321     return result;
 322 }
 323 
 324 - (jobject) copyDraggingDataForFormat:(jlong)format
 325 {
 326     JNIEnv*      env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment
 327 
 328     NSData*      data = nil;
 329 
 330     // Convert the Java format (datatransferer int index) to a pasteboard format (NSString):
 331     NSString* pbType = formatForIndex(format);
 332     if ([sPasteboardTypes containsObject:pbType]) {
 333         NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
 334         data = [sPasteboardData objectAtIndex:dataIndex];
 335 
 336         if ((id) data == [NSNull null])
 337             data = nil;
 338 
 339         // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
 340         else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
 341             data = [self getDraggingDataForURL:data];
 342     }
 343 
 344     // Get NS data:
 345     char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
 346     NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
 347 
 348     // Create a global byte array:
 349     jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
 350     if (lbyteArray == nil)
 351         return nil;
 352     jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray);
 353     (*env)->DeleteLocalRef(env, lbyteArray);
 354     if (gbyteArray == nil)
 355         return nil;
 356 
 357     // Get byte array elements:
 358     jboolean isCopy;
 359     jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
 360     if (jbytes == nil)
 361         return nil;
 362 
 363     // Copy data to byte array and release elements:
 364     memcpy(jbytes, dataBytes, dataLength);
 365     (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
 366 
 367     // In case of an error make sure to return nil:
 368     if ((*env)->ExceptionOccurred(env)) {
 369                 (*env)->ExceptionDescribe(env);
 370         gbyteArray = nil;
 371         }
 372 
 373     return gbyteArray;
 374 }
 375 
 376 - (void)safeReleaseDraggingData:(NSNumber *)arg
 377 {
 378     jlong draggingSequenceNumber = [arg longLongValue];
 379 
 380     // Make sure dragging data is released only if no new drag is under way. If a new drag
 381     // has been initiated it has released the old dragging data already. This has to be called
 382     // on the native event thread - otherwise we'd need to start synchronizing.
 383     if (draggingSequenceNumber == sDraggingSequenceNumber)
 384         [self releaseDraggingData];
 385 }
 386 
 387 - (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction
 388 {
 389     NSNumber *draggingSequenceNumberID = [NSNumber numberWithLongLong:draggingSequenceNumber];
 390         // Report back actual Swing success, not what AppKit thinks
 391         sDraggingError = !jsuccess;
 392         sDragOperation = [DnDUtilities mapJavaDragOperationToNS:jdropaction];
 393 
 394     // Release dragging data if any when Java's AWT event thread is all finished.
 395     // Make sure dragging data is released on the native event thread.
 396     [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) on:self withObject:draggingSequenceNumberID waitUntilDone:NO];
 397 }
 398 
 399 - (jint)currentJavaActions {
 400     return [DnDUtilities mapNSDragOperationToJava:sUpdateOperation];
 401 }
 402 
 403 /********************************  BEGIN NSDraggingDestination Interface  ********************************/
 404 
 405 
 406 // Private API to calculate the current Java actions
 407 - (void) calculateCurrentSourceActions:(jint *)actions dropAction:(jint *)dropAction
 408 {
 409     // Get the raw (unmodified by keys) source actions
 410     id jrsDrag = objc_lookUpClass("JRSDrag");
 411     if (jrsDrag != nil) {
 412         NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)];
 413         if (rawDragActions != NSDragOperationNone) {
 414             // Both actions and dropAction default to the rawActions
 415             *actions = [DnDUtilities mapNSDragOperationMaskToJava:rawDragActions];
 416             *dropAction = *actions;
 417 
 418             // Get the current key modifiers.
 419             NSUInteger dragModifiers = (NSUInteger) [jrsDrag performSelector:@selector(currentModifiers)];
 420             // Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers
 421             if (dragModifiers) {
 422                 // Get the user selected operation based on the drag modifiers, then return the intersection
 423                 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:dragModifiers];
 424                 NSDragOperation allowedOp = rawDragActions & currentOp;
 425 
 426                 *dropAction = [DnDUtilities mapNSDragOperationToJava:allowedOp];
 427             }
 428         }
 429     }
 430     *dropAction = [DnDUtilities narrowJavaDropActions:*dropAction];
 431 }
 432 
 433 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
 434 {
 435     DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
 436 
 437     sCurrentDropTarget = self;
 438 
 439     JNIEnv* env = [ThreadUtilities getJNIEnv];
 440     NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
 441 
 442     // Set the initial drag operation return value:
 443     NSDragOperation dragOp = NSDragOperationNone;
 444         sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
 445 
 446     // We could probably special-case some stuff if drag and drop objects match:
 447     //if ([sender dragSource] == fView)
 448 
 449     if (draggingSequenceNumber != sDraggingSequenceNumber) {
 450         sDraggingSequenceNumber = draggingSequenceNumber;
 451         sDraggingError = FALSE;
 452 
 453         // Delete any drop target context peer left over from a previous drag:
 454         if (fDropTargetContextPeer != NULL) {
 455             JNFDeleteGlobalRef(env, fDropTargetContextPeer);
 456             fDropTargetContextPeer = NULL;
 457         }
 458 
 459         // Look up the CDropTargetContextPeer class:
 460         JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
 461         if (sDraggingError == FALSE) {
 462             // Create a new drop target context peer:
 463             jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod);
 464 
 465             if (dropTargetContextPeer != nil) {
 466                 fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer);
 467                 (*env)->DeleteLocalRef(env, dropTargetContextPeer);
 468             }
 469         }
 470 
 471         // Get dragging types (dragging data is only copied if dropped):
 472         if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
 473             sDraggingError = TRUE;
 474     }
 475 
 476     if (sDraggingError == FALSE) {
 477         sDraggingExited = FALSE;
 478         sDraggingLocation = [sender draggingLocation];
 479         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 480         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 481 
 482         DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 483 
 484                 ////////// BEGIN Calculate the current drag actions //////////
 485                 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 486         jint dropAction = actions;
 487 
 488                 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 489 
 490                 sJavaDropOperation = dropAction;
 491                 ////////// END Calculate the current drag actions //////////
 492 
 493         jlongArray formats = sDraggingFormats;
 494 
 495         JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
 496         if (sDraggingError == FALSE) {
 497             // Double-casting self gets rid of 'different size' compiler warning:
 498             // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 499             actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod,
 500                                        fComponent, (jint) javaLocation.x, (jint) javaLocation.y,
 501                                        dropAction, actions, formats, ptr_to_jlong(self));
 502         }
 503 
 504         if (sDraggingError == FALSE) {
 505             // Initialize drag operation:
 506             sDragOperation = NSDragOperationNone;
 507 
 508             // Map Java actions back to NSDragOperation.
 509             // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
 510             // (as can be the case with lightweight children) we must not return NSDragOperationNone
 511             // since that would prevent dropping into any of the contained drop targets.
 512             // Unfortunately there is no easy way to test this so we just test actions and override them
 513             // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
 514             // called right away, taking care of setting the right cursor and snap-back action.
 515             dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
 516                 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
 517 
 518             // Remember the dragOp for no-op'd update messages:
 519             sUpdateOperation = dragOp;
 520         }
 521     }
 522 
 523     // 9-11-02 Note: the native event thread would not handle an exception gracefully:
 524     //if (sDraggingError == TRUE)
 525     //    [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."];
 526 
 527     DLog2(@"[CDropTarget draggingEntered]: returning %lu\n", (unsigned long) dragOp);
 528 
 529     return dragOp;
 530 }
 531 
 532 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
 533 {
 534     //DLog2(@"[CDropTarget draggingUpdated]: %@\n", self);
 535 
 536     sCurrentDropTarget = self;
 537 
 538     // Set the initial drag operation return value:
 539     NSDragOperation dragOp = (sDraggingError == FALSE ? sUpdateOperation : NSDragOperationNone);
 540 
 541     // There are two things we would be interested in:
 542     // a) mouse pointer has moved
 543     // b) drag actions (key modifiers) have changed
 544 
 545     NSPoint draggingLocation = [sender draggingLocation];
 546     JNIEnv* env = [ThreadUtilities getJNIEnv];
 547 
 548     BOOL notifyJava = FALSE;
 549 
 550     // a) mouse pointer has moved:
 551     if (NSEqualPoints(draggingLocation, sDraggingLocation) == FALSE) {
 552         //DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self);
 553         sDraggingLocation = draggingLocation;
 554         notifyJava = TRUE;
 555     }
 556 
 557     // b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications):
 558         ////////// BEGIN Calculate the current drag actions //////////
 559         jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 560         jint dropAction = actions;
 561 
 562         [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 563 
 564         if (sJavaDropOperation != dropAction) {
 565             sJavaDropOperation = dropAction;
 566             notifyJava = TRUE;
 567         }
 568         ////////// END Calculate the current drag actions //////////
 569 
 570     jint userAction = dropAction;
 571 
 572     // Should we notify Java things have changed?
 573     if (sDraggingError == FALSE && notifyJava) {
 574         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 575         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 576         //DLog5(@"  : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 577 
 578         jlongArray formats = sDraggingFormats;
 579 
 580         JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
 581         if (sDraggingError == FALSE) {
 582             DLog3(@"  >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
 583             userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 584         }
 585 
 586         if (sDraggingError == FALSE) {
 587             dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
 588 
 589             // Remember the dragOp for no-op'd update messages:
 590             sUpdateOperation = dragOp;
 591         } else {
 592             dragOp = NSDragOperationNone;
 593         }
 594     }
 595 
 596     DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
 597 
 598     return dragOp;
 599 }
 600 
 601 - (void)draggingExited:(id<NSDraggingInfo>)sender
 602 {
 603     DLog2(@"[CDropTarget draggingExited]: %@\n", self);
 604 
 605     sCurrentDropTarget = nil;
 606 
 607     JNIEnv* env = [ThreadUtilities getJNIEnv];
 608 
 609     if (sDraggingExited == FALSE && sDraggingError == FALSE) {
 610         JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
 611         if (sDraggingError == FALSE) {
 612             DLog3(@"  - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
 613              // AWT_THREADING Safe (CToolkitThreadBlockedHandler) 
 614             JNFCallVoidMethod(env, fDropTargetContextPeer,
 615                               handleExitMessageMethod, fComponent, ptr_to_jlong(self));
 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 }