0001: /*
0002: * Copyright 2003-2007 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 sun.misc.Unsafe;
0037:
0038: /**
0039: * XDropTargetProtocol implementation for Motif DnD protocol.
0040: *
0041: * @since 1.5
0042: */
0043: class MotifDnDDropTargetProtocol extends XDropTargetProtocol {
0044: private static final Unsafe unsafe = XlibWrapper.unsafe;
0045:
0046: private long sourceWindow = 0;
0047: private long sourceWindowMask = 0;
0048: private int sourceProtocolVersion = 0;
0049: private int sourceActions = DnDConstants.ACTION_NONE;
0050: private long[] sourceFormats = null;
0051: private long sourceAtom = 0;
0052: private int userAction = DnDConstants.ACTION_NONE;
0053: private int sourceX = 0;
0054: private int sourceY = 0;
0055: private XWindow targetXWindow = null;
0056: private boolean topLevelLeavePostponed = false;
0057:
0058: protected MotifDnDDropTargetProtocol(
0059: XDropTargetProtocolListener listener) {
0060: super (listener);
0061: }
0062:
0063: /**
0064: * Creates an instance associated with the specified listener.
0065: *
0066: * @throws NullPointerException if listener is <code>null</code>.
0067: */
0068: static XDropTargetProtocol createInstance(
0069: XDropTargetProtocolListener listener) {
0070: return new MotifDnDDropTargetProtocol(listener);
0071: }
0072:
0073: public String getProtocolName() {
0074: return XDragAndDropProtocols.MotifDnD;
0075: }
0076:
0077: public void registerDropTarget(long window) {
0078: assert XToolkit.isAWTLockHeldByCurrentThread();
0079:
0080: MotifDnDConstants.writeDragReceiverInfoStruct(window);
0081: }
0082:
0083: public void unregisterDropTarget(long window) {
0084: assert XToolkit.isAWTLockHeldByCurrentThread();
0085:
0086: MotifDnDConstants.XA_MOTIF_ATOM_0.DeleteProperty(window);
0087: }
0088:
0089: public void registerEmbedderDropSite(long embedder) {
0090: assert XToolkit.isAWTLockHeldByCurrentThread();
0091:
0092: boolean overriden = false;
0093: int version = 0;
0094: long proxy = 0;
0095: long newProxy = XDropTargetRegistry.getDnDProxyWindow();
0096: int status = 0;
0097: long data = 0;
0098: int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
0099:
0100: WindowPropertyGetter wpg = new WindowPropertyGetter(embedder,
0101: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 0,
0102: 0xFFFF, false, XlibWrapper.AnyPropertyType);
0103:
0104: try {
0105: status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
0106:
0107: /*
0108: * DragICCI.h:
0109: *
0110: * typedef struct _xmDragReceiverInfoStruct{
0111: * BYTE byte_order;
0112: * BYTE protocol_version;
0113: * BYTE drag_protocol_style;
0114: * BYTE pad1;
0115: * CARD32 proxy_window B32;
0116: * CARD16 num_drop_sites B16;
0117: * CARD16 pad2 B16;
0118: * CARD32 heap_offset B32;
0119: * } xmDragReceiverInfoStruct;
0120: */
0121: if (status == (int) XlibWrapper.Success
0122: && wpg.getData() != 0
0123: && wpg.getActualType() != 0
0124: && wpg.getActualFormat() == 8
0125: && wpg.getNumberOfItems() >= MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
0126:
0127: overriden = true;
0128: data = wpg.getData();
0129: dataSize = wpg.getNumberOfItems();
0130:
0131: byte byteOrderByte = unsafe.getByte(data);
0132:
0133: {
0134: int tproxy = unsafe.getInt(data + 4);
0135: if (byteOrderByte != MotifDnDConstants
0136: .getByteOrderByte()) {
0137: tproxy = MotifDnDConstants.Swapper.swap(tproxy);
0138: }
0139: proxy = tproxy;
0140: }
0141:
0142: if (proxy == newProxy) {
0143: // Embedder already registered.
0144: return;
0145: }
0146:
0147: {
0148: int tproxy = (int) newProxy;
0149: if (byteOrderByte != MotifDnDConstants
0150: .getByteOrderByte()) {
0151: tproxy = MotifDnDConstants.Swapper.swap(tproxy);
0152: }
0153: unsafe.putInt(data + 4, tproxy);
0154: }
0155: } else {
0156: data = unsafe.allocateMemory(dataSize);
0157:
0158: unsafe.putByte(data, MotifDnDConstants
0159: .getByteOrderByte()); /* byte order */
0160: unsafe.putByte(data + 1,
0161: MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
0162: unsafe.putByte(data + 2,
0163: (byte) MotifDnDConstants.MOTIF_DYNAMIC_STYLE); /* protocol style */
0164: unsafe.putByte(data + 3, (byte) 0); /* pad */
0165: unsafe.putInt(data + 4, (int) newProxy); /* proxy window */
0166: unsafe.putShort(data + 8, (short) 0); /* num_drop_sites */
0167: unsafe.putShort(data + 10, (short) 0); /* pad */
0168: unsafe.putInt(data + 12, dataSize);
0169: }
0170:
0171: XToolkit
0172: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0173: XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
0174: embedder,
0175: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO
0176: .getAtom(),
0177: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO
0178: .getAtom(), 8, XlibWrapper.PropModeReplace,
0179: data, dataSize);
0180: XToolkit.RESTORE_XERROR_HANDLER();
0181:
0182: if (XToolkit.saved_error != null
0183: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0184: throw new XException(
0185: "Cannot write Motif receiver info property");
0186: }
0187: } finally {
0188: if (!overriden) {
0189: unsafe.freeMemory(data);
0190: data = 0;
0191: }
0192: wpg.dispose();
0193: }
0194:
0195: putEmbedderRegistryEntry(embedder, overriden, version, proxy);
0196: }
0197:
0198: public void unregisterEmbedderDropSite(long embedder) {
0199: assert XToolkit.isAWTLockHeldByCurrentThread();
0200:
0201: EmbedderRegistryEntry entry = getEmbedderRegistryEntry(embedder);
0202:
0203: if (entry == null) {
0204: return;
0205: }
0206:
0207: if (entry.isOverriden()) {
0208: int status = 0;
0209:
0210: WindowPropertyGetter wpg = new WindowPropertyGetter(
0211: embedder,
0212: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 0,
0213: 0xFFFF, false, XlibWrapper.AnyPropertyType);
0214:
0215: try {
0216: status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
0217:
0218: /*
0219: * DragICCI.h:
0220: *
0221: * typedef struct _xmDragReceiverInfoStruct{
0222: * BYTE byte_order;
0223: * BYTE protocol_version;
0224: * BYTE drag_protocol_style;
0225: * BYTE pad1;
0226: * CARD32 proxy_window B32;
0227: * CARD16 num_drop_sites B16;
0228: * CARD16 pad2 B16;
0229: * CARD32 heap_offset B32;
0230: * } xmDragReceiverInfoStruct;
0231: */
0232: if (status == (int) XlibWrapper.Success
0233: && wpg.getData() != 0
0234: && wpg.getActualType() != 0
0235: && wpg.getActualFormat() == 8
0236: && wpg.getNumberOfItems() >= MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
0237:
0238: int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
0239: long data = wpg.getData();
0240: byte byteOrderByte = unsafe.getByte(data);
0241:
0242: int tproxy = (int) entry.getProxy();
0243: if (MotifDnDConstants.getByteOrderByte() != byteOrderByte) {
0244: tproxy = MotifDnDConstants.Swapper.swap(tproxy);
0245: }
0246:
0247: unsafe.putInt(data + 4, tproxy);
0248:
0249: XToolkit
0250: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
0251: XlibWrapper
0252: .XChangeProperty(
0253: XToolkit.getDisplay(),
0254: embedder,
0255: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO
0256: .getAtom(),
0257: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO
0258: .getAtom(), 8,
0259: XlibWrapper.PropModeReplace, data,
0260: dataSize);
0261: XToolkit.RESTORE_XERROR_HANDLER();
0262:
0263: if (XToolkit.saved_error != null
0264: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0265: throw new XException(
0266: "Cannot write Motif receiver info property");
0267: }
0268: }
0269: } finally {
0270: wpg.dispose();
0271: }
0272: } else {
0273: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO
0274: .DeleteProperty(embedder);
0275: }
0276: }
0277:
0278: /*
0279: * Gets and stores in the registry the embedder's Motif DnD drop site info
0280: * from the embedded.
0281: */
0282: public void registerEmbeddedDropSite(long embedded) {
0283: assert XToolkit.isAWTLockHeldByCurrentThread();
0284:
0285: boolean overriden = false;
0286: int version = 0;
0287: long proxy = 0;
0288: int status = 0;
0289:
0290: WindowPropertyGetter wpg = new WindowPropertyGetter(embedded,
0291: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 0,
0292: 0xFFFF, false, XlibWrapper.AnyPropertyType);
0293:
0294: try {
0295: status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
0296:
0297: /*
0298: * DragICCI.h:
0299: *
0300: * typedef struct _xmDragReceiverInfoStruct{
0301: * BYTE byte_order;
0302: * BYTE protocol_version;
0303: * BYTE drag_protocol_style;
0304: * BYTE pad1;
0305: * CARD32 proxy_window B32;
0306: * CARD16 num_drop_sites B16;
0307: * CARD16 pad2 B16;
0308: * CARD32 heap_offset B32;
0309: * } xmDragReceiverInfoStruct;
0310: */
0311: if (status == (int) XlibWrapper.Success
0312: && wpg.getData() != 0
0313: && wpg.getActualType() != 0
0314: && wpg.getActualFormat() == 8
0315: && wpg.getNumberOfItems() >= MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
0316:
0317: overriden = true;
0318: long data = wpg.getData();
0319:
0320: byte byteOrderByte = unsafe.getByte(data);
0321:
0322: {
0323: int tproxy = unsafe.getInt(data + 4);
0324: if (byteOrderByte != MotifDnDConstants
0325: .getByteOrderByte()) {
0326: tproxy = MotifDnDConstants.Swapper.swap(tproxy);
0327: }
0328: proxy = tproxy;
0329: }
0330: }
0331: } finally {
0332: wpg.dispose();
0333: }
0334:
0335: putEmbedderRegistryEntry(embedded, overriden, version, proxy);
0336: }
0337:
0338: public boolean isProtocolSupported(long window) {
0339: WindowPropertyGetter wpg = new WindowPropertyGetter(window,
0340: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 0,
0341: 0xFFFF, false, XlibWrapper.AnyPropertyType);
0342:
0343: try {
0344: int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
0345:
0346: if (status == (int) XlibWrapper.Success
0347: && wpg.getData() != 0
0348: && wpg.getActualType() != 0
0349: && wpg.getActualFormat() == 8
0350: && wpg.getNumberOfItems() >= MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
0351: return true;
0352: } else {
0353: return false;
0354: }
0355: } finally {
0356: wpg.dispose();
0357: }
0358: }
0359:
0360: private boolean processTopLevelEnter(XClientMessageEvent xclient) {
0361: assert XToolkit.isAWTLockHeldByCurrentThread();
0362:
0363: if (targetXWindow != null || sourceWindow != 0) {
0364: return false;
0365: }
0366:
0367: if (!(XToolkit.windowToXWindow(xclient.get_window()) instanceof XWindow)
0368: && getEmbedderRegistryEntry(xclient.get_window()) == null) {
0369: return false;
0370: }
0371:
0372: long source_win = 0;
0373: long source_win_mask = 0;
0374: int protocol_version = 0;
0375: long property_atom = 0;
0376: long[] formats = null;
0377:
0378: {
0379: long data = xclient.get_data();
0380: byte eventByteOrder = unsafe.getByte(data + 1);
0381: source_win = MotifDnDConstants.Swapper.getInt(data + 8,
0382: eventByteOrder);
0383: property_atom = MotifDnDConstants.Swapper.getInt(data + 12,
0384: eventByteOrder);
0385: }
0386:
0387: /* Extract the available data types. */
0388: {
0389: WindowPropertyGetter wpg = new WindowPropertyGetter(
0390: source_win, XAtom.get(property_atom), 0, 0xFFFF,
0391: false,
0392: MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO
0393: .getAtom());
0394:
0395: try {
0396: int status = wpg
0397: .execute(XToolkit.IgnoreBadWindowHandler);
0398:
0399: if (status == XlibWrapper.Success
0400: && wpg.getData() != 0
0401: && wpg.getActualType() == MotifDnDConstants.XA_MOTIF_DRAG_INITIATOR_INFO
0402: .getAtom()
0403: && wpg.getActualFormat() == 8
0404: && wpg.getNumberOfItems() == MotifDnDConstants.MOTIF_INITIATOR_INFO_SIZE) {
0405:
0406: long data = wpg.getData();
0407: byte propertyByteOrder = unsafe.getByte(data);
0408:
0409: protocol_version = unsafe.getByte(data + 1);
0410:
0411: if (protocol_version != MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION) {
0412: return false;
0413: }
0414:
0415: int index = MotifDnDConstants.Swapper.getShort(
0416: data + 2, propertyByteOrder);
0417:
0418: formats = MotifDnDConstants
0419: .getTargetListForIndex(index);
0420: } else {
0421: formats = new long[0];
0422: }
0423: } finally {
0424: wpg.dispose();
0425: }
0426: }
0427:
0428: /*
0429: * Select for StructureNotifyMask to receive DestroyNotify in case of source
0430: * crash.
0431: */
0432: XWindowAttributes wattr = new XWindowAttributes();
0433: try {
0434: XToolkit
0435: .WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
0436: int status = XlibWrapper.XGetWindowAttributes(XToolkit
0437: .getDisplay(), source_win, wattr.pData);
0438:
0439: XToolkit.RESTORE_XERROR_HANDLER();
0440:
0441: if (status == 0
0442: || (XToolkit.saved_error != null && XToolkit.saved_error
0443: .get_error_code() != XlibWrapper.Success)) {
0444: throw new XException("XGetWindowAttributes failed");
0445: }
0446:
0447: source_win_mask = wattr.get_your_event_mask();
0448: } finally {
0449: wattr.dispose();
0450: }
0451:
0452: XToolkit.WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
0453: XlibWrapper.XSelectInput(XToolkit.getDisplay(), source_win,
0454: source_win_mask | XlibWrapper.StructureNotifyMask);
0455:
0456: XToolkit.RESTORE_XERROR_HANDLER();
0457:
0458: if (XToolkit.saved_error != null
0459: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
0460: throw new XException("XSelectInput failed");
0461: }
0462:
0463: sourceWindow = source_win;
0464: sourceWindowMask = source_win_mask;
0465: sourceProtocolVersion = protocol_version;
0466: /*
0467: * TOP_LEVEL_ENTER doesn't communicate the list of supported actions
0468: * They are provided in DRAG_MOTION.
0469: */
0470: sourceActions = DnDConstants.ACTION_NONE;
0471: sourceFormats = formats;
0472: sourceAtom = property_atom;
0473:
0474: return true;
0475: }
0476:
0477: private boolean processDragMotion(XClientMessageEvent xclient) {
0478: long data = xclient.get_data();
0479: byte eventByteOrder = unsafe.getByte(data + 1);
0480: byte eventReason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0481: int x = 0;
0482: int y = 0;
0483:
0484: short flags = MotifDnDConstants.Swapper.getShort(data + 2,
0485: eventByteOrder);
0486:
0487: int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >> MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
0488: int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >> MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
0489:
0490: int java_action = MotifDnDConstants
0491: .getJavaActionsForMotifActions(motif_action);
0492: int java_actions = MotifDnDConstants
0493: .getJavaActionsForMotifActions(motif_actions);
0494:
0495: /* Append source window id to the event data, so that we can send the
0496: response properly. */
0497: {
0498: int win = (int) sourceWindow;
0499: if (eventByteOrder != MotifDnDConstants.getByteOrderByte()) {
0500: win = MotifDnDConstants.Swapper.swap(win);
0501: }
0502: unsafe.putInt(data + 12, win);
0503: }
0504:
0505: XWindow xwindow = null;
0506: {
0507: XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient
0508: .get_window());
0509: if (xbasewindow instanceof XWindow) {
0510: xwindow = (XWindow) xbasewindow;
0511: }
0512: }
0513:
0514: if (eventReason == MotifDnDConstants.OPERATION_CHANGED) {
0515: /* OPERATION_CHANGED event doesn't provide coordinates, so we use
0516: previously stored position and component ref. */
0517: x = sourceX;
0518: y = sourceY;
0519:
0520: if (xwindow == null) {
0521: xwindow = targetXWindow;
0522: }
0523: } else {
0524: x = MotifDnDConstants.Swapper.getShort(data + 8,
0525: eventByteOrder);
0526: y = MotifDnDConstants.Swapper.getShort(data + 10,
0527: eventByteOrder);
0528:
0529: if (xwindow == null) {
0530: long receiver = XDropTargetRegistry
0531: .getRegistry()
0532: .getEmbeddedDropSite(xclient.get_window(), x, y);
0533:
0534: if (receiver != 0) {
0535: XBaseWindow xbasewindow = XToolkit
0536: .windowToXWindow(receiver);
0537: if (xbasewindow instanceof XWindow) {
0538: xwindow = (XWindow) xbasewindow;
0539: }
0540: }
0541: }
0542:
0543: if (xwindow != null) {
0544: Point p = xwindow.toLocal(x, y);
0545: x = p.x;
0546: y = p.y;
0547: }
0548: }
0549:
0550: if (xwindow == null) {
0551: if (targetXWindow != null) {
0552: notifyProtocolListener(targetXWindow, x, y,
0553: DnDConstants.ACTION_NONE, java_actions,
0554: xclient, MouseEvent.MOUSE_EXITED);
0555: }
0556: } else {
0557: int java_event_id = 0;
0558:
0559: if (targetXWindow == null) {
0560: java_event_id = MouseEvent.MOUSE_ENTERED;
0561: } else {
0562: java_event_id = MouseEvent.MOUSE_DRAGGED;
0563: }
0564:
0565: notifyProtocolListener(xwindow, x, y, java_action,
0566: java_actions, xclient, java_event_id);
0567: }
0568:
0569: sourceActions = java_actions;
0570: userAction = java_action;
0571: sourceX = x;
0572: sourceY = y;
0573: targetXWindow = xwindow;
0574:
0575: return true;
0576: }
0577:
0578: private boolean processTopLevelLeave(XClientMessageEvent xclient) {
0579: assert XToolkit.isAWTLockHeldByCurrentThread();
0580:
0581: long data = xclient.get_data();
0582: byte eventByteOrder = unsafe.getByte(data + 1);
0583:
0584: long source_win = MotifDnDConstants.Swapper.getInt(data + 8,
0585: eventByteOrder);
0586:
0587: /* Ignore Motif DnD messages from all other windows. */
0588: if (source_win != sourceWindow) {
0589: return false;
0590: }
0591:
0592: /*
0593: * Postpone upcall to java, so that we can abort it in case
0594: * if drop immediatelly follows (see BugTraq ID 4395290).
0595: * Send a dummy ClientMessage event to guarantee that a postponed java
0596: * upcall will be processed.
0597: */
0598: topLevelLeavePostponed = true;
0599: {
0600: long proxy;
0601:
0602: /*
0603: * If this is an embedded drop site, the event should go to the
0604: * awt_root_window as this is a proxy for all embedded drop sites.
0605: * Otherwise the event should go to the event->window, as we don't use
0606: * proxies for normal drop sites.
0607: */
0608: if (getEmbedderRegistryEntry(xclient.get_window()) != null) {
0609: proxy = XDropTargetRegistry.getDnDProxyWindow();
0610: } else {
0611: proxy = xclient.get_window();
0612: }
0613:
0614: XClientMessageEvent dummy = new XClientMessageEvent();
0615:
0616: try {
0617: dummy.set_type(XlibWrapper.ClientMessage);
0618: dummy.set_window(xclient.get_window());
0619: dummy.set_format(32);
0620: dummy.set_message_type(0);
0621: dummy.set_data(0, 0);
0622: dummy.set_data(1, 0);
0623: dummy.set_data(2, 0);
0624: dummy.set_data(3, 0);
0625: dummy.set_data(4, 0);
0626: XlibWrapper.XSendEvent(XToolkit.getDisplay(), proxy,
0627: false, XlibWrapper.NoEventMask, dummy.pData);
0628: } finally {
0629: dummy.dispose();
0630: }
0631: }
0632: return true;
0633: }
0634:
0635: private boolean processDropStart(XClientMessageEvent xclient) {
0636: long data = xclient.get_data();
0637: byte eventByteOrder = unsafe.getByte(data + 1);
0638:
0639: long source_win = MotifDnDConstants.Swapper.getInt(data + 16,
0640: eventByteOrder);
0641:
0642: /* Ignore Motif DnD messages from all other windows. */
0643: if (source_win != sourceWindow) {
0644: return false;
0645: }
0646:
0647: long property_atom = MotifDnDConstants.Swapper.getInt(
0648: data + 12, eventByteOrder);
0649:
0650: short flags = MotifDnDConstants.Swapper.getShort(data + 2,
0651: eventByteOrder);
0652:
0653: int motif_action = (flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >> MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
0654: int motif_actions = (flags & MotifDnDConstants.MOTIF_DND_ACTIONS_MASK) >> MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT;
0655:
0656: int java_action = MotifDnDConstants
0657: .getJavaActionsForMotifActions(motif_action);
0658: int java_actions = MotifDnDConstants
0659: .getJavaActionsForMotifActions(motif_actions);
0660:
0661: int x = MotifDnDConstants.Swapper.getShort(data + 8,
0662: eventByteOrder);
0663: int y = MotifDnDConstants.Swapper.getShort(data + 10,
0664: eventByteOrder);
0665:
0666: XWindow xwindow = null;
0667: {
0668: XBaseWindow xbasewindow = XToolkit.windowToXWindow(xclient
0669: .get_window());
0670: if (xbasewindow instanceof XWindow) {
0671: xwindow = (XWindow) xbasewindow;
0672: }
0673: }
0674:
0675: if (xwindow == null) {
0676: long receiver = XDropTargetRegistry.getRegistry()
0677: .getEmbeddedDropSite(xclient.get_window(), x, y);
0678:
0679: if (receiver != 0) {
0680: XBaseWindow xbasewindow = XToolkit
0681: .windowToXWindow(receiver);
0682: if (xbasewindow instanceof XWindow) {
0683: xwindow = (XWindow) xbasewindow;
0684: }
0685: }
0686: }
0687:
0688: if (xwindow != null) {
0689: Point p = xwindow.toLocal(x, y);
0690: x = p.x;
0691: y = p.y;
0692: }
0693:
0694: if (xwindow != null) {
0695: notifyProtocolListener(xwindow, x, y, java_action,
0696: java_actions, xclient, MouseEvent.MOUSE_RELEASED);
0697: } else if (targetXWindow != null) {
0698: notifyProtocolListener(targetXWindow, x, y,
0699: DnDConstants.ACTION_NONE, java_actions, xclient,
0700: MouseEvent.MOUSE_EXITED);
0701: }
0702:
0703: return true;
0704: }
0705:
0706: public int getMessageType(XClientMessageEvent xclient) {
0707: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0708: .getAtom()) {
0709:
0710: return UNKNOWN_MESSAGE;
0711: }
0712:
0713: long data = xclient.get_data();
0714: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0715:
0716: switch (reason) {
0717: case MotifDnDConstants.TOP_LEVEL_ENTER:
0718: return ENTER_MESSAGE;
0719: case MotifDnDConstants.DRAG_MOTION:
0720: case MotifDnDConstants.OPERATION_CHANGED:
0721: return MOTION_MESSAGE;
0722: case MotifDnDConstants.TOP_LEVEL_LEAVE:
0723: return LEAVE_MESSAGE;
0724: case MotifDnDConstants.DROP_START:
0725: return DROP_MESSAGE;
0726: default:
0727: return UNKNOWN_MESSAGE;
0728: }
0729: }
0730:
0731: protected boolean processClientMessageImpl(
0732: XClientMessageEvent xclient) {
0733: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0734: .getAtom()) {
0735: if (topLevelLeavePostponed) {
0736: topLevelLeavePostponed = false;
0737: cleanup();
0738: }
0739:
0740: return false;
0741: }
0742:
0743: long data = xclient.get_data();
0744: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0745: byte origin = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
0746:
0747: if (topLevelLeavePostponed) {
0748: topLevelLeavePostponed = false;
0749: if (reason != MotifDnDConstants.DROP_START) {
0750: cleanup();
0751: }
0752: }
0753:
0754: /* Only initiator messages should be handled. */
0755: if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
0756: return false;
0757: }
0758:
0759: switch (reason) {
0760: case MotifDnDConstants.TOP_LEVEL_ENTER:
0761: return processTopLevelEnter(xclient);
0762: case MotifDnDConstants.DRAG_MOTION:
0763: case MotifDnDConstants.OPERATION_CHANGED:
0764: return processDragMotion(xclient);
0765: case MotifDnDConstants.TOP_LEVEL_LEAVE:
0766: return processTopLevelLeave(xclient);
0767: case MotifDnDConstants.DROP_START:
0768: return processDropStart(xclient);
0769: default:
0770: return false;
0771: }
0772: }
0773:
0774: /*
0775: * Currently we don't synthesize enter/leave messages for Motif DnD
0776: * protocol. See comments in XDropTargetProtocol.postProcessClientMessage.
0777: */
0778: protected void sendEnterMessageToToplevel(long win,
0779: XClientMessageEvent xclient) {
0780: throw new Error("UNIMPLEMENTED");
0781: }
0782:
0783: protected void sendLeaveMessageToToplevel(long win,
0784: XClientMessageEvent xclient) {
0785: throw new Error("UNIMPLEMENTED");
0786: }
0787:
0788: public boolean forwardEventToEmbedded(long embedded, long ctxt,
0789: int eventID) {
0790: // UNIMPLEMENTED.
0791: return false;
0792: }
0793:
0794: public boolean isXEmbedSupported() {
0795: return false;
0796: }
0797:
0798: public boolean sendResponse(long ctxt, int eventID, int action) {
0799: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0800: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0801: .getAtom()) {
0802: return false;
0803: }
0804:
0805: long data = xclient.get_data();
0806: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0807: byte origin = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
0808: byte eventByteOrder = unsafe.getByte(data + 1);
0809: byte response_reason = (byte) 0;
0810:
0811: /* Only initiator messages should be handled. */
0812: if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
0813: return false;
0814: }
0815:
0816: switch (reason) {
0817: case MotifDnDConstants.TOP_LEVEL_ENTER:
0818: case MotifDnDConstants.TOP_LEVEL_LEAVE:
0819: /* Receiver shouldn't rely to these messages. */
0820: return false;
0821: case MotifDnDConstants.DRAG_MOTION:
0822: switch (eventID) {
0823: case MouseEvent.MOUSE_ENTERED:
0824: response_reason = MotifDnDConstants.DROP_SITE_ENTER;
0825: break;
0826: case MouseEvent.MOUSE_DRAGGED:
0827: response_reason = MotifDnDConstants.DRAG_MOTION;
0828: break;
0829: case MouseEvent.MOUSE_EXITED:
0830: response_reason = MotifDnDConstants.DROP_SITE_LEAVE;
0831: break;
0832: }
0833: break;
0834: case MotifDnDConstants.OPERATION_CHANGED:
0835: case MotifDnDConstants.DROP_START:
0836: response_reason = reason;
0837: break;
0838: default:
0839: // Unknown reason. Shouldn't get here.
0840: assert false;
0841: }
0842:
0843: XClientMessageEvent msg = new XClientMessageEvent();
0844:
0845: try {
0846: msg.set_type(XlibWrapper.ClientMessage);
0847: msg.set_window(MotifDnDConstants.Swapper.getInt(data + 12,
0848: eventByteOrder));
0849: msg.set_format(8);
0850: msg
0851: .set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0852: .getAtom());
0853:
0854: long responseData = msg.get_data();
0855:
0856: unsafe
0857: .putByte(
0858: responseData,
0859: (byte) (response_reason | MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER));
0860: unsafe.putByte(responseData + 1, MotifDnDConstants
0861: .getByteOrderByte());
0862:
0863: int response_flags = 0;
0864:
0865: if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
0866: short flags = MotifDnDConstants.Swapper.getShort(
0867: data + 2, eventByteOrder);
0868: byte dropSiteStatus = (action == DnDConstants.ACTION_NONE) ? MotifDnDConstants.MOTIF_INVALID_DROP_SITE
0869: : MotifDnDConstants.MOTIF_VALID_DROP_SITE;
0870:
0871: /* Clear action and drop site status bits. */
0872: response_flags = flags
0873: & ~MotifDnDConstants.MOTIF_DND_ACTION_MASK
0874: & ~MotifDnDConstants.MOTIF_DND_STATUS_MASK;
0875: /* Fill in new action and drop site status. */
0876: response_flags |= MotifDnDConstants
0877: .getMotifActionsForJavaActions(action) << MotifDnDConstants.MOTIF_DND_ACTION_SHIFT;
0878: response_flags |= dropSiteStatus << MotifDnDConstants.MOTIF_DND_STATUS_SHIFT;
0879: } else {
0880: response_flags = 0;
0881: }
0882:
0883: unsafe.putShort(responseData + 2, (short) response_flags);
0884:
0885: /* Write time stamp. */
0886: int time = MotifDnDConstants.Swapper.getInt(data + 4,
0887: eventByteOrder);
0888: unsafe.putInt(responseData + 4, time);
0889:
0890: /* Write coordinates. */
0891: if (response_reason != MotifDnDConstants.DROP_SITE_LEAVE) {
0892: short x = MotifDnDConstants.Swapper.getShort(data + 8,
0893: eventByteOrder);
0894: short y = MotifDnDConstants.Swapper.getShort(data + 10,
0895: eventByteOrder);
0896: unsafe.putShort(responseData + 8, x); // x
0897: unsafe.putShort(responseData + 10, y); // y
0898: } else {
0899: unsafe.putShort(responseData + 8, (short) 0); // x
0900: unsafe.putShort(responseData + 10, (short) 0); // y
0901: }
0902:
0903: XToolkit.awtLock();
0904: try {
0905: XlibWrapper.XSendEvent(XToolkit.getDisplay(), msg
0906: .get_window(), false, XlibWrapper.NoEventMask,
0907: msg.pData);
0908: } finally {
0909: XToolkit.awtUnlock();
0910: }
0911: } finally {
0912: msg.dispose();
0913: }
0914:
0915: return true;
0916: }
0917:
0918: public Object getData(long ctxt, long format)
0919: throws IllegalArgumentException, IOException {
0920: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0921:
0922: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0923: .getAtom()) {
0924: throw new IllegalArgumentException();
0925: }
0926:
0927: long data = xclient.get_data();
0928: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0929: byte origin = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
0930: byte eventByteOrder = unsafe.getByte(data + 1);
0931:
0932: if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
0933: throw new IOException("Cannot get data: corrupted context");
0934: }
0935:
0936: long selatom = 0;
0937:
0938: switch (reason) {
0939: case MotifDnDConstants.DRAG_MOTION:
0940: case MotifDnDConstants.OPERATION_CHANGED:
0941: selatom = sourceAtom;
0942: break;
0943: case MotifDnDConstants.DROP_START:
0944: selatom = MotifDnDConstants.Swapper.getInt(data + 12,
0945: eventByteOrder);
0946: break;
0947: default:
0948: throw new IOException(
0949: "Cannot get data: invalid message reason");
0950: }
0951:
0952: if (selatom == 0) {
0953: throw new IOException(
0954: "Cannot get data: drag source property atom unavailable");
0955: }
0956:
0957: long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4,
0958: eventByteOrder);
0959: XAtom selectionAtom = XAtom.get(selatom);
0960:
0961: XSelection selection = XSelection.getSelection(selectionAtom);
0962: if (selection == null) {
0963: selection = new XSelection(selectionAtom, null);
0964: }
0965:
0966: return selection.getData(format, time_stamp);
0967: }
0968:
0969: public boolean sendDropDone(long ctxt, boolean success,
0970: int dropAction) {
0971: XClientMessageEvent xclient = new XClientMessageEvent(ctxt);
0972:
0973: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
0974: .getAtom()) {
0975: return false;
0976: }
0977:
0978: long data = xclient.get_data();
0979: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
0980: byte origin = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
0981: byte eventByteOrder = unsafe.getByte(data + 1);
0982:
0983: if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR) {
0984: return false;
0985: }
0986:
0987: if (reason != MotifDnDConstants.DROP_START) {
0988: return false;
0989: }
0990:
0991: long time_stamp = MotifDnDConstants.Swapper.getInt(data + 4,
0992: eventByteOrder);
0993: long sel_atom = MotifDnDConstants.Swapper.getInt(data + 12,
0994: eventByteOrder);
0995:
0996: long status_atom = 0;
0997:
0998: if (success) {
0999: status_atom = MotifDnDConstants.XA_XmTRANSFER_SUCCESS
1000: .getAtom();
1001: } else {
1002: status_atom = MotifDnDConstants.XA_XmTRANSFER_FAILURE
1003: .getAtom();
1004: }
1005:
1006: XToolkit.awtLock();
1007: try {
1008: XlibWrapper
1009: .XConvertSelection(
1010: XToolkit.getDisplay(),
1011: sel_atom,
1012: status_atom,
1013: MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom(),
1014: XWindow.getXAWTRootWindow().getWindow(),
1015: time_stamp);
1016:
1017: /*
1018: * Flush the buffer to guarantee that the drop completion event is sent
1019: * to the source before the method returns.
1020: */
1021: XlibWrapper.XFlush(XToolkit.getDisplay());
1022: } finally {
1023: XToolkit.awtUnlock();
1024: }
1025:
1026: /* Trick to prevent cleanup() from posting dragExit */
1027: targetXWindow = null;
1028:
1029: /* Cannot do cleanup before the drop finishes as we may need
1030: source protocol version to send drop finished message. */
1031: cleanup();
1032: return true;
1033: }
1034:
1035: public final long getSourceWindow() {
1036: return sourceWindow;
1037: }
1038:
1039: /**
1040: * Reset the state of the object.
1041: */
1042: public void cleanup() {
1043: // Clear the reference to this protocol.
1044: XDropTargetEventProcessor.reset();
1045:
1046: if (targetXWindow != null) {
1047: notifyProtocolListener(targetXWindow, 0, 0,
1048: DnDConstants.ACTION_NONE, sourceActions, null,
1049: MouseEvent.MOUSE_EXITED);
1050: }
1051:
1052: if (sourceWindow != 0) {
1053: XToolkit.awtLock();
1054: try {
1055: XToolkit
1056: .WITH_XERROR_HANDLER(XToolkit.IgnoreBadWindowHandler);
1057: XlibWrapper.XSelectInput(XToolkit.getDisplay(),
1058: sourceWindow, sourceWindowMask);
1059: XToolkit.RESTORE_XERROR_HANDLER();
1060: } finally {
1061: XToolkit.awtUnlock();
1062: }
1063: }
1064:
1065: sourceWindow = 0;
1066: sourceWindowMask = 0;
1067: sourceProtocolVersion = 0;
1068: sourceActions = DnDConstants.ACTION_NONE;
1069: sourceFormats = null;
1070: sourceAtom = 0;
1071: userAction = DnDConstants.ACTION_NONE;
1072: sourceX = 0;
1073: sourceY = 0;
1074: targetXWindow = null;
1075: topLevelLeavePostponed = false;
1076: }
1077:
1078: public boolean isDragOverComponent() {
1079: return targetXWindow != null;
1080: }
1081:
1082: private void notifyProtocolListener(XWindow xwindow, int x, int y,
1083: int dropAction, int actions, XClientMessageEvent xclient,
1084: int eventID) {
1085: long nativeCtxt = 0;
1086:
1087: // Make a copy of the passed XClientMessageEvent structure, since
1088: // the original structure can be freed before this
1089: // SunDropTargetEvent is dispatched.
1090: if (xclient != null) {
1091: int size = new XClientMessageEvent(nativeCtxt).getSize();
1092:
1093: nativeCtxt = unsafe.allocateMemory(size + 4
1094: * Native.getLongSize());
1095:
1096: unsafe.copyMemory(xclient.pData, nativeCtxt, size);
1097: }
1098:
1099: getProtocolListener().handleDropTargetNotification(xwindow, x,
1100: y, dropAction, actions, sourceFormats, nativeCtxt,
1101: eventID);
1102: }
1103: }
|