1 /* 2 * Copyright (c) 2003, 2014, 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 jdk.internal.misc.Unsafe; 37 38 /** 39 * XDropTargetProtocol implementation for Motif DnD protocol. 40 * 41 * @since 1.5 42 */ 43 class MotifDnDDropTargetProtocol extends XDropTargetProtocol { 44 private static final Unsafe unsafe = XlibWrapper.unsafe; 45 46 private long sourceWindow = 0; 47 private long sourceWindowMask = 0; 48 private int sourceProtocolVersion = 0; 49 private int sourceActions = DnDConstants.ACTION_NONE; 50 private long[] sourceFormats = null; 51 private long sourceAtom = 0; 52 private int userAction = DnDConstants.ACTION_NONE; 53 private int sourceX = 0; 54 private int sourceY = 0; 55 private XWindow targetXWindow = null; 56 private boolean topLevelLeavePostponed = false; 57 MotifDnDDropTargetProtocol(XDropTargetProtocolListener listener)58 protected MotifDnDDropTargetProtocol(XDropTargetProtocolListener listener) { 59 super(listener); 60 } 61 62 /** 63 * Creates an instance associated with the specified listener. 64 * 65 * @throws NullPointerException if listener is {@code null}. 66 */ createInstance(XDropTargetProtocolListener listener)67 static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) { 68 return new MotifDnDDropTargetProtocol(listener); 69 } 70 getProtocolName()71 public String getProtocolName() { 72 return XDragAndDropProtocols.MotifDnD; 73 } 74 registerDropTarget(long window)75 public void registerDropTarget(long window) { 76 assert XToolkit.isAWTLockHeldByCurrentThread(); 77 78 MotifDnDConstants.writeDragReceiverInfoStruct(window); 79 } 80 unregisterDropTarget(long window)81 public void unregisterDropTarget(long window) { 82 assert XToolkit.isAWTLockHeldByCurrentThread(); 83 84 MotifDnDConstants.XA_MOTIF_ATOM_0.DeleteProperty(window); 85 } 86 registerEmbedderDropSite(long embedder)87 public void registerEmbedderDropSite(long embedder) { 88 assert XToolkit.isAWTLockHeldByCurrentThread(); 89 90 boolean overriden = false; 91 int version = 0; 92 long proxy = 0; 93 long newProxy = XDropTargetRegistry.getDnDProxyWindow(); 94 int status = 0; 95 long data = 0; 96 int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE; 97 98 WindowPropertyGetter wpg = 99 new WindowPropertyGetter(embedder, 100 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 101 0, 0xFFFF, false, 102 XConstants.AnyPropertyType); 103 104 try { 105 status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 106 107 /* 108 * DragICCI.h: 109 * 110 * typedef struct _xmDragReceiverInfoStruct{ 111 * BYTE byte_order; 112 * BYTE protocol_version; 113 * BYTE drag_protocol_style; 114 * BYTE pad1; 115 * CARD32 proxy_window B32; 116 * CARD16 num_drop_sites B16; 117 * CARD16 pad2 B16; 118 * CARD32 heap_offset B32; 119 * } xmDragReceiverInfoStruct; 120 */ 121 if (status == XConstants.Success && wpg.getData() != 0 && 122 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 && 123 wpg.getNumberOfItems() >= 124 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) { 125 126 overriden = true; 127 data = wpg.getData(); 128 dataSize = wpg.getNumberOfItems(); 129 130 byte byteOrderByte = unsafe.getByte(data); 131 132 { 133 int tproxy = unsafe.getInt(data + 4); 134 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) { 135 tproxy = MotifDnDConstants.Swapper.swap(tproxy); 136 } 137 proxy = tproxy; 138 } 139 140 if (proxy == newProxy) { 141 // Embedder already registered. 142 return; 143 } 144 145 { 146 int tproxy = (int)newProxy; 147 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) { 148 tproxy = MotifDnDConstants.Swapper.swap(tproxy); 149 } 150 unsafe.putInt(data + 4, tproxy); 151 } 152 } else { 153 data = unsafe.allocateMemory(dataSize); 154 155 unsafe.putByte(data, MotifDnDConstants.getByteOrderByte()); /* byte order */ 156 unsafe.putByte(data + 1, MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION); /* protocol version */ 157 unsafe.putByte(data + 2, (byte)MotifDnDConstants.MOTIF_DYNAMIC_STYLE); /* protocol style */ 158 unsafe.putByte(data + 3, (byte)0); /* pad */ 159 unsafe.putInt(data + 4, (int)newProxy); /* proxy window */ 160 unsafe.putShort(data + 8, (short)0); /* num_drop_sites */ 161 unsafe.putShort(data + 10, (short)0); /* pad */ 162 unsafe.putInt(data + 12, dataSize); 163 } 164 165 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 166 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder, 167 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(), 168 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(), 169 8, XConstants.PropModeReplace, 170 data, dataSize); 171 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 172 173 if ((XErrorHandlerUtil.saved_error != null) && 174 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 175 throw new XException("Cannot write Motif receiver info property"); 176 } 177 } finally { 178 if (!overriden) { 179 unsafe.freeMemory(data); 180 data = 0; 181 } 182 wpg.dispose(); 183 } 184 185 putEmbedderRegistryEntry(embedder, overriden, version, proxy); 186 } 187 unregisterEmbedderDropSite(long embedder)188 public void unregisterEmbedderDropSite(long embedder) { 189 assert XToolkit.isAWTLockHeldByCurrentThread(); 190 191 EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder); 192 193 if (entry == null) { 194 return; 195 } 196 197 if (entry.isOverriden()) { 198 int status = 0; 199 200 WindowPropertyGetter wpg = 201 new WindowPropertyGetter(embedder, 202 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 203 0, 0xFFFF, false, 204 XConstants.AnyPropertyType); 205 206 try { 207 status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 208 209 /* 210 * DragICCI.h: 211 * 212 * typedef struct _xmDragReceiverInfoStruct{ 213 * BYTE byte_order; 214 * BYTE protocol_version; 215 * BYTE drag_protocol_style; 216 * BYTE pad1; 217 * CARD32 proxy_window B32; 218 * CARD16 num_drop_sites B16; 219 * CARD16 pad2 B16; 220 * CARD32 heap_offset B32; 221 * } xmDragReceiverInfoStruct; 222 */ 223 if (status == XConstants.Success && wpg.getData() != 0 && 224 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 && 225 wpg.getNumberOfItems() >= 226 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) { 227 228 int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE; 229 long data = wpg.getData(); 230 byte byteOrderByte = unsafe.getByte(data); 231 232 int tproxy = (int)entry.getProxy(); 233 if (MotifDnDConstants.getByteOrderByte() != byteOrderByte) { 234 tproxy = MotifDnDConstants.Swapper.swap(tproxy); 235 } 236 237 unsafe.putInt(data + 4, tproxy); 238 239 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance()); 240 XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder, 241 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(), 242 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(), 243 8, XConstants.PropModeReplace, 244 data, dataSize); 245 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 246 247 if ((XErrorHandlerUtil.saved_error != null) && 248 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 249 throw new XException("Cannot write Motif receiver info property"); 250 } 251 } 252 } finally { 253 wpg.dispose(); 254 } 255 } else { 256 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.DeleteProperty(embedder); 257 } 258 } 259 260 /* 261 * Gets and stores in the registry the embedder's Motif DnD drop site info 262 * from the embedded. 263 */ registerEmbeddedDropSite(long embedded)264 public void registerEmbeddedDropSite(long embedded) { 265 assert XToolkit.isAWTLockHeldByCurrentThread(); 266 267 boolean overriden = false; 268 int version = 0; 269 long proxy = 0; 270 int status = 0; 271 272 WindowPropertyGetter wpg = 273 new WindowPropertyGetter(embedded, 274 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 275 0, 0xFFFF, false, 276 XConstants.AnyPropertyType); 277 278 try { 279 status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 280 281 /* 282 * DragICCI.h: 283 * 284 * typedef struct _xmDragReceiverInfoStruct{ 285 * BYTE byte_order; 286 * BYTE protocol_version; 287 * BYTE drag_protocol_style; 288 * BYTE pad1; 289 * CARD32 proxy_window B32; 290 * CARD16 num_drop_sites B16; 291 * CARD16 pad2 B16; 292 * CARD32 heap_offset B32; 293 * } xmDragReceiverInfoStruct; 294 */ 295 if (status == XConstants.Success && wpg.getData() != 0 && 296 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 && 297 wpg.getNumberOfItems() >= 298 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) { 299 300 overriden = true; 301 long data = wpg.getData(); 302 303 byte byteOrderByte = unsafe.getByte(data); 304 305 { 306 int tproxy = unsafe.getInt(data + 4); 307 if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) { 308 tproxy = MotifDnDConstants.Swapper.swap(tproxy); 309 } 310 proxy = tproxy; 311 } 312 } 313 } finally { 314 wpg.dispose(); 315 } 316 317 putEmbedderRegistryEntry(embedded, overriden, version, proxy); 318 } 319 isProtocolSupported(long window)320 public boolean isProtocolSupported(long window) { 321 WindowPropertyGetter wpg = 322 new WindowPropertyGetter(window, 323 MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 324 0, 0xFFFF, false, 325 XConstants.AnyPropertyType); 326 327 try { 328 int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 329 330 if (status == XConstants.Success && wpg.getData() != 0 && 331 wpg.getActualType() != 0 && wpg.getActualFormat() == 8 && 332 wpg.getNumberOfItems() >= 333 MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) { 334 return true; 335 } else { 336 return false; 337 } 338 } finally { 339 wpg.dispose(); 340 } 341 } 342 processTopLevelEnter(XClientMessageEvent xclient)343 private boolean processTopLevelEnter(XClientMessageEvent xclient) { 344 assert XToolkit.isAWTLockHeldByCurrentThread(); 345 346 if (targetXWindow != null || sourceWindow != 0) { 347 return false; 348 } 349 350 if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow) 351 && getEmbedderRegistryEntry(xclient.get_window()) == null) { 352 return false; 353 } 354 355 long source_win = 0; 356 long source_win_mask = 0; 357 int protocol_version = 0; 358 long property_atom = 0; 359 long[] formats = null; 360 361 { 362 long data = xclient.get_data(); 363 byte eventByteOrder = unsafe.getByte(data + 1); 364 source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder); 365 property_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder); 366 } 367 368 /* Extract the available data types. */ 369 { 370 WindowPropertyGetter wpg = 371 new WindowPropertyGetter(source_win, 372 XAtom.get(property_atom), 373 0, 0xFFFF, 374 false, 375 MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom()); 376 377 try { 378 int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 379 380 if (status == XConstants.Success && wpg.getData() != 0 && 381 wpg.getActualType() == 382 MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom() && 383 wpg.getActualFormat() == 8 && 384 wpg.getNumberOfItems() == 385 MotifDnDConstants.MOTIF_INITIATOR_INFO_SIZE) { 386 387 long data = wpg.getData(); 388 byte propertyByteOrder = unsafe.getByte(data); 389 390 protocol_version = unsafe.getByte(data + 1); 391 392 if (protocol_version != 393 MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION) { 394 return false; 395 } 396 397 int index = 398 MotifDnDConstants.Swapper.getShort(data + 2, propertyByteOrder); 399 400 formats = MotifDnDConstants.getTargetListForIndex(index); 401 } else { 402 formats = new long[0]; 403 } 404 } finally { 405 wpg.dispose(); 406 } 407 } 408 409 /* 410 * Select for StructureNotifyMask to receive DestroyNotify in case of source 411 * crash. 412 */ 413 XWindowAttributes wattr = new XWindowAttributes(); 414 try { 415 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 416 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), 417 source_win, wattr.pData); 418 419 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 420 421 if ((status == 0) || 422 ((XErrorHandlerUtil.saved_error != null) && 423 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) { 424 throw new XException("XGetWindowAttributes failed"); 425 } 426 427 source_win_mask = wattr.get_your_event_mask(); 428 } finally { 429 wattr.dispose(); 430 } 431 432 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 433 XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win, 434 source_win_mask | 435 XConstants.StructureNotifyMask); 436 437 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 438 439 if ((XErrorHandlerUtil.saved_error != null) && 440 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) { 441 throw new XException("XSelectInput failed"); 442 } 443 444 sourceWindow = source_win; 445 sourceWindowMask = source_win_mask; 446 sourceProtocolVersion = protocol_version; 447 /* 448 * TOP_LEVEL_ENTER doesn't communicate the list of supported actions 449 * They are provided in DRAG_MOTION. 450 */ 451 sourceActions = DnDConstants.ACTION_NONE; 452 sourceFormats = formats; 453 sourceAtom = property_atom; 454 455 return true; 456 } 457 processDragMotion(XClientMessageEvent xclient)458 private boolean processDragMotion(XClientMessageEvent xclient) { 459 long data = xclient.get_data(); 460 byte eventByteOrder = unsafe.getByte(data + 1); 461 byte eventReason = (byte)(unsafe.getByte(data) & 462 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 463 int x = 0; 464 int y = 0; 465 466 short flags = MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder); 467 468 int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >> 469 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT; 470 int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >> 471 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT; 472 473 int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action); 474 int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions); 475 476 /* Append source window id to the event data, so that we can send the 477 response properly. */ 478 { 479 int win = (int)sourceWindow; 480 if (eventByteOrder != MotifDnDConstants.getByteOrderByte()) { 481 win = MotifDnDConstants.Swapper.swap(win); 482 } 483 unsafe.putInt(data + 12, win); 484 } 485 486 XWindow xwindow = null; 487 { 488 XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window()); 489 if (xbasewindow instanceof XWindow) { 490 xwindow = (XWindow)xbasewindow; 491 } 492 } 493 494 if (eventReason == MotifDnDConstants.OPERATION_CHANGED) { 495 /* OPERATION_CHANGED event doesn't provide coordinates, so we use 496 previously stored position and component ref. */ 497 x = sourceX; 498 y = sourceY; 499 500 if (xwindow == null) { 501 xwindow = targetXWindow; 502 } 503 } else { 504 x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder); 505 y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder); 506 507 if (xwindow == null) { 508 long receiver = 509 XDropTargetRegistry.getRegistry().getEmbeddedDropSite( 510 xclient.get_window(), x, y); 511 512 if (receiver != 0) { 513 XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver); 514 if (xbasewindow instanceof XWindow) { 515 xwindow = (XWindow)xbasewindow; 516 } 517 } 518 } 519 520 if (xwindow != null) { 521 Point p = xwindow.toLocal(x, y); 522 x = p.x; 523 y = p.y; 524 } 525 } 526 527 if (xwindow == null) { 528 if (targetXWindow != null) { 529 notifyProtocolListener(targetXWindow, x, y, 530 DnDConstants.ACTION_NONE, java_actions, 531 xclient, MouseEvent.MOUSE_EXITED); 532 } 533 } else { 534 int java_event_id = 0; 535 536 if (targetXWindow == null) { 537 java_event_id = MouseEvent.MOUSE_ENTERED; 538 } else { 539 java_event_id = MouseEvent.MOUSE_DRAGGED; 540 } 541 542 notifyProtocolListener(xwindow, x, y, java_action, java_actions, 543 xclient, java_event_id); 544 } 545 546 sourceActions = java_actions; 547 userAction = java_action; 548 sourceX = x; 549 sourceY = y; 550 targetXWindow = xwindow; 551 552 return true; 553 } 554 processTopLevelLeave(XClientMessageEvent xclient)555 private boolean processTopLevelLeave(XClientMessageEvent xclient) { 556 assert XToolkit.isAWTLockHeldByCurrentThread(); 557 558 long data = xclient.get_data(); 559 byte eventByteOrder = unsafe.getByte(data + 1); 560 561 long source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder); 562 563 /* Ignore Motif DnD messages from all other windows. */ 564 if (source_win != sourceWindow) { 565 return false; 566 } 567 568 /* 569 * Postpone upcall to java, so that we can abort it in case 570 * if drop immediatelly follows (see BugTraq ID 4395290). 571 * Send a dummy ClientMessage event to guarantee that a postponed java 572 * upcall will be processed. 573 */ 574 topLevelLeavePostponed = true; 575 { 576 long proxy; 577 578 /* 579 * If this is an embedded drop site, the event should go to the 580 * awt_root_window as this is a proxy for all embedded drop sites. 581 * Otherwise the event should go to the event->window, as we don't use 582 * proxies for normal drop sites. 583 */ 584 if (getEmbedderRegistryEntry(xclient.get_window()) != null) { 585 proxy = XDropTargetRegistry.getDnDProxyWindow(); 586 } else { 587 proxy = xclient.get_window(); 588 } 589 590 XClientMessageEvent dummy = new XClientMessageEvent(); 591 592 try { 593 dummy.set_type(XConstants.ClientMessage); 594 dummy.set_window(xclient.get_window()); 595 dummy.set_format(32); 596 dummy.set_message_type(0); 597 dummy.set_data(0, 0); 598 dummy.set_data(1, 0); 599 dummy.set_data(2, 0); 600 dummy.set_data(3, 0); 601 dummy.set_data(4, 0); 602 XlibWrapper.XSendEvent(XToolkit.getDisplay(), 603 proxy, false, XConstants.NoEventMask, 604 dummy.pData); 605 } finally { 606 dummy.dispose(); 607 } 608 } 609 return true; 610 } 611 processDropStart(XClientMessageEvent xclient)612 private boolean processDropStart(XClientMessageEvent xclient) { 613 long data = xclient.get_data(); 614 byte eventByteOrder = unsafe.getByte(data + 1); 615 616 long source_win = 617 MotifDnDConstants.Swapper.getInt(data + 16, eventByteOrder); 618 619 /* Ignore Motif DnD messages from all other windows. */ 620 if (source_win != sourceWindow) { 621 return false; 622 } 623 624 long property_atom = 625 MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder); 626 627 short flags = 628 MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder); 629 630 int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >> 631 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT; 632 int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >> 633 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT; 634 635 int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action); 636 int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions); 637 638 int x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder); 639 int y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder); 640 641 XWindow xwindow = null; 642 { 643 XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window()); 644 if (xbasewindow instanceof XWindow) { 645 xwindow = (XWindow)xbasewindow; 646 } 647 } 648 649 if (xwindow == null) { 650 long receiver = 651 XDropTargetRegistry.getRegistry().getEmbeddedDropSite( 652 xclient.get_window(), x, y); 653 654 if (receiver != 0) { 655 XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver); 656 if (xbasewindow instanceof XWindow) { 657 xwindow = (XWindow)xbasewindow; 658 } 659 } 660 } 661 662 if (xwindow != null) { 663 Point p = xwindow.toLocal(x, y); 664 x = p.x; 665 y = p.y; 666 } 667 668 if (xwindow != null) { 669 notifyProtocolListener(xwindow, x, y, java_action, java_actions, 670 xclient, MouseEvent.MOUSE_RELEASED); 671 } else if (targetXWindow != null) { 672 notifyProtocolListener(targetXWindow, x, y, 673 DnDConstants.ACTION_NONE, java_actions, 674 xclient, MouseEvent.MOUSE_EXITED); 675 } 676 677 return true; 678 } 679 getMessageType(XClientMessageEvent xclient)680 public int getMessageType(XClientMessageEvent xclient) { 681 if (xclient.get_message_type() != 682 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) { 683 684 return UNKNOWN_MESSAGE; 685 } 686 687 long data = xclient.get_data(); 688 byte reason = (byte)(unsafe.getByte(data) & 689 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 690 691 switch (reason) { 692 case MotifDnDConstants.TOP_LEVEL_ENTER : 693 return ENTER_MESSAGE; 694 case MotifDnDConstants.DRAG_MOTION : 695 case MotifDnDConstants.OPERATION_CHANGED : 696 return MOTION_MESSAGE; 697 case MotifDnDConstants.TOP_LEVEL_LEAVE : 698 return LEAVE_MESSAGE; 699 case MotifDnDConstants.DROP_START : 700 return DROP_MESSAGE; 701 default: 702 return UNKNOWN_MESSAGE; 703 } 704 } 705 processClientMessageImpl(XClientMessageEvent xclient)706 protected boolean processClientMessageImpl(XClientMessageEvent xclient) { 707 if (xclient.get_message_type() != 708 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) { 709 if (topLevelLeavePostponed) { 710 topLevelLeavePostponed = false; 711 cleanup(); 712 } 713 714 return false; 715 } 716 717 long data = xclient.get_data(); 718 byte reason = (byte)(unsafe.getByte(data) & 719 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 720 byte origin = (byte)(unsafe.getByte(data) & 721 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK); 722 723 if (topLevelLeavePostponed) { 724 topLevelLeavePostponed = false; 725 if (reason != MotifDnDConstants.DROP_START) { 726 cleanup(); 727 } 728 } 729 730 /* Only initiator messages should be handled. */ 731 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) { 732 return false; 733 } 734 735 switch (reason) { 736 case MotifDnDConstants.TOP_LEVEL_ENTER : 737 return processTopLevelEnter(xclient); 738 case MotifDnDConstants.DRAG_MOTION : 739 case MotifDnDConstants.OPERATION_CHANGED : 740 return processDragMotion(xclient); 741 case MotifDnDConstants.TOP_LEVEL_LEAVE : 742 return processTopLevelLeave(xclient); 743 case MotifDnDConstants.DROP_START : 744 return processDropStart(xclient); 745 default: 746 return false; 747 } 748 } 749 750 /* 751 * Currently we don't synthesize enter/leave messages for Motif DnD 752 * protocol. See comments in XDropTargetProtocol.postProcessClientMessage. 753 */ sendEnterMessageToToplevel(long win, XClientMessageEvent xclient)754 protected void sendEnterMessageToToplevel(long win, 755 XClientMessageEvent xclient) { 756 throw new Error("UNIMPLEMENTED"); 757 } 758 sendLeaveMessageToToplevel(long win, XClientMessageEvent xclient)759 protected void sendLeaveMessageToToplevel(long win, 760 XClientMessageEvent xclient) { 761 throw new Error("UNIMPLEMENTED"); 762 } 763 forwardEventToEmbedded(long embedded, long ctxt, int eventID)764 public boolean forwardEventToEmbedded(long embedded, long ctxt, 765 int eventID) { 766 // UNIMPLEMENTED. 767 return false; 768 } 769 isXEmbedSupported()770 public boolean isXEmbedSupported() { 771 return false; 772 } 773 sendResponse(long ctxt, int eventID, int action)774 public boolean sendResponse(long ctxt, int eventID, int action) { 775 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 776 if (xclient.get_message_type() != 777 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) { 778 return false; 779 } 780 781 long data = xclient.get_data(); 782 byte reason = (byte)(unsafe.getByte(data) & 783 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 784 byte origin = (byte)(unsafe.getByte(data) & 785 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK); 786 byte eventByteOrder = unsafe.getByte(data + 1); 787 byte response_reason = (byte)0; 788 789 /* Only initiator messages should be handled. */ 790 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) { 791 return false; 792 } 793 794 switch (reason) { 795 case MotifDnDConstants.TOP_LEVEL_ENTER: 796 case MotifDnDConstants.TOP_LEVEL_LEAVE: 797 /* Receiver shouldn't rely to these messages. */ 798 return false; 799 case MotifDnDConstants.DRAG_MOTION: 800 switch (eventID) { 801 case MouseEvent.MOUSE_ENTERED: 802 response_reason = MotifDnDConstants.DROP_SITE_ENTER; 803 break; 804 case MouseEvent.MOUSE_DRAGGED: 805 response_reason = MotifDnDConstants.DRAG_MOTION; 806 break; 807 case MouseEvent.MOUSE_EXITED: 808 response_reason = MotifDnDConstants.DROP_SITE_LEAVE; 809 break; 810 } 811 break; 812 case MotifDnDConstants.OPERATION_CHANGED: 813 case MotifDnDConstants.DROP_START: 814 response_reason = reason; 815 break; 816 default: 817 // Unknown reason. Shouldn't get here. 818 assert false; 819 } 820 821 XClientMessageEvent msg = new XClientMessageEvent(); 822 823 try { 824 msg.set_type(XConstants.ClientMessage); 825 msg.set_window(MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder)); 826 msg.set_format(8); 827 msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()); 828 829 long responseData = msg.get_data(); 830 831 unsafe.putByte(responseData, (byte)(response_reason | 832 MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER)); 833 unsafe.putByte(responseData + 1, MotifDnDConstants.getByteOrderByte()); 834 835 int response_flags = 0; 836 837 if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) { 838 short flags = MotifDnDConstants.Swapper.getShort(data + 2, 839 eventByteOrder); 840 byte dropSiteStatus = (action == DnDConstants.ACTION_NONE) ? 841 MotifDnDConstants.MOTIF_INVALID_DROP_SITE : 842 MotifDnDConstants.MOTIF_VALID_DROP_SITE; 843 844 /* Clear action and drop site status bits. */ 845 response_flags = flags & 846 ~MotifDnDConstants.MOTIF_DND_ACTION_MASK & 847 ~MotifDnDConstants.MOTIF_DND_STATUS_MASK; 848 /* Fill in new action and drop site status. */ 849 response_flags |= 850 MotifDnDConstants.getMotifActionsForJavaActions(action) << 851 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT; 852 response_flags |= 853 dropSiteStatus << MotifDnDConstants.MOTIF_DND_STATUS_SHIFT; 854 } else { 855 response_flags = 0; 856 } 857 858 unsafe.putShort(responseData + 2, (short)response_flags); 859 860 /* Write time stamp. */ 861 int time = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder); 862 unsafe.putInt(responseData + 4, time); 863 864 /* Write coordinates. */ 865 if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) { 866 short x = MotifDnDConstants.Swapper.getShort(data + 8, 867 eventByteOrder); 868 short y = MotifDnDConstants.Swapper.getShort(data + 10, 869 eventByteOrder); 870 unsafe.putShort(responseData + 8, x); // x 871 unsafe.putShort(responseData + 10, y); // y 872 } else { 873 unsafe.putShort(responseData + 8, (short)0); // x 874 unsafe.putShort(responseData + 10, (short)0); // y 875 } 876 877 XToolkit.awtLock(); 878 try { 879 XlibWrapper.XSendEvent(XToolkit.getDisplay(), 880 msg.get_window(), 881 false, XConstants.NoEventMask, 882 msg.pData); 883 } finally { 884 XToolkit.awtUnlock(); 885 } 886 } finally { 887 msg.dispose(); 888 } 889 890 return true; 891 } 892 getData(long ctxt, long format)893 public Object getData(long ctxt, long format) 894 throws IllegalArgumentException, IOException { 895 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 896 897 if (xclient.get_message_type() != 898 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) { 899 throw new IllegalArgumentException(); 900 } 901 902 long data = xclient.get_data(); 903 byte reason = (byte)(unsafe.getByte(data) & 904 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 905 byte origin = (byte)(unsafe.getByte(data) & 906 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK); 907 byte eventByteOrder = unsafe.getByte(data + 1); 908 909 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) { 910 throw new IOException("Cannot get data: corrupted context"); 911 } 912 913 long selatom = 0; 914 915 switch (reason) { 916 case MotifDnDConstants.DRAG_MOTION : 917 case MotifDnDConstants.OPERATION_CHANGED : 918 selatom = sourceAtom; 919 break; 920 case MotifDnDConstants.DROP_START : 921 selatom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder); 922 break; 923 default: 924 throw new IOException("Cannot get data: invalid message reason"); 925 } 926 927 if (selatom == 0) { 928 throw new IOException("Cannot get data: drag source property atom unavailable"); 929 } 930 931 long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder) & 0xffffffffL; 932 // with correction of (32-bit unsigned to 64-bit signed) implicit conversion. 933 934 XAtom selectionAtom = XAtom.get(selatom); 935 936 XSelection selection = XSelection.getSelection(selectionAtom); 937 if (selection == null) { 938 selection = new XSelection(selectionAtom); 939 } 940 941 return selection.getData(format, time_stamp); 942 } 943 sendDropDone(long ctxt, boolean success, int dropAction)944 public boolean sendDropDone(long ctxt, boolean success, int dropAction) { 945 XClientMessageEvent xclient = new XClientMessageEvent(ctxt); 946 947 if (xclient.get_message_type() != 948 MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) { 949 return false; 950 } 951 952 long data = xclient.get_data(); 953 byte reason = (byte)(unsafe.getByte(data) & 954 MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK); 955 byte origin = (byte)(unsafe.getByte(data) & 956 MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK); 957 byte eventByteOrder = unsafe.getByte(data + 1); 958 959 if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) { 960 return false; 961 } 962 963 if (reason != MotifDnDConstants.DROP_START) { 964 return false; 965 } 966 967 long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder) & 0xffffffffL; 968 // with correction of (32-bit unsigned to 64-bit signed) implicit conversion. 969 970 long sel_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder); 971 972 long status_atom = 0; 973 974 if (success) { 975 status_atom = MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom(); 976 } else { 977 status_atom = MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom(); 978 } 979 980 XToolkit.awtLock(); 981 try { 982 XlibWrapper.XConvertSelection(XToolkit.getDisplay(), 983 sel_atom, 984 status_atom, 985 MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom(), 986 XWindow.getXAWTRootWindow().getWindow(), 987 time_stamp); 988 989 /* 990 * Flush the buffer to guarantee that the drop completion event is sent 991 * to the source before the method returns. 992 */ 993 XlibWrapper.XFlush(XToolkit.getDisplay()); 994 } finally { 995 XToolkit.awtUnlock(); 996 } 997 998 /* Trick to prevent cleanup() from posting dragExit */ 999 targetXWindow = null; 1000 1001 /* Cannot do cleanup before the drop finishes as we may need 1002 source protocol version to send drop finished message. */ 1003 cleanup(); 1004 return true; 1005 } 1006 getSourceWindow()1007 public final long getSourceWindow() { 1008 return sourceWindow; 1009 } 1010 1011 /** 1012 * Reset the state of the object. 1013 */ cleanup()1014 public void cleanup() { 1015 // Clear the reference to this protocol. 1016 XDropTargetEventProcessor.reset(); 1017 1018 if (targetXWindow != null) { 1019 notifyProtocolListener(targetXWindow, 0, 0, 1020 DnDConstants.ACTION_NONE, sourceActions, 1021 null, MouseEvent.MOUSE_EXITED); 1022 } 1023 1024 if (sourceWindow != 0) { 1025 XToolkit.awtLock(); 1026 try { 1027 XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance()); 1028 XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow, 1029 sourceWindowMask); 1030 XErrorHandlerUtil.RESTORE_XERROR_HANDLER(); 1031 } finally { 1032 XToolkit.awtUnlock(); 1033 } 1034 } 1035 1036 sourceWindow = 0; 1037 sourceWindowMask = 0; 1038 sourceProtocolVersion = 0; 1039 sourceActions = DnDConstants.ACTION_NONE; 1040 sourceFormats = null; 1041 sourceAtom = 0; 1042 userAction = DnDConstants.ACTION_NONE; 1043 sourceX = 0; 1044 sourceY = 0; 1045 targetXWindow = null; 1046 topLevelLeavePostponed = false; 1047 } 1048 isDragOverComponent()1049 public boolean isDragOverComponent() { 1050 return targetXWindow != null; 1051 } 1052 notifyProtocolListener(XWindow xwindow, int x, int y, int dropAction, int actions, XClientMessageEvent xclient, int eventID)1053 private void notifyProtocolListener(XWindow xwindow, int x, int y, 1054 int dropAction, int actions, 1055 XClientMessageEvent xclient, 1056 int eventID) { 1057 long nativeCtxt = 0; 1058 1059 // Make a copy of the passed XClientMessageEvent structure, since 1060 // the original structure can be freed before this 1061 // SunDropTargetEvent is dispatched. 1062 if (xclient != null) { 1063 int size = XClientMessageEvent.getSize(); 1064 1065 nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize()); 1066 1067 unsafe.copyMemory(xclient.pData, nativeCtxt, size); 1068 } 1069 1070 getProtocolListener().handleDropTargetNotification(xwindow, x, y, 1071 dropAction, 1072 actions, 1073 sourceFormats, 1074 nativeCtxt, 1075 eventID); 1076 } 1077 } 1078