jdk/src/solaris/classes/sun/awt/X11/MotifDnDDragSourceProtocol.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/MotifDnDDragSourceProtocol.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2003-2007 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 sun.misc.Unsafe;
+
+/**
+ * XDragSourceProtocol implementation for Motif DnD protocol.
+ *
+ * @since 1.5
+ */
+class MotifDnDDragSourceProtocol extends XDragSourceProtocol
+    implements XEventDispatcher {
+
+    private static final Unsafe unsafe = XlibWrapper.unsafe;
+
+    private long targetEnterServerTime = XlibWrapper.CurrentTime;
+
+    protected MotifDnDDragSourceProtocol(XDragSourceProtocolListener listener) {
+        super(listener);
+        XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
+    }
+
+    /**
+     * Creates an instance associated with the specified listener.
+     *
+     * @throws NullPointerException if listener is <code>null</code>.
+     */
+    static XDragSourceProtocol createInstance(XDragSourceProtocolListener listener) {
+        return new MotifDnDDragSourceProtocol(listener);
+    }
+
+    public String getProtocolName() {
+        return XDragAndDropProtocols.MotifDnD;
+    }
+
+    protected void initializeDragImpl(int actions, Transferable contents,
+                                      Map formatMap, long[] formats)
+      throws InvalidDnDOperationException,
+        IllegalArgumentException, XException {
+
+        long window = XDragSourceProtocol.getDragSourceWindow();
+
+        /* Write the Motif DnD initiator info on the root XWindow. */
+        try {
+            int index = MotifDnDConstants.getIndexForTargetList(formats);
+
+            MotifDnDConstants.writeDragInitiatorInfoStruct(window, index);
+        } catch (XException xe) {
+            cleanup();
+            throw xe;
+        } catch (InvalidDnDOperationException idoe) {
+            cleanup();
+            throw idoe;
+        }
+
+        if (!MotifDnDConstants.MotifDnDSelection.setOwner(contents, formatMap,
+                                                          formats,
+                                                          XlibWrapper.CurrentTime)) {
+            cleanup();
+            throw new InvalidDnDOperationException("Cannot acquire selection ownership");
+        }
+    }
+
+    /**
+     * Processes the specified client message event.
+     *
+     * @returns true if the event was successfully processed.
+     */
+    public boolean processClientMessage(XClientMessageEvent xclient) {
+        if (xclient.get_message_type() !=
+            MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
+            return false;
+        }
+
+        long data = xclient.get_data();
+        byte reason = (byte)(unsafe.getByte(data) &
+            MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
+        byte origin = (byte)(unsafe.getByte(data) &
+            MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
+        byte byteOrder = unsafe.getByte(data + 1);
+        boolean swapNeeded = byteOrder != MotifDnDConstants.getByteOrderByte();
+        int action = DnDConstants.ACTION_NONE;
+        int x = 0;
+        int y = 0;
+
+        /* Only receiver messages should be handled. */
+        if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER) {
+            return false;
+        }
+
+        switch (reason) {
+        case MotifDnDConstants.DROP_SITE_ENTER:
+        case MotifDnDConstants.DROP_SITE_LEAVE:
+        case MotifDnDConstants.DRAG_MOTION:
+        case MotifDnDConstants.OPERATION_CHANGED:
+            break;
+        default:
+            // Unknown reason.
+            return false;
+        }
+
+        int t = unsafe.getInt(data + 4);
+        if (swapNeeded) {
+            t = MotifDnDConstants.Swapper.swap(t);
+        }
+        long time = t;
+
+        /* Discard events from the previous receiver. */
+        if (targetEnterServerTime == XlibWrapper.CurrentTime ||
+            time < targetEnterServerTime) {
+            return true;
+        }
+
+        if (reason != MotifDnDConstants.DROP_SITE_LEAVE) {
+            short flags = unsafe.getShort(data + 2);
+            if (swapNeeded) {
+                flags = MotifDnDConstants.Swapper.swap(flags);
+            }
+
+            byte status = (byte)((flags & MotifDnDConstants.MOTIF_DND_STATUS_MASK) >>
+                MotifDnDConstants.MOTIF_DND_STATUS_SHIFT);
+            byte motif_action = (byte)((flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
+                MotifDnDConstants.MOTIF_DND_ACTION_SHIFT);
+
+            if (status == MotifDnDConstants.MOTIF_VALID_DROP_SITE) {
+                action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
+            } else {
+                action = DnDConstants.ACTION_NONE;
+            }
+
+            short tx = unsafe.getShort(data + 8);
+            short ty = unsafe.getShort(data + 10);
+            if (swapNeeded) {
+                tx = MotifDnDConstants.Swapper.swap(tx);
+                ty = MotifDnDConstants.Swapper.swap(ty);
+            }
+            x = tx;
+            y = ty;
+        }
+
+        getProtocolListener().handleDragReply(action, x, y);
+
+        return true;
+    }
+
+    public TargetWindowInfo getTargetWindowInfo(long window) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+
+        WindowPropertyGetter wpg =
+            new WindowPropertyGetter(window,
+                                     MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
+                                     0, 0xFFFF, false,
+                                     XlibWrapper.AnyPropertyType);
+
+        try {
+            int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
+
+            /*
+             * DragICCI.h:
+             *
+             * typedef struct _xmDragReceiverInfoStruct{
+             *     BYTE byte_order;
+             *     BYTE protocol_version;
+             *     BYTE drag_protocol_style;
+             *     BYTE pad1;
+             *     CARD32       proxy_window B32;
+             *     CARD16       num_drop_sites B16;
+             *     CARD16       pad2 B16;
+             *     CARD32       heap_offset B32;
+             * } xmDragReceiverInfoStruct;
+             */
+            if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
+                wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
+                wpg.getNumberOfItems() >=
+                MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
+
+                long data = wpg.getData();
+                byte byteOrderByte = unsafe.getByte(data);
+                byte dragProtocolStyle = unsafe.getByte(data + 2);
+                switch (dragProtocolStyle) {
+                case MotifDnDConstants.MOTIF_PREFER_PREREGISTER_STYLE :
+                case MotifDnDConstants.MOTIF_PREFER_DYNAMIC_STYLE :
+                case MotifDnDConstants.MOTIF_DYNAMIC_STYLE :
+                case MotifDnDConstants.MOTIF_PREFER_RECEIVER_STYLE :
+                    int proxy = unsafe.getInt(data + 4);
+                    if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
+                        proxy = MotifDnDConstants.Swapper.swap(proxy);
+                    }
+
+                    int protocolVersion = unsafe.getByte(data + 1);
+
+                    return new TargetWindowInfo(proxy, protocolVersion);
+                default:
+                    // Unsupported protocol style.
+                    return null;
+                }
+            } else {
+                return null;
+            }
+        } finally {
+            wpg.dispose();
+        }
+    }
+
+    public void sendEnterMessage(long[] formats,
+                                 int sourceAction, int sourceActions, long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+        assert formats != null;
+
+        targetEnterServerTime = time;
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type(XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(8);
+            msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
+
+            long data = msg.get_data();
+            int flags =
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
+                 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
+                 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
+
+            unsafe.putByte(data,
+                           (byte)(MotifDnDConstants.TOP_LEVEL_ENTER |
+                                  MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
+            unsafe.putByte(data + 1,
+                           MotifDnDConstants.getByteOrderByte());
+            unsafe.putShort(data + 2, (short)flags);
+            unsafe.putInt(data + 4, (int)time);
+            unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());
+            unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
+
+            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(XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(8);
+            msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
+
+            long data = msg.get_data();
+            int flags =
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
+                 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
+                 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
+
+            unsafe.putByte(data,
+                           (byte)(MotifDnDConstants.DRAG_MOTION |
+                                  MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
+            unsafe.putByte(data + 1,
+                           MotifDnDConstants.getByteOrderByte());
+            unsafe.putShort(data + 2, (short)flags);
+            unsafe.putInt(data + 4, (int)time);
+            unsafe.putShort(data + 8, (short)xRoot);
+            unsafe.putShort(data + 10, (short)yRoot);
+
+            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(XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(8);
+            msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
+
+            long data = msg.get_data();
+
+            unsafe.putByte(data,
+                           (byte)(MotifDnDConstants.TOP_LEVEL_LEAVE |
+                                  MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
+            unsafe.putByte(data + 1,
+                           MotifDnDConstants.getByteOrderByte());
+            unsafe.putShort(data + 2, (short)0);
+            unsafe.putInt(data + 4, (int)time);
+            unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());
+
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    protected void sendDropMessage(int xRoot, int yRoot,
+                                   int sourceAction, int sourceActions,
+                                   long time) {
+        assert XToolkit.isAWTLockHeldByCurrentThread();
+        assert getTargetWindow() != 0;
+
+        /*
+         * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START.
+         */
+        sendLeaveMessage(time);
+
+        XClientMessageEvent msg = new XClientMessageEvent();
+        try {
+            msg.set_type(XlibWrapper.ClientMessage);
+            msg.set_window(getTargetWindow());
+            msg.set_format(8);
+            msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
+
+            long data = msg.get_data();
+            int flags =
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
+                 MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
+                (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
+                 MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
+
+            unsafe.putByte(data,
+                           (byte)(MotifDnDConstants.DROP_START |
+                                  MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
+            unsafe.putByte(data + 1,
+                           MotifDnDConstants.getByteOrderByte());
+            unsafe.putShort(data + 2, (short)flags);
+            unsafe.putInt(data + 4, (int)time);
+            unsafe.putShort(data + 8, (short)xRoot);
+            unsafe.putShort(data + 10, (short)yRoot);
+            unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
+            unsafe.putInt(data + 16, (int)XDragSourceProtocol.getDragSourceWindow());
+
+            XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+                                   getTargetProxyWindow(),
+                                   false, XlibWrapper.NoEventMask,
+                                   msg.pData);
+        } finally {
+            msg.dispose();
+        }
+    }
+
+    public boolean processProxyModeEvent(XClientMessageEvent xclient,
+                                         long sourceWindow) {
+        // Motif DnD for XEmbed is not implemented.
+        return false;
+    }
+
+    public void cleanupTargetInfo() {
+        super.cleanupTargetInfo();
+        targetEnterServerTime = XlibWrapper.CurrentTime;
+    }
+
+    public void dispatchEvent(XEvent ev) {
+        switch (ev.get_type()) {
+        case XlibWrapper.SelectionRequest:
+            XSelectionRequestEvent xsre = ev.get_xselectionrequest();
+            long atom = xsre.get_selection();
+
+            if (atom == MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom()) {
+                long target = xsre.get_target();
+                if (target == MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom()) {
+                    getProtocolListener().handleDragFinished(true);
+                } else if (target == MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom()) {
+                    getProtocolListener().handleDragFinished(false);
+                }
+            }
+            break;
+        }
+    }
+}