0N/A/*
0N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
0N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
0N/A * or visit www.oracle.com if you need additional information or have any
0N/A * questions.
0N/A */
0N/A
0N/Apackage sun.awt.X11;
0N/A
0N/Aimport java.awt.datatransfer.Transferable;
0N/A
0N/Aimport java.awt.dnd.DnDConstants;
0N/Aimport java.awt.dnd.InvalidDnDOperationException;
0N/A
0N/Aimport java.util.Map;
0N/A
0N/Aimport sun.misc.Unsafe;
0N/A
0N/A/**
0N/A * XDragSourceProtocol implementation for Motif DnD protocol.
0N/A *
0N/A * @since 1.5
0N/A */
0N/Aclass MotifDnDDragSourceProtocol extends XDragSourceProtocol
0N/A implements XEventDispatcher {
0N/A
0N/A private static final Unsafe unsafe = XlibWrapper.unsafe;
0N/A
0N/A private long targetEnterServerTime = XConstants.CurrentTime;
0N/A
0N/A protected MotifDnDDragSourceProtocol(XDragSourceProtocolListener listener) {
0N/A super(listener);
0N/A XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);
0N/A }
0N/A
0N/A /**
0N/A * Creates an instance associated with the specified listener.
0N/A *
0N/A * @throws NullPointerException if listener is <code>null</code>.
0N/A */
0N/A static XDragSourceProtocol createInstance(XDragSourceProtocolListener listener) {
0N/A return new MotifDnDDragSourceProtocol(listener);
0N/A }
0N/A
0N/A public String getProtocolName() {
0N/A return XDragAndDropProtocols.MotifDnD;
0N/A }
0N/A
0N/A protected void initializeDragImpl(int actions, Transferable contents,
0N/A Map formatMap, long[] formats)
0N/A throws InvalidDnDOperationException,
0N/A IllegalArgumentException, XException {
0N/A
0N/A long window = XDragSourceProtocol.getDragSourceWindow();
0N/A
0N/A /* Write the Motif DnD initiator info on the root XWindow. */
0N/A try {
0N/A int index = MotifDnDConstants.getIndexForTargetList(formats);
0N/A
0N/A MotifDnDConstants.writeDragInitiatorInfoStruct(window, index);
0N/A } catch (XException xe) {
0N/A cleanup();
0N/A throw xe;
0N/A } catch (InvalidDnDOperationException idoe) {
0N/A cleanup();
0N/A throw idoe;
0N/A }
0N/A
0N/A if (!MotifDnDConstants.MotifDnDSelection.setOwner(contents, formatMap,
0N/A formats,
0N/A XConstants.CurrentTime)) {
0N/A cleanup();
0N/A throw new InvalidDnDOperationException("Cannot acquire selection ownership");
0N/A }
0N/A }
33N/A
0N/A /**
0N/A * Processes the specified client message event.
0N/A *
0N/A * @returns true if the event was successfully processed.
0N/A */
0N/A public boolean processClientMessage(XClientMessageEvent xclient) {
0N/A if (xclient.get_message_type() !=
0N/A MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {
0N/A return false;
0N/A }
0N/A
0N/A long data = xclient.get_data();
0N/A byte reason = (byte)(unsafe.getByte(data) &
0N/A MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
63N/A byte origin = (byte)(unsafe.getByte(data) &
0N/A MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
0N/A byte byteOrder = unsafe.getByte(data + 1);
0N/A boolean swapNeeded = byteOrder != MotifDnDConstants.getByteOrderByte();
0N/A int action = DnDConstants.ACTION_NONE;
0N/A int x = 0;
0N/A int y = 0;
0N/A
0N/A /* Only receiver messages should be handled. */
0N/A if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER) {
0N/A return false;
0N/A }
0N/A
0N/A switch (reason) {
0N/A case MotifDnDConstants.DROP_SITE_ENTER:
0N/A case MotifDnDConstants.DROP_SITE_LEAVE:
0N/A case MotifDnDConstants.DRAG_MOTION:
0N/A case MotifDnDConstants.OPERATION_CHANGED:
0N/A break;
0N/A default:
0N/A // Unknown reason.
0N/A return false;
0N/A }
0N/A
0N/A int t = unsafe.getInt(data + 4);
0N/A if (swapNeeded) {
0N/A t = MotifDnDConstants.Swapper.swap(t);
0N/A }
0N/A long time = t & 0xffffffffL;
0N/A // with correction of (32-bit unsigned to 64-bit signed) implicit conversion.
0N/A
0N/A /* Discard events from the previous receiver. */
0N/A if (targetEnterServerTime == XConstants.CurrentTime ||
0N/A time < targetEnterServerTime) {
0N/A return true;
0N/A }
0N/A
0N/A if (reason != MotifDnDConstants.DROP_SITE_LEAVE) {
0N/A short flags = unsafe.getShort(data + 2);
0N/A if (swapNeeded) {
0N/A flags = MotifDnDConstants.Swapper.swap(flags);
0N/A }
0N/A
0N/A byte status = (byte)((flags & MotifDnDConstants.MOTIF_DND_STATUS_MASK) >>
0N/A MotifDnDConstants.MOTIF_DND_STATUS_SHIFT);
0N/A byte motif_action = (byte)((flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>
0N/A MotifDnDConstants.MOTIF_DND_ACTION_SHIFT);
0N/A
0N/A if (status == MotifDnDConstants.MOTIF_VALID_DROP_SITE) {
0N/A action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);
0N/A } else {
0N/A action = DnDConstants.ACTION_NONE;
0N/A }
0N/A
0N/A short tx = unsafe.getShort(data + 8);
0N/A short ty = unsafe.getShort(data + 10);
0N/A if (swapNeeded) {
0N/A tx = MotifDnDConstants.Swapper.swap(tx);
0N/A ty = MotifDnDConstants.Swapper.swap(ty);
0N/A }
0N/A x = tx;
0N/A y = ty;
0N/A }
0N/A
0N/A getProtocolListener().handleDragReply(action, x, y);
0N/A
0N/A return true;
0N/A }
0N/A
0N/A public TargetWindowInfo getTargetWindowInfo(long window) {
0N/A assert XToolkit.isAWTLockHeldByCurrentThread();
0N/A
0N/A WindowPropertyGetter wpg =
0N/A new WindowPropertyGetter(window,
0N/A MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,
0N/A 0, 0xFFFF, false,
0N/A XConstants.AnyPropertyType);
0N/A
0N/A try {
0N/A int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
0N/A
0N/A /*
0N/A * DragICCI.h:
0N/A *
0N/A * typedef struct _xmDragReceiverInfoStruct{
0N/A * BYTE byte_order;
0N/A * BYTE protocol_version;
0N/A * BYTE drag_protocol_style;
0N/A * BYTE pad1;
0N/A * CARD32 proxy_window B32;
0N/A * CARD16 num_drop_sites B16;
0N/A * CARD16 pad2 B16;
0N/A * CARD32 heap_offset B32;
0N/A * } xmDragReceiverInfoStruct;
0N/A */
0N/A if (status == (int)XConstants.Success && wpg.getData() != 0 &&
0N/A wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&
0N/A wpg.getNumberOfItems() >=
0N/A MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
0N/A
0N/A long data = wpg.getData();
0N/A byte byteOrderByte = unsafe.getByte(data);
0N/A byte dragProtocolStyle = unsafe.getByte(data + 2);
0N/A switch (dragProtocolStyle) {
0N/A case MotifDnDConstants.MOTIF_PREFER_PREREGISTER_STYLE :
0N/A case MotifDnDConstants.MOTIF_PREFER_DYNAMIC_STYLE :
0N/A case MotifDnDConstants.MOTIF_DYNAMIC_STYLE :
0N/A case MotifDnDConstants.MOTIF_PREFER_RECEIVER_STYLE :
0N/A int proxy = unsafe.getInt(data + 4);
0N/A if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {
0N/A proxy = MotifDnDConstants.Swapper.swap(proxy);
0N/A }
0N/A
0N/A int protocolVersion = unsafe.getByte(data + 1);
0N/A
0N/A return new TargetWindowInfo(proxy, protocolVersion);
0N/A default:
0N/A // Unsupported protocol style.
0N/A return null;
0N/A }
0N/A } else {
0N/A return null;
0N/A }
0N/A } finally {
0N/A wpg.dispose();
0N/A }
0N/A }
0N/A
0N/A public void sendEnterMessage(long[] formats,
0N/A int sourceAction, int sourceActions, long time) {
0N/A assert XToolkit.isAWTLockHeldByCurrentThread();
0N/A assert getTargetWindow() != 0;
0N/A assert formats != null;
0N/A
0N/A targetEnterServerTime = time;
0N/A
0N/A XClientMessageEvent msg = new XClientMessageEvent();
0N/A try {
0N/A msg.set_type(XConstants.ClientMessage);
0N/A msg.set_window(getTargetWindow());
0N/A msg.set_format(8);
0N/A msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
0N/A
0N/A long data = msg.get_data();
0N/A int flags =
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
0N/A
0N/A unsafe.putByte(data,
0N/A (byte)(MotifDnDConstants.TOP_LEVEL_ENTER |
0N/A MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
0N/A unsafe.putByte(data + 1,
0N/A MotifDnDConstants.getByteOrderByte());
0N/A unsafe.putShort(data + 2, (short)flags);
0N/A unsafe.putInt(data + 4, (int)time);
0N/A unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());
0N/A unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
0N/A
0N/A XlibWrapper.XSendEvent(XToolkit.getDisplay(),
0N/A getTargetProxyWindow(),
0N/A false, XConstants.NoEventMask,
0N/A msg.pData);
0N/A } finally {
0N/A msg.dispose();
0N/A }
0N/A }
0N/A
0N/A public void sendMoveMessage(int xRoot, int yRoot,
0N/A int sourceAction, int sourceActions, long time) {
0N/A assert XToolkit.isAWTLockHeldByCurrentThread();
0N/A assert getTargetWindow() != 0;
0N/A
0N/A XClientMessageEvent msg = new XClientMessageEvent();
0N/A try {
0N/A msg.set_type(XConstants.ClientMessage);
0N/A msg.set_window(getTargetWindow());
0N/A msg.set_format(8);
0N/A msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
0N/A
0N/A long data = msg.get_data();
0N/A int flags =
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
0N/A
0N/A unsafe.putByte(data,
0N/A (byte)(MotifDnDConstants.DRAG_MOTION |
0N/A MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
0N/A unsafe.putByte(data + 1,
0N/A MotifDnDConstants.getByteOrderByte());
0N/A unsafe.putShort(data + 2, (short)flags);
0N/A unsafe.putInt(data + 4, (int)time);
0N/A unsafe.putShort(data + 8, (short)xRoot);
0N/A unsafe.putShort(data + 10, (short)yRoot);
0N/A
0N/A XlibWrapper.XSendEvent(XToolkit.getDisplay(),
0N/A getTargetProxyWindow(),
0N/A false, XConstants.NoEventMask,
0N/A msg.pData);
0N/A } finally {
0N/A msg.dispose();
0N/A }
0N/A }
0N/A
0N/A public void sendLeaveMessage(long time) {
0N/A assert XToolkit.isAWTLockHeldByCurrentThread();
0N/A assert getTargetWindow() != 0;
0N/A
0N/A XClientMessageEvent msg = new XClientMessageEvent();
0N/A try {
0N/A msg.set_type(XConstants.ClientMessage);
0N/A msg.set_window(getTargetWindow());
0N/A msg.set_format(8);
0N/A msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
0N/A
0N/A long data = msg.get_data();
0N/A
0N/A unsafe.putByte(data,
0N/A (byte)(MotifDnDConstants.TOP_LEVEL_LEAVE |
0N/A MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
0N/A unsafe.putByte(data + 1,
0N/A MotifDnDConstants.getByteOrderByte());
0N/A unsafe.putShort(data + 2, (short)0);
0N/A unsafe.putInt(data + 4, (int)time);
0N/A unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());
0N/A
0N/A XlibWrapper.XSendEvent(XToolkit.getDisplay(),
0N/A getTargetProxyWindow(),
0N/A false, XConstants.NoEventMask,
0N/A msg.pData);
0N/A } finally {
0N/A msg.dispose();
0N/A }
0N/A }
0N/A
0N/A protected void sendDropMessage(int xRoot, int yRoot,
0N/A int sourceAction, int sourceActions,
0N/A long time) {
0N/A assert XToolkit.isAWTLockHeldByCurrentThread();
0N/A assert getTargetWindow() != 0;
0N/A
0N/A /*
0N/A * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START.
0N/A */
0N/A sendLeaveMessage(time);
0N/A
0N/A XClientMessageEvent msg = new XClientMessageEvent();
0N/A try {
0N/A msg.set_type(XConstants.ClientMessage);
0N/A msg.set_window(getTargetWindow());
0N/A msg.set_format(8);
0N/A msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());
0N/A
0N/A long data = msg.get_data();
0N/A int flags =
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |
0N/A (MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<
0N/A MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
0N/A
0N/A unsafe.putByte(data,
0N/A (byte)(MotifDnDConstants.DROP_START |
0N/A MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
0N/A unsafe.putByte(data + 1,
0N/A MotifDnDConstants.getByteOrderByte());
0N/A unsafe.putShort(data + 2, (short)flags);
0N/A unsafe.putInt(data + 4, (int)time);
0N/A unsafe.putShort(data + 8, (short)xRoot);
0N/A unsafe.putShort(data + 10, (short)yRoot);
0N/A unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
0N/A unsafe.putInt(data + 16, (int)XDragSourceProtocol.getDragSourceWindow());
0N/A
0N/A XlibWrapper.XSendEvent(XToolkit.getDisplay(),
0N/A getTargetProxyWindow(),
0N/A false, XConstants.NoEventMask,
0N/A msg.pData);
0N/A } finally {
0N/A msg.dispose();
0N/A }
0N/A }
0N/A
0N/A public boolean processProxyModeEvent(XClientMessageEvent xclient,
0N/A long sourceWindow) {
0N/A // Motif DnD for XEmbed is not implemented.
0N/A return false;
0N/A }
0N/A
0N/A public void cleanupTargetInfo() {
0N/A super.cleanupTargetInfo();
0N/A targetEnterServerTime = XConstants.CurrentTime;
0N/A }
0N/A
0N/A public void dispatchEvent(XEvent ev) {
0N/A switch (ev.get_type()) {
0N/A case XConstants.SelectionRequest:
0N/A XSelectionRequestEvent xsre = ev.get_xselectionrequest();
0N/A long atom = xsre.get_selection();
0N/A
0N/A if (atom == MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom()) {
0N/A long target = xsre.get_target();
0N/A if (target == MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom()) {
0N/A getProtocolListener().handleDragFinished(true);
0N/A } else if (target == MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom()) {
0N/A getProtocolListener().handleDragFinished(false);
0N/A }
0N/A }
0N/A break;
0N/A }
0N/A }
0N/A}
0N/A