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