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