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 }