Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xwin / winclipboardwrappers.c
CommitLineData
a09e091a
JB
1/*
2 *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
3 *Copyright (C) Colin Harrison 2005-2008
4 *
5 *Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 *"Software"), to deal in the Software without restriction, including
8 *without limitation the rights to use, copy, modify, merge, publish,
9 *distribute, sublicense, and/or sell copies of the Software, and to
10 *permit persons to whom the Software is furnished to do so, subject to
11 *the following conditions:
12 *
13 *The above copyright notice and this permission notice shall be
14 *included in all copies or substantial portions of the Software.
15 *
16 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
20 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 *Except as contained in this notice, the name of the copyright holder(s)
25 *and author(s) shall not be used in advertising or otherwise to promote
26 *the sale, use or other dealings in this Software without prior written
27 *authorization from the copyright holder(s) and author(s).
28 *
29 * Authors: Harold L Hunt II
30 * Colin Harrison
31 */
32
33#ifdef HAVE_XWIN_CONFIG_H
34#include <xwin-config.h>
35#endif
36#include "win.h"
37#include "dixstruct.h"
38#include <X11/Xatom.h>
39
40/*
41 * Constants
42 */
43
44#define CLIP_NUM_SELECTIONS 2
45#define CLIP_OWN_PRIMARY 0
46#define CLIP_OWN_CLIPBOARD 1
47
48/*
49 * Local function prototypes
50 */
51
52DISPATCH_PROC(winProcEstablishConnection);
53DISPATCH_PROC(winProcSetSelectionOwner);
54
55/*
56 * References to external symbols
57 */
58
59extern Bool g_fClipboardLaunched;
60extern Bool g_fClipboardStarted;
61extern Bool g_fClipboard;
62extern Window g_iClipboardWindow;
63extern Atom g_atomLastOwnedSelection;
64extern HWND g_hwndClipboard;
65
66
67/*
68 * Wrapper for internal EstablishConnection function.
69 * Initializes internal clients that must not be started until
70 * an external client has connected.
71 */
72
73int
74winProcEstablishConnection(ClientPtr client)
75{
76 int iReturn;
77 static int s_iCallCount = 0;
78 static unsigned long s_ulServerGeneration = 0;
79
80 if (s_iCallCount == 0)
81 winDebug("winProcEstablishConnection - Hello\n");
82
83 /* Do nothing if clipboard is not enabled */
84 if (!g_fClipboard) {
85 ErrorF("winProcEstablishConnection - Clipboard is not enabled, "
86 "returning.\n");
87
88 /* Unwrap the original function, call it, and return */
89 InitialVector[2] = winProcEstablishConnectionOrig;
90 iReturn = (*winProcEstablishConnectionOrig) (client);
91 winProcEstablishConnectionOrig = NULL;
92 return iReturn;
93 }
94
95 /* Watch for server reset */
96 if (s_ulServerGeneration != serverGeneration) {
97 /* Save new generation number */
98 s_ulServerGeneration = serverGeneration;
99
100 /* Reset call count */
101 s_iCallCount = 0;
102 }
103
104 /* Increment call count */
105 ++s_iCallCount;
106
107 /*
108 * This procedure is only used for initialization.
109 * We can unwrap the original procedure at this point
110 * so that this function is no longer called until the
111 * server resets and the function is wrapped again.
112 */
113 InitialVector[2] = winProcEstablishConnectionOrig;
114
115 /*
116 * Call original function and bail if it fails.
117 * NOTE: We must do this first, since we need XdmcpOpenDisplay
118 * to be called before we initialize our clipboard client.
119 */
120 iReturn = (*winProcEstablishConnectionOrig) (client);
121 if (iReturn != 0) {
122 ErrorF("winProcEstablishConnection - ProcEstablishConnection "
123 "failed, bailing.\n");
124 return iReturn;
125 }
126
127 /* Clear original function pointer */
128 winProcEstablishConnectionOrig = NULL;
129
130 /* If the clipboard client has already been started, abort */
131 if (g_fClipboardLaunched) {
132 ErrorF("winProcEstablishConnection - Clipboard client already "
133 "launched, returning.\n");
134 return iReturn;
135 }
136
137 /* Startup the clipboard client if clipboard mode is being used */
138 if (g_fClipboard) {
139 /*
140 * NOTE: The clipboard client is started here for a reason:
141 * 1) Assume you are using XDMCP (e.g. XWin -query %hostname%)
142 * 2) If the clipboard client attaches during X Server startup,
143 * then it becomes the "magic client" that causes the X Server
144 * to reset if it exits.
145 * 3) XDMCP calls KillAllClients when it starts up.
146 * 4) The clipboard client is a client, so it is killed.
147 * 5) The clipboard client is the "magic client", so the X Server
148 * resets itself.
149 * 6) This repeats ad infinitum.
150 * 7) We avoid this by waiting until at least one client (could
151 * be XDM, could be another client) connects, which makes it
152 * almost certain that the clipboard client will not connect
153 * until after XDM when using XDMCP.
154 */
155
156 /* Create the clipboard client thread */
157 if (!winInitClipboard()) {
158 ErrorF("winProcEstablishConnection - winClipboardInit "
159 "failed.\n");
160 return iReturn;
161 }
162
163 ErrorF("winProcEstablishConnection - winInitClipboard returned.\n");
164 }
165
166 /* Flag that clipboard client has been launched */
167 g_fClipboardLaunched = TRUE;
168
169 return iReturn;
170}
171
172/*
173 * Wrapper for internal SetSelectionOwner function.
174 * Grabs ownership of Windows clipboard when X11 clipboard owner changes.
175 */
176
177int
178winProcSetSelectionOwner(ClientPtr client)
179{
180 int i;
181 DrawablePtr pDrawable;
182 WindowPtr pWindow = None;
183 Bool fOwnedToNotOwned = FALSE;
184 static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None };
185 static unsigned long s_ulServerGeneration = 0;
186
187 REQUEST(xSetSelectionOwnerReq);
188
189 REQUEST_SIZE_MATCH(xSetSelectionOwnerReq);
190
191 winDebug("winProcSetSelectionOwner - Hello.\n");
192
193 /* Watch for server reset */
194 if (s_ulServerGeneration != serverGeneration) {
195 /* Save new generation number */
196 s_ulServerGeneration = serverGeneration;
197
198 /* Initialize static variables */
199 for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
200 s_iOwners[i] = None;
201 }
202
203 /* Abort if clipboard not completely initialized yet */
204 if (!g_fClipboardStarted) {
205 /* ErrorF ("winProcSetSelectionOwner - Clipboard not yet started, "
206 "aborting.\n"); */
207 goto winProcSetSelectionOwner_Done;
208 }
209
210 /* Grab window if we have one */
211 if (None != stuff->window) {
212 /* Grab the Window from the request */
213 int rc =
214 dixLookupWindow(&pWindow, stuff->window, client, DixReadAccess);
215 if (rc != Success) {
216 ErrorF("winProcSetSelectionOwner - Found BadWindow, aborting.\n");
217 goto winProcSetSelectionOwner_Done;
218 }
219 }
220
221 /* Now we either have a valid window or None */
222
223 /* Save selection owners for monitored selections, ignore other selections */
224 if (XA_PRIMARY == stuff->selection) {
225 /* Look for owned -> not owned transition */
226 if (None == stuff->window && None != s_iOwners[CLIP_OWN_PRIMARY]) {
227 fOwnedToNotOwned = TRUE;
228
229 winDebug("winProcSetSelectionOwner - PRIMARY - Going from "
230 "owned to not owned.\n");
231
232 /* Adjust last owned selection */
233 if (None != s_iOwners[CLIP_OWN_CLIPBOARD])
234 g_atomLastOwnedSelection = MakeAtom("CLIPBOARD", 9, TRUE);
235 else
236 g_atomLastOwnedSelection = None;
237 }
238
239 /* Save new selection owner or None */
240 s_iOwners[CLIP_OWN_PRIMARY] = stuff->window;
241
242 winDebug("winProcSetSelectionOwner - PRIMARY - Now owned by: %d\n",
243 stuff->window);
244 }
245 else if (MakeAtom("CLIPBOARD", 9, TRUE) == stuff->selection) {
246 /* Look for owned -> not owned transition */
247 if (None == stuff->window && None != s_iOwners[CLIP_OWN_CLIPBOARD]) {
248 fOwnedToNotOwned = TRUE;
249
250 winDebug("winProcSetSelectionOwner - CLIPBOARD - Going from "
251 "owned to not owned.\n");
252
253 /* Adjust last owned selection */
254 if (None != s_iOwners[CLIP_OWN_PRIMARY])
255 g_atomLastOwnedSelection = XA_PRIMARY;
256 else
257 g_atomLastOwnedSelection = None;
258 }
259
260 /* Save new selection owner or None */
261 s_iOwners[CLIP_OWN_CLIPBOARD] = stuff->window;
262
263 winDebug("winProcSetSelectionOwner - CLIPBOARD - Now owned by: %d\n",
264 stuff->window);
265
266 }
267 else
268 goto winProcSetSelectionOwner_Done;
269
270 /*
271 * At this point, if one of the selections is still owned by the
272 * clipboard manager then it should be marked as unowned since
273 * we will be taking ownership of the Win32 clipboard.
274 */
275 if (g_iClipboardWindow == s_iOwners[CLIP_OWN_PRIMARY])
276 s_iOwners[CLIP_OWN_PRIMARY] = None;
277 if (g_iClipboardWindow == s_iOwners[CLIP_OWN_CLIPBOARD])
278 s_iOwners[CLIP_OWN_CLIPBOARD] = None;
279
280 /*
281 * Handle case when selection is being disowned,
282 * WM_DRAWCLIPBOARD did not do the disowning,
283 * both monitored selections are no longer owned,
284 * an owned to not owned transition was detected,
285 * and we currently own the Win32 clipboard.
286 */
287 if (stuff->window == None
288 && s_iOwners[CLIP_OWN_PRIMARY] == None
289 && s_iOwners[CLIP_OWN_CLIPBOARD] == None
290 && fOwnedToNotOwned
291 && g_hwndClipboard != NULL && g_hwndClipboard == GetClipboardOwner()) {
292 winDebug("winProcSetSelectionOwner - We currently own the "
293 "clipboard and neither the PRIMARY nor the CLIPBOARD "
294 "selections are owned, releasing ownership of Win32 "
295 "clipboard.\n");
296
297 /* Release ownership of the Windows clipboard */
298 OpenClipboard(NULL);
299 EmptyClipboard();
300 CloseClipboard();
301
302 goto winProcSetSelectionOwner_Done;
303 }
304
305 /* Abort if no window at this point */
306 if (None == stuff->window) {
307 winDebug("winProcSetSelectionOwner - No window, returning.\n");
308 goto winProcSetSelectionOwner_Done;
309 }
310
311 /* Abort if invalid selection */
312 if (!ValidAtom(stuff->selection)) {
313 ErrorF("winProcSetSelectionOwner - Found BadAtom, aborting.\n");
314 goto winProcSetSelectionOwner_Done;
315 }
316
317 /* Cast Window to Drawable */
318 pDrawable = (DrawablePtr) pWindow;
319
320 /* Abort if clipboard manager is owning the selection */
321 if (pDrawable->id == g_iClipboardWindow) {
322 winDebug("winProcSetSelectionOwner - We changed ownership, "
323 "aborting.\n");
324 goto winProcSetSelectionOwner_Done;
325 }
326
327 /* Abort if root window is taking ownership */
328 if (pDrawable->id == 0) {
329 ErrorF("winProcSetSelectionOwner - Root window taking ownership, "
330 "aborting\n");
331 goto winProcSetSelectionOwner_Done;
332 }
333
334 /* Close clipboard if we have it open already */
335 if (GetOpenClipboardWindow() == g_hwndClipboard) {
336 CloseClipboard();
337 }
338
339 /* Access the Windows clipboard */
340 if (!OpenClipboard(g_hwndClipboard)) {
341 ErrorF("winProcSetSelectionOwner - OpenClipboard () failed: %08x\n",
342 (int) GetLastError());
343 goto winProcSetSelectionOwner_Done;
344 }
345
346 /* Take ownership of the Windows clipboard */
347 if (!EmptyClipboard()) {
348 ErrorF("winProcSetSelectionOwner - EmptyClipboard () failed: %08x\n",
349 (int) GetLastError());
350 goto winProcSetSelectionOwner_Done;
351 }
352
353 /* Advertise regular text and unicode */
354 SetClipboardData(CF_UNICODETEXT, NULL);
355 SetClipboardData(CF_TEXT, NULL);
356
357 /* Save handle to last owned selection */
358 g_atomLastOwnedSelection = stuff->selection;
359
360 /* Release the clipboard */
361 if (!CloseClipboard()) {
362 ErrorF("winProcSetSelectionOwner - CloseClipboard () failed: "
363 "%08x\n", (int) GetLastError());
364 goto winProcSetSelectionOwner_Done;
365 }
366
367 winProcSetSelectionOwner_Done:
368 return (*winProcSetSelectionOwnerOrig) (client);
369}