0001: /*
0002: * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.awt.X11;
0027:
0028: import java.awt.Point;
0029:
0030: import java.awt.dnd.DnDConstants;
0031:
0032: import java.awt.event.MouseEvent;
0033:
0034: import java.io.IOException;
0035:
0036: import java.util.logging.*;
0037:
0038: import sun.misc.Unsafe;
0039:
0040: /**
0041: * XDropTargetProtocol implementation for XDnD protocol.
0042: *
0043: * @since 1.5
0044: */
0045: class XDnDDropTargetProtocol extends XDropTargetProtocol {
0046: private static final Logger logger = Logger
0047: .getLogger("sun.awt.X11.xembed.xdnd.XDnDDropTargetProtocol");
0048:
0049: private static final Unsafe unsafe = XlibWrapper.unsafe;
0050:
0051: private long sourceWindow = 0;
0052: private long sourceWindowMask = 0;
0053: private int sourceProtocolVersion = 0;
0054: private int sourceActions = DnDConstants.ACTION_NONE;
0055: private long[] sourceFormats = null;
0056: private boolean trackSourceActions = false;
0057: private int userAction = DnDConstants.ACTION_NONE;
0058: private int sourceX = 0;
0059: private int sourceY = 0;
0060: private XWindow targetXWindow = null;
0061:
0062: // XEmbed stuff.
0063: private long prevCtxt = 0;
0064: private boolean overXEmbedClient = false;
0065:
0066: protected XDnDDropTargetProtocol(
0067: XDropTargetProtocolListener listener) {
0068: super (listener);
0069: }
0070:
0071: /**
0072: * Creates an instance associated with the specified listener.
0073: *
0074: * @throws NullPointerException if listener is <code>null</code>.
0075: */
0076: static XDropTargetProtocol createInstance(
0077: XDropTargetProtocolListener listener) {
0078: return new XDnDDropTargetProtocol(listener);
0079: }
0080:
0081: public String getProtocolName() {
0082: return XDragAndDropProtocols.XDnD;
0083: }
0084:
0085: public void registerDropTarget(long window) {
0086: assert XToolkit.isAWTLockHeldByCurrentThread();
0087:
0088: long data = Native.allocateLongArray(1);
0089:
0090: try {
0091: Native
0092: .putLong(data, 0,
0093: XDnDConstants.XDND_PROTOCOL_VERSION);
0094:
0095: XToolkit
0096: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0097: XDnDConstants.XA_XdndAware.setAtomData(window,
0098: XAtom.XA_ATOM, data, 1);
0099: XToolkit.RESTORE_XERROR_HANDLER();
0100:
0101: if (XToolkit.saved_error != null
0102: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0103: throw new XException("Cannot write XdndAware property");
0104: }
0105: } finally {
0106: unsafe.freeMemory(data);
0107: data = 0;
0108: }
0109: }
0110:
0111: public void unregisterDropTarget(long window) {
0112: assert XToolkit.isAWTLockHeldByCurrentThread();
0113:
0114: XDnDConstants.XA_XdndAware.DeleteProperty(window);
0115: }
0116:
0117: public void registerEmbedderDropSite(long embedder) {
0118: assert XToolkit.isAWTLockHeldByCurrentThread();
0119:
0120: boolean overriden = false;
0121: int version = 0;
0122: long proxy = 0;
0123: long newProxy = XDropTargetRegistry.getDnDProxyWindow();
0124: int status = 0;
0125:
0126: WindowPropertyGetter wpg1 = new WindowPropertyGetter(embedder,
0127: XDnDConstants.XA_XdndAware, 0, 1, false,
0128: XlibWrapper.AnyPropertyType);
0129:
0130: try {
0131: status = wpg1.execute(XToolkit.IgnoreBadWindowHandler);
0132:
0133: if (status == XlibWrapper.Success && wpg1.getData() != 0
0134: && wpg1.getActualType() == XAtom.XA_ATOM) {
0135:
0136: overriden = true;
0137: version = (int) Native.getLong(wpg1.getData());
0138: }
0139: } finally {
0140: wpg1.dispose();
0141: }
0142:
0143: /* XdndProxy is not supported for prior to XDnD version 4 */
0144: if (overriden && version >= 4) {
0145: WindowPropertyGetter wpg2 = new WindowPropertyGetter(
0146: embedder, XDnDConstants.XA_XdndProxy, 0, 1, false,
0147: XAtom.XA_WINDOW);
0148:
0149: try {
0150: status = wpg2.execute(XToolkit.IgnoreBadWindowHandler);
0151:
0152: if (status == XlibWrapper.Success
0153: && wpg2.getData() != 0
0154: && wpg2.getActualType() == XAtom.XA_WINDOW) {
0155:
0156: proxy = Native.getLong(wpg2.getData());
0157: }
0158: } finally {
0159: wpg2.dispose();
0160: }
0161:
0162: if (proxy != 0) {
0163: WindowPropertyGetter wpg3 = new WindowPropertyGetter(
0164: proxy, XDnDConstants.XA_XdndProxy, 0, 1, false,
0165: XAtom.XA_WINDOW);
0166:
0167: try {
0168: status = wpg3
0169: .execute(XToolkit.IgnoreBadWindowHandler);
0170:
0171: if (status != XlibWrapper.Success
0172: || wpg3.getData() == 0
0173: || wpg3.getActualType() != XAtom.XA_WINDOW
0174: || Native.getLong(wpg3.getData()) != proxy) {
0175:
0176: proxy = 0;
0177: } else {
0178: WindowPropertyGetter wpg4 = new WindowPropertyGetter(
0179: proxy, XDnDConstants.XA_XdndAware, 0,
0180: 1, false, XlibWrapper.AnyPropertyType);
0181:
0182: try {
0183: status = wpg4
0184: .execute(XToolkit.IgnoreBadWindowHandler);
0185:
0186: if (status != XlibWrapper.Success
0187: || wpg4.getData() == 0
0188: || wpg4.getActualType() != XAtom.XA_ATOM) {
0189:
0190: proxy = 0;
0191: }
0192: } finally {
0193: wpg4.dispose();
0194: }
0195: }
0196: } finally {
0197: wpg3.dispose();
0198: }
0199: }
0200: }
0201:
0202: if (proxy == newProxy) {
0203: // Embedder already registered.
0204: return;
0205: }
0206:
0207: long data = Native.allocateLongArray(1);
0208:
0209: try {
0210: Native
0211: .putLong(data, 0,
0212: XDnDConstants.XDND_PROTOCOL_VERSION);
0213:
0214: /* The proxy window must have the XdndAware set, as XDnD protocol
0215: prescribes to check the proxy window for XdndAware. */
0216: XToolkit
0217: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0218: XDnDConstants.XA_XdndAware.setAtomData(newProxy,
0219: XAtom.XA_ATOM, data, 1);
0220: XToolkit.RESTORE_XERROR_HANDLER();
0221:
0222: if (XToolkit.saved_error != null
0223: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0224: throw new XException("Cannot write XdndAware property");
0225: }
0226:
0227: Native.putLong(data, 0, newProxy);
0228:
0229: /* The proxy window must have the XdndProxy set to point to itself.*/
0230: XToolkit
0231: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0232: XDnDConstants.XA_XdndProxy.setAtomData(newProxy,
0233: XAtom.XA_WINDOW, data, 1);
0234: XToolkit.RESTORE_XERROR_HANDLER();
0235:
0236: if (XToolkit.saved_error != null
0237: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0238: throw new XException("Cannot write XdndProxy property");
0239: }
0240:
0241: Native
0242: .putLong(data, 0,
0243: XDnDConstants.XDND_PROTOCOL_VERSION);
0244:
0245: XToolkit
0246: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0247: XDnDConstants.XA_XdndAware.setAtomData(embedder,
0248: XAtom.XA_ATOM, data, 1);
0249: XToolkit.RESTORE_XERROR_HANDLER();
0250:
0251: if (XToolkit.saved_error != null
0252: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0253: throw new XException("Cannot write XdndAware property");
0254: }
0255:
0256: Native.putLong(data, 0, newProxy);
0257:
0258: XToolkit
0259: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0260: XDnDConstants.XA_XdndProxy.setAtomData(embedder,
0261: XAtom.XA_WINDOW, data, 1);
0262: XToolkit.RESTORE_XERROR_HANDLER();
0263:
0264: if (XToolkit.saved_error != null
0265: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0266: throw new XException("Cannot write XdndProxy property");
0267: }
0268: } finally {
0269: unsafe.freeMemory(data);
0270: data = 0;
0271: }
0272:
0273: putEmbedderRegistryEntry(embedder, overriden, version, proxy);
0274: }
0275:
0276: public void unregisterEmbedderDropSite(long embedder) {
0277: assert XToolkit.isAWTLockHeldByCurrentThread();
0278:
0279: EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);
0280:
0281: if (entry == null) {
0282: return;
0283: }
0284:
0285: if (entry.isOverriden()) {
0286: long data = Native.allocateLongArray(1);
0287:
0288: try {
0289: Native.putLong(data, 0, entry.getVersion());
0290:
0291: XToolkit
0292: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0293: XDnDConstants.XA_XdndAware.setAtomData(embedder,
0294: XAtom.XA_ATOM, data, 1);
0295: XToolkit.RESTORE_XERROR_HANDLER();
0296:
0297: if (XToolkit.saved_error != null
0298: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0299: throw new XException(
0300: "Cannot write XdndAware property");
0301: }
0302:
0303: Native.putLong(data, 0, (int) entry.getProxy());
0304:
0305: XToolkit
0306: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0307: XDnDConstants.XA_XdndProxy.setAtomData(embedder,
0308: XAtom.XA_WINDOW, data, 1);
0309: XToolkit.RESTORE_XERROR_HANDLER();
0310:
0311: if (XToolkit.saved_error != null
0312: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0313: throw new XException(
0314: "Cannot write XdndProxy property");
0315: }
0316: } finally {
0317: unsafe.freeMemory(data);
0318: data = 0;
0319: }
0320: } else {
0321: XDnDConstants.XA_XdndAware.DeleteProperty(embedder);
0322: XDnDConstants.XA_XdndProxy.DeleteProperty(embedder);
0323: }
0324: }
0325:
0326: /*
0327: * Gets and stores in the registry the embedder's XDnD drop site info
0328: * from the embedded.
0329: */
0330: public void registerEmbeddedDropSite(long embedded) {
0331: assert XToolkit.isAWTLockHeldByCurrentThread();
0332:
0333: boolean overriden = false;
0334: int version = 0;
0335: long proxy = 0;
0336: long newProxy = XDropTargetRegistry.getDnDProxyWindow();
0337: int status = 0;
0338:
0339: WindowPropertyGetter wpg1 = new WindowPropertyGetter(embedded,
0340: XDnDConstants.XA_XdndAware, 0, 1, false,
0341: XlibWrapper.AnyPropertyType);
0342:
0343: try {
0344: status = wpg1.execute(XToolkit.IgnoreBadWindowHandler);
0345:
0346: if (status == XlibWrapper.Success && wpg1.getData() != 0
0347: && wpg1.getActualType() == XAtom.XA_ATOM) {
0348:
0349: overriden = true;
0350: version = (int) Native.getLong(wpg1.getData());
0351: }
0352: } finally {
0353: wpg1.dispose();
0354: }
0355:
0356: /* XdndProxy is not supported for prior to XDnD version 4 */
0357: if (overriden && version >= 4) {
0358: WindowPropertyGetter wpg2 = new WindowPropertyGetter(
0359: embedded, XDnDConstants.XA_XdndProxy, 0, 1, false,
0360: XAtom.XA_WINDOW);
0361:
0362: try {
0363: status = wpg2.execute(XToolkit.IgnoreBadWindowHandler);
0364:
0365: if (status == XlibWrapper.Success
0366: && wpg2.getData() != 0
0367: && wpg2.getActualType() == XAtom.XA_WINDOW) {
0368:
0369: proxy = Native.getLong(wpg2.getData());
0370: }
0371: } finally {
0372: wpg2.dispose();
0373: }
0374:
0375: if (proxy != 0) {
0376: WindowPropertyGetter wpg3 = new WindowPropertyGetter(
0377: proxy, XDnDConstants.XA_XdndProxy, 0, 1, false,
0378: XAtom.XA_WINDOW);
0379:
0380: try {
0381: status = wpg3
0382: .execute(XToolkit.IgnoreBadWindowHandler);
0383:
0384: if (status != XlibWrapper.Success
0385: || wpg3.getData() == 0
0386: || wpg3.getActualType() != XAtom.XA_WINDOW
0387: || Native.getLong(wpg3.getData()) != proxy) {
0388:
0389: proxy = 0;
0390: } else {
0391: WindowPropertyGetter wpg4 = new WindowPropertyGetter(
0392: proxy, XDnDConstants.XA_XdndAware, 0,
0393: 1, false, XlibWrapper.AnyPropertyType);
0394:
0395: try {
0396: status = wpg4
0397: .execute(XToolkit.IgnoreBadWindowHandler);
0398:
0399: if (status != XlibWrapper.Success
0400: || wpg4.getData() == 0
0401: || wpg4.getActualType() != XAtom.XA_ATOM) {
0402:
0403: proxy = 0;
0404: }
0405: } finally {
0406: wpg4.dispose();
0407: }
0408: }
0409: } finally {
0410: wpg3.dispose();
0411: }
0412: }
0413: }
0414:
0415: putEmbedderRegistryEntry(embedded, overriden, version, proxy);
0416: }
0417:
0418: public boolean isProtocolSupported(long window) {
0419: assert XToolkit.isAWTLockHeldByCurrentThread();
0420:
0421: WindowPropertyGetter wpg1 = new WindowPropertyGetter(window,
0422: XDnDConstants.XA_XdndAware, 0, 1, false,
0423: XlibWrapper.AnyPropertyType);
0424:
0425: try {
0426: int status = wpg1.execute(XToolkit.IgnoreBadWindowHandler);
0427:
0428: if (status == XlibWrapper.Success && wpg1.getData() != 0
0429: && wpg1.getActualType() == XAtom.XA_ATOM) {
0430:
0431: return true;
0432: } else {
0433: return false;
0434: }
0435: } finally {
0436: wpg1.dispose();
0437: }
0438: }
0439:
0440: private boolean processXdndEnter(XClientMessageEvent xclient) {
0441: long source_win = 0;
0442: long source_win_mask = 0;
0443: int protocol_version = 0;
0444: int actions = DnDConstants.ACTION_NONE;
0445: boolean track = true;
0446: long[] formats = null;
0447:
0448: if (getSourceWindow() != 0) {
0449: return false;
0450: }
0451:
0452: if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)
0453: && getEmbedderRegistryEntry(xclient.get_window()) == null) {
0454: return false;
0455: }
0456:
0457: if (xclient.get_message_type() != XDnDConstants.XA_XdndEnter
0458: .getAtom()) {
0459: return false;
0460: }
0461:
0462: protocol_version = (int) ((xclient.get_data(1) & XDnDConstants.XDND_PROTOCOL_MASK) >> XDnDConstants.XDND_PROTOCOL_SHIFT);
0463:
0464: /* XDnD compliance only requires supporting version 3 and up. */
0465: if (protocol_version < XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
0466: return false;
0467: }
0468:
0469: /* Ignore the source if the protocol version is higher than we support. */
0470: if (protocol_version > XDnDConstants.XDND_PROTOCOL_VERSION) {
0471: return false;
0472: }
0473:
0474: source_win = xclient.get_data(0);
0475:
0476: /* Extract the list of supported actions. */
0477: if (protocol_version < 2) {
0478: /* Prior to XDnD version 2 only COPY action was supported. */
0479: actions = DnDConstants.ACTION_COPY;
0480: } else {
0481: WindowPropertyGetter wpg = new WindowPropertyGetter(
0482: source_win, XDnDConstants.XA_XdndActionList, 0,
0483: 0xFFFF, false, XAtom.XA_ATOM);
0484: try {
0485: wpg.execute(XToolkit.IgnoreBadWindowHandler);
0486:
0487: if (wpg.getActualType() == XAtom.XA_ATOM
0488: && wpg.getActualFormat() == 32) {
0489: long data = wpg.getData();
0490:
0491: for (int i = 0; i < wpg.getNumberOfItems(); i++) {
0492: actions |= XDnDConstants
0493: .getJavaActionForXDnDAction(Native
0494: .getLong(data, i));
0495: }
0496: } else {
0497: /*
0498: * According to XDnD protocol, XdndActionList is optional.
0499: * If XdndActionList is not set we try to guess which actions are
0500: * supported.
0501: */
0502: actions = DnDConstants.ACTION_COPY;
0503: track = true;
0504: }
0505: } finally {
0506: wpg.dispose();
0507: }
0508: }
0509:
0510: /* Extract the available data types. */
0511: if ((xclient.get_data(1) & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {
0512: WindowPropertyGetter wpg = new WindowPropertyGetter(
0513: source_win, XDnDConstants.XA_XdndTypeList, 0,
0514: 0xFFFF, false, XAtom.XA_ATOM);
0515: try {
0516: wpg.execute(XToolkit.IgnoreBadWindowHandler);
0517:
0518: if (wpg.getActualType() == XAtom.XA_ATOM
0519: && wpg.getActualFormat() == 32) {
0520: formats = Native.toLongs(wpg.getData(), wpg
0521: .getNumberOfItems());
0522: } else {
0523: formats = new long[0];
0524: }
0525: } finally {
0526: wpg.dispose();
0527: }
0528: } else {
0529: int countFormats = 0;
0530: long[] formats3 = new long[3];
0531:
0532: for (int i = 0; i < 3; i++) {
0533: long j;
0534: if ((j = xclient.get_data(2 + i)) != XlibWrapper.None) {
0535: formats3[countFormats++] = j;
0536: }
0537: }
0538:
0539: formats = new long[countFormats];
0540:
0541: System.arraycopy(formats3, 0, formats, 0, countFormats);
0542: }
0543:
0544: assert XToolkit.isAWTLockHeldByCurrentThread();
0545:
0546: /*
0547: * Select for StructureNotifyMask to receive DestroyNotify in case of source
0548: * crash.
0549: */
0550: XWindowAttributes wattr = new XWindowAttributes();
0551: try {
0552: XToolkit
0553: .WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
0554: int status = XlibWrapper.XGetWindowAttributes(XToolkit
0555: .getDisplay(), source_win, wattr.pData);
0556:
0557: XToolkit.RESTORE_XERROR_HANDLER();
0558:
0559: if (status == 0
0560: || (XToolkit.saved_error != null && XToolkit.saved_error
0561: .get_error_code() != XlibWrapper.Success)) {
0562: throw new XException("XGetWindowAttributes failed");
0563: }
0564:
0565: source_win_mask = wattr.get_your_event_mask();
0566: } finally {
0567: wattr.dispose();
0568: }
0569:
0570: XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
0571: XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
0572: source_win_mask | XlibWrapper.StructureNotifyMask);
0573:
0574: XToolkit.RESTORE_XERROR_HANDLER();
0575:
0576: if (XToolkit.saved_error != null
0577: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0578: throw new XException("XSelectInput failed");
0579: }
0580:
0581: sourceWindow = source_win;
0582: sourceWindowMask = source_win_mask;
0583: sourceProtocolVersion = protocol_version;
0584: sourceActions = actions;
0585: sourceFormats = formats;
0586: trackSourceActions = track;
0587:
0588: return true;
0589: }
0590:
0591: private boolean processXdndPosition(XClientMessageEvent xclient) {
0592: long time_stamp = (int) XlibWrapper.CurrentTime;
0593: long xdnd_action = 0;
0594: int java_action = DnDConstants.ACTION_NONE;
0595: int x = 0;
0596: int y = 0;
0597:
0598: /* Ignore XDnD messages from all other windows. */
0599: if (sourceWindow != xclient.get_data(0)) {
0600: return false;
0601: }
0602:
0603: XWindow xwindow = null;
0604: {
0605: XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient
0606: .get_window());
0607: if (xbasewindow instanceof XWindow) {
0608: xwindow = (XWindow) xbasewindow;
0609: }
0610: }
0611:
0612: x = (int) (xclient.get_data(2) >> 16);
0613: y = (int) (xclient.get_data(2) & 0xFFFF);
0614:
0615: if (xwindow == null) {
0616: long receiver = XDropTargetRegistry.getRegistry()
0617: .getEmbeddedDropSite(xclient.get_window(), x, y);
0618:
0619: if (receiver != 0) {
0620: XBaseWindow xbasewindow = XToolkit
0621: .windowToXWindow(receiver);
0622: if (xbasewindow instanceof XWindow) {
0623: xwindow = (XWindow) xbasewindow;
0624: }
0625: }
0626: }
0627:
0628: if (xwindow != null) {
0629: /* Translate mouse position from root coordinates
0630: to the target window coordinates. */
0631: Point p = xwindow.toLocal(x, y);
0632: x = p.x;
0633: y = p.y;
0634: }
0635:
0636: /* Time stamp - new in XDnD version 1. */
0637: if (sourceProtocolVersion > 0) {
0638: time_stamp = xclient.get_data(3);
0639: }
0640:
0641: /* User action - new in XDnD version 2. */
0642: if (sourceProtocolVersion > 1) {
0643: xdnd_action = xclient.get_data(4);
0644: } else {
0645: /* The default action is XdndActionCopy */
0646: xdnd_action = XDnDConstants.XA_XdndActionCopy.getAtom();
0647: }
0648:
0649: java_action = XDnDConstants
0650: .getJavaActionForXDnDAction(xdnd_action);
0651:
0652: if (trackSourceActions) {
0653: sourceActions |= java_action;
0654: }
0655:
0656: if (xwindow == null) {
0657: if (targetXWindow != null) {
0658: notifyProtocolListener(targetXWindow, x, y,
0659: DnDConstants.ACTION_NONE, xclient,
0660: MouseEvent.MOUSE_EXITED);
0661: }
0662: } else {
0663: int java_event_id = 0;
0664:
0665: if (targetXWindow == null) {
0666: java_event_id = MouseEvent.MOUSE_ENTERED;
0667: } else {
0668: java_event_id = MouseEvent.MOUSE_DRAGGED;
0669: }
0670:
0671: notifyProtocolListener(xwindow, x, y, java_action, xclient,
0672: java_event_id);
0673: }
0674:
0675: userAction = java_action;
0676: sourceX = x;
0677: sourceY = y;
0678: targetXWindow = xwindow;
0679:
0680: return true;
0681: }
0682:
0683: private boolean processXdndLeave(XClientMessageEvent xclient) {
0684: /* Ignore XDnD messages from all other windows. */
0685: if (sourceWindow != xclient.get_data(0)) {
0686: return false;
0687: }
0688:
0689: cleanup();
0690:
0691: return true;
0692: }
0693:
0694: private boolean processXdndDrop(XClientMessageEvent xclient) {
0695: /* Ignore XDnD messages from all other windows. */
0696: if (sourceWindow != xclient.get_data(0)) {
0697: return false;
0698: }
0699:
0700: if (targetXWindow != null) {
0701: notifyProtocolListener(targetXWindow, sourceX, sourceY,
0702: userAction, xclient, MouseEvent.MOUSE_RELEASED);
0703: }
0704:
0705: return true;
0706: }
0707:
0708: public int getMessageType(XClientMessageEvent xclient) {
0709: long messageType = xclient.get_message_type();
0710:
0711: if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {
0712: return ENTER_MESSAGE;
0713: } else if (messageType == XDnDConstants.XA_XdndPosition
0714: .getAtom()) {
0715: return MOTION_MESSAGE;
0716: } else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {
0717: return LEAVE_MESSAGE;
0718: } else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {
0719: return DROP_MESSAGE;
0720: } else {
0721: return UNKNOWN_MESSAGE;
0722: }
0723: }
0724:
0725: protected boolean processClientMessageImpl(
0726: XClientMessageEvent xclient) {
0727: long messageType = xclient.get_message_type();
0728:
0729: if (messageType == XDnDConstants.XA_XdndEnter.getAtom()) {
0730: return processXdndEnter(xclient);
0731: } else if (messageType == XDnDConstants.XA_XdndPosition
0732: .getAtom()) {
0733: return processXdndPosition(xclient);
0734: } else if (messageType == XDnDConstants.XA_XdndLeave.getAtom()) {
0735: return processXdndLeave(xclient);
0736: } else if (messageType == XDnDConstants.XA_XdndDrop.getAtom()) {
0737: return processXdndDrop(xclient);
0738: } else {
0739: return false;
0740: }
0741: }
0742:
0743: protected void sendEnterMessageToToplevel(long toplevel,
0744: XClientMessageEvent xclient) {
0745: /* flags */
0746: long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;
0747: if (sourceFormats != null && sourceFormats.length > 3) {
0748: data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
0749: }
0750: long data2 = sourceFormats.length > 0 ? sourceFormats[0] : 0;
0751: long data3 = sourceFormats.length > 1 ? sourceFormats[1] : 0;
0752: long data4 = sourceFormats.length > 2 ? sourceFormats[2] : 0;
0753: sendEnterMessageToToplevelImpl(toplevel, xclient.get_data(0),
0754: data1, data2, data3, data4);
0755:
0756: }
0757:
0758: private void sendEnterMessageToToplevelImpl(long toplevel,
0759: long sourceWindow, long data1, long data2, long data3,
0760: long data4) {
0761: XClientMessageEvent enter = new XClientMessageEvent();
0762: try {
0763: enter.set_type((int) XlibWrapper.ClientMessage);
0764: enter.set_window(toplevel);
0765: enter.set_format(32);
0766: enter
0767: .set_message_type(XDnDConstants.XA_XdndEnter
0768: .getAtom());
0769: /* XID of the source window */
0770: enter.set_data(0, sourceWindow);
0771: enter.set_data(1, data1);
0772: enter.set_data(2, data2);
0773: enter.set_data(3, data3);
0774: enter.set_data(4, data4);
0775:
0776: forwardClientMessageToToplevel(toplevel, enter);
0777: } finally {
0778: enter.dispose();
0779: }
0780: }
0781:
0782: protected void sendLeaveMessageToToplevel(long toplevel,
0783: XClientMessageEvent xclient) {
0784: sendLeaveMessageToToplevelImpl(toplevel, xclient.get_data(0));
0785: }
0786:
0787: protected void sendLeaveMessageToToplevelImpl(long toplevel,
0788: long sourceWindow) {
0789: XClientMessageEvent leave = new XClientMessageEvent();
0790: try {
0791: leave.set_type((int) XlibWrapper.ClientMessage);
0792: leave.set_window(toplevel);
0793: leave.set_format(32);
0794: leave
0795: .set_message_type(XDnDConstants.XA_XdndLeave
0796: .getAtom());
0797: /* XID of the source window */
0798: leave.set_data(0, sourceWindow);
0799: /* flags */
0800: leave.set_data(1, 0);
0801:
0802: forwardClientMessageToToplevel(toplevel, leave);
0803: } finally {
0804: leave.dispose();
0805: }
0806: }
0807:
0808: public boolean sendResponse(long ctxt, int eventID, int action) {
0809: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0810:
0811: if (xclient.get_message_type() != XDnDConstants.XA_XdndPosition
0812: .getAtom()) {
0813:
0814: return false;
0815: }
0816:
0817: if (eventID == MouseEvent.MOUSE_EXITED) {
0818: action = DnDConstants.ACTION_NONE;
0819: }
0820:
0821: XClientMessageEvent msg = new XClientMessageEvent();
0822: try {
0823: msg.set_type((int) XlibWrapper.ClientMessage);
0824: msg.set_window(xclient.get_data(0));
0825: msg.set_format(32);
0826: msg.set_message_type(XDnDConstants.XA_XdndStatus.getAtom());
0827: /* target window */
0828: msg.set_data(0, xclient.get_window());
0829: /* flags */
0830: long flags = 0;
0831: if (action != DnDConstants.ACTION_NONE) {
0832: flags |= XDnDConstants.XDND_ACCEPT_DROP_FLAG;
0833: }
0834: msg.set_data(1, flags);
0835: /* specify an empty rectangle */
0836: msg.set_data(2, 0); /* x, y */
0837: msg.set_data(3, 0); /* w, h */
0838: /* action accepted by the target */
0839: msg.set_data(4, XDnDConstants
0840: .getXDnDActionForJavaAction(action));
0841:
0842: XToolkit.awtLock();
0843: try {
0844: XlibWrapper.XSendEvent(XToolkit.getDisplay(), xclient
0845: .get_data(0), false, XlibWrapper.NoEventMask,
0846: msg.pData);
0847: } finally {
0848: XToolkit.awtUnlock();
0849: }
0850: } finally {
0851: msg.dispose();
0852: }
0853:
0854: return true;
0855: }
0856:
0857: public Object getData(long ctxt, long format)
0858: throws IllegalArgumentException, IOException {
0859: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0860: long message_type = xclient.get_message_type();
0861: long time_stamp = XlibWrapper.CurrentTime;
0862:
0863: // NOTE: we assume that the source supports at least version 1, so we
0864: // can use the time stamp
0865: if (message_type == XDnDConstants.XA_XdndPosition.getAtom()) {
0866: // X server time is an unsigned 32-bit number!
0867: time_stamp = xclient.get_data(3) & 0xFFFFFFFFL;
0868: } else if (message_type == XDnDConstants.XA_XdndDrop.getAtom()) {
0869: // X server time is an unsigned 32-bit number!
0870: time_stamp = xclient.get_data(2) & 0xFFFFFFFFL;
0871: } else {
0872: throw new IllegalArgumentException();
0873: }
0874:
0875: return XDnDConstants.XDnDSelection.getData(format, time_stamp);
0876: }
0877:
0878: public boolean sendDropDone(long ctxt, boolean success,
0879: int dropAction) {
0880: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0881:
0882: if (xclient.get_message_type() != XDnDConstants.XA_XdndDrop
0883: .getAtom()) {
0884: return false;
0885: }
0886:
0887: /*
0888: * The XDnD protocol recommends that the target requests the special
0889: * target DELETE in case if the drop action is XdndActionMove.
0890: */
0891: if (dropAction == DnDConstants.ACTION_MOVE && success) {
0892:
0893: long time_stamp = xclient.get_data(2);
0894: long xdndSelectionAtom = XDnDConstants.XDnDSelection
0895: .getSelectionAtom().getAtom();
0896:
0897: XToolkit.awtLock();
0898: try {
0899: XlibWrapper.XConvertSelection(XToolkit.getDisplay(),
0900: xdndSelectionAtom, XAtom.get("DELETE")
0901: .getAtom(), XAtom.get("XAWT_SELECTION")
0902: .getAtom(), XWindow.getXAWTRootWindow()
0903: .getWindow(), time_stamp);
0904: } finally {
0905: XToolkit.awtUnlock();
0906: }
0907: }
0908:
0909: XClientMessageEvent msg = new XClientMessageEvent();
0910: try {
0911: msg.set_type((int) XlibWrapper.ClientMessage);
0912: msg.set_window(xclient.get_data(0));
0913: msg.set_format(32);
0914: msg.set_message_type(XDnDConstants.XA_XdndFinished
0915: .getAtom());
0916: msg.set_data(0, xclient.get_window()); /* target window */
0917: msg.set_data(1, 0); /* flags */
0918: /* specify an empty rectangle */
0919: msg.set_data(2, 0);
0920: if (sourceProtocolVersion >= 5) {
0921: if (success) {
0922: msg
0923: .set_data(1,
0924: XDnDConstants.XDND_ACCEPT_DROP_FLAG);
0925: }
0926: /* action performed by the target */
0927: msg.set_data(2, XDnDConstants
0928: .getXDnDActionForJavaAction(dropAction));
0929: }
0930: msg.set_data(3, 0);
0931: msg.set_data(4, 0);
0932:
0933: XToolkit.awtLock();
0934: try {
0935: XlibWrapper.XSendEvent(XToolkit.getDisplay(), xclient
0936: .get_data(0), false, XlibWrapper.NoEventMask,
0937: msg.pData);
0938: } finally {
0939: XToolkit.awtUnlock();
0940: }
0941: } finally {
0942: msg.dispose();
0943: }
0944:
0945: /*
0946: * Flush the buffer to guarantee that the drop completion event is sent
0947: * to the source before the method returns.
0948: */
0949: XToolkit.awtLock();
0950: try {
0951: XlibWrapper.XFlush(XToolkit.getDisplay());
0952: } finally {
0953: XToolkit.awtUnlock();
0954: }
0955:
0956: /* Trick to prevent cleanup() from posting dragExit */
0957: targetXWindow = null;
0958:
0959: /* Cannot do cleanup before the drop finishes as we may need
0960: source protocol version to send drop finished message. */
0961: cleanup();
0962: return true;
0963: }
0964:
0965: public final long getSourceWindow() {
0966: return sourceWindow;
0967: }
0968:
0969: /**
0970: * Reset the state of the object.
0971: */
0972: public void cleanup() {
0973: // Clear the reference to this protocol.
0974: XDropTargetEventProcessor.reset();
0975:
0976: if (targetXWindow != null) {
0977: notifyProtocolListener(targetXWindow, 0, 0,
0978: DnDConstants.ACTION_NONE, null,
0979: MouseEvent.MOUSE_EXITED);
0980: }
0981:
0982: if (sourceWindow != 0) {
0983: XToolkit.awtLock();
0984: try {
0985: XToolkit
0986: .WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
0987: XlibWrapper.XSelectInput(XToolkit.getDisplay(),
0988: sourceWindow, sourceWindowMask);
0989: XToolkit.RESTORE_XERROR_HANDLER();
0990: } finally {
0991: XToolkit.awtUnlock();
0992: }
0993: }
0994:
0995: sourceWindow = 0;
0996: sourceWindowMask = 0;
0997: sourceProtocolVersion = 0;
0998: sourceActions = DnDConstants.ACTION_NONE;
0999: sourceFormats = null;
1000: trackSourceActions = false;
1001: userAction = DnDConstants.ACTION_NONE;
1002: sourceX = 0;
1003: sourceY = 0;
1004: targetXWindow = null;
1005: }
1006:
1007: public boolean isDragOverComponent() {
1008: return targetXWindow != null;
1009: }
1010:
1011: public void adjustEventForForwarding(XClientMessageEvent xclient,
1012: EmbedderRegistryEntry entry) {
1013: /* Adjust the event to match the XDnD protocol version. */
1014: int version = entry.getVersion();
1015: if (xclient.get_message_type() == XDnDConstants.XA_XdndEnter
1016: .getAtom()) {
1017: int min_version = sourceProtocolVersion < version ? sourceProtocolVersion
1018: : version;
1019: long data1 = min_version << XDnDConstants.XDND_PROTOCOL_SHIFT;
1020: if (sourceFormats != null && sourceFormats.length > 3) {
1021: data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
1022: }
1023: if (logger.isLoggable(Level.FINEST)) {
1024: logger.finest(" "
1025: + " entryVersion="
1026: + version
1027: + " sourceProtocolVersion="
1028: + sourceProtocolVersion
1029: + " sourceFormats.length="
1030: + (sourceFormats != null ? sourceFormats.length
1031: : 0));
1032: }
1033: xclient.set_data(1, data1);
1034: }
1035: }
1036:
1037: private void notifyProtocolListener(XWindow xwindow, int x, int y,
1038: int dropAction, XClientMessageEvent xclient, int eventID) {
1039: long nativeCtxt = 0;
1040:
1041: // Make a copy of the passed XClientMessageEvent structure, since
1042: // the original structure can be freed before this
1043: // SunDropTargetEvent is dispatched.
1044: if (xclient != null) {
1045: int size = new XClientMessageEvent(nativeCtxt).getSize();
1046:
1047: nativeCtxt = unsafe.allocateMemory(size + 4
1048: * Native.getLongSize());
1049:
1050: unsafe.copyMemory(xclient.pData, nativeCtxt, size);
1051:
1052: long data1 = sourceProtocolVersion << XDnDConstants.XDND_PROTOCOL_SHIFT;
1053: if (sourceFormats != null && sourceFormats.length > 3) {
1054: data1 |= XDnDConstants.XDND_DATA_TYPES_BIT;
1055: }
1056: // Append information from the latest XdndEnter event.
1057: Native.putLong(nativeCtxt + size, data1);
1058: Native.putLong(nativeCtxt + size + Native.getLongSize(),
1059: sourceFormats.length > 0 ? sourceFormats[0] : 0);
1060: Native.putLong(
1061: nativeCtxt + size + 2 * Native.getLongSize(),
1062: sourceFormats.length > 1 ? sourceFormats[1] : 0);
1063: Native.putLong(
1064: nativeCtxt + size + 3 * Native.getLongSize(),
1065: sourceFormats.length > 2 ? sourceFormats[2] : 0);
1066: }
1067:
1068: getProtocolListener().handleDropTargetNotification(xwindow, x,
1069: y, dropAction, sourceActions, sourceFormats,
1070: nativeCtxt, eventID);
1071: }
1072:
1073: /*
1074: * The methods/fields defined below are executed/accessed only on
1075: * the toolkit thread.
1076: * The methods/fields defined below are executed/accessed only on the event
1077: * dispatch thread.
1078: */
1079:
1080: public boolean forwardEventToEmbedded(long embedded, long ctxt,
1081: int eventID) {
1082: if (logger.isLoggable(Level.FINEST)) {
1083: logger
1084: .finest(" ctxt="
1085: + ctxt
1086: + " type="
1087: + (ctxt != 0 ? getMessageType(new XClientMessageEvent(
1088: ctxt))
1089: : 0)
1090: + " prevCtxt="
1091: + prevCtxt
1092: + " prevType="
1093: + (prevCtxt != 0 ? getMessageType(new XClientMessageEvent(
1094: prevCtxt))
1095: : 0));
1096: }
1097: if ((ctxt == 0 || getMessageType(new XClientMessageEvent(ctxt)) == UNKNOWN_MESSAGE)
1098: && (prevCtxt == 0 || getMessageType(new XClientMessageEvent(
1099: prevCtxt)) == UNKNOWN_MESSAGE)) {
1100: return false;
1101: }
1102:
1103: // The size of XClientMessageEvent structure.
1104: int size = XClientMessageEvent.getSize();
1105:
1106: if (ctxt != 0) {
1107: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
1108: if (!overXEmbedClient) {
1109: long data1 = Native.getLong(ctxt + size);
1110: long data2 = Native.getLong(ctxt + size
1111: + Native.getLongSize());
1112: long data3 = Native.getLong(ctxt + size + 2
1113: * Native.getLongSize());
1114: long data4 = Native.getLong(ctxt + size + 3
1115: * Native.getLongSize());
1116:
1117: if (logger.isLoggable(Level.FINEST)) {
1118: logger.finest(" 1 " + " embedded="
1119: + embedded + " source="
1120: + xclient.get_data(0) + " data1=" + data1
1121: + " data2=" + data2 + " data3=" + data3
1122: + " data4=" + data4);
1123: }
1124:
1125: // Copy XdndTypeList from source to proxy.
1126: if ((data1 & XDnDConstants.XDND_DATA_TYPES_BIT) != 0) {
1127: WindowPropertyGetter wpg = new WindowPropertyGetter(
1128: xclient.get_data(0),
1129: XDnDConstants.XA_XdndTypeList, 0, 0xFFFF,
1130: false, XAtom.XA_ATOM);
1131: try {
1132: wpg.execute(XToolkit.IgnoreBadWindowHandler);
1133:
1134: if (wpg.getActualType() == XAtom.XA_ATOM
1135: && wpg.getActualFormat() == 32) {
1136:
1137: XToolkit.awtLock();
1138: try {
1139: XToolkit
1140: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
1141: XDnDConstants.XA_XdndTypeList
1142: .setAtomData(xclient
1143: .get_window(),
1144: XAtom.XA_ATOM, wpg
1145: .getData(),
1146: wpg.getNumberOfItems());
1147: XToolkit.RESTORE_XERROR_HANDLER();
1148:
1149: if (XToolkit.saved_error != null
1150: && XToolkit.saved_error
1151: .get_error_code() != XlibWrapper.Success) {
1152: if (logger
1153: .isLoggable(Level.WARNING)) {
1154: logger
1155: .warning("Cannot set XdndTypeList on the proxy window");
1156: }
1157: }
1158: } finally {
1159: XToolkit.awtUnlock();
1160: }
1161: } else {
1162: if (logger.isLoggable(Level.WARNING)) {
1163: logger
1164: .warning("Cannot read XdndTypeList from the source window");
1165: }
1166: }
1167: } finally {
1168: wpg.dispose();
1169: }
1170: }
1171: XDragSourceContextPeer.setProxyModeSourceWindow(xclient
1172: .get_data(0));
1173:
1174: sendEnterMessageToToplevelImpl(embedded, xclient
1175: .get_window(), data1, data2, data3, data4);
1176: overXEmbedClient = true;
1177: }
1178:
1179: if (logger.isLoggable(Level.FINEST)) {
1180: logger.finest(" 2 " + " embedded=" + embedded
1181: + " xclient=" + xclient);
1182: }
1183:
1184: /* Make a copy of the original event, since we are going to modify the
1185: event while it still can be referenced from other Java events. */
1186: {
1187: XClientMessageEvent copy = new XClientMessageEvent();
1188: unsafe.copyMemory(xclient.pData, copy.pData, copy
1189: .getSize());
1190:
1191: copy.set_data(0, xclient.get_window());
1192:
1193: forwardClientMessageToToplevel(embedded, copy);
1194: }
1195: }
1196:
1197: if (eventID == MouseEvent.MOUSE_EXITED) {
1198: if (overXEmbedClient) {
1199: if (ctxt != 0 || prevCtxt != 0) {
1200: // Last chance to send XdndLeave to the XEmbed client.
1201: XClientMessageEvent xclient = ctxt != 0 ? new XClientMessageEvent(
1202: ctxt)
1203: : new XClientMessageEvent(prevCtxt);
1204: sendLeaveMessageToToplevelImpl(embedded, xclient
1205: .get_window());
1206: }
1207: overXEmbedClient = false;
1208: // We have to clear the proxy mode source window here,
1209: // when the drag exits the XEmbedCanvasPeer.
1210: // NOTE: at this point the XEmbed client still might have some
1211: // drag notifications to process and it will send responses to
1212: // us. With the proxy mode source window cleared we won't be
1213: // able to forward these responses to the actual source. This is
1214: // not a problem if the drag operation was initiated in this
1215: // JVM. However, if it was initiated in another processes the
1216: // responses will be lost. We bear with it for now, as it seems
1217: // there is no other reliable point to clear.
1218: XDragSourceContextPeer.setProxyModeSourceWindow(0);
1219: }
1220: }
1221:
1222: if (eventID == MouseEvent.MOUSE_RELEASED) {
1223: overXEmbedClient = false;
1224: cleanup();
1225: }
1226:
1227: if (prevCtxt != 0) {
1228: unsafe.freeMemory(prevCtxt);
1229: prevCtxt = 0;
1230: }
1231:
1232: if (ctxt != 0 && overXEmbedClient) {
1233: prevCtxt = unsafe.allocateMemory(size + 4
1234: * Native.getLongSize());
1235:
1236: unsafe.copyMemory(ctxt, prevCtxt, size + 4
1237: * Native.getLongSize());
1238: }
1239:
1240: return true;
1241: }
1242:
1243: public boolean isXEmbedSupported() {
1244: return true;
1245: }
1246: }
|