Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/awt/CDragSource.m
41152 views
1
/*
2
* Copyright (c) 2011, 2017, 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 "java_awt_dnd_DnDConstants.h"
29
30
#import <Cocoa/Cocoa.h>
31
32
#import "AWTEvent.h"
33
#import "AWTView.h"
34
#import "CDataTransferer.h"
35
#import "CDropTarget.h"
36
#import "CDragSource.h"
37
#import "DnDUtilities.h"
38
#import "ThreadUtilities.h"
39
#import "LWCToolkit.h"
40
#import "JNIUtilities.h"
41
42
43
// When sIsJavaDragging is true Java drag gesture has been recognized and a drag is/has been initialized.
44
// We must stop posting MouseEvent.MOUSE_DRAGGED events for the duration of the drag or all hell will break
45
// loose in shared code - tracking state going haywire.
46
static BOOL sIsJavaDragging;
47
48
49
@interface NSEvent(AWTAdditions)
50
51
+ (void)javaDraggingBegin;
52
+ (void)javaDraggingEnd;
53
54
@end
55
56
57
@implementation NSEvent(AWTAdditions)
58
59
60
+ (void)javaDraggingBegin
61
{
62
sIsJavaDragging = YES;
63
}
64
65
+ (void)javaDraggingEnd
66
{
67
// sIsJavaDragging is reset on mouseDown as well.
68
sIsJavaDragging = NO;
69
}
70
@end
71
72
static jclass DataTransfererClass = NULL;
73
static jclass CDragSourceContextPeerClass = NULL;
74
75
#define GET_DT_CLASS() \
76
GET_CLASS(DataTransfererClass, "sun/awt/datatransfer/DataTransferer");
77
78
#define GET_DT_CLASS_RETURN(ret) \
79
GET_CLASS_RETURN(DataTransfererClass, "sun/awt/datatransfer/DataTransferer", ret);
80
81
#define GET_DSCP_CLASS() \
82
GET_CLASS(CDragSourceContextPeerClass, "sun/lwawt/macosx/CDragSourceContextPeer");
83
84
static NSDragOperation sDragOperation;
85
static NSPoint sDraggingLocation;
86
87
static BOOL sNeedsEnter;
88
89
@interface CDragSource ()
90
// Updates from the destination to the source
91
- (void) postDragEnter;
92
- (void) postDragExit;
93
// Utility
94
- (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint) point;
95
@end
96
97
@implementation CDragSource
98
99
- (id) init:(jobject)jDragSourceContextPeer
100
component:(jobject)jComponent
101
control:(id)control
102
transferable:(jobject)jTransferable
103
triggerEvent:(jobject)jTrigger
104
dragPosX:(jint)dragPosX
105
dragPosY:(jint)dragPosY
106
modifiers:(jint)extModifiers
107
clickCount:(jint)clickCount
108
timeStamp:(jlong)timeStamp
109
dragImage:(jlong)nsDragImagePtr
110
dragImageOffsetX:(jint)jDragImageOffsetX
111
dragImageOffsetY:(jint)jDragImageOffsetY
112
sourceActions:(jint)jSourceActions
113
formats:(jlongArray)jFormats
114
formatMap:(jobject)jFormatMap
115
{
116
self = [super init];
117
DLog2(@"[CDragSource init]: %@\n", self);
118
119
fView = nil;
120
fComponent = nil;
121
122
// Construct the object if we have a valid model for it:
123
if (control != nil) {
124
fComponent = jComponent;
125
fDragSourceContextPeer = jDragSourceContextPeer;
126
fTransferable = jTransferable;
127
fTriggerEvent = jTrigger;
128
129
if (nsDragImagePtr) {
130
fDragImage = (NSImage*) jlong_to_ptr(nsDragImagePtr);
131
[fDragImage retain];
132
}
133
134
fDragImageOffset = NSMakePoint(jDragImageOffsetX, jDragImageOffsetY);
135
136
fSourceActions = jSourceActions;
137
fFormats = jFormats;
138
fFormatMap = jFormatMap;
139
140
fTriggerEventTimeStamp = timeStamp;
141
fDragPos = NSMakePoint(dragPosX, dragPosY);
142
fClickCount = clickCount;
143
fModifiers = extModifiers;
144
145
// Set this object as a dragging source:
146
147
fView = [(AWTView *) control retain];
148
[fView setDragSource:self];
149
150
// Let AWTEvent know Java drag is getting underway:
151
[NSEvent javaDraggingBegin];
152
}
153
154
else {
155
[self release];
156
self = nil;
157
}
158
159
return self;
160
}
161
162
- (void)removeFromView:(JNIEnv *)env
163
{
164
DLog2(@"[CDragSource removeFromView]: %@\n", self);
165
166
// Remove this dragging source from the view:
167
[((AWTView *) fView) setDragSource:nil];
168
169
// Clean up JNI refs
170
if (fComponent != NULL) {
171
(*env)->DeleteGlobalRef(env, fComponent);
172
fComponent = NULL;
173
}
174
175
if (fDragSourceContextPeer != NULL) {
176
(*env)->DeleteGlobalRef(env, fDragSourceContextPeer);
177
fDragSourceContextPeer = NULL;
178
}
179
180
if (fTransferable != NULL) {
181
(*env)->DeleteGlobalRef(env, fTransferable);
182
fTransferable = NULL;
183
}
184
185
if (fTriggerEvent != NULL) {
186
(*env)->DeleteGlobalRef(env, fTriggerEvent);
187
fTriggerEvent = NULL;
188
}
189
190
if (fFormats != NULL) {
191
(*env)->DeleteGlobalRef(env, fFormats);
192
fFormats = NULL;
193
}
194
195
if (fFormatMap != NULL) {
196
(*env)->DeleteGlobalRef(env, fFormatMap);
197
fFormatMap = NULL;
198
}
199
200
[self release];
201
}
202
203
- (void)dealloc
204
{
205
DLog2(@"[CDragSource dealloc]: %@\n", self);
206
207
// Delete or release local data:
208
[fView release];
209
fView = nil;
210
211
[fDragImage release];
212
fDragImage = nil;
213
214
[super dealloc];
215
}
216
217
// Appropriated from Windows' awt_DataTransferer.cpp:
218
//
219
// * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
220
//
221
- (jobject)dataTransferer:(JNIEnv*)env
222
{
223
GET_DT_CLASS_RETURN(NULL);
224
DECLARE_STATIC_METHOD_RETURN(getInstanceMethod, DataTransfererClass, "getInstance", "()Lsun/awt/datatransfer/DataTransferer;", NULL);
225
jobject o = (*env)->CallStaticObjectMethod(env, DataTransfererClass, getInstanceMethod);
226
CHECK_EXCEPTION();
227
return o;
228
}
229
230
// Appropriated from Windows' awt_DataTransferer.cpp:
231
//
232
// * NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
233
//
234
- (jbyteArray)convertData:(jlong)format
235
{
236
JNIEnv* env = [ThreadUtilities getJNIEnv];
237
jobject transferer = [self dataTransferer:env];
238
jbyteArray data = nil;
239
240
if (transferer != NULL) {
241
GET_DT_CLASS_RETURN(NULL);
242
DECLARE_METHOD_RETURN(convertDataMethod, DataTransfererClass, "convertData", "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B", NULL);
243
data = (*env)->CallObjectMethod(env, transferer, convertDataMethod, fComponent, fTransferable, format, fFormatMap, (jboolean) TRUE);
244
}
245
CHECK_EXCEPTION();
246
247
return data;
248
}
249
250
251
// Encodes a byte array of zero-terminated filenames into an NSArray of NSStrings representing them.
252
// Borrowed and adapted from awt_DataTransferer.c, convertFileType().
253
- (id)getFileList:(jbyte *)jbytes dataLength:(jsize)jbytesLength
254
{
255
jsize strings = 0;
256
jsize i;
257
258
// Get number of filenames while making sure to skip over empty strings.
259
for (i = 1; i < jbytesLength; i++) {
260
if (jbytes[i] == '\0' && jbytes[i - 1] != '\0')
261
strings++;
262
}
263
264
// Create the file list to return:
265
NSMutableArray* fileList = [NSMutableArray arrayWithCapacity:strings];
266
267
for (i = 0; i < jbytesLength; i++) {
268
char* start = (char *) &jbytes[i];
269
270
// Skip over empty strings:
271
if (start[0] == '\0') {
272
continue;
273
}
274
275
// Update the position marker:
276
i += strlen(start);
277
278
// Add this filename to the file list:
279
NSMutableString* fileName = [NSMutableString stringWithUTF8String:start];
280
// Decompose the filename
281
CFStringNormalize((CFMutableStringRef)fileName, kCFStringNormalizationFormD);
282
[fileList addObject:fileName];
283
}
284
285
// 03-01-09 Note: keep this around for debugging.
286
// return [NSArray arrayWithObjects:@"/tmp/foo1", @"/tmp/foo2", nil];
287
288
return ([fileList count] > 0 ? fileList : nil);
289
}
290
291
292
// Set up the pasteboard for dragging:
293
- (BOOL)declareTypesToPasteboard:(NSPasteboard *)pb withEnv:(JNIEnv *) env {
294
// 9-20-02 Note: leave this here for debugging:
295
//[pb declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: self];
296
//return TRUE;
297
298
// Get byte array elements:
299
jboolean isCopy;
300
jlong* jformats = (*env)->GetLongArrayElements(env, fFormats, &isCopy);
301
if (jformats == nil)
302
return FALSE;
303
304
// Allocate storage arrays for dragging types to register with the pasteboard:
305
jsize formatsLength = (*env)->GetArrayLength(env, fFormats);
306
NSMutableArray* pbTypes = [[NSMutableArray alloc] initWithCapacity:formatsLength];
307
308
// And assume there are no NS-type data: [Radar 3065621]
309
// This is to be able to drop transferables containing only a serialized object flavor, e.g.:
310
// "JAVA_DATAFLAVOR:application/x-java-serialized-object; class=java.awt.Label".
311
BOOL hasNSTypeData = false;
312
313
// Collect all supported types in a pasteboard format into the storage arrays:
314
jsize i;
315
for (i = 0; i < formatsLength; i++) {
316
jlong jformat = jformats[i];
317
318
if (jformat >= 0) {
319
NSString* type = formatForIndex(jformat);
320
321
// Add element type to the storage array.
322
if (type != nil) {
323
if ([type hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-jvm-local-objectref;"] == false) {
324
[pbTypes addObject:type];
325
326
// This is a good approximation if not perfect. A conclusive search would
327
// have to be done matching all defined strings in AppKit's commonStrings.h.
328
hasNSTypeData = [type hasPrefix:@"NS"] || [type hasPrefix:@"NeXT"] || [type hasPrefix:@"public."];
329
}
330
}
331
}
332
}
333
334
// 1-16-03 Note: [Radar 3065621]
335
// When TransferHandler is used with Swing components it puts only a type like this on the pasteboard:
336
// "JAVA_DATAFLAVOR:application/x-java-jvm-local-objectref; class=java.lang.String"
337
// And there's similar type for serialized object only transferables.
338
// Since our drop targets aren't trained for arbitrary data types yet we need to fake an empty string
339
// which will cause drop target handlers to fire.
340
// KCH - 3550405 If the drag is between Swing components, formatsLength == 0, so expand the check.
341
// Also, use a custom format rather than NSString, since that will prevent random views from accepting the drag
342
if (hasNSTypeData == false && formatsLength >= 0) {
343
[pbTypes addObject:[DnDUtilities javaPboardType]];
344
}
345
346
(*env)->ReleaseLongArrayElements(env, fFormats, jformats, JNI_ABORT);
347
348
// Declare pasteboard types. If the types array is empty we still want to declare them
349
// as otherwise an old set of types/data would remain on the pasteboard.
350
NSUInteger typesCount = [pbTypes count];
351
[pb declareTypes:pbTypes owner: self];
352
353
// KCH - Lame conversion bug between Cocoa and Carbon drag types
354
// If I provide the filenames _right now_, NSFilenamesPboardType is properly converted to CoreDrag flavors
355
// If I try to wait until pasteboard:provideDataForType:, the conversion won't happen
356
// and pasteboard:provideDataForType: won't even get called! (unless I go over a Cocoa app)
357
if ([pbTypes containsObject:NSFilenamesPboardType]) {
358
[self pasteboard:pb provideDataForType:NSFilenamesPboardType];
359
}
360
361
[pbTypes release];
362
363
return typesCount > 0 ? TRUE : FALSE;
364
}
365
366
// This is an NSPasteboard callback. In declareTypesToPasteboard:withEnv:, we only declared the types
367
// When the AppKit DnD system actually needs the data, this method will be invoked.
368
// Note that if the transfer is handled entirely from Swing (as in a local-vm drag), this method may never be called.
369
- (void)pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type {
370
AWT_ASSERT_APPKIT_THREAD;
371
372
// 9-20-02 Note: leave this here for debugging:
373
//[pb setString: @"Hello, World!" forType: NSStringPboardType];
374
// return;
375
376
// Set up Java environment:
377
JNIEnv* env = [ThreadUtilities getJNIEnv];
378
379
id pbData = nil;
380
381
// Collect data in a pasteboard format:
382
jlong jformat = indexForFormat(type);
383
if (jformat >= 0) {
384
// Convert DataTransfer data to a Java byte array:
385
// Note that this will eventually call getTransferData()
386
jbyteArray jdata = [self convertData:jformat];
387
388
if (jdata != nil) {
389
jboolean isCopy;
390
jsize jdataLength = (*env)->GetArrayLength(env, jdata);
391
jbyte* jbytedata = (*env)->GetByteArrayElements(env, jdata, &isCopy);
392
393
if (jdataLength > 0 && jbytedata != nil) {
394
// Get element data to the storage array. For NSFilenamesPboardType type we use
395
// an NSArray-type data - NSData-type data would cause a crash.
396
if (type != nil) {
397
pbData = ([type isEqualTo:NSFilenamesPboardType]) ?
398
[self getFileList:jbytedata dataLength:jdataLength] :
399
[NSData dataWithBytes:jbytedata length:jdataLength];
400
}
401
}
402
403
(*env)->ReleaseByteArrayElements(env, jdata, jbytedata, JNI_ABORT);
404
405
(*env)->DeleteLocalRef(env, jdata);
406
}
407
}
408
409
// If we are the custom type that matches local-vm drags, set an empty NSData
410
if ( (pbData == nil) && ([type isEqualTo:[DnDUtilities javaPboardType]]) ) {
411
pbData = [NSData dataWithBytes:"" length:1];
412
}
413
414
// Add pasteboard data for the type:
415
// Remember, NSFilenamesPboardType's data is NSArray (property list), not NSData!
416
// We must use proper pb accessor depending on the data type.
417
if ([pbData isKindOfClass:[NSArray class]])
418
[pb setPropertyList:pbData forType:type];
419
else
420
[pb setData:pbData forType:type];
421
}
422
423
424
- (void)validateDragImage
425
{
426
// Make a small blank image if we don't have a drag image:
427
if (fDragImage == nil) {
428
// 9-30-02 Note: keep this around for debugging:
429
fDragImage = [[NSImage alloc] initWithSize:NSMakeSize(21, 21)];
430
NSSize imageSize = [fDragImage size];
431
432
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
433
pixelsWide:imageSize.width pixelsHigh:imageSize.height bitsPerSample:8 samplesPerPixel:4
434
hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:0 bitsPerPixel:32];
435
436
[fDragImage addRepresentation:imageRep];
437
fDragImageOffset = NSMakePoint(0, 0);
438
439
[imageRep release];
440
}
441
}
442
443
- (NSEvent*)nsDragEvent:(BOOL)isDrag
444
{
445
// Get NSView for the drag source:
446
NSWindow* window = [fView window];
447
448
NSInteger windowNumber = [window windowNumber];
449
450
// Convert mouse coordinates to NS:
451
NSPoint eventLocation = [fView convertPoint:NSMakePoint(fDragPos.x, fDragPos.y) toView:nil];
452
eventLocation.y = [[fView window] frame].size.height - eventLocation.y;
453
454
// Convert fTriggerEventTimeStamp to NS - AWTEvent.h defines UTC(nsEvent) as ((jlong)[event timestamp] * 1000):
455
NSTimeInterval timeStamp = fTriggerEventTimeStamp / 1000;
456
457
// Convert fModifiers (extModifiers) to NS:
458
NSEventType mouseButtons = 0;
459
float pressure = 0.0;
460
if (isDrag) {
461
mouseButtons = (NSEventType) [DnDUtilities mapJavaExtModifiersToNSMouseDownButtons:fModifiers];
462
pressure = 1.0;
463
} else {
464
mouseButtons = (NSEventType) [DnDUtilities mapJavaExtModifiersToNSMouseUpButtons:fModifiers];
465
}
466
467
// Convert fModifiers (extModifiers) to NS:
468
NSUInteger modifiers = JavaModifiersToNsKeyModifiers(fModifiers, TRUE);
469
470
// Just a dummy value ...
471
NSInteger eventNumber = 0;
472
// NSEvent.context is deprecated and unused
473
NSGraphicsContext* unusedPassNil = nil;
474
475
// Make a native autoreleased dragging event:
476
NSEvent* dragEvent = [NSEvent mouseEventWithType:mouseButtons location:eventLocation
477
modifierFlags:modifiers timestamp:timeStamp windowNumber:windowNumber context:unusedPassNil
478
eventNumber:eventNumber clickCount:fClickCount pressure:pressure];
479
480
return dragEvent;
481
}
482
483
- (void)doDrag
484
{
485
AWT_ASSERT_APPKIT_THREAD;
486
487
DLog2(@"[CDragSource doDrag]: %@\n", self);
488
489
// Set up Java environment:
490
JNIEnv *env = [ThreadUtilities getJNIEnv];
491
492
// Set up the pasteboard:
493
NSPasteboard *pb = [NSPasteboard pasteboardWithName: NSDragPboard];
494
[self declareTypesToPasteboard:pb withEnv:env];
495
496
// Make a native autoreleased NS dragging event:
497
NSEvent *dragEvent = [self nsDragEvent:YES];
498
499
// Get NSView for the drag source:
500
NSView *view = fView;
501
502
// Make sure we have a valid drag image:
503
[self validateDragImage];
504
NSImage* dragImage = fDragImage;
505
506
// Get drag origin and offset:
507
NSPoint dragOrigin = [dragEvent locationInWindow];
508
dragOrigin.x += fDragImageOffset.x;
509
dragOrigin.y -= fDragImageOffset.y + [dragImage size].height;
510
511
// Drag offset values don't seem to matter:
512
NSSize dragOffset = NSMakeSize(0, 0);
513
514
// These variables should be set based on the transferable:
515
BOOL isFileDrag = FALSE;
516
BOOL fileDragPromises = FALSE;
517
518
DLog(@"[CDragSource drag]: calling dragImage/File:");
519
DLog3(@" - drag origin: %f, %f", fDragPos.x, fDragPos.y);
520
DLog5(@" - drag image: %f, %f (%f x %f)", fDragImageOffset.x, fDragImageOffset.y, [dragImage size].width, [dragImage size].height);
521
DLog3(@" - event point (window) %f, %f", [dragEvent locationInWindow].x, [dragEvent locationInWindow].y);
522
DLog3(@" - drag point (view) %f, %f", dragOrigin.x, dragOrigin.y);
523
// Set up the fDragKeyModifier, so we know if the operation has changed
524
// Set up the fDragMouseModifier, so we can |= it later (since CoreDrag doesn't tell us mouse states during a drag)
525
fDragKeyModifiers = [DnDUtilities extractJavaExtKeyModifiersFromJavaExtModifiers:fModifiers];
526
fDragMouseModifiers = [DnDUtilities extractJavaExtMouseModifiersFromJavaExtModifiers:fModifiers];
527
528
@try {
529
sNeedsEnter = YES;
530
AWTToolkit.inDoDragDropLoop = YES;
531
// Data dragging:
532
if (isFileDrag == FALSE) {
533
[view dragImage:dragImage at:dragOrigin offset:dragOffset event:dragEvent pasteboard:pb source:view slideBack:YES];
534
} else if (fileDragPromises == FALSE) {
535
// File dragging:
536
NSLog(@"[CDragSource drag]: file dragging is unsupported.");
537
NSString* fileName = nil; // This should be set based on the transferable.
538
NSRect fileLocationRect = NSMakeRect(0, 0, 0, 0); // This should be set based on the filename.
539
540
BOOL success = [view dragFile:fileName fromRect:fileLocationRect slideBack:YES event:dragEvent];
541
if (success == TRUE) { // One would erase dragged file if this was a move operation.
542
}
543
} else {
544
// Promised file dragging:
545
NSLog(@"[CDragSource drag]: file dragging promises are unsupported.");
546
NSArray* fileTypesArray = nil; // This should be set based on the transferable.
547
NSRect fileLocationRect = NSMakeRect(0, 0, 0, 0); // This should be set based on all filenames.
548
549
BOOL success = [view dragPromisedFilesOfTypes:fileTypesArray fromRect:fileLocationRect source:view slideBack:YES event:dragEvent];
550
if (success == TRUE) { // One would write out the promised files here.
551
}
552
}
553
554
NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
555
556
// Convert drag operation to Java:
557
jint dragOp = [DnDUtilities mapNSDragOperationToJava:sDragOperation];
558
559
// Drag success must acount for DragOperationNone:
560
jboolean success = (dragOp != java_awt_dnd_DnDConstants_ACTION_NONE);
561
562
// We have a problem here... we don't send DragSource dragEnter/Exit messages outside of our own process
563
// because we don't get anything from AppKit/CoreDrag
564
// This means that if you drag outside of the app and drop, even if it's valid, a dragDropFinished is posted without dragEnter
565
// I'm worried that this might confuse Java, so we're going to send a "bogus" dragEnter if necessary (only if the drag succeeded)
566
if (success && sNeedsEnter) {
567
[self postDragEnter];
568
}
569
570
// DragSourceContextPeer.dragDropFinished() should be called even if there was an error:
571
GET_DSCP_CLASS();
572
DECLARE_METHOD(dragDropFinishedMethod, CDragSourceContextPeerClass, "dragDropFinished", "(ZIII)V");
573
DLog3(@" -> posting dragDropFinished, point %f, %f", point.x, point.y);
574
(*env)->CallVoidMethod(env, fDragSourceContextPeer, dragDropFinishedMethod, success, dragOp, (jint) point.x, (jint) point.y);
575
CHECK_EXCEPTION();
576
DECLARE_METHOD(resetHoveringMethod, CDragSourceContextPeerClass, "resetHovering", "()V");
577
(*env)->CallVoidMethod(env, fDragSourceContextPeer, resetHoveringMethod); // Hust reset static variable
578
CHECK_EXCEPTION();
579
} @finally {
580
sNeedsEnter = NO;
581
AWTToolkit.inDoDragDropLoop = NO;
582
}
583
584
// We have to do this, otherwise AppKit doesn't know we're finished dragging. Yup, it's that bad.
585
if ([[[NSRunLoop currentRunLoop] currentMode] isEqualTo:NSEventTrackingRunLoopMode]) {
586
[NSApp postEvent:[self nsDragEvent:NO] atStart:YES];
587
}
588
589
DLog2(@"[CDragSource doDrag] end: %@\n", self);
590
}
591
592
- (void)drag
593
{
594
AWT_ASSERT_NOT_APPKIT_THREAD;
595
596
[self performSelectorOnMainThread:@selector(doDrag) withObject:nil waitUntilDone:YES];
597
}
598
599
/******************************** BEGIN NSDraggingSource Interface ********************************/
600
601
- (void)draggingOperationChanged:(NSDragOperation)dragOp {
602
//DLog2(@"[CDragSource draggingOperationChanged]: %@\n", self);
603
604
JNIEnv* env = [ThreadUtilities getJNIEnv];
605
606
jint targetActions = fSourceActions;
607
if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
608
609
NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
610
DLog3(@" -> posting operationChanged, point %f, %f", point.x, point.y);
611
jint modifiedModifiers = fDragKeyModifiers | fDragMouseModifiers | [DnDUtilities javaKeyModifiersForNSDragOperation:dragOp];
612
613
GET_DSCP_CLASS();
614
DECLARE_METHOD(operationChangedMethod, CDragSourceContextPeerClass, "operationChanged", "(IIII)V");
615
(*env)->CallVoidMethod(env, fDragSourceContextPeer, operationChangedMethod, targetActions, modifiedModifiers, (jint) point.x, (jint) point.y);
616
CHECK_EXCEPTION();
617
}
618
619
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)localDrag {
620
//DLog2(@"[CDragSource draggingSourceOperationMaskForLocal]: %@\n", self);
621
return [DnDUtilities mapJavaDragOperationToNS:fSourceActions];
622
}
623
624
/* 9-16-02 Note: we don't support promises yet.
625
- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination {
626
}*/
627
628
- (void)draggedImage:(NSImage *)image beganAt:(NSPoint)screenPoint {
629
DLog4(@"[CDragSource draggedImage beganAt]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
630
[AWTToolkit eventCountPlusPlus];
631
// Initialize static variables:
632
sDragOperation = NSDragOperationNone;
633
sDraggingLocation = screenPoint;
634
}
635
636
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation {
637
DLog4(@"[CDragSource draggedImage endedAt:]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
638
[AWTToolkit eventCountPlusPlus];
639
sDraggingLocation = screenPoint;
640
sDragOperation = operation;
641
}
642
643
- (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint {
644
//DLog4(@"[CDragSource draggedImage moved]: (%d, %d) %@\n", (int) screenPoint.x, (int) screenPoint.y, self);
645
JNIEnv* env = [ThreadUtilities getJNIEnv];
646
647
JNI_COCOA_ENTER(env);
648
[AWTToolkit eventCountPlusPlus];
649
// There are two things we would be interested in:
650
// a) mouse pointer has moved
651
// b) drag actions (key modifiers) have changed
652
653
BOOL notifyJava = FALSE;
654
655
// a) mouse pointer has moved:
656
if (NSEqualPoints(screenPoint, sDraggingLocation) == FALSE) {
657
//DLog2(@"[CDragSource draggedImage:movedTo]: mouse moved, %@\n", self);
658
notifyJava = TRUE;
659
}
660
661
// b) drag actions (key modifiers) have changed:
662
jint modifiers = NsKeyModifiersToJavaModifiers([NSEvent modifierFlags], YES);
663
if (fDragKeyModifiers != modifiers) {
664
NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:[NSEvent modifierFlags]];
665
NSDragOperation allowedOp = [DnDUtilities mapJavaDragOperationToNS:fSourceActions] & currentOp;
666
667
fDragKeyModifiers = modifiers;
668
669
if (sDragOperation != allowedOp) {
670
sDragOperation = allowedOp;
671
[self draggingOperationChanged:allowedOp];
672
}
673
}
674
675
// Should we notify Java things have changed?
676
if (notifyJava) {
677
sDraggingLocation = screenPoint;
678
679
NSPoint point = [self mapNSScreenPointToJavaWithOffset:screenPoint];
680
681
jint targetActions = fSourceActions;
682
if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
683
684
// Motion: dragMotion, dragMouseMoved
685
DLog4(@"[CDragSource draggedImage moved]: (%f, %f) %@\n", screenPoint.x, screenPoint.y, self);
686
687
DLog3(@" -> posting dragMotion, point %f, %f", point.x, point.y);
688
GET_DSCP_CLASS();
689
DECLARE_METHOD(dragMotionMethod, CDragSourceContextPeerClass, "dragMotion", "(IIII)V");
690
(*env)->CallVoidMethod(env, fDragSourceContextPeer, dragMotionMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
691
CHECK_EXCEPTION();
692
DLog3(@" -> posting dragMouseMoved, point %f, %f", point.x, point.y);
693
DECLARE_METHOD(dragMouseMovedMethod, CDragSourceContextPeerClass, "dragMouseMoved", "(IIII)V");
694
(*env)->CallVoidMethod(env, fDragSourceContextPeer, dragMouseMovedMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
695
CHECK_EXCEPTION();
696
}
697
JNI_COCOA_EXIT(env);
698
}
699
700
- (BOOL)ignoreModifierKeysWhileDragging {
701
//DLog2(@"[CDragSource ignoreModifierKeysWhileDragging]: %@\n", self);
702
return NO;
703
}
704
705
/******************************** END NSDraggingSource Interface ********************************/
706
707
708
// postDragEnter and postDragExit are called from CDropTarget when possible and appropriate
709
// Currently only possible if source and target are in the same process
710
- (void) postDragEnter {
711
JNIEnv *env = [ThreadUtilities getJNIEnv];
712
sNeedsEnter = NO;
713
714
jint targetActions = fSourceActions;
715
if ([CDropTarget currentDropTarget]) targetActions = [[CDropTarget currentDropTarget] currentJavaActions];
716
717
NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
718
DLog3(@" -> posting dragEnter, point %f, %f", point.x, point.y);
719
GET_DSCP_CLASS();
720
DECLARE_METHOD(dragEnterMethod, CDragSourceContextPeerClass, "dragEnter", "(IIII)V");
721
(*env)->CallVoidMethod(env, fDragSourceContextPeer, dragEnterMethod, targetActions, (jint) fModifiers, (jint) point.x, (jint) point.y);
722
CHECK_EXCEPTION();
723
}
724
725
- (void) postDragExit {
726
JNIEnv *env = [ThreadUtilities getJNIEnv];
727
sNeedsEnter = YES;
728
729
NSPoint point = [self mapNSScreenPointToJavaWithOffset:sDraggingLocation];
730
DLog3(@" -> posting dragExit, point %f, %f", point.x, point.y);
731
GET_DSCP_CLASS();
732
DECLARE_METHOD(dragExitMethod, CDragSourceContextPeerClass, "dragExit", "(II)V");
733
(*env)->CallVoidMethod(env, fDragSourceContextPeer, dragExitMethod, (jint) point.x, (jint) point.y);
734
CHECK_EXCEPTION();
735
736
}
737
738
739
// Java assumes that the origin is the top-left corner of the screen.
740
// Cocoa assumes that the origin is the bottom-left corner of the screen.
741
// Adjust the y coordinate to account for this.
742
// NOTE: Also need to take into account the 0 screen relative screen coords.
743
// This is because all screen coords in Cocoa are relative to the 0 screen.
744
// Also see +[CWindow convertAWTToCocoaScreenRect]
745
// NSScreen-to-JavaScreen mapping:
746
- (NSPoint) mapNSScreenPointToJavaWithOffset:(NSPoint)screenPoint {
747
NSRect mainR = [[[NSScreen screens] objectAtIndex:0] frame];
748
NSPoint point = NSMakePoint(screenPoint.x, mainR.size.height - (screenPoint.y));
749
750
// Adjust the point with the drag image offset to get the real mouse hotspot:
751
// The point should remain in screen coordinates (as per DragSourceEvent.getLocation() documentation)
752
point.x -= fDragImageOffset.x;
753
point.y -= ([fDragImage size].height + fDragImageOffset.y);
754
755
return point;
756
}
757
758
@end
759
760