1 /* 2 * Copyright (c) 2011, 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.lwawt.macosx; 27 28 import java.awt.*; 29 import java.awt.dnd.DropTarget; 30 31 import sun.awt.dnd.SunDropTargetContextPeer; 32 import sun.awt.dnd.SunDropTargetEvent; 33 34 import javax.swing.*; 35 36 37 final class CDropTargetContextPeer extends SunDropTargetContextPeer { 38 39 private long fNativeDropTransfer = 0; 40 private long fNativeDataAvailable = 0; 41 private Object fNativeData = null; 42 private DropTarget insideTarget = null; 43 44 Object awtLockAccess = new Object(); 45 getDropTargetContextPeer()46 static CDropTargetContextPeer getDropTargetContextPeer() { 47 return new CDropTargetContextPeer(); 48 } 49 CDropTargetContextPeer()50 private CDropTargetContextPeer() { 51 super(); 52 } 53 getNativeData(long format)54 protected Object getNativeData(long format) { 55 long nativeDropTarget = this.getNativeDragContext(); 56 57 synchronized (awtLockAccess) { 58 fNativeDataAvailable = 0; 59 60 if (fNativeDropTransfer == 0) { 61 fNativeDropTransfer = startTransfer(nativeDropTarget, format); 62 } else { 63 addTransfer(nativeDropTarget, fNativeDropTransfer, format); 64 } 65 66 while (format != fNativeDataAvailable) { 67 try { 68 awtLockAccess.wait(); 69 } catch (Throwable e) { 70 e.printStackTrace(); 71 } 72 } 73 } 74 75 return fNativeData; 76 } 77 78 // We need to take care of dragEnter and dragExit messages because 79 // native system generates them only for heavyweights 80 @Override processMotionMessage(SunDropTargetEvent event, boolean operationChanged)81 protected void processMotionMessage(SunDropTargetEvent event, boolean operationChanged) { 82 boolean eventInsideTarget = isEventInsideTarget(event); 83 if (event.getComponent().getDropTarget() == insideTarget) { 84 if (!eventInsideTarget) { 85 processExitMessage(event); 86 return; 87 } 88 } else { 89 if (eventInsideTarget) { 90 processEnterMessage(event); 91 } else { 92 return; 93 } 94 } 95 super.processMotionMessage(event, operationChanged); 96 } 97 98 /** 99 * Could be called when DnD enters a heavyweight or synthesized in processMotionMessage 100 */ 101 @Override processEnterMessage(SunDropTargetEvent event)102 protected void processEnterMessage(SunDropTargetEvent event) { 103 Component c = event.getComponent(); 104 DropTarget dt = event.getComponent().getDropTarget(); 105 if (isEventInsideTarget(event) 106 && dt != insideTarget 107 && c.isShowing() 108 && dt != null 109 && dt.isActive()) { 110 insideTarget = dt; 111 super.processEnterMessage(event); 112 } 113 } 114 115 /** 116 * Could be called when DnD exits a heavyweight or synthesized in processMotionMessage 117 */ 118 @Override processExitMessage(SunDropTargetEvent event)119 protected void processExitMessage(SunDropTargetEvent event) { 120 if (event.getComponent().getDropTarget() == insideTarget) { 121 insideTarget = null; 122 super.processExitMessage(event); 123 } 124 } 125 126 @Override processDropMessage(SunDropTargetEvent event)127 protected void processDropMessage(SunDropTargetEvent event) { 128 if (isEventInsideTarget(event)) { 129 super.processDropMessage(event); 130 insideTarget = null; 131 } 132 } 133 isEventInsideTarget(SunDropTargetEvent event)134 private boolean isEventInsideTarget(SunDropTargetEvent event) { 135 Component eventSource = event.getComponent(); 136 Point screenPoint = event.getPoint(); 137 SwingUtilities.convertPointToScreen(screenPoint, eventSource); 138 Point locationOnScreen = eventSource.getLocationOnScreen(); 139 Rectangle screenBounds = new Rectangle(locationOnScreen.x, 140 locationOnScreen.y, 141 eventSource.getWidth(), 142 eventSource.getHeight()); 143 return screenBounds.contains(screenPoint); 144 } 145 146 @Override postDropTargetEvent(Component component, int x, int y, int dropAction, int actions, long[] formats, long nativeCtxt, int eventID, boolean dispatchType)147 protected int postDropTargetEvent(Component component, int x, int y, int dropAction, 148 int actions, long[] formats, long nativeCtxt, int eventID, 149 boolean dispatchType) { 150 // On MacOS X all the DnD events should be synchronous 151 return super.postDropTargetEvent(component, x, y, dropAction, actions, formats, nativeCtxt, 152 eventID, SunDropTargetContextPeer.DISPATCH_SYNC); 153 } 154 155 // Signal drop complete: doDropDone(boolean success, int dropAction, boolean isLocal)156 protected void doDropDone(boolean success, int dropAction, boolean isLocal) { 157 long nativeDropTarget = this.getNativeDragContext(); 158 159 dropDone(nativeDropTarget, fNativeDropTransfer, isLocal, success, dropAction); 160 } 161 162 // Notify transfer complete - this is an upcall from getNativeData's native calls: newData(long format, byte[] data)163 private void newData(long format, byte[] data) { 164 fNativeDataAvailable = format; 165 fNativeData = data; 166 167 awtLockAccess.notifyAll(); 168 } 169 170 // Notify transfer failed - this is an upcall from getNativeData's native calls: transferFailed(long format)171 private void transferFailed(long format) { 172 fNativeDataAvailable = format; 173 fNativeData = null; 174 175 awtLockAccess.notifyAll(); 176 } 177 178 // Schedule a native dnd transfer: startTransfer(long nativeDropTarget, long format)179 private native long startTransfer(long nativeDropTarget, long format); 180 181 // Schedule a native dnd data transfer: addTransfer(long nativeDropTarget, long nativeDropTransfer, long format)182 private native void addTransfer(long nativeDropTarget, long nativeDropTransfer, long format); 183 184 // Notify drop completed: dropDone(long nativeDropTarget, long nativeDropTransfer, boolean isLocal, boolean success, int dropAction)185 private native void dropDone(long nativeDropTarget, long nativeDropTransfer, boolean isLocal, boolean success, int dropAction); 186 } 187