blob: 8d63906a66438144a82c05c31d799c2056ca8e57 [file] [log] [blame]
/*
* Copyright (c) 2003, 2014, 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.awt.X11;
import java.awt.Point;
import java.awt.dnd.DnDConstants;
import java.awt.event.MouseEvent;
import java.io.IOException;
import jdk.internal.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}.
*/
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,
XConstants.AnyPropertyType);
try {
status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
/*
* 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 == XConstants.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);
}
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
8, XConstants.PropModeReplace,
data, dataSize);
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
if ((XErrorHandlerUtil.saved_error != null) &&
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.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,
XConstants.AnyPropertyType);
try {
status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
/*
* 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 == XConstants.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);
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
XlibWrapper.XChangeProperty(XToolkit.getDisplay(), embedder,
MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
8, XConstants.PropModeReplace,
data, dataSize);
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
if ((XErrorHandlerUtil.saved_error != null) &&
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.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,
XConstants.AnyPropertyType);
try {
status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
/*
* 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 == XConstants.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,
XConstants.AnyPropertyType);
try {
int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
if (status == XConstants.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(XErrorHandler.IgnoreBadWindowHandler.getInstance());
if (status == XConstants.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 {
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
source_win, wattr.pData);
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
if ((status == 0) ||
((XErrorHandlerUtil.saved_error != null) &&
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
throw new XException("XGetWindowAttributes failed");
}
source_win_mask = wattr.get_your_event_mask();
} finally {
wattr.dispose();
}
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
source_win_mask |
XConstants.StructureNotifyMask);
XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
if ((XErrorHandlerUtil.saved_error != null) &&
(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.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(XConstants.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, XConstants.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(XConstants.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, XConstants.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) & 0xffffffffL;
// with correction of (32-bit unsigned to 64-bit signed) implicit conversion.
XAtom selectionAtom = XAtom.get(selatom);
XSelection selection = XSelection.getSelection(selectionAtom);
if (selection == null) {
selection = new XSelection(selectionAtom);
}
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) & 0xffffffffL;
// with correction of (32-bit unsigned to 64-bit signed) implicit conversion.
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 {
XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,
sourceWindowMask);
XErrorHandlerUtil.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 = XClientMessageEvent.getSize();
nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());
unsafe.copyMemory(xclient.pData, nativeCtxt, size);
}
getProtocolListener().handleDropTargetNotification(xwindow, x, y,
dropAction,
actions,
sourceFormats,
nativeCtxt,
eventID);
}
}