Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/XDnDDropTargetProtocol.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.Point;2829import java.awt.dnd.DnDConstants;3031import java.awt.event.MouseEvent;3233import java.io.IOException;3435import sun.util.logging.PlatformLogger;3637import jdk.internal.misc.Unsafe;3839import java.awt.Rectangle;4041import java.awt.GraphicsDevice;4243import java.awt.GraphicsEnvironment;4445import sun.awt.X11GraphicsConfig;4647/**48* XDropTargetProtocol implementation for XDnD protocol.49*50* @since 1.551*/52class XDnDDropTargetProtocol extends XDropTargetProtocol {53private static final PlatformLogger logger =54PlatformLogger.getLogger("sun.awt.X11.xembed.xdnd.XDnDDropTargetProtocol");5556private static final Unsafe unsafe = XlibWrapper.unsafe;5758private long sourceWindow = 0;59private long sourceWindowMask = 0;60private int sourceProtocolVersion = 0;61private int sourceActions = DnDConstants.ACTION_NONE;62private long[] sourceFormats = null;63private boolean trackSourceActions = false;64private int userAction = DnDConstants.ACTION_NONE;65private int sourceX = 0;66private int sourceY = 0;67private XWindow targetXWindow = null;6869// XEmbed stuff.70private long prevCtxt = 0;71private boolean overXEmbedClient = false;7273protected XDnDDropTargetProtocol(XDropTargetProtocolListener listener) {74super(listener);75}7677/**78* Creates an instance associated with the specified listener.79*80* @throws NullPointerException if listener is {@code null}.81*/82static XDropTargetProtocol createInstance(XDropTargetProtocolListener listener) {83return new XDnDDropTargetProtocol(listener);84}8586public String getProtocolName() {87return XDragAndDropProtocols.XDnD;88}8990public void registerDropTarget(long window) {91assert XToolkit.isAWTLockHeldByCurrentThread();9293long data = Native.allocateLongArray(1);9495try {96Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);9798XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());99XDnDConstants.XA_XdndAware.setAtomData(window, XAtom.XA_ATOM, data, 1);100XErrorHandlerUtil.RESTORE_XERROR_HANDLER();101102if ((XErrorHandlerUtil.saved_error != null) &&103(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {104throw new XException("Cannot write XdndAware property");105}106} finally {107unsafe.freeMemory(data);108data = 0;109}110}111112public void unregisterDropTarget(long window) {113assert XToolkit.isAWTLockHeldByCurrentThread();114115XDnDConstants.XA_XdndAware.DeleteProperty(window);116}117118public void registerEmbedderDropSite(long embedder) {119assert XToolkit.isAWTLockHeldByCurrentThread();120121boolean overriden = false;122int version = 0;123long proxy = 0;124long newProxy = XDropTargetRegistry.getDnDProxyWindow();125int status = 0;126127WindowPropertyGetter wpg1 =128new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndAware, 0, 1,129false, XConstants.AnyPropertyType);130131try {132status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());133134if (status == XConstants.Success &&135wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {136137overriden = true;138version = (int)Native.getLong(wpg1.getData());139}140} finally {141wpg1.dispose();142}143144/* XdndProxy is not supported for prior to XDnD version 4 */145if (overriden && version >= 4) {146WindowPropertyGetter wpg2 =147new WindowPropertyGetter(embedder, XDnDConstants.XA_XdndProxy,1480, 1, false, XAtom.XA_WINDOW);149150try {151status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());152153if (status == XConstants.Success &&154wpg2.getData() != 0 &&155wpg2.getActualType() == XAtom.XA_WINDOW) {156157proxy = Native.getLong(wpg2.getData());158}159} finally {160wpg2.dispose();161}162163if (proxy != 0) {164WindowPropertyGetter wpg3 =165new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,1660, 1, false, XAtom.XA_WINDOW);167168try {169status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());170171if (status != XConstants.Success ||172wpg3.getData() == 0 ||173wpg3.getActualType() != XAtom.XA_WINDOW ||174Native.getLong(wpg3.getData()) != proxy) {175176proxy = 0;177} else {178WindowPropertyGetter wpg4 =179new WindowPropertyGetter(proxy,180XDnDConstants.XA_XdndAware,1810, 1, false,182XConstants.AnyPropertyType);183184try {185status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());186187if (status != XConstants.Success ||188wpg4.getData() == 0 ||189wpg4.getActualType() != XAtom.XA_ATOM) {190191proxy = 0;192}193} finally {194wpg4.dispose();195}196}197} finally {198wpg3.dispose();199}200}201}202203if (proxy == newProxy) {204// Embedder already registered.205return;206}207208long data = Native.allocateLongArray(1);209210try {211Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);212213/* The proxy window must have the XdndAware set, as XDnD protocol214prescribes to check the proxy window for XdndAware. */215XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());216XDnDConstants.XA_XdndAware.setAtomData(newProxy, XAtom.XA_ATOM,217data, 1);218XErrorHandlerUtil.RESTORE_XERROR_HANDLER();219220if ((XErrorHandlerUtil.saved_error != null) &&221(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {222throw new XException("Cannot write XdndAware property");223}224225Native.putLong(data, 0, newProxy);226227/* The proxy window must have the XdndProxy set to point to itself.*/228XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());229XDnDConstants.XA_XdndProxy.setAtomData(newProxy, XAtom.XA_WINDOW,230data, 1);231XErrorHandlerUtil.RESTORE_XERROR_HANDLER();232233if ((XErrorHandlerUtil.saved_error != null) &&234(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {235throw new XException("Cannot write XdndProxy property");236}237238Native.putLong(data, 0, XDnDConstants.XDND_PROTOCOL_VERSION);239240XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());241XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,242data, 1);243XErrorHandlerUtil.RESTORE_XERROR_HANDLER();244245if ((XErrorHandlerUtil.saved_error != null) &&246(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {247throw new XException("Cannot write XdndAware property");248}249250Native.putLong(data, 0, newProxy);251252XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());253XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,254data, 1);255XErrorHandlerUtil.RESTORE_XERROR_HANDLER();256257if ((XErrorHandlerUtil.saved_error != null) &&258(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {259throw new XException("Cannot write XdndProxy property");260}261} finally {262unsafe.freeMemory(data);263data = 0;264}265266putEmbedderRegistryEntry(embedder, overriden, version, proxy);267}268269public void unregisterEmbedderDropSite(long embedder) {270assert XToolkit.isAWTLockHeldByCurrentThread();271272EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);273274if (entry == null) {275return;276}277278if (entry.isOverriden()) {279long data = Native.allocateLongArray(1);280281try {282Native.putLong(data, 0, entry.getVersion());283284XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());285XDnDConstants.XA_XdndAware.setAtomData(embedder, XAtom.XA_ATOM,286data, 1);287XErrorHandlerUtil.RESTORE_XERROR_HANDLER();288289if ((XErrorHandlerUtil.saved_error != null) &&290(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {291throw new XException("Cannot write XdndAware property");292}293294Native.putLong(data, 0, (int)entry.getProxy());295296XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());297XDnDConstants.XA_XdndProxy.setAtomData(embedder, XAtom.XA_WINDOW,298data, 1);299XErrorHandlerUtil.RESTORE_XERROR_HANDLER();300301if ((XErrorHandlerUtil.saved_error != null) &&302(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {303throw new XException("Cannot write XdndProxy property");304}305} finally {306unsafe.freeMemory(data);307data = 0;308}309} else {310XDnDConstants.XA_XdndAware.DeleteProperty(embedder);311XDnDConstants.XA_XdndProxy.DeleteProperty(embedder);312}313}314315/*316* Gets and stores in the registry the embedder's XDnD drop site info317* from the embedded.318*/319public void registerEmbeddedDropSite(long embedded) {320assert XToolkit.isAWTLockHeldByCurrentThread();321322boolean overriden = false;323int version = 0;324long proxy = 0;325long newProxy = XDropTargetRegistry.getDnDProxyWindow();326int status = 0;327328WindowPropertyGetter wpg1 =329new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndAware, 0, 1,330false, XConstants.AnyPropertyType);331332try {333status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());334335if (status == XConstants.Success &&336wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {337338overriden = true;339version = (int)Native.getLong(wpg1.getData());340}341} finally {342wpg1.dispose();343}344345/* XdndProxy is not supported for prior to XDnD version 4 */346if (overriden && version >= 4) {347WindowPropertyGetter wpg2 =348new WindowPropertyGetter(embedded, XDnDConstants.XA_XdndProxy,3490, 1, false, XAtom.XA_WINDOW);350351try {352status = wpg2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());353354if (status == XConstants.Success &&355wpg2.getData() != 0 &&356wpg2.getActualType() == XAtom.XA_WINDOW) {357358proxy = Native.getLong(wpg2.getData());359}360} finally {361wpg2.dispose();362}363364if (proxy != 0) {365WindowPropertyGetter wpg3 =366new WindowPropertyGetter(proxy, XDnDConstants.XA_XdndProxy,3670, 1, false, XAtom.XA_WINDOW);368369try {370status = wpg3.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());371372if (status != XConstants.Success ||373wpg3.getData() == 0 ||374wpg3.getActualType() != XAtom.XA_WINDOW ||375Native.getLong(wpg3.getData()) != proxy) {376377proxy = 0;378} else {379WindowPropertyGetter wpg4 =380new WindowPropertyGetter(proxy,381XDnDConstants.XA_XdndAware,3820, 1, false,383XConstants.AnyPropertyType);384385try {386status = wpg4.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());387388if (status != XConstants.Success ||389wpg4.getData() == 0 ||390wpg4.getActualType() != XAtom.XA_ATOM) {391392proxy = 0;393}394} finally {395wpg4.dispose();396}397}398} finally {399wpg3.dispose();400}401}402}403404putEmbedderRegistryEntry(embedded, overriden, version, proxy);405}406407public boolean isProtocolSupported(long window) {408assert XToolkit.isAWTLockHeldByCurrentThread();409410WindowPropertyGetter wpg1 =411new WindowPropertyGetter(window, XDnDConstants.XA_XdndAware, 0, 1,412false, XConstants.AnyPropertyType);413414try {415int status = wpg1.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());416417if (status == XConstants.Success &&418wpg1.getData() != 0 && wpg1.getActualType() == XAtom.XA_ATOM) {419420return true;421} else {422return false;423}424} finally {425wpg1.dispose();426}427}428429private boolean processXdndEnter(XClientMessageEvent xclient) {430long source_win = 0;431long source_win_mask = 0;432int protocol_version = 0;433int actions = DnDConstants.ACTION_NONE;434boolean track = true;435long[] formats = null;436437if (getSourceWindow() != 0) {438return false;439}440441if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)442&& getEmbedderRegistryEntry(xclient.get_window()) == null) {443return false;444}445446if (xclient.get_message_type() != XDnDConstants.XA_XdndEnter.getAtom()){447return false;448}449450protocol_version =451(int)((xclient.get_data(1) & XDnDConstants.XDND_PROTOCOL_MASK) >>452XDnDConstants.XDND_PROTOCOL_SHIFT);453454/* XDnD compliance only requires supporting version 3 and up. */455if (protocol_version < XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {456return false;457}458459/* Ignore the source if the protocol version is higher than we support. */460if (protocol_version > XDnDConstants.XDND_PROTOCOL_VERSION) {461return false;462}463464source_win = xclient.get_data(0);465466/* Extract the list of supported actions. */467if (protocol_version < 2) {468/* Prior to XDnD version 2 only COPY action was supported. */469actions = DnDConstants.ACTION_COPY;470} else {471WindowPropertyGetter wpg =472new WindowPropertyGetter(source_win,473XDnDConstants.XA_XdndActionList,4740, 0xFFFF, false,475XAtom.XA_ATOM);476try {477wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());478479if (wpg.getActualType() == XAtom.XA_ATOM &&480wpg.getActualFormat() == 32) {481long data = wpg.getData();482483for (int i = 0; i < wpg.getNumberOfItems(); i++) {484actions |=485XDnDConstants.getJavaActionForXDnDAction(Native.getLong(data, i));486}487} else {488/*489* According to XDnD protocol, XdndActionList is optional.490* If XdndActionList is not set we try to guess which actions are491* supported.492*/493actions = DnDConstants.ACTION_COPY;494track = true;495}496} finally {497wpg.dispose();498}499}500501/* Extract the available data types. */502if ((xclient.get_data(1) & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {503WindowPropertyGetter wpg =504new WindowPropertyGetter(source_win,505XDnDConstants.XA_XdndTypeList,5060, 0xFFFF, false,507XAtom.XA_ATOM);508try {509wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());510511if (wpg.getActualType() == XAtom.XA_ATOM &&512wpg.getActualFormat() == 32) {513formats = Native.toLongs(wpg.getData(),514wpg.getNumberOfItems());515} else {516formats = new long[0];517}518} finally {519wpg.dispose();520}521} else {522int countFormats = 0;523long[] formats3 = new long[3];524525for (int i = 0; i < 3; i++) {526long j;527if ((j = xclient.get_data(2 + i)) != XConstants.None) {528formats3[countFormats++] = j;529}530}531532formats = new long[countFormats];533534System.arraycopy(formats3, 0, formats, 0, countFormats);535}536537assert XToolkit.isAWTLockHeldByCurrentThread();538539/*540* Select for StructureNotifyMask to receive DestroyNotify in case of source541* crash.542*/543XWindowAttributes wattr = new XWindowAttributes();544try {545XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());546int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),547source_win, wattr.pData);548549XErrorHandlerUtil.RESTORE_XERROR_HANDLER();550551if ((status == 0) ||552((XErrorHandlerUtil.saved_error != null) &&553(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {554throw new XException("XGetWindowAttributes failed");555}556557source_win_mask = wattr.get_your_event_mask();558} finally {559wattr.dispose();560}561562XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());563XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,564source_win_mask |565XConstants.StructureNotifyMask);566567XErrorHandlerUtil.RESTORE_XERROR_HANDLER();568569if ((XErrorHandlerUtil.saved_error != null) &&570(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {571throw new XException("XSelectInput failed");572}573574sourceWindow = source_win;575sourceWindowMask = source_win_mask;576sourceProtocolVersion = protocol_version;577sourceActions = actions;578sourceFormats = formats;579trackSourceActions = track;580581return true;582}583584private boolean processXdndPosition(XClientMessageEvent xclient) {585long time_stamp = (int)XConstants.CurrentTime;586long xdnd_action = 0;587int java_action = DnDConstants.ACTION_NONE;588int x = 0;589int y = 0;590591/* Ignore XDnD messages from all other windows. */592if (sourceWindow != xclient.get_data(0)) {593return false;594}595596XWindow xwindow = null;597{598XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient.get_window());599if (xbasewindow instanceof XWindow) {600xwindow = (XWindow)xbasewindow;601}602}603604x = (int)(xclient.get_data(2) >> 16);605y = (int)(xclient.get_data(2) & 0xFFFF);606607if (xwindow != null) {608x = xwindow.scaleDown(x);609y = xwindow.scaleDown(y);610} else {611GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();612for (GraphicsDevice gd : ge.getScreenDevices()) {613X11GraphicsConfig gc = (X11GraphicsConfig)gd.getDefaultConfiguration();614Rectangle rt = gc.getBounds();615rt.x = gc.scaleUp(rt.x);616rt.y = gc.scaleUp(rt.y);617rt.width = gc.scaleUp(rt.width);618rt.height = gc.scaleUp(rt.height);619if (rt.contains(x, y)) {620x = gc.scaleDown(x);621y = gc.scaleDown(y);622break;623}624}625626long receiver =627XDropTargetRegistry.getRegistry().getEmbeddedDropSite(628xclient.get_window(), x, y);629630if (receiver != 0) {631XBaseWindow xbasewindow = XToolkit.windowToXWindow(receiver);632if (xbasewindow instanceof XWindow) {633xwindow = (XWindow)xbasewindow;634}635}636}637638if (xwindow != null) {639/* Translate mouse position from root coordinates640to the target window coordinates. */641Point p = xwindow.toLocal(x, y);642x = p.x;643y = p.y;644}645646/* Time stamp - new in XDnD version 1. */647if (sourceProtocolVersion > 0) {648time_stamp = xclient.get_data(3) & 0xFFFFFFFFL;649}650651/* User action - new in XDnD version 2. */652if (sourceProtocolVersion > 1) {653xdnd_action = xclient.get_data(4);654} else {655/* The default action is XdndActionCopy */656xdnd_action = XDnDConstants.XA_XdndActionCopy.getAtom();657}658659java_action = XDnDConstants.getJavaActionForXDnDAction(xdnd_action);660661if (trackSourceActions) {662sourceActions |= java_action;663}664665if (xwindow == null) {666if (targetXWindow != null) {667notifyProtocolListener(targetXWindow, x, y,668DnDConstants.ACTION_NONE, xclient,669MouseEvent.MOUSE_EXITED);670}671} else {672int java_event_id = 0;673674if (targetXWindow == null) {675java_event_id = MouseEvent.MOUSE_ENTERED;676} else {677java_event_id = MouseEvent.MOUSE_DRAGGED;678}679680notifyProtocolListener(xwindow, x, y, java_action, xclient,681java_event_id);682}683684userAction = java_action;685sourceX = x;686sourceY = y;687targetXWindow = xwindow;688689return true;690}691692private boolean processXdndLeave(XClientMessageEvent xclient) {693/* Ignore XDnD messages from all other windows. */694if (sourceWindow != xclient.get_data(0)) {695return false;696}697698cleanup();699700return true;701}702703private boolean processXdndDrop(XClientMessageEvent xclient) {704/* Ignore XDnD messages from all other windows. */705if (sourceWindow != xclient.get_data(0)) {706return false;707}708709if (targetXWindow != null) {710notifyProtocolListener(targetXWindow, sourceX, sourceY, userAction,711xclient, MouseEvent.MOUSE_RELEASED);712}713714return true;715}716717public int getMessageType(XClientMessageEvent xclient) {718long messageType = xclient.get_message_type();719720if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {721return ENTER_MESSAGE;722} else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) {723return MOTION_MESSAGE;724} else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {725return LEAVE_MESSAGE;726} else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {727return DROP_MESSAGE;728} else {729return UNKNOWN_MESSAGE;730}731}732733protected boolean processClientMessageImpl(XClientMessageEvent xclient) {734long messageType = xclient.get_message_type();735736if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {737return processXdndEnter(xclient);738} else if (messageType == XDnDConstants.XA_XdndPosition.getAtom()) {739return processXdndPosition(xclient);740} else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {741return processXdndLeave(xclient);742} else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {743return processXdndDrop(xclient);744} else {745return false;746}747}748749protected void sendEnterMessageToToplevel(long toplevel,750XClientMessageEvent xclient) {751/* flags */752long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;753if (sourceFormats != null && sourceFormats.length > 3) {754data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;755}756long data2 = sourceFormats.length > 0 ? sourceFormats[0] : 0;757long data3 = sourceFormats.length > 1 ? sourceFormats[1] : 0;758long data4 = sourceFormats.length > 2 ? sourceFormats[2] : 0;759sendEnterMessageToToplevelImpl(toplevel, xclient.get_data(0),760data1, data2, data3, data4);761762}763764private void sendEnterMessageToToplevelImpl(long toplevel,765long sourceWindow,766long data1, long data2,767long data3, long data4) {768XClientMessageEvent enter = new XClientMessageEvent();769try {770enter.set_type(XConstants.ClientMessage);771enter.set_window(toplevel);772enter.set_format(32);773enter.set_message_type(XDnDConstants.XA_XdndEnter.getAtom());774/* XID of the source window */775enter.set_data(0, sourceWindow);776enter.set_data(1, data1);777enter.set_data(2, data2);778enter.set_data(3, data3);779enter.set_data(4, data4);780781forwardClientMessageToToplevel(toplevel, enter);782} finally {783enter.dispose();784}785}786787protected void sendLeaveMessageToToplevel(long toplevel,788XClientMessageEvent xclient) {789sendLeaveMessageToToplevelImpl(toplevel, xclient.get_data(0));790}791792protected void sendLeaveMessageToToplevelImpl(long toplevel,793long sourceWindow) {794XClientMessageEvent leave = new XClientMessageEvent();795try {796leave.set_type(XConstants.ClientMessage);797leave.set_window(toplevel);798leave.set_format(32);799leave.set_message_type(XDnDConstants.XA_XdndLeave.getAtom());800/* XID of the source window */801leave.set_data(0, sourceWindow);802/* flags */803leave.set_data(1, 0);804805forwardClientMessageToToplevel(toplevel, leave);806} finally {807leave.dispose();808}809}810811public boolean sendResponse(long ctxt, int eventID, int action) {812XClientMessageEvent xclient = new XClientMessageEvent(ctxt);813814if (xclient.get_message_type() !=815XDnDConstants.XA_XdndPosition.getAtom()) {816817return false;818}819820if (eventID == MouseEvent.MOUSE_EXITED) {821action = DnDConstants.ACTION_NONE;822}823824XClientMessageEvent msg = new XClientMessageEvent();825try {826msg.set_type(XConstants.ClientMessage);827msg.set_window(xclient.get_data(0));828msg.set_format(32);829msg.set_message_type(XDnDConstants.XA_XdndStatus.getAtom());830/* target window */831msg.set_data(0, xclient.get_window());832/* flags */833long flags = 0;834if (action != DnDConstants.ACTION_NONE) {835flags |= XDnDConstants.XDND_ACCEPT_DROP_FLAG;836}837msg.set_data(1, flags);838/* specify an empty rectangle */839msg.set_data(2, 0); /* x, y */840msg.set_data(3, 0); /* w, h */841/* action accepted by the target */842msg.set_data(4, XDnDConstants.getXDnDActionForJavaAction(action));843844XToolkit.awtLock();845try {846XlibWrapper.XSendEvent(XToolkit.getDisplay(),847xclient.get_data(0),848false, XConstants.NoEventMask,849msg.pData);850} finally {851XToolkit.awtUnlock();852}853} finally {854msg.dispose();855}856857return true;858}859860public Object getData(long ctxt, long format)861throws IllegalArgumentException, IOException {862XClientMessageEvent xclient = new XClientMessageEvent(ctxt);863long message_type = xclient.get_message_type();864long time_stamp = XConstants.CurrentTime;865866// NOTE: we assume that the source supports at least version 1, so we867// can use the time stamp868if (message_type == XDnDConstants.XA_XdndPosition.getAtom()) {869// X server time is an unsigned 32-bit number!870time_stamp = xclient.get_data(3) & 0xFFFFFFFFL;871} else if (message_type == XDnDConstants.XA_XdndDrop.getAtom()) {872// X server time is an unsigned 32-bit number!873time_stamp = xclient.get_data(2) & 0xFFFFFFFFL;874} else {875throw new IllegalArgumentException();876}877878return XDnDConstants.XDnDSelection.getData(format, time_stamp);879}880881public boolean sendDropDone(long ctxt, boolean success, int dropAction) {882XClientMessageEvent xclient = new XClientMessageEvent(ctxt);883884if (xclient.get_message_type() !=885XDnDConstants.XA_XdndDrop.getAtom()) {886return false;887}888889/*890* The XDnD protocol recommends that the target requests the special891* target DELETE in case if the drop action is XdndActionMove.892*/893if (dropAction == DnDConstants.ACTION_MOVE && success) {894895long time_stamp = xclient.get_data(2) & 0xFFFFFFFFL;896long xdndSelectionAtom =897XDnDConstants.XDnDSelection.getSelectionAtom().getAtom();898899XToolkit.awtLock();900try {901XlibWrapper.XConvertSelection(XToolkit.getDisplay(),902xdndSelectionAtom,903XAtom.get("DELETE").getAtom(),904XAtom.get("XAWT_SELECTION").getAtom(),905XWindow.getXAWTRootWindow().getWindow(),906time_stamp);907} finally {908XToolkit.awtUnlock();909}910}911912XClientMessageEvent msg = new XClientMessageEvent();913try {914msg.set_type(XConstants.ClientMessage);915msg.set_window(xclient.get_data(0));916msg.set_format(32);917msg.set_message_type(XDnDConstants.XA_XdndFinished.getAtom());918msg.set_data(0, xclient.get_window()); /* target window */919msg.set_data(1, 0); /* flags */920/* specify an empty rectangle */921msg.set_data(2, 0);922if (sourceProtocolVersion >= 5) {923if (success) {924msg.set_data(1, XDnDConstants.XDND_ACCEPT_DROP_FLAG);925}926/* action performed by the target */927msg.set_data(2, XDnDConstants.getXDnDActionForJavaAction(dropAction));928}929msg.set_data(3, 0);930msg.set_data(4, 0);931932XToolkit.awtLock();933try {934XlibWrapper.XSendEvent(XToolkit.getDisplay(),935xclient.get_data(0),936false, XConstants.NoEventMask,937msg.pData);938} finally {939XToolkit.awtUnlock();940}941} finally {942msg.dispose();943}944945/*946* Flush the buffer to guarantee that the drop completion event is sent947* to the source before the method returns.948*/949XToolkit.awtLock();950try {951XlibWrapper.XFlush(XToolkit.getDisplay());952} finally {953XToolkit.awtUnlock();954}955956/* Trick to prevent cleanup() from posting dragExit */957targetXWindow = null;958959/* Cannot do cleanup before the drop finishes as we may need960source protocol version to send drop finished message. */961cleanup();962return true;963}964965public final long getSourceWindow() {966return sourceWindow;967}968969/**970* Reset the state of the object.971*/972public void cleanup() {973// Clear the reference to this protocol.974XDropTargetEventProcessor.reset();975976if (targetXWindow != null) {977notifyProtocolListener(targetXWindow, 0, 0,978DnDConstants.ACTION_NONE, null,979MouseEvent.MOUSE_EXITED);980}981982if (sourceWindow != 0) {983XToolkit.awtLock();984try {985XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());986XlibWrapper.XSelectInput(XToolkit.getDisplay(), sourceWindow,987sourceWindowMask);988XErrorHandlerUtil.RESTORE_XERROR_HANDLER();989} finally {990XToolkit.awtUnlock();991}992}993994sourceWindow = 0;995sourceWindowMask = 0;996sourceProtocolVersion = 0;997sourceActions = DnDConstants.ACTION_NONE;998sourceFormats = null;999trackSourceActions = false;1000userAction = DnDConstants.ACTION_NONE;1001sourceX = 0;1002sourceY = 0;1003targetXWindow = null;1004}10051006public boolean isDragOverComponent() {1007return targetXWindow != null;1008}10091010public void adjustEventForForwarding(XClientMessageEvent xclient,1011EmbedderRegistryEntry entry) {1012/* Adjust the event to match the XDnD protocol version. */1013int version = entry.getVersion();1014if (xclient.get_message_type() == XDnDConstants.XA_XdndEnter.getAtom()) {1015int min_version = sourceProtocolVersion < version ?1016sourceProtocolVersion : version;1017long data1 = min_version << XDnDConstants.XDND_PROTOCOL_SHIFT;1018if (sourceFormats != null && sourceFormats.length > 3) {1019data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;1020}1021if (logger.isLoggable(PlatformLogger.Level.FINEST)) {1022logger.finest(" "1023+ " entryVersion=" + version1024+ " sourceProtocolVersion=" +1025sourceProtocolVersion1026+ " sourceFormats.length=" +1027(sourceFormats != null ? sourceFormats.length : 0));1028}1029xclient.set_data(1, data1);1030}1031}10321033@SuppressWarnings("static")1034private void notifyProtocolListener(XWindow xwindow, int x, int y,1035int dropAction,1036XClientMessageEvent xclient,1037int eventID) {1038long nativeCtxt = 0;10391040// Make a copy of the passed XClientMessageEvent structure, since1041// the original structure can be freed before this1042// SunDropTargetEvent is dispatched.1043if (xclient != null) {1044int size = new XClientMessageEvent(nativeCtxt).getSize();10451046nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());10471048unsafe.copyMemory(xclient.pData, nativeCtxt, size);10491050long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;1051if (sourceFormats != null && sourceFormats.length > 3) {1052data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;1053}1054// Append information from the latest XdndEnter event.1055Native.putLong(nativeCtxt + size, data1);1056Native.putLong(nativeCtxt + size + Native.getLongSize(),1057sourceFormats.length > 0 ? sourceFormats[0] : 0);1058Native.putLong(nativeCtxt + size + 2 * Native.getLongSize(),1059sourceFormats.length > 1 ? sourceFormats[1] : 0);1060Native.putLong(nativeCtxt + size + 3 * Native.getLongSize(),1061sourceFormats.length > 2 ? sourceFormats[2] : 0);1062}10631064getProtocolListener().handleDropTargetNotification(xwindow, x, y,1065dropAction,1066sourceActions,1067sourceFormats,1068nativeCtxt,1069eventID);1070}10711072/*1073* The methods/fields defined below are executed/accessed only on1074* the toolkit thread.1075* The methods/fields defined below are executed/accessed only on the event1076* dispatch thread.1077*/10781079public boolean forwardEventToEmbedded(long embedded, long ctxt,1080int eventID) {1081if (logger.isLoggable(PlatformLogger.Level.FINEST)) {1082logger.finest(" ctxt=" + ctxt +1083" type=" + (ctxt != 0 ?1084getMessageType(new1085XClientMessageEvent(ctxt)) : 0) +1086" prevCtxt=" + prevCtxt +1087" prevType=" + (prevCtxt != 0 ?1088getMessageType(new1089XClientMessageEvent(prevCtxt)) : 0));1090}1091if ((ctxt == 0 ||1092getMessageType(new XClientMessageEvent(ctxt)) == UNKNOWN_MESSAGE) &&1093(prevCtxt == 0 ||1094getMessageType(new XClientMessageEvent(prevCtxt)) == UNKNOWN_MESSAGE)) {1095return false;1096}10971098// The size of XClientMessageEvent structure.1099int size = XClientMessageEvent.getSize();11001101if (ctxt != 0) {1102XClientMessageEvent xclient = new XClientMessageEvent(ctxt);1103if (!overXEmbedClient) {1104long data1 = Native.getLong(ctxt + size);1105long data2 = Native.getLong(ctxt + size + Native.getLongSize());1106long data3 = Native.getLong(ctxt + size + 2 * Native.getLongSize());1107long data4 = Native.getLong(ctxt + size + 3 * Native.getLongSize());11081109if (logger.isLoggable(PlatformLogger.Level.FINEST)) {1110logger.finest(" 1 "1111+ " embedded=" + embedded1112+ " source=" + xclient.get_data(0)1113+ " data1=" + data11114+ " data2=" + data21115+ " data3=" + data31116+ " data4=" + data4);1117}11181119// Copy XdndTypeList from source to proxy.1120if ((data1 & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {1121WindowPropertyGetter wpg =1122new WindowPropertyGetter(xclient.get_data(0),1123XDnDConstants.XA_XdndTypeList,11240, 0xFFFF, false,1125XAtom.XA_ATOM);1126try {1127wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());11281129if (wpg.getActualType() == XAtom.XA_ATOM &&1130wpg.getActualFormat() == 32) {11311132XToolkit.awtLock();1133try {1134XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());1135XDnDConstants.XA_XdndTypeList.setAtomData(xclient.get_window(),1136XAtom.XA_ATOM,1137wpg.getData(),1138wpg.getNumberOfItems());1139XErrorHandlerUtil.RESTORE_XERROR_HANDLER();11401141if ((XErrorHandlerUtil.saved_error != null) &&1142(XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {1143if (logger.isLoggable(PlatformLogger.Level.WARNING)) {1144logger.warning("Cannot set XdndTypeList on the proxy window");1145}1146}1147} finally {1148XToolkit.awtUnlock();1149}1150} else {1151if (logger.isLoggable(PlatformLogger.Level.WARNING)) {1152logger.warning("Cannot read XdndTypeList from the source window");1153}1154}1155} finally {1156wpg.dispose();1157}1158}1159XDragSourceContextPeer.setProxyModeSourceWindow(xclient.get_data(0));11601161sendEnterMessageToToplevelImpl(embedded, xclient.get_window(),1162data1, data2, data3, data4);1163overXEmbedClient = true;1164}11651166if (logger.isLoggable(PlatformLogger.Level.FINEST)) {1167logger.finest(" 2 "1168+ " embedded=" + embedded1169+ " xclient=" + xclient);1170}11711172/* Make a copy of the original event, since we are going to modify the1173event while it still can be referenced from other Java events. */1174{1175XClientMessageEvent copy = new XClientMessageEvent();1176unsafe.copyMemory(xclient.pData, copy.pData, XClientMessageEvent.getSize());11771178copy.set_data(0, xclient.get_window());11791180forwardClientMessageToToplevel(embedded, copy);1181}1182}11831184if (eventID == MouseEvent.MOUSE_EXITED) {1185if (overXEmbedClient) {1186if (ctxt != 0 || prevCtxt != 0) {1187// Last chance to send XdndLeave to the XEmbed client.1188XClientMessageEvent xclient = ctxt != 0 ?1189new XClientMessageEvent(ctxt) :1190new XClientMessageEvent(prevCtxt);1191sendLeaveMessageToToplevelImpl(embedded, xclient.get_window());1192}1193overXEmbedClient = false;1194// We have to clear the proxy mode source window here,1195// when the drag exits the XEmbedCanvasPeer.1196// NOTE: at this point the XEmbed client still might have some1197// drag notifications to process and it will send responses to1198// us. With the proxy mode source window cleared we won't be1199// able to forward these responses to the actual source. This is1200// not a problem if the drag operation was initiated in this1201// JVM. However, if it was initiated in another processes the1202// responses will be lost. We bear with it for now, as it seems1203// there is no other reliable point to clear.1204XDragSourceContextPeer.setProxyModeSourceWindow(0);1205}1206}12071208if (eventID == MouseEvent.MOUSE_RELEASED) {1209overXEmbedClient = false;1210cleanup();1211}12121213if (prevCtxt != 0) {1214unsafe.freeMemory(prevCtxt);1215prevCtxt = 0;1216}12171218if (ctxt != 0 && overXEmbedClient) {1219prevCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize());12201221unsafe.copyMemory(ctxt, prevCtxt, size + 4 * Native.getLongSize());1222}12231224return true;1225}12261227public boolean isXEmbedSupported() {1228return true;1229}1230}123112321233