001: /*
002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.X11;
027:
028: import java.awt.datatransfer.Transferable;
029:
030: import java.awt.dnd.DnDConstants;
031: import java.awt.dnd.InvalidDnDOperationException;
032:
033: import java.util.Map;
034:
035: import sun.misc.Unsafe;
036:
037: /**
038: * XDragSourceProtocol implementation for Motif DnD protocol.
039: *
040: * @since 1.5
041: */
042: class MotifDnDDragSourceProtocol extends XDragSourceProtocol implements
043: XEventDispatcher {
044:
045: private static final Unsafe unsafe = XlibWrapper.unsafe;
046:
047: private long targetEnterServerTime = XlibWrapper.CurrentTime;
048:
049: protected MotifDnDDragSourceProtocol(
050: XDragSourceProtocolListener listener) {
051: super (listener);
052: XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow()
053: .getWindow(), this );
054: }
055:
056: /**
057: * Creates an instance associated with the specified listener.
058: *
059: * @throws NullPointerException if listener is <code>null</code>.
060: */
061: static XDragSourceProtocol createInstance(
062: XDragSourceProtocolListener listener) {
063: return new MotifDnDDragSourceProtocol(listener);
064: }
065:
066: public String getProtocolName() {
067: return XDragAndDropProtocols.MotifDnD;
068: }
069:
070: protected void initializeDragImpl(int actions,
071: Transferable contents, Map formatMap, long[] formats)
072: throws InvalidDnDOperationException,
073: IllegalArgumentException, XException {
074:
075: long window = XDragSourceProtocol.getDragSourceWindow();
076:
077: /* Write the Motif DnD initiator info on the root XWindow. */
078: try {
079: int index = MotifDnDConstants
080: .getIndexForTargetList(formats);
081:
082: MotifDnDConstants.writeDragInitiatorInfoStruct(window,
083: index);
084: } catch (XException xe) {
085: cleanup();
086: throw xe;
087: } catch (InvalidDnDOperationException idoe) {
088: cleanup();
089: throw idoe;
090: }
091:
092: if (!MotifDnDConstants.MotifDnDSelection.setOwner(contents,
093: formatMap, formats, XlibWrapper.CurrentTime)) {
094: cleanup();
095: throw new InvalidDnDOperationException(
096: "Cannot acquire selection ownership");
097: }
098: }
099:
100: /**
101: * Processes the specified client message event.
102: *
103: * @returns true if the event was successfully processed.
104: */
105: public boolean processClientMessage(XClientMessageEvent xclient) {
106: if (xclient.get_message_type() != MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
107: .getAtom()) {
108: return false;
109: }
110:
111: long data = xclient.get_data();
112: byte reason = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_REASON_MASK);
113: byte origin = (byte) (unsafe.getByte(data) & MotifDnDConstants.MOTIF_MESSAGE_SENDER_MASK);
114: byte byteOrder = unsafe.getByte(data + 1);
115: boolean swapNeeded = byteOrder != MotifDnDConstants
116: .getByteOrderByte();
117: int action = DnDConstants.ACTION_NONE;
118: int x = 0;
119: int y = 0;
120:
121: /* Only receiver messages should be handled. */
122: if (origin != MotifDnDConstants.MOTIF_MESSAGE_FROM_RECEIVER) {
123: return false;
124: }
125:
126: switch (reason) {
127: case MotifDnDConstants.DROP_SITE_ENTER:
128: case MotifDnDConstants.DROP_SITE_LEAVE:
129: case MotifDnDConstants.DRAG_MOTION:
130: case MotifDnDConstants.OPERATION_CHANGED:
131: break;
132: default:
133: // Unknown reason.
134: return false;
135: }
136:
137: int t = unsafe.getInt(data + 4);
138: if (swapNeeded) {
139: t = MotifDnDConstants.Swapper.swap(t);
140: }
141: long time = t;
142:
143: /* Discard events from the previous receiver. */
144: if (targetEnterServerTime == XlibWrapper.CurrentTime
145: || time < targetEnterServerTime) {
146: return true;
147: }
148:
149: if (reason != MotifDnDConstants.DROP_SITE_LEAVE) {
150: short flags = unsafe.getShort(data + 2);
151: if (swapNeeded) {
152: flags = MotifDnDConstants.Swapper.swap(flags);
153: }
154:
155: byte status = (byte) ((flags & MotifDnDConstants.MOTIF_DND_STATUS_MASK) >> MotifDnDConstants.MOTIF_DND_STATUS_SHIFT);
156: byte motif_action = (byte) ((flags & MotifDnDConstants.MOTIF_DND_ACTION_MASK) >> MotifDnDConstants.MOTIF_DND_ACTION_SHIFT);
157:
158: if (status == MotifDnDConstants.MOTIF_VALID_DROP_SITE) {
159: action = MotifDnDConstants
160: .getJavaActionsForMotifActions(motif_action);
161: } else {
162: action = DnDConstants.ACTION_NONE;
163: }
164:
165: short tx = unsafe.getShort(data + 8);
166: short ty = unsafe.getShort(data + 10);
167: if (swapNeeded) {
168: tx = MotifDnDConstants.Swapper.swap(tx);
169: ty = MotifDnDConstants.Swapper.swap(ty);
170: }
171: x = tx;
172: y = ty;
173: }
174:
175: getProtocolListener().handleDragReply(action, x, y);
176:
177: return true;
178: }
179:
180: public TargetWindowInfo getTargetWindowInfo(long window) {
181: assert XToolkit.isAWTLockHeldByCurrentThread();
182:
183: WindowPropertyGetter wpg = new WindowPropertyGetter(window,
184: MotifDnDConstants.XA_MOTIF_DRAG_RECEIVER_INFO, 0,
185: 0xFFFF, false, XlibWrapper.AnyPropertyType);
186:
187: try {
188: int status = wpg.execute(XToolkit.IgnoreBadWindowHandler);
189:
190: /*
191: * DragICCI.h:
192: *
193: * typedef struct _xmDragReceiverInfoStruct{
194: * BYTE byte_order;
195: * BYTE protocol_version;
196: * BYTE drag_protocol_style;
197: * BYTE pad1;
198: * CARD32 proxy_window B32;
199: * CARD16 num_drop_sites B16;
200: * CARD16 pad2 B16;
201: * CARD32 heap_offset B32;
202: * } xmDragReceiverInfoStruct;
203: */
204: if (status == (int) XlibWrapper.Success
205: && wpg.getData() != 0
206: && wpg.getActualType() != 0
207: && wpg.getActualFormat() == 8
208: && wpg.getNumberOfItems() >= MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE) {
209:
210: long data = wpg.getData();
211: byte byteOrderByte = unsafe.getByte(data);
212: byte dragProtocolStyle = unsafe.getByte(data + 2);
213: switch (dragProtocolStyle) {
214: case MotifDnDConstants.MOTIF_PREFER_PREREGISTER_STYLE:
215: case MotifDnDConstants.MOTIF_PREFER_DYNAMIC_STYLE:
216: case MotifDnDConstants.MOTIF_DYNAMIC_STYLE:
217: case MotifDnDConstants.MOTIF_PREFER_RECEIVER_STYLE:
218: int proxy = unsafe.getInt(data + 4);
219: if (byteOrderByte != MotifDnDConstants
220: .getByteOrderByte()) {
221: proxy = MotifDnDConstants.Swapper.swap(proxy);
222: }
223:
224: int protocolVersion = unsafe.getByte(data + 1);
225:
226: return new TargetWindowInfo(proxy, protocolVersion);
227: default:
228: // Unsupported protocol style.
229: return null;
230: }
231: } else {
232: return null;
233: }
234: } finally {
235: wpg.dispose();
236: }
237: }
238:
239: public void sendEnterMessage(long[] formats, int sourceAction,
240: int sourceActions, long time) {
241: assert XToolkit.isAWTLockHeldByCurrentThread();
242: assert getTargetWindow() != 0;
243: assert formats != null;
244:
245: targetEnterServerTime = time;
246:
247: XClientMessageEvent msg = new XClientMessageEvent();
248: try {
249: msg.set_type(XlibWrapper.ClientMessage);
250: msg.set_window(getTargetWindow());
251: msg.set_format(8);
252: msg
253: .set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
254: .getAtom());
255:
256: long data = msg.get_data();
257: int flags = (MotifDnDConstants
258: .getMotifActionsForJavaActions(sourceAction) << MotifDnDConstants.MOTIF_DND_ACTION_SHIFT)
259: | (MotifDnDConstants
260: .getMotifActionsForJavaActions(sourceActions) << MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
261:
262: unsafe
263: .putByte(
264: data,
265: (byte) (MotifDnDConstants.TOP_LEVEL_ENTER | MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
266: unsafe.putByte(data + 1, MotifDnDConstants
267: .getByteOrderByte());
268: unsafe.putShort(data + 2, (short) flags);
269: unsafe.putInt(data + 4, (int) time);
270: unsafe.putInt(data + 8, (int) XDragSourceProtocol
271: .getDragSourceWindow());
272: unsafe.putInt(data + 12,
273: (int) MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
274:
275: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
276: getTargetProxyWindow(), false,
277: XlibWrapper.NoEventMask, msg.pData);
278: } finally {
279: msg.dispose();
280: }
281: }
282:
283: public void sendMoveMessage(int xRoot, int yRoot, int sourceAction,
284: int sourceActions, long time) {
285: assert XToolkit.isAWTLockHeldByCurrentThread();
286: assert getTargetWindow() != 0;
287:
288: XClientMessageEvent msg = new XClientMessageEvent();
289: try {
290: msg.set_type(XlibWrapper.ClientMessage);
291: msg.set_window(getTargetWindow());
292: msg.set_format(8);
293: msg
294: .set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
295: .getAtom());
296:
297: long data = msg.get_data();
298: int flags = (MotifDnDConstants
299: .getMotifActionsForJavaActions(sourceAction) << MotifDnDConstants.MOTIF_DND_ACTION_SHIFT)
300: | (MotifDnDConstants
301: .getMotifActionsForJavaActions(sourceActions) << MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
302:
303: unsafe
304: .putByte(
305: data,
306: (byte) (MotifDnDConstants.DRAG_MOTION | MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
307: unsafe.putByte(data + 1, MotifDnDConstants
308: .getByteOrderByte());
309: unsafe.putShort(data + 2, (short) flags);
310: unsafe.putInt(data + 4, (int) time);
311: unsafe.putShort(data + 8, (short) xRoot);
312: unsafe.putShort(data + 10, (short) yRoot);
313:
314: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
315: getTargetProxyWindow(), false,
316: XlibWrapper.NoEventMask, msg.pData);
317: } finally {
318: msg.dispose();
319: }
320: }
321:
322: public void sendLeaveMessage(long time) {
323: assert XToolkit.isAWTLockHeldByCurrentThread();
324: assert getTargetWindow() != 0;
325:
326: XClientMessageEvent msg = new XClientMessageEvent();
327: try {
328: msg.set_type(XlibWrapper.ClientMessage);
329: msg.set_window(getTargetWindow());
330: msg.set_format(8);
331: msg
332: .set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
333: .getAtom());
334:
335: long data = msg.get_data();
336:
337: unsafe
338: .putByte(
339: data,
340: (byte) (MotifDnDConstants.TOP_LEVEL_LEAVE | MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
341: unsafe.putByte(data + 1, MotifDnDConstants
342: .getByteOrderByte());
343: unsafe.putShort(data + 2, (short) 0);
344: unsafe.putInt(data + 4, (int) time);
345: unsafe.putInt(data + 8, (int) XDragSourceProtocol
346: .getDragSourceWindow());
347:
348: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
349: getTargetProxyWindow(), false,
350: XlibWrapper.NoEventMask, msg.pData);
351: } finally {
352: msg.dispose();
353: }
354: }
355:
356: protected void sendDropMessage(int xRoot, int yRoot,
357: int sourceAction, int sourceActions, long time) {
358: assert XToolkit.isAWTLockHeldByCurrentThread();
359: assert getTargetWindow() != 0;
360:
361: /*
362: * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START.
363: */
364: sendLeaveMessage(time);
365:
366: XClientMessageEvent msg = new XClientMessageEvent();
367: try {
368: msg.set_type(XlibWrapper.ClientMessage);
369: msg.set_window(getTargetWindow());
370: msg.set_format(8);
371: msg
372: .set_message_type(MotifDnDConstants.XA_MOTIF_DRAG_AND_DROP_MESSAGE
373: .getAtom());
374:
375: long data = msg.get_data();
376: int flags = (MotifDnDConstants
377: .getMotifActionsForJavaActions(sourceAction) << MotifDnDConstants.MOTIF_DND_ACTION_SHIFT)
378: | (MotifDnDConstants
379: .getMotifActionsForJavaActions(sourceActions) << MotifDnDConstants.MOTIF_DND_ACTIONS_SHIFT);
380:
381: unsafe
382: .putByte(
383: data,
384: (byte) (MotifDnDConstants.DROP_START | MotifDnDConstants.MOTIF_MESSAGE_FROM_INITIATOR));
385: unsafe.putByte(data + 1, MotifDnDConstants
386: .getByteOrderByte());
387: unsafe.putShort(data + 2, (short) flags);
388: unsafe.putInt(data + 4, (int) time);
389: unsafe.putShort(data + 8, (short) xRoot);
390: unsafe.putShort(data + 10, (short) yRoot);
391: unsafe.putInt(data + 12,
392: (int) MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom());
393: unsafe.putInt(data + 16, (int) XDragSourceProtocol
394: .getDragSourceWindow());
395:
396: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
397: getTargetProxyWindow(), false,
398: XlibWrapper.NoEventMask, msg.pData);
399: } finally {
400: msg.dispose();
401: }
402: }
403:
404: public boolean processProxyModeEvent(XClientMessageEvent xclient,
405: long sourceWindow) {
406: // Motif DnD for XEmbed is not implemented.
407: return false;
408: }
409:
410: public void cleanupTargetInfo() {
411: super .cleanupTargetInfo();
412: targetEnterServerTime = XlibWrapper.CurrentTime;
413: }
414:
415: public void dispatchEvent(XEvent ev) {
416: switch (ev.get_type()) {
417: case XlibWrapper.SelectionRequest:
418: XSelectionRequestEvent xsre = ev.get_xselectionrequest();
419: long atom = xsre.get_selection();
420:
421: if (atom == MotifDnDConstants.XA_MOTIF_ATOM_0.getAtom()) {
422: long target = xsre.get_target();
423: if (target == MotifDnDConstants.XA_XmTRANSFER_SUCCESS
424: .getAtom()) {
425: getProtocolListener().handleDragFinished(true);
426: } else if (target == MotifDnDConstants.XA_XmTRANSFER_FAILURE
427: .getAtom()) {
428: getProtocolListener().handleDragFinished(false);
429: }
430: }
431: break;
432: }
433: }
434: }
|