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