annotate src/macosx/native/sun/awt/CDropTarget.m @ 7871:d502cc7bcc3d

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