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