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 }