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