1 /* 2 * Copyright (c) 2000, 2021, 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.dnd; 27 28 import java.awt.Component; 29 import java.awt.Point; 30 31 import java.awt.datatransfer.DataFlavor; 32 import java.awt.datatransfer.Transferable; 33 import java.awt.datatransfer.UnsupportedFlavorException; 34 35 import java.awt.dnd.DnDConstants; 36 37 import java.awt.dnd.DropTarget; 38 import java.awt.dnd.DropTargetContext; 39 import java.awt.dnd.DropTargetListener; 40 import java.awt.dnd.DropTargetEvent; 41 import java.awt.dnd.DropTargetDragEvent; 42 import java.awt.dnd.DropTargetDropEvent; 43 import java.awt.dnd.InvalidDnDOperationException; 44 45 import java.awt.dnd.peer.DropTargetContextPeer; 46 47 import java.util.HashSet; 48 import java.util.Map; 49 import java.util.Arrays; 50 51 import sun.awt.AWTAccessor; 52 import sun.awt.AWTAccessor.DropTargetContextAccessor; 53 import sun.util.logging.PlatformLogger; 54 55 import java.io.IOException; 56 import java.io.InputStream; 57 58 import sun.awt.AppContext; 59 import sun.awt.AWTPermissions; 60 import sun.awt.SunToolkit; 61 import sun.awt.datatransfer.DataTransferer; 62 import sun.awt.datatransfer.ToolkitThreadBlockedHandler; 63 64 /** 65 * <p> 66 * The SunDropTargetContextPeer class is the generic class responsible for handling 67 * the interaction between a windowing systems DnD system and Java. 68 * </p> 69 * 70 * @since 1.3.1 71 * 72 */ 73 74 public abstract class SunDropTargetContextPeer implements DropTargetContextPeer, Transferable { 75 76 /* 77 * A boolean constant that requires the peer to wait until the 78 * SunDropTargetEvent is processed and return the status back 79 * to the native code. 80 */ 81 public static final boolean DISPATCH_SYNC = true; 82 private DropTarget currentDT; 83 private DropTargetContext currentDTC; 84 private long[] currentT; 85 private int currentA; // target actions 86 private int currentSA; // source actions 87 private int currentDA; // current drop action 88 private int previousDA; 89 90 private long nativeDragContext; 91 92 private Transferable local; 93 94 private boolean dragRejected = false; 95 96 protected int dropStatus = STATUS_NONE; 97 protected boolean dropComplete = false; 98 99 // The flag is used to monitor whether the drop action is 100 // handled by a user. That allows to distinct during 101 // which operation getTransferData() method is invoked. 102 boolean dropInProcess = false; 103 104 /* 105 * global lock 106 */ 107 108 protected static final Object _globalLock = new Object(); 109 110 private static final PlatformLogger dndLog = PlatformLogger.getLogger("sun.awt.dnd.SunDropTargetContextPeer"); 111 112 /* 113 * a primitive mechanism for advertising intra-JVM Transferables 114 */ 115 116 protected static Transferable currentJVMLocalSourceTransferable = null; 117 setCurrentJVMLocalSourceTransferable(Transferable t)118 public static void setCurrentJVMLocalSourceTransferable(Transferable t) throws InvalidDnDOperationException { 119 synchronized(_globalLock) { 120 if (t != null && currentJVMLocalSourceTransferable != null) { 121 throw new InvalidDnDOperationException(); 122 } else { 123 currentJVMLocalSourceTransferable = t; 124 } 125 } 126 } 127 128 /** 129 * obtain the transferable iff the operation is in the same VM 130 */ 131 getJVMLocalSourceTransferable()132 private static Transferable getJVMLocalSourceTransferable() { 133 return currentJVMLocalSourceTransferable; 134 } 135 136 /* 137 * constants used by dropAccept() or dropReject() 138 */ 139 140 protected static final int STATUS_NONE = 0; // none pending 141 protected static final int STATUS_WAIT = 1; // drop pending 142 protected static final int STATUS_ACCEPT = 2; 143 protected static final int STATUS_REJECT = -1; 144 145 /** 146 * create the peer 147 */ 148 SunDropTargetContextPeer()149 public SunDropTargetContextPeer() { 150 super(); 151 } 152 153 /** 154 * @return the DropTarget associated with this peer 155 */ 156 getDropTarget()157 public DropTarget getDropTarget() { return currentDT; } 158 159 /** 160 * @param actions set the current actions 161 */ 162 setTargetActions(int actions)163 public synchronized void setTargetActions(int actions) { 164 currentA = actions & 165 (DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK); 166 } 167 168 /** 169 * @return the current target actions 170 */ 171 getTargetActions()172 public int getTargetActions() { 173 return currentA; 174 } 175 176 /** 177 * get the Transferable associated with the drop 178 */ 179 getTransferable()180 public Transferable getTransferable() { 181 return this; 182 } 183 184 /** 185 * @return current DataFlavors available 186 */ 187 // NOTE: This method may be called by privileged threads. 188 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 189 getTransferDataFlavors()190 public DataFlavor[] getTransferDataFlavors() { 191 final Transferable localTransferable = local; 192 193 if (localTransferable != null) { 194 return localTransferable.getTransferDataFlavors(); 195 } else { 196 return DataTransferer.getInstance().getFlavorsForFormatsAsArray 197 (currentT, DataTransferer.adaptFlavorMap 198 (currentDT.getFlavorMap())); 199 } 200 } 201 202 /** 203 * @return if the flavor is supported 204 */ 205 isDataFlavorSupported(DataFlavor df)206 public boolean isDataFlavorSupported(DataFlavor df) { 207 Transferable localTransferable = local; 208 209 if (localTransferable != null) { 210 return localTransferable.isDataFlavorSupported(df); 211 } else { 212 return DataTransferer.getInstance().getFlavorsForFormats 213 (currentT, DataTransferer.adaptFlavorMap 214 (currentDT.getFlavorMap())). 215 containsKey(df); 216 } 217 } 218 219 /** 220 * @return the data 221 */ 222 getTransferData(DataFlavor df)223 public Object getTransferData(DataFlavor df) 224 throws UnsupportedFlavorException, IOException, 225 InvalidDnDOperationException 226 { 227 228 @SuppressWarnings("removal") 229 SecurityManager sm = System.getSecurityManager(); 230 try { 231 if (!dropInProcess && sm != null) { 232 sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION); 233 } 234 } catch (Exception e) { 235 Thread currentThread = Thread.currentThread(); 236 currentThread.getUncaughtExceptionHandler().uncaughtException(currentThread, e); 237 return null; 238 } 239 240 Long lFormat = null; 241 Transferable localTransferable = local; 242 243 if (localTransferable != null) { 244 return localTransferable.getTransferData(df); 245 } 246 247 if (dropStatus != STATUS_ACCEPT || dropComplete) { 248 throw new InvalidDnDOperationException("No drop current"); 249 } 250 251 Map<DataFlavor, Long> flavorMap = DataTransferer.getInstance() 252 .getFlavorsForFormats(currentT, DataTransferer.adaptFlavorMap 253 (currentDT.getFlavorMap())); 254 255 lFormat = flavorMap.get(df); 256 if (lFormat == null) { 257 throw new UnsupportedFlavorException(df); 258 } 259 260 if (df.isRepresentationClassRemote() && 261 currentDA != DnDConstants.ACTION_LINK) { 262 throw new InvalidDnDOperationException("only ACTION_LINK is permissable for transfer of java.rmi.Remote objects"); 263 } 264 265 final long format = lFormat.longValue(); 266 267 Object ret = getNativeData(format); 268 269 if (ret instanceof byte[]) { 270 try { 271 return DataTransferer.getInstance(). 272 translateBytes((byte[])ret, df, format, this); 273 } catch (IOException e) { 274 throw new InvalidDnDOperationException(e.getMessage()); 275 } 276 } else if (ret instanceof InputStream) { 277 try { 278 return DataTransferer.getInstance(). 279 translateStream((InputStream)ret, df, format, this); 280 } catch (IOException e) { 281 throw new InvalidDnDOperationException(e.getMessage()); 282 } 283 } else { 284 throw new IOException("no native data was transfered"); 285 } 286 } 287 getNativeData(long format)288 protected abstract Object getNativeData(long format) 289 throws IOException; 290 291 /** 292 * @return if the transfer is a local one 293 */ isTransferableJVMLocal()294 public boolean isTransferableJVMLocal() { 295 return local != null || getJVMLocalSourceTransferable() != null; 296 } 297 handleEnterMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)298 private int handleEnterMessage(final Component component, 299 final int x, final int y, 300 final int dropAction, 301 final int actions, final long[] formats, 302 final long nativeCtxt) { 303 return postDropTargetEvent(component, x, y, dropAction, actions, 304 formats, nativeCtxt, 305 SunDropTargetEvent.MOUSE_ENTERED, 306 SunDropTargetContextPeer.DISPATCH_SYNC); 307 } 308 309 /** 310 * actual processing on EventQueue Thread 311 */ 312 processEnterMessage(SunDropTargetEvent event)313 protected void processEnterMessage(SunDropTargetEvent event) { 314 Component c = (Component)event.getSource(); 315 DropTarget dt = c.getDropTarget(); 316 Point hots = event.getPoint(); 317 318 local = getJVMLocalSourceTransferable(); 319 DropTargetContextAccessor acc = 320 AWTAccessor.getDropTargetContextAccessor(); 321 if (currentDTC != null) { // some wreckage from last time 322 acc.reset(currentDTC); 323 currentDTC = null; 324 } 325 326 if (c.isShowing() && dt != null && dt.isActive()) { 327 currentDT = dt; 328 currentDTC = currentDT.getDropTargetContext(); 329 330 acc.setDropTargetContextPeer(currentDTC, this); 331 332 currentA = dt.getDefaultActions(); 333 334 try { 335 ((DropTargetListener)dt).dragEnter(new DropTargetDragEvent(currentDTC, 336 hots, 337 currentDA, 338 currentSA)); 339 } catch (Exception e) { 340 e.printStackTrace(); 341 currentDA = DnDConstants.ACTION_NONE; 342 } 343 } else { 344 currentDT = null; 345 currentDTC = null; 346 currentDA = DnDConstants.ACTION_NONE; 347 currentSA = DnDConstants.ACTION_NONE; 348 currentA = DnDConstants.ACTION_NONE; 349 } 350 351 } 352 353 /** 354 * upcall to handle exit messages 355 */ 356 handleExitMessage(final Component component, final long nativeCtxt)357 private void handleExitMessage(final Component component, 358 final long nativeCtxt) { 359 /* 360 * Even though the return value is irrelevant for this event, it is 361 * dispatched synchronously to fix 4393148 properly. 362 */ 363 postDropTargetEvent(component, 0, 0, DnDConstants.ACTION_NONE, 364 DnDConstants.ACTION_NONE, null, nativeCtxt, 365 SunDropTargetEvent.MOUSE_EXITED, 366 SunDropTargetContextPeer.DISPATCH_SYNC); 367 } 368 369 /** 370 * 371 */ 372 processExitMessage(SunDropTargetEvent event)373 protected void processExitMessage(SunDropTargetEvent event) { 374 Component c = (Component)event.getSource(); 375 DropTarget dt = c.getDropTarget(); 376 DropTargetContext dtc = null; 377 DropTargetContextAccessor acc = 378 AWTAccessor.getDropTargetContextAccessor(); 379 380 if (dt == null) { 381 currentDT = null; 382 currentT = null; 383 384 if (currentDTC != null) { 385 acc.reset(currentDTC); 386 } 387 388 currentDTC = null; 389 390 return; 391 } 392 393 if (dt != currentDT) { 394 395 if (currentDTC != null) { 396 acc.reset(currentDTC); 397 } 398 399 currentDT = dt; 400 currentDTC = dt.getDropTargetContext(); 401 402 acc.setDropTargetContextPeer(currentDTC, this); 403 } 404 405 dtc = currentDTC; 406 407 if (dt.isActive()) try { 408 ((DropTargetListener)dt).dragExit(new DropTargetEvent(dtc)); 409 } catch (Exception e) { 410 e.printStackTrace(); 411 } finally { 412 currentA = DnDConstants.ACTION_NONE; 413 currentSA = DnDConstants.ACTION_NONE; 414 currentDA = DnDConstants.ACTION_NONE; 415 currentDT = null; 416 currentT = null; 417 418 acc.reset(currentDTC); 419 currentDTC = null; 420 421 local = null; 422 423 dragRejected = false; 424 } 425 } 426 handleMotionMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)427 private int handleMotionMessage(final Component component, 428 final int x, final int y, 429 final int dropAction, 430 final int actions, final long[] formats, 431 final long nativeCtxt) { 432 return postDropTargetEvent(component, x, y, dropAction, actions, 433 formats, nativeCtxt, 434 SunDropTargetEvent.MOUSE_DRAGGED, 435 SunDropTargetContextPeer.DISPATCH_SYNC); 436 } 437 438 /** 439 * 440 */ 441 processMotionMessage(SunDropTargetEvent event, boolean operationChanged)442 protected void processMotionMessage(SunDropTargetEvent event, 443 boolean operationChanged) { 444 Component c = (Component)event.getSource(); 445 Point hots = event.getPoint(); 446 int id = event.getID(); 447 DropTarget dt = c.getDropTarget(); 448 DropTargetContext dtc = null; 449 DropTargetContextAccessor acc = 450 AWTAccessor.getDropTargetContextAccessor(); 451 452 if (c.isShowing() && (dt != null) && dt.isActive()) { 453 if (currentDT != dt) { 454 if (currentDTC != null) { 455 acc.reset(currentDTC); 456 } 457 458 currentDT = dt; 459 currentDTC = null; 460 } 461 462 dtc = currentDT.getDropTargetContext(); 463 if (dtc != currentDTC) { 464 if (currentDTC != null) { 465 acc.reset(currentDTC); 466 } 467 468 currentDTC = dtc; 469 acc.setDropTargetContextPeer(currentDTC, this); 470 } 471 472 currentA = currentDT.getDefaultActions(); 473 474 try { 475 DropTargetDragEvent dtde = new DropTargetDragEvent(dtc, 476 hots, 477 currentDA, 478 currentSA); 479 DropTargetListener dtl = (DropTargetListener)dt; 480 if (operationChanged) { 481 dtl.dropActionChanged(dtde); 482 } else { 483 dtl.dragOver(dtde); 484 } 485 486 if (dragRejected) { 487 currentDA = DnDConstants.ACTION_NONE; 488 } 489 } catch (Exception e) { 490 e.printStackTrace(); 491 currentDA = DnDConstants.ACTION_NONE; 492 } 493 } else { 494 currentDA = DnDConstants.ACTION_NONE; 495 } 496 } 497 498 /** 499 * upcall to handle the Drop message 500 */ 501 handleDropMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)502 private void handleDropMessage(final Component component, 503 final int x, final int y, 504 final int dropAction, final int actions, 505 final long[] formats, 506 final long nativeCtxt) { 507 postDropTargetEvent(component, x, y, dropAction, actions, 508 formats, nativeCtxt, 509 SunDropTargetEvent.MOUSE_DROPPED, 510 !SunDropTargetContextPeer.DISPATCH_SYNC); 511 } 512 513 /** 514 * 515 */ 516 processDropMessage(SunDropTargetEvent event)517 protected void processDropMessage(SunDropTargetEvent event) { 518 Component c = (Component)event.getSource(); 519 Point hots = event.getPoint(); 520 DropTarget dt = c.getDropTarget(); 521 522 dropStatus = STATUS_WAIT; // drop pending ACK 523 dropComplete = false; 524 525 if (c.isShowing() && dt != null && dt.isActive()) { 526 DropTargetContext dtc = dt.getDropTargetContext(); 527 528 currentDT = dt; 529 DropTargetContextAccessor acc = 530 AWTAccessor.getDropTargetContextAccessor(); 531 532 if (currentDTC != null) { 533 acc.reset(currentDTC); 534 } 535 536 currentDTC = dtc; 537 acc.setDropTargetContextPeer(currentDTC, this); 538 currentA = dt.getDefaultActions(); 539 540 synchronized(_globalLock) { 541 if ((local = getJVMLocalSourceTransferable()) != null) 542 setCurrentJVMLocalSourceTransferable(null); 543 } 544 545 dropInProcess = true; 546 547 try { 548 ((DropTargetListener)dt).drop(new DropTargetDropEvent(dtc, 549 hots, 550 currentDA, 551 currentSA, 552 local != null)); 553 } finally { 554 if (dropStatus == STATUS_WAIT) { 555 rejectDrop(); 556 } else if (dropComplete == false) { 557 dropComplete(false); 558 } 559 dropInProcess = false; 560 } 561 } else { 562 rejectDrop(); 563 } 564 } 565 postDropTargetEvent(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt, final int eventID, final boolean dispatchType)566 protected int postDropTargetEvent(final Component component, 567 final int x, final int y, 568 final int dropAction, 569 final int actions, 570 final long[] formats, 571 final long nativeCtxt, 572 final int eventID, 573 final boolean dispatchType) { 574 AppContext appContext = SunToolkit.targetToAppContext(component); 575 576 EventDispatcher dispatcher = 577 new EventDispatcher(this, dropAction, actions, formats, nativeCtxt, 578 dispatchType); 579 580 SunDropTargetEvent event = 581 new SunDropTargetEvent(component, eventID, x, y, dispatcher); 582 583 if (dispatchType == SunDropTargetContextPeer.DISPATCH_SYNC) { 584 DataTransferer.getInstance().getToolkitThreadBlockedHandler().lock(); 585 } 586 587 // schedule callback 588 SunToolkit.postEvent(appContext, event); 589 590 eventPosted(event); 591 592 if (dispatchType == SunDropTargetContextPeer.DISPATCH_SYNC) { 593 while (!dispatcher.isDone()) { 594 DataTransferer.getInstance().getToolkitThreadBlockedHandler().enter(); 595 } 596 597 DataTransferer.getInstance().getToolkitThreadBlockedHandler().unlock(); 598 599 // return target's response 600 return dispatcher.getReturnValue(); 601 } else { 602 return 0; 603 } 604 } 605 606 /** 607 * acceptDrag 608 */ 609 acceptDrag(int dragOperation)610 public synchronized void acceptDrag(int dragOperation) { 611 if (currentDT == null) { 612 throw new InvalidDnDOperationException("No Drag pending"); 613 } 614 currentDA = mapOperation(dragOperation); 615 if (currentDA != DnDConstants.ACTION_NONE) { 616 dragRejected = false; 617 } 618 } 619 620 /** 621 * rejectDrag 622 */ 623 rejectDrag()624 public synchronized void rejectDrag() { 625 if (currentDT == null) { 626 throw new InvalidDnDOperationException("No Drag pending"); 627 } 628 currentDA = DnDConstants.ACTION_NONE; 629 dragRejected = true; 630 } 631 632 /** 633 * acceptDrop 634 */ 635 acceptDrop(int dropOperation)636 public synchronized void acceptDrop(int dropOperation) { 637 if (dropOperation == DnDConstants.ACTION_NONE) 638 throw new IllegalArgumentException("invalid acceptDrop() action"); 639 640 if (dropStatus == STATUS_WAIT || dropStatus == STATUS_ACCEPT) { 641 currentDA = currentA = mapOperation(dropOperation & currentSA); 642 643 dropStatus = STATUS_ACCEPT; 644 dropComplete = false; 645 } else { 646 throw new InvalidDnDOperationException("invalid acceptDrop()"); 647 } 648 } 649 650 /** 651 * reject Drop 652 */ 653 rejectDrop()654 public synchronized void rejectDrop() { 655 if (dropStatus != STATUS_WAIT) { 656 throw new InvalidDnDOperationException("invalid rejectDrop()"); 657 } 658 dropStatus = STATUS_REJECT; 659 /* 660 * Fix for 4285634. 661 * The target rejected the drop means that it doesn't perform any 662 * drop action. This change is to make Solaris behavior consistent 663 * with Win32. 664 */ 665 currentDA = DnDConstants.ACTION_NONE; 666 dropComplete(false); 667 } 668 669 /** 670 * mapOperation 671 */ 672 mapOperation(int operation)673 private int mapOperation(int operation) { 674 int[] operations = { 675 DnDConstants.ACTION_MOVE, 676 DnDConstants.ACTION_COPY, 677 DnDConstants.ACTION_LINK, 678 }; 679 int ret = DnDConstants.ACTION_NONE; 680 681 for (int i = 0; i < operations.length; i++) { 682 if ((operation & operations[i]) == operations[i]) { 683 ret = operations[i]; 684 break; 685 } 686 } 687 688 return ret; 689 } 690 691 /** 692 * signal drop complete 693 */ 694 dropComplete(boolean success)695 public synchronized void dropComplete(boolean success) { 696 if (dropStatus == STATUS_NONE) { 697 throw new InvalidDnDOperationException("No Drop pending"); 698 } 699 700 if (currentDTC != null) { 701 AWTAccessor.getDropTargetContextAccessor().reset(currentDTC); 702 } 703 704 currentDT = null; 705 currentDTC = null; 706 currentT = null; 707 currentA = DnDConstants.ACTION_NONE; 708 709 synchronized(_globalLock) { 710 currentJVMLocalSourceTransferable = null; 711 } 712 713 dropStatus = STATUS_NONE; 714 dropComplete = true; 715 716 try { 717 doDropDone(success, currentDA, local != null); 718 } finally { 719 currentDA = DnDConstants.ACTION_NONE; 720 // The native context is invalid after the drop is done. 721 // Clear the reference to prohibit access. 722 nativeDragContext = 0; 723 } 724 } 725 doDropDone(boolean success, int dropAction, boolean isLocal)726 protected abstract void doDropDone(boolean success, 727 int dropAction, boolean isLocal); 728 getNativeDragContext()729 protected synchronized long getNativeDragContext() { 730 return nativeDragContext; 731 } 732 eventPosted(SunDropTargetEvent e)733 protected void eventPosted(SunDropTargetEvent e) {} 734 eventProcessed(SunDropTargetEvent e, int returnValue, boolean dispatcherDone)735 protected void eventProcessed(SunDropTargetEvent e, int returnValue, 736 boolean dispatcherDone) {} 737 738 protected static class EventDispatcher { 739 740 private final SunDropTargetContextPeer peer; 741 742 // context fields 743 private final int dropAction; 744 private final int actions; 745 private final long[] formats; 746 private long nativeCtxt; 747 private final boolean dispatchType; 748 private boolean dispatcherDone = false; 749 750 // dispatcher state fields 751 private int returnValue = 0; 752 // set of events to be dispatched by this dispatcher 753 private final HashSet<SunDropTargetEvent> eventSet = new HashSet<>(3); 754 755 static final ToolkitThreadBlockedHandler handler = 756 DataTransferer.getInstance().getToolkitThreadBlockedHandler(); 757 EventDispatcher(SunDropTargetContextPeer peer, int dropAction, int actions, long[] formats, long nativeCtxt, boolean dispatchType)758 EventDispatcher(SunDropTargetContextPeer peer, 759 int dropAction, 760 int actions, 761 long[] formats, 762 long nativeCtxt, 763 boolean dispatchType) { 764 765 this.peer = peer; 766 this.nativeCtxt = nativeCtxt; 767 this.dropAction = dropAction; 768 this.actions = actions; 769 this.formats = 770 (null == formats) ? null : Arrays.copyOf(formats, formats.length); 771 this.dispatchType = dispatchType; 772 } 773 dispatchEvent(SunDropTargetEvent e)774 void dispatchEvent(SunDropTargetEvent e) { 775 int id = e.getID(); 776 777 switch (id) { 778 case SunDropTargetEvent.MOUSE_ENTERED: 779 dispatchEnterEvent(e); 780 break; 781 case SunDropTargetEvent.MOUSE_DRAGGED: 782 dispatchMotionEvent(e); 783 break; 784 case SunDropTargetEvent.MOUSE_EXITED: 785 dispatchExitEvent(e); 786 break; 787 case SunDropTargetEvent.MOUSE_DROPPED: 788 dispatchDropEvent(e); 789 break; 790 default: 791 throw new InvalidDnDOperationException(); 792 } 793 } 794 dispatchEnterEvent(SunDropTargetEvent e)795 private void dispatchEnterEvent(SunDropTargetEvent e) { 796 synchronized (peer) { 797 798 // store the drop action here to track operation changes 799 peer.previousDA = dropAction; 800 801 // setup peer context 802 peer.nativeDragContext = nativeCtxt; 803 peer.currentT = formats; 804 peer.currentSA = actions; 805 peer.currentDA = dropAction; 806 // To allow data retrieval. 807 peer.dropStatus = STATUS_ACCEPT; 808 peer.dropComplete = false; 809 810 try { 811 peer.processEnterMessage(e); 812 } finally { 813 peer.dropStatus = STATUS_NONE; 814 } 815 816 setReturnValue(peer.currentDA); 817 } 818 } 819 dispatchMotionEvent(SunDropTargetEvent e)820 private void dispatchMotionEvent(SunDropTargetEvent e) { 821 synchronized (peer) { 822 823 boolean operationChanged = peer.previousDA != dropAction; 824 peer.previousDA = dropAction; 825 826 // setup peer context 827 peer.nativeDragContext = nativeCtxt; 828 peer.currentT = formats; 829 peer.currentSA = actions; 830 peer.currentDA = dropAction; 831 // To allow data retrieval. 832 peer.dropStatus = STATUS_ACCEPT; 833 peer.dropComplete = false; 834 835 try { 836 peer.processMotionMessage(e, operationChanged); 837 } finally { 838 peer.dropStatus = STATUS_NONE; 839 } 840 841 setReturnValue(peer.currentDA); 842 } 843 } 844 dispatchExitEvent(SunDropTargetEvent e)845 private void dispatchExitEvent(SunDropTargetEvent e) { 846 synchronized (peer) { 847 848 // setup peer context 849 peer.nativeDragContext = nativeCtxt; 850 851 peer.processExitMessage(e); 852 } 853 } 854 dispatchDropEvent(SunDropTargetEvent e)855 private void dispatchDropEvent(SunDropTargetEvent e) { 856 synchronized (peer) { 857 858 // setup peer context 859 peer.nativeDragContext = nativeCtxt; 860 peer.currentT = formats; 861 peer.currentSA = actions; 862 peer.currentDA = dropAction; 863 864 peer.processDropMessage(e); 865 } 866 } 867 setReturnValue(int ret)868 void setReturnValue(int ret) { 869 returnValue = ret; 870 } 871 getReturnValue()872 int getReturnValue() { 873 return returnValue; 874 } 875 isDone()876 boolean isDone() { 877 return eventSet.isEmpty(); 878 } 879 registerEvent(SunDropTargetEvent e)880 void registerEvent(SunDropTargetEvent e) { 881 handler.lock(); 882 if (!eventSet.add(e) && dndLog.isLoggable(PlatformLogger.Level.FINE)) { 883 dndLog.fine("Event is already registered: " + e); 884 } 885 handler.unlock(); 886 } 887 unregisterEvent(SunDropTargetEvent e)888 void unregisterEvent(SunDropTargetEvent e) { 889 handler.lock(); 890 try { 891 if (!eventSet.remove(e)) { 892 // This event has already been unregistered. 893 return; 894 } 895 if (eventSet.isEmpty()) { 896 if (!dispatcherDone && dispatchType == DISPATCH_SYNC) { 897 handler.exit(); 898 } 899 dispatcherDone = true; 900 } 901 } finally { 902 handler.unlock(); 903 } 904 905 try { 906 peer.eventProcessed(e, returnValue, dispatcherDone); 907 } finally { 908 /* 909 * Clear the reference to the native context if all copies of 910 * the original event are processed. 911 */ 912 if (dispatcherDone) { 913 nativeCtxt = 0; 914 // Fix for 6342381 915 peer.nativeDragContext = 0; 916 917 } 918 } 919 } 920 unregisterAllEvents()921 public void unregisterAllEvents() { 922 Object[] events = null; 923 handler.lock(); 924 try { 925 events = eventSet.toArray(); 926 } finally { 927 handler.unlock(); 928 } 929 930 if (events != null) { 931 for (int i = 0; i < events.length; i++) { 932 unregisterEvent((SunDropTargetEvent)events[i]); 933 } 934 } 935 } 936 } 937 } 938