xevents.c revision 1b5d61b8
114b11b2bSmrg/*
214b11b2bSmrg *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
314b11b2bSmrg *Copyright (C) Colin Harrison 2005-2008
414b11b2bSmrg *
514b11b2bSmrg *Permission is hereby granted, free of charge, to any person obtaining
614b11b2bSmrg * a copy of this software and associated documentation files (the
714b11b2bSmrg *"Software"), to deal in the Software without restriction, including
814b11b2bSmrg *without limitation the rights to use, copy, modify, merge, publish,
914b11b2bSmrg *distribute, sublicense, and/or sell copies of the Software, and to
1014b11b2bSmrg *permit persons to whom the Software is furnished to do so, subject to
1114b11b2bSmrg *the following conditions:
1214b11b2bSmrg *
1314b11b2bSmrg *The above copyright notice and this permission notice shall be
1414b11b2bSmrg *included in all copies or substantial portions of the Software.
1514b11b2bSmrg *
1614b11b2bSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1714b11b2bSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1814b11b2bSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1914b11b2bSmrg *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
2014b11b2bSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2114b11b2bSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2214b11b2bSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2314b11b2bSmrg *
2414b11b2bSmrg *Except as contained in this notice, the name of the copyright holder(s)
2514b11b2bSmrg *and author(s) shall not be used in advertising or otherwise to promote
2614b11b2bSmrg *the sale, use or other dealings in this Software without prior written
2714b11b2bSmrg *authorization from the copyright holder(s) and author(s).
2814b11b2bSmrg *
2914b11b2bSmrg * Authors:	Harold L Hunt II
3014b11b2bSmrg *              Colin Harrison
3114b11b2bSmrg */
3214b11b2bSmrg
3314b11b2bSmrg#ifdef HAVE_XWIN_CONFIG_H
3414b11b2bSmrg#include <xwin-config.h>
3514b11b2bSmrg#endif
3614b11b2bSmrg
3714b11b2bSmrg/*
3814b11b2bSmrg * Including any server header might define the macro _XSERVER64 on 64 bit machines.
3914b11b2bSmrg * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen.
4014b11b2bSmrg * So let's undef that macro if necessary.
4114b11b2bSmrg */
4214b11b2bSmrg#ifdef _XSERVER64
4314b11b2bSmrg#undef _XSERVER64
4414b11b2bSmrg#endif
4514b11b2bSmrg
4614b11b2bSmrg#include <limits.h>
4714b11b2bSmrg#include <wchar.h>
4814b11b2bSmrg#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
68extern int xfixes_event_base;
69Bool fPrimarySelection = TRUE;
70
71/*
72 * Local variables
73 */
74
75static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None };
76static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
77    { "PRIMARY", "CLIPBOARD" };
78
79static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
80
81static void
82MonitorSelection(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
114Atom
115winClipboardGetLastOwnedSelectionAtom(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
130void
131winClipboardInitMonitoredSelections(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
141static int
142winClipboardSelectionNotifyTargets(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
191int
192winClipboardFlushXEvents(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