--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1073 @@
+/*
+ * 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.Point;
+
+import java.awt.dnd.DnDConstants;
+
+import java.awt.event.MouseEvent;
+
+import java.io.IOException;
+
+import sun.misc.Unsafe;
+
+/**
+ * XDropTargetProtocol implementation for Motif DnD protocol.
+ *
+ * @since 1.5
+ */
+class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
+ private static final Unsafe unsafe = XlibWrapper.unsafe;
+
+ private long sourceWindow = 0;
+ private long sourceWindowMask = 0;
+ private int sourceProtocolVersion = 0;
+ private int sourceActions = DnDConstants.ACTION_NONE;
+ private long[] sourceFormats = null;
+ private long sourceAtom = 0;
+ private int userAction = DnDConstants.ACTION_NONE;
+ private int sourceX = 0;
+ private int sourceY = 0;
+ private XWindow targetXWindow = null;
+ private boolean topLevelLeavePostponed = false;
+
+ protected MotifDnDDropTargetProtocol(XDropTargetProtocolListener listener) {
+ super(listener);
+ }
+
+ /**
+ * Creates an instance associated with the specified listener.
+ *
+ * @throws NullPointerException if listener is <code>null</code>.
+ */
+ static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) {
+ return new MotifDnDDropTargetProtocol(listener);
+ }
+
+ public String getProtocolName() {
+ return XDragAndDropProtocols.MotifDnD;
+ }
+
+ public void registerDropTarget(long window) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ MotifDnDConstants.writeDragReceiverInfoStruct(window);
+ }
+
+ public void unregisterDropTarget(long window) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ MotifDnDConstants.XA_MOTIF_ATOM_0.DeleteProperty(window);
+ }
+
+ public void registerEmbedderDropSite(long embedder) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ boolean overriden = false;
+ int version = 0;
+ long proxy = 0;
+ long newProxy = XDropTargetRegistry.getDnDProxyWindow();
+ int status = 0;
+ long data = 0;
+ int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
+
+ WindowPropertyGetter wpg =
+ new WindowPropertyGetter(embedder,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
+ 0, 0xFFFF, false,
+ XlibWrapper.AnyPropertyType);
+
+ try {
+ 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) {
+
+ overriden = true;
+ data = wpg.getData();
+ dataSize = wpg.getNumberOfItems();
+
+ byte byteOrderByte = unsafe.getByte(data);
+
+ {
+ int tproxy = unsafe.getInt(data + 4);
+ if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
+ tproxy = MotifDnDConstants.Swapper.swap(tproxy);
+ }
+ proxy = tproxy;
+ }
+
+ if (proxy == newProxy) {
+ // Embedder already registered.
+ return;
+ }
+
+ {
+ int tproxy = (int)newProxy;
+ if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
+ tproxy = MotifDnDConstants.Swapper.swap(tproxy);
+ }
+ unsafe.putInt(data + 4, tproxy);
+ }
+ } else {
+ data = unsafe.allocateMemory(dataSize);
+
+ unsafe.putByte(data, MotifDnDConstants.getByteOrderByte()); /* byte order */
+ unsafe.putByte(data + 1, MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
+ unsafe.putByte(data + 2, (byte)MotifDnDConstants.MOTIF_DYNAMIC_STYLE); /* protocol style */
+ unsafe.putByte(data + 3, (byte)0); /* pad */
+ unsafe.putInt(data + 4, (int)newProxy); /* proxy window */
+ unsafe.putShort(data + 8, (short)0); /* num_drop_sites */
+ unsafe.putShort(data + 10, (short)0); /* pad */
+ unsafe.putInt(data + 12, dataSize);
+ }
+
+ XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
+ XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
+ 8, XlibWrapper.PropModeReplace,
+ data, dataSize);
+ XToolkit.RESTORE_XERROR_HANDLER();
+
+ if (XToolkit.saved_error != null &&
+ XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
+ throw new XException("Cannot write Motif receiver info property");
+ }
+ } finally {
+ if (!overriden) {
+ unsafe.freeMemory(data);
+ data = 0;
+ }
+ wpg.dispose();
+ }
+
+ putEmbedderRegistryEntry(embedder, overriden, version, proxy);
+ }
+
+ public void unregisterEmbedderDropSite(long embedder) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);
+
+ if (entry == null) {
+ return;
+ }
+
+ if (entry.isOverriden()) {
+ int status = 0;
+
+ WindowPropertyGetter wpg =
+ new WindowPropertyGetter(embedder,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
+ 0, 0xFFFF, false,
+ XlibWrapper.AnyPropertyType);
+
+ try {
+ 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) {
+
+ int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
+ long data = wpg.getData();
+ byte byteOrderByte = unsafe.getByte(data);
+
+ int tproxy = (int)entry.getProxy();
+ if (MotifDnDConstants.getByteOrderByte() != byteOrderByte) {
+ tproxy = MotifDnDConstants.Swapper.swap(tproxy);
+ }
+
+ unsafe.putInt(data + 4, tproxy);
+
+ XToolkit.WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
+ XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
+ 8, XlibWrapper.PropModeReplace,
+ data, dataSize);
+ XToolkit.RESTORE_XERROR_HANDLER();
+
+ if (XToolkit.saved_error != null &&
+ XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
+ throw new XException("Cannot write Motif receiver info property");
+ }
+ }
+ } finally {
+ wpg.dispose();
+ }
+ } else {
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.DeleteProperty(embedder);
+ }
+ }
+
+ /*
+ * Gets and stores in the registry the embedder's Motif DnD drop site info
+ * from the embedded.
+ */
+ public void registerEmbeddedDropSite(long embedded) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ boolean overriden = false;
+ int version = 0;
+ long proxy = 0;
+ int status = 0;
+
+ WindowPropertyGetter wpg =
+ new WindowPropertyGetter(embedded,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
+ 0, 0xFFFF, false,
+ XlibWrapper.AnyPropertyType);
+
+ try {
+ 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) {
+
+ overriden = true;
+ long data = wpg.getData();
+
+ byte byteOrderByte = unsafe.getByte(data);
+
+ {
+ int tproxy = unsafe.getInt(data + 4);
+ if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
+ tproxy = MotifDnDConstants.Swapper.swap(tproxy);
+ }
+ proxy = tproxy;
+ }
+ }
+ } finally {
+ wpg.dispose();
+ }
+
+ putEmbedderRegistryEntry(embedded, overriden, version, proxy);
+ }
+
+ public boolean isProtocolSupported(long window) {
+ WindowPropertyGetter wpg =
+ new WindowPropertyGetter(window,
+ MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
+ 0, 0xFFFF, false,
+ XlibWrapper.AnyPropertyType);
+
+ try {
+ int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
+
+ if (status == (int)XlibWrapper.Success && wpg.getData() != 0 &&
+ wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
+ wpg.getNumberOfItems() >=
+ MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ wpg.dispose();
+ }
+ }
+
+ private boolean processTopLevelEnter(XClientMessageEvent xclient) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ if (targetXWindow != null || sourceWindow != 0) {
+ return false;
+ }
+
+ if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)
+ && getEmbedderRegistryEntry(xclient.get_window()) == null) {
+ return false;
+ }
+
+ long source_win = 0;
+ long source_win_mask = 0;
+ int protocol_version = 0;
+ long property_atom = 0;
+ long[] formats = null;
+
+ {
+ long data = xclient.get_data();
+ byte eventByteOrder = unsafe.getByte(data + 1);
+ source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder);
+ property_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
+ }
+
+ /* Extract the available data types. */
+ {
+ WindowPropertyGetter wpg =
+ new WindowPropertyGetter(source_win,
+ XAtom.get(property_atom),
+ 0, 0xFFFF,
+ false,
+ MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom());
+
+ try {
+ int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
+
+ if (status == XlibWrapper.Success && wpg.getData() != 0 &&
+ wpg.getActualType() ==
+ MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO.getAtom() &&
+ wpg.getActualFormat() == 8 &&
+ wpg.getNumberOfItems() ==
+ MotifDnDConstants.MOTIF_INITIATOR_INFO_SIZE) {
+
+ long data = wpg.getData();
+ byte propertyByteOrder = unsafe.getByte(data);
+
+ protocol_version = unsafe.getByte(data + 1);
+
+ if (protocol_version !=
+ MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION) {
+ return false;
+ }
+
+ int index =
+ MotifDnDConstants.Swapper.getShort(data + 2, propertyByteOrder);
+
+ formats = MotifDnDConstants.getTargetListForIndex(index);
+ } else {
+ formats = new long[0];
+ }
+ } finally {
+ wpg.dispose();
+ }
+ }
+
+ /*
+ * Select for StructureNotifyMask to receive DestroyNotify in case of source
+ * crash.
+ */
+ XWindowAttributes wattr = new XWindowAttributes();
+ try {
+ XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
+ int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
+ source_win, wattr.pData);
+
+ XToolkit.RESTORE_XERROR_HANDLER();
+
+ if (status == 0 ||
+ (XToolkit.saved_error != null &&
+ XToolkit.saved_error.get_error_code() != XlibWrapper.Success)) {
+ throw new XException("XGetWindowAttributes failed");
+ }
+
+ source_win_mask = wattr.get_your_event_mask();
+ } finally {
+ wattr.dispose();
+ }
+
+ XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
+ XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
+ source_win_mask |
+ XlibWrapper.StructureNotifyMask);
+
+ XToolkit.RESTORE_XERROR_HANDLER();
+
+ if (XToolkit.saved_error != null &&
+ XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
+ throw new XException("XSelectInput failed");
+ }
+
+ sourceWindow = source_win;
+ sourceWindowMask = source_win_mask;
+ sourceProtocolVersion = protocol_version;
+ /*
+ * TOP_LEVEL_ENTER doesn't communicate the list of supported actions
+ * They are provided in DRAG_MOTION.
+ */
+ sourceActions = DnDConstants.ACTION_NONE;
+ sourceFormats = formats;
+ sourceAtom = property_atom;
+
+ return true;
+ }
+
+ private boolean processDragMotion(XClientMessageEvent xclient) {
+ long data = xclient.get_data();
+ byte eventByteOrder = unsafe.getByte(data + 1);
+ byte eventReason = (byte)(unsafe.getByte(data) &
+ MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
+ int x = 0;
+ int y = 0;
+
+ short flags = MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder);
+
+ int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
+ MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
+ int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >>
+ MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
+
+ int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
+ int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions);
+
+ /* Append source window id to the event data, so that we can send the
+ response properly. */
+ {
+ int win = (int)sourceWindow;
+ if (eventByteOrder != MotifDnDConstants.getByteOrderByte()) {
+ win = MotifDnDConstants.Swapper.swap(win);
+ }
+ unsafe.putInt(data + 12, win);
+ }
+
+ XWindow xwindow = null;
+ {
+ XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());
+ if (xbasewindow instanceof XWindow) {
+ xwindow = (XWindow)xbasewindow;
+ }
+ }
+
+ if (eventReason == MotifDnDConstants.OPERATION_CHANGED) {
+ /* OPERATION_CHANGED event doesn't provide coordinates, so we use
+ previously stored position and component ref. */
+ x = sourceX;
+ y = sourceY;
+
+ if (xwindow == null) {
+ xwindow = targetXWindow;
+ }
+ } else {
+ x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder);
+ y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder);
+
+ if (xwindow == null) {
+ long receiver =
+ XDropTargetRegistry.getRegistry().getEmbeddedDropSite(
+ xclient.get_window(), x, y);
+
+ if (receiver != 0) {
+ XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);
+ if (xbasewindow instanceof XWindow) {
+ xwindow = (XWindow)xbasewindow;
+ }
+ }
+ }
+
+ if (xwindow != null) {
+ Point p = xwindow.toLocal(x, y);
+ x = p.x;
+ y = p.y;
+ }
+ }
+
+ if (xwindow == null) {
+ if (targetXWindow != null) {
+ notifyProtocolListener(targetXWindow, x, y,
+ DnDConstants.ACTION_NONE, java_actions,
+ xclient, MouseEvent.MOUSE_EXITED);
+ }
+ } else {
+ int java_event_id = 0;
+
+ if (targetXWindow == null) {
+ java_event_id = MouseEvent.MOUSE_ENTERED;
+ } else {
+ java_event_id = MouseEvent.MOUSE_DRAGGED;
+ }
+
+ notifyProtocolListener(xwindow, x, y, java_action, java_actions,
+ xclient, java_event_id);
+ }
+
+ sourceActions = java_actions;
+ userAction = java_action;
+ sourceX = x;
+ sourceY = y;
+ targetXWindow = xwindow;
+
+ return true;
+ }
+
+ private boolean processTopLevelLeave(XClientMessageEvent xclient) {
+ assert XToolkit.isAWTLockHeldByCurrentThread();
+
+ long data = xclient.get_data();
+ byte eventByteOrder = unsafe.getByte(data + 1);
+
+ long source_win = MotifDnDConstants.Swapper.getInt(data + 8, eventByteOrder);
+
+ /* Ignore Motif DnD messages from all other windows. */
+ if (source_win != sourceWindow) {
+ return false;
+ }
+
+ /*
+ * Postpone upcall to java, so that we can abort it in case
+ * if drop immediatelly follows (see BugTraq ID 4395290).
+ * Send a dummy ClientMessage event to guarantee that a postponed java
+ * upcall will be processed.
+ */
+ topLevelLeavePostponed = true;
+ {
+ long proxy;
+
+ /*
+ * If this is an embedded drop site, the event should go to the
+ * awt_root_window as this is a proxy for all embedded drop sites.
+ * Otherwise the event should go to the event->window, as we don't use
+ * proxies for normal drop sites.
+ */
+ if (getEmbedderRegistryEntry(xclient.get_window()) != null) {
+ proxy = XDropTargetRegistry.getDnDProxyWindow();
+ } else {
+ proxy = xclient.get_window();
+ }
+
+ XClientMessageEvent dummy = new XClientMessageEvent();
+
+ try {
+ dummy.set_type(XlibWrapper.ClientMessage);
+ dummy.set_window(xclient.get_window());
+ dummy.set_format(32);
+ dummy.set_message_type(0);
+ dummy.set_data(0, 0);
+ dummy.set_data(1, 0);
+ dummy.set_data(2, 0);
+ dummy.set_data(3, 0);
+ dummy.set_data(4, 0);
+ XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+ proxy, false, XlibWrapper.NoEventMask,
+ dummy.pData);
+ } finally {
+ dummy.dispose();
+ }
+ }
+ return true;
+ }
+
+ private boolean processDropStart(XClientMessageEvent xclient) {
+ long data = xclient.get_data();
+ byte eventByteOrder = unsafe.getByte(data + 1);
+
+ long source_win =
+ MotifDnDConstants.Swapper.getInt(data + 16, eventByteOrder);
+
+ /* Ignore Motif DnD messages from all other windows. */
+ if (source_win != sourceWindow) {
+ return false;
+ }
+
+ long property_atom =
+ MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
+
+ short flags =
+ MotifDnDConstants.Swapper.getShort(data + 2, eventByteOrder);
+
+ int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
+ MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
+ int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >>
+ MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
+
+ int java_action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
+ int java_actions = MotifDnDConstants.getJavaActionsForMotifActions(motif_actions);
+
+ int x = MotifDnDConstants.Swapper.getShort(data + 8, eventByteOrder);
+ int y = MotifDnDConstants.Swapper.getShort(data + 10, eventByteOrder);
+
+ XWindow xwindow = null;
+ {
+ XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());
+ if (xbasewindow instanceof XWindow) {
+ xwindow = (XWindow)xbasewindow;
+ }
+ }
+
+ if (xwindow == null) {
+ long receiver =
+ XDropTargetRegistry.getRegistry().getEmbeddedDropSite(
+ xclient.get_window(), x, y);
+
+ if (receiver != 0) {
+ XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);
+ if (xbasewindow instanceof XWindow) {
+ xwindow = (XWindow)xbasewindow;
+ }
+ }
+ }
+
+ if (xwindow != null) {
+ Point p = xwindow.toLocal(x, y);
+ x = p.x;
+ y = p.y;
+ }
+
+ if (xwindow != null) {
+ notifyProtocolListener(xwindow, x, y, java_action, java_actions,
+ xclient, MouseEvent.MOUSE_RELEASED);
+ } else if (targetXWindow != null) {
+ notifyProtocolListener(targetXWindow, x, y,
+ DnDConstants.ACTION_NONE, java_actions,
+ xclient, MouseEvent.MOUSE_EXITED);
+ }
+
+ return true;
+ }
+
+ public int getMessageType(XClientMessageEvent xclient) {
+ if (xclient.get_message_type() !=
+ MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
+
+ return UNKNOWN_MESSAGE;
+ }
+
+ long data = xclient.get_data();
+ byte reason = (byte)(unsafe.getByte(data) &
+ MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
+
+ switch (reason) {
+ case MotifDnDConstants.TOP_LEVEL_ENTER :
+ return ENTER_MESSAGE;
+ case MotifDnDConstants.DRAG_MOTION :
+ case MotifDnDConstants.OPERATION_CHANGED :
+ return MOTION_MESSAGE;
+ case MotifDnDConstants.TOP_LEVEL_LEAVE :
+ return LEAVE_MESSAGE;
+ case MotifDnDConstants.DROP_START :
+ return DROP_MESSAGE;
+ default:
+ return UNKNOWN_MESSAGE;
+ }
+ }
+
+ protected boolean processClientMessageImpl(XClientMessageEvent xclient) {
+ if (xclient.get_message_type() !=
+ MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
+ if (topLevelLeavePostponed) {
+ topLevelLeavePostponed = false;
+ cleanup();
+ }
+
+ 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);
+
+ if (topLevelLeavePostponed) {
+ topLevelLeavePostponed = false;
+ if (reason != MotifDnDConstants.DROP_START) {
+ cleanup();
+ }
+ }
+
+ /* Only initiator messages should be handled. */
+ if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
+ return false;
+ }
+
+ switch (reason) {
+ case MotifDnDConstants.TOP_LEVEL_ENTER :
+ return processTopLevelEnter(xclient);
+ case MotifDnDConstants.DRAG_MOTION :
+ case MotifDnDConstants.OPERATION_CHANGED :
+ return processDragMotion(xclient);
+ case MotifDnDConstants.TOP_LEVEL_LEAVE :
+ return processTopLevelLeave(xclient);
+ case MotifDnDConstants.DROP_START :
+ return processDropStart(xclient);
+ default:
+ return false;
+ }
+ }
+
+ /*
+ * Currently we don't synthesize enter/leave messages for Motif DnD
+ * protocol. See comments in XDropTargetProtocol.postProcessClientMessage.
+ */
+ protected void sendEnterMessageToToplevel(long win,
+ XClientMessageEvent xclient) {
+ throw new Error("UNIMPLEMENTED");
+ }
+
+ protected void sendLeaveMessageToToplevel(long win,
+ XClientMessageEvent xclient) {
+ throw new Error("UNIMPLEMENTED");
+ }
+
+ public boolean forwardEventToEmbedded(long embedded, long ctxt,
+ int eventID) {
+ // UNIMPLEMENTED.
+ return false;
+ }
+
+ public boolean isXEmbedSupported() {
+ return false;
+ }
+
+ public boolean sendResponse(long ctxt, int eventID, int action) {
+ XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
+ 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 eventByteOrder = unsafe.getByte(data + 1);
+ byte response_reason = (byte)0;
+
+ /* Only initiator messages should be handled. */
+ if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
+ return false;
+ }
+
+ switch (reason) {
+ case MotifDnDConstants.TOP_LEVEL_ENTER:
+ case MotifDnDConstants.TOP_LEVEL_LEAVE:
+ /* Receiver shouldn't rely to these messages. */
+ return false;
+ case MotifDnDConstants.DRAG_MOTION:
+ switch (eventID) {
+ case MouseEvent.MOUSE_ENTERED:
+ response_reason = MotifDnDConstants.DROP_SITE_ENTER;
+ break;
+ case MouseEvent.MOUSE_DRAGGED:
+ response_reason = MotifDnDConstants.DRAG_MOTION;
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ response_reason = MotifDnDConstants.DROP_SITE_LEAVE;
+ break;
+ }
+ break;
+ case MotifDnDConstants.OPERATION_CHANGED:
+ case MotifDnDConstants.DROP_START:
+ response_reason = reason;
+ break;
+ default:
+ // Unknown reason. Shouldn't get here.
+ assert false;
+ }
+
+ XClientMessageEvent msg = new XClientMessageEvent();
+
+ try {
+ msg.set_type(XlibWrapper.ClientMessage);
+ msg.set_window(MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder));
+ msg.set_format(8);
+ msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
+
+ long responseData = msg.get_data();
+
+ unsafe.putByte(responseData, (byte)(response_reason |
+ MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER));
+ unsafe.putByte(responseData + 1, MotifDnDConstants.getByteOrderByte());
+
+ int response_flags = 0;
+
+ if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
+ short flags = MotifDnDConstants.Swapper.getShort(data + 2,
+ eventByteOrder);
+ byte dropSiteStatus = (action == DnDConstants.ACTION_NONE) ?
+ MotifDnDConstants.MOTIF_INVALID_DROP_SITE :
+ MotifDnDConstants.MOTIF_VALID_DROP_SITE;
+
+ /* Clear action and drop site status bits. */
+ response_flags = flags &
+ ~MotifDnDConstants.MOTIF_DND_ACTION_MASK &
+ ~MotifDnDConstants.MOTIF_DND_STATUS_MASK;
+ /* Fill in new action and drop site status. */
+ response_flags |=
+ MotifDnDConstants.getMotifActionsForJavaActions(action) <<
+ MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
+ response_flags |=
+ dropSiteStatus << MotifDnDConstants.MOTIF_DND_STATUS_SHIFT;
+ } else {
+ response_flags = 0;
+ }
+
+ unsafe.putShort(responseData + 2, (short)response_flags);
+
+ /* Write time stamp. */
+ int time = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
+ unsafe.putInt(responseData + 4, time);
+
+ /* Write coordinates. */
+ if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
+ short x = MotifDnDConstants.Swapper.getShort(data + 8,
+ eventByteOrder);
+ short y = MotifDnDConstants.Swapper.getShort(data + 10,
+ eventByteOrder);
+ unsafe.putShort(responseData + 8, x); // x
+ unsafe.putShort(responseData + 10, y); // y
+ } else {
+ unsafe.putShort(responseData + 8, (short)0); // x
+ unsafe.putShort(responseData + 10, (short)0); // y
+ }
+
+ XToolkit.awtLock();
+ try {
+ XlibWrapper.XSendEvent(XToolkit.getDisplay(),
+ msg.get_window(),
+ false, XlibWrapper.NoEventMask,
+ msg.pData);
+ } finally {
+ XToolkit.awtUnlock();
+ }
+ } finally {
+ msg.dispose();
+ }
+
+ return true;
+ }
+
+ public Object getData(long ctxt, long format)
+ throws IllegalArgumentException, IOException {
+ XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
+
+ if (xclient.get_message_type() !=
+ MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
+ throw new IllegalArgumentException();
+ }
+
+ 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 eventByteOrder = unsafe.getByte(data + 1);
+
+ if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
+ throw new IOException("Cannot get data: corrupted context");
+ }
+
+ long selatom = 0;
+
+ switch (reason) {
+ case MotifDnDConstants.DRAG_MOTION :
+ case MotifDnDConstants.OPERATION_CHANGED :
+ selatom = sourceAtom;
+ break;
+ case MotifDnDConstants.DROP_START :
+ selatom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
+ break;
+ default:
+ throw new IOException("Cannot get data: invalid message reason");
+ }
+
+ if (selatom == 0) {
+ throw new IOException("Cannot get data: drag source property atom unavailable");
+ }
+
+ long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
+ XAtom selectionAtom = XAtom.get(selatom);
+
+ XSelection selection = XSelection.getSelection(selectionAtom);
+ if (selection == null) {
+ selection = new XSelection(selectionAtom, null);
+ }
+
+ return selection.getData(format, time_stamp);
+ }
+
+ public boolean sendDropDone(long ctxt, boolean success, int dropAction) {
+ XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
+
+ 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 eventByteOrder = unsafe.getByte(data + 1);
+
+ if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
+ return false;
+ }
+
+ if (reason != MotifDnDConstants.DROP_START) {
+ return false;
+ }
+
+ long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4, eventByteOrder);
+ long sel_atom = MotifDnDConstants.Swapper.getInt(data + 12, eventByteOrder);
+
+ long status_atom = 0;
+
+ if (success) {
+ status_atom = MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom();
+ } else {
+ status_atom = MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom();
+ }
+
+ XToolkit.awtLock();
+ try {
+ XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
+ sel_atom,
+ status_atom,
+ MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom(),
+ XWindow.getXAWTRootWindow().getWindow(),
+ time_stamp);
+
+ /*
+ * Flush the buffer to guarantee that the drop completion event is sent
+ * to the source before the method returns.
+ */
+ XlibWrapper.XFlush(XToolkit.getDisplay());
+ } finally {
+ XToolkit.awtUnlock();
+ }
+
+ /* Trick to prevent cleanup() from posting dragExit */
+ targetXWindow = null;
+
+ /* Cannot do cleanup before the drop finishes as we may need
+ source protocol version to send drop finished message. */
+ cleanup();
+ return true;
+ }
+
+ public final long getSourceWindow() {
+ return sourceWindow;
+ }
+
+ /**
+ * Reset the state of the object.
+ */
+ public void cleanup() {
+ // Clear the reference to this protocol.
+ XDropTargetEventProcessor.reset();
+
+ if (targetXWindow != null) {
+ notifyProtocolListener(targetXWindow, 0, 0,
+ DnDConstants.ACTION_NONE, sourceActions,
+ null, MouseEvent.MOUSE_EXITED);
+ }
+
+ if (sourceWindow != 0) {
+ XToolkit.awtLock();
+ try {
+ XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
+ XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
+ sourceWindowMask);
+ XToolkit.RESTORE_XERROR_HANDLER();
+ } finally {
+ XToolkit.awtUnlock();
+ }
+ }
+
+ sourceWindow = 0;
+ sourceWindowMask = 0;
+ sourceProtocolVersion = 0;
+ sourceActions = DnDConstants.ACTION_NONE;
+ sourceFormats = null;
+ sourceAtom = 0;
+ userAction = DnDConstants.ACTION_NONE;
+ sourceX = 0;
+ sourceY = 0;
+ targetXWindow = null;
+ topLevelLeavePostponed = false;
+ }
+
+ public boolean isDragOverComponent() {
+ return targetXWindow != null;
+ }
+
+ private void notifyProtocolListener(XWindow xwindow, int x, int y,
+ int dropAction, int actions,
+ XClientMessageEvent xclient,
+ int eventID) {
+ long nativeCtxt = 0;
+
+ // Make a copy of the passed XClientMessageEvent structure, since
+ // the original structure can be freed before this
+ // SunDropTargetEvent is dispatched.
+ if (xclient != null) {
+ int size = new XClientMessageEvent(nativeCtxt).getSize();
+
+ nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
+
+ unsafe.copyMemory(xclient.pData, nativeCtxt, size);
+ }
+
+ getProtocolListener().handleDropTargetNotification(xwindow, x, y,
+ dropAction,
+ actions,
+ sourceFormats,
+ nativeCtxt,
+ eventID);
+ }
+}