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