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 46 static CDropTargetContextPeer getDropTargetContextPeer() { 47 return new CDropTargetContextPeer(); 48 } 49 50 private CDropTargetContextPeer() { 51 super(); 52 } 53 54 // We block, waiting for an empty event to get posted (CToolkit.invokeAndWait) 55 // This is so we finish dispatching DropTarget events before we dispatch the dragDropFinished event (which is a higher priority). 56 private void flushEvents(Component c) { 57 try { 58 LWCToolkit.invokeAndWait(new Runnable() { 59 public synchronized void run() { 60 } 61 }, c); 62 } 63 catch(Exception e) { 64 e.printStackTrace(); 65 } 66 } 67 68 protected Object getNativeData(long format) { 69 long nativeDropTarget = this.getNativeDragContext(); 70 71 synchronized (awtLockAccess) { 72 fNativeDataAvailable = 0; 73 74 if (fNativeDropTransfer == 0) { 75 fNativeDropTransfer = startTransfer(nativeDropTarget, format); 76 } else { 77 addTransfer(nativeDropTarget, fNativeDropTransfer, format); 78 } 79 80 while (format != fNativeDataAvailable) { 81 try { 82 awtLockAccess.wait(); 83 } catch (Throwable e) { 84 e.printStackTrace(); 85 } 86 } 87 } 88 89 return fNativeData; 90 } 91 92 // We need to take care of dragEnter and dragExit messages because 93 // native system generates them only for heavyweights 94 @Override 95 protected void processMotionMessage(SunDropTargetEvent event, boolean operationChanged) { 96 boolean eventInsideTarget = isEventInsideTarget(event); 97 if (event.getComponent().getDropTarget() == insideTarget) { 98 if (!eventInsideTarget) { 99 processExitMessage(event); 100 return; 101 } 102 } else { 103 if (eventInsideTarget) { 104 processEnterMessage(event); 105 } else { 106 return; 107 } 108 } 109 super.processMotionMessage(event, operationChanged); 110 } 111 112 /** 113 * Could be called when DnD enters a heavyweight or synthesized in processMotionMessage 114 */ 115 @Override 116 protected void processEnterMessage(SunDropTargetEvent event) { 117 Component c = event.getComponent(); 118 DropTarget dt = event.getComponent().getDropTarget(); 119 if (isEventInsideTarget(event) 120 && dt != insideTarget 121 && c.isShowing() 122 && dt != null 123 && dt.isActive()) { 124 insideTarget = dt; 125 super.processEnterMessage(event); 126 } 127 } 128 129 /** 130 * Could be called when DnD exits a heavyweight or synthesized in processMotionMessage 131 */ 132 @Override 133 protected void processExitMessage(SunDropTargetEvent event) { 134 if (event.getComponent().getDropTarget() == insideTarget) { 135 insideTarget = null; 136 super.processExitMessage(event); 137 } 138 } 139 140 @Override 141 protected void processDropMessage(SunDropTargetEvent event) { 142 if (isEventInsideTarget(event)) { 143 super.processDropMessage(event); 144 insideTarget = null; 145 } 146 } 147 148 private boolean isEventInsideTarget(SunDropTargetEvent event) { 149 Component eventSource = event.getComponent(); 150 Point screenPoint = event.getPoint(); 151 SwingUtilities.convertPointToScreen(screenPoint, eventSource); 152 Point locationOnScreen = eventSource.getLocationOnScreen(); 153 Rectangle screenBounds = new Rectangle(locationOnScreen.x, 154 locationOnScreen.y, 155 eventSource.getWidth(), 156 eventSource.getHeight()); 157 return screenBounds.contains(screenPoint); 158 } 159 160 @Override 161 protected int postDropTargetEvent(Component component, int x, int y, int dropAction, 162 int actions, long[] formats, long nativeCtxt, int eventID, 163 boolean dispatchType) { 164 // On MacOS X all the DnD events should be synchronous 165 return super.postDropTargetEvent(component, x, y, dropAction, actions, formats, nativeCtxt, 166 eventID, SunDropTargetContextPeer.DISPATCH_SYNC); 167 } 168 169 @Override 170 protected void handleDropMessage(Component component, int x, int y, 171 int dropAction, int actions, long[] formats, 172 long nativeCtxt) { 173 super.handleDropMessage(component, x, y, dropAction, actions, formats, nativeCtxt); 174 flushEvents(component); 175 } 176 177 // Signal drop complete: 178 protected void doDropDone(boolean success, int dropAction, boolean isLocal) { 179 long nativeDropTarget = this.getNativeDragContext(); 180 181 dropDone(nativeDropTarget, fNativeDropTransfer, isLocal, success, dropAction); 182 } 183 184 // Notify transfer complete - this is an upcall from getNativeData's native calls: 185 private void newData(long format, byte[] data) { 186 fNativeDataAvailable = format; 187 fNativeData = data; 188 189 awtLockAccess.notifyAll(); 190 } 191 192 // Notify transfer failed - this is an upcall from getNativeData's native calls: 193 private void transferFailed(long format) { 194 fNativeDataAvailable = format; 195 fNativeData = null; 196 197 awtLockAccess.notifyAll(); 198 } 199 200 // Schedule a native dnd transfer: 201 private native long startTransfer(long nativeDropTarget, long format); 202 203 // Schedule a native dnd data transfer: 204 private native void addTransfer(long nativeDropTarget, long nativeDropTransfer, long format); 205 206 // Notify drop completed: 207 private native void dropDone(long nativeDropTarget, long nativeDropTransfer, boolean isLocal, boolean success, int dropAction); 208 }