1 /* 2 * Copyright (c) 2000, 2015, 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 SecurityManager sm = System.getSecurityManager(); 229 try { 230 if (!dropInProcess && sm != null) { 231 sm.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION); 232 } 233 } catch (Exception e) { 234 Thread currentThread = Thread.currentThread(); 235 currentThread.getUncaughtExceptionHandler().uncaughtException(currentThread, e); 236 return null; 237 } 238 239 Long lFormat = null; 240 Transferable localTransferable = local; 241 242 if (localTransferable != null) { 243 return localTransferable.getTransferData(df); 244 } 245 246 if (dropStatus != STATUS_ACCEPT || dropComplete) { 247 throw new InvalidDnDOperationException("No drop current"); 248 } 249 250 Map<DataFlavor, Long> flavorMap = DataTransferer.getInstance() 251 .getFlavorsForFormats(currentT, DataTransferer.adaptFlavorMap 252 (currentDT.getFlavorMap())); 253 254 lFormat = flavorMap.get(df); 255 if (lFormat == null) { 256 throw new UnsupportedFlavorException(df); 257 } 258 259 if (df.isRepresentationClassRemote() && 260 currentDA != DnDConstants.ACTION_LINK) { 261 throw new InvalidDnDOperationException("only ACTION_LINK is permissable for transfer of java.rmi.Remote objects"); 262 } 263 264 final long format = lFormat.longValue(); 265 266 Object ret = getNativeData(format); 267 268 if (ret instanceof byte[]) { 269 try { 270 return DataTransferer.getInstance(). 271 translateBytes((byte[])ret, df, format, this); 272 } catch (IOException e) { 273 throw new InvalidDnDOperationException(e.getMessage()); 274 } 275 } else if (ret instanceof InputStream) { 276 try { 277 return DataTransferer.getInstance(). 278 translateStream((InputStream)ret, df, format, this); 279 } catch (IOException e) { 280 throw new InvalidDnDOperationException(e.getMessage()); 281 } 282 } else { 283 throw new IOException("no native data was transfered"); 284 } 285 } 286 getNativeData(long format)287 protected abstract Object getNativeData(long format) 288 throws IOException; 289 290 /** 291 * @return if the transfer is a local one 292 */ isTransferableJVMLocal()293 public boolean isTransferableJVMLocal() { 294 return local != null || getJVMLocalSourceTransferable() != null; 295 } 296 handleEnterMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)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 processEnterMessage(SunDropTargetEvent event)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 DropTargetContextAccessor acc = 319 AWTAccessor.getDropTargetContextAccessor(); 320 if (currentDTC != null) { // some wreckage from last time 321 acc.reset(currentDTC); 322 currentDTC = null; 323 } 324 325 if (c.isShowing() && dt != null && dt.isActive()) { 326 currentDT = dt; 327 currentDTC = currentDT.getDropTargetContext(); 328 329 acc.setDropTargetContextPeer(currentDTC, this); 330 331 currentA = dt.getDefaultActions(); 332 333 try { 334 ((DropTargetListener)dt).dragEnter(new DropTargetDragEvent(currentDTC, 335 hots, 336 currentDA, 337 currentSA)); 338 } catch (Exception e) { 339 e.printStackTrace(); 340 currentDA = DnDConstants.ACTION_NONE; 341 } 342 } else { 343 currentDT = null; 344 currentDTC = null; 345 currentDA = DnDConstants.ACTION_NONE; 346 currentSA = DnDConstants.ACTION_NONE; 347 currentA = DnDConstants.ACTION_NONE; 348 } 349 350 } 351 352 /** 353 * upcall to handle exit messages 354 */ 355 handleExitMessage(final Component component, final long nativeCtxt)356 private void handleExitMessage(final Component component, 357 final long nativeCtxt) { 358 /* 359 * Even though the return value is irrelevant for this event, it is 360 * dispatched synchronously to fix 4393148 properly. 361 */ 362 postDropTargetEvent(component, 0, 0, DnDConstants.ACTION_NONE, 363 DnDConstants.ACTION_NONE, null, nativeCtxt, 364 SunDropTargetEvent.MOUSE_EXITED, 365 SunDropTargetContextPeer.DISPATCH_SYNC); 366 } 367 368 /** 369 * 370 */ 371 processExitMessage(SunDropTargetEvent event)372 protected void processExitMessage(SunDropTargetEvent event) { 373 Component c = (Component)event.getSource(); 374 DropTarget dt = c.getDropTarget(); 375 DropTargetContext dtc = null; 376 DropTargetContextAccessor acc = 377 AWTAccessor.getDropTargetContextAccessor(); 378 379 if (dt == null) { 380 currentDT = null; 381 currentT = null; 382 383 if (currentDTC != null) { 384 acc.reset(currentDTC); 385 } 386 387 currentDTC = null; 388 389 return; 390 } 391 392 if (dt != currentDT) { 393 394 if (currentDTC != null) { 395 acc.reset(currentDTC); 396 } 397 398 currentDT = dt; 399 currentDTC = dt.getDropTargetContext(); 400 401 acc.setDropTargetContextPeer(currentDTC, this); 402 } 403 404 dtc = currentDTC; 405 406 if (dt.isActive()) try { 407 ((DropTargetListener)dt).dragExit(new DropTargetEvent(dtc)); 408 } catch (Exception e) { 409 e.printStackTrace(); 410 } finally { 411 currentA = DnDConstants.ACTION_NONE; 412 currentSA = DnDConstants.ACTION_NONE; 413 currentDA = DnDConstants.ACTION_NONE; 414 currentDT = null; 415 currentT = null; 416 417 acc.reset(currentDTC); 418 currentDTC = null; 419 420 local = null; 421 422 dragRejected = false; 423 } 424 } 425 handleMotionMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)426 private int handleMotionMessage(final Component component, 427 final int x, final int y, 428 final int dropAction, 429 final int actions, final long[] formats, 430 final long nativeCtxt) { 431 return postDropTargetEvent(component, x, y, dropAction, actions, 432 formats, nativeCtxt, 433 SunDropTargetEvent.MOUSE_DRAGGED, 434 SunDropTargetContextPeer.DISPATCH_SYNC); 435 } 436 437 /** 438 * 439 */ 440 processMotionMessage(SunDropTargetEvent event, boolean operationChanged)441 protected void processMotionMessage(SunDropTargetEvent event, 442 boolean operationChanged) { 443 Component c = (Component)event.getSource(); 444 Point hots = event.getPoint(); 445 int id = event.getID(); 446 DropTarget dt = c.getDropTarget(); 447 DropTargetContext dtc = null; 448 DropTargetContextAccessor acc = 449 AWTAccessor.getDropTargetContextAccessor(); 450 451 if (c.isShowing() && (dt != null) && dt.isActive()) { 452 if (currentDT != dt) { 453 if (currentDTC != null) { 454 acc.reset(currentDTC); 455 } 456 457 currentDT = dt; 458 currentDTC = null; 459 } 460 461 dtc = currentDT.getDropTargetContext(); 462 if (dtc != currentDTC) { 463 if (currentDTC != null) { 464 acc.reset(currentDTC); 465 } 466 467 currentDTC = dtc; 468 acc.setDropTargetContextPeer(currentDTC, this); 469 } 470 471 currentA = currentDT.getDefaultActions(); 472 473 try { 474 DropTargetDragEvent dtde = new DropTargetDragEvent(dtc, 475 hots, 476 currentDA, 477 currentSA); 478 DropTargetListener dtl = (DropTargetListener)dt; 479 if (operationChanged) { 480 dtl.dropActionChanged(dtde); 481 } else { 482 dtl.dragOver(dtde); 483 } 484 485 if (dragRejected) { 486 currentDA = DnDConstants.ACTION_NONE; 487 } 488 } catch (Exception e) { 489 e.printStackTrace(); 490 currentDA = DnDConstants.ACTION_NONE; 491 } 492 } else { 493 currentDA = DnDConstants.ACTION_NONE; 494 } 495 } 496 497 /** 498 * upcall to handle the Drop message 499 */ 500 handleDropMessage(final Component component, final int x, final int y, final int dropAction, final int actions, final long[] formats, final long nativeCtxt)501 private void handleDropMessage(final Component component, 502 final int x, final int y, 503 final int dropAction, final int actions, 504 final long[] formats, 505 final long nativeCtxt) { 506 postDropTargetEvent(component, x, y, dropAction, actions, 507 formats, nativeCtxt, 508 SunDropTargetEvent.MOUSE_DROPPED, 509 !SunDropTargetContextPeer.DISPATCH_SYNC); 510 } 511 512 /** 513 * 514 */ 515 processDropMessage(SunDropTargetEvent event)516 protected void processDropMessage(SunDropTargetEvent event) { 517 Component c = (Component)event.getSource(); 518 Point hots = event.getPoint(); 519 DropTarget dt = c.getDropTarget(); 520 521 dropStatus = STATUS_WAIT; // drop pending ACK 522 dropComplete = false; 523 524 if (c.isShowing() && dt != null && dt.isActive()) { 525 DropTargetContext dtc = dt.getDropTargetContext(); 526 527 currentDT = dt; 528 DropTargetContextAccessor acc = 529 AWTAccessor.getDropTargetContextAccessor(); 530 531 if (currentDTC != null) { 532 acc.reset(currentDTC); 533 } 534 535 currentDTC = dtc; 536 acc.setDropTargetContextPeer(currentDTC, this); 537 currentA = dt.getDefaultActions(); 538 539 synchronized(_globalLock) { 540 if ((local = getJVMLocalSourceTransferable()) != null) 541 setCurrentJVMLocalSourceTransferable(null); 542 } 543 544 dropInProcess = true; 545 546 try { 547 ((DropTargetListener)dt).drop(new DropTargetDropEvent(dtc, 548 hots, 549 currentDA, 550 currentSA, 551 local != null)); 552 } finally { 553 if (dropStatus == STATUS_WAIT) { 554 rejectDrop(); 555 } else if (dropComplete == false) { 556 dropComplete(false); 557 } 558 dropInProcess = false; 559 } 560 } else { 561 rejectDrop(); 562 } 563 } 564 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)565 protected int postDropTargetEvent(final Component component, 566 final int x, final int y, 567 final int dropAction, 568 final int actions, 569 final long[] formats, 570 final long nativeCtxt, 571 final int eventID, 572 final boolean dispatchType) { 573 AppContext appContext = SunToolkit.targetToAppContext(component); 574 575 EventDispatcher dispatcher = 576 new EventDispatcher(this, dropAction, actions, formats, nativeCtxt, 577 dispatchType); 578 579 SunDropTargetEvent event = 580 new SunDropTargetEvent(component, eventID, x, y, dispatcher); 581 582 if (dispatchType == SunDropTargetContextPeer.DISPATCH_SYNC) { 583 DataTransferer.getInstance().getToolkitThreadBlockedHandler().lock(); 584 } 585 586 // schedule callback 587 SunToolkit.postEvent(appContext, event); 588 589 eventPosted(event); 590 591 if (dispatchType == SunDropTargetContextPeer.DISPATCH_SYNC) { 592 while (!dispatcher.isDone()) { 593 DataTransferer.getInstance().getToolkitThreadBlockedHandler().enter(); 594 } 595 596 DataTransferer.getInstance().getToolkitThreadBlockedHandler().unlock(); 597 598 // return target's response 599 return dispatcher.getReturnValue(); 600 } else { 601 return 0; 602 } 603 } 604 605 /** 606 * acceptDrag 607 */ 608 acceptDrag(int dragOperation)609 public synchronized void acceptDrag(int dragOperation) { 610 if (currentDT == null) { 611 throw new InvalidDnDOperationException("No Drag pending"); 612 } 613 currentDA = mapOperation(dragOperation); 614 if (currentDA != DnDConstants.ACTION_NONE) { 615 dragRejected = false; 616 } 617 } 618 619 /** 620 * rejectDrag 621 */ 622 rejectDrag()623 public synchronized void rejectDrag() { 624 if (currentDT == null) { 625 throw new InvalidDnDOperationException("No Drag pending"); 626 } 627 currentDA = DnDConstants.ACTION_NONE; 628 dragRejected = true; 629 } 630 631 /** 632 * acceptDrop 633 */ 634 acceptDrop(int dropOperation)635 public synchronized void acceptDrop(int dropOperation) { 636 if (dropOperation == DnDConstants.ACTION_NONE) 637 throw new IllegalArgumentException("invalid acceptDrop() action"); 638 639 if (dropStatus == STATUS_WAIT || dropStatus == STATUS_ACCEPT) { 640 currentDA = currentA = mapOperation(dropOperation & currentSA); 641 642 dropStatus = STATUS_ACCEPT; 643 dropComplete = false; 644 } else { 645 throw new InvalidDnDOperationException("invalid acceptDrop()"); 646 } 647 } 648 649 /** 650 * reject Drop 651 */ 652 rejectDrop()653 public synchronized void rejectDrop() { 654 if (dropStatus != STATUS_WAIT) { 655 throw new InvalidDnDOperationException("invalid rejectDrop()"); 656 } 657 dropStatus = STATUS_REJECT; 658 /* 659 * Fix for 4285634. 660 * The target rejected the drop means that it doesn't perform any 661 * drop action. This change is to make Solaris behavior consistent 662 * with Win32. 663 */ 664 currentDA = DnDConstants.ACTION_NONE; 665 dropComplete(false); 666 } 667 668 /** 669 * mapOperation 670 */ 671 mapOperation(int operation)672 private int mapOperation(int operation) { 673 int[] operations = { 674 DnDConstants.ACTION_MOVE, 675 DnDConstants.ACTION_COPY, 676 DnDConstants.ACTION_LINK, 677 }; 678 int ret = DnDConstants.ACTION_NONE; 679 680 for (int i = 0; i < operations.length; i++) { 681 if ((operation & operations[i]) == operations[i]) { 682 ret = operations[i]; 683 break; 684 } 685 } 686 687 return ret; 688 } 689 690 /** 691 * signal drop complete 692 */ 693 dropComplete(boolean success)694 public synchronized void dropComplete(boolean success) { 695 if (dropStatus == STATUS_NONE) { 696 throw new InvalidDnDOperationException("No Drop pending"); 697 } 698 699 if (currentDTC != null) { 700 AWTAccessor.getDropTargetContextAccessor().reset(currentDTC); 701 } 702 703 currentDT = null; 704 currentDTC = null; 705 currentT = null; 706 currentA = DnDConstants.ACTION_NONE; 707 708 synchronized(_globalLock) { 709 currentJVMLocalSourceTransferable = null; 710 } 711 712 dropStatus = STATUS_NONE; 713 dropComplete = true; 714 715 try { 716 doDropDone(success, currentDA, local != null); 717 } finally { 718 currentDA = DnDConstants.ACTION_NONE; 719 // The native context is invalid after the drop is done. 720 // Clear the reference to prohibit access. 721 nativeDragContext = 0; 722 } 723 } 724 doDropDone(boolean success, int dropAction, boolean isLocal)725 protected abstract void doDropDone(boolean success, 726 int dropAction, boolean isLocal); 727 getNativeDragContext()728 protected synchronized long getNativeDragContext() { 729 return nativeDragContext; 730 } 731 eventPosted(SunDropTargetEvent e)732 protected void eventPosted(SunDropTargetEvent e) {} 733 eventProcessed(SunDropTargetEvent e, int returnValue, boolean dispatcherDone)734 protected void eventProcessed(SunDropTargetEvent e, int returnValue, 735 boolean dispatcherDone) {} 736 737 protected static class EventDispatcher { 738 739 private final SunDropTargetContextPeer peer; 740 741 // context fields 742 private final int dropAction; 743 private final int actions; 744 private final long[] formats; 745 private long nativeCtxt; 746 private final boolean dispatchType; 747 private boolean dispatcherDone = false; 748 749 // dispatcher state fields 750 private int returnValue = 0; 751 // set of events to be dispatched by this dispatcher 752 private final HashSet<SunDropTargetEvent> eventSet = new HashSet<>(3); 753 754 static final ToolkitThreadBlockedHandler handler = 755 DataTransferer.getInstance().getToolkitThreadBlockedHandler(); 756 EventDispatcher(SunDropTargetContextPeer peer, int dropAction, int actions, long[] formats, long nativeCtxt, boolean dispatchType)757 EventDispatcher(SunDropTargetContextPeer peer, 758 int dropAction, 759 int actions, 760 long[] formats, 761 long nativeCtxt, 762 boolean dispatchType) { 763 764 this.peer = peer; 765 this.nativeCtxt = nativeCtxt; 766 this.dropAction = dropAction; 767 this.actions = actions; 768 this.formats = 769 (null == formats) ? null : Arrays.copyOf(formats, formats.length); 770 this.dispatchType = dispatchType; 771 } 772 dispatchEvent(SunDropTargetEvent e)773 void dispatchEvent(SunDropTargetEvent e) { 774 int id = e.getID(); 775 776 switch (id) { 777 case SunDropTargetEvent.MOUSE_ENTERED: 778 dispatchEnterEvent(e); 779 break; 780 case SunDropTargetEvent.MOUSE_DRAGGED: 781 dispatchMotionEvent(e); 782 break; 783 case SunDropTargetEvent.MOUSE_EXITED: 784 dispatchExitEvent(e); 785 break; 786 case SunDropTargetEvent.MOUSE_DROPPED: 787 dispatchDropEvent(e); 788 break; 789 default: 790 throw new InvalidDnDOperationException(); 791 } 792 } 793 dispatchEnterEvent(SunDropTargetEvent e)794 private void dispatchEnterEvent(SunDropTargetEvent e) { 795 synchronized (peer) { 796 797 // store the drop action here to track operation changes 798 peer.previousDA = dropAction; 799 800 // setup peer context 801 peer.nativeDragContext = nativeCtxt; 802 peer.currentT = formats; 803 peer.currentSA = actions; 804 peer.currentDA = dropAction; 805 // To allow data retrieval. 806 peer.dropStatus = STATUS_ACCEPT; 807 peer.dropComplete = false; 808 809 try { 810 peer.processEnterMessage(e); 811 } finally { 812 peer.dropStatus = STATUS_NONE; 813 } 814 815 setReturnValue(peer.currentDA); 816 } 817 } 818 dispatchMotionEvent(SunDropTargetEvent e)819 private void dispatchMotionEvent(SunDropTargetEvent e) { 820 synchronized (peer) { 821 822 boolean operationChanged = peer.previousDA != dropAction; 823 peer.previousDA = dropAction; 824 825 // setup peer context 826 peer.nativeDragContext = nativeCtxt; 827 peer.currentT = formats; 828 peer.currentSA = actions; 829 peer.currentDA = dropAction; 830 // To allow data retrieval. 831 peer.dropStatus = STATUS_ACCEPT; 832 peer.dropComplete = false; 833 834 try { 835 peer.processMotionMessage(e, operationChanged); 836 } finally { 837 peer.dropStatus = STATUS_NONE; 838 } 839 840 setReturnValue(peer.currentDA); 841 } 842 } 843 dispatchExitEvent(SunDropTargetEvent e)844 private void dispatchExitEvent(SunDropTargetEvent e) { 845 synchronized (peer) { 846 847 // setup peer context 848 peer.nativeDragContext = nativeCtxt; 849 850 peer.processExitMessage(e); 851 } 852 } 853 dispatchDropEvent(SunDropTargetEvent e)854 private void dispatchDropEvent(SunDropTargetEvent e) { 855 synchronized (peer) { 856 857 // setup peer context 858 peer.nativeDragContext = nativeCtxt; 859 peer.currentT = formats; 860 peer.currentSA = actions; 861 peer.currentDA = dropAction; 862 863 peer.processDropMessage(e); 864 } 865 } 866 setReturnValue(int ret)867 void setReturnValue(int ret) { 868 returnValue = ret; 869 } 870 getReturnValue()871 int getReturnValue() { 872 return returnValue; 873 } 874 isDone()875 boolean isDone() { 876 return eventSet.isEmpty(); 877 } 878 registerEvent(SunDropTargetEvent e)879 void registerEvent(SunDropTargetEvent e) { 880 handler.lock(); 881 if (!eventSet.add(e) && dndLog.isLoggable(PlatformLogger.Level.FINE)) { 882 dndLog.fine("Event is already registered: " + e); 883 } 884 handler.unlock(); 885 } 886 unregisterEvent(SunDropTargetEvent e)887 void unregisterEvent(SunDropTargetEvent e) { 888 handler.lock(); 889 try { 890 if (!eventSet.remove(e)) { 891 // This event has already been unregistered. 892 return; 893 } 894 if (eventSet.isEmpty()) { 895 if (!dispatcherDone && dispatchType == DISPATCH_SYNC) { 896 handler.exit(); 897 } 898 dispatcherDone = true; 899 } 900 } finally { 901 handler.unlock(); 902 } 903 904 try { 905 peer.eventProcessed(e, returnValue, dispatcherDone); 906 } finally { 907 /* 908 * Clear the reference to the native context if all copies of 909 * the original event are processed. 910 */ 911 if (dispatcherDone) { 912 nativeCtxt = 0; 913 // Fix for 6342381 914 peer.nativeDragContext = 0; 915 916 } 917 } 918 } 919 unregisterAllEvents()920 public void unregisterAllEvents() { 921 Object[] events = null; 922 handler.lock(); 923 try { 924 events = eventSet.toArray(); 925 } finally { 926 handler.unlock(); 927 } 928 929 if (events != null) { 930 for (int i = 0; i < events.length; i++) { 931 unregisterEvent((SunDropTargetEvent)events[i]); 932 } 933 } 934 } 935 } 936 } 937