1 /*
2  * Copyright (c) 2003, 2013, 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 
XDragSourceContextPeer(DragGestureEvent dge)98     private XDragSourceContextPeer(DragGestureEvent dge) {
99         super(dge);
100     }
101 
getXDragSourceProtocolListener()102     static XDragSourceProtocolListener getXDragSourceProtocolListener() {
103         return theInstance;
104     }
105 
createDragSourceContextPeer(DragGestureEvent dge)106     static XDragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
107       throws InvalidDnDOperationException {
108     theInstance.setTrigger(dge);
109         return theInstance;
110     }
111 
startDrag(Transferable transferable, long[] formats, Map formatMap)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 
getProxyModeSourceWindow()239     public long getProxyModeSourceWindow() {
240         return proxyModeSourceWindow;
241     }
242 
setProxyModeSourceWindowImpl(long window)243     private void setProxyModeSourceWindowImpl(long window) {
244         proxyModeSourceWindow = window;
245     }
246 
setProxyModeSourceWindow(long window)247     public static void setProxyModeSourceWindow(long window) {
248         theInstance.setProxyModeSourceWindowImpl(window);
249     }
250 
251     /**
252      * set cursor
253      */
254 
setCursor(Cursor c)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 
setNativeCursor(long nativeCtxt, Cursor c, int cType)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 
needsBogusExitBeforeDrop()283     protected boolean needsBogusExitBeforeDrop() {
284         return false;
285     }
286 
throwGrabFailureException(String msg, int grabStatus)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      */
cleanup(long time)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      */
cleanupTargetInfo()344     private void cleanupTargetInfo() {
345         targetAction = DnDConstants.ACTION_NONE;
346         dragProtocol = null;
347         targetRootSubwindow = 0;
348     }
349 
removeDnDGrab(long time)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 
processClientMessage(XClientMessageEvent xclient)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      */
updateSourceAction(int state)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      */
findClientWindow(long window)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 
doUpdateTargetWindow(long subwindow, long time)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 
updateTargetWindow(XMotionEvent xmotion)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      */
processMouseMove(XMotionEvent xmotion)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 
processDrop(XButtonEvent xbutton)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 
processProxyModeEvent(XEvent ev)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.Level.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      */
doProcessEvent(XEvent ev)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 
processEvent(XEvent ev)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 
handleDragReply(int action)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 
handleDragReply(int action, int x, int y)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 
handleDragReply(int action, int x, int y, int modifiers)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 
handleDragFinished()781     public void handleDragFinished() {
782         /* Assume that the drop was successful. */
783         handleDragFinished(true);
784     }
785 
handleDragFinished(boolean success)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 
handleDragFinished(boolean success, int action)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 
handleDragFinished(boolean success, int action, int x, int y)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 }
805