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