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
37 /*
38 * Including any server header might define the macro _XSERVER64 on 64 bit machines.
39 * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
40 * So let's undef that macro if necessary.
41 */
42 #ifdef _XSERVER64
43 #undef _XSERVER64
44 #endif
45
46 #include <limits.h>
47 #include <wchar.h>
48 #include <X11/Xutil.h>
49 #include <X11/Xatom.h>
50 #include <X11/extensions/Xfixes.h>
51
52 #include "winclipboard.h"
53 #include "internal.h"
54
55 /*
56 * Constants
57 */
58
59 #define CLIP_NUM_SELECTIONS 2
60 #define CLIP_OWN_NONE -1
61 #define CLIP_OWN_PRIMARY 0
62 #define CLIP_OWN_CLIPBOARD 1
63
64 /*
65 * Global variables
66 */
67
68 extern int xfixes_event_base;
69 Bool fPrimarySelection = TRUE;
70
71 /*
72 * Local variables
73 */
74
75 static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None };
76 static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
77 { "PRIMARY", "CLIPBOARD" };
78
79 static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
80
81 static void
MonitorSelection(XFixesSelectionNotifyEvent * e,unsigned int i)82 MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i)
83 {
84 /* Look for owned -> not owned transition */
85 if (None == e->owner && None != s_iOwners[i]) {
86 unsigned int other_index;
87
88 winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
89 szSelectionNames[i]);
90
91 /* If this selection is not owned, the other monitored selection must be the most
92 recently owned, if it is owned at all */
93 if (i == CLIP_OWN_PRIMARY)
94 other_index = CLIP_OWN_CLIPBOARD;
95 if (i == CLIP_OWN_CLIPBOARD)
96 other_index = CLIP_OWN_PRIMARY;
97 if (None != s_iOwners[other_index])
98 lastOwnedSelectionIndex = other_index;
99 else
100 lastOwnedSelectionIndex = CLIP_OWN_NONE;
101 }
102
103 /* Save last owned selection */
104 if (None != e->owner) {
105 lastOwnedSelectionIndex = i;
106 }
107
108 /* Save new selection owner or None */
109 s_iOwners[i] = e->owner;
110 winDebug("MonitorSelection - %s - Now owned by XID %lx\n",
111 szSelectionNames[i], e->owner);
112 }
113
114 Atom
winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms * atoms)115 winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
116 {
117 if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
118 return None;
119
120 if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
121 return XA_PRIMARY;
122
123 if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
124 return atoms->atomClipboard;
125
126 return None;
127 }
128
129
130 void
winClipboardInitMonitoredSelections(void)131 winClipboardInitMonitoredSelections(void)
132 {
133 /* Initialize static variables */
134 int i;
135 for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
136 s_iOwners[i] = None;
137
138 lastOwnedSelectionIndex = CLIP_OWN_NONE;
139 }
140
141 static int
winClipboardSelectionNotifyTargets(HWND hwnd,Window iWindow,Display * pDisplay,ClipboardConversionData * data,ClipboardAtoms * atoms)142 winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
143 {
144 Atom type;
145 int format;
146 unsigned long nitems;
147 unsigned long after;
148 Atom *prop;
149
150 /* Retrieve the selection data and delete the property */
151 int iReturn = XGetWindowProperty(pDisplay,
152 iWindow,
153 atoms->atomLocalProperty,
154 0,
155 INT_MAX,
156 True,
157 AnyPropertyType,
158 &type,
159 &format,
160 &nitems,
161 &after,
162 (unsigned char **)&prop);
163 if (iReturn != Success) {
164 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
165 "XGetWindowProperty () failed, aborting: %d\n", iReturn);
166 } else {
167 int i;
168 data->targetList = malloc((nitems+1)*sizeof(Atom));
169
170 for (i = 0; i < nitems; i++)
171 {
172 Atom atom = prop[i];
173 char *pszAtomName = XGetAtomName(pDisplay, atom);
174 data->targetList[i] = atom;
175 winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %ld = %s\n", i, atom, pszAtomName);
176 XFree(pszAtomName);
177 }
178
179 data->targetList[nitems] = 0;
180
181 XFree(prop);
182 }
183
184 return WIN_XEVENTS_NOTIFY_TARGETS;
185 }
186
187 /*
188 * Process any pending X events
189 */
190
191 int
winClipboardFlushXEvents(HWND hwnd,Window iWindow,Display * pDisplay,ClipboardConversionData * data,ClipboardAtoms * atoms)192 winClipboardFlushXEvents(HWND hwnd,
193 Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms)
194 {
195 Atom atomClipboard = atoms->atomClipboard;
196 Atom atomLocalProperty = atoms->atomLocalProperty;
197 Atom atomUTF8String = atoms->atomUTF8String;
198 Atom atomCompoundText = atoms->atomCompoundText;
199 Atom atomTargets = atoms->atomTargets;
200
201 /* Process all pending events */
202 while (XPending(pDisplay)) {
203 XTextProperty xtpText = { 0 };
204 XEvent event;
205 XSelectionEvent eventSelection;
206 unsigned long ulReturnBytesLeft;
207 char *pszReturnData = NULL;
208 char *pszGlobalData = NULL;
209 int iReturn;
210 HGLOBAL hGlobal = NULL;
211 XICCEncodingStyle xiccesStyle;
212 char *pszConvertData = NULL;
213 char *pszTextList[2] = { NULL };
214 int iCount;
215 char **ppszTextList = NULL;
216 wchar_t *pwszUnicodeStr = NULL;
217 Bool fAbort = FALSE;
218 Bool fCloseClipboard = FALSE;
219 Bool fSetClipboardData = TRUE;
220
221 /* Get the next event - will not block because one is ready */
222 XNextEvent(pDisplay, &event);
223
224 /* Branch on the event type */
225 switch (event.type) {
226 /*
227 * SelectionRequest
228 */
229
230 case SelectionRequest:
231 {
232 char *pszAtomName = NULL;
233
234 winDebug("SelectionRequest - target %ld\n",
235 event.xselectionrequest.target);
236
237 pszAtomName = XGetAtomName(pDisplay,
238 event.xselectionrequest.target);
239 winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
240 XFree(pszAtomName);
241 pszAtomName = NULL;
242 }
243
244 /* Abort if invalid target type */
245 if (event.xselectionrequest.target != XA_STRING
246 && event.xselectionrequest.target != atomUTF8String
247 && event.xselectionrequest.target != atomCompoundText
248 && event.xselectionrequest.target != atomTargets) {
249 /* Abort */
250 fAbort = TRUE;
251 goto winClipboardFlushXEvents_SelectionRequest_Done;
252 }
253
254 /* Handle targets type of request */
255 if (event.xselectionrequest.target == atomTargets) {
256 Atom atomTargetArr[] = { atomTargets,
257 atomCompoundText,
258 atomUTF8String,
259 XA_STRING
260 };
261
262 /* Try to change the property */
263 iReturn = XChangeProperty(pDisplay,
264 event.xselectionrequest.requestor,
265 event.xselectionrequest.property,
266 XA_ATOM,
267 32,
268 PropModeReplace,
269 (unsigned char *) atomTargetArr,
270 ARRAY_SIZE(atomTargetArr));
271 if (iReturn == BadAlloc
272 || iReturn == BadAtom
273 || iReturn == BadMatch
274 || iReturn == BadValue || iReturn == BadWindow) {
275 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
276 "XChangeProperty failed: %d\n", iReturn);
277 }
278
279 /* Setup selection notify xevent */
280 eventSelection.type = SelectionNotify;
281 eventSelection.send_event = True;
282 eventSelection.display = pDisplay;
283 eventSelection.requestor = event.xselectionrequest.requestor;
284 eventSelection.selection = event.xselectionrequest.selection;
285 eventSelection.target = event.xselectionrequest.target;
286 eventSelection.property = event.xselectionrequest.property;
287 eventSelection.time = event.xselectionrequest.time;
288
289 /*
290 * Notify the requesting window that
291 * the operation has completed
292 */
293 iReturn = XSendEvent(pDisplay,
294 eventSelection.requestor,
295 False, 0L, (XEvent *) &eventSelection);
296 if (iReturn == BadValue || iReturn == BadWindow) {
297 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
298 "XSendEvent () failed\n");
299 }
300 break;
301 }
302
303 /* Close clipboard if we have it open already */
304 if (GetOpenClipboardWindow() == hwnd) {
305 CloseClipboard();
306 }
307
308 /* Access the clipboard */
309 if (!OpenClipboard(hwnd)) {
310 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
311 "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError());
312
313 /* Abort */
314 fAbort = TRUE;
315 goto winClipboardFlushXEvents_SelectionRequest_Done;
316 }
317
318 /* Indicate that clipboard was opened */
319 fCloseClipboard = TRUE;
320
321 /* Check that clipboard format is available */
322 if (data->fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
323 static int count; /* Hack to stop acroread spamming the log */
324 static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */
325
326 if (hwnd != lasthwnd)
327 count = 0;
328 count++;
329 if (count < 6)
330 ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
331 "available from Win32 clipboard. Aborting %d.\n",
332 count);
333 lasthwnd = hwnd;
334
335 /* Abort */
336 fAbort = TRUE;
337 goto winClipboardFlushXEvents_SelectionRequest_Done;
338 }
339 else if (!data->fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) {
340 ErrorF("winClipboardFlushXEvents - CF_TEXT is not "
341 "available from Win32 clipboard. Aborting.\n");
342
343 /* Abort */
344 fAbort = TRUE;
345 goto winClipboardFlushXEvents_SelectionRequest_Done;
346 }
347
348 /* Setup the string style */
349 if (event.xselectionrequest.target == XA_STRING)
350 xiccesStyle = XStringStyle;
351 #ifdef X_HAVE_UTF8_STRING
352 else if (event.xselectionrequest.target == atomUTF8String)
353 xiccesStyle = XUTF8StringStyle;
354 #endif
355 else if (event.xselectionrequest.target == atomCompoundText)
356 xiccesStyle = XCompoundTextStyle;
357 else
358 xiccesStyle = XStringStyle;
359
360 /* Get a pointer to the clipboard text, in desired format */
361 if (data->fUseUnicode) {
362 /* Retrieve clipboard data */
363 hGlobal = GetClipboardData(CF_UNICODETEXT);
364 }
365 else {
366 /* Retrieve clipboard data */
367 hGlobal = GetClipboardData(CF_TEXT);
368 }
369 if (!hGlobal) {
370 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
371 "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError());
372
373 /* Abort */
374 fAbort = TRUE;
375 goto winClipboardFlushXEvents_SelectionRequest_Done;
376 }
377 pszGlobalData = (char *) GlobalLock(hGlobal);
378
379 /* Convert the Unicode string to UTF8 (MBCS) */
380 if (data->fUseUnicode) {
381 int iConvertDataLen = WideCharToMultiByte(CP_UTF8,
382 0,
383 (LPCWSTR) pszGlobalData,
384 -1, NULL, 0, NULL, NULL);
385 /* NOTE: iConvertDataLen includes space for null terminator */
386 pszConvertData = malloc(iConvertDataLen);
387 WideCharToMultiByte(CP_UTF8,
388 0,
389 (LPCWSTR) pszGlobalData,
390 -1,
391 pszConvertData,
392 iConvertDataLen, NULL, NULL);
393 }
394 else {
395 pszConvertData = strdup(pszGlobalData);
396 }
397
398 /* Convert DOS string to UNIX string */
399 winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
400
401 /* Setup our text list */
402 pszTextList[0] = pszConvertData;
403 pszTextList[1] = NULL;
404
405 /* Initialize the text property */
406 xtpText.value = NULL;
407 xtpText.nitems = 0;
408
409 /* Create the text property from the text list */
410 if (data->fUseUnicode) {
411 #ifdef X_HAVE_UTF8_STRING
412 iReturn = Xutf8TextListToTextProperty(pDisplay,
413 pszTextList,
414 1, xiccesStyle, &xtpText);
415 #endif
416 }
417 else {
418 iReturn = XmbTextListToTextProperty(pDisplay,
419 pszTextList,
420 1, xiccesStyle, &xtpText);
421 }
422 if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) {
423 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
424 "X*TextListToTextProperty failed: %d\n", iReturn);
425
426 /* Abort */
427 fAbort = TRUE;
428 goto winClipboardFlushXEvents_SelectionRequest_Done;
429 }
430
431 /* Free the converted string */
432 free(pszConvertData);
433 pszConvertData = NULL;
434
435 /* Copy the clipboard text to the requesting window */
436 iReturn = XChangeProperty(pDisplay,
437 event.xselectionrequest.requestor,
438 event.xselectionrequest.property,
439 event.xselectionrequest.target,
440 8,
441 PropModeReplace,
442 xtpText.value, xtpText.nitems);
443 if (iReturn == BadAlloc || iReturn == BadAtom
444 || iReturn == BadMatch || iReturn == BadValue
445 || iReturn == BadWindow) {
446 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
447 "XChangeProperty failed: %d\n", iReturn);
448
449 /* Abort */
450 fAbort = TRUE;
451 goto winClipboardFlushXEvents_SelectionRequest_Done;
452 }
453
454 /* Release the clipboard data */
455 GlobalUnlock(hGlobal);
456 pszGlobalData = NULL;
457 fCloseClipboard = FALSE;
458 CloseClipboard();
459
460 /* Clean up */
461 XFree(xtpText.value);
462 xtpText.value = NULL;
463 xtpText.nitems = 0;
464
465 /* Setup selection notify event */
466 eventSelection.type = SelectionNotify;
467 eventSelection.send_event = True;
468 eventSelection.display = pDisplay;
469 eventSelection.requestor = event.xselectionrequest.requestor;
470 eventSelection.selection = event.xselectionrequest.selection;
471 eventSelection.target = event.xselectionrequest.target;
472 eventSelection.property = event.xselectionrequest.property;
473 eventSelection.time = event.xselectionrequest.time;
474
475 /* Notify the requesting window that the operation has completed */
476 iReturn = XSendEvent(pDisplay,
477 eventSelection.requestor,
478 False, 0L, (XEvent *) &eventSelection);
479 if (iReturn == BadValue || iReturn == BadWindow) {
480 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
481 "XSendEvent () failed\n");
482
483 /* Abort */
484 fAbort = TRUE;
485 goto winClipboardFlushXEvents_SelectionRequest_Done;
486 }
487
488 winClipboardFlushXEvents_SelectionRequest_Done:
489 /* Free allocated resources */
490 if (xtpText.value) {
491 XFree(xtpText.value);
492 xtpText.value = NULL;
493 xtpText.nitems = 0;
494 }
495 free(pszConvertData);
496 if (hGlobal && pszGlobalData)
497 GlobalUnlock(hGlobal);
498
499 /*
500 * Send a SelectionNotify event to the requesting
501 * client when we abort.
502 */
503 if (fAbort) {
504 /* Setup selection notify event */
505 eventSelection.type = SelectionNotify;
506 eventSelection.send_event = True;
507 eventSelection.display = pDisplay;
508 eventSelection.requestor = event.xselectionrequest.requestor;
509 eventSelection.selection = event.xselectionrequest.selection;
510 eventSelection.target = event.xselectionrequest.target;
511 eventSelection.property = None;
512 eventSelection.time = event.xselectionrequest.time;
513
514 /* Notify the requesting window that the operation is complete */
515 iReturn = XSendEvent(pDisplay,
516 eventSelection.requestor,
517 False, 0L, (XEvent *) &eventSelection);
518 if (iReturn == BadValue || iReturn == BadWindow) {
519 /*
520 * Should not be a problem if XSendEvent fails because
521 * the client may simply have exited.
522 */
523 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
524 "XSendEvent () failed for abort event.\n");
525 }
526 }
527
528 /* Close clipboard if it was opened */
529 if (fCloseClipboard) {
530 fCloseClipboard = FALSE;
531 CloseClipboard();
532 }
533 break;
534
535 /*
536 * SelectionNotify
537 */
538
539 case SelectionNotify:
540 winDebug("winClipboardFlushXEvents - SelectionNotify\n");
541 {
542 char *pszAtomName;
543
544 pszAtomName = XGetAtomName(pDisplay,
545 event.xselection.selection);
546
547 winDebug
548 ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n",
549 pszAtomName);
550 XFree(pszAtomName);
551 }
552
553 /*
554 SelectionNotify with property of None indicates either:
555
556 (i) Generated by the X server if no owner for the specified selection exists
557 (perhaps it's disappeared on us mid-transaction), or
558 (ii) Sent by the selection owner when the requested selection conversion could
559 not be performed or server errors prevented the conversion data being returned
560 */
561 if (event.xselection.property == None) {
562 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
563 "Conversion to format %ld refused.\n",
564 event.xselection.target);
565 return WIN_XEVENTS_FAILED;
566 }
567
568 if (event.xselection.target == atomTargets) {
569 return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms);
570 }
571
572 /* Retrieve the selection data and delete the property */
573 iReturn = XGetWindowProperty(pDisplay,
574 iWindow,
575 atomLocalProperty,
576 0,
577 INT_MAX,
578 True,
579 AnyPropertyType,
580 &xtpText.encoding,
581 &xtpText.format,
582 &xtpText.nitems,
583 &ulReturnBytesLeft, &xtpText.value);
584 if (iReturn != Success) {
585 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
586 "XGetWindowProperty () failed, aborting: %d\n", iReturn);
587 goto winClipboardFlushXEvents_SelectionNotify_Done;
588 }
589
590 {
591 char *pszAtomName = NULL;
592
593 winDebug("SelectionNotify - returned data %lu left %lu\n",
594 xtpText.nitems, ulReturnBytesLeft);
595 pszAtomName = XGetAtomName(pDisplay, xtpText.encoding);
596 winDebug("Notify atom name %s\n", pszAtomName);
597 XFree(pszAtomName);
598 pszAtomName = NULL;
599 }
600
601 if (data->fUseUnicode) {
602 #ifdef X_HAVE_UTF8_STRING
603 /* Convert the text property to a text list */
604 iReturn = Xutf8TextPropertyToTextList(pDisplay,
605 &xtpText,
606 &ppszTextList, &iCount);
607 #endif
608 }
609 else {
610 iReturn = XmbTextPropertyToTextList(pDisplay,
611 &xtpText,
612 &ppszTextList, &iCount);
613 }
614 if (iReturn == Success || iReturn > 0) {
615 /* Conversion succeeded or some unconvertible characters */
616 if (ppszTextList != NULL) {
617 int i;
618 int iReturnDataLen = 0;
619 for (i = 0; i < iCount; i++) {
620 iReturnDataLen += strlen(ppszTextList[i]);
621 }
622 pszReturnData = malloc(iReturnDataLen + 1);
623 pszReturnData[0] = '\0';
624 for (i = 0; i < iCount; i++) {
625 strcat(pszReturnData, ppszTextList[i]);
626 }
627 }
628 else {
629 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
630 "X*TextPropertyToTextList list_return is NULL.\n");
631 pszReturnData = malloc(1);
632 pszReturnData[0] = '\0';
633 }
634 }
635 else {
636 ErrorF("winClipboardFlushXEvents - SelectionNotify - "
637 "X*TextPropertyToTextList returned: ");
638 switch (iReturn) {
639 case XNoMemory:
640 ErrorF("XNoMemory\n");
641 break;
642 case XLocaleNotSupported:
643 ErrorF("XLocaleNotSupported\n");
644 break;
645 case XConverterNotFound:
646 ErrorF("XConverterNotFound\n");
647 break;
648 default:
649 ErrorF("%d\n", iReturn);
650 break;
651 }
652 pszReturnData = malloc(1);
653 pszReturnData[0] = '\0';
654 }
655
656 /* Free the data returned from XGetWindowProperty */
657 if (ppszTextList)
658 XFreeStringList(ppszTextList);
659 ppszTextList = NULL;
660 XFree(xtpText.value);
661 xtpText.value = NULL;
662 xtpText.nitems = 0;
663
664 /* Convert the X clipboard string to DOS format */
665 winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
666
667 if (data->fUseUnicode) {
668 /* Find out how much space needed to convert MBCS to Unicode */
669 int iUnicodeLen = MultiByteToWideChar(CP_UTF8,
670 0,
671 pszReturnData, -1, NULL, 0);
672
673 /* NOTE: iUnicodeLen includes space for null terminator */
674 pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
675 if (!pwszUnicodeStr) {
676 ErrorF("winClipboardFlushXEvents - SelectionNotify "
677 "malloc failed for pwszUnicodeStr, aborting.\n");
678
679 /* Abort */
680 fAbort = TRUE;
681 goto winClipboardFlushXEvents_SelectionNotify_Done;
682 }
683
684 /* Do the actual conversion */
685 MultiByteToWideChar(CP_UTF8,
686 0,
687 pszReturnData,
688 -1, pwszUnicodeStr, iUnicodeLen);
689
690 /* Allocate global memory for the X clipboard data */
691 hGlobal = GlobalAlloc(GMEM_MOVEABLE,
692 sizeof(wchar_t) * iUnicodeLen);
693 }
694 else {
695 int iConvertDataLen = 0;
696 pszConvertData = strdup(pszReturnData);
697 iConvertDataLen = strlen(pszConvertData) + 1;
698
699 /* Allocate global memory for the X clipboard data */
700 hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen);
701 }
702
703 free(pszReturnData);
704
705 /* Check that global memory was allocated */
706 if (!hGlobal) {
707 ErrorF("winClipboardFlushXEvents - SelectionNotify "
708 "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
709
710 /* Abort */
711 fAbort = TRUE;
712 goto winClipboardFlushXEvents_SelectionNotify_Done;
713 }
714
715 /* Obtain a pointer to the global memory */
716 pszGlobalData = GlobalLock(hGlobal);
717 if (pszGlobalData == NULL) {
718 ErrorF("winClipboardFlushXEvents - Could not lock global "
719 "memory for clipboard transfer\n");
720
721 /* Abort */
722 fAbort = TRUE;
723 goto winClipboardFlushXEvents_SelectionNotify_Done;
724 }
725
726 /* Copy the returned string into the global memory */
727 if (data->fUseUnicode) {
728 wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
729 free(pwszUnicodeStr);
730 pwszUnicodeStr = NULL;
731 }
732 else {
733 strcpy(pszGlobalData, pszConvertData);
734 free(pszConvertData);
735 pszConvertData = NULL;
736 }
737
738 /* Release the pointer to the global memory */
739 GlobalUnlock(hGlobal);
740 pszGlobalData = NULL;
741
742 /* Push the selection data to the Windows clipboard */
743 if (data->fUseUnicode)
744 SetClipboardData(CF_UNICODETEXT, hGlobal);
745 else
746 SetClipboardData(CF_TEXT, hGlobal);
747
748 /* Flag that SetClipboardData has been called */
749 fSetClipboardData = FALSE;
750
751 /*
752 * NOTE: Do not try to free pszGlobalData, it is owned by
753 * Windows after the call to SetClipboardData ().
754 */
755
756 winClipboardFlushXEvents_SelectionNotify_Done:
757 /* Free allocated resources */
758 if (ppszTextList)
759 XFreeStringList(ppszTextList);
760 if (xtpText.value) {
761 XFree(xtpText.value);
762 xtpText.value = NULL;
763 xtpText.nitems = 0;
764 }
765 free(pszConvertData);
766 free(pwszUnicodeStr);
767 if (hGlobal && pszGlobalData)
768 GlobalUnlock(hGlobal);
769 if (fSetClipboardData) {
770 SetClipboardData(CF_UNICODETEXT, NULL);
771 SetClipboardData(CF_TEXT, NULL);
772 }
773 return WIN_XEVENTS_NOTIFY_DATA;
774
775 case SelectionClear:
776 winDebug("SelectionClear - doing nothing\n");
777 break;
778
779 case PropertyNotify:
780 break;
781
782 case MappingNotify:
783 break;
784
785 default:
786 if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) {
787 XFixesSelectionNotifyEvent *e =
788 (XFixesSelectionNotifyEvent *) & event;
789
790 winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
791
792 /* Save selection owners for monitored selections, ignore other selections */
793 if ((e->selection == XA_PRIMARY) && fPrimarySelection) {
794 MonitorSelection(e, CLIP_OWN_PRIMARY);
795 }
796 else if (e->selection == atomClipboard) {
797 MonitorSelection(e, CLIP_OWN_CLIPBOARD);
798 }
799 else
800 break;
801
802 /* Selection is being disowned */
803 if (e->owner == None) {
804 winDebug
805 ("winClipboardFlushXEvents - No window, returning.\n");
806 break;
807 }
808
809 /*
810 XXX: there are all kinds of wacky edge cases we might need here:
811 - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
812 - root window is taking ownership?
813 */
814
815 /* If we are the owner of the most recently owned selection, don't go all recursive :) */
816 if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
817 (s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
818 winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
819 break;
820 }
821
822 /* Close clipboard if we have it open already (possible? correct??) */
823 if (GetOpenClipboardWindow() == hwnd) {
824 CloseClipboard();
825 }
826
827 /* Access the Windows clipboard */
828 if (!OpenClipboard(hwnd)) {
829 ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
830 (int) GetLastError());
831 break;
832 }
833
834 /* Take ownership of the Windows clipboard */
835 if (!EmptyClipboard()) {
836 ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
837 (int) GetLastError());
838 break;
839 }
840
841 /* Advertise regular text and unicode */
842 SetClipboardData(CF_UNICODETEXT, NULL);
843 SetClipboardData(CF_TEXT, NULL);
844
845 /* Release the clipboard */
846 if (!CloseClipboard()) {
847 ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
848 (int) GetLastError());
849 break;
850 }
851 }
852 /* XFixesSelectionWindowDestroyNotifyMask */
853 /* XFixesSelectionClientCloseNotifyMask */
854 else {
855 ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
856 event.type);
857 }
858 break;
859 }
860 }
861
862 return WIN_XEVENTS_SUCCESS;
863 }
864