CDropTarget.m revision 4830
3832N/A/*
3832N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3832N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3832N/A *
3832N/A * This code is free software; you can redistribute it and/or modify it
3832N/A * under the terms of the GNU General Public License version 2 only, as
3832N/A * published by the Free Software Foundation. Oracle designates this
3832N/A * particular file as subject to the "Classpath" exception as provided
3832N/A * by Oracle in the LICENSE file that accompanied this code.
3832N/A *
3832N/A * This code is distributed in the hope that it will be useful, but WITHOUT
3832N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3832N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3832N/A * version 2 for more details (a copy is included in the LICENSE file that
3832N/A * accompanied this code).
3832N/A *
3832N/A * You should have received a copy of the GNU General Public License version
3832N/A * 2 along with this work; if not, write to the Free Software Foundation,
3832N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3832N/A *
3832N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3832N/A * or visit www.oracle.com if you need additional information or have any
3832N/A * questions.
3832N/A */
5061N/A
3832N/A//#define DND_DEBUG TRUE
3832N/A
4458N/A#import "CDropTarget.h"
3832N/A#import "AWTView.h"
3832N/A
3832N/A#import "sun_lwawt_macosx_CDropTarget.h"
3832N/A#import "java_awt_dnd_DnDConstants.h"
4692N/A
4692N/A#import <JavaNativeFoundation/JavaNativeFoundation.h>
4776N/A#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
4776N/A#include <objc/objc-runtime.h>
4776N/A
4776N/A
4776N/A#import "CDragSource.h"
4692N/A#import "CDataTransferer.h"
4692N/A#import "DnDUtilities.h"
4692N/A#import "ThreadUtilities.h"
4692N/A
4776N/A
4776N/Astatic NSInteger sDraggingSequenceNumber = -1;
4776N/Astatic NSDragOperation sDragOperation;
4692N/Astatic NSDragOperation sUpdateOperation;
4692N/Astatic jint sJavaDropOperation;
4692N/Astatic NSPoint sDraggingLocation;
4692N/Astatic BOOL sDraggingExited;
4692N/Astatic BOOL sDraggingError;
4692N/A
3832N/Astatic NSUInteger sPasteboardItemsCount = 0;
3832N/Astatic NSArray* sPasteboardTypes = nil;
5061N/Astatic NSArray* sPasteboardData = nil;
3832N/Astatic jlongArray sDraggingFormats = nil;
5061N/A
3832N/Astatic CDropTarget* sCurrentDropTarget;
4458N/A
4458N/Aextern JNFClassInfo jc_CDropTargetContextPeer;
4458N/A
4458N/A@implementation CDropTarget
4458N/A
4458N/A+ (CDropTarget *) currentDropTarget {
4458N/A return sCurrentDropTarget;
4458N/A}
3832N/A
4458N/A- (id)init:(jobject)jdropTarget component:(jobject)jcomponent peer:(jobject)jpeer control:(id)control
3832N/A{
3832N/A self = [super init];
4458N/A DLog2(@"[CDropTarget init]: %@\n", self);
3832N/A
5061N/A fView = nil;
3832N/A fComponent = nil;
4458N/A fDropTarget = nil;
4458N/A fDropTargetContextPeer = nil;
4458N/A
5061N/A
5061N/A if (control != nil) {
5061N/A JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
5061N/A fComponent = JNFNewGlobalRef(env, jcomponent);
5061N/A fDropTarget = JNFNewGlobalRef(env, jdropTarget);
5061N/A
5061N/A AWTView *awtView = [((NSWindow *) control) contentView];
5061N/A fView = [awtView retain];
5061N/A [awtView setDropTarget:self];
4458N/A
4458N/A
3832N/A } else {
4458N/A // This would be an error.
3832N/A [self release];
3832N/A self = nil;
3832N/A }
3832N/A return self;
3832N/A}
3832N/A
3832N/A// When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel
4458N/A// (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget,
4458N/A// to let it know it's been set up now.
4458N/A- (void)controlModelControlValid
4458N/A{
4458N/A // 9-30-02 Note: [Radar 3065621]
4458N/A // List all known pasteboard types here (see AppKit's NSPasteboard.h)
4458N/A // How to register for non-standard data types remains to be determined.
4458N/A NSArray* dataTypes = [[NSArray alloc] initWithObjects:
4458N/A NSStringPboardType,
4458N/A NSFilenamesPboardType,
3832N/A NSPostScriptPboardType,
3832N/A NSTIFFPboardType,
3832N/A NSRTFPboardType,
3832N/A NSTabularTextPboardType,
4259N/A NSFontPboardType,
3832N/A NSRulerPboardType,
3832N/A NSFileContentsPboardType,
4714N/A NSColorPboardType,
3832N/A NSRTFDPboardType,
4714N/A NSHTMLPboardType,
3832N/A NSURLPboardType,
3832N/A NSPDFPboardType,
3832N/A NSVCardPboardType,
3832N/A NSFilesPromisePboardType,
3832N/A [DnDUtilities javaPboardType],
4714N/A nil];
3832N/A
4714N/A // Enable dragging events over this object:
3832N/A [fView registerForDraggedTypes:dataTypes];
3832N/A
3832N/A [dataTypes release];
3832N/A}
4458N/A
4458N/A- (void)releaseDraggingData
3832N/A{
3832N/A DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self);
3832N/A
4458N/A // Release any old pasteboard types, data and properties:
4458N/A [sPasteboardTypes release];
4458N/A sPasteboardTypes = nil;
4458N/A
4458N/A [sPasteboardData release];
4458N/A sPasteboardData = nil;
4458N/A
4458N/A if (sDraggingFormats != NULL) {
4458N/A JNIEnv *env = [ThreadUtilities getJNIEnv];
4458N/A JNFDeleteGlobalRef(env, sDraggingFormats);
4458N/A sDraggingFormats = NULL;
3832N/A }
4458N/A
3832N/A sPasteboardItemsCount = 0;
4458N/A sDraggingSequenceNumber = -1;
4458N/A}
4458N/A
4458N/A- (void)removeFromView:(JNIEnv *)env
4458N/A{
4458N/A DLog2(@"[CDropTarget removeFromView]: %@\n", self);
4495N/A
4458N/A // Remove this dragging destination from the view:
4495N/A [((AWTView *) fView) setDropTarget:nil];
4458N/A
4458N/A // Clean up JNI refs
4458N/A if (fComponent != NULL) {
4458N/A JNFDeleteGlobalRef(env, fComponent);
4458N/A fComponent = NULL;
4458N/A }
4458N/A if (fDropTarget != NULL) {
4458N/A JNFDeleteGlobalRef(env, fDropTarget);
4495N/A fDropTarget = NULL;
4458N/A }
4495N/A if (fDropTargetContextPeer != NULL) {
4458N/A JNFDeleteGlobalRef(env, fDropTargetContextPeer);
4458N/A fDropTargetContextPeer = NULL;
4458N/A }
4458N/A
4458N/A CFRelease(self);
4495N/A}
4495N/A
4495N/A- (void)dealloc
4495N/A{
4495N/A DLog2(@"[CDropTarget dealloc]: %@\n", self);
4495N/A
4495N/A [fView release];
4495N/A fView = nil;
4495N/A
4495N/A [super dealloc];
4495N/A}
4714N/A//- (void)finalize { [super finalize]; }
4714N/A
4714N/A- (NSInteger) getDraggingSequenceNumber
4714N/A{
4495N/A return sDraggingSequenceNumber;
4495N/A}
4458N/A
4458N/A// Debugging help:
4458N/A- (void)dumpPasteboard:(NSPasteboard*)pasteboard
4458N/A{
4458N/A NSArray* pasteboardTypes = [pasteboard types];
4458N/A NSUInteger pasteboardItemsCount = [pasteboardTypes count];
4458N/A NSUInteger i;
4458N/A
4458N/A // For each flavor on the pasteboard show the type, its data, and its property if there is one:
4458N/A for (i = 0; i < pasteboardItemsCount; i++) {
4458N/A NSString* pbType = [pasteboardTypes objectAtIndex:i];
4458N/A CFShow(pbType);
4495N/A
4458N/A NSData* pbData = [pasteboard dataForType:pbType];
4458N/A CFShow(pbData);
4458N/A
4458N/A if ([pbType hasPrefix:@"CorePasteboardFlavorType"] == NO) {
4458N/A id pbDataProperty = [pasteboard propertyListForType:pbType];
4458N/A CFShow(pbDataProperty);
4458N/A }
4458N/A }
4458N/A}
3832N/A
3832N/A- (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender
4458N/A{
4458N/A DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self);
4458N/A JNIEnv* env = [ThreadUtilities getJNIEnv];
4458N/A
4458N/A // Release any old pasteboard data:
4458N/A [self releaseDraggingData];
4458N/A
4458N/A NSPasteboard* pb = [sender draggingPasteboard];
5061N/A sPasteboardTypes = [[pb types] retain];
5061N/A sPasteboardItemsCount = [sPasteboardTypes count];
4458N/A if (sPasteboardItemsCount == 0)
4458N/A return FALSE;
4495N/A
5061N/A jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount);
5061N/A if (formats == nil)
4458N/A return FALSE;
4458N/A
4458N/A sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats);
4495N/A (*env)->DeleteLocalRef(env, formats);
4495N/A if (sDraggingFormats == nil)
4495N/A return FALSE;
4495N/A
4458N/A jboolean isCopy;
4458N/A jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy);
4458N/A if (jformats == nil) {
4458N/A return FALSE;
4458N/A }
4458N/A
4458N/A // Copy all data formats and properties. In case of properties, if they are nil, we need to use
4458N/A // a special NilProperty since [NSArray addObject] would crash on adding a nil object.
4458N/A DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
4458N/A NSUInteger i;
4458N/A for (i = 0; i < sPasteboardItemsCount; i++) {
4458N/A NSString* pbType = [sPasteboardTypes objectAtIndex:i];
4458N/A DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType);
4458N/A
4458N/A // 01-10-03 Note: until we need data properties for doing something useful don't copy them.
4458N/A // They're often copies of their flavor's data and copying them for all available pasteboard flavors
4458N/A // (which are often auto-translation of one another) can be a significant time/space hit.
4458N/A
4458N/A // If this is a remote object type (not a pre-defined format) register it with the pasteboard:
4458N/A jformats[i] = indexForFormat(pbType);
4458N/A if (jformats[i] == -1 && [pbType hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-remote-object;"])
4458N/A jformats[i] = registerFormatWithPasteboard(pbType);
4458N/A }
4458N/A
4458N/A (*env)->ReleaseLongArrayElements(env, sDraggingFormats, jformats, JNI_COMMIT);
4458N/A
4458N/A return TRUE;
4458N/A}
4458N/A
4458N/A- (BOOL)copyDraggingData:(id<NSDraggingInfo>)sender
4458N/A{
4458N/A DLog2(@"[CDropTarget copyDraggingData]: %@\n", self);
4458N/A
4458N/A sPasteboardData = [[NSMutableArray alloc] init];
4458N/A if (sPasteboardData == nil)
4458N/A return FALSE;
4458N/A
4458N/A // Copy all data items to a safe place since the pasteboard may go away before we'll need them:
4458N/A NSPasteboard* pb = [sender draggingPasteboard];
4458N/A NSUInteger i;
4458N/A for (i = 0; i < sPasteboardItemsCount; i++) {
4458N/A // Get a type and its data and save the data:
4458N/A NSString* pbType = [sPasteboardTypes objectAtIndex:i];
4458N/A // 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit)
4458N/A // would be a good idea since we can't do anything with those CoreFoundation unknown types anyway.
4458N/A // But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder,
4458N/A // to be evaluated later.
4458N/A //id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data!
4458N/A id pbData = [pb dataForType:pbType];
4458N/A
4458N/A // If the data is null we can't store it in the array - an exception would be thrown.
4458N/A // We use the special object NSNull instead which is kosher.
3832N/A if (pbData == nil)
3832N/A pbData = [NSNull null];
3832N/A
4458N/A [((NSMutableArray*) sPasteboardData) addObject:pbData];
3832N/A }
4458N/A
4458N/A return TRUE;
4458N/A}
4458N/A
4458N/A- (NSData*) getDraggingDataForURL:(NSData*)data
4458N/A{
4458N/A NSData* result = nil;
4458N/A
4495N/A // Convert data into a property list if possible:
4495N/A NSPropertyListFormat propertyListFormat;
4495N/A NSString* errorString = nil;
4495N/A id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable
4495N/A format:&propertyListFormat errorDescription:&errorString];
4495N/A
4495N/A // URL types have only a single URL string in an array:
4495N/A if (propertyList != nil && errorString == nil && [propertyList isKindOfClass:[NSArray class]]) {
4495N/A NSArray* array = (NSArray*) propertyList;
4458N/A if ([array count] > 0) {
4458N/A NSString* url = (NSString*) [array objectAtIndex:0];
4458N/A if (url != nil && [url length] > 0)
4458N/A result = [url dataUsingEncoding:[url fastestEncoding]];
4458N/A }
4458N/A }
4458N/A
4458N/A return result;
4458N/A}
4458N/A
4458N/A- (jobject) copyDraggingDataForFormat:(jlong)format
4458N/A{
3832N/A JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment
4458N/A
4458N/A NSData* data = nil;
4458N/A
4458N/A // Convert the Java format (datatransferer int index) to a pasteboard format (NSString):
4458N/A NSString* pbType = formatForIndex(format);
4458N/A if ([sPasteboardTypes containsObject:pbType]) {
4458N/A NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType];
4458N/A data = [sPasteboardData objectAtIndex:dataIndex];
4458N/A
4458N/A if ((id) data == [NSNull null])
4458N/A data = nil;
4458N/A
4458N/A // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
4458N/A else if ([pbType isEqualToString:@"Apple URL pasteboard type"])
4458N/A data = [self getDraggingDataForURL:data];
4458N/A }
4458N/A
4458N/A // Get NS data:
4458N/A char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type";
4458N/A NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type");
4458N/A
4458N/A // Create a global byte array:
4458N/A jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength);
3832N/A if (lbyteArray == nil)
3832N/A return nil;
4458N/A jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray);
4458N/A (*env)->DeleteLocalRef(env, lbyteArray);
4458N/A if (gbyteArray == nil)
4458N/A return nil;
4458N/A
4495N/A // Get byte array elements:
4458N/A jboolean isCopy;
4458N/A jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy);
4495N/A if (jbytes == nil)
4458N/A return nil;
4458N/A
4458N/A // Copy data to byte array and release elements:
4458N/A memcpy(jbytes, dataBytes, dataLength);
4458N/A (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT);
4458N/A
4458N/A // In case of an error make sure to return nil:
4458N/A if ((*env)->ExceptionOccurred(env)) {
4458N/A (*env)->ExceptionDescribe(env);
4495N/A gbyteArray = nil;
4458N/A }
4458N/A
4458N/A return gbyteArray;
5061N/A}
4458N/A
5061N/A- (void)safeReleaseDraggingData:(NSNumber *)arg
5061N/A{
4458N/A jlong draggingSequenceNumber = [arg longLongValue];
4458N/A
4458N/A // Make sure dragging data is released only if no new drag is under way. If a new drag
4458N/A // has been initiated it has released the old dragging data already. This has to be called
4458N/A // on the native event thread - otherwise we'd need to start synchronizing.
4458N/A if (draggingSequenceNumber == sDraggingSequenceNumber)
4495N/A [self releaseDraggingData];
4458N/A}
4978N/A
5061N/A- (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction
5061N/A{
3832N/A NSNumber *draggingSequenceNumberID = [NSNumber numberWithLongLong:draggingSequenceNumber];
3832N/A // Report back actual Swing success, not what AppKit thinks
4458N/A sDraggingError = !jsuccess;
3832N/A sDragOperation = [DnDUtilities mapJavaDragOperationToNS:jdropaction];
3832N/A
3832N/A // Release dragging data if any when Java's AWT event thread is all finished.
3832N/A // Make sure dragging data is released on the native event thread.
3832N/A [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self
3832N/A withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO];
3832N/A}
3832N/A
3832N/A- (jint)currentJavaActions {
3832N/A return [DnDUtilities mapNSDragOperationToJava:sUpdateOperation];
3832N/A}
3832N/A
3832N/A/******************************** BEGIN NSDraggingDestination Interface ********************************/
3832N/A
3832N/A
3832N/A// Private API to calculate the current Java actions
4645N/A- (void) calculateCurrentSourceActions:(jint *)actions dropAction:(jint *)dropAction
3832N/A{
3832N/A // Get the raw (unmodified by keys) source actions
3832N/A id jrsDrag = objc_lookUpClass("JRSDrag");
3832N/A if (jrsDrag != nil) {
3832N/A NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)];
3832N/A if (rawDragActions != NSDragOperationNone) {
4645N/A // Both actions and dropAction default to the rawActions
3832N/A *actions = [DnDUtilities mapNSDragOperationMaskToJava:rawDragActions];
3832N/A *dropAction = *actions;
3832N/A
3832N/A // Get the current key modifiers.
4645N/A NSUInteger dragModifiers = (NSUInteger) [jrsDrag performSelector:@selector(currentModifiers)];
3832N/A // Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers
3832N/A if (dragModifiers) {
4645N/A // Get the user selected operation based on the drag modifiers, then return the intersection
3832N/A NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:dragModifiers];
4645N/A NSDragOperation allowedOp = rawDragActions & currentOp;
4645N/A
4645N/A *dropAction = [DnDUtilities mapNSDragOperationToJava:allowedOp];
4645N/A }
4645N/A }
4645N/A }
4645N/A *dropAction = [DnDUtilities narrowJavaDropActions:*dropAction];
4645N/A}
4645N/A
4645N/A- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
4645N/A{
4645N/A DLog2(@"[CDropTarget draggingEntered]: %@\n", self);
4645N/A
4645N/A sCurrentDropTarget = self;
3832N/A
4645N/A JNIEnv* env = [ThreadUtilities getJNIEnv];
3832N/A NSInteger draggingSequenceNumber = [sender draggingSequenceNumber];
4645N/A
4645N/A // Set the initial drag operation return value:
4645N/A NSDragOperation dragOp = NSDragOperationNone;
4645N/A sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE;
3832N/A
3832N/A // We could probably special-case some stuff if drag and drop objects match:
3832N/A //if ([sender dragSource] == fView)
4645N/A
4645N/A if (draggingSequenceNumber != sDraggingSequenceNumber) {
4645N/A sDraggingSequenceNumber = draggingSequenceNumber;
3832N/A sDraggingError = FALSE;
4645N/A
3832N/A // Delete any drop target context peer left over from a previous drag:
3832N/A if (fDropTargetContextPeer != NULL) {
JNFDeleteGlobalRef(env, fDropTargetContextPeer);
fDropTargetContextPeer = NULL;
}
// Look up the CDropTargetContextPeer class:
JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
if (sDraggingError == FALSE) {
// Create a new drop target context peer:
jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod);
if (dropTargetContextPeer != nil) {
fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer);
(*env)->DeleteLocalRef(env, dropTargetContextPeer);
}
}
// Get dragging types (dragging data is only copied if dropped):
if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE)
sDraggingError = TRUE;
}
if (sDraggingError == FALSE) {
sDraggingExited = FALSE;
sDraggingLocation = [sender draggingLocation];
NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
////////// BEGIN Calculate the current drag actions //////////
jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
jint dropAction = actions;
[self calculateCurrentSourceActions:&actions dropAction:&dropAction];
sJavaDropOperation = dropAction;
////////// END Calculate the current drag actions //////////
jlongArray formats = sDraggingFormats;
JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
if (sDraggingError == FALSE) {
// Double-casting self gets rid of 'different size' compiler warning:
actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
}
if (sDraggingError == FALSE) {
// Initialize drag operation:
sDragOperation = NSDragOperationNone;
// Map Java actions back to NSDragOperation.
// 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
// (as can be the case with lightweight children) we must not return NSDragOperationNone
// since that would prevent dropping into any of the contained drop targets.
// Unfortunately there is no easy way to test this so we just test actions and override them
// with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
// called right away, taking care of setting the right cursor and snap-back action.
dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ?
[DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric);
// Remember the dragOp for no-op'd update messages:
sUpdateOperation = dragOp;
}
// If we are in the same process as the sender, make the sender post the appropriate message
if (sender) {
[[CDragSource currentDragSource] postDragEnter];
}
}
// 9-11-02 Note: the native event thread would not handle an exception gracefully:
//if (sDraggingError == TRUE)
// [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."];
DLog2(@"[CDropTarget draggingEntered]: returning %lu\n", (unsigned long) dragOp);
return dragOp;
}
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
{
//DLog2(@"[CDropTarget draggingUpdated]: %@\n", self);
sCurrentDropTarget = self;
// Set the initial drag operation return value:
NSDragOperation dragOp = (sDraggingError == FALSE ? sUpdateOperation : NSDragOperationNone);
// There are two things we would be interested in:
// a) mouse pointer has moved
// b) drag actions (key modifiers) have changed
NSPoint draggingLocation = [sender draggingLocation];
JNIEnv* env = [ThreadUtilities getJNIEnv];
BOOL notifyJava = FALSE;
// a) mouse pointer has moved:
if (NSEqualPoints(draggingLocation, sDraggingLocation) == FALSE) {
//DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self);
sDraggingLocation = draggingLocation;
notifyJava = TRUE;
}
// b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications):
////////// BEGIN Calculate the current drag actions //////////
jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
jint dropAction = actions;
[self calculateCurrentSourceActions:&actions dropAction:&dropAction];
if (sJavaDropOperation != dropAction) {
sJavaDropOperation = dropAction;
notifyJava = TRUE;
}
////////// END Calculate the current drag actions //////////
jint userAction = dropAction;
// Should we notify Java things have changed?
if (sDraggingError == FALSE && notifyJava) {
NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
// For some reason even after the convertPoint drag events come with the y coordinate reverted
javaLocation.y = fView.window.frame.size.height - javaLocation.y;
//DLog5(@" : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
jlongArray formats = sDraggingFormats;
JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
if (sDraggingError == FALSE) {
DLog3(@" >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y);
userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
}
if (sDraggingError == FALSE) {
dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction];
// Remember the dragOp for no-op'd update messages:
sUpdateOperation = dragOp;
} else {
dragOp = NSDragOperationNone;
}
}
DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp);
return dragOp;
}
- (void)draggingExited:(id<NSDraggingInfo>)sender
{
DLog2(@"[CDropTarget draggingExited]: %@\n", self);
sCurrentDropTarget = nil;
JNIEnv* env = [ThreadUtilities getJNIEnv];
if (sDraggingExited == FALSE && sDraggingError == FALSE) {
JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
if (sDraggingError == FALSE) {
DLog3(@" - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y);
JNFCallVoidMethod(env, fDropTargetContextPeer, handleExitMessageMethod, fComponent, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
// If we are in the same process as the sender, make the sender post the appropriate message
if (sender) {
[[CDragSource currentDragSource] postDragExit];
}
}
// 5-27-03 Note: [Radar 3270455]
// -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
// twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
sDraggingExited = TRUE;
}
DLog(@"[CDropTarget draggingExited]: returning.\n");
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self);
DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
return sDraggingError ? NO : YES;
}
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
{
DLog2(@"[CDropTarget performDragOperation]: %@\n", self);
sCurrentDropTarget = nil;
JNIEnv* env = [ThreadUtilities getJNIEnv];
// Now copy dragging data:
if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE)
sDraggingError = TRUE;
if (sDraggingError == FALSE) {
sDraggingLocation = [sender draggingLocation];
NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil];
// The y coordinate that comes in the NSDraggingInfo seems to be reversed - probably
// has to do something with the type of view it comes to.
// This is the earliest place where we can correct it.
javaLocation.y = fView.window.frame.size.height - javaLocation.y;
jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]];
jint dropAction = sJavaDropOperation;
jlongArray formats = sDraggingFormats;
JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
if (sDraggingError == FALSE) {
JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
}
if (sDraggingError == FALSE) {
JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V");
if (sDraggingError == FALSE) {
JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode)
}
}
} else {
// 8-19-03 Note: [Radar 3368754]
// draggingExited: is not called after a drop - we must do that here ... but only in case
// of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
[self draggingExited:sender];
}
// TODO:BG
// [(id)sender _setLastDragDestinationOperation:sDragOperation];
DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES"));
return !sDraggingError;
}
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender
{
sCurrentDropTarget = nil;
DLog2(@"[CDropTarget concludeDragOperation]: %@\n", self);
DLog(@"[CDropTarget concludeDragOperation]: returning.\n");
}
// 9-11-02 Note: draggingEnded is not yet implemented by the AppKit.
- (void)draggingEnded:(id<NSDraggingInfo>)sender
{
sCurrentDropTarget = nil;
DLog2(@"[CDropTarget draggingEnded]: %@\n", self);
DLog(@"[CDropTarget draggingEnded]: returning.\n");
}
/******************************** END NSDraggingDestination Interface ********************************/
@end
/*
* Class: sun_lwawt_macosx_CDropTarget
* Method: createNativeDropTarget
* Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget
(JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer)
{
CDropTarget* dropTarget = nil;
JNF_COCOA_ENTER(env);
id controlObj = (id) jlong_to_ptr(jnativepeer);
dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj];
JNF_COCOA_EXIT(env);
if (dropTarget) {
CFRetain(dropTarget); // GC
[dropTarget release];
}
return ptr_to_jlong(dropTarget);
}
/*
* Class: sun_lwawt_macosx_CDropTarget
* Method: releaseNativeDropTarget
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget
(JNIEnv *env, jobject jthis, jlong nativeDropTargetVal)
{
id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal);
JNF_COCOA_ENTER(env);
[dropTarget removeFromView:env];
JNF_COCOA_EXIT(env);
}