jdk/src/macosx/native/sun/awt/CDropTarget.m
changeset 12047 320a714614e9
child 12416 7f39181f3c6e
equal deleted inserted replaced
12046:378aa3362868 12047:320a714614e9
       
     1 /*
       
     2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 //#define DND_DEBUG TRUE
       
    27 
       
    28 #import "CDropTarget.h"
       
    29 #import "AWTView.h"
       
    30 
       
    31 #import "sun_lwawt_macosx_CDropTarget.h"
       
    32 #import "java_awt_dnd_DnDConstants.h"
       
    33 
       
    34 #import <JavaNativeFoundation/JavaNativeFoundation.h>
       
    35 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
       
    36 #include <objc/objc-runtime.h>
       
    37 
       
    38 
       
    39 #import "CDragSource.h"
       
    40 #import "CDataTransferer.h"
       
    41 #import "DnDUtilities.h"
       
    42 #import "ThreadUtilities.h"
       
    43 
       
    44 
       
    45 static NSInteger        sDraggingSequenceNumber = -1;
       
    46 static NSDragOperation    sDragOperation;
       
    47 static NSDragOperation    sUpdateOperation;
       
    48 static jint                sJavaDropOperation;
       
    49 static NSPoint            sDraggingLocation;
       
    50 static BOOL                sDraggingExited;
       
    51 static BOOL                sDraggingError;
       
    52 
       
    53 static NSUInteger        sPasteboardItemsCount = 0;
       
    54 static NSArray*            sPasteboardTypes = nil;
       
    55 static NSArray*            sPasteboardData = nil;
       
    56 static jlongArray        sDraggingFormats = nil;
       
    57 
       
    58 static CDropTarget*        sCurrentDropTarget;
       
    59 
       
    60 extern JNFClassInfo jc_CDropTargetContextPeer;
       
    61 
       
    62 @implementation CDropTarget
       
    63 
       
    64 + (CDropTarget *) currentDropTarget {
       
    65     return sCurrentDropTarget;
       
    66 }
       
    67 
       
    68 - (id)init:(jobject)jdropTarget component:(jobject)jcomponent peer:(jobject)jpeer control:(id)control
       
    69 {
       
    70     self = [super init];
       
    71     DLog2(@"[CDropTarget init]: %@\n", self);
       
    72 
       
    73     fView = nil;
       
    74     fComponent = nil;
       
    75     fDropTarget = nil;
       
    76     fDropTargetContextPeer = nil;
       
    77 
       
    78 
       
    79     if (control != nil) {
       
    80         JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
       
    81         fComponent = JNFNewGlobalRef(env, jcomponent);
       
    82         fDropTarget = JNFNewGlobalRef(env, jdropTarget);
       
    83 
       
    84         AWTView *awtView = [((NSWindow *) control) contentView];
       
    85         fView = [awtView retain];
       
    86         [awtView setDropTarget:self];
       
    87 
       
    88 
       
    89     } else {
       
    90         // This would be an error.
       
    91         [self release];
       
    92         self = nil;
       
    93     }
       
    94     return self;
       
    95 }
       
    96 
       
    97 // When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel
       
    98 // (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget,
       
    99 // to let it know it's been set up now.
       
   100 - (void)controlModelControlValid
       
   101 {
       
   102     // 9-30-02 Note: [Radar 3065621]
       
   103     // List all known pasteboard types here (see AppKit's NSPasteboard.h)
       
   104     // How to register for non-standard data types remains to be determined.
       
   105     NSArray* dataTypes = [[NSArray alloc] initWithObjects:
       
   106         NSStringPboardType,
       
   107         NSFilenamesPboardType,
       
   108         NSPostScriptPboardType,
       
   109         NSTIFFPboardType,
       
   110         NSRTFPboardType,
       
   111         NSTabularTextPboardType,
       
   112         NSFontPboardType,
       
   113         NSRulerPboardType,
       
   114         NSFileContentsPboardType,
       
   115         NSColorPboardType,
       
   116         NSRTFDPboardType,
       
   117         NSHTMLPboardType,
       
   118         NSURLPboardType,
       
   119         NSPDFPboardType,
       
   120         NSVCardPboardType,
       
   121         NSFilesPromisePboardType,
       
   122         [DnDUtilities javaPboardType],
       
   123         nil];
       
   124 
       
   125     // Enable dragging events over this object:
       
   126     [fView registerForDraggedTypes:dataTypes];
       
   127 
       
   128     [dataTypes release];
       
   129 }
       
   130 
       
   131 - (void)releaseDraggingData
       
   132 {
       
   133     DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self);
       
   134 
       
   135     // Release any old pasteboard types, data and properties:
       
   136     [sPasteboardTypes release];
       
   137     sPasteboardTypes = nil;
       
   138 
       
   139     [sPasteboardData release];
       
   140     sPasteboardData = nil;
       
   141 
       
   142     if (sDraggingFormats != NULL) {
       
   143         JNIEnv *env = [ThreadUtilities getJNIEnv];
       
   144         JNFDeleteGlobalRef(env, sDraggingFormats);
       
   145         sDraggingFormats = NULL;
       
   146     }
       
   147 
       
   148     sPasteboardItemsCount = 0;
       
   149     sDraggingSequenceNumber = -1;
       
   150 }
       
   151 
       
   152 - (void)removeFromView:(JNIEnv *)env
       
   153 {
       
   154     DLog2(@"[CDropTarget removeFromView]: %@\n", self);
       
   155 
       
   156     // Remove this dragging destination from the view:
       
   157     [((AWTView *) fView) setDropTarget:nil];
       
   158 
       
   159     // Clean up JNI refs
       
   160     if (fComponent != NULL) {
       
   161         JNFDeleteGlobalRef(env, fComponent);
       
   162         fComponent = NULL;
       
   163     }
       
   164     if (fDropTarget != NULL) {
       
   165         JNFDeleteGlobalRef(env, fDropTarget);
       
   166         fDropTarget = NULL;
       
   167     }
       
   168     if (fDropTargetContextPeer != NULL) {
       
   169         JNFDeleteGlobalRef(env, fDropTargetContextPeer);
       
   170         fDropTargetContextPeer = NULL;
       
   171     }
       
   172 
       
   173     CFRelease(self);
       
   174 }
       
   175 
       
   176 - (void)dealloc
       
   177 {
       
   178     DLog2(@"[CDropTarget dealloc]: %@\n", self);
       
   179 
       
   180     [fView release];
       
   181     fView = nil;
       
   182 
       
   183     [super dealloc];
       
   184 }
       
   185 //- (void)finalize { [super finalize]; }
       
   186 
       
   187 - (NSInteger) getDraggingSequenceNumber
       
   188 {
       
   189     return sDraggingSequenceNumber;
       
   190 }
       
   191 
       
   192 // Debugging help:
       
   193 - (void)dumpPasteboard:(NSPasteboard*)pasteboard
       
   194 {
       
   195     NSArray* pasteboardTypes = [pasteboard types];
       
   196     NSUInteger pasteboardItemsCount = [pasteboardTypes count];
       
   197     NSUInteger i;
       
   198 
       
   199     // For each flavor on the pasteboard show the type, its data, and its property if there is one:
       
   200     for (i = 0; i < pasteboardItemsCount; i++) {
       
   201         NSString* pbType = [pasteboardTypes objectAtIndex:i];
       
   202         CFShow(pbType);
       
   203 
       
   204         NSData*    pbData = [pasteboard dataForType:pbType];
       
   205         CFShow(pbData);
       
   206 
       
   207         if ([pbType hasPrefix:@"CorePasteboardFlavorType"] == NO) {
       
   208             id pbDataProperty = [pasteboard propertyListForType:pbType];
       
   209             CFShow(pbDataProperty);
       
   210         }
       
   211     }
       
   212 }
       
   213 
       
   214 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
       
   215 {
       
   216     DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
       
   217     JNIEnv*    env = [ThreadUtilities getJNIEnv];
       
   218 
       
   219     // Release any old pasteboard data:
       
   220     [self releaseDraggingData];
       
   221 
       
   222     NSPasteboard* pb = [sender draggingPasteboard];
       
   223     sPasteboardTypes = [[pb types] retain];
       
   224     sPasteboardItemsCount = [sPasteboardTypes count];
       
   225     if (sPasteboardItemsCount == 0)
       
   226         return FALSE;
       
   227 
       
   228     jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
       
   229     if (formats == nil)
       
   230         return FALSE;
       
   231 
       
   232     sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats);
       
   233     (*env)->DeleteLocalRef(env, formats);
       
   234     if (sDraggingFormats == nil)
       
   235         return FALSE;
       
   236 
       
   237     jboolean isCopy;
       
   238     jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
       
   239     if (jformats == nil) {
       
   240         return FALSE;
       
   241     }
       
   242 
       
   243     // Copy all data formats and properties. In case of properties, if they are nil, we need to use
       
   244     // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
       
   245     DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
       
   246     NSUInteger i;
       
   247     for (i = 0; i < sPasteboardItemsCount; i++) {
       
   248         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
       
   249         DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
       
   250 
       
   251         // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
       
   252         // They're often copies of their flavor's data and copying them for all available pasteboard flavors
       
   253         // (which are often auto-translation of one another) can be a significant time/space hit.
       
   254 
       
   255         // If this is a remote object type (not a pre-defined format) register it with the pasteboard:
       
   256         jformats[i] = indexForFormat(pbType);
       
   257         if (jformats[i] == -1 && [pbType hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-remote-object;"])
       
   258             jformats[i] = registerFormatWithPasteboard(pbType);
       
   259     }
       
   260 
       
   261     (*env)->ReleaseLongArrayElements(env, sDraggingFormats, jformats, JNI_COMMIT);
       
   262 
       
   263     return TRUE;
       
   264 }
       
   265 
       
   266 - (BOOL)copyDraggingData:(id<NSDraggingInfo>)sender
       
   267 {
       
   268     DLog2(@"[CDropTarget copyDraggingData]: %@\n", self);
       
   269 
       
   270     sPasteboardData = [[NSMutableArray alloc] init];
       
   271     if (sPasteboardData == nil)
       
   272         return FALSE;
       
   273 
       
   274     // Copy all data items to a safe place since the pasteboard may go away before we'll need them:
       
   275     NSPasteboard* pb = [sender draggingPasteboard];
       
   276     NSUInteger i;
       
   277     for (i = 0; i < sPasteboardItemsCount; i++) {
       
   278         // Get a type and its data and save the data:
       
   279         NSString* pbType = [sPasteboardTypes objectAtIndex:i];
       
   280         // 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit)
       
   281         // would be a good idea since we can't do anything with those CoreFoundation unknown types anyway.
       
   282         // But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder,
       
   283         // to be evaluated later.
       
   284         //id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data!
       
   285         id pbData = [pb dataForType:pbType];
       
   286 
       
   287         // If the data is null we can't store it in the array - an exception would be thrown.
       
   288         // We use the special object NSNull instead which is kosher.
       
   289         if (pbData == nil)
       
   290             pbData = [NSNull null];
       
   291 
       
   292         [((NSMutableArray*) sPasteboardData) addObject:pbData];
       
   293     }
       
   294 
       
   295     return TRUE;
       
   296 }
       
   297 
       
   298 - (NSData*) getDraggingDataForURL:(NSData*)data
       
   299 {
       
   300     NSData* result = nil;
       
   301 
       
   302     // Convert data into a property list if possible:
       
   303     NSPropertyListFormat propertyListFormat;
       
   304     NSString* errorString = nil;
       
   305     id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable
       
   306         format:&propertyListFormat errorDescription:&errorString];
       
   307 
       
   308     // URL types have only a single URL string in an array:
       
   309     if (propertyList != nil && errorString == nil && [propertyList isKindOfClass:[NSArray class]]) {
       
   310         NSArray*  array = (NSArray*) propertyList;
       
   311         if ([array count] > 0) {
       
   312             NSString* url = (NSString*) [array objectAtIndex:0];
       
   313             if (url != nil && [url length] > 0)
       
   314                 result = [url dataUsingEncoding:[url fastestEncoding]];
       
   315         }
       
   316     }
       
   317 
       
   318     return result;
       
   319 }
       
   320 
       
   321 - (jobject) copyDraggingDataForFormat:(jlong)format
       
   322 {
       
   323     JNIEnv*      env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment
       
   324 
       
   325     NSData*      data = nil;
       
   326 
       
   327     // Convert the Java format (datatransferer int index) to a pasteboard format (NSString):
       
   328     NSString* pbType = formatForIndex(format);
       
   329     if ([sPasteboardTypes containsObject:pbType]) {
       
   330         NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
       
   331         data = [sPasteboardData objectAtIndex:dataIndex];
       
   332 
       
   333         if ((id) data == [NSNull null])
       
   334             data = nil;
       
   335 
       
   336         // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
       
   337         else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
       
   338             data = [self getDraggingDataForURL:data];
       
   339     }
       
   340 
       
   341     // Get NS data:
       
   342     char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
       
   343     NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
       
   344 
       
   345     // Create a global byte array:
       
   346     jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
       
   347     if (lbyteArray == nil)
       
   348         return nil;
       
   349     jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray);
       
   350     (*env)->DeleteLocalRef(env, lbyteArray);
       
   351     if (gbyteArray == nil)
       
   352         return nil;
       
   353 
       
   354     // Get byte array elements:
       
   355     jboolean isCopy;
       
   356     jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
       
   357     if (jbytes == nil)
       
   358         return nil;
       
   359 
       
   360     // Copy data to byte array and release elements:
       
   361     memcpy(jbytes, dataBytes, dataLength);
       
   362     (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
       
   363 
       
   364     // In case of an error make sure to return nil:
       
   365     if ((*env)->ExceptionOccurred(env)) {
       
   366                 (*env)->ExceptionDescribe(env);
       
   367         gbyteArray = nil;
       
   368         }
       
   369 
       
   370     return gbyteArray;
       
   371 }
       
   372 
       
   373 - (void)safeReleaseDraggingData:(NSNumber *)arg
       
   374 {
       
   375     jlong draggingSequenceNumber = [arg longLongValue];
       
   376 
       
   377     // Make sure dragging data is released only if no new drag is under way. If a new drag
       
   378     // has been initiated it has released the old dragging data already. This has to be called
       
   379     // on the native event thread - otherwise we'd need to start synchronizing.
       
   380     if (draggingSequenceNumber == sDraggingSequenceNumber)
       
   381         [self releaseDraggingData];
       
   382 }
       
   383 
       
   384 - (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction
       
   385 {
       
   386     NSNumber *draggingSequenceNumberID = [NSNumber numberWithLongLong:draggingSequenceNumber];
       
   387         // Report back actual Swing success, not what AppKit thinks
       
   388         sDraggingError = !jsuccess;
       
   389         sDragOperation = [DnDUtilities mapJavaDragOperationToNS:jdropaction];
       
   390 
       
   391     // Release dragging data if any when Java's AWT event thread is all finished.
       
   392     // Make sure dragging data is released on the native event thread.
       
   393     [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self
       
   394                               withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO];
       
   395 }
       
   396 
       
   397 - (jint)currentJavaActions {
       
   398     return [DnDUtilities mapNSDragOperationToJava:sUpdateOperation];
       
   399 }
       
   400 
       
   401 /********************************  BEGIN NSDraggingDestination Interface  ********************************/
       
   402 
       
   403 
       
   404 // Private API to calculate the current Java actions
       
   405 - (void) calculateCurrentSourceActions:(jint *)actions dropAction:(jint *)dropAction
       
   406 {
       
   407     // Get the raw (unmodified by keys) source actions
       
   408     id jrsDrag = objc_lookUpClass("JRSDrag");
       
   409     if (jrsDrag != nil) {
       
   410         NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)];
       
   411         if (rawDragActions != NSDragOperationNone) {
       
   412             // Both actions and dropAction default to the rawActions
       
   413             *actions = [DnDUtilities mapNSDragOperationMaskToJava:rawDragActions];
       
   414             *dropAction = *actions;
       
   415 
       
   416             // Get the current key modifiers.
       
   417             NSUInteger dragModifiers = (NSUInteger) [jrsDrag performSelector:@selector(currentModifiers)];
       
   418             // Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers
       
   419             if (dragModifiers) {
       
   420                 // Get the user selected operation based on the drag modifiers, then return the intersection
       
   421                 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:dragModifiers];
       
   422                 NSDragOperation allowedOp = rawDragActions & currentOp;
       
   423 
       
   424                 *dropAction = [DnDUtilities mapNSDragOperationToJava:allowedOp];
       
   425             }
       
   426         }
       
   427     }
       
   428     *dropAction = [DnDUtilities narrowJavaDropActions:*dropAction];
       
   429 }
       
   430 
       
   431 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
       
   432 {
       
   433     DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
       
   434 
       
   435     sCurrentDropTarget = self;
       
   436 
       
   437     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   438     NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
       
   439 
       
   440     // Set the initial drag operation return value:
       
   441     NSDragOperation dragOp = NSDragOperationNone;
       
   442         sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   443 
       
   444     // We could probably special-case some stuff if drag and drop objects match:
       
   445     //if ([sender dragSource] == fView)
       
   446 
       
   447     if (draggingSequenceNumber != sDraggingSequenceNumber) {
       
   448         sDraggingSequenceNumber = draggingSequenceNumber;
       
   449         sDraggingError = FALSE;
       
   450 
       
   451         // Delete any drop target context peer left over from a previous drag:
       
   452         if (fDropTargetContextPeer != NULL) {
       
   453             JNFDeleteGlobalRef(env, fDropTargetContextPeer);
       
   454             fDropTargetContextPeer = NULL;
       
   455         }
       
   456 
       
   457         // Look up the CDropTargetContextPeer class:
       
   458         JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
       
   459         if (sDraggingError == FALSE) {
       
   460             // Create a new drop target context peer:
       
   461             jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod);
       
   462 
       
   463             if (dropTargetContextPeer != nil) {
       
   464                 fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer);
       
   465                 (*env)->DeleteLocalRef(env, dropTargetContextPeer);
       
   466             }
       
   467         }
       
   468 
       
   469         // Get dragging types (dragging data is only copied if dropped):
       
   470         if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
       
   471             sDraggingError = TRUE;
       
   472     }
       
   473 
       
   474     if (sDraggingError == FALSE) {
       
   475         sDraggingExited = FALSE;
       
   476         sDraggingLocation = [sender draggingLocation];
       
   477         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
       
   478         DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
       
   479 
       
   480                 ////////// BEGIN Calculate the current drag actions //////////
       
   481                 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   482         jint dropAction = actions;
       
   483 
       
   484                 [self calculateCurrentSourceActions:&actions dropAction:&dropAction];
       
   485 
       
   486                 sJavaDropOperation = dropAction;
       
   487                 ////////// END Calculate the current drag actions //////////
       
   488 
       
   489         jlongArray formats = sDraggingFormats;
       
   490 
       
   491         JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
       
   492         if (sDraggingError == FALSE) {
       
   493             // Double-casting self gets rid of 'different size' compiler warning:
       
   494             actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
       
   495         }
       
   496 
       
   497         if (sDraggingError == FALSE) {
       
   498             // Initialize drag operation:
       
   499             sDragOperation = NSDragOperationNone;
       
   500 
       
   501             // Map Java actions back to NSDragOperation.
       
   502             // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
       
   503             // (as can be the case with lightweight children) we must not return NSDragOperationNone
       
   504             // since that would prevent dropping into any of the contained drop targets.
       
   505             // Unfortunately there is no easy way to test this so we just test actions and override them
       
   506             // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
       
   507             // called right away, taking care of setting the right cursor and snap-back action.
       
   508             dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
       
   509                 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
       
   510 
       
   511             // Remember the dragOp for no-op'd update messages:
       
   512             sUpdateOperation = dragOp;
       
   513         }
       
   514 
       
   515         // If we are in the same process as the sender, make the sender post the appropriate message
       
   516         if (sender) {
       
   517             [[CDragSource currentDragSource] postDragEnter];
       
   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             JNFCallVoidMethod(env, fDropTargetContextPeer, handleExitMessageMethod, fComponent, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
       
   613             // If we are in the same process as the sender, make the sender post the appropriate message
       
   614             if (sender) {
       
   615                 [[CDragSource currentDragSource] postDragExit];
       
   616             }
       
   617         }
       
   618 
       
   619         // 5-27-03 Note: [Radar 3270455]
       
   620         // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
       
   621         // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
       
   622         sDraggingExited = TRUE;
       
   623     }
       
   624 
       
   625     DLog(@"[CDropTarget draggingExited]: returning.\n");
       
   626 }
       
   627 
       
   628 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
       
   629 {
       
   630     DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
       
   631     DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
       
   632 
       
   633     return sDraggingError ? NO : YES;
       
   634 }
       
   635 
       
   636 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
       
   637 {
       
   638     DLog2(@"[CDropTarget performDragOperation]: %@\n", self);
       
   639 
       
   640     sCurrentDropTarget = nil;
       
   641 
       
   642     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   643 
       
   644     // Now copy dragging data:
       
   645     if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
       
   646         sDraggingError = TRUE;
       
   647 
       
   648     if (sDraggingError == FALSE) {
       
   649         sDraggingLocation = [sender draggingLocation];
       
   650         NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
       
   651 
       
   652         jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
       
   653         jint dropAction = sJavaDropOperation;
       
   654 
       
   655         jlongArray formats = sDraggingFormats;
       
   656 
       
   657         JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
       
   658 
       
   659         if (sDraggingError == FALSE) {
       
   660             JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
       
   661         }
       
   662 
       
   663         if (sDraggingError == FALSE) {
       
   664             JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V");
       
   665             if (sDraggingError == FALSE) {
       
   666                 JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode)
       
   667             }
       
   668         }
       
   669     } else {
       
   670         // 8-19-03 Note: [Radar 3368754]
       
   671         // draggingExited: is not called after a drop - we must do that here ... but only in case
       
   672         // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
       
   673         [self draggingExited:sender];
       
   674     }
       
   675 
       
   676 // TODO:BG
       
   677 //   [(id)sender _setLastDragDestinationOperation:sDragOperation];
       
   678 
       
   679 
       
   680     DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
       
   681 
       
   682     return !sDraggingError;
       
   683 }
       
   684 
       
   685 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender
       
   686 {
       
   687     sCurrentDropTarget = nil;
       
   688 
       
   689     DLog2(@"[CDropTarget concludeDragOperation]: %@\n", self);
       
   690     DLog(@"[CDropTarget concludeDragOperation]: returning.\n");
       
   691 }
       
   692 
       
   693 // 9-11-02 Note: draggingEnded is not yet implemented by the AppKit.
       
   694 - (void)draggingEnded:(id<NSDraggingInfo>)sender
       
   695 {
       
   696     sCurrentDropTarget = nil;
       
   697 
       
   698     DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
       
   699     DLog(@"[CDropTarget draggingEnded]: returning.\n");
       
   700 }
       
   701 
       
   702 /********************************  END NSDraggingDestination Interface  ********************************/
       
   703 
       
   704 @end
       
   705 
       
   706 
       
   707 /*
       
   708  * Class:     sun_lwawt_macosx_CDropTarget
       
   709  * Method:    createNativeDropTarget
       
   710  * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
       
   711  */
       
   712 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
       
   713   (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer)
       
   714 {
       
   715     CDropTarget* dropTarget = nil;
       
   716 
       
   717 JNF_COCOA_ENTER(env);
       
   718     id controlObj = (id) jlong_to_ptr(jnativepeer);
       
   719     dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj];
       
   720 JNF_COCOA_EXIT(env);
       
   721 
       
   722     if (dropTarget) {
       
   723         CFRetain(dropTarget); // GC
       
   724         [dropTarget release];
       
   725     }
       
   726     return ptr_to_jlong(dropTarget);
       
   727 }
       
   728 
       
   729 /*
       
   730  * Class:     sun_lwawt_macosx_CDropTarget
       
   731  * Method:    releaseNativeDropTarget
       
   732  * Signature: (J)V
       
   733  */
       
   734 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
       
   735   (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
       
   736 {
       
   737     id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
       
   738 
       
   739 JNF_COCOA_ENTER(env);
       
   740     [dropTarget removeFromView:env];
       
   741 JNF_COCOA_EXIT(env);
       
   742 }