001: /*
002: * Copyright 2003-2005 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 java.util.logging.*;
036:
037: import sun.misc.Unsafe;
038:
039: /**
040: * XDragSourceProtocol implementation for XDnD protocol.
041: *
042: * @since 1.5
043: */
044: class XDnDDragSourceProtocol extends XDragSourceProtocol {
045: private static final Logger logger = Logger
046: .getLogger("sun.awt.X11.xembed.xdnd.XDnDDragSourceProtocol");
047:
048: private static final Unsafe unsafe = XlibWrapper.unsafe;
049:
050: protected XDnDDragSourceProtocol(
051: XDragSourceProtocolListener listener) {
052: super (listener);
053: }
054:
055: /**
056: * Creates an instance associated with the specified listener.
057: *
058: * @throws NullPointerException if listener is <code>null</code>.
059: */
060: static XDragSourceProtocol createInstance(
061: XDragSourceProtocolListener listener) {
062: return new XDnDDragSourceProtocol(listener);
063: }
064:
065: public String getProtocolName() {
066: return XDragAndDropProtocols.XDnD;
067: }
068:
069: /**
070: * Performs protocol-specific drag initialization.
071: *
072: * @returns true if the initialized successfully.
073: */
074: protected void initializeDragImpl(int actions,
075: Transferable contents, Map formatMap, long[] formats)
076: throws InvalidDnDOperationException,
077: IllegalArgumentException, XException {
078: assert XToolkit.isAWTLockHeldByCurrentThread();
079:
080: long window = XDragSourceProtocol.getDragSourceWindow();
081:
082: long data = Native.allocateLongArray(3);
083: int action_count = 0;
084: try {
085: if ((actions & DnDConstants.ACTION_COPY) != 0) {
086: Native.putLong(data, action_count,
087: XDnDConstants.XA_XdndActionCopy.getAtom());
088: action_count++;
089: }
090: if ((actions & DnDConstants.ACTION_MOVE) != 0) {
091: Native.putLong(data, action_count,
092: XDnDConstants.XA_XdndActionMove.getAtom());
093: action_count++;
094: }
095: if ((actions & DnDConstants.ACTION_LINK) != 0) {
096: Native.putLong(data, action_count,
097: XDnDConstants.XA_XdndActionLink.getAtom());
098: action_count++;
099: }
100:
101: XToolkit
102: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
103: XDnDConstants.XA_XdndActionList.setAtomData(window,
104: XAtom.XA_ATOM, data, action_count);
105: XToolkit.RESTORE_XERROR_HANDLER();
106:
107: if (XToolkit.saved_error != null
108: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
109: cleanup();
110: throw new XException(
111: "Cannot write XdndActionList property");
112: }
113: } finally {
114: unsafe.freeMemory(data);
115: data = 0;
116: }
117:
118: data = Native.allocateLongArray(formats.length);
119:
120: try {
121: Native.put(data, formats);
122:
123: XToolkit
124: .WITH_XERROR_HANDLER(XWM.VerifyChangePropertyHandler);
125: XDnDConstants.XA_XdndTypeList.setAtomData(window,
126: XAtom.XA_ATOM, data, formats.length);
127: XToolkit.RESTORE_XERROR_HANDLER();
128:
129: if (XToolkit.saved_error != null
130: && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
131: cleanup();
132: throw new XException(
133: "Cannot write XdndActionList property");
134: }
135: } finally {
136: unsafe.freeMemory(data);
137: data = 0;
138: }
139:
140: if (!XDnDConstants.XDnDSelection.setOwner(contents, formatMap,
141: formats, XlibWrapper.CurrentTime)) {
142: cleanup();
143: throw new InvalidDnDOperationException(
144: "Cannot acquire selection ownership");
145: }
146: }
147:
148: private boolean processXdndStatus(XClientMessageEvent xclient) {
149: int action = DnDConstants.ACTION_NONE;
150:
151: /* Ignore XDnD messages from all other windows. */
152: if (xclient.get_data(0) != getTargetWindow()) {
153: return true;
154: }
155:
156: if ((xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0) {
157: /* This feature is new in XDnD version 2, but we can use it as XDnD
158: compliance only requires supporting version 3 and up. */
159: action = XDnDConstants.getJavaActionForXDnDAction(xclient
160: .get_data(4));
161: }
162:
163: getProtocolListener().handleDragReply(action);
164:
165: return true;
166: }
167:
168: private boolean processXdndFinished(XClientMessageEvent xclient) {
169: /* Ignore XDnD messages from all other windows. */
170: if (xclient.get_data(0) != getTargetWindow()) {
171: return true;
172: }
173:
174: if (getTargetProtocolVersion() >= 5) {
175: boolean success = (xclient.get_data(1) & XDnDConstants.XDND_ACCEPT_DROP_FLAG) != 0;
176: int action = XDnDConstants
177: .getJavaActionForXDnDAction(xclient.get_data(2));
178: getProtocolListener().handleDragFinished(success, action);
179: } else {
180: getProtocolListener().handleDragFinished();
181: }
182:
183: finalizeDrop();
184:
185: return true;
186: }
187:
188: public boolean processClientMessage(XClientMessageEvent xclient) {
189: if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus
190: .getAtom()) {
191: return processXdndStatus(xclient);
192: } else if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished
193: .getAtom()) {
194: return processXdndFinished(xclient);
195: } else {
196: return false;
197: }
198: }
199:
200: public TargetWindowInfo getTargetWindowInfo(long window) {
201: assert XToolkit.isAWTLockHeldByCurrentThread();
202:
203: WindowPropertyGetter wpg1 = new WindowPropertyGetter(window,
204: XDnDConstants.XA_XdndAware, 0, 1, false,
205: XlibWrapper.AnyPropertyType);
206:
207: int status = wpg1.execute(XToolkit.IgnoreBadWindowHandler);
208:
209: if (status == XlibWrapper.Success && wpg1.getData() != 0
210: && wpg1.getActualType() == XAtom.XA_ATOM) {
211:
212: int targetVersion = (int) Native.getLong(wpg1.getData());
213:
214: wpg1.dispose();
215:
216: if (targetVersion >= XDnDConstants.XDND_MIN_PROTOCOL_VERSION) {
217: long proxy = 0;
218: int protocolVersion = targetVersion < XDnDConstants.XDND_PROTOCOL_VERSION ? targetVersion
219: : XDnDConstants.XDND_PROTOCOL_VERSION;
220:
221: WindowPropertyGetter wpg2 = new WindowPropertyGetter(
222: window, XDnDConstants.XA_XdndProxy, 0, 1,
223: false, XAtom.XA_WINDOW);
224:
225: try {
226: status = wpg2
227: .execute(XToolkit.IgnoreBadWindowHandler);
228:
229: if (status == XlibWrapper.Success
230: && wpg2.getData() != 0
231: && wpg2.getActualType() == XAtom.XA_WINDOW) {
232:
233: proxy = Native.getLong(wpg2.getData());
234: }
235: } finally {
236: wpg2.dispose();
237: }
238:
239: if (proxy != 0) {
240: WindowPropertyGetter wpg3 = new WindowPropertyGetter(
241: proxy, XDnDConstants.XA_XdndProxy, 0, 1,
242: false, XAtom.XA_WINDOW);
243:
244: try {
245: status = wpg3
246: .execute(XToolkit.IgnoreBadWindowHandler);
247:
248: if (status != XlibWrapper.Success
249: || wpg3.getData() == 0
250: || wpg3.getActualType() != XAtom.XA_WINDOW
251: || Native.getLong(wpg3.getData()) != proxy) {
252:
253: proxy = 0;
254: } else {
255: WindowPropertyGetter wpg4 = new WindowPropertyGetter(
256: proxy, XDnDConstants.XA_XdndAware,
257: 0, 1, false,
258: XlibWrapper.AnyPropertyType);
259:
260: try {
261: status = wpg4
262: .execute(XToolkit.IgnoreBadWindowHandler);
263:
264: if (status != XlibWrapper.Success
265: || wpg4.getData() == 0
266: || wpg4.getActualType() != XAtom.XA_ATOM) {
267:
268: proxy = 0;
269: }
270: } finally {
271: wpg4.dispose();
272: }
273: }
274: } finally {
275: wpg3.dispose();
276: }
277: }
278:
279: return new TargetWindowInfo(proxy, protocolVersion);
280: }
281: } else {
282: wpg1.dispose();
283: }
284:
285: return null;
286: }
287:
288: public void sendEnterMessage(long[] formats, int sourceAction,
289: int sourceActions, long time) {
290: assert XToolkit.isAWTLockHeldByCurrentThread();
291: assert getTargetWindow() != 0;
292: assert formats != null;
293:
294: XClientMessageEvent msg = new XClientMessageEvent();
295: try {
296: msg.set_type((int) XlibWrapper.ClientMessage);
297: msg.set_window(getTargetWindow());
298: msg.set_format(32);
299: msg.set_message_type(XDnDConstants.XA_XdndEnter.getAtom());
300: msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
301: long data1 = getTargetProtocolVersion() << XDnDConstants.XDND_PROTOCOL_SHIFT;
302: data1 |= formats.length > 3 ? XDnDConstants.XDND_DATA_TYPES_BIT
303: : 0;
304: msg.set_data(1, data1);
305: msg.set_data(2, formats.length > 0 ? formats[0] : 0);
306: msg.set_data(3, formats.length > 1 ? formats[1] : 0);
307: msg.set_data(4, formats.length > 2 ? formats[2] : 0);
308: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
309: getTargetProxyWindow(), false,
310: XlibWrapper.NoEventMask, msg.pData);
311: } finally {
312: msg.dispose();
313: }
314: }
315:
316: public void sendMoveMessage(int xRoot, int yRoot, int sourceAction,
317: int sourceActions, long time) {
318: assert XToolkit.isAWTLockHeldByCurrentThread();
319: assert getTargetWindow() != 0;
320:
321: XClientMessageEvent msg = new XClientMessageEvent();
322: try {
323: msg.set_type((int) XlibWrapper.ClientMessage);
324: msg.set_window(getTargetWindow());
325: msg.set_format(32);
326: msg.set_message_type(XDnDConstants.XA_XdndPosition
327: .getAtom());
328: msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
329: msg.set_data(1, 0); /* flags */
330: msg.set_data(2, xRoot << 16 | yRoot);
331: msg.set_data(3, time);
332: msg.set_data(4, XDnDConstants
333: .getXDnDActionForJavaAction(sourceAction));
334: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
335: getTargetProxyWindow(), false,
336: XlibWrapper.NoEventMask, msg.pData);
337: } finally {
338: msg.dispose();
339: }
340: }
341:
342: public void sendLeaveMessage(long time) {
343: assert XToolkit.isAWTLockHeldByCurrentThread();
344: assert getTargetWindow() != 0;
345:
346: XClientMessageEvent msg = new XClientMessageEvent();
347: try {
348: msg.set_type((int) XlibWrapper.ClientMessage);
349: msg.set_window(getTargetWindow());
350: msg.set_format(32);
351: msg.set_message_type(XDnDConstants.XA_XdndLeave.getAtom());
352: msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
353: msg.set_data(1, 0);
354: msg.set_data(2, 0);
355: msg.set_data(3, 0);
356: msg.set_data(4, 0);
357: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
358: getTargetProxyWindow(), false,
359: XlibWrapper.NoEventMask, msg.pData);
360: } finally {
361: msg.dispose();
362: }
363: }
364:
365: public void sendDropMessage(int xRoot, int yRoot, int sourceAction,
366: int sourceActions, long time) {
367: assert XToolkit.isAWTLockHeldByCurrentThread();
368: assert getTargetWindow() != 0;
369:
370: XClientMessageEvent msg = new XClientMessageEvent();
371: try {
372: msg.set_type((int) XlibWrapper.ClientMessage);
373: msg.set_window(getTargetWindow());
374: msg.set_format(32);
375: msg.set_message_type(XDnDConstants.XA_XdndDrop.getAtom());
376: msg.set_data(0, XDragSourceProtocol.getDragSourceWindow());
377: msg.set_data(1, 0); /* flags */
378: msg.set_data(2, time);
379: msg.set_data(3, 0);
380: msg.set_data(4, 0);
381: XlibWrapper.XSendEvent(XToolkit.getDisplay(),
382: getTargetProxyWindow(), false,
383: XlibWrapper.NoEventMask, msg.pData);
384: } finally {
385: msg.dispose();
386: }
387: }
388:
389: public boolean processProxyModeEvent(XClientMessageEvent xclient,
390: long sourceWindow) {
391: if (xclient.get_message_type() == XDnDConstants.XA_XdndStatus
392: .getAtom()
393: || xclient.get_message_type() == XDnDConstants.XA_XdndFinished
394: .getAtom()) {
395:
396: if (xclient.get_message_type() == XDnDConstants.XA_XdndFinished
397: .getAtom()) {
398: XDragSourceContextPeer.setProxyModeSourceWindow(0);
399: }
400:
401: // This can happen if the drag operation started in the XEmbed server.
402: // In this case there is no need to forward it elsewhere, we should
403: // process it here.
404: if (xclient.get_window() == sourceWindow) {
405: return false;
406: }
407:
408: if (logger.isLoggable(Level.FINEST)) {
409: logger.finest(" sourceWindow=" + sourceWindow
410: + " get_window=" + xclient.get_window()
411: + " xclient=" + xclient);
412: }
413: xclient.set_data(0, xclient.get_window());
414: xclient.set_window(sourceWindow);
415:
416: assert XToolkit.isAWTLockHeldByCurrentThread();
417:
418: XlibWrapper.XSendEvent(XToolkit.getDisplay(), sourceWindow,
419: false, XlibWrapper.NoEventMask, xclient.pData);
420:
421: return true;
422: }
423:
424: return false;
425: }
426:
427: // TODO: register this runnable with XDnDSelection.
428: public void run() {
429: // XdndSelection ownership lost.
430: cleanup();
431: }
432: }
|