xref: /OK3568_Linux_fs/external/xserver/hw/xwin/winclipboard/xevents.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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