1/* 2 * Copyright (c) 2011, 2012, 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 27/* 28Documentation for Drag and Drop (Radar 3065640) 29There are several problems with Drag and Drop - notably, the mismatch between Java, Cocoa, and Carbon 30 31 Java reports both the original source actions, and the user-selected actions (selected using KB modifiers) to both the source and target during the drag. AppKit only reports to the destination during the drag. This was solved by directly asking CGS for the KB state during the source's image moved callback. 32 33 Java uses Shift/Move, Control/Copy and Shift+Control/Link. AppKit uses Command/Move, Alternate/Copy and Control/Link. Carbon uses Command/Move, Alternate/Copy and Command+Alternate/Link. This is bad, because Control overlaps between Java and AppKit. In this case, we choose compatibility between Carbon and Java (Java wins over AppKit wrt Control). This means that drags between Java applications will work correctly, regardless of whether you use the Carbon or the Java key modifiers. Drags to Java applications will work correctly regardless of whether you use the Carbon or the Java key modifiers. Drags from Java applications to non-Java applications will only work if you use the Carbon modifiers. 34 35 The reason we can't just set the CoreDrag(G/S)etAllowableActions directly (while ignoring the modifier keys) is because Carbon apps traditionally don't pay any attention - they only look at the modifier keys. 36 */ 37 38#import <Cocoa/Cocoa.h> 39#import "DnDUtilities.h" 40#import "java_awt_dnd_DnDConstants.h" 41#import "java_awt_event_InputEvent.h" 42 43@implementation DnDUtilities 44 45// Make sure we don't let other apps see local drags by using a process unique pasteboard type. 46// This may not work in the Applet case, since they are all running in the same VM 47+ (NSString *) javaPboardType { 48 static NSString *customJavaPboardType = nil; 49 if (customJavaPboardType == nil) 50 customJavaPboardType = [[NSString stringWithFormat:@"NSJavaPboardType-%@", [[NSProcessInfo processInfo] globallyUniqueString]] retain]; 51 return customJavaPboardType; 52} 53 54+ (jint)mapNSDragOperationToJava:(NSDragOperation)dragOperation 55{ 56 jint result = java_awt_dnd_DnDConstants_ACTION_NONE; 57 58 if ((dragOperation & NSDragOperationCopy) != 0) // 1 59 result = ((dragOperation & NSDragOperationMove) == 0) ? java_awt_dnd_DnDConstants_ACTION_COPY : java_awt_dnd_DnDConstants_ACTION_COPY_OR_MOVE; 60 61 else if ((dragOperation & NSDragOperationMove) != 0) // 16 62 result = java_awt_dnd_DnDConstants_ACTION_MOVE; 63 64 else if ((dragOperation & NSDragOperationLink) != 0) // 2 65 result = java_awt_dnd_DnDConstants_ACTION_LINK; 66 67 else if ((dragOperation & NSDragOperationGeneric) != 0) // 4 68 result = java_awt_dnd_DnDConstants_ACTION_MOVE; 69 70 // Pre-empted by the above cases: 71 //else if (dragOperation == NSDragOperationEvery) // UINT_MAX 72 // result = java_awt_dnd_DnDConstants_ACTION_COPY_OR_MOVE; 73 74 // To be rejected: 75 //else if ((dragOperation & NSDragOperationPrivate) != 0) // 8 76 //else if ((dragOperation & NSDragOperationAll_Obsolete) != 0) // 15 77 //else if ((dragOperation & NSDragOperationDelete) != 0) // 32 78 79 return result; 80} 81 82+ (jint)mapNSDragOperationMaskToJava:(NSDragOperation)dragOperation 83{ 84 jint result = java_awt_dnd_DnDConstants_ACTION_NONE; 85 86 if (dragOperation & NSDragOperationMove) 87 result |= java_awt_dnd_DnDConstants_ACTION_MOVE; 88 89 if (dragOperation & NSDragOperationCopy) 90 result |= java_awt_dnd_DnDConstants_ACTION_COPY; 91 92 if (dragOperation & NSDragOperationLink) 93 result |= java_awt_dnd_DnDConstants_ACTION_LINK; 94 95 // Only look at Generic if none of the other options are specified 96 if ( (dragOperation & NSDragOperationGeneric) && !(dragOperation & (NSDragOperationMove|NSDragOperationCopy|NSDragOperationLink)) ) 97 result |= java_awt_dnd_DnDConstants_ACTION_MOVE; 98 99 return result; 100} 101 102+ (jint)narrowJavaDropActions:(jint)actions 103{ 104 if (YES) { 105 // Order is defined in the java.awt.dnd.DropTargetDropEvent JavaDoc 106 if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) { 107 return java_awt_dnd_DnDConstants_ACTION_MOVE; 108 } 109 if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) { 110 return java_awt_dnd_DnDConstants_ACTION_COPY; 111 } 112 if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) { 113 return java_awt_dnd_DnDConstants_ACTION_LINK; 114 } 115 } else { 116 // Order is what is most intuitive on Mac OS X 117 if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) { 118 return java_awt_dnd_DnDConstants_ACTION_COPY; 119 } 120 if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) { 121 return java_awt_dnd_DnDConstants_ACTION_LINK; 122 } 123 if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) { 124 return java_awt_dnd_DnDConstants_ACTION_MOVE; 125 } 126 } 127 128 return java_awt_dnd_DnDConstants_ACTION_NONE; 129} 130 131+ (NSDragOperation)mapJavaDragOperationToNS:(jint)dragOperation 132{ 133 NSDragOperation result = NSDragOperationNone; 134 135 switch (dragOperation) { 136 case java_awt_dnd_DnDConstants_ACTION_NONE: // 0 137 result = NSDragOperationNone; 138 break; 139 case java_awt_dnd_DnDConstants_ACTION_COPY: // 1 140 result = NSDragOperationCopy; 141 break; 142 case java_awt_dnd_DnDConstants_ACTION_MOVE: // 2 143 result = NSDragOperationMove; 144 break; 145 case java_awt_dnd_DnDConstants_ACTION_COPY_OR_MOVE: // 3 146 result = NSDragOperationCopy | NSDragOperationMove; 147 break; 148 case java_awt_dnd_DnDConstants_ACTION_LINK: // 1073741824L 149 result = NSDragOperationLink; 150 break; 151 case (java_awt_dnd_DnDConstants_ACTION_COPY_OR_MOVE | java_awt_dnd_DnDConstants_ACTION_LINK): 152 result = NSDragOperationCopy | NSDragOperationMove | NSDragOperationLink; 153 break; 154 } 155 156 if (result != NSDragOperationNone) { 157 result |= NSDragOperationGeneric; 158 } 159 160 return result; 161} 162 163// Mouse and key modifiers mapping: 164+ (NSUInteger)mapJavaExtModifiersToNSMouseDownButtons:(jint)modifiers 165{ 166 NSUInteger result = NSLeftMouseDown; 167 168 if ((modifiers & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) != 0) 169 result = NSLeftMouseDown; 170 171 if ((modifiers & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) != 0) 172 result = NSOtherMouseDown; 173 174 if ((modifiers & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) != 0) 175 result = NSRightMouseDown; 176 177 return result; 178} 179 180+ (NSUInteger)mapJavaExtModifiersToNSMouseUpButtons:(jint)modifiers 181{ 182 NSUInteger result = NSLeftMouseUp; 183 184 if ((modifiers & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) != 0) 185 result = NSLeftMouseUp; 186 187 if ((modifiers & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) != 0) 188 result = NSOtherMouseUp; 189 190 if ((modifiers & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) != 0) 191 result = NSRightMouseUp; 192 193 return result; 194} 195 196 197// Specialized key modifiers mappings (for DragSource.operationChanged) 198 199// Returns just the key modifiers from a java modifier flag 200+ (jint)extractJavaExtKeyModifiersFromJavaExtModifiers:(jint)modifiers 201{ 202 // Build the mask 203 static jint mask = java_awt_event_InputEvent_SHIFT_DOWN_MASK | java_awt_event_InputEvent_CTRL_DOWN_MASK | java_awt_event_InputEvent_META_DOWN_MASK | java_awt_event_InputEvent_ALT_DOWN_MASK; 204 //static int mask = java_awt_event_InputEvent_SHIFT_DOWN_MASK | java_awt_event_InputEvent_CTRL_DOWN_MASK; 205 206 // Get results 207 jint result = modifiers & mask; 208 209 // Java appears to have 2 ALT buttons - combine them. 210 if (modifiers & java_awt_event_InputEvent_ALT_GRAPH_DOWN_MASK) 211 result |= java_awt_event_InputEvent_ALT_DOWN_MASK; 212 213 return result; 214} 215 216// Returns just the mouse modifiers from a java modifier flag 217+ (jint)extractJavaExtMouseModifiersFromJavaExtModifiers:(jint)modifiers 218{ 219 // Build the mask 220 static jint mask = java_awt_event_InputEvent_BUTTON1_DOWN_MASK | java_awt_event_InputEvent_BUTTON2_DOWN_MASK | java_awt_event_InputEvent_BUTTON3_DOWN_MASK; 221 222 // Get results 223 return modifiers & mask; 224} 225 226+ (NSDragOperation) nsDragOperationForModifiers:(NSUInteger)modifiers { 227 228 // Java first 229 if ( (modifiers & NSShiftKeyMask) && (modifiers & NSControlKeyMask) ) { 230 return NSDragOperationLink; 231 } 232 if (modifiers & NSShiftKeyMask) { 233 return NSDragOperationMove; 234 } 235 if (modifiers & NSControlKeyMask) { 236 return NSDragOperationCopy; 237 } 238 239 // Then native 240 if ( (modifiers & NSCommandKeyMask) && (modifiers & NSAlternateKeyMask) ) { 241 return NSDragOperationLink; 242 } 243 if (modifiers & NSCommandKeyMask) { 244 return NSDragOperationMove; 245 } 246 if (modifiers & NSAlternateKeyMask) { 247 return NSDragOperationCopy; 248 } 249 250 // Otherwise, we allow anything 251 return NSDragOperationEvery; 252} 253 254+ (jint) javaKeyModifiersForNSDragOperation:(NSDragOperation)dragOperation { 255 if (dragOperation & NSDragOperationMove) 256 return java_awt_event_InputEvent_SHIFT_DOWN_MASK; 257 258 if (dragOperation & NSDragOperationCopy) 259 return java_awt_event_InputEvent_CTRL_DOWN_MASK; 260 261 if (dragOperation & NSDragOperationLink) { 262 return java_awt_event_InputEvent_SHIFT_DOWN_MASK | java_awt_event_InputEvent_CTRL_DOWN_MASK; 263 } 264 return 0; 265} 266 267@end 268