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