Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/XDnDDragSourceProtocol.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 sun.util.logging.PlatformLogger;3637import jdk.internal.misc.Unsafe;3839/**40* XDragSourceProtocol implementation for XDnD protocol.41*42* @since 1.543*/44class XDnDDragSourceProtocol extends XDragSourceProtocol {45private static final PlatformLogger logger =46PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDnDDragSourceProtocol");4748private static final Unsafe unsafe = XlibWrapper.unsafe;4950protected XDnDDragSourceProtocol(XDragSourceProtocolListener listener) {51super(listener);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 XDnDDragSourceProtocol(listener);61}6263public String getProtocolName() {64return XDragAndDropProtocols.XDnD;65}6667/**68* Performs protocol-specific drag initialization.69*70* @return true if the initialized successfully.71*/72protected void initializeDragImpl(int actions, Transferable contents,73Map<Long, DataFlavor> formatMap, long[] formats)74throws InvalidDnDOperationException,75IllegalArgumentException, XException {76assert XToolkit.isAWTLockHeldByCurrentThread();7778long window = XDragSourceProtocol.getDragSourceWindow();7980long data = Native.allocateLongArray(3);81int action_count = 0;82try {83if ((actions & DnDConstants.ACTION_COPY) != 0) {84Native.putLong(data, action_count,85XDnDConstants.XA_XdndActionCopy.getAtom());86action_count++;87}88if ((actions & DnDConstants.ACTION_MOVE) != 0) {89Native.putLong(data, action_count,90XDnDConstants.XA_XdndActionMove.getAtom());91action_count++;92}93if ((actions & DnDConstants.ACTION_LINK) != 0) {94Native.putLong(data, action_count,95XDnDConstants.XA_XdndActionLink.getAtom());96action_count++;97}9899XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());100XDnDConstants.XA_XdndActionList.setAtomData(window,101XAtom.XA_ATOM,102data, action_count);103XErrorHandlerUtil.RESTORE_XERROR_HANDLER();104105if ((XErrorHandlerUtil.saved_error) != null &&106(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {107cleanup();108throw new XException("Cannot write XdndActionList property");109}110} finally {111unsafe.freeMemory(data);112data = 0;113}114115data = Native.allocateLongArray(formats.length);116117try {118Native.put(data, formats);119120XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());121XDnDConstants.XA_XdndTypeList.setAtomData(window,122XAtom.XA_ATOM,123data, formats.length);124XErrorHandlerUtil.RESTORE_XERROR_HANDLER();125126if ((XErrorHandlerUtil.saved_error != null) &&127(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {128cleanup();129throw new XException("Cannot write XdndActionList property");130}131} finally {132unsafe.freeMemory(data);133data = 0;134}135136if (!XDnDConstants.XDnDSelection.setOwner(contents, formatMap, formats,137XConstants.CurrentTime)) {138cleanup();139throw new InvalidDnDOperationException("Cannot acquire selection ownership");140}141}142143private boolean processXdndStatus(XClientMessageEvent xclient) {144int action = DnDConstants.ACTION_NONE;145146/* Ignore XDnD messages from all other windows. */147if (xclient.get_data(0) != getTargetWindow()) {148return true;149}150151if ((xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0) {152/* This feature is new in XDnD version 2, but we can use it as XDnD153compliance only requires supporting version 3 and up. */154action = XDnDConstants.getJavaActionForXDnDAction(xclient.get_data(4));155}156157getProtocolListener().handleDragReply(action);158159return true;160}161162private boolean processXdndFinished(XClientMessageEvent xclient) {163/* Ignore XDnD messages from all other windows. */164if (xclient.get_data(0) != getTargetWindow()) {165return true;166}167168if (getTargetProtocolVersion() >= 5) {169boolean success = (xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0;170int action = XDnDConstants.getJavaActionForXDnDAction(xclient.get_data(2));171getProtocolListener().handleDragFinished(success, action);172} else {173getProtocolListener().handleDragFinished();174}175176finalizeDrop();177178return true;179}180181public boolean processClientMessage(XClientMessageEvent xclient) {182if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus.getAtom()) {183return processXdndStatus(xclient);184} else if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {185return processXdndFinished(xclient);186} else {187return false;188}189}190191public TargetWindowInfo getTargetWindowInfo(long window) {192assert XToolkit.isAWTLockHeldByCurrentThread();193194WindowPropertyGetter wpg1 =195new WindowPropertyGetter(window, XDnDConstants.XA_XdndAware, 0, 1,196false, XConstants.AnyPropertyType);197198int status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());199200if (status == XConstants.Success &&201wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {202203int targetVersion = (int)Native.getLong(wpg1.getData());204205wpg1.dispose();206207if (targetVersion >= XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {208long proxy = 0;209int protocolVersion =210targetVersion < XDnDConstants.XDND_PROTOCOL_VERSION ?211targetVersion : XDnDConstants.XDND_PROTOCOL_VERSION;212213WindowPropertyGetter wpg2 =214new WindowPropertyGetter(window, XDnDConstants.XA_XdndProxy,2150, 1, false, XAtom.XA_WINDOW);216217try {218status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());219220if (status == XConstants.Success &&221wpg2.getData() != 0 &&222wpg2.getActualType() == XAtom.XA_WINDOW) {223224proxy = Native.getLong(wpg2.getData());225}226} finally {227wpg2.dispose();228}229230if (proxy != 0) {231WindowPropertyGetter wpg3 =232new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,2330, 1, false, XAtom.XA_WINDOW);234235try {236status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());237238if (status != XConstants.Success ||239wpg3.getData() == 0 ||240wpg3.getActualType() != XAtom.XA_WINDOW ||241Native.getLong(wpg3.getData()) != proxy) {242243proxy = 0;244} else {245WindowPropertyGetter wpg4 =246new WindowPropertyGetter(proxy,247XDnDConstants.XA_XdndAware,2480, 1, false,249XConstants.AnyPropertyType);250251try {252status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());253254if (status != XConstants.Success ||255wpg4.getData() == 0 ||256wpg4.getActualType() != XAtom.XA_ATOM) {257258proxy = 0;259}260} finally {261wpg4.dispose();262}263}264} finally {265wpg3.dispose();266}267}268269return new TargetWindowInfo(proxy, protocolVersion);270}271} else {272wpg1.dispose();273}274275return null;276}277278public void sendEnterMessage(long[] formats,279int sourceAction, int sourceActions, long time) {280assert XToolkit.isAWTLockHeldByCurrentThread();281assert getTargetWindow() != 0;282assert formats != null;283284XClientMessageEvent msg = new XClientMessageEvent();285try {286msg.set_type(XConstants.ClientMessage);287msg.set_window(getTargetWindow());288msg.set_format(32);289msg.set_message_type(XDnDConstants.XA_XdndEnter.getAtom());290msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());291long data1 =292getTargetProtocolVersion() << XDnDConstants.XDND_PROTOCOL_SHIFT;293data1 |= formats.length > 3 ? XDnDConstants.XDND_DATA_TYPES_BIT : 0;294msg.set_data(1, data1);295msg.set_data(2, formats.length > 0 ? formats[0] : 0);296msg.set_data(3, formats.length > 1 ? formats[1] : 0);297msg.set_data(4, formats.length > 2 ? formats[2] : 0);298XlibWrapper.XSendEvent(XToolkit.getDisplay(),299getTargetProxyWindow(),300false, XConstants.NoEventMask,301msg.pData);302} finally {303msg.dispose();304}305}306307public void sendMoveMessage(int xRoot, int yRoot,308int sourceAction, int sourceActions, long time) {309assert XToolkit.isAWTLockHeldByCurrentThread();310assert getTargetWindow() != 0;311312XClientMessageEvent msg = new XClientMessageEvent();313try {314msg.set_type(XConstants.ClientMessage);315msg.set_window(getTargetWindow());316msg.set_format(32);317msg.set_message_type(XDnDConstants.XA_XdndPosition.getAtom());318msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());319msg.set_data(1, 0); /* flags */320msg.set_data(2, xRoot << 16 | yRoot);321msg.set_data(3, time);322msg.set_data(4, XDnDConstants.getXDnDActionForJavaAction(sourceAction));323XlibWrapper.XSendEvent(XToolkit.getDisplay(),324getTargetProxyWindow(),325false, XConstants.NoEventMask,326msg.pData);327} finally {328msg.dispose();329}330}331332public void sendLeaveMessage(long time) {333assert XToolkit.isAWTLockHeldByCurrentThread();334assert getTargetWindow() != 0;335336XClientMessageEvent msg = new XClientMessageEvent();337try {338msg.set_type(XConstants.ClientMessage);339msg.set_window(getTargetWindow());340msg.set_format(32);341msg.set_message_type(XDnDConstants.XA_XdndLeave.getAtom());342msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());343msg.set_data(1, 0);344msg.set_data(2, 0);345msg.set_data(3, 0);346msg.set_data(4, 0);347XlibWrapper.XSendEvent(XToolkit.getDisplay(),348getTargetProxyWindow(),349false, XConstants.NoEventMask,350msg.pData);351} finally {352msg.dispose();353}354}355356public void sendDropMessage(int xRoot, int yRoot,357int sourceAction, int sourceActions,358long time) {359assert XToolkit.isAWTLockHeldByCurrentThread();360assert getTargetWindow() != 0;361362XClientMessageEvent msg = new XClientMessageEvent();363try {364msg.set_type(XConstants.ClientMessage);365msg.set_window(getTargetWindow());366msg.set_format(32);367msg.set_message_type(XDnDConstants.XA_XdndDrop.getAtom());368msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());369msg.set_data(1, 0); /* flags */370msg.set_data(2, time);371msg.set_data(3, 0);372msg.set_data(4, 0);373XlibWrapper.XSendEvent(XToolkit.getDisplay(),374getTargetProxyWindow(),375false, XConstants.NoEventMask,376msg.pData);377} finally {378msg.dispose();379}380}381382public boolean processProxyModeEvent(XClientMessageEvent xclient,383long sourceWindow) {384if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus.getAtom() ||385xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {386387if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished.getAtom()) {388XDragSourceContextPeer.setProxyModeSourceWindow(0);389}390391// This can happen if the drag operation started in the XEmbed server.392// In this case there is no need to forward it elsewhere, we should393// process it here.394if (xclient.get_window() == sourceWindow) {395return false;396}397398if (logger.isLoggable(PlatformLogger.Level.FINEST)) {399logger.finest(" sourceWindow=" + sourceWindow +400" get_window=" + xclient.get_window() +401" xclient=" + xclient);402}403xclient.set_data(0, xclient.get_window());404xclient.set_window(sourceWindow);405406assert XToolkit.isAWTLockHeldByCurrentThread();407408XlibWrapper.XSendEvent(XToolkit.getDisplay(), sourceWindow,409false, XConstants.NoEventMask,410xclient.pData);411412return true;413}414415return false;416}417418// TODO: register this runnable with XDnDSelection.419public void run() {420// XdndSelection ownership lost.421cleanup();422}423}424425426