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