/*
 * 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
/** * 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
/** * 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); } // 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); }