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