Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/XDnDDropTargetProtocol.java
41159 views
1
/*
2
* Copyright (c) 2003, 2014, 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
package sun.awt.X11;
27
28
import java.awt.Point;
29
30
import java.awt.dnd.DnDConstants;
31
32
import java.awt.event.MouseEvent;
33
34
import java.io.IOException;
35
36
import sun.util.logging.PlatformLogger;
37
38
import jdk.internal.misc.Unsafe;
39
40
import java.awt.Rectangle;
41
42
import java.awt.GraphicsDevice;
43
44
import java.awt.GraphicsEnvironment;
45
46
import sun.awt.X11GraphicsConfig;
47
48
/**
49
* XDropTargetProtocol implementation for XDnD protocol.
50
*
51
* @since 1.5
52
*/
53
class XDnDDropTargetProtocol extends XDropTargetProtocol {
54
private static final PlatformLogger logger =
55
PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDnDDropTargetProtocol");
56
57
private static final Unsafe unsafe = XlibWrapper.unsafe;
58
59
private long sourceWindow = 0;
60
private long sourceWindowMask = 0;
61
private int sourceProtocolVersion = 0;
62
private int sourceActions = DnDConstants.ACTION_NONE;
63
private long[] sourceFormats = null;
64
private boolean trackSourceActions = false;
65
private int userAction = DnDConstants.ACTION_NONE;
66
private int sourceX = 0;
67
private int sourceY = 0;
68
private XWindow targetXWindow = null;
69
70
// XEmbed stuff.
71
private long prevCtxt = 0;
72
private boolean overXEmbedClient = false;
73
74
protected XDnDDropTargetProtocol(XDropTargetProtocolListener listener) {
75
super(listener);
76
}
77
78
/**
79
* Creates an instance associated with the specified listener.
80
*
81
* @throws NullPointerException if listener is {@code null}.
82
*/
83
static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) {
84
return new XDnDDropTargetProtocol(listener);
85
}
86
87
public String getProtocolName() {
88
return XDragAndDropProtocols.XDnD;
89
}
90
91
public void registerDropTarget(long window) {
92
assert XToolkit.isAWTLockHeldByCurrentThread();
93
94
long data = Native.allocateLongArray(1);
95
96
try {
97
Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);
98
99
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
100
XDnDConstants.XA_XdndAware.setAtomData(window, XAtom.XA_ATOM, data, 1);
101
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
102
103
if ((XErrorHandlerUtil.saved_error != null) &&
104
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
105
throw new XException("Cannot write XdndAware property");
106
}
107
} finally {
108
unsafe.freeMemory(data);
109
data = 0;
110
}
111
}
112
113
public void unregisterDropTarget(long window) {
114
assert XToolkit.isAWTLockHeldByCurrentThread();
115
116
XDnDConstants.XA_XdndAware.DeleteProperty(window);
117
}
118
119
public void registerEmbedderDropSite(long embedder) {
120
assert XToolkit.isAWTLockHeldByCurrentThread();
121
122
boolean overriden = false;
123
int version = 0;
124
long proxy = 0;
125
long newProxy = XDropTargetRegistry.getDnDProxyWindow();
126
int status = 0;
127
128
WindowPropertyGetter wpg1 =
129
new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndAware, 0, 1,
130
false, XConstants.AnyPropertyType);
131
132
try {
133
status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
134
135
if (status == XConstants.Success &&
136
wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {
137
138
overriden = true;
139
version = (int)Native.getLong(wpg1.getData());
140
}
141
} finally {
142
wpg1.dispose();
143
}
144
145
/* XdndProxy is not supported for prior to XDnD version 4 */
146
if (overriden && version >= 4) {
147
WindowPropertyGetter wpg2 =
148
new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndProxy,
149
0, 1, false, XAtom.XA_WINDOW);
150
151
try {
152
status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
153
154
if (status == XConstants.Success &&
155
wpg2.getData() != 0 &&
156
wpg2.getActualType() == XAtom.XA_WINDOW) {
157
158
proxy = Native.getLong(wpg2.getData());
159
}
160
} finally {
161
wpg2.dispose();
162
}
163
164
if (proxy != 0) {
165
WindowPropertyGetter wpg3 =
166
new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,
167
0, 1, false, XAtom.XA_WINDOW);
168
169
try {
170
status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
171
172
if (status != XConstants.Success ||
173
wpg3.getData() == 0 ||
174
wpg3.getActualType() != XAtom.XA_WINDOW ||
175
Native.getLong(wpg3.getData()) != proxy) {
176
177
proxy = 0;
178
} else {
179
WindowPropertyGetter wpg4 =
180
new WindowPropertyGetter(proxy,
181
XDnDConstants.XA_XdndAware,
182
0, 1, false,
183
XConstants.AnyPropertyType);
184
185
try {
186
status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
187
188
if (status != XConstants.Success ||
189
wpg4.getData() == 0 ||
190
wpg4.getActualType() != XAtom.XA_ATOM) {
191
192
proxy = 0;
193
}
194
} finally {
195
wpg4.dispose();
196
}
197
}
198
} finally {
199
wpg3.dispose();
200
}
201
}
202
}
203
204
if (proxy == newProxy) {
205
// Embedder already registered.
206
return;
207
}
208
209
long data = Native.allocateLongArray(1);
210
211
try {
212
Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);
213
214
/* The proxy window must have the XdndAware set, as XDnD protocol
215
prescribes to check the proxy window for XdndAware. */
216
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
217
XDnDConstants.XA_XdndAware.setAtomData(newProxy, XAtom.XA_ATOM,
218
data, 1);
219
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
220
221
if ((XErrorHandlerUtil.saved_error != null) &&
222
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
223
throw new XException("Cannot write XdndAware property");
224
}
225
226
Native.putLong(data, 0, newProxy);
227
228
/* The proxy window must have the XdndProxy set to point to itself.*/
229
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
230
XDnDConstants.XA_XdndProxy.setAtomData(newProxy, XAtom.XA_WINDOW,
231
data, 1);
232
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
233
234
if ((XErrorHandlerUtil.saved_error != null) &&
235
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
236
throw new XException("Cannot write XdndProxy property");
237
}
238
239
Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);
240
241
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
242
XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,
243
data, 1);
244
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
245
246
if ((XErrorHandlerUtil.saved_error != null) &&
247
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
248
throw new XException("Cannot write XdndAware property");
249
}
250
251
Native.putLong(data, 0, newProxy);
252
253
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
254
XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,
255
data, 1);
256
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
257
258
if ((XErrorHandlerUtil.saved_error != null) &&
259
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
260
throw new XException("Cannot write XdndProxy property");
261
}
262
} finally {
263
unsafe.freeMemory(data);
264
data = 0;
265
}
266
267
putEmbedderRegistryEntry(embedder, overriden, version, proxy);
268
}
269
270
public void unregisterEmbedderDropSite(long embedder) {
271
assert XToolkit.isAWTLockHeldByCurrentThread();
272
273
EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);
274
275
if (entry == null) {
276
return;
277
}
278
279
if (entry.isOverriden()) {
280
long data = Native.allocateLongArray(1);
281
282
try {
283
Native.putLong(data, 0, entry.getVersion());
284
285
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
286
XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,
287
data, 1);
288
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
289
290
if ((XErrorHandlerUtil.saved_error != null) &&
291
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
292
throw new XException("Cannot write XdndAware property");
293
}
294
295
Native.putLong(data, 0, (int)entry.getProxy());
296
297
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
298
XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,
299
data, 1);
300
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
301
302
if ((XErrorHandlerUtil.saved_error != null) &&
303
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
304
throw new XException("Cannot write XdndProxy property");
305
}
306
} finally {
307
unsafe.freeMemory(data);
308
data = 0;
309
}
310
} else {
311
XDnDConstants.XA_XdndAware.DeleteProperty(embedder);
312
XDnDConstants.XA_XdndProxy.DeleteProperty(embedder);
313
}
314
}
315
316
/*
317
* Gets and stores in the registry the embedder's XDnD drop site info
318
* from the embedded.
319
*/
320
public void registerEmbeddedDropSite(long embedded) {
321
assert XToolkit.isAWTLockHeldByCurrentThread();
322
323
boolean overriden = false;
324
int version = 0;
325
long proxy = 0;
326
long newProxy = XDropTargetRegistry.getDnDProxyWindow();
327
int status = 0;
328
329
WindowPropertyGetter wpg1 =
330
new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndAware, 0, 1,
331
false, XConstants.AnyPropertyType);
332
333
try {
334
status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
335
336
if (status == XConstants.Success &&
337
wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {
338
339
overriden = true;
340
version = (int)Native.getLong(wpg1.getData());
341
}
342
} finally {
343
wpg1.dispose();
344
}
345
346
/* XdndProxy is not supported for prior to XDnD version 4 */
347
if (overriden && version >= 4) {
348
WindowPropertyGetter wpg2 =
349
new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndProxy,
350
0, 1, false, XAtom.XA_WINDOW);
351
352
try {
353
status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
354
355
if (status == XConstants.Success &&
356
wpg2.getData() != 0 &&
357
wpg2.getActualType() == XAtom.XA_WINDOW) {
358
359
proxy = Native.getLong(wpg2.getData());
360
}
361
} finally {
362
wpg2.dispose();
363
}
364
365
if (proxy != 0) {
366
WindowPropertyGetter wpg3 =
367
new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,
368
0, 1, false, XAtom.XA_WINDOW);
369
370
try {
371
status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
372
373
if (status != XConstants.Success ||
374
wpg3.getData() == 0 ||
375
wpg3.getActualType() != XAtom.XA_WINDOW ||
376
Native.getLong(wpg3.getData()) != proxy) {
377
378
proxy = 0;
379
} else {
380
WindowPropertyGetter wpg4 =
381
new WindowPropertyGetter(proxy,
382
XDnDConstants.XA_XdndAware,
383
0, 1, false,
384
XConstants.AnyPropertyType);
385
386
try {
387
status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
388
389
if (status != XConstants.Success ||
390
wpg4.getData() == 0 ||
391
wpg4.getActualType() != XAtom.XA_ATOM) {
392
393
proxy = 0;
394
}
395
} finally {
396
wpg4.dispose();
397
}
398
}
399
} finally {
400
wpg3.dispose();
401
}
402
}
403
}
404
405
putEmbedderRegistryEntry(embedded, overriden, version, proxy);
406
}
407
408
public boolean isProtocolSupported(long window) {
409
assert XToolkit.isAWTLockHeldByCurrentThread();
410
411
WindowPropertyGetter wpg1 =
412
new WindowPropertyGetter(window, XDnDConstants.XA_XdndAware, 0, 1,
413
false, XConstants.AnyPropertyType);
414
415
try {
416
int status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
417
418
if (status == XConstants.Success &&
419
wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {
420
421
return true;
422
} else {
423
return false;
424
}
425
} finally {
426
wpg1.dispose();
427
}
428
}
429
430
private boolean processXdndEnter(XClientMessageEvent xclient) {
431
long source_win = 0;
432
long source_win_mask = 0;
433
int protocol_version = 0;
434
int actions = DnDConstants.ACTION_NONE;
435
boolean track = true;
436
long[] formats = null;
437
438
if (getSourceWindow() != 0) {
439
return false;
440
}
441
442
if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)
443
&& getEmbedderRegistryEntry(xclient.get_window()) == null) {
444
return false;
445
}
446
447
if (xclient.get_message_type() != XDnDConstants.XA_XdndEnter.getAtom()){
448
return false;
449
}
450
451
protocol_version =
452
(int)((xclient.get_data(1) & XDnDConstants.XDND_PROTOCOL_MASK) >>
453
XDnDConstants.XDND_PROTOCOL_SHIFT);
454
455
/* XDnD compliance only requires supporting version 3 and up. */
456
if (protocol_version < XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
457
return false;
458
}
459
460
/* Ignore the source if the protocol version is higher than we support. */
461
if (protocol_version > XDnDConstants.XDND_PROTOCOL_VERSION) {
462
return false;
463
}
464
465
source_win = xclient.get_data(0);
466
467
/* Extract the list of supported actions. */
468
if (protocol_version < 2) {
469
/* Prior to XDnD version 2 only COPY action was supported. */
470
actions = DnDConstants.ACTION_COPY;
471
} else {
472
WindowPropertyGetter wpg =
473
new WindowPropertyGetter(source_win,
474
XDnDConstants.XA_XdndActionList,
475
0, 0xFFFF, false,
476
XAtom.XA_ATOM);
477
try {
478
wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
479
480
if (wpg.getActualType() == XAtom.XA_ATOM &&
481
wpg.getActualFormat() == 32) {
482
long data = wpg.getData();
483
484
for (int i = 0; i < wpg.getNumberOfItems(); i++) {
485
actions |=
486
XDnDConstants.getJavaActionForXDnDAction(Native.getLong(data, i));
487
}
488
} else {
489
/*
490
* According to XDnD protocol, XdndActionList is optional.
491
* If XdndActionList is not set we try to guess which actions are
492
* supported.
493
*/
494
actions = DnDConstants.ACTION_COPY;
495
track = true;
496
}
497
} finally {
498
wpg.dispose();
499
}
500
}
501
502
/* Extract the available data types. */
503
if ((xclient.get_data(1) & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {
504
WindowPropertyGetter wpg =
505
new WindowPropertyGetter(source_win,
506
XDnDConstants.XA_XdndTypeList,
507
0, 0xFFFF, false,
508
XAtom.XA_ATOM);
509
try {
510
wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
511
512
if (wpg.getActualType() == XAtom.XA_ATOM &&
513
wpg.getActualFormat() == 32) {
514
formats = Native.toLongs(wpg.getData(),
515
wpg.getNumberOfItems());
516
} else {
517
formats = new long[0];
518
}
519
} finally {
520
wpg.dispose();
521
}
522
} else {
523
int countFormats = 0;
524
long[] formats3 = new long[3];
525
526
for (int i = 0; i < 3; i++) {
527
long j;
528
if ((j = xclient.get_data(2 + i)) != XConstants.None) {
529
formats3[countFormats++] = j;
530
}
531
}
532
533
formats = new long[countFormats];
534
535
System.arraycopy(formats3, 0, formats, 0, countFormats);
536
}
537
538
assert XToolkit.isAWTLockHeldByCurrentThread();
539
540
/*
541
* Select for StructureNotifyMask to receive DestroyNotify in case of source
542
* crash.
543
*/
544
XWindowAttributes wattr = new XWindowAttributes();
545
try {
546
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
547
int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
548
source_win, wattr.pData);
549
550
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
551
552
if ((status == 0) ||
553
((XErrorHandlerUtil.saved_error != null) &&
554
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
555
throw new XException("XGetWindowAttributes failed");
556
}
557
558
source_win_mask = wattr.get_your_event_mask();
559
} finally {
560
wattr.dispose();
561
}
562
563
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
564
XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
565
source_win_mask |
566
XConstants.StructureNotifyMask);
567
568
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
569
570
if ((XErrorHandlerUtil.saved_error != null) &&
571
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
572
throw new XException("XSelectInput failed");
573
}
574
575
sourceWindow = source_win;
576
sourceWindowMask = source_win_mask;
577
sourceProtocolVersion = protocol_version;
578
sourceActions = actions;
579
sourceFormats = formats;
580
trackSourceActions = track;
581
582
return true;
583
}
584
585
private boolean processXdndPosition(XClientMessageEvent xclient) {
586
long time_stamp = (int)XConstants.CurrentTime;
587
long xdnd_action = 0;
588
int java_action = DnDConstants.ACTION_NONE;
589
int x = 0;
590
int y = 0;
591
592
/* Ignore XDnD messages from all other windows. */
593
if (sourceWindow != xclient.get_data(0)) {
594
return false;
595
}
596
597
XWindow xwindow = null;
598
{
599
XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());
600
if (xbasewindow instanceof XWindow) {
601
xwindow = (XWindow)xbasewindow;
602
}
603
}
604
605
x = (int)(xclient.get_data(2) >> 16);
606
y = (int)(xclient.get_data(2) & 0xFFFF);
607
608
if (xwindow != null) {
609
x = xwindow.scaleDown(x);
610
y = xwindow.scaleDown(y);
611
} else {
612
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
613
for (GraphicsDevice gd : ge.getScreenDevices()) {
614
X11GraphicsConfig gc = (X11GraphicsConfig)gd.getDefaultConfiguration();
615
Rectangle rt = gc.getBounds();
616
rt.x = gc.scaleUp(rt.x);
617
rt.y = gc.scaleUp(rt.y);
618
rt.width = gc.scaleUp(rt.width);
619
rt.height = gc.scaleUp(rt.height);
620
if (rt.contains(x, y)) {
621
x = gc.scaleDown(x);
622
y = gc.scaleDown(y);
623
break;
624
}
625
}
626
627
long receiver =
628
XDropTargetRegistry.getRegistry().getEmbeddedDropSite(
629
xclient.get_window(), x, y);
630
631
if (receiver != 0) {
632
XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);
633
if (xbasewindow instanceof XWindow) {
634
xwindow = (XWindow)xbasewindow;
635
}
636
}
637
}
638
639
if (xwindow != null) {
640
/* Translate mouse position from root coordinates
641
to the target window coordinates. */
642
Point p = xwindow.toLocal(x, y);
643
x = p.x;
644
y = p.y;
645
}
646
647
/* Time stamp - new in XDnD version 1. */
648
if (sourceProtocolVersion > 0) {
649
time_stamp = xclient.get_data(3) & 0xFFFFFFFFL;
650
}
651
652
/* User action - new in XDnD version 2. */
653
if (sourceProtocolVersion > 1) {
654
xdnd_action = xclient.get_data(4);
655
} else {
656
/* The default action is XdndActionCopy */
657
xdnd_action = XDnDConstants.XA_XdndActionCopy.getAtom();
658
}
659
660
java_action = XDnDConstants.getJavaActionForXDnDAction(xdnd_action);
661
662
if (trackSourceActions) {
663
sourceActions |= java_action;
664
}
665
666
if (xwindow == null) {
667
if (targetXWindow != null) {
668
notifyProtocolListener(targetXWindow, x, y,
669
DnDConstants.ACTION_NONE, xclient,
670
MouseEvent.MOUSE_EXITED);
671
}
672
} else {
673
int java_event_id = 0;
674
675
if (targetXWindow == null) {
676
java_event_id = MouseEvent.MOUSE_ENTERED;
677
} else {
678
java_event_id = MouseEvent.MOUSE_DRAGGED;
679
}
680
681
notifyProtocolListener(xwindow, x, y, java_action, xclient,
682
java_event_id);
683
}
684
685
userAction = java_action;
686
sourceX = x;
687
sourceY = y;
688
targetXWindow = xwindow;
689
690
return true;
691
}
692
693
private boolean processXdndLeave(XClientMessageEvent xclient) {
694
/* Ignore XDnD messages from all other windows. */
695
if (sourceWindow != xclient.get_data(0)) {
696
return false;
697
}
698
699
cleanup();
700
701
return true;
702
}
703
704
private boolean processXdndDrop(XClientMessageEvent xclient) {
705
/* Ignore XDnD messages from all other windows. */
706
if (sourceWindow != xclient.get_data(0)) {
707
return false;
708
}
709
710
if (targetXWindow != null) {
711
notifyProtocolListener(targetXWindow, sourceX, sourceY, userAction,
712
xclient, MouseEvent.MOUSE_RELEASED);
713
}
714
715
return true;
716
}
717
718
public int getMessageType(XClientMessageEvent xclient) {
719
long messageType = xclient.get_message_type();
720
721
if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {
722
return ENTER_MESSAGE;
723
} else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) {
724
return MOTION_MESSAGE;
725
} else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {
726
return LEAVE_MESSAGE;
727
} else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {
728
return DROP_MESSAGE;
729
} else {
730
return UNKNOWN_MESSAGE;
731
}
732
}
733
734
protected boolean processClientMessageImpl(XClientMessageEvent xclient) {
735
long messageType = xclient.get_message_type();
736
737
if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {
738
return processXdndEnter(xclient);
739
} else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) {
740
return processXdndPosition(xclient);
741
} else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {
742
return processXdndLeave(xclient);
743
} else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {
744
return processXdndDrop(xclient);
745
} else {
746
return false;
747
}
748
}
749
750
protected void sendEnterMessageToToplevel(long toplevel,
751
XClientMessageEvent xclient) {
752
/* flags */
753
long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;
754
if (sourceFormats != null && sourceFormats.length > 3) {
755
data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
756
}
757
long data2 = sourceFormats.length > 0 ? sourceFormats[0] : 0;
758
long data3 = sourceFormats.length > 1 ? sourceFormats[1] : 0;
759
long data4 = sourceFormats.length > 2 ? sourceFormats[2] : 0;
760
sendEnterMessageToToplevelImpl(toplevel, xclient.get_data(0),
761
data1, data2, data3, data4);
762
763
}
764
765
private void sendEnterMessageToToplevelImpl(long toplevel,
766
long sourceWindow,
767
long data1, long data2,
768
long data3, long data4) {
769
XClientMessageEvent enter = new XClientMessageEvent();
770
try {
771
enter.set_type(XConstants.ClientMessage);
772
enter.set_window(toplevel);
773
enter.set_format(32);
774
enter.set_message_type(XDnDConstants.XA_XdndEnter.getAtom());
775
/* XID of the source window */
776
enter.set_data(0, sourceWindow);
777
enter.set_data(1, data1);
778
enter.set_data(2, data2);
779
enter.set_data(3, data3);
780
enter.set_data(4, data4);
781
782
forwardClientMessageToToplevel(toplevel, enter);
783
} finally {
784
enter.dispose();
785
}
786
}
787
788
protected void sendLeaveMessageToToplevel(long toplevel,
789
XClientMessageEvent xclient) {
790
sendLeaveMessageToToplevelImpl(toplevel, xclient.get_data(0));
791
}
792
793
protected void sendLeaveMessageToToplevelImpl(long toplevel,
794
long sourceWindow) {
795
XClientMessageEvent leave = new XClientMessageEvent();
796
try {
797
leave.set_type(XConstants.ClientMessage);
798
leave.set_window(toplevel);
799
leave.set_format(32);
800
leave.set_message_type(XDnDConstants.XA_XdndLeave.getAtom());
801
/* XID of the source window */
802
leave.set_data(0, sourceWindow);
803
/* flags */
804
leave.set_data(1, 0);
805
806
forwardClientMessageToToplevel(toplevel, leave);
807
} finally {
808
leave.dispose();
809
}
810
}
811
812
public boolean sendResponse(long ctxt, int eventID, int action) {
813
XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
814
815
if (xclient.get_message_type() !=
816
XDnDConstants.XA_XdndPosition.getAtom()) {
817
818
return false;
819
}
820
821
if (eventID == MouseEvent.MOUSE_EXITED) {
822
action = DnDConstants.ACTION_NONE;
823
}
824
825
XClientMessageEvent msg = new XClientMessageEvent();
826
try {
827
msg.set_type(XConstants.ClientMessage);
828
msg.set_window(xclient.get_data(0));
829
msg.set_format(32);
830
msg.set_message_type(XDnDConstants.XA_XdndStatus.getAtom());
831
/* target window */
832
msg.set_data(0, xclient.get_window());
833
/* flags */
834
long flags = 0;
835
if (action != DnDConstants.ACTION_NONE) {
836
flags |= XDnDConstants.XDND_ACCEPT_DROP_FLAG;
837
}
838
msg.set_data(1, flags);
839
/* specify an empty rectangle */
840
msg.set_data(2, 0); /* x, y */
841
msg.set_data(3, 0); /* w, h */
842
/* action accepted by the target */
843
msg.set_data(4, XDnDConstants.getXDnDActionForJavaAction(action));
844
845
XToolkit.awtLock();
846
try {
847
XlibWrapper.XSendEvent(XToolkit.getDisplay(),
848
xclient.get_data(0),
849
false, XConstants.NoEventMask,
850
msg.pData);
851
} finally {
852
XToolkit.awtUnlock();
853
}
854
} finally {
855
msg.dispose();
856
}
857
858
return true;
859
}
860
861
public Object getData(long ctxt, long format)
862
throws IllegalArgumentException, IOException {
863
XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
864
long message_type = xclient.get_message_type();
865
long time_stamp = XConstants.CurrentTime;
866
867
// NOTE: we assume that the source supports at least version 1, so we
868
// can use the time stamp
869
if (message_type == XDnDConstants.XA_XdndPosition.getAtom()) {
870
// X server time is an unsigned 32-bit number!
871
time_stamp = xclient.get_data(3) & 0xFFFFFFFFL;
872
} else if (message_type == XDnDConstants.XA_XdndDrop.getAtom()) {
873
// X server time is an unsigned 32-bit number!
874
time_stamp = xclient.get_data(2) & 0xFFFFFFFFL;
875
} else {
876
throw new IllegalArgumentException();
877
}
878
879
return XDnDConstants.XDnDSelection.getData(format, time_stamp);
880
}
881
882
public boolean sendDropDone(long ctxt, boolean success, int dropAction) {
883
XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
884
885
if (xclient.get_message_type() !=
886
XDnDConstants.XA_XdndDrop.getAtom()) {
887
return false;
888
}
889
890
/*
891
* The XDnD protocol recommends that the target requests the special
892
* target DELETE in case if the drop action is XdndActionMove.
893
*/
894
if (dropAction == DnDConstants.ACTION_MOVE && success) {
895
896
long time_stamp = xclient.get_data(2) & 0xFFFFFFFFL;
897
long xdndSelectionAtom =
898
XDnDConstants.XDnDSelection.getSelectionAtom().getAtom();
899
900
XToolkit.awtLock();
901
try {
902
XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
903
xdndSelectionAtom,
904
XAtom.get("DELETE").getAtom(),
905
XAtom.get("XAWT_SELECTION").getAtom(),
906
XWindow.getXAWTRootWindow().getWindow(),
907
time_stamp);
908
} finally {
909
XToolkit.awtUnlock();
910
}
911
}
912
913
XClientMessageEvent msg = new XClientMessageEvent();
914
try {
915
msg.set_type(XConstants.ClientMessage);
916
msg.set_window(xclient.get_data(0));
917
msg.set_format(32);
918
msg.set_message_type(XDnDConstants.XA_XdndFinished.getAtom());
919
msg.set_data(0, xclient.get_window()); /* target window */
920
msg.set_data(1, 0); /* flags */
921
/* specify an empty rectangle */
922
msg.set_data(2, 0);
923
if (sourceProtocolVersion >= 5) {
924
if (success) {
925
msg.set_data(1, XDnDConstants.XDND_ACCEPT_DROP_FLAG);
926
}
927
/* action performed by the target */
928
msg.set_data(2, XDnDConstants.getXDnDActionForJavaAction(dropAction));
929
}
930
msg.set_data(3, 0);
931
msg.set_data(4, 0);
932
933
XToolkit.awtLock();
934
try {
935
XlibWrapper.XSendEvent(XToolkit.getDisplay(),
936
xclient.get_data(0),
937
false, XConstants.NoEventMask,
938
msg.pData);
939
} finally {
940
XToolkit.awtUnlock();
941
}
942
} finally {
943
msg.dispose();
944
}
945
946
/*
947
* Flush the buffer to guarantee that the drop completion event is sent
948
* to the source before the method returns.
949
*/
950
XToolkit.awtLock();
951
try {
952
XlibWrapper.XFlush(XToolkit.getDisplay());
953
} finally {
954
XToolkit.awtUnlock();
955
}
956
957
/* Trick to prevent cleanup() from posting dragExit */
958
targetXWindow = null;
959
960
/* Cannot do cleanup before the drop finishes as we may need
961
source protocol version to send drop finished message. */
962
cleanup();
963
return true;
964
}
965
966
public final long getSourceWindow() {
967
return sourceWindow;
968
}
969
970
/**
971
* Reset the state of the object.
972
*/
973
public void cleanup() {
974
// Clear the reference to this protocol.
975
XDropTargetEventProcessor.reset();
976
977
if (targetXWindow != null) {
978
notifyProtocolListener(targetXWindow, 0, 0,
979
DnDConstants.ACTION_NONE, null,
980
MouseEvent.MOUSE_EXITED);
981
}
982
983
if (sourceWindow != 0) {
984
XToolkit.awtLock();
985
try {
986
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
987
XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
988
sourceWindowMask);
989
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
990
} finally {
991
XToolkit.awtUnlock();
992
}
993
}
994
995
sourceWindow = 0;
996
sourceWindowMask = 0;
997
sourceProtocolVersion = 0;
998
sourceActions = DnDConstants.ACTION_NONE;
999
sourceFormats = null;
1000
trackSourceActions = false;
1001
userAction = DnDConstants.ACTION_NONE;
1002
sourceX = 0;
1003
sourceY = 0;
1004
targetXWindow = null;
1005
}
1006
1007
public boolean isDragOverComponent() {
1008
return targetXWindow != null;
1009
}
1010
1011
public void adjustEventForForwarding(XClientMessageEvent xclient,
1012
EmbedderRegistryEntry entry) {
1013
/* Adjust the event to match the XDnD protocol version. */
1014
int version = entry.getVersion();
1015
if (xclient.get_message_type() == XDnDConstants.XA_XdndEnter.getAtom()) {
1016
int min_version = sourceProtocolVersion < version ?
1017
sourceProtocolVersion : version;
1018
long data1 = min_version << XDnDConstants.XDND_PROTOCOL_SHIFT;
1019
if (sourceFormats != null && sourceFormats.length > 3) {
1020
data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
1021
}
1022
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
1023
logger.finest(" "
1024
+ " entryVersion=" + version
1025
+ " sourceProtocolVersion=" +
1026
sourceProtocolVersion
1027
+ " sourceFormats.length=" +
1028
(sourceFormats != null ? sourceFormats.length : 0));
1029
}
1030
xclient.set_data(1, data1);
1031
}
1032
}
1033
1034
@SuppressWarnings("static")
1035
private void notifyProtocolListener(XWindow xwindow, int x, int y,
1036
int dropAction,
1037
XClientMessageEvent xclient,
1038
int eventID) {
1039
long nativeCtxt = 0;
1040
1041
// Make a copy of the passed XClientMessageEvent structure, since
1042
// the original structure can be freed before this
1043
// SunDropTargetEvent is dispatched.
1044
if (xclient != null) {
1045
int size = new XClientMessageEvent(nativeCtxt).getSize();
1046
1047
nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
1048
1049
unsafe.copyMemory(xclient.pData, nativeCtxt, size);
1050
1051
long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;
1052
if (sourceFormats != null && sourceFormats.length > 3) {
1053
data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
1054
}
1055
// Append information from the latest XdndEnter event.
1056
Native.putLong(nativeCtxt + size, data1);
1057
Native.putLong(nativeCtxt + size + Native.getLongSize(),
1058
sourceFormats.length > 0 ? sourceFormats[0] : 0);
1059
Native.putLong(nativeCtxt + size + 2 * Native.getLongSize(),
1060
sourceFormats.length > 1 ? sourceFormats[1] : 0);
1061
Native.putLong(nativeCtxt + size + 3 * Native.getLongSize(),
1062
sourceFormats.length > 2 ? sourceFormats[2] : 0);
1063
}
1064
1065
getProtocolListener().handleDropTargetNotification(xwindow, x, y,
1066
dropAction,
1067
sourceActions,
1068
sourceFormats,
1069
nativeCtxt,
1070
eventID);
1071
}
1072
1073
/*
1074
* The methods/fields defined below are executed/accessed only on
1075
* the toolkit thread.
1076
* The methods/fields defined below are executed/accessed only on the event
1077
* dispatch thread.
1078
*/
1079
1080
public boolean forwardEventToEmbedded(long embedded, long ctxt,
1081
int eventID) {
1082
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
1083
logger.finest(" ctxt=" + ctxt +
1084
" type=" + (ctxt != 0 ?
1085
getMessageType(new
1086
XClientMessageEvent(ctxt)) : 0) +
1087
" prevCtxt=" + prevCtxt +
1088
" prevType=" + (prevCtxt != 0 ?
1089
getMessageType(new
1090
XClientMessageEvent(prevCtxt)) : 0));
1091
}
1092
if ((ctxt == 0 ||
1093
getMessageType(new XClientMessageEvent(ctxt)) == UNKNOWN_MESSAGE) &&
1094
(prevCtxt == 0 ||
1095
getMessageType(new XClientMessageEvent(prevCtxt)) == UNKNOWN_MESSAGE)) {
1096
return false;
1097
}
1098
1099
// The size of XClientMessageEvent structure.
1100
int size = XClientMessageEvent.getSize();
1101
1102
if (ctxt != 0) {
1103
XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
1104
if (!overXEmbedClient) {
1105
long data1 = Native.getLong(ctxt + size);
1106
long data2 = Native.getLong(ctxt + size + Native.getLongSize());
1107
long data3 = Native.getLong(ctxt + size + 2 * Native.getLongSize());
1108
long data4 = Native.getLong(ctxt + size + 3 * Native.getLongSize());
1109
1110
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
1111
logger.finest(" 1 "
1112
+ " embedded=" + embedded
1113
+ " source=" + xclient.get_data(0)
1114
+ " data1=" + data1
1115
+ " data2=" + data2
1116
+ " data3=" + data3
1117
+ " data4=" + data4);
1118
}
1119
1120
// Copy XdndTypeList from source to proxy.
1121
if ((data1 & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {
1122
WindowPropertyGetter wpg =
1123
new WindowPropertyGetter(xclient.get_data(0),
1124
XDnDConstants.XA_XdndTypeList,
1125
0, 0xFFFF, false,
1126
XAtom.XA_ATOM);
1127
try {
1128
wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
1129
1130
if (wpg.getActualType() == XAtom.XA_ATOM &&
1131
wpg.getActualFormat() == 32) {
1132
1133
XToolkit.awtLock();
1134
try {
1135
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
1136
XDnDConstants.XA_XdndTypeList.setAtomData(xclient.get_window(),
1137
XAtom.XA_ATOM,
1138
wpg.getData(),
1139
wpg.getNumberOfItems());
1140
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
1141
1142
if ((XErrorHandlerUtil.saved_error != null) &&
1143
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
1144
if (logger.isLoggable(PlatformLogger.Level.WARNING)) {
1145
logger.warning("Cannot set XdndTypeList on the proxy window");
1146
}
1147
}
1148
} finally {
1149
XToolkit.awtUnlock();
1150
}
1151
} else {
1152
if (logger.isLoggable(PlatformLogger.Level.WARNING)) {
1153
logger.warning("Cannot read XdndTypeList from the source window");
1154
}
1155
}
1156
} finally {
1157
wpg.dispose();
1158
}
1159
}
1160
XDragSourceContextPeer.setProxyModeSourceWindow(xclient.get_data(0));
1161
1162
sendEnterMessageToToplevelImpl(embedded, xclient.get_window(),
1163
data1, data2, data3, data4);
1164
overXEmbedClient = true;
1165
}
1166
1167
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
1168
logger.finest(" 2 "
1169
+ " embedded=" + embedded
1170
+ " xclient=" + xclient);
1171
}
1172
1173
/* Make a copy of the original event, since we are going to modify the
1174
event while it still can be referenced from other Java events. */
1175
{
1176
XClientMessageEvent copy = new XClientMessageEvent();
1177
unsafe.copyMemory(xclient.pData, copy.pData, XClientMessageEvent.getSize());
1178
1179
copy.set_data(0, xclient.get_window());
1180
1181
forwardClientMessageToToplevel(embedded, copy);
1182
}
1183
}
1184
1185
if (eventID == MouseEvent.MOUSE_EXITED) {
1186
if (overXEmbedClient) {
1187
if (ctxt != 0 || prevCtxt != 0) {
1188
// Last chance to send XdndLeave to the XEmbed client.
1189
XClientMessageEvent xclient = ctxt != 0 ?
1190
new XClientMessageEvent(ctxt) :
1191
new XClientMessageEvent(prevCtxt);
1192
sendLeaveMessageToToplevelImpl(embedded, xclient.get_window());
1193
}
1194
overXEmbedClient = false;
1195
// We have to clear the proxy mode source window here,
1196
// when the drag exits the XEmbedCanvasPeer.
1197
// NOTE: at this point the XEmbed client still might have some
1198
// drag notifications to process and it will send responses to
1199
// us. With the proxy mode source window cleared we won't be
1200
// able to forward these responses to the actual source. This is
1201
// not a problem if the drag operation was initiated in this
1202
// JVM. However, if it was initiated in another processes the
1203
// responses will be lost. We bear with it for now, as it seems
1204
// there is no other reliable point to clear.
1205
XDragSourceContextPeer.setProxyModeSourceWindow(0);
1206
}
1207
}
1208
1209
if (eventID == MouseEvent.MOUSE_RELEASED) {
1210
overXEmbedClient = false;
1211
cleanup();
1212
}
1213
1214
if (prevCtxt != 0) {
1215
unsafe.freeMemory(prevCtxt);
1216
prevCtxt = 0;
1217
}
1218
1219
if (ctxt != 0 && overXEmbedClient) {
1220
prevCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
1221
1222
unsafe.copyMemory(ctxt, prevCtxt, size + 4 * Native.getLongSize());
1223
}
1224
1225
return true;
1226
}
1227
1228
public boolean isXEmbedSupported() {
1229
return true;
1230
}
1231
}
1232
1233