1 /*
2 * Copyright (c) 2003, 2008, 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.Component;
29 import java.awt.Cursor;
30 import java.awt.Window;
31
32 import java.awt.datatransfer.Transferable;
33
34 import java.awt.dnd.DnDConstants;
35 import java.awt.dnd.DragGestureEvent;
36 import java.awt.dnd.InvalidDnDOperationException;
37
38 import java.util.*;
39
40 import sun.util.logging.PlatformLogger;
41
42 import sun.awt.dnd.SunDragSourceContextPeer;
43 import sun.awt.dnd.SunDropTargetContextPeer;
44 import sun.awt.SunToolkit;
45 import sun.awt.AWTAccessor;
46
47 /**
48 * The XDragSourceContextPeer class is the class responsible for handling
49 * the interaction between the XDnD/Motif DnD subsystem and Java drag sources.
50 *
51 * @since 1.5
52 */
53 public final class XDragSourceContextPeer
54 extends SunDragSourceContextPeer implements XDragSourceProtocolListener {
55 private static final PlatformLogger logger =
56 PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDragSourceContextPeer");
57
58 /* The events selected on the root window when the drag begins. */
59 private static final int ROOT_EVENT_MASK = (int)XConstants.ButtonMotionMask |
60 (int)XConstants.KeyPressMask | (int)XConstants.KeyReleaseMask;
61 /* The events to be delivered during grab. */
62 private static final int GRAB_EVENT_MASK = (int)XConstants.ButtonPressMask |
63 (int)XConstants.ButtonMotionMask | (int)XConstants.ButtonReleaseMask;
64
65 /* The event mask of the root window before the drag operation starts. */
66 private long rootEventMask = 0;
67 private boolean dndInProgress = false;
68 private boolean dragInProgress = false;
69 private long dragRootWindow = 0;
70
71 /* The protocol chosen for the communication with the current drop target. */
72 private XDragSourceProtocol dragProtocol = null;
73 /* The drop action chosen by the current drop target. */
74 private int targetAction = DnDConstants.ACTION_NONE;
75 /* The set of drop actions supported by the drag source. */
76 private int sourceActions = DnDConstants.ACTION_NONE;
77 /* The drop action selected by the drag source based on the modifiers state
78 and the action selected by the current drop target. */
79 private int sourceAction = DnDConstants.ACTION_NONE;
80 /* The data formats supported by the drag source for the current drag
81 operation. */
82 private long[] sourceFormats = null;
83 /* The XID of the root subwindow that contains the current target. */
84 private long targetRootSubwindow = 0;
85 /* The pointer location. */
86 private int xRoot = 0;
87 private int yRoot = 0;
88 /* Keyboard modifiers state. */
89 private int eventState = 0;
90
91 /* XEmbed DnD support. We act as a proxy between source and target. */
92 private long proxyModeSourceWindow = 0;
93
94 /* The singleton instance. */
95 private static final XDragSourceContextPeer theInstance =
96 new XDragSourceContextPeer(null);
97
98 private XDragSourceContextPeer(DragGestureEvent dge) {
99 super(dge);
100 }
101
102 static XDragSourceProtocolListener getXDragSourceProtocolListener() {
103 return theInstance;
104 }
105
106 static XDragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
107 throws InvalidDnDOperationException {
108 theInstance.setTrigger(dge);
109 return theInstance;
110 }
111
112 protected void startDrag(Transferable transferable,
113 long[] formats, Map formatMap) {
114 Component component = getTrigger().getComponent();
115 Component c = null;
116 XWindowPeer wpeer = null;
117
118 for (c = component; c != null && !(c instanceof Window);
119 c = AWTAccessor.getComponentAccessor().getParent(c));
120
121 if (c instanceof Window) {
122 wpeer = (XWindowPeer)c.getPeer();
123 }
124
125 if (wpeer == null) {
126 throw new InvalidDnDOperationException(
127 "Cannot find top-level for the drag source component");
128 }
129
130 long xcursor = 0;
131 long rootWindow = 0;
132 long dragWindow = 0;
133 long timeStamp = 0;
134
135 /* Retrieve the X cursor for the drag operation. */
136 {
137 Cursor cursor = getCursor();
138 if (cursor != null) {
139 xcursor = XGlobalCursorManager.getCursor(cursor);
140 }
141 }
142
143 XToolkit.awtLock();
144 try {
145 if (proxyModeSourceWindow != 0) {
146 throw new InvalidDnDOperationException("Proxy drag in progress");
147 }
148 if (dndInProgress) {
149 throw new InvalidDnDOperationException("Drag in progress");
150 }
151
152 /* Determine the root window for the drag operation. */
153 {
154 long screen = XlibWrapper.XScreenNumberOfScreen(wpeer.getScreen());
155 rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen);
156 }
157
158 dragWindow = XWindow.getXAWTRootWindow().getWindow();
159
160 timeStamp = XToolkit.getCurrentServerTime();
161
162 int dropActions = getDragSourceContext().getSourceActions();
163
164 Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
165 while (dragProtocols.hasNext()) {
166 XDragSourceProtocol dragProtocol = (XDragSourceProtocol)dragProtocols.next();
167 try {
168 dragProtocol.initializeDrag(dropActions, transferable,
169 formatMap, formats);
170 } catch (XException xe) {
171 throw (InvalidDnDOperationException)
172 new InvalidDnDOperationException().initCause(xe);
173 }
174 }
175
176 /* Install X grabs. */
177 {
178 int status;
179 XWindowAttributes wattr = new XWindowAttributes();
180 try {
181 status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
182 rootWindow, wattr.pData);
183
184 if (status == 0) {
185 throw new InvalidDnDOperationException("XGetWindowAttributes failed");
186 }
187
188 rootEventMask = wattr.get_your_event_mask();
189
190 XlibWrapper.XSelectInput(XToolkit.getDisplay(), rootWindow,
191 rootEventMask | ROOT_EVENT_MASK);
192 } finally {
193 wattr.dispose();
194 }
195
196 XBaseWindow.ungrabInput();
197
198 status = XlibWrapper.XGrabPointer(XToolkit.getDisplay(), rootWindow,
199 0, GRAB_EVENT_MASK,
200 XConstants.GrabModeAsync,
201 XConstants.GrabModeAsync,
202 XConstants.None, xcursor, timeStamp);
203
204 if (status != XConstants.GrabSuccess) {
205 cleanup(timeStamp);
206 throwGrabFailureException("Cannot grab pointer", status);
207 return;
208 }
209
210 status = XlibWrapper.XGrabKeyboard(XToolkit.getDisplay(), rootWindow,
211 0,
212 XConstants.GrabModeAsync,
213 XConstants.GrabModeAsync,
214 timeStamp);
215
216 if (status != XConstants.GrabSuccess) {
217 cleanup(timeStamp);
218 throwGrabFailureException("Cannot grab keyboard", status);
219 return;
220 }
221 }
222
223 /* Update the global state. */
224 dndInProgress = true;
225 dragInProgress = true;
226 dragRootWindow = rootWindow;
227 sourceActions = dropActions;
228 sourceFormats = formats;
229 } finally {
230 XToolkit.awtUnlock();
231 }
232
233 /* This implementation doesn't use native context */
234 setNativeContext(0);
235
236 SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(transferable);
237 }
238
239 public long getProxyModeSourceWindow() {
240 return proxyModeSourceWindow;
241 }
242
243 private void setProxyModeSourceWindowImpl(long window) {
244 proxyModeSourceWindow = window;
245 }
246
247 public static void setProxyModeSourceWindow(long window) {
248 theInstance.setProxyModeSourceWindowImpl(window);
249 }
250
251 /**
252 * set cursor
253 */
254
255 public void setCursor(Cursor c) throws InvalidDnDOperationException {
256 XToolkit.awtLock();
257 try {
258 super.setCursor(c);
259 } finally {
260 XToolkit.awtUnlock();
261 }
262 }
263
264 protected void setNativeCursor(long nativeCtxt, Cursor c, int cType) {
265 assert XToolkit.isAWTLockHeldByCurrentThread();
266
267 if (c == null) {
268 return;
269 }
270
271 long xcursor = XGlobalCursorManager.getCursor(c);
272
273 if (xcursor == 0) {
274 return;
275 }
276
277 XlibWrapper.XChangeActivePointerGrab(XToolkit.getDisplay(),
278 GRAB_EVENT_MASK,
279 xcursor,
280 XConstants.CurrentTime);
281 }
282
283 protected boolean needsBogusExitBeforeDrop() {
284 return false;
285 }
286
287 private void throwGrabFailureException(String msg, int grabStatus)
288 throws InvalidDnDOperationException {
289 String msgCause = "";
290 switch (grabStatus) {
291 case XConstants.GrabNotViewable: msgCause = "not viewable"; break;
292 case XConstants.AlreadyGrabbed: msgCause = "already grabbed"; break;
293 case XConstants.GrabInvalidTime: msgCause = "invalid time"; break;
294 case XConstants.GrabFrozen: msgCause = "grab frozen"; break;
295 default: msgCause = "unknown failure"; break;
296 }
297 throw new InvalidDnDOperationException(msg + ": " + msgCause);
298 }
299
300 /**
301 * The caller must own awtLock.
302 */
303 public void cleanup(long time) {
304 if (dndInProgress) {
305 if (dragProtocol != null) {
306 dragProtocol.sendLeaveMessage(time);
307 }
308
309 if (targetAction != DnDConstants.ACTION_NONE) {
310 dragExit(xRoot, yRoot);
311 }
312
313 dragDropFinished(false, DnDConstants.ACTION_NONE, xRoot, yRoot);
314 }
315
316 Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
317 while (dragProtocols.hasNext()) {
318 XDragSourceProtocol dragProtocol = (XDragSourceProtocol)dragProtocols.next();
319 try {
320 dragProtocol.cleanup();
321 } catch (XException xe) {
322 // Ignore the exception.
323 }
324 }
325
326 dndInProgress = false;
327 dragInProgress = false;
328 dragRootWindow = 0;
329 sourceFormats = null;
330 sourceActions = DnDConstants.ACTION_NONE;
331 sourceAction = DnDConstants.ACTION_NONE;
332 eventState = 0;
333 xRoot = 0;
334 yRoot = 0;
335
336 cleanupTargetInfo();
337
338 removeDnDGrab(time);
339 }
340
341 /**
342 * The caller must own awtLock.
343 */
344 private void cleanupTargetInfo() {
345 targetAction = DnDConstants.ACTION_NONE;
346 dragProtocol = null;
347 targetRootSubwindow = 0;
348 }
349
350 private void removeDnDGrab(long time) {
351 assert XToolkit.isAWTLockHeldByCurrentThread();
352
353 XlibWrapper.XUngrabPointer(XToolkit.getDisplay(), time);
354 XlibWrapper.XUngrabKeyboard(XToolkit.getDisplay(), time);
355
356 /* Restore the root event mask if it was changed. */
357 if ((rootEventMask | ROOT_EVENT_MASK) != rootEventMask &&
358 dragRootWindow != 0) {
359
360 XlibWrapper.XSelectInput(XToolkit.getDisplay(),
361 dragRootWindow,
362 rootEventMask);
363 }
364
365 rootEventMask = 0;
366 dragRootWindow = 0;
367 }
368
369 private boolean processClientMessage(XClientMessageEvent xclient) {
370 if (dragProtocol != null) {
371 return dragProtocol.processClientMessage(xclient);
372 }
373 return false;
374 }
375
376 /**
377 * Updates the source action according to the specified state.
378 *
379 * @returns true if the source
380 */
381 private boolean updateSourceAction(int state) {
382 int action = SunDragSourceContextPeer.convertModifiersToDropAction(XWindow.getModifiers(state, 0, 0),
383 sourceActions);
384 if (sourceAction == action) {
385 return false;
386 }
387 sourceAction = action;
388 return true;
389 }
390
391 /**
392 * Returns the client window under the specified root subwindow.
393 */
394 private static long findClientWindow(long window) {
395 if (XlibUtil.isTrueToplevelWindow(window)) {
396 return window;
397 }
398
399 Set<Long> children = XlibUtil.getChildWindows(window);
400 for (Long child : children) {
401 long win = findClientWindow(child);
402 if (win != 0) {
403 return win;
404 }
405 }
406
407 return 0;
408 }
409
410 private void doUpdateTargetWindow(long subwindow, long time) {
411 long clientWindow = 0;
412 long proxyWindow = 0;
413 XDragSourceProtocol protocol = null;
414 boolean isReceiver = false;
415
416 if (subwindow != 0) {
417 clientWindow = findClientWindow(subwindow);
418 }
419
420 if (clientWindow != 0) {
421 Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
422 while (dragProtocols.hasNext()) {
423 XDragSourceProtocol dragProtocol = (XDragSourceProtocol)dragProtocols.next();
424 if (dragProtocol.attachTargetWindow(clientWindow, time)) {
425 protocol = dragProtocol;
426 break;
427 }
428 }
429 }
430
431 /* Update the global state. */
432 dragProtocol = protocol;
433 targetAction = DnDConstants.ACTION_NONE;
434 targetRootSubwindow = subwindow;
435 }
436
437 private void updateTargetWindow(XMotionEvent xmotion) {
438 assert XToolkit.isAWTLockHeldByCurrentThread();
439
440 int x = xmotion.get_x_root();
441 int y = xmotion.get_y_root();
442 long time = xmotion.get_time();
443 long subwindow = xmotion.get_subwindow();
444
445 /*
446 * If this event had occurred before the pointer was grabbed,
447 * query the server for the current root subwindow.
448 */
449 if (xmotion.get_window() != xmotion.get_root()) {
450 XlibWrapper.XQueryPointer(XToolkit.getDisplay(),
451 xmotion.get_root(),
452 XlibWrapper.larg1, // root
453 XlibWrapper.larg2, // subwindow
454 XlibWrapper.larg3, // x_root
455 XlibWrapper.larg4, // y_root
456 XlibWrapper.larg5, // x
457 XlibWrapper.larg6, // y
458 XlibWrapper.larg7); // modifiers
459 subwindow = Native.getLong(XlibWrapper.larg2);
460 }
461
462 if (targetRootSubwindow != subwindow) {
463 if (dragProtocol != null) {
464 dragProtocol.sendLeaveMessage(time);
465
466 /*
467 * Neither Motif DnD nor XDnD provide a mean for the target
468 * to notify the source that the pointer exits the drop site
469 * that occupies the whole top level.
470 * We detect this situation and post dragExit.
471 */
472 if (targetAction != DnDConstants.ACTION_NONE) {
473 dragExit(x, y);
474 }
475 }
476
477 /* Update the global state. */
478 doUpdateTargetWindow(subwindow, time);
479
480 if (dragProtocol != null) {
481 dragProtocol.sendEnterMessage(sourceFormats,
482 sourceAction,
483 sourceActions,
484 time);
485 }
486 }
487 }
488
489 /*
490 * DO NOT USE is_hint field of xmotion since it could not be set when we
491 * convert XKeyEvent or XButtonRelease to XMotionEvent.
492 */
493 private void processMouseMove(XMotionEvent xmotion) {
494 if (!dragInProgress) {
495 return;
496 }
497 if (xRoot != xmotion.get_x_root() || yRoot != xmotion.get_y_root()) {
498 xRoot = xmotion.get_x_root();
499 yRoot = xmotion.get_y_root();
500
501 postDragSourceDragEvent(targetAction,
502 XWindow.getModifiers(xmotion.get_state(),0,0),
503 xRoot, yRoot, DISPATCH_MOUSE_MOVED);
504 }
505
506 if (eventState != xmotion.get_state()) {
507 if (updateSourceAction(xmotion.get_state()) && dragProtocol != null) {
508 postDragSourceDragEvent(targetAction,
509 XWindow.getModifiers(xmotion.get_state(),0,0),
510 xRoot, yRoot, DISPATCH_CHANGED);
511 }
512 eventState = xmotion.get_state();
513 }
514
515 updateTargetWindow(xmotion);
516
517 if (dragProtocol != null) {
518 dragProtocol.sendMoveMessage(xmotion.get_x_root(),
519 xmotion.get_y_root(),
520 sourceAction, sourceActions,
521 xmotion.get_time());
522 }
523 }
524
525 private void processDrop(XButtonEvent xbutton) {
526 try {
527 dragProtocol.initiateDrop(xbutton.get_x_root(),
528 xbutton.get_y_root(),
529 sourceAction, sourceActions,
530 xbutton.get_time());
531 } catch (XException e) {
532 cleanup(xbutton.get_time());
533 }
534 }
535
536 private boolean processProxyModeEvent(XEvent ev) {
537 if (getProxyModeSourceWindow() == 0) {
538 return false;
539 }
540
541 if (ev.get_type() != (int)XConstants.ClientMessage) {
542 return false;
543 }
544
545 if (logger.isLoggable(PlatformLogger.FINEST)) {
546 logger.finest(" proxyModeSourceWindow=" +
547 getProxyModeSourceWindow() +
548 " ev=" + ev);
549 }
550
551 XClientMessageEvent xclient = ev.get_xclient();
552
553 Iterator dragProtocols = XDragAndDropProtocols.getDragSourceProtocols();
554 while (dragProtocols.hasNext()) {
555 XDragSourceProtocol dragProtocol =
556 (XDragSourceProtocol)dragProtocols.next();
557 if (dragProtocol.processProxyModeEvent(xclient,
558 getProxyModeSourceWindow())) {
559 return true;
560 }
561 }
562
563 return false;
564 }
565
566 /**
567 * The caller must own awtLock.
568 *
569 * @returns true if the even was processed and shouldn't be passed along.
570 */
571 private boolean doProcessEvent(XEvent ev) {
572 assert XToolkit.isAWTLockHeldByCurrentThread();
573
574 if (processProxyModeEvent(ev)) {
575 return true;
576 }
577
578 if (!dndInProgress) {
579 return false;
580 }
581
582 switch (ev.get_type()) {
583 case XConstants.ClientMessage: {
584 XClientMessageEvent xclient = ev.get_xclient();
585 return processClientMessage(xclient);
586 }
587 case XConstants.DestroyNotify: {
588 XDestroyWindowEvent xde = ev.get_xdestroywindow();
589
590 /* Target crashed during drop processing - cleanup. */
591 if (!dragInProgress &&
592 dragProtocol != null &&
593 xde.get_window() == dragProtocol.getTargetWindow()) {
594 cleanup(XConstants.CurrentTime);
595 return true;
596 }
597 /* Pass along */
598 return false;
599 }
600 }
601
602 if (!dragInProgress) {
603 return false;
604 }
605
606 /* Process drag-only messages. */
607 switch (ev.get_type()) {
608 case XConstants.KeyRelease:
609 case XConstants.KeyPress: {
610 XKeyEvent xkey = ev.get_xkey();
611 long keysym = XlibWrapper.XKeycodeToKeysym(XToolkit.getDisplay(),
612 xkey.get_keycode(), 0);
613 switch ((int)keysym) {
614 case (int)XKeySymConstants.XK_Escape: {
615 if (ev.get_type() == (int)XConstants.KeyRelease) {
616 cleanup(xkey.get_time());
617 }
618 break;
619 }
620 case (int)XKeySymConstants.XK_Control_R:
621 case (int)XKeySymConstants.XK_Control_L:
622 case (int)XKeySymConstants.XK_Shift_R:
623 case (int)XKeySymConstants.XK_Shift_L: {
624 XlibWrapper.XQueryPointer(XToolkit.getDisplay(),
625 xkey.get_root(),
626 XlibWrapper.larg1, // root
627 XlibWrapper.larg2, // subwindow
628 XlibWrapper.larg3, // x_root
629 XlibWrapper.larg4, // y_root
630 XlibWrapper.larg5, // x
631 XlibWrapper.larg6, // y
632 XlibWrapper.larg7); // modifiers
633 XMotionEvent xmotion = new XMotionEvent();
634 try {
635 xmotion.set_type(XConstants.MotionNotify);
636 xmotion.set_serial(xkey.get_serial());
637 xmotion.set_send_event(xkey.get_send_event());
638 xmotion.set_display(xkey.get_display());
639 xmotion.set_window(xkey.get_window());
640 xmotion.set_root(xkey.get_root());
641 xmotion.set_subwindow(xkey.get_subwindow());
642 xmotion.set_time(xkey.get_time());
643 xmotion.set_x(xkey.get_x());
644 xmotion.set_y(xkey.get_y());
645 xmotion.set_x_root(xkey.get_x_root());
646 xmotion.set_y_root(xkey.get_y_root());
647 xmotion.set_state((int)Native.getLong(XlibWrapper.larg7));
648 // we do not use this field, so it's unset for now
649 // xmotion.set_is_hint(???);
650 xmotion.set_same_screen(xkey.get_same_screen());
651
652 //It's safe to use key event as motion event since we use only their common fields.
653 processMouseMove(xmotion);
654 } finally {
655 xmotion.dispose();
656 }
657 break;
658 }
659 }
660 return true;
661 }
662 case XConstants.ButtonPress:
663 return true;
664 case XConstants.MotionNotify:
665 processMouseMove(ev.get_xmotion());
666 return true;
667 case XConstants.ButtonRelease: {
668 XButtonEvent xbutton = ev.get_xbutton();
669 /*
670 * Ignore the buttons above 20 due to the bit limit for
671 * InputEvent.BUTTON_DOWN_MASK.
672 * One more bit is reserved for FIRST_HIGH_BIT.
673 */
674 if (xbutton.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) {
675 return true;
676 }
677
678 /*
679 * On some X servers it could happen that ButtonRelease coordinates
680 * differ from the latest MotionNotify coordinates, so we need to
681 * process it as a mouse motion.
682 */
683 XMotionEvent xmotion = new XMotionEvent();
684 try {
685 xmotion.set_type(XConstants.MotionNotify);
686 xmotion.set_serial(xbutton.get_serial());
687 xmotion.set_send_event(xbutton.get_send_event());
688 xmotion.set_display(xbutton.get_display());
689 xmotion.set_window(xbutton.get_window());
690 xmotion.set_root(xbutton.get_root());
691 xmotion.set_subwindow(xbutton.get_subwindow());
692 xmotion.set_time(xbutton.get_time());
693 xmotion.set_x(xbutton.get_x());
694 xmotion.set_y(xbutton.get_y());
695 xmotion.set_x_root(xbutton.get_x_root());
696 xmotion.set_y_root(xbutton.get_y_root());
697 xmotion.set_state(xbutton.get_state());
698 // we do not use this field, so it's unset for now
699 // xmotion.set_is_hint(???);
700 xmotion.set_same_screen(xbutton.get_same_screen());
701
702 //It's safe to use key event as motion event since we use only their common fields.
703 processMouseMove(xmotion);
704 } finally {
705 xmotion.dispose();
706 }
707 if (xbutton.get_button() == XConstants.buttons[0]
708 || xbutton.get_button() == XConstants.buttons[1]) {
709 // drag is initiated with Button1 or Button2 pressed and
710 // ended on release of either of these buttons (as the same
711 // behavior was with our old Motif DnD-based implementation)
712 removeDnDGrab(xbutton.get_time());
713 dragInProgress = false;
714 if (dragProtocol != null && targetAction != DnDConstants.ACTION_NONE) {
715 /*
716 * ACTION_NONE indicates that either the drop target rejects the
717 * drop or it haven't responded yet. The latter could happen in
718 * case of fast drag, slow target-server connection or slow
719 * drag notifications processing on the target side.
720 */
721 processDrop(xbutton);
722 } else {
723 cleanup(xbutton.get_time());
724 }
725 }
726 return true;
727 }
728 }
729
730 return false;
731 }
732
733 static boolean processEvent(XEvent ev) {
734 XToolkit.awtLock();
735 try {
736 try {
737 return theInstance.doProcessEvent(ev);
738 } catch (XException e) {
739 e.printStackTrace();
740 return false;
741 }
742 } finally {
743 XToolkit.awtUnlock();
744 }
745 }
746
747 /* XDragSourceProtocolListener implementation */
748
749 public void handleDragReply(int action) {
750 // NOTE: we have to use the current pointer location, since
751 // the target didn't specify the coordinates for the reply.
752 handleDragReply(action, xRoot, yRoot);
753 }
754
755 public void handleDragReply(int action, int x, int y) {
756 // NOTE: we have to use the current modifiers state, since
757 // the target didn't specify the modifiers state for the reply.
758 handleDragReply(action, xRoot, yRoot, XWindow.getModifiers(eventState,0,0));
759 }
760
761 public void handleDragReply(int action, int x, int y, int modifiers) {
762 if (action == DnDConstants.ACTION_NONE &&
763 targetAction != DnDConstants.ACTION_NONE) {
764 dragExit(x, y);
765 } else if (action != DnDConstants.ACTION_NONE) {
766 int type = 0;
767
768 if (targetAction == DnDConstants.ACTION_NONE) {
769 type = SunDragSourceContextPeer.DISPATCH_ENTER;
770 } else {
771 type = SunDragSourceContextPeer.DISPATCH_MOTION;
772 }
773
774 // Note that we use the modifiers state a
775 postDragSourceDragEvent(action, modifiers, x, y, type);
776 }
777
778 targetAction = action;
779 }
780
781 public void handleDragFinished() {
782 /* Assume that the drop was successful. */
783 handleDragFinished(true);
784 }
785
786 public void handleDragFinished(boolean success) {
787 /* Assume that the performed drop action is the latest drop action
788 accepted by the drop target. */
789 handleDragFinished(true, targetAction);
790 }
791
792 public void handleDragFinished(boolean success, int action) {
793 // NOTE: we have to use the current pointer location, since
794 // the target didn't specify the coordinates for the reply.
795 handleDragFinished(success, action, xRoot, yRoot);
796 }
797
798 public void handleDragFinished(boolean success, int action, int x, int y) {
799 dragDropFinished(success, action, x, y);
800
801 dndInProgress = false;
802 cleanup(XConstants.CurrentTime);
803 }
804 }
--- EOF ---