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