jdk/src/solaris/classes/sun/awt/X11/XDnDDragSourceProtocol.java
changeset 2 90ce3da70b43
child 439 3488710b02f8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDnDDragSourceProtocol.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.awt.X11;
+
+import java.awt.datatransfer.Transferable;
+
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.InvalidDnDOperationException;
+
+import java.util.Map;
+
+import java.util.logging.*;
+
+import sun.misc.Unsafe;
+
+/**
+ * XDragSourceProtocol implementation for XDnD protocol.
+ *
+ * @since 1.5
+ */
+class XDnDDragSourceProtocol extends XDragSourceProtocol {
+    private static final Logger logger =
+        Logger.getLogger("sun.awt.X11.xembed.xdnd.XDnDDragSourceProtocol");
+
+    private static final Unsafe unsafe = XlibWrapper.unsafe;
+
+    protected XDnDDragSourceProtocol(XDragSourceProtocolListener listener) {
+        super(listener);
+    }
+
+    /**
+     * Creates an instance associated with the specified listener.
+     *
+     * @throws NullPointerException if listener is <code>null</code>.
+     */
+    static XDragSourceProtocol createInstance(XDragSourceProtocolListener listener) {
+        return new XDnDDragSourceProtocol(listener);
+    }
+
+    public String getProtocolName() {
+        return XDragAndDropProtocols.XDnD;
+    }
+
+    /**
+     * Performs protocol-specific drag initialization.
+     *
+     * @returns true if the initialized successfully.
+     */
+    protected void initializeDragImpl(int actions, Transferable contents,
+                                         Map formatMap, long[] formats)
+      throws InvalidDnDOperationException,
+        IllegalArgumentException, XException {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+
+        long window = XDragSourceProtocol.getDragSourceWindow();
+
+        long data = Native.allocateLongArray(3);
+        int action_count = 0;
+        try {
+            if ((actions & DnDConstants.ACTION_COPY) != 0) {
+                Native.putLong(data, action_count,
+                               XDnDConstants.XA_XdndActionCopy.getAtom());
+                action_count++;
+            }
+            if ((actions & DnDConstants.ACTION_MOVE) != 0) {
+                Native.putLong(data, action_count,
+                               XDnDConstants.XA_XdndActionMove.getAtom());
+                action_count++;
+            }
+            if ((actions & DnDConstants.ACTION_LINK) != 0) {
+                Native.putLong(data, action_count,
+                               XDnDConstants.XA_XdndActionLink.getAtom());
+                action_count++;
+            }
+
+            XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
+            XDnDConstants.XA_XdndActionList.setAtomData(window,
+                                                        XAtom.XA_ATOM,
+                                                        data, action_count);
+            XToolkit.RESTORE_XERROR_HANDLER();
+
+            if (XToolkit.saved_error != null &&
+                XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
+                cleanup();
+                throw new XException("Cannot write XdndActionList property");
+            }
+        } finally {
+            unsafe.freeMemory(data);
+            data = 0;
+        }
+
+        data = Native.allocateLongArray(formats.length);
+
+        try {
+            Native.put(data, formats);
+
+            XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
+            XDnDConstants.XA_XdndTypeList.setAtomData(window,
+                                                      XAtom.XA_ATOM,
+                                                      data, formats.length);
+            XToolkit.RESTORE_XERROR_HANDLER();
+
+            if (XToolkit.saved_error != null &&
+                XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
+                cleanup();
+                throw new XException("Cannot write XdndActionList property");
+            }
+        } finally {
+            unsafe.freeMemory(data);
+            data = 0;
+        }
+
+        if (!XDnDConstants.XDnDSelection.setOwner(contents, formatMap, formats,
+                                                  XlibWrapper.CurrentTime)) {
+            cleanup();
+            throw new InvalidDnDOperationException("Cannot acquire selection ownership");
+        }
+    }
+
+    private boolean processXdndStatus(XClientMessageEvent xclient) {
+        int action = DnDConstants.ACTION_NONE;
+
+        /* Ignore XDnD messages from all other windows. */
+        if (xclient.get_data(0) != getTargetWindow()) {
+            return true;
+        }
+
+        if ((xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0) {
+            /* This feature is new in XDnD version 2, but we can use it as XDnD
+               compliance only requires supporting version 3 and up. */
+            action = XDnDConstants.getJavaActionForXDnDAction(xclient.get_data(4));
+        }
+
+        getProtocolListener().handleDragReply(action);
+
+        return true;
+    }
+
+    private boolean processXdndFinished(XClientMessageEvent xclient) {
+        /* Ignore XDnD messages from all other windows. */
+        if (xclient.get_data(0) != getTargetWindow()) {
+            return true;
+        }
+
+        if (getTargetProtocolVersion() >= 5) {
+            boolean success = (xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0;
+            int action = XDnDConstants.getJavaActionForXDnDAction(xclient.get_data(2));
+            getProtocolListener().handleDragFinished(success, action);
+        } else {
+            getProtocolListener().handleDragFinished();
+        }
+
+        finalizeDrop();
+
+        return true;
+    }
+
+    public boolean processClientMessage(XClientMessageEvent xclient) {
+        if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus.getAtom()) {
+            return processXdndStatus(xclient);
+        } else if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {
+            return processXdndFinished(xclient);
+        } else {
+            return false;
+        }
+    }
+
+    public TargetWindowInfo getTargetWindowInfo(long window) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+
+        WindowPropertyGetter wpg1 =
+            new WindowPropertyGetter(window, XDnDConstants.XA_XdndAware, 0, 1,
+                                     false, XlibWrapper.AnyPropertyType);
+
+        int status = wpg1.execute(XToolkit.IgnoreBadWindowHandler);
+
+        if (status == XlibWrapper.Success &&
+            wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {
+
+            int targetVersion = (int)Native.getLong(wpg1.getData());
+
+            wpg1.dispose();
+
+            if (targetVersion >= XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
+                long proxy = 0;
+                int protocolVersion =
+                    targetVersion < XDnDConstants.XDND_PROTOCOL_VERSION ?
+                    targetVersion : XDnDConstants.XDND_PROTOCOL_VERSION;
+
+                WindowPropertyGetter wpg2 =
+                    new WindowPropertyGetter(window, XDnDConstants.XA_XdndProxy,
+                                             0, 1, false, XAtom.XA_WINDOW);
+
+                try {
+                    status = wpg2.execute(XToolkit.IgnoreBadWindowHandler);
+
+                    if (status == XlibWrapper.Success &&
+                        wpg2.getData() != 0 &&
+                        wpg2.getActualType() == XAtom.XA_WINDOW) {
+
+                        proxy = Native.getLong(wpg2.getData());
+                    }
+                } finally {
+                    wpg2.dispose();
+                }
+
+                if (proxy != 0) {
+                    WindowPropertyGetter wpg3 =
+                        new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,
+                                                 0, 1, false, XAtom.XA_WINDOW);
+
+                    try {
+                        status = wpg3.execute(XToolkit.IgnoreBadWindowHandler);
+
+                        if (status != XlibWrapper.Success ||
+                            wpg3.getData() == 0 ||
+                            wpg3.getActualType() != XAtom.XA_WINDOW ||
+                            Native.getLong(wpg3.getData()) != proxy) {
+
+                            proxy = 0;
+                        } else {
+                            WindowPropertyGetter wpg4 =
+                                new WindowPropertyGetter(proxy,
+                                                         XDnDConstants.XA_XdndAware,
+                                                         0, 1, false,
+                                                         XlibWrapper.AnyPropertyType);
+
+                            try {
+                                status = wpg4.execute(XToolkit.IgnoreBadWindowHandler);
+
+                                if (status != XlibWrapper.Success ||
+                                    wpg4.getData() == 0 ||
+                                    wpg4.getActualType() != XAtom.XA_ATOM) {
+
+                                    proxy = 0;
+                                }
+                            } finally {
+                                wpg4.dispose();
+                            }
+                        }
+                    } finally {
+                        wpg3.dispose();
+                    }
+                }
+
+                return new TargetWindowInfo(proxy, protocolVersion);
+            }
+        } else {
+            wpg1.dispose();
+        }
+
+        return null;
+    }
+
+    public void sendEnterMessage(long[] formats,
+                                 int sourceAction, int sourceActions, long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+        assert formats != null;
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type((int)XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(32);
+            msg.set_message_type(XDnDConstants.XA_XdndEnter.getAtom());
+            msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
+            long data1 =
+                getTargetProtocolVersion() << XDnDConstants.XDND_PROTOCOL_SHIFT;
+            data1 |= formats.length > 3 ? XDnDConstants.XDND_DATA_TYPES_BIT : 0;
+            msg.set_data(1, data1);
+            msg.set_data(2, formats.length > 0 ? formats[0] : 0);
+            msg.set_data(3, formats.length > 1 ? formats[1] : 0);
+            msg.set_data(4, formats.length > 2 ? formats[2] : 0);
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    public void sendMoveMessage(int xRoot, int yRoot,
+                                int sourceAction, int sourceActions, long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type((int)XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(32);
+            msg.set_message_type(XDnDConstants.XA_XdndPosition.getAtom());
+            msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
+            msg.set_data(1, 0); /* flags */
+            msg.set_data(2, xRoot << 16 | yRoot);
+            msg.set_data(3, time);
+            msg.set_data(4, XDnDConstants.getXDnDActionForJavaAction(sourceAction));
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    public void sendLeaveMessage(long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type((int)XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(32);
+            msg.set_message_type(XDnDConstants.XA_XdndLeave.getAtom());
+            msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
+            msg.set_data(1, 0);
+            msg.set_data(2, 0);
+            msg.set_data(3, 0);
+            msg.set_data(4, 0);
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    public void sendDropMessage(int xRoot, int yRoot,
+                                int sourceAction, int sourceActions,
+                                long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type((int)XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(32);
+            msg.set_message_type(XDnDConstants.XA_XdndDrop.getAtom());
+            msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
+            msg.set_data(1, 0); /* flags */
+            msg.set_data(2, time);
+            msg.set_data(3, 0);
+            msg.set_data(4, 0);
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    public boolean processProxyModeEvent(XClientMessageEvent xclient,
+                                         long sourceWindow) {
+        if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus.getAtom() ||
+            xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {
+
+            if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {
+                XDragSourceContextPeer.setProxyModeSourceWindow(0);
+            }
+
+            // This can happen if the drag operation started in the XEmbed server.
+            // In this case there is no need to forward it elsewhere, we should
+            // process it here.
+            if (xclient.get_window() == sourceWindow) {
+                return false;
+            }
+
+            if (logger.isLoggable(Level.FINEST)) {
+                logger.finest("        sourceWindow=" + sourceWindow +
+                              " get_window=" + xclient.get_window() +
+                              " xclient=" + xclient);
+            }
+            xclient.set_data(0, xclient.get_window());
+            xclient.set_window(sourceWindow);
+
+            assert XToolkit.isAWTLockHeldByCurrentThread();
+
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(), sourceWindow,
+                                   false, XlibWrapper.NoEventMask,
+                                   xclient.pData);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    // TODO: register this runnable with XDnDSelection.
+    public void run() {
+        // XdndSelection ownership lost.
+        cleanup();
+    }
+}