1 /* 2 * Copyright (c) 2000, 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.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 import sun.security.util.SecurityConstants; 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 setCurrentJVMLocalSourceTransferable(Transferable t)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 getJVMLocalSourceTransferable()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 SunDropTargetContextPeer()147 public SunDropTargetContextPeer() { 148 super(); 149 } 150 151 /** 152 * @return the DropTarget associated with this peer 153 */ 154 getDropTarget()155 public DropTarget getDropTarget() { return currentDT; } 156 157 /** 158 * @param actions set the current actions 159 */ 160 setTargetActions(int actions)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 getTargetActions()170 public int getTargetActions() { 171 return currentA; 172 } 173 174 /** 175 * get the Transferable associated with the drop 176 */ 177 getTransferable()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 getTransferDataFlavors()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 isDataFlavorSupported(DataFlavor df)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 getTransferData(DataFlavor df)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(SecurityConstants.AWT.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 getNativeData(long format)285 protected abstract Object getNativeData(long format) 286 throws IOException; 287 288 /** 289 * @return if the transfer is a local one 290 */ isTransferableJVMLocal()291 public boolean isTransferableJVMLocal() { 292 return local != null || getJVMLocalSourceTransferable() != null; 293 } 294 handleEnterMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)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 processEnterMessage(SunDropTargetEvent event)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 handleExitMessage(final Component component, final long nativeCtxt)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 processExitMessage(SunDropTargetEvent event)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 handleMotionMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)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 processMotionMessage(SunDropTargetEvent event, boolean operationChanged)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 handleDropMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)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 processDropMessage(SunDropTargetEvent event)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 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)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 acceptDrag(int dragOperation)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 rejectDrag()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 acceptDrop(int dropOperation)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 rejectDrop()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 mapOperation(int operation)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 dropComplete(boolean success)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 doDropDone(boolean success, int dropAction, boolean isLocal)714 protected abstract void doDropDone(boolean success, 715 int dropAction, boolean isLocal); 716 getNativeDragContext()717 protected synchronized long getNativeDragContext() { 718 return nativeDragContext; 719 } 720 eventPosted(SunDropTargetEvent e)721 protected void eventPosted(SunDropTargetEvent e) {} 722 eventProcessed(SunDropTargetEvent e, int returnValue, boolean dispatcherDone)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 EventDispatcher(SunDropTargetContextPeer peer, int dropAction, int actions, long[] formats, long nativeCtxt, boolean dispatchType)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 dispatchEvent(SunDropTargetEvent e)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 dispatchEnterEvent(SunDropTargetEvent e)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 dispatchMotionEvent(SunDropTargetEvent e)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 dispatchExitEvent(SunDropTargetEvent e)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 dispatchDropEvent(SunDropTargetEvent e)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 setReturnValue(int ret)856 void setReturnValue(int ret) { 857 returnValue = ret; 858 } 859 getReturnValue()860 int getReturnValue() { 861 return returnValue; 862 } 863 isDone()864 boolean isDone() { 865 return eventSet.isEmpty(); 866 } 867 registerEvent(SunDropTargetEvent e)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 unregisterEvent(SunDropTargetEvent e)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 unregisterAllEvents()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 } 926