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