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         DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 481 
 482                 ////////// BEGIN Calculate the current drag actions //////////
 483                 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 484         jint dropAction = actions;
 485 
 486                 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 487 
 488                 sJavaDropOperation = dropAction;
 489                 ////////// END Calculate the current drag actions //////////
 490 
 491         jlongArray formats = sDraggingFormats;
 492 
 493         JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
 494         if (sDraggingError == FALSE) {
 495             // Double-casting self gets rid of 'different size' compiler warning:
 496             // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 497             actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod,
 498                                        fComponent, (jint) javaLocation.x, (jint) javaLocation.y,
 499                                        dropAction, actions, formats, ptr_to_jlong(self));
 500         }
 501 
 502         if (sDraggingError == FALSE) {
 503             // Initialize drag operation:
 504             sDragOperation = NSDragOperationNone;
 505 
 506             // Map Java actions back to NSDragOperation.
 507             // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
 508             // (as can be the case with lightweight children) we must not return NSDragOperationNone
 509             // since that would prevent dropping into any of the contained drop targets.
 510             // Unfortunately there is no easy way to test this so we just test actions and override them
 511             // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
 512             // called right away, taking care of setting the right cursor and snap-back action.
 513             dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
 514                 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
 515 
 516             // Remember the dragOp for no-op'd update messages:
 517             sUpdateOperation = dragOp;
 518         }
 519     }
 520 
 521     // 9-11-02 Note: the native event thread would not handle an exception gracefully:
 522     //if (sDraggingError == TRUE)
 523     //    [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."];
 524 
 525     DLog2(@"[CDropTarget draggingEntered]: returning %lu\n", (unsigned long) dragOp);
 526 
 527     return dragOp;
 528 }
 529 
 530 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
 531 {
 532     //DLog2(@"[CDropTarget draggingUpdated]: %@\n", self);
 533 
 534     sCurrentDropTarget = self;
 535 
 536     // Set the initial drag operation return value:
 537     NSDragOperation dragOp = (sDraggingError == FALSE ? sUpdateOperation : NSDragOperationNone);
 538 
 539     // There are two things we would be interested in:
 540     // a) mouse pointer has moved
 541     // b) drag actions (key modifiers) have changed
 542 
 543     NSPoint draggingLocation = [sender draggingLocation];
 544     JNIEnv* env = [ThreadUtilities getJNIEnv];
 545 
 546     BOOL notifyJava = FALSE;
 547 
 548     // a) mouse pointer has moved:
 549     if (NSEqualPoints(draggingLocation, sDraggingLocation) == FALSE) {
 550         //DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self);
 551         sDraggingLocation = draggingLocation;
 552         notifyJava = TRUE;
 553     }
 554 
 555     // b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications):
 556         ////////// BEGIN Calculate the current drag actions //////////
 557         jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
 558         jint dropAction = actions;
 559 
 560         [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
 561 
 562         if (sJavaDropOperation != dropAction) {
 563             sJavaDropOperation = dropAction;
 564             notifyJava = TRUE;
 565         }
 566         ////////// END Calculate the current drag actions //////////
 567 
 568     jint userAction = dropAction;
 569 
 570     // Should we notify Java things have changed?
 571     if (sDraggingError == FALSE && notifyJava) {
 572         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 573                 // For some reason even after the convertPoint drag events come with the y coordinate reverted
 574                 javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 575         //DLog5(@"  : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
 576 
 577         jlongArray formats = sDraggingFormats;
 578 
 579         JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
 580         if (sDraggingError == FALSE) {
 581             DLog3(@"  >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
 582             userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
 583         }
 584 
 585         if (sDraggingError == FALSE) {
 586             dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
 587 
 588             // Remember the dragOp for no-op'd update messages:
 589             sUpdateOperation = dragOp;
 590         } else {
 591             dragOp = NSDragOperationNone;
 592         }
 593     }
 594 
 595     DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
 596 
 597     return dragOp;
 598 }
 599 
 600 - (void)draggingExited:(id<NSDraggingInfo>)sender
 601 {
 602     DLog2(@"[CDropTarget draggingExited]: %@\n", self);
 603 
 604     sCurrentDropTarget = nil;
 605 
 606     JNIEnv* env = [ThreadUtilities getJNIEnv];
 607 
 608     if (sDraggingExited == FALSE && sDraggingError == FALSE) {
 609         JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
 610         if (sDraggingError == FALSE) {
 611             DLog3(@"  - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
 612              // AWT_THREADING Safe (CToolkitThreadBlockedHandler) 
 613             JNFCallVoidMethod(env, fDropTargetContextPeer,
 614                               handleExitMessageMethod, fComponent, ptr_to_jlong(self));
 615         }
 616 
 617         // 5-27-03 Note: [Radar 3270455]
 618         // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
 619         // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
 620         sDraggingExited = TRUE;
 621     }
 622 
 623     DLog(@"[CDropTarget draggingExited]: returning.\n");
 624 }
 625 
 626 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
 627 {
 628     DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
 629     DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
 630 
 631     return sDraggingError ? NO : YES;
 632 }
 633 
 634 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
 635 {
 636     DLog2(@"[CDropTarget performDragOperation]: %@\n", self);
 637 
 638     sCurrentDropTarget = nil;
 639 
 640     JNIEnv* env = [ThreadUtilities getJNIEnv];
 641 
 642     // Now copy dragging data:
 643     if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
 644         sDraggingError = TRUE;
 645 
 646     if (sDraggingError == FALSE) {
 647         sDraggingLocation = [sender draggingLocation];
 648         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
 649         // The y coordinate that comes in the NSDraggingInfo seems to be reversed - probably
 650         // has to do something with the type of view it comes to.
 651         // This is the earliest place where we can correct it.
 652         javaLocation.y = fView.window.frame.size.height - javaLocation.y;
 653 
 654         jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
 655         jint dropAction = sJavaDropOperation;
 656 
 657         jlongArray formats = sDraggingFormats;
 658 
 659         JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
 660 
 661         if (sDraggingError == FALSE) {
 662             JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
 663         }
 664 
 665         if (sDraggingError == FALSE) {
 666             JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V");
 667             if (sDraggingError == FALSE) {
 668                 JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode)
 669             }
 670         }
 671     } else {
 672         // 8-19-03 Note: [Radar 3368754]
 673         // draggingExited: is not called after a drop - we must do that here ... but only in case
 674         // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
 675         [self draggingExited:sender];
 676     }
 677 
 678 // TODO:BG
 679 //   [(id)sender _setLastDragDestinationOperation:sDragOperation];
 680 
 681 
 682     DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
 683 
 684     return !sDraggingError;
 685 }
 686 
 687 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender
 688 {
 689     sCurrentDropTarget = nil;
 690 
 691     DLog2(@"[CDropTarget concludeDragOperation]: %@\n", self);
 692     DLog(@"[CDropTarget concludeDragOperation]: returning.\n");
 693 }
 694 
 695 // 9-11-02 Note: draggingEnded is not yet implemented by the AppKit.
 696 - (void)draggingEnded:(id<NSDraggingInfo>)sender
 697 {
 698     sCurrentDropTarget = nil;
 699 
 700     DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
 701     DLog(@"[CDropTarget draggingEnded]: returning.\n");
 702 }
 703 
 704 /********************************  END NSDraggingDestination Interface  ********************************/
 705 
 706 @end
 707 
 708 
 709 /*
 710  * Class:     sun_lwawt_macosx_CDropTarget
 711  * Method:    createNativeDropTarget
 712  * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
 713  */
 714 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
 715   (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer)
 716 {
 717     CDropTarget* dropTarget = nil;
 718 
 719 JNF_COCOA_ENTER(env);
 720     id controlObj = (id) jlong_to_ptr(jnativepeer);
 721     dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj];
 722 JNF_COCOA_EXIT(env);
 723 
 724     if (dropTarget) {
 725         CFRetain(dropTarget); // GC
 726         [dropTarget release];
 727     }
 728     return ptr_to_jlong(dropTarget);
 729 }
 730 
 731 /*
 732  * Class:     sun_lwawt_macosx_CDropTarget
 733  * Method:    releaseNativeDropTarget
 734  * Signature: (J)V
 735  */
 736 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
 737   (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
 738 {
 739     id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
 740 
 741 JNF_COCOA_ENTER(env);
 742     [dropTarget removeFromView:env];
 743 JNF_COCOA_EXIT(env);
 744 }