/* * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.lwawt.macosx; import java.awt.*; import java.awt.dnd.DropTarget; import sun.awt.dnd.SunDropTargetContextPeer; import sun.awt.dnd.SunDropTargetEvent; import javax.swing.*; final class CDropTargetContextPeer extends SunDropTargetContextPeer { private long fNativeDropTransfer = 0; private long fNativeDataAvailable = 0; private Object fNativeData = null; private DropTarget insideTarget = null; Object awtLockAccess = new Object(); static CDropTargetContextPeer getDropTargetContextPeer() { return new CDropTargetContextPeer(); } private CDropTargetContextPeer() { super(); } // We block, waiting for an empty event to get posted (CToolkit.invokeAndWait) // This is so we finish dispatching DropTarget events before we dispatch the dragDropFinished event (which is a higher priority). private void flushEvents(Component c) { try { LWCToolkit.invokeAndWait(new Runnable() { public synchronized void run() { } }, c); } catch(Exception e) { e.printStackTrace(); } } protected Object getNativeData(long format) { long nativeDropTarget = this.getNativeDragContext(); synchronized (awtLockAccess) { fNativeDataAvailable = 0; if (fNativeDropTransfer == 0) { fNativeDropTransfer = startTransfer(nativeDropTarget, format); } else { addTransfer(nativeDropTarget, fNativeDropTransfer, format); } while (format != fNativeDataAvailable) { try { awtLockAccess.wait(); } catch (Throwable e) { e.printStackTrace(); } } } return fNativeData; } // We need to take care of dragEnter and dragExit messages because // native system generates them only for heavyweights @Override protected void processMotionMessage(SunDropTargetEvent event, boolean operationChanged) { boolean eventInsideTarget = isEventInsideTarget(event); if (event.getComponent().getDropTarget() == insideTarget) { if (!eventInsideTarget) { processExitMessage(event); return; } } else { if (eventInsideTarget) { processEnterMessage(event); } else { return; } } super.processMotionMessage(event, operationChanged); } /** * Could be called when DnD enters a heavyweight or synthesized in processMotionMessage */ @Override protected void processEnterMessage(SunDropTargetEvent event) { Component c = event.getComponent(); DropTarget dt = event.getComponent().getDropTarget(); if (isEventInsideTarget(event) && dt != insideTarget && c.isShowing() && dt != null && dt.isActive()) { insideTarget = dt; super.processEnterMessage(event); } } /** * Could be called when DnD exits a heavyweight or synthesized in processMotionMessage */ @Override protected void processExitMessage(SunDropTargetEvent event) { if (event.getComponent().getDropTarget() == insideTarget) { insideTarget = null; super.processExitMessage(event); } } @Override protected void processDropMessage(SunDropTargetEvent event) { if (isEventInsideTarget(event)) { super.processDropMessage(event); insideTarget = null; } } private boolean isEventInsideTarget(SunDropTargetEvent event) { Component eventSource = event.getComponent(); Point screenPoint = event.getPoint(); SwingUtilities.convertPointToScreen(screenPoint, eventSource); Point locationOnScreen = eventSource.getLocationOnScreen(); Rectangle screenBounds = new Rectangle(locationOnScreen.x, locationOnScreen.y, eventSource.getWidth(), eventSource.getHeight()); return screenBounds.contains(screenPoint); } @Override protected int postDropTargetEvent(Component component, int x, int y, int dropAction, int actions, long[] formats, long nativeCtxt, int eventID, boolean dispatchType) { // On MacOS X all the DnD events should be synchronous return super.postDropTargetEvent(component, x, y, dropAction, actions, formats, nativeCtxt, eventID, SunDropTargetContextPeer.DISPATCH_SYNC); } @Override protected void handleDropMessage(Component component, int x, int y, int dropAction, int actions, long[] formats, long nativeCtxt) { super.handleDropMessage(component, x, y, dropAction, actions, formats, nativeCtxt); flushEvents(component); } // Signal drop complete: protected void doDropDone(boolean success, int dropAction, boolean isLocal) { long nativeDropTarget = this.getNativeDragContext(); dropDone(nativeDropTarget, fNativeDropTransfer, isLocal, success, dropAction); } // Notify transfer complete - this is an upcall from getNativeData's native calls: private void newData(long format, byte[] data) { fNativeDataAvailable = format; fNativeData = data; awtLockAccess.notifyAll(); } // Notify transfer failed - this is an upcall from getNativeData's native calls: private void transferFailed(long format) { fNativeDataAvailable = format; fNativeData = null; awtLockAccess.notifyAll(); } // Schedule a native dnd transfer: private native long startTransfer(long nativeDropTarget, long format); // Schedule a native dnd data transfer: private native void addTransfer(long nativeDropTarget, long nativeDropTransfer, long format); // Notify drop completed: private native void dropDone(long nativeDropTarget, long nativeDropTransfer, boolean isLocal, boolean success, int dropAction); }