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