Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/MotifDnDDragSourceProtocol.java
41159 views
/*1* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt.X11;2627import java.awt.datatransfer.Transferable;28import java.awt.datatransfer.DataFlavor;2930import java.awt.dnd.DnDConstants;31import java.awt.dnd.InvalidDnDOperationException;3233import java.util.Map;3435import jdk.internal.misc.Unsafe;3637/**38* XDragSourceProtocol implementation for Motif DnD protocol.39*40* @since 1.541*/42class MotifDnDDragSourceProtocol extends XDragSourceProtocol43implements XEventDispatcher {4445private static final Unsafe unsafe = XlibWrapper.unsafe;4647private long targetEnterServerTime = XConstants.CurrentTime;4849protected MotifDnDDragSourceProtocol(XDragSourceProtocolListener listener) {50super(listener);51XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this);52}5354/**55* Creates an instance associated with the specified listener.56*57* @throws NullPointerException if listener is {@code null}.58*/59static XDragSourceProtocol createInstance(XDragSourceProtocolListener listener) {60return new MotifDnDDragSourceProtocol(listener);61}6263public String getProtocolName() {64return XDragAndDropProtocols.MotifDnD;65}6667protected void initializeDragImpl(int actions, Transferable contents,68Map<Long, DataFlavor> formatMap, long[] formats)69throws InvalidDnDOperationException,70IllegalArgumentException, XException {7172long window = XDragSourceProtocol.getDragSourceWindow();7374/* Write the Motif DnD initiator info on the root XWindow. */75try {76int index = MotifDnDConstants.getIndexForTargetList(formats);7778MotifDnDConstants.writeDragInitiatorInfoStruct(window, index);79} catch (XException xe) {80cleanup();81throw xe;82} catch (InvalidDnDOperationException idoe) {83cleanup();84throw idoe;85}8687if (!MotifDnDConstants.MotifDnDSelection.setOwner(contents, formatMap,88formats,89XConstants.CurrentTime)) {90cleanup();91throw new InvalidDnDOperationException("Cannot acquire selection ownership");92}93}9495/**96* Processes the specified client message event.97*98* @return true if the event was successfully processed.99*/100public boolean processClientMessage(XClientMessageEvent xclient) {101if (xclient.get_message_type() !=102MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom()) {103return false;104}105106long data = xclient.get_data();107byte reason = (byte)(unsafe.getByte(data) &108MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);109byte origin = (byte)(unsafe.getByte(data) &110MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);111byte byteOrder = unsafe.getByte(data + 1);112boolean swapNeeded = byteOrder != MotifDnDConstants.getByteOrderByte();113int action = DnDConstants.ACTION_NONE;114int x = 0;115int y = 0;116117/* Only receiver messages should be handled. */118if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER) {119return false;120}121122switch (reason) {123case MotifDnDConstants.DROP_SITE_ENTER:124case MotifDnDConstants.DROP_SITE_LEAVE:125case MotifDnDConstants.DRAG_MOTION:126case MotifDnDConstants.OPERATION_CHANGED:127break;128default:129// Unknown reason.130return false;131}132133int t = unsafe.getInt(data + 4);134if (swapNeeded) {135t = MotifDnDConstants.Swapper.swap(t);136}137long time = t & 0xffffffffL;138// with correction of (32-bit unsigned to 64-bit signed) implicit conversion.139140/* Discard events from the previous receiver. */141if (targetEnterServerTime == XConstants.CurrentTime ||142time < targetEnterServerTime) {143return true;144}145146if (reason != MotifDnDConstants.DROP_SITE_LEAVE) {147short flags = unsafe.getShort(data + 2);148if (swapNeeded) {149flags = MotifDnDConstants.Swapper.swap(flags);150}151152byte status = (byte)((flags & MotifDnDConstants.MOTIF_DND_STATUS_MASK) >>153MotifDnDConstants.MOTIF_DND_STATUS_SHIFT);154byte motif_action = (byte)((flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >>155MotifDnDConstants.MOTIF_DND_ACTION_SHIFT);156157if (status == MotifDnDConstants.MOTIF_VALID_DROP_SITE) {158action = MotifDnDConstants.getJavaActionsForMotifActions(motif_action);159} else {160action = DnDConstants.ACTION_NONE;161}162163short tx = unsafe.getShort(data + 8);164short ty = unsafe.getShort(data + 10);165if (swapNeeded) {166tx = MotifDnDConstants.Swapper.swap(tx);167ty = MotifDnDConstants.Swapper.swap(ty);168}169x = tx;170y = ty;171}172173getProtocolListener().handleDragReply(action, x, y);174175return true;176}177178public TargetWindowInfo getTargetWindowInfo(long window) {179assert XToolkit.isAWTLockHeldByCurrentThread();180181WindowPropertyGetter wpg =182new WindowPropertyGetter(window,183MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO,1840, 0xFFFF, false,185XConstants.AnyPropertyType);186187try {188int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());189190/*191* DragICCI.h:192*193* typedef struct _xmDragReceiverInfoStruct{194* BYTE byte_order;195* BYTE protocol_version;196* BYTE drag_protocol_style;197* BYTE pad1;198* CARD32 proxy_window B32;199* CARD16 num_drop_sites B16;200* CARD16 pad2 B16;201* CARD32 heap_offset B32;202* } xmDragReceiverInfoStruct;203*/204if (status == XConstants.Success && wpg.getData() != 0 &&205wpg.getActualType() != 0 && wpg.getActualFormat() == 8 &&206wpg.getNumberOfItems() >=207MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {208209long data = wpg.getData();210byte byteOrderByte = unsafe.getByte(data);211byte dragProtocolStyle = unsafe.getByte(data + 2);212switch (dragProtocolStyle) {213case MotifDnDConstants.MOTIF_PREFER_PREREGISTER_STYLE :214case MotifDnDConstants.MOTIF_PREFER_DYNAMIC_STYLE :215case MotifDnDConstants.MOTIF_DYNAMIC_STYLE :216case MotifDnDConstants.MOTIF_PREFER_RECEIVER_STYLE :217int proxy = unsafe.getInt(data + 4);218if (byteOrderByte != MotifDnDConstants.getByteOrderByte()) {219proxy = MotifDnDConstants.Swapper.swap(proxy);220}221222int protocolVersion = unsafe.getByte(data + 1);223224return new TargetWindowInfo(proxy, protocolVersion);225default:226// Unsupported protocol style.227return null;228}229} else {230return null;231}232} finally {233wpg.dispose();234}235}236237public void sendEnterMessage(long[] formats,238int sourceAction, int sourceActions, long time) {239assert XToolkit.isAWTLockHeldByCurrentThread();240assert getTargetWindow() != 0;241assert formats != null;242243targetEnterServerTime = time;244245XClientMessageEvent msg = new XClientMessageEvent();246try {247msg.set_type(XConstants.ClientMessage);248msg.set_window(getTargetWindow());249msg.set_format(8);250msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());251252long data = msg.get_data();253int flags =254(MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<255MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |256(MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<257MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);258259unsafe.putByte(data,260(byte)(MotifDnDConstants.TOP_LEVEL_ENTER |261MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));262unsafe.putByte(data + 1,263MotifDnDConstants.getByteOrderByte());264unsafe.putShort(data + 2, (short)flags);265unsafe.putInt(data + 4, (int)time);266unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());267unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());268269XlibWrapper.XSendEvent(XToolkit.getDisplay(),270getTargetProxyWindow(),271false, XConstants.NoEventMask,272msg.pData);273} finally {274msg.dispose();275}276}277278public void sendMoveMessage(int xRoot, int yRoot,279int sourceAction, int sourceActions, long time) {280assert XToolkit.isAWTLockHeldByCurrentThread();281assert getTargetWindow() != 0;282283XClientMessageEvent msg = new XClientMessageEvent();284try {285msg.set_type(XConstants.ClientMessage);286msg.set_window(getTargetWindow());287msg.set_format(8);288msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());289290long data = msg.get_data();291int flags =292(MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<293MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |294(MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<295MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);296297unsafe.putByte(data,298(byte)(MotifDnDConstants.DRAG_MOTION |299MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));300unsafe.putByte(data + 1,301MotifDnDConstants.getByteOrderByte());302unsafe.putShort(data + 2, (short)flags);303unsafe.putInt(data + 4, (int)time);304unsafe.putShort(data + 8, (short)xRoot);305unsafe.putShort(data + 10, (short)yRoot);306307XlibWrapper.XSendEvent(XToolkit.getDisplay(),308getTargetProxyWindow(),309false, XConstants.NoEventMask,310msg.pData);311} finally {312msg.dispose();313}314}315316public void sendLeaveMessage(long time) {317assert XToolkit.isAWTLockHeldByCurrentThread();318assert getTargetWindow() != 0;319320XClientMessageEvent msg = new XClientMessageEvent();321try {322msg.set_type(XConstants.ClientMessage);323msg.set_window(getTargetWindow());324msg.set_format(8);325msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());326327long data = msg.get_data();328329unsafe.putByte(data,330(byte)(MotifDnDConstants.TOP_LEVEL_LEAVE |331MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));332unsafe.putByte(data + 1,333MotifDnDConstants.getByteOrderByte());334unsafe.putShort(data + 2, (short)0);335unsafe.putInt(data + 4, (int)time);336unsafe.putInt(data + 8, (int)XDragSourceProtocol.getDragSourceWindow());337338XlibWrapper.XSendEvent(XToolkit.getDisplay(),339getTargetProxyWindow(),340false, XConstants.NoEventMask,341msg.pData);342} finally {343msg.dispose();344}345}346347protected void sendDropMessage(int xRoot, int yRoot,348int sourceAction, int sourceActions,349long time) {350assert XToolkit.isAWTLockHeldByCurrentThread();351assert getTargetWindow() != 0;352353/*354* Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START.355*/356sendLeaveMessage(time);357358XClientMessageEvent msg = new XClientMessageEvent();359try {360msg.set_type(XConstants.ClientMessage);361msg.set_window(getTargetWindow());362msg.set_format(8);363msg.set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE.getAtom());364365long data = msg.get_data();366int flags =367(MotifDnDConstants.getMotifActionsForJavaActions(sourceAction) <<368MotifDnDConstants.MOTIF_DND_ACTION_SHIFT) |369(MotifDnDConstants.getMotifActionsForJavaActions(sourceActions) <<370MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);371372unsafe.putByte(data,373(byte)(MotifDnDConstants.DROP_START |374MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));375unsafe.putByte(data + 1,376MotifDnDConstants.getByteOrderByte());377unsafe.putShort(data + 2, (short)flags);378unsafe.putInt(data + 4, (int)time);379unsafe.putShort(data + 8, (short)xRoot);380unsafe.putShort(data + 10, (short)yRoot);381unsafe.putInt(data + 12, (int)MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());382unsafe.putInt(data + 16, (int)XDragSourceProtocol.getDragSourceWindow());383384XlibWrapper.XSendEvent(XToolkit.getDisplay(),385getTargetProxyWindow(),386false, XConstants.NoEventMask,387msg.pData);388} finally {389msg.dispose();390}391}392393public boolean processProxyModeEvent(XClientMessageEvent xclient,394long sourceWindow) {395// Motif DnD for XEmbed is not implemented.396return false;397}398399public void cleanupTargetInfo() {400super.cleanupTargetInfo();401targetEnterServerTime = XConstants.CurrentTime;402}403404public void dispatchEvent(XEvent ev) {405switch (ev.get_type()) {406case XConstants.SelectionRequest:407XSelectionRequestEvent xsre = ev.get_xselectionrequest();408long atom = xsre.get_selection();409410if (atom == MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom()) {411long target = xsre.get_target();412if (target == MotifDnDConstants.XA_XmTRANSFER_SUCCESS.getAtom()) {413getProtocolListener().handleDragFinished(true);414} else if (target == MotifDnDConstants.XA_XmTRANSFER_FAILURE.getAtom()) {415getProtocolListener().handleDragFinished(false);416}417}418break;419}420}421}422423424