blob: a67a2f552a05ac63e158ffb645623481c806cf4a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.awt.X11;
27
28import java.awt.Point;
29
30import java.awt.dnd.DnDConstants;
31
32import java.awt.event.MouseEvent;
33
34import java.io.IOException;
35
36import sun.misc.Unsafe;
37
38/**
39 * XDropTargetProtocol implementation for Motif DnD protocol.
40 *
41 * @since 1.5
42 */
43class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
44 private static final Unsafe unsafe = XlibWrapper.unsafe;
45
46 private long sourceWindow = 0;
47 private long sourceWindowMask = 0;
48 private int sourceProtocolVersion = 0;
49 private int sourceActions = DnDConstants.ACTION_NONE;
50 private long[] sourceFormats = null;
51 private long sourceAtom = 0;
52 private int userAction = DnDConstants.ACTION_NONE;
53 private int sourceX = 0;
54 private int sourceY = 0;
55 private XWindow targetXWindow = null;
56 private boolean topLevelLeavePostponed = false;
57
58 protected MotifDnDDropTargetProtocol(XDropTargetProtocolListener listener) {
59 super(listener);
60 }
61
62 /**
63 * Creates an instance associated with the specified listener.
64 *
65 * @throws NullPointerException if listener is <code>null</code>.
66 */
67 static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) {
68 return new MotifDnDDropTargetProtocol(listener);
69 }
70
71 public String getProtocolName() {
72 return XDragAndDropProtocols.MotifDnD;
73 }
74
75 public void registerDropTarget(long window) {
76 assert XToolkit.isAWTLockHeldByCurrentThread();
77
78 MotifDnDConstants.writeDragReceiverInfoStruct(window);
79 }
80
81 public void unregisterDropTarget(long window) {
82 assert XToolkit.isAWTLockHeldByCurrentThread();
83
84 MotifDnDConstants.XA_MOTIF_ATOM_0.DeleteProperty(window);
85 }
86
87 public void registerEmbedderDropSite(long embedder) {
88 assert XToolkit.isAWTLockHeldByCurrentThread();
89
90 boolean overriden = false;
91 int version = 0;
92 long proxy = 0;
93 long newProxy = XDropTargetRegistry.getDnDProxyWindow();
94 int status = 0;
95 long data = 0;
96 int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
97
98 WindowPropertyGetter wpg =
99 new WindowPropertyGetter(embedder,
100 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
101 0, 0xFFFF, false,
102 XlibWrapper.AnyPropertyType);
103
104 try {
105 status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
106
107 /*
108 * DragICCI.h:
109 *
110 * typedef struct _xmDragReceiverInfoStruct{
111 * BYTE byte_order;
112 * BYTE protocol_version;
113 * BYTE drag_protocol_style;
114 * BYTE pad1;
115 * CARD32 proxy_window B32;
116 * CARD16 num_drop_sites B16;
117 * CARD16 pad2 B16;
118 * CARD32 heap_offset B32;
119 * } xmDragReceiverInfoStruct;
120 */
121 if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
122 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
123 wpg.getNumberOfItems() >=
124 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
125
126 overriden = true;
127 data = wpg.getData();
128 dataSize = wpg.getNumberOfItems();
129
130 byte byteOrderByte = unsafe.getByte(data);
131
132 {
133 int tproxy = unsafe.getInt(data + 4);
134 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
135 tproxy = MotifDnDConstants.Swapper.swap(tproxy);
136 }
137 proxy = tproxy;
138 }
139
140 if (proxy == newProxy) {
141 // Embedder already registered.
142 return;
143 }
144
145 {
146 int tproxy = (int)newProxy;
147 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
148 tproxy = MotifDnDConstants.Swapper.swap(tproxy);
149 }
150 unsafe.putInt(data + 4, tproxy);
151 }
152 } else {
153 data = unsafe.allocateMemory(dataSize);
154
155 unsafe.putByte(data, MotifDnDConstants.getByteOrderByte()); /* byte order */
156 unsafe.putByte(data + 1, MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
157 unsafe.putByte(data + 2, (byte)MotifDnDConstants.MOTIF_DYNAMIC_STYLE); /* protocol style */
158 unsafe.putByte(data + 3, (byte)0); /* pad */
159 unsafe.putInt(data + 4, (int)newProxy); /* proxy window */
160 unsafe.putShort(data + 8, (short)0); /* num_drop_sites */
161 unsafe.putShort(data + 10, (short)0); /* pad */
162 unsafe.putInt(data + 12, dataSize);
163 }
164
165 XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
166 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
167 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
168 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
169 8, XlibWrapper.PropModeReplace,
170 data, dataSize);
171 XToolkit.RESTORE_XERROR_HANDLER();
172
173 if (XToolkit.saved_error != null &&
174 XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
175 throw new XException("Cannot write Motif receiver info property");
176 }
177 } finally {
178 if (!overriden) {
179 unsafe.freeMemory(data);
180 data = 0;
181 }
182 wpg.dispose();
183 }
184
185 putEmbedderRegistryEntry(embedder, overriden, version, proxy);
186 }
187
188 public void unregisterEmbedderDropSite(long embedder) {
189 assert XToolkit.isAWTLockHeldByCurrentThread();
190
191 EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);
192
193 if (entry == null) {
194 return;
195 }
196
197 if (entry.isOverriden()) {
198 int status = 0;
199
200 WindowPropertyGetter wpg =
201 new WindowPropertyGetter(embedder,
202 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
203 0, 0xFFFF, false,
204 XlibWrapper.AnyPropertyType);
205
206 try {
207 status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
208
209 /*
210 * DragICCI.h:
211 *
212 * typedef struct _xmDragReceiverInfoStruct{
213 * BYTE byte_order;
214 * BYTE protocol_version;
215 * BYTE drag_protocol_style;
216 * BYTE pad1;
217 * CARD32 proxy_window B32;
218 * CARD16 num_drop_sites B16;
219 * CARD16 pad2 B16;
220 * CARD32 heap_offset B32;
221 * } xmDragReceiverInfoStruct;
222 */
223 if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
224 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
225 wpg.getNumberOfItems() >=
226 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
227
228 int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
229 long data = wpg.getData();
230 byte byteOrderByte = unsafe.getByte(data);
231
232 int tproxy = (int)entry.getProxy();
233 if (MotifDnDConstants.getByteOrderByte() != byteOrderByte) {
234 tproxy = MotifDnDConstants.Swapper.swap(tproxy);
235 }
236
237 unsafe.putInt(data + 4, tproxy);
238
239 XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
240 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
241 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
242 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
243 8, XlibWrapper.PropModeReplace,
244 data, dataSize);
245 XToolkit.RESTORE_XERROR_HANDLER();
246
247 if (XToolkit.saved_error != null &&
248 XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
249 throw new XException("Cannot write Motif receiver info property");
250 }
251 }
252 } finally {
253 wpg.dispose();
254 }
255 } else {
256 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.DeleteProperty(embedder);
257 }
258 }
259
260 /*
261 * Gets and stores in the registry the embedder's Motif DnD drop site info
262 * from the embedded.
263 */
264 public void registerEmbeddedDropSite(long embedded) {
265 assert XToolkit.isAWTLockHeldByCurrentThread();
266
267 boolean overriden = false;
268 int version = 0;
269 long proxy = 0;
270 int status = 0;
271
272 WindowPropertyGetter wpg =
273 new WindowPropertyGetter(embedded,
274 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
275 0, 0xFFFF, false,
276 XlibWrapper.AnyPropertyType);
277
278 try {
279 status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
280
281 /*
282 * DragICCI.h:
283 *
284 * typedef struct _xmDragReceiverInfoStruct{
285 * BYTE byte_order;
286 * BYTE protocol_version;
287 * BYTE drag_protocol_style;
288 * BYTE pad1;
289 * CARD32 proxy_window B32;
290 * CARD16 num_drop_sites B16;
291 * CARD16 pad2 B16;
292 * CARD32 heap_offset B32;
293 * } xmDragReceiverInfoStruct;
294 */
295 if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
296 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
297 wpg.getNumberOfItems() >=
298 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
299
300 overriden = true;
301 long data = wpg.getData();
302
303 byte byteOrderByte = unsafe.getByte(data);
304
305 {
306 int tproxy = unsafe.getInt(data + 4);
307 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
308 tproxy = MotifDnDConstants.Swapper.swap(tproxy);
309 }
310 proxy = tproxy;
311 }
312 }
313 } finally {
314 wpg.dispose();
315 }
316
317 putEmbedderRegistryEntry(embedded, overriden, version, proxy);
318 }
319
320 public boolean isProtocolSupported(long window) {
321 WindowPropertyGetter wpg =
322 new WindowPropertyGetter(window,
323 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
324 0, 0xFFFF, false,
325 XlibWrapper.AnyPropertyType);
326
327 try {
328 int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
329
330 if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
331 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
332 wpg.getNumberOfItems() >=
333 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
334 return true;
335 } else {
336 return false;
337 }
338 } finally {
339 wpg.dispose();
340 }
341 }
342
343 private boolean processTopLevelEnter(XClientMessageEvent xclient) {
344 assert XToolkit.isAWTLockHeldByCurrentThread();
345
346 if (targetXWindow != null || sourceWindow != 0) {
347 return false;
348 }
349
350 if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)
351 && getEmbedderRegistryEntry(xclient.get_window()) == null) {
352 return false;
353 }
354
355 long source_win = 0;
356 long source_win_mask = 0;
357 int protocol_version = 0;
358 long property_atom = 0;
359 long[] formats = null;
360
361 {
362 long data = xclient.get_data();
363 byte eventByteOrder = unsafe.getByte(data + 1);
364 source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder);
365 property_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
366 }
367
368 /* Extract the available data types. */
369 {
370 WindowPropertyGetter wpg =
371 new WindowPropertyGetter(source_win,
372 XAtom.get(property_atom),
373 0, 0xFFFF,
374 false,
375 MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom());
376
377 try {
378 int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
379
380 if (status == XlibWrapper.Success && wpg.getData() != 0 &&
381 wpg.getActualType() ==
382 MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom() &&
383 wpg.getActualFormat() == 8 &&
384 wpg.getNumberOfItems() ==
385 MotifDnDConstants.MOTIF_INITIATOR_INFO_SIZE) {
386
387 long data = wpg.getData();
388 byte propertyByteOrder = unsafe.getByte(data);
389
390 protocol_version = unsafe.getByte(data + 1);
391
392 if (protocol_version !=
393 MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION) {
394 return false;
395 }
396
397 int index =
398 MotifDnDConstants.Swapper.getShort(data + 2, propertyByteOrder);
399
400 formats = MotifDnDConstants.getTargetListForIndex(index);
401 } else {
402 formats = new long[0];
403 }
404 } finally {
405 wpg.dispose();
406 }
407 }
408
409 /*
410 * Select for StructureNotifyMask to receive DestroyNotify in case of source
411 * crash.
412 */
413 XWindowAttributes wattr = new XWindowAttributes();
414 try {
415 XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
416 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
417 source_win, wattr.pData);
418
419 XToolkit.RESTORE_XERROR_HANDLER();
420
421 if (status == 0 ||
422 (XToolkit.saved_error != null &&
423 XToolkit.saved_error.get_error_code() != XlibWrapper.Success)) {
424 throw new XException("XGetWindowAttributes failed");
425 }
426
427 source_win_mask = wattr.get_your_event_mask();
428 } finally {
429 wattr.dispose();
430 }
431
432 XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
433 XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
434 source_win_mask |
435 XlibWrapper.StructureNotifyMask);
436
437 XToolkit.RESTORE_XERROR_HANDLER();
438
439 if (XToolkit.saved_error != null &&
440 XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
441 throw new XException("XSelectInput failed");
442 }
443
444 sourceWindow = source_win;
445 sourceWindowMask = source_win_mask;
446 sourceProtocolVersion = protocol_version;
447 /*
448 * TOP_LEVEL_ENTER doesn't communicate the list of supported actions
449 * They are provided in DRAG_MOTION.
450 */
451 sourceActions = DnDConstants.ACTION_NONE;
452 sourceFormats = formats;
453 sourceAtom = property_atom;
454
455 return true;
456 }
457
458 private boolean processDragMotion(XClientMessageEvent xclient) {
459 long data = xclient.get_data();
460 byte eventByteOrder = unsafe.getByte(data + 1);
461 byte eventReason = (byte)(unsafe.getByte(data) &
462 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
463 int x = 0;
464 int y = 0;
465
466 short flags = MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder);
467
468 int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
469 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
470 int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >>
471 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
472
473 int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
474 int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions);
475
476 /* Append source window id to the event data, so that we can send the
477 response properly. */
478 {
479 int win = (int)sourceWindow;
480 if (eventByteOrder != MotifDnDConstants.getByteOrderByte()) {
481 win = MotifDnDConstants.Swapper.swap(win);
482 }
483 unsafe.putInt(data + 12, win);
484 }
485
486 XWindow xwindow = null;
487 {
488 XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());
489 if (xbasewindow instanceof XWindow) {
490 xwindow = (XWindow)xbasewindow;
491 }
492 }
493
494 if (eventReason == MotifDnDConstants.OPERATION_CHANGED) {
495 /* OPERATION_CHANGED event doesn't provide coordinates, so we use
496 previously stored position and component ref. */
497 x = sourceX;
498 y = sourceY;
499
500 if (xwindow == null) {
501 xwindow = targetXWindow;
502 }
503 } else {
504 x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder);
505 y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder);
506
507 if (xwindow == null) {
508 long receiver =
509 XDropTargetRegistry.getRegistry().getEmbeddedDropSite(
510 xclient.get_window(), x, y);
511
512 if (receiver != 0) {
513 XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);
514 if (xbasewindow instanceof XWindow) {
515 xwindow = (XWindow)xbasewindow;
516 }
517 }
518 }
519
520 if (xwindow != null) {
521 Point p = xwindow.toLocal(x, y);
522 x = p.x;
523 y = p.y;
524 }
525 }
526
527 if (xwindow == null) {
528 if (targetXWindow != null) {
529 notifyProtocolListener(targetXWindow, x, y,
530 DnDConstants.ACTION_NONE, java_actions,
531 xclient, MouseEvent.MOUSE_EXITED);
532 }
533 } else {
534 int java_event_id = 0;
535
536 if (targetXWindow == null) {
537 java_event_id = MouseEvent.MOUSE_ENTERED;
538 } else {
539 java_event_id = MouseEvent.MOUSE_DRAGGED;
540 }
541
542 notifyProtocolListener(xwindow, x, y, java_action, java_actions,
543 xclient, java_event_id);
544 }
545
546 sourceActions = java_actions;
547 userAction = java_action;
548 sourceX = x;
549 sourceY = y;
550 targetXWindow = xwindow;
551
552 return true;
553 }
554
555 private boolean processTopLevelLeave(XClientMessageEvent xclient) {
556 assert XToolkit.isAWTLockHeldByCurrentThread();
557
558 long data = xclient.get_data();
559 byte eventByteOrder = unsafe.getByte(data + 1);
560
561 long source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder);
562
563 /* Ignore Motif DnD messages from all other windows. */
564 if (source_win != sourceWindow) {
565 return false;
566 }
567
568 /*
569 * Postpone upcall to java, so that we can abort it in case
570 * if drop immediatelly follows (see BugTraq ID 4395290).
571 * Send a dummy ClientMessage event to guarantee that a postponed java
572 * upcall will be processed.
573 */
574 topLevelLeavePostponed = true;
575 {
576 long proxy;
577
578 /*
579 * If this is an embedded drop site, the event should go to the
580 * awt_root_window as this is a proxy for all embedded drop sites.
581 * Otherwise the event should go to the event->window, as we don't use
582 * proxies for normal drop sites.
583 */
584 if (getEmbedderRegistryEntry(xclient.get_window()) != null) {
585 proxy = XDropTargetRegistry.getDnDProxyWindow();
586 } else {
587 proxy = xclient.get_window();
588 }
589
590 XClientMessageEvent dummy = new XClientMessageEvent();
591
592 try {
593 dummy.set_type(XlibWrapper.ClientMessage);
594 dummy.set_window(xclient.get_window());
595 dummy.set_format(32);
596 dummy.set_message_type(0);
597 dummy.set_data(0, 0);
598 dummy.set_data(1, 0);
599 dummy.set_data(2, 0);
600 dummy.set_data(3, 0);
601 dummy.set_data(4, 0);
602 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
603 proxy, false, XlibWrapper.NoEventMask,
604 dummy.pData);
605 } finally {
606 dummy.dispose();
607 }
608 }
609 return true;
610 }
611
612 private boolean processDropStart(XClientMessageEvent xclient) {
613 long data = xclient.get_data();
614 byte eventByteOrder = unsafe.getByte(data + 1);
615
616 long source_win =
617 MotifDnDConstants.Swapper.getInt(data + 16, eventByteOrder);
618
619 /* Ignore Motif DnD messages from all other windows. */
620 if (source_win != sourceWindow) {
621 return false;
622 }
623
624 long property_atom =
625 MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
626
627 short flags =
628 MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder);
629
630 int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
631 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
632 int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >>
633 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
634
635 int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
636 int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions);
637
638 int x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder);
639 int y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder);
640
641 XWindow xwindow = null;
642 {
643 XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());
644 if (xbasewindow instanceof XWindow) {
645 xwindow = (XWindow)xbasewindow;
646 }
647 }
648
649 if (xwindow == null) {
650 long receiver =
651 XDropTargetRegistry.getRegistry().getEmbeddedDropSite(
652 xclient.get_window(), x, y);
653
654 if (receiver != 0) {
655 XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);
656 if (xbasewindow instanceof XWindow) {
657 xwindow = (XWindow)xbasewindow;
658 }
659 }
660 }
661
662 if (xwindow != null) {
663 Point p = xwindow.toLocal(x, y);
664 x = p.x;
665 y = p.y;
666 }
667
668 if (xwindow != null) {
669 notifyProtocolListener(xwindow, x, y, java_action, java_actions,
670 xclient, MouseEvent.MOUSE_RELEASED);
671 } else if (targetXWindow != null) {
672 notifyProtocolListener(targetXWindow, x, y,
673 DnDConstants.ACTION_NONE, java_actions,
674 xclient, MouseEvent.MOUSE_EXITED);
675 }
676
677 return true;
678 }
679
680 public int getMessageType(XClientMessageEvent xclient) {
681 if (xclient.get_message_type() !=
682 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
683
684 return UNKNOWN_MESSAGE;
685 }
686
687 long data = xclient.get_data();
688 byte reason = (byte)(unsafe.getByte(data) &
689 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
690
691 switch (reason) {
692 case MotifDnDConstants.TOP_LEVEL_ENTER :
693 return ENTER_MESSAGE;
694 case MotifDnDConstants.DRAG_MOTION :
695 case MotifDnDConstants.OPERATION_CHANGED :
696 return MOTION_MESSAGE;
697 case MotifDnDConstants.TOP_LEVEL_LEAVE :
698 return LEAVE_MESSAGE;
699 case MotifDnDConstants.DROP_START :
700 return DROP_MESSAGE;
701 default:
702 return UNKNOWN_MESSAGE;
703 }
704 }
705
706 protected boolean processClientMessageImpl(XClientMessageEvent xclient) {
707 if (xclient.get_message_type() !=
708 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
709 if (topLevelLeavePostponed) {
710 topLevelLeavePostponed = false;
711 cleanup();
712 }
713
714 return false;
715 }
716
717 long data = xclient.get_data();
718 byte reason = (byte)(unsafe.getByte(data) &
719 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
720 byte origin = (byte)(unsafe.getByte(data) &
721 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
722
723 if (topLevelLeavePostponed) {
724 topLevelLeavePostponed = false;
725 if (reason != MotifDnDConstants.DROP_START) {
726 cleanup();
727 }
728 }
729
730 /* Only initiator messages should be handled. */
731 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
732 return false;
733 }
734
735 switch (reason) {
736 case MotifDnDConstants.TOP_LEVEL_ENTER :
737 return processTopLevelEnter(xclient);
738 case MotifDnDConstants.DRAG_MOTION :
739 case MotifDnDConstants.OPERATION_CHANGED :
740 return processDragMotion(xclient);
741 case MotifDnDConstants.TOP_LEVEL_LEAVE :
742 return processTopLevelLeave(xclient);
743 case MotifDnDConstants.DROP_START :
744 return processDropStart(xclient);
745 default:
746 return false;
747 }
748 }
749
750 /*
751 * Currently we don't synthesize enter/leave messages for Motif DnD
752 * protocol. See comments in XDropTargetProtocol.postProcessClientMessage.
753 */
754 protected void sendEnterMessageToToplevel(long win,
755 XClientMessageEvent xclient) {
756 throw new Error("UNIMPLEMENTED");
757 }
758
759 protected void sendLeaveMessageToToplevel(long win,
760 XClientMessageEvent xclient) {
761 throw new Error("UNIMPLEMENTED");
762 }
763
764 public boolean forwardEventToEmbedded(long embedded, long ctxt,
765 int eventID) {
766 // UNIMPLEMENTED.
767 return false;
768 }
769
770 public boolean isXEmbedSupported() {
771 return false;
772 }
773
774 public boolean sendResponse(long ctxt, int eventID, int action) {
775 XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
776 if (xclient.get_message_type() !=
777 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
778 return false;
779 }
780
781 long data = xclient.get_data();
782 byte reason = (byte)(unsafe.getByte(data) &
783 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
784 byte origin = (byte)(unsafe.getByte(data) &
785 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
786 byte eventByteOrder = unsafe.getByte(data + 1);
787 byte response_reason = (byte)0;
788
789 /* Only initiator messages should be handled. */
790 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
791 return false;
792 }
793
794 switch (reason) {
795 case MotifDnDConstants.TOP_LEVEL_ENTER:
796 case MotifDnDConstants.TOP_LEVEL_LEAVE:
797 /* Receiver shouldn't rely to these messages. */
798 return false;
799 case MotifDnDConstants.DRAG_MOTION:
800 switch (eventID) {
801 case MouseEvent.MOUSE_ENTERED:
802 response_reason = MotifDnDConstants.DROP_SITE_ENTER;
803 break;
804 case MouseEvent.MOUSE_DRAGGED:
805 response_reason = MotifDnDConstants.DRAG_MOTION;
806 break;
807 case MouseEvent.MOUSE_EXITED:
808 response_reason = MotifDnDConstants.DROP_SITE_LEAVE;
809 break;
810 }
811 break;
812 case MotifDnDConstants.OPERATION_CHANGED:
813 case MotifDnDConstants.DROP_START:
814 response_reason = reason;
815 break;
816 default:
817 // Unknown reason. Shouldn't get here.
818 assert false;
819 }
820
821 XClientMessageEvent msg = new XClientMessageEvent();
822
823 try {
824 msg.set_type(XlibWrapper.ClientMessage);
825 msg.set_window(MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder));
826 msg.set_format(8);
827 msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
828
829 long responseData = msg.get_data();
830
831 unsafe.putByte(responseData, (byte)(response_reason |
832 MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER));
833 unsafe.putByte(responseData + 1, MotifDnDConstants.getByteOrderByte());
834
835 int response_flags = 0;
836
837 if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
838 short flags = MotifDnDConstants.Swapper.getShort(data + 2,
839 eventByteOrder);
840 byte dropSiteStatus = (action == DnDConstants.ACTION_NONE) ?
841 MotifDnDConstants.MOTIF_INVALID_DROP_SITE :
842 MotifDnDConstants.MOTIF_VALID_DROP_SITE;
843
844 /* Clear action and drop site status bits. */
845 response_flags = flags &
846 ~MotifDnDConstants.MOTIF_DND_ACTION_MASK &
847 ~MotifDnDConstants.MOTIF_DND_STATUS_MASK;
848 /* Fill in new action and drop site status. */
849 response_flags |=
850 MotifDnDConstants.getMotifActionsForJavaActions(action) <<
851 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
852 response_flags |=
853 dropSiteStatus << MotifDnDConstants.MOTIF_DND_STATUS_SHIFT;
854 } else {
855 response_flags = 0;
856 }
857
858 unsafe.putShort(responseData + 2, (short)response_flags);
859
860 /* Write time stamp. */
861 int time = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
862 unsafe.putInt(responseData + 4, time);
863
864 /* Write coordinates. */
865 if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
866 short x = MotifDnDConstants.Swapper.getShort(data + 8,
867 eventByteOrder);
868 short y = MotifDnDConstants.Swapper.getShort(data + 10,
869 eventByteOrder);
870 unsafe.putShort(responseData + 8, x); // x
871 unsafe.putShort(responseData + 10, y); // y
872 } else {
873 unsafe.putShort(responseData + 8, (short)0); // x
874 unsafe.putShort(responseData + 10, (short)0); // y
875 }
876
877 XToolkit.awtLock();
878 try {
879 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
880 msg.get_window(),
881 false, XlibWrapper.NoEventMask,
882 msg.pData);
883 } finally {
884 XToolkit.awtUnlock();
885 }
886 } finally {
887 msg.dispose();
888 }
889
890 return true;
891 }
892
893 public Object getData(long ctxt, long format)
894 throws IllegalArgumentException, IOException {
895 XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
896
897 if (xclient.get_message_type() !=
898 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
899 throw new IllegalArgumentException();
900 }
901
902 long data = xclient.get_data();
903 byte reason = (byte)(unsafe.getByte(data) &
904 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
905 byte origin = (byte)(unsafe.getByte(data) &
906 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
907 byte eventByteOrder = unsafe.getByte(data + 1);
908
909 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
910 throw new IOException("Cannot get data: corrupted context");
911 }
912
913 long selatom = 0;
914
915 switch (reason) {
916 case MotifDnDConstants.DRAG_MOTION :
917 case MotifDnDConstants.OPERATION_CHANGED :
918 selatom = sourceAtom;
919 break;
920 case MotifDnDConstants.DROP_START :
921 selatom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
922 break;
923 default:
924 throw new IOException("Cannot get data: invalid message reason");
925 }
926
927 if (selatom == 0) {
928 throw new IOException("Cannot get data: drag source property atom unavailable");
929 }
930
931 long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
932 XAtom selectionAtom = XAtom.get(selatom);
933
934 XSelection selection = XSelection.getSelection(selectionAtom);
935 if (selection == null) {
936 selection = new XSelection(selectionAtom, null);
937 }
938
939 return selection.getData(format, time_stamp);
940 }
941
942 public boolean sendDropDone(long ctxt, boolean success, int dropAction) {
943 XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
944
945 if (xclient.get_message_type() !=
946 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
947 return false;
948 }
949
950 long data = xclient.get_data();
951 byte reason = (byte)(unsafe.getByte(data) &
952 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
953 byte origin = (byte)(unsafe.getByte(data) &
954 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
955 byte eventByteOrder = unsafe.getByte(data + 1);
956
957 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
958 return false;
959 }
960
961 if (reason != MotifDnDConstants.DROP_START) {
962 return false;
963 }
964
965 long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
966 long sel_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
967
968 long status_atom = 0;
969
970 if (success) {
971 status_atom = MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom();
972 } else {
973 status_atom = MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom();
974 }
975
976 XToolkit.awtLock();
977 try {
978 XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
979 sel_atom,
980 status_atom,
981 MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom(),
982 XWindow.getXAWTRootWindow().getWindow(),
983 time_stamp);
984
985 /*
986 * Flush the buffer to guarantee that the drop completion event is sent
987 * to the source before the method returns.
988 */
989 XlibWrapper.XFlush(XToolkit.getDisplay());
990 } finally {
991 XToolkit.awtUnlock();
992 }
993
994 /* Trick to prevent cleanup() from posting dragExit */
995 targetXWindow = null;
996
997 /* Cannot do cleanup before the drop finishes as we may need
998 source protocol version to send drop finished message. */
999 cleanup();
1000 return true;
1001 }
1002
1003 public final long getSourceWindow() {
1004 return sourceWindow;
1005 }
1006
1007 /**
1008 * Reset the state of the object.
1009 */
1010 public void cleanup() {
1011 // Clear the reference to this protocol.
1012 XDropTargetEventProcessor.reset();
1013
1014 if (targetXWindow != null) {
1015 notifyProtocolListener(targetXWindow, 0, 0,
1016 DnDConstants.ACTION_NONE, sourceActions,
1017 null, MouseEvent.MOUSE_EXITED);
1018 }
1019
1020 if (sourceWindow != 0) {
1021 XToolkit.awtLock();
1022 try {
1023 XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
1024 XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
1025 sourceWindowMask);
1026 XToolkit.RESTORE_XERROR_HANDLER();
1027 } finally {
1028 XToolkit.awtUnlock();
1029 }
1030 }
1031
1032 sourceWindow = 0;
1033 sourceWindowMask = 0;
1034 sourceProtocolVersion = 0;
1035 sourceActions = DnDConstants.ACTION_NONE;
1036 sourceFormats = null;
1037 sourceAtom = 0;
1038 userAction = DnDConstants.ACTION_NONE;
1039 sourceX = 0;
1040 sourceY = 0;
1041 targetXWindow = null;
1042 topLevelLeavePostponed = false;
1043 }
1044
1045 public boolean isDragOverComponent() {
1046 return targetXWindow != null;
1047 }
1048
1049 private void notifyProtocolListener(XWindow xwindow, int x, int y,
1050 int dropAction, int actions,
1051 XClientMessageEvent xclient,
1052 int eventID) {
1053 long nativeCtxt = 0;
1054
1055 // Make a copy of the passed XClientMessageEvent structure, since
1056 // the original structure can be freed before this
1057 // SunDropTargetEvent is dispatched.
1058 if (xclient != null) {
1059 int size = new XClientMessageEvent(nativeCtxt).getSize();
1060
1061 nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
1062
1063 unsafe.copyMemory(xclient.pData, nativeCtxt, size);
1064 }
1065
1066 getProtocolListener().handleDropTargetNotification(xwindow, x, y,
1067 dropAction,
1068 actions,
1069 sourceFormats,
1070 nativeCtxt,
1071 eventID);
1072 }
1073}