1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt.X11; 27 28 import java.awt.Point; 29 30 import java.awt.dnd.DnDConstants; 31 32 import java.awt.event.MouseEvent; 33 34 import java.io.IOException; 35 36 import sun.util.logging.PlatformLogger; 37 38 import sun.misc.Unsafe; 39 40 /** 41 * XDropTargetProtocol implementation for XDnD protocol. 42 * 43 * @since 1.5 44 */ 45 class XDnDDropTargetProtocol extends XDropTargetProtocol { 46 private static final PlatformLogger logger = 47 PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDnDDropTargetProtocol"); 48 49 private static final Unsafe unsafe = XlibWrapper.unsafe; 50 51 private long sourceWindow = 0; 52 private long sourceWindowMask = 0; 53 private int sourceProtocolVersion = 0; 54 private int sourceActions = DnDConstants.ACTION_NONE; 55 private long[] sourceFormats = null; 56 private boolean trackSourceActions = false; 57 private int userAction = DnDConstants.ACTION_NONE; 58 private int sourceX = 0; 59 private int sourceY = 0; 60 private XWindow targetXWindow = null; 61 62 // XEmbed stuff. 63 private long prevCtxt = 0; 64 private boolean overXEmbedClient = false; 65 66 protected XDnDDropTargetProtocol(XDropTargetProtocolListener listener) { 67 super(listener); 68 } 69 70 /** 71 * Creates an instance associated with the specified listener. 72 * 73 * @throws NullPointerException if listener is <code>null</code>. 74 */ 75 static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) { 76 return new XDnDDropTargetProtocol(listener); 77 } 78 79 public String getProtocolName() { 80 return XDragAndDropProtocols.XDnD; 81 } 82 83 public void registerDropTarget(long window) { 84 assert XToolkit.isAWTLockHeldByCurrentThread(); 85 86 long data = Native.allocateLongArray(1); 87 88 try { 89 Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION); 90 91 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 92 XDnDConstants.XA_XdndAware.setAtomData(window, XAtom.XA_ATOM, data, 1); 93 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 94 95 if ((XErrorHandlerUtil.saved_error != null) && 96 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 97 throw new XException("Cannot write XdndAware property"); 98 } 99 } finally { 100 unsafe.freeMemory(data); 101 data = 0; 102 } 103 } 104 105 public void unregisterDropTarget(long window) { 106 assert XToolkit.isAWTLockHeldByCurrentThread(); 107 108 XDnDConstants.XA_XdndAware.DeleteProperty(window); 109 } 110 111 public void registerEmbedderDropSite(long embedder) { 112 assert XToolkit.isAWTLockHeldByCurrentThread(); 113 114 boolean overriden = false; 115 int version = 0; 116 long proxy = 0; 117 long newProxy = XDropTargetRegistry.getDnDProxyWindow(); 118 int status = 0; 119 120 WindowPropertyGetter wpg1 = 121 new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndAware, 0, 1, 122 false, XConstants.AnyPropertyType); 123 124 try { 125 status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 126 127 if (status == XConstants.Success && 128 wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) { 129 130 overriden = true; 131 version = (int)Native.getLong(wpg1.getData()); 132 } 133 } finally { 134 wpg1.dispose(); 135 } 136 137 /* XdndProxy is not supported for prior to XDnD version 4 */ 138 if (overriden && version >= 4) { 139 WindowPropertyGetter wpg2 = 140 new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndProxy, 141 0, 1, false, XAtom.XA_WINDOW); 142 143 try { 144 status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 145 146 if (status == XConstants.Success && 147 wpg2.getData() != 0 && 148 wpg2.getActualType() == XAtom.XA_WINDOW) { 149 150 proxy = Native.getLong(wpg2.getData()); 151 } 152 } finally { 153 wpg2.dispose(); 154 } 155 156 if (proxy != 0) { 157 WindowPropertyGetter wpg3 = 158 new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy, 159 0, 1, false, XAtom.XA_WINDOW); 160 161 try { 162 status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 163 164 if (status != XConstants.Success || 165 wpg3.getData() == 0 || 166 wpg3.getActualType() != XAtom.XA_WINDOW || 167 Native.getLong(wpg3.getData()) != proxy) { 168 169 proxy = 0; 170 } else { 171 WindowPropertyGetter wpg4 = 172 new WindowPropertyGetter(proxy, 173 XDnDConstants.XA_XdndAware, 174 0, 1, false, 175 XConstants.AnyPropertyType); 176 177 try { 178 status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 179 180 if (status != XConstants.Success || 181 wpg4.getData() == 0 || 182 wpg4.getActualType() != XAtom.XA_ATOM) { 183 184 proxy = 0; 185 } 186 } finally { 187 wpg4.dispose(); 188 } 189 } 190 } finally { 191 wpg3.dispose(); 192 } 193 } 194 } 195 196 if (proxy == newProxy) { 197 // Embedder already registered. 198 return; 199 } 200 201 long data = Native.allocateLongArray(1); 202 203 try { 204 Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION); 205 206 /* The proxy window must have the XdndAware set, as XDnD protocol 207 prescribes to check the proxy window for XdndAware. */ 208 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 209 XDnDConstants.XA_XdndAware.setAtomData(newProxy, XAtom.XA_ATOM, 210 data, 1); 211 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 212 213 if ((XErrorHandlerUtil.saved_error != null) && 214 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 215 throw new XException("Cannot write XdndAware property"); 216 } 217 218 Native.putLong(data, 0, newProxy); 219 220 /* The proxy window must have the XdndProxy set to point to itself.*/ 221 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 222 XDnDConstants.XA_XdndProxy.setAtomData(newProxy, XAtom.XA_WINDOW, 223 data, 1); 224 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 225 226 if ((XErrorHandlerUtil.saved_error != null) && 227 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 228 throw new XException("Cannot write XdndProxy property"); 229 } 230 231 Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION); 232 233 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 234 XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM, 235 data, 1); 236 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 237 238 if ((XErrorHandlerUtil.saved_error != null) && 239 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 240 throw new XException("Cannot write XdndAware property"); 241 } 242 243 Native.putLong(data, 0, newProxy); 244 245 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 246 XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW, 247 data, 1); 248 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 249 250 if ((XErrorHandlerUtil.saved_error != null) && 251 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 252 throw new XException("Cannot write XdndProxy property"); 253 } 254 } finally { 255 unsafe.freeMemory(data); 256 data = 0; 257 } 258 259 putEmbedderRegistryEntry(embedder, overriden, version, proxy); 260 } 261 262 public void unregisterEmbedderDropSite(long embedder) { 263 assert XToolkit.isAWTLockHeldByCurrentThread(); 264 265 EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder); 266 267 if (entry == null) { 268 return; 269 } 270 271 if (entry.isOverriden()) { 272 long data = Native.allocateLongArray(1); 273 274 try { 275 Native.putLong(data, 0, entry.getVersion()); 276 277 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 278 XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM, 279 data, 1); 280 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 281 282 if ((XErrorHandlerUtil.saved_error != null) && 283 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 284 throw new XException("Cannot write XdndAware property"); 285 } 286 287 Native.putLong(data, 0, (int)entry.getProxy()); 288 289 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 290 XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW, 291 data, 1); 292 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 293 294 if ((XErrorHandlerUtil.saved_error != null) && 295 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 296 throw new XException("Cannot write XdndProxy property"); 297 } 298 } finally { 299 unsafe.freeMemory(data); 300 data = 0; 301 } 302 } else { 303 XDnDConstants.XA_XdndAware.DeleteProperty(embedder); 304 XDnDConstants.XA_XdndProxy.DeleteProperty(embedder); 305 } 306 } 307 308 /* 309 * Gets and stores in the registry the embedder's XDnD drop site info 310 * from the embedded. 311 */ 312 public void registerEmbeddedDropSite(long embedded) { 313 assert XToolkit.isAWTLockHeldByCurrentThread(); 314 315 boolean overriden = false; 316 int version = 0; 317 long proxy = 0; 318 long newProxy = XDropTargetRegistry.getDnDProxyWindow(); 319 int status = 0; 320 321 WindowPropertyGetter wpg1 = 322 new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndAware, 0, 1, 323 false, XConstants.AnyPropertyType); 324 325 try { 326 status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 327 328 if (status == XConstants.Success && 329 wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) { 330 331 overriden = true; 332 version = (int)Native.getLong(wpg1.getData()); 333 } 334 } finally { 335 wpg1.dispose(); 336 } 337 338 /* XdndProxy is not supported for prior to XDnD version 4 */ 339 if (overriden && version >= 4) { 340 WindowPropertyGetter wpg2 = 341 new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndProxy, 342 0, 1, false, XAtom.XA_WINDOW); 343 344 try { 345 status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 346 347 if (status == XConstants.Success && 348 wpg2.getData() != 0 && 349 wpg2.getActualType() == XAtom.XA_WINDOW) { 350 351 proxy = Native.getLong(wpg2.getData()); 352 } 353 } finally { 354 wpg2.dispose(); 355 } 356 357 if (proxy != 0) { 358 WindowPropertyGetter wpg3 = 359 new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy, 360 0, 1, false, XAtom.XA_WINDOW); 361 362 try { 363 status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 364 365 if (status != XConstants.Success || 366 wpg3.getData() == 0 || 367 wpg3.getActualType() != XAtom.XA_WINDOW || 368 Native.getLong(wpg3.getData()) != proxy) { 369 370 proxy = 0; 371 } else { 372 WindowPropertyGetter wpg4 = 373 new WindowPropertyGetter(proxy, 374 XDnDConstants.XA_XdndAware, 375 0, 1, false, 376 XConstants.AnyPropertyType); 377 378 try { 379 status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 380 381 if (status != XConstants.Success || 382 wpg4.getData() == 0 || 383 wpg4.getActualType() != XAtom.XA_ATOM) { 384 385 proxy = 0; 386 } 387 } finally { 388 wpg4.dispose(); 389 } 390 } 391 } finally { 392 wpg3.dispose(); 393 } 394 } 395 } 396 397 putEmbedderRegistryEntry(embedded, overriden, version, proxy); 398 } 399 400 public boolean isProtocolSupported(long window) { 401 assert XToolkit.isAWTLockHeldByCurrentThread(); 402 403 WindowPropertyGetter wpg1 = 404 new WindowPropertyGetter(window, XDnDConstants.XA_XdndAware, 0, 1, 405 false, XConstants.AnyPropertyType); 406 407 try { 408 int status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 409 410 if (status == XConstants.Success && 411 wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) { 412 413 return true; 414 } else { 415 return false; 416 } 417 } finally { 418 wpg1.dispose(); 419 } 420 } 421 422 private boolean processXdndEnter(XClientMessageEvent xclient) { 423 long source_win = 0; 424 long source_win_mask = 0; 425 int protocol_version = 0; 426 int actions = DnDConstants.ACTION_NONE; 427 boolean track = true; 428 long[] formats = null; 429 430 if (getSourceWindow() != 0) { 431 return false; 432 } 433 434 if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow) 435 && getEmbedderRegistryEntry(xclient.get_window()) == null) { 436 return false; 437 } 438 439 if (xclient.get_message_type() != XDnDConstants.XA_XdndEnter.getAtom()){ 440 return false; 441 } 442 443 protocol_version = 444 (int)((xclient.get_data(1) & XDnDConstants.XDND_PROTOCOL_MASK) >> 445 XDnDConstants.XDND_PROTOCOL_SHIFT); 446 447 /* XDnD compliance only requires supporting version 3 and up. */ 448 if (protocol_version < XDnDConstants.XDND_MIN_PROTOCOL_VERSION) { 449 return false; 450 } 451 452 /* Ignore the source if the protocol version is higher than we support. */ 453 if (protocol_version > XDnDConstants.XDND_PROTOCOL_VERSION) { 454 return false; 455 } 456 457 source_win = xclient.get_data(0); 458 459 /* Extract the list of supported actions. */ 460 if (protocol_version < 2) { 461 /* Prior to XDnD version 2 only COPY action was supported. */ 462 actions = DnDConstants.ACTION_COPY; 463 } else { 464 WindowPropertyGetter wpg = 465 new WindowPropertyGetter(source_win, 466 XDnDConstants.XA_XdndActionList, 467 0, 0xFFFF, false, 468 XAtom.XA_ATOM); 469 try { 470 wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 471 472 if (wpg.getActualType() == XAtom.XA_ATOM && 473 wpg.getActualFormat() == 32) { 474 long data = wpg.getData(); 475 476 for (int i = 0; i < wpg.getNumberOfItems(); i++) { 477 actions |= 478 XDnDConstants.getJavaActionForXDnDAction(Native.getLong(data, i)); 479 } 480 } else { 481 /* 482 * According to XDnD protocol, XdndActionList is optional. 483 * If XdndActionList is not set we try to guess which actions are 484 * supported. 485 */ 486 actions = DnDConstants.ACTION_COPY; 487 track = true; 488 } 489 } finally { 490 wpg.dispose(); 491 } 492 } 493 494 /* Extract the available data types. */ 495 if ((xclient.get_data(1) & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) { 496 WindowPropertyGetter wpg = 497 new WindowPropertyGetter(source_win, 498 XDnDConstants.XA_XdndTypeList, 499 0, 0xFFFF, false, 500 XAtom.XA_ATOM); 501 try { 502 wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 503 504 if (wpg.getActualType() == XAtom.XA_ATOM && 505 wpg.getActualFormat() == 32) { 506 formats = Native.toLongs(wpg.getData(), 507 wpg.getNumberOfItems()); 508 } else { 509 formats = new long[0]; 510 } 511 } finally { 512 wpg.dispose(); 513 } 514 } else { 515 int countFormats = 0; 516 long[] formats3 = new long[3]; 517 518 for (int i = 0; i < 3; i++) { 519 long j; 520 if ((j = xclient.get_data(2 + i)) != XConstants.None) { 521 formats3[countFormats++] = j; 522 } 523 } 524 525 formats = new long[countFormats]; 526 527 System.arraycopy(formats3, 0, formats, 0, countFormats); 528 } 529 530 assert XToolkit.isAWTLockHeldByCurrentThread(); 531 532 /* 533 * Select for StructureNotifyMask to receive DestroyNotify in case of source 534 * crash. 535 */ 536 XWindowAttributes wattr = new XWindowAttributes(); 537 try { 538 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 539 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), 540 source_win, wattr.pData); 541 542 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 543 544 if ((status == 0) || 545 ((XErrorHandlerUtil.saved_error != null) && 546 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) { 547 throw new XException("XGetWindowAttributes failed"); 548 } 549 550 source_win_mask = wattr.get_your_event_mask(); 551 } finally { 552 wattr.dispose(); 553 } 554 555 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 556 XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win, 557 source_win_mask | 558 XConstants.StructureNotifyMask); 559 560 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 561 562 if ((XErrorHandlerUtil.saved_error != null) && 563 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 564 throw new XException("XSelectInput failed"); 565 } 566 567 sourceWindow = source_win; 568 sourceWindowMask = source_win_mask; 569 sourceProtocolVersion = protocol_version; 570 sourceActions = actions; 571 sourceFormats = formats; 572 trackSourceActions = track; 573 574 return true; 575 } 576 577 private boolean processXdndPosition(XClientMessageEvent xclient) { 578 long time_stamp = (int)XConstants.CurrentTime; 579 long xdnd_action = 0; 580 int java_action = DnDConstants.ACTION_NONE; 581 int x = 0; 582 int y = 0; 583 584 /* Ignore XDnD messages from all other windows. */ 585 if (sourceWindow != xclient.get_data(0)) { 586 return false; 587 } 588 589 XWindow xwindow = null; 590 { 591 XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window()); 592 if (xbasewindow instanceof XWindow) { 593 xwindow = (XWindow)xbasewindow; 594 } 595 } 596 597 x = (int)(xclient.get_data(2) >> 16); 598 y = (int)(xclient.get_data(2) & 0xFFFF); 599 600 if (xwindow == null) { 601 long receiver = 602 XDropTargetRegistry.getRegistry().getEmbeddedDropSite( 603 xclient.get_window(), x, y); 604 605 if (receiver != 0) { 606 XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver); 607 if (xbasewindow instanceof XWindow) { 608 xwindow = (XWindow)xbasewindow; 609 } 610 } 611 } 612 613 if (xwindow != null) { 614 /* Translate mouse position from root coordinates 615 to the target window coordinates. */ 616 Point p = xwindow.toLocal(x, y); 617 x = p.x; 618 y = p.y; 619 } 620 621 /* Time stamp - new in XDnD version 1. */ 622 if (sourceProtocolVersion > 0) { 623 time_stamp = xclient.get_data(3); 624 } 625 626 /* User action - new in XDnD version 2. */ 627 if (sourceProtocolVersion > 1) { 628 xdnd_action = xclient.get_data(4); 629 } else { 630 /* The default action is XdndActionCopy */ 631 xdnd_action = XDnDConstants.XA_XdndActionCopy.getAtom(); 632 } 633 634 java_action = XDnDConstants.getJavaActionForXDnDAction(xdnd_action); 635 636 if (trackSourceActions) { 637 sourceActions |= java_action; 638 } 639 640 if (xwindow == null) { 641 if (targetXWindow != null) { 642 notifyProtocolListener(targetXWindow, x, y, 643 DnDConstants.ACTION_NONE, xclient, 644 MouseEvent.MOUSE_EXITED); 645 } 646 } else { 647 int java_event_id = 0; 648 649 if (targetXWindow == null) { 650 java_event_id = MouseEvent.MOUSE_ENTERED; 651 } else { 652 java_event_id = MouseEvent.MOUSE_DRAGGED; 653 } 654 655 notifyProtocolListener(xwindow, x, y, java_action, xclient, 656 java_event_id); 657 } 658 659 userAction = java_action; 660 sourceX = x; 661 sourceY = y; 662 targetXWindow = xwindow; 663 664 return true; 665 } 666 667 private boolean processXdndLeave(XClientMessageEvent xclient) { 668 /* Ignore XDnD messages from all other windows. */ 669 if (sourceWindow != xclient.get_data(0)) { 670 return false; 671 } 672 673 cleanup(); 674 675 return true; 676 } 677 678 private boolean processXdndDrop(XClientMessageEvent xclient) { 679 /* Ignore XDnD messages from all other windows. */ 680 if (sourceWindow != xclient.get_data(0)) { 681 return false; 682 } 683 684 if (targetXWindow != null) { 685 notifyProtocolListener(targetXWindow, sourceX, sourceY, userAction, 686 xclient, MouseEvent.MOUSE_RELEASED); 687 } 688 689 return true; 690 } 691 692 public int getMessageType(XClientMessageEvent xclient) { 693 long messageType = xclient.get_message_type(); 694 695 if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) { 696 return ENTER_MESSAGE; 697 } else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) { 698 return MOTION_MESSAGE; 699 } else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) { 700 return LEAVE_MESSAGE; 701 } else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) { 702 return DROP_MESSAGE; 703 } else { 704 return UNKNOWN_MESSAGE; 705 } 706 } 707 708 protected boolean processClientMessageImpl(XClientMessageEvent xclient) { 709 long messageType = xclient.get_message_type(); 710 711 if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) { 712 return processXdndEnter(xclient); 713 } else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) { 714 return processXdndPosition(xclient); 715 } else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) { 716 return processXdndLeave(xclient); 717 } else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) { 718 return processXdndDrop(xclient); 719 } else { 720 return false; 721 } 722 } 723 724 protected void sendEnterMessageToToplevel(long toplevel, 725 XClientMessageEvent xclient) { 726 /* flags */ 727 long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT; 728 if (sourceFormats != null && sourceFormats.length > 3) { 729 data1 |= XDnDConstants.XDND_DATA_TYPES_BIT; 730 } 731 long data2 = sourceFormats.length > 0 ? sourceFormats[0] : 0; 732 long data3 = sourceFormats.length > 1 ? sourceFormats[1] : 0; 733 long data4 = sourceFormats.length > 2 ? sourceFormats[2] : 0; 734 sendEnterMessageToToplevelImpl(toplevel, xclient.get_data(0), 735 data1, data2, data3, data4); 736 737 } 738 739 private void sendEnterMessageToToplevelImpl(long toplevel, 740 long sourceWindow, 741 long data1, long data2, 742 long data3, long data4) { 743 XClientMessageEvent enter = new XClientMessageEvent(); 744 try { 745 enter.set_type((int)XConstants.ClientMessage); 746 enter.set_window(toplevel); 747 enter.set_format(32); 748 enter.set_message_type(XDnDConstants.XA_XdndEnter.getAtom()); 749 /* XID of the source window */ 750 enter.set_data(0, sourceWindow); 751 enter.set_data(1, data1); 752 enter.set_data(2, data2); 753 enter.set_data(3, data3); 754 enter.set_data(4, data4); 755 756 forwardClientMessageToToplevel(toplevel, enter); 757 } finally { 758 enter.dispose(); 759 } 760 } 761 762 protected void sendLeaveMessageToToplevel(long toplevel, 763 XClientMessageEvent xclient) { 764 sendLeaveMessageToToplevelImpl(toplevel, xclient.get_data(0)); 765 } 766 767 protected void sendLeaveMessageToToplevelImpl(long toplevel, 768 long sourceWindow) { 769 XClientMessageEvent leave = new XClientMessageEvent(); 770 try { 771 leave.set_type((int)XConstants.ClientMessage); 772 leave.set_window(toplevel); 773 leave.set_format(32); 774 leave.set_message_type(XDnDConstants.XA_XdndLeave.getAtom()); 775 /* XID of the source window */ 776 leave.set_data(0, sourceWindow); 777 /* flags */ 778 leave.set_data(1, 0); 779 780 forwardClientMessageToToplevel(toplevel, leave); 781 } finally { 782 leave.dispose(); 783 } 784 } 785 786 public boolean sendResponse(long ctxt, int eventID, int action) { 787 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 788 789 if (xclient.get_message_type() != 790 XDnDConstants.XA_XdndPosition.getAtom()) { 791 792 return false; 793 } 794 795 if (eventID == MouseEvent.MOUSE_EXITED) { 796 action = DnDConstants.ACTION_NONE; 797 } 798 799 XClientMessageEvent msg = new XClientMessageEvent(); 800 try { 801 msg.set_type((int)XConstants.ClientMessage); 802 msg.set_window(xclient.get_data(0)); 803 msg.set_format(32); 804 msg.set_message_type(XDnDConstants.XA_XdndStatus.getAtom()); 805 /* target window */ 806 msg.set_data(0, xclient.get_window()); 807 /* flags */ 808 long flags = 0; 809 if (action != DnDConstants.ACTION_NONE) { 810 flags |= XDnDConstants.XDND_ACCEPT_DROP_FLAG; 811 } 812 msg.set_data(1, flags); 813 /* specify an empty rectangle */ 814 msg.set_data(2, 0); /* x, y */ 815 msg.set_data(3, 0); /* w, h */ 816 /* action accepted by the target */ 817 msg.set_data(4, XDnDConstants.getXDnDActionForJavaAction(action)); 818 819 XToolkit.awtLock(); 820 try { 821 XlibWrapper.XSendEvent(XToolkit.getDisplay(), 822 xclient.get_data(0), 823 false, XConstants.NoEventMask, 824 msg.pData); 825 } finally { 826 XToolkit.awtUnlock(); 827 } 828 } finally { 829 msg.dispose(); 830 } 831 832 return true; 833 } 834 835 public Object getData(long ctxt, long format) 836 throws IllegalArgumentException, IOException { 837 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 838 long message_type = xclient.get_message_type(); 839 long time_stamp = XConstants.CurrentTime; 840 841 // NOTE: we assume that the source supports at least version 1, so we 842 // can use the time stamp 843 if (message_type == XDnDConstants.XA_XdndPosition.getAtom()) { 844 // X server time is an unsigned 32-bit number! 845 time_stamp = xclient.get_data(3) & 0xFFFFFFFFL; 846 } else if (message_type == XDnDConstants.XA_XdndDrop.getAtom()) { 847 // X server time is an unsigned 32-bit number! 848 time_stamp = xclient.get_data(2) & 0xFFFFFFFFL; 849 } else { 850 throw new IllegalArgumentException(); 851 } 852 853 return XDnDConstants.XDnDSelection.getData(format, time_stamp); 854 } 855 856 public boolean sendDropDone(long ctxt, boolean success, int dropAction) { 857 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 858 859 if (xclient.get_message_type() != 860 XDnDConstants.XA_XdndDrop.getAtom()) { 861 return false; 862 } 863 864 /* 865 * The XDnD protocol recommends that the target requests the special 866 * target DELETE in case if the drop action is XdndActionMove. 867 */ 868 if (dropAction == DnDConstants.ACTION_MOVE && success) { 869 870 long time_stamp = xclient.get_data(2); 871 long xdndSelectionAtom = 872 XDnDConstants.XDnDSelection.getSelectionAtom().getAtom(); 873 874 XToolkit.awtLock(); 875 try { 876 XlibWrapper.XConvertSelection(XToolkit.getDisplay(), 877 xdndSelectionAtom, 878 XAtom.get("DELETE").getAtom(), 879 XAtom.get("XAWT_SELECTION").getAtom(), 880 XWindow.getXAWTRootWindow().getWindow(), 881 time_stamp); 882 } finally { 883 XToolkit.awtUnlock(); 884 } 885 } 886 887 XClientMessageEvent msg = new XClientMessageEvent(); 888 try { 889 msg.set_type((int)XConstants.ClientMessage); 890 msg.set_window(xclient.get_data(0)); 891 msg.set_format(32); 892 msg.set_message_type(XDnDConstants.XA_XdndFinished.getAtom()); 893 msg.set_data(0, xclient.get_window()); /* target window */ 894 msg.set_data(1, 0); /* flags */ 895 /* specify an empty rectangle */ 896 msg.set_data(2, 0); 897 if (sourceProtocolVersion >= 5) { 898 if (success) { 899 msg.set_data(1, XDnDConstants.XDND_ACCEPT_DROP_FLAG); 900 } 901 /* action performed by the target */ 902 msg.set_data(2, XDnDConstants.getXDnDActionForJavaAction(dropAction)); 903 } 904 msg.set_data(3, 0); 905 msg.set_data(4, 0); 906 907 XToolkit.awtLock(); 908 try { 909 XlibWrapper.XSendEvent(XToolkit.getDisplay(), 910 xclient.get_data(0), 911 false, XConstants.NoEventMask, 912 msg.pData); 913 } finally { 914 XToolkit.awtUnlock(); 915 } 916 } finally { 917 msg.dispose(); 918 } 919 920 /* 921 * Flush the buffer to guarantee that the drop completion event is sent 922 * to the source before the method returns. 923 */ 924 XToolkit.awtLock(); 925 try { 926 XlibWrapper.XFlush(XToolkit.getDisplay()); 927 } finally { 928 XToolkit.awtUnlock(); 929 } 930 931 /* Trick to prevent cleanup() from posting dragExit */ 932 targetXWindow = null; 933 934 /* Cannot do cleanup before the drop finishes as we may need 935 source protocol version to send drop finished message. */ 936 cleanup(); 937 return true; 938 } 939 940 public final long getSourceWindow() { 941 return sourceWindow; 942 } 943 944 /** 945 * Reset the state of the object. 946 */ 947 public void cleanup() { 948 // Clear the reference to this protocol. 949 XDropTargetEventProcessor.reset(); 950 951 if (targetXWindow != null) { 952 notifyProtocolListener(targetXWindow, 0, 0, 953 DnDConstants.ACTION_NONE, null, 954 MouseEvent.MOUSE_EXITED); 955 } 956 957 if (sourceWindow != 0) { 958 XToolkit.awtLock(); 959 try { 960 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 961 XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow, 962 sourceWindowMask); 963 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 964 } finally { 965 XToolkit.awtUnlock(); 966 } 967 } 968 969 sourceWindow = 0; 970 sourceWindowMask = 0; 971 sourceProtocolVersion = 0; 972 sourceActions = DnDConstants.ACTION_NONE; 973 sourceFormats = null; 974 trackSourceActions = false; 975 userAction = DnDConstants.ACTION_NONE; 976 sourceX = 0; 977 sourceY = 0; 978 targetXWindow = null; 979 } 980 981 public boolean isDragOverComponent() { 982 return targetXWindow != null; 983 } 984 985 public void adjustEventForForwarding(XClientMessageEvent xclient, 986 EmbedderRegistryEntry entry) { 987 /* Adjust the event to match the XDnD protocol version. */ 988 int version = entry.getVersion(); 989 if (xclient.get_message_type() == XDnDConstants.XA_XdndEnter.getAtom()) { 990 int min_version = sourceProtocolVersion < version ? 991 sourceProtocolVersion : version; 992 long data1 = min_version << XDnDConstants.XDND_PROTOCOL_SHIFT; 993 if (sourceFormats != null && sourceFormats.length > 3) { 994 data1 |= XDnDConstants.XDND_DATA_TYPES_BIT; 995 } 996 if (logger.isLoggable(PlatformLogger.Level.FINEST)) { 997 logger.finest(" " 998 + " entryVersion=" + version 999 + " sourceProtocolVersion=" + 1000 sourceProtocolVersion 1001 + " sourceFormats.length=" + 1002 (sourceFormats != null ? sourceFormats.length : 0)); 1003 } 1004 xclient.set_data(1, data1); 1005 } 1006 } 1007 1008 private void notifyProtocolListener(XWindow xwindow, int x, int y, 1009 int dropAction, 1010 XClientMessageEvent xclient, 1011 int eventID) { 1012 long nativeCtxt = 0; 1013 1014 // Make a copy of the passed XClientMessageEvent structure, since 1015 // the original structure can be freed before this 1016 // SunDropTargetEvent is dispatched. 1017 if (xclient != null) { 1018 int size = new XClientMessageEvent(nativeCtxt).getSize(); 1019 1020 nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize()); 1021 1022 unsafe.copyMemory(xclient.pData, nativeCtxt, size); 1023 1024 long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT; 1025 if (sourceFormats != null && sourceFormats.length > 3) { 1026 data1 |= XDnDConstants.XDND_DATA_TYPES_BIT; 1027 } 1028 // Append information from the latest XdndEnter event. 1029 Native.putLong(nativeCtxt + size, data1); 1030 Native.putLong(nativeCtxt + size + Native.getLongSize(), 1031 sourceFormats.length > 0 ? sourceFormats[0] : 0); 1032 Native.putLong(nativeCtxt + size + 2 * Native.getLongSize(), 1033 sourceFormats.length > 1 ? sourceFormats[1] : 0); 1034 Native.putLong(nativeCtxt + size + 3 * Native.getLongSize(), 1035 sourceFormats.length > 2 ? sourceFormats[2] : 0); 1036 } 1037 1038 getProtocolListener().handleDropTargetNotification(xwindow, x, y, 1039 dropAction, 1040 sourceActions, 1041 sourceFormats, 1042 nativeCtxt, 1043 eventID); 1044 } 1045 1046 /* 1047 * The methods/fields defined below are executed/accessed only on 1048 * the toolkit thread. 1049 * The methods/fields defined below are executed/accessed only on the event 1050 * dispatch thread. 1051 */ 1052 1053 public boolean forwardEventToEmbedded(long embedded, long ctxt, 1054 int eventID) { 1055 if (logger.isLoggable(PlatformLogger.Level.FINEST)) { 1056 logger.finest(" ctxt=" + ctxt + 1057 " type=" + (ctxt != 0 ? 1058 getMessageType(new 1059 XClientMessageEvent(ctxt)) : 0) + 1060 " prevCtxt=" + prevCtxt + 1061 " prevType=" + (prevCtxt != 0 ? 1062 getMessageType(new 1063 XClientMessageEvent(prevCtxt)) : 0)); 1064 } 1065 if ((ctxt == 0 || 1066 getMessageType(new XClientMessageEvent(ctxt)) == UNKNOWN_MESSAGE) && 1067 (prevCtxt == 0 || 1068 getMessageType(new XClientMessageEvent(prevCtxt)) == UNKNOWN_MESSAGE)) { 1069 return false; 1070 } 1071 1072 // The size of XClientMessageEvent structure. 1073 int size = XClientMessageEvent.getSize(); 1074 1075 if (ctxt != 0) { 1076 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 1077 if (!overXEmbedClient) { 1078 long data1 = Native.getLong(ctxt + size); 1079 long data2 = Native.getLong(ctxt + size + Native.getLongSize()); 1080 long data3 = Native.getLong(ctxt + size + 2 * Native.getLongSize()); 1081 long data4 = Native.getLong(ctxt + size + 3 * Native.getLongSize()); 1082 1083 if (logger.isLoggable(PlatformLogger.Level.FINEST)) { 1084 logger.finest(" 1 " 1085 + " embedded=" + embedded 1086 + " source=" + xclient.get_data(0) 1087 + " data1=" + data1 1088 + " data2=" + data2 1089 + " data3=" + data3 1090 + " data4=" + data4); 1091 } 1092 1093 // Copy XdndTypeList from source to proxy. 1094 if ((data1 & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) { 1095 WindowPropertyGetter wpg = 1096 new WindowPropertyGetter(xclient.get_data(0), 1097 XDnDConstants.XA_XdndTypeList, 1098 0, 0xFFFF, false, 1099 XAtom.XA_ATOM); 1100 try { 1101 wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 1102 1103 if (wpg.getActualType() == XAtom.XA_ATOM && 1104 wpg.getActualFormat() == 32) { 1105 1106 XToolkit.awtLock(); 1107 try { 1108 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 1109 XDnDConstants.XA_XdndTypeList.setAtomData(xclient.get_window(), 1110 XAtom.XA_ATOM, 1111 wpg.getData(), 1112 wpg.getNumberOfItems()); 1113 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 1114 1115 if ((XErrorHandlerUtil.saved_error != null) && 1116 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 1117 if (logger.isLoggable(PlatformLogger.Level.WARNING)) { 1118 logger.warning("Cannot set XdndTypeList on the proxy window"); 1119 } 1120 } 1121 } finally { 1122 XToolkit.awtUnlock(); 1123 } 1124 } else { 1125 if (logger.isLoggable(PlatformLogger.Level.WARNING)) { 1126 logger.warning("Cannot read XdndTypeList from the source window"); 1127 } 1128 } 1129 } finally { 1130 wpg.dispose(); 1131 } 1132 } 1133 XDragSourceContextPeer.setProxyModeSourceWindow(xclient.get_data(0)); 1134 1135 sendEnterMessageToToplevelImpl(embedded, xclient.get_window(), 1136 data1, data2, data3, data4); 1137 overXEmbedClient = true; 1138 } 1139 1140 if (logger.isLoggable(PlatformLogger.Level.FINEST)) { 1141 logger.finest(" 2 " 1142 + " embedded=" + embedded 1143 + " xclient=" + xclient); 1144 } 1145 1146 /* Make a copy of the original event, since we are going to modify the 1147 event while it still can be referenced from other Java events. */ 1148 { 1149 XClientMessageEvent copy = new XClientMessageEvent(); 1150 unsafe.copyMemory(xclient.pData, copy.pData, copy.getSize()); 1151 1152 copy.set_data(0, xclient.get_window()); 1153 1154 forwardClientMessageToToplevel(embedded, copy); 1155 } 1156 } 1157 1158 if (eventID == MouseEvent.MOUSE_EXITED) { 1159 if (overXEmbedClient) { 1160 if (ctxt != 0 || prevCtxt != 0) { 1161 // Last chance to send XdndLeave to the XEmbed client. 1162 XClientMessageEvent xclient = ctxt != 0 ? 1163 new XClientMessageEvent(ctxt) : 1164 new XClientMessageEvent(prevCtxt); 1165 sendLeaveMessageToToplevelImpl(embedded, xclient.get_window()); 1166 } 1167 overXEmbedClient = false; 1168 // We have to clear the proxy mode source window here, 1169 // when the drag exits the XEmbedCanvasPeer. 1170 // NOTE: at this point the XEmbed client still might have some 1171 // drag notifications to process and it will send responses to 1172 // us. With the proxy mode source window cleared we won't be 1173 // able to forward these responses to the actual source. This is 1174 // not a problem if the drag operation was initiated in this 1175 // JVM. However, if it was initiated in another processes the 1176 // responses will be lost. We bear with it for now, as it seems 1177 // there is no other reliable point to clear. 1178 XDragSourceContextPeer.setProxyModeSourceWindow(0); 1179 } 1180 } 1181 1182 if (eventID == MouseEvent.MOUSE_RELEASED) { 1183 overXEmbedClient = false; 1184 cleanup(); 1185 } 1186 1187 if (prevCtxt != 0) { 1188 unsafe.freeMemory(prevCtxt); 1189 prevCtxt = 0; 1190 } 1191 1192 if (ctxt != 0 && overXEmbedClient) { 1193 prevCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize()); 1194 1195 unsafe.copyMemory(ctxt, prevCtxt, size + 4 * Native.getLongSize()); 1196 } 1197 1198 return true; 1199 } 1200 1201 public boolean isXEmbedSupported() { 1202 return true; 1203 } 1204 }