1 /*
2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.X11;
27 
28 import java.awt.datatransfer.Transferable;
29 
30 import java.awt.dnd.DnDConstants;
31 import java.awt.dnd.InvalidDnDOperationException;
32 
33 import java.util.Map;
34 
35 /**
36  * An abstract class for drag protocols on X11 systems.
37  * Contains protocol-independent drag source code.
38  *
39  * @since 1.5
40  */
41 abstract class XDragSourceProtocol {
42     private final XDragSourceProtocolListener listener;
43 
44     private boolean initialized = false;
45 
46     private long targetWindow = 0;
47     private long targetProxyWindow = 0;
48     private int targetProtocolVersion = 0;
49     private long targetWindowMask = 0;
50 
51     // Always use the XAWT root window as the drag source window.
getDragSourceWindow()52     static long getDragSourceWindow() {
53         return XWindow.getXAWTRootWindow().getWindow();
54     }
55 
XDragSourceProtocol(XDragSourceProtocolListener listener)56     protected XDragSourceProtocol(XDragSourceProtocolListener listener) {
57         if (listener == null) {
58             throw new NullPointerException("Null XDragSourceProtocolListener");
59         }
60         this.listener = listener;
61     }
62 
getProtocolListener()63     protected final XDragSourceProtocolListener getProtocolListener() {
64         return listener;
65     }
66 
67     /**
68      * Returns the protocol name. The protocol name cannot be null.
69      */
getProtocolName()70     public abstract String getProtocolName();
71 
72     /**
73      * Initializes a drag operation with the specified supported drop actions,
74      * contents and data formats.
75      *
76      * @param actions a bitwise mask of <code>DnDConstants</code> that represent
77      *                the supported drop actions.
78      * @param contents the contents for the drag operation.
79      * @param formats an array of Atoms that represent the supported data formats.
80      * @param formats an array of Atoms that represent the supported data formats.
81      * @throws InvalidDnDOperationException if a drag operation is already
82      * initialized.
83      * @throws IllegalArgumentException if some argument has invalid value.
84      * @throws XException if some X call failed.
85      */
initializeDrag(int actions, Transferable contents, Map formatMap, long[] formats)86     public final void initializeDrag(int actions, Transferable contents,
87                                      Map formatMap, long[] formats)
88       throws InvalidDnDOperationException,
89              IllegalArgumentException, XException {
90         XToolkit.awtLock();
91         try {
92             try {
93                 if (initialized) {
94                     throw new InvalidDnDOperationException("Already initialized");
95                 }
96 
97                 initializeDragImpl(actions, contents, formatMap, formats);
98 
99                 initialized = true;
100             } finally {
101                 if (!initialized) {
102                     cleanup();
103                 }
104             }
105         } finally {
106             XToolkit.awtUnlock();
107         }
108     }
109 
110     /* The caller must hold AWT_LOCK. */
initializeDragImpl(int actions, Transferable contents, Map formatMap, long[] formats)111     protected abstract void initializeDragImpl(int actions,
112                                                Transferable contents,
113                                                Map formatMap, long[] formats)
114       throws InvalidDnDOperationException, IllegalArgumentException, XException;
115 
116     /**
117      * Terminates the current drag operation (if any) and resets the internal
118      * state of this object.
119      *
120      * @throws XException if some X call failed.
121      */
cleanup()122     public void cleanup() {
123         initialized = false;
124         cleanupTargetInfo();
125     }
126 
127     /**
128      * Clears the information on the current drop target.
129      *
130      * @throws XException if some X call failed.
131      */
cleanupTargetInfo()132     public void cleanupTargetInfo() {
133         targetWindow = 0;
134         targetProxyWindow = 0;
135         targetProtocolVersion = 0;
136     }
137 
138     /**
139      * Processes the specified client message event.
140      *
141      * @returns true if the event was successfully processed.
142      */
processClientMessage(XClientMessageEvent xclient)143     public abstract boolean processClientMessage(XClientMessageEvent xclient)
144       throws XException;
145 
146     /* The caller must hold AWT_LOCK. */
attachTargetWindow(long window, long time)147     public final boolean attachTargetWindow(long window, long time) {
148         assert XToolkit.isAWTLockHeldByCurrentThread();
149 
150         TargetWindowInfo info = getTargetWindowInfo(window);
151         if (info == null) {
152             return false;
153         } else {
154             targetWindow = window;
155             targetProxyWindow = info.getProxyWindow();
156             targetProtocolVersion = info.getProtocolVersion();
157             return true;
158         }
159     }
160 
161     /* The caller must hold AWT_LOCK. */
getTargetWindowInfo(long window)162     public abstract TargetWindowInfo getTargetWindowInfo(long window);
163 
164     /* The caller must hold AWT_LOCK. */
sendEnterMessage(long[] formats, int sourceAction, int sourceActions, long time)165     public abstract void sendEnterMessage(long[] formats, int sourceAction,
166                                           int sourceActions, long time);
167     /* The caller must hold AWT_LOCK. */
sendMoveMessage(int xRoot, int yRoot, int sourceAction, int sourceActions, long time)168     public abstract void sendMoveMessage(int xRoot, int yRoot,
169                                          int sourceAction, int sourceActions,
170                                          long time);
171     /* The caller must hold AWT_LOCK. */
sendLeaveMessage(long time)172     public abstract void sendLeaveMessage(long time);
173 
174     /* The caller must hold AWT_LOCK. */
sendDropMessage(int xRoot, int yRoot, int sourceAction, int sourceActions, long time)175     protected abstract void sendDropMessage(int xRoot, int yRoot,
176                                             int sourceAction, int sourceActions,
177                                             long time);
178 
initiateDrop(int xRoot, int yRoot, int sourceAction, int sourceActions, long time)179     public final void initiateDrop(int xRoot, int yRoot,
180                                    int sourceAction, int sourceActions,
181                                    long time) {
182         XWindowAttributes wattr = new XWindowAttributes();
183         try {
184             XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
185             int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
186                                                           targetWindow, wattr.pData);
187 
188             XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
189 
190             if ((status == 0) ||
191                 ((XErrorHandlerUtil.saved_error != null) &&
192                 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success))) {
193                 throw new XException("XGetWindowAttributes failed");
194             }
195 
196             targetWindowMask = wattr.get_your_event_mask();
197         } finally {
198             wattr.dispose();
199         }
200 
201         XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
202         XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
203                                  targetWindowMask |
204                                  XConstants.StructureNotifyMask);
205 
206         XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
207 
208         if ((XErrorHandlerUtil.saved_error != null) &&
209             (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
210             throw new XException("XSelectInput failed");
211         }
212 
213         sendDropMessage(xRoot, yRoot, sourceAction, sourceActions, time);
214     }
215 
finalizeDrop()216     protected final void finalizeDrop() {
217         XErrorHandlerUtil.WITH_XERROR_HANDLER(XErrorHandler.IgnoreBadWindowHandler.getInstance());
218         XlibWrapper.XSelectInput(XToolkit.getDisplay(), targetWindow,
219                                  targetWindowMask);
220         XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
221     }
222 
processProxyModeEvent(XClientMessageEvent xclient, long sourceWindow)223     public abstract boolean processProxyModeEvent(XClientMessageEvent xclient,
224                                                   long sourceWindow);
225 
getTargetWindow()226     protected final long getTargetWindow() {
227         return targetWindow;
228     }
229 
getTargetProxyWindow()230     protected final long getTargetProxyWindow() {
231         if (targetProxyWindow != 0) {
232             return targetProxyWindow;
233         } else {
234             return targetWindow;
235         }
236     }
237 
getTargetProtocolVersion()238     protected final int getTargetProtocolVersion() {
239         return targetProtocolVersion;
240     }
241 
242     public static class TargetWindowInfo {
243         private final long proxyWindow;
244         private final int protocolVersion;
TargetWindowInfo(long proxy, int version)245         public TargetWindowInfo(long proxy, int version) {
246             proxyWindow = proxy;
247             protocolVersion = version;
248         }
getProxyWindow()249         public long getProxyWindow() {
250             return proxyWindow;
251         }
getProtocolVersion()252         public int getProtocolVersion() {
253             return protocolVersion;
254         }
255     }
256 }
257