135c4bbdfSmrg/*
235c4bbdfSmrg *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved.
335c4bbdfSmrg *Copyright (C) Colin Harrison 2005-2008
435c4bbdfSmrg *
535c4bbdfSmrg *Permission is hereby granted, free of charge, to any person obtaining
635c4bbdfSmrg * a copy of this software and associated documentation files (the
735c4bbdfSmrg *"Software"), to deal in the Software without restriction, including
835c4bbdfSmrg *without limitation the rights to use, copy, modify, merge, publish,
935c4bbdfSmrg *distribute, sublicense, and/or sell copies of the Software, and to
1035c4bbdfSmrg *permit persons to whom the Software is furnished to do so, subject to
1135c4bbdfSmrg *the following conditions:
1235c4bbdfSmrg *
1335c4bbdfSmrg *The above copyright notice and this permission notice shall be
1435c4bbdfSmrg *included in all copies or substantial portions of the Software.
1535c4bbdfSmrg *
1635c4bbdfSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1735c4bbdfSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1835c4bbdfSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1935c4bbdfSmrg *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
2035c4bbdfSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2135c4bbdfSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2235c4bbdfSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2335c4bbdfSmrg *
2435c4bbdfSmrg *Except as contained in this notice, the name of the copyright holder(s)
2535c4bbdfSmrg *and author(s) shall not be used in advertising or otherwise to promote
2635c4bbdfSmrg *the sale, use or other dealings in this Software without prior written
2735c4bbdfSmrg *authorization from the copyright holder(s) and author(s).
2835c4bbdfSmrg *
2935c4bbdfSmrg * Authors:	Harold L Hunt II
3035c4bbdfSmrg *              Colin Harrison
3135c4bbdfSmrg */
3235c4bbdfSmrg
3335c4bbdfSmrg#ifdef HAVE_XWIN_CONFIG_H
3435c4bbdfSmrg#include <xwin-config.h>
3535c4bbdfSmrg#endif
3635c4bbdfSmrg
3735c4bbdfSmrg#include <limits.h>
3835c4bbdfSmrg#include <wchar.h>
39ed6184dfSmrg
40ed6184dfSmrg#include <xcb/xcb.h>
41ed6184dfSmrg#include <xcb/xfixes.h>
4235c4bbdfSmrg
4335c4bbdfSmrg#include "winclipboard.h"
4435c4bbdfSmrg#include "internal.h"
4535c4bbdfSmrg
4635c4bbdfSmrg/*
4735c4bbdfSmrg * Constants
4835c4bbdfSmrg */
4935c4bbdfSmrg
5035c4bbdfSmrg#define CLIP_NUM_SELECTIONS		2
51ed6184dfSmrg#define CLIP_OWN_NONE			-1
5235c4bbdfSmrg#define CLIP_OWN_PRIMARY		0
5335c4bbdfSmrg#define CLIP_OWN_CLIPBOARD		1
5435c4bbdfSmrg
55ed6184dfSmrg#define CP_ISO_8559_1 28591
56ed6184dfSmrg
5735c4bbdfSmrg/*
5835c4bbdfSmrg * Global variables
5935c4bbdfSmrg */
6035c4bbdfSmrg
6135c4bbdfSmrgextern int xfixes_event_base;
62ed6184dfSmrgBOOL fPrimarySelection = TRUE;
6335c4bbdfSmrg
6435c4bbdfSmrg/*
6535c4bbdfSmrg * Local variables
6635c4bbdfSmrg */
6735c4bbdfSmrg
68ed6184dfSmrgstatic xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE };
6935c4bbdfSmrgstatic const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
7035c4bbdfSmrg    { "PRIMARY", "CLIPBOARD" };
7135c4bbdfSmrg
7235c4bbdfSmrgstatic unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
7335c4bbdfSmrg
7435c4bbdfSmrgstatic void
75ed6184dfSmrgMonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i)
7635c4bbdfSmrg{
7735c4bbdfSmrg    /* Look for owned -> not owned transition */
78ed6184dfSmrg    if ((XCB_NONE == e->owner) && (XCB_NONE != s_iOwners[i])) {
7935c4bbdfSmrg        unsigned int other_index;
8035c4bbdfSmrg
8135c4bbdfSmrg        winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
8235c4bbdfSmrg                 szSelectionNames[i]);
8335c4bbdfSmrg
8435c4bbdfSmrg        /* If this selection is not owned, the other monitored selection must be the most
8535c4bbdfSmrg           recently owned, if it is owned at all */
8635c4bbdfSmrg        if (i == CLIP_OWN_PRIMARY)
8735c4bbdfSmrg            other_index = CLIP_OWN_CLIPBOARD;
8835c4bbdfSmrg        if (i == CLIP_OWN_CLIPBOARD)
8935c4bbdfSmrg            other_index = CLIP_OWN_PRIMARY;
90ed6184dfSmrg        if (XCB_NONE != s_iOwners[other_index])
9135c4bbdfSmrg            lastOwnedSelectionIndex = other_index;
9235c4bbdfSmrg        else
9335c4bbdfSmrg            lastOwnedSelectionIndex = CLIP_OWN_NONE;
9435c4bbdfSmrg    }
9535c4bbdfSmrg
9635c4bbdfSmrg    /* Save last owned selection */
97ed6184dfSmrg    if (XCB_NONE != e->owner) {
9835c4bbdfSmrg        lastOwnedSelectionIndex = i;
9935c4bbdfSmrg    }
10035c4bbdfSmrg
10135c4bbdfSmrg    /* Save new selection owner or None */
10235c4bbdfSmrg    s_iOwners[i] = e->owner;
103ed6184dfSmrg    winDebug("MonitorSelection - %s - Now owned by XID %x\n",
10435c4bbdfSmrg             szSelectionNames[i], e->owner);
10535c4bbdfSmrg}
10635c4bbdfSmrg
107ed6184dfSmrgxcb_atom_t
10835c4bbdfSmrgwinClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
10935c4bbdfSmrg{
11035c4bbdfSmrg    if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
111ed6184dfSmrg        return XCB_NONE;
11235c4bbdfSmrg
11335c4bbdfSmrg    if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
114ed6184dfSmrg        return XCB_ATOM_PRIMARY;
11535c4bbdfSmrg
11635c4bbdfSmrg    if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
11735c4bbdfSmrg        return atoms->atomClipboard;
11835c4bbdfSmrg
119ed6184dfSmrg    return XCB_NONE;
12035c4bbdfSmrg}
12135c4bbdfSmrg
12235c4bbdfSmrg
12335c4bbdfSmrgvoid
12435c4bbdfSmrgwinClipboardInitMonitoredSelections(void)
12535c4bbdfSmrg{
12635c4bbdfSmrg    /* Initialize static variables */
12735c4bbdfSmrg    int i;
12835c4bbdfSmrg    for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
129ed6184dfSmrg      s_iOwners[i] = XCB_NONE;
13035c4bbdfSmrg
13135c4bbdfSmrg    lastOwnedSelectionIndex = CLIP_OWN_NONE;
13235c4bbdfSmrg}
13335c4bbdfSmrg
134ed6184dfSmrgstatic char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
13535c4bbdfSmrg{
136ed6184dfSmrg    char *ret;
137ed6184dfSmrg    xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom);
138ed6184dfSmrg    xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL);
139ed6184dfSmrg    if (!reply)
140ed6184dfSmrg        return NULL;
141ed6184dfSmrg    ret = malloc(xcb_get_atom_name_name_length(reply) + 1);
142ed6184dfSmrg    if (ret) {
143ed6184dfSmrg        memcpy(ret, xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
144ed6184dfSmrg        ret[xcb_get_atom_name_name_length(reply)] = '\0';
145ed6184dfSmrg    }
146ed6184dfSmrg    free(reply);
147ed6184dfSmrg    return ret;
148ed6184dfSmrg}
14935c4bbdfSmrg
150ed6184dfSmrgstatic int
151ed6184dfSmrgwinClipboardSelectionNotifyTargets(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
152ed6184dfSmrg{
15335c4bbdfSmrg  /* Retrieve the selection data and delete the property */
154ed6184dfSmrg  xcb_get_property_cookie_t cookie = xcb_get_property(conn,
155ed6184dfSmrg                                                      TRUE,
156ed6184dfSmrg                                                      iWindow,
157ed6184dfSmrg                                                      atoms->atomLocalProperty,
158ed6184dfSmrg                                                      XCB_GET_PROPERTY_TYPE_ANY,
159ed6184dfSmrg                                                      0,
160ed6184dfSmrg                                                      INT_MAX);
161ed6184dfSmrg  xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
162ed6184dfSmrg  if (!reply) {
163ed6184dfSmrg      ErrorF("winClipboardFlushXEvents - SelectionNotify - "
164ed6184dfSmrg             "XGetWindowProperty () failed\n");
16535c4bbdfSmrg  } else {
166ed6184dfSmrg      xcb_atom_t *prop = xcb_get_property_value(reply);
167ed6184dfSmrg      int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
168ed6184dfSmrg      int i;
169ed6184dfSmrg      data->targetList = malloc((nitems+1)*sizeof(xcb_atom_t));
170ed6184dfSmrg
171ed6184dfSmrg      for (i = 0; i < nitems; i++)
172ed6184dfSmrg          {
173ed6184dfSmrg              xcb_atom_t atom = prop[i];
174ed6184dfSmrg              char *pszAtomName = get_atom_name(conn, atom);
175ed6184dfSmrg              data->targetList[i] = atom;
176ed6184dfSmrg              winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName);
177ed6184dfSmrg              free(pszAtomName);
17835c4bbdfSmrg      }
17935c4bbdfSmrg
18035c4bbdfSmrg    data->targetList[nitems] = 0;
18135c4bbdfSmrg
182ed6184dfSmrg    free(reply);
18335c4bbdfSmrg  }
18435c4bbdfSmrg
18535c4bbdfSmrg  return WIN_XEVENTS_NOTIFY_TARGETS;
18635c4bbdfSmrg}
18735c4bbdfSmrg
188ed6184dfSmrgstatic int
189ed6184dfSmrgwinClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
190ed6184dfSmrg{
191ed6184dfSmrg    xcb_atom_t encoding;
192ed6184dfSmrg    int format;
193ed6184dfSmrg    unsigned long int nitems;
194ed6184dfSmrg    unsigned long int after;
195ed6184dfSmrg    unsigned char *value;
196ed6184dfSmrg
197ed6184dfSmrg    unsigned char *xtpText_value;
198ed6184dfSmrg    xcb_atom_t xtpText_encoding;
199ed6184dfSmrg    int xtpText_nitems;
200ed6184dfSmrg
201ed6184dfSmrg    BOOL fSetClipboardData = TRUE;
202ed6184dfSmrg    char *pszReturnData = NULL;
203ed6184dfSmrg    UINT codepage;
204ed6184dfSmrg    wchar_t *pwszUnicodeStr = NULL;
205ed6184dfSmrg    HGLOBAL hGlobal = NULL;
206ed6184dfSmrg    char *pszGlobalData = NULL;
207ed6184dfSmrg
208ed6184dfSmrg    /* Retrieve the selection data and delete the property */
209ed6184dfSmrg    xcb_get_property_cookie_t cookie = xcb_get_property(conn,
210ed6184dfSmrg                                                        TRUE,
211ed6184dfSmrg                                                        iWindow,
212ed6184dfSmrg                                                        atoms->atomLocalProperty,
213ed6184dfSmrg                                                        XCB_GET_PROPERTY_TYPE_ANY,
214ed6184dfSmrg                                                        0,
215ed6184dfSmrg                                                        INT_MAX);
216ed6184dfSmrg    xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
217ed6184dfSmrg    if (!reply) {
218ed6184dfSmrg        ErrorF("winClipboardFlushXEvents - SelectionNotify - "
219ed6184dfSmrg               "XGetWindowProperty () failed\n");
220ed6184dfSmrg        goto winClipboardFlushXEvents_SelectionNotify_Done;
221ed6184dfSmrg    } else {
222ed6184dfSmrg        nitems = xcb_get_property_value_length(reply);
223ed6184dfSmrg        value =  xcb_get_property_value(reply);
224ed6184dfSmrg        after = reply->bytes_after;
225ed6184dfSmrg        encoding = reply->type;
226ed6184dfSmrg        format = reply->format;
227ed6184dfSmrg        // We assume format == 8 (i.e. data is a sequence of bytes).  It's not
228ed6184dfSmrg        // clear how anything else should be handled.
229ed6184dfSmrg        if (format != 8)
230ed6184dfSmrg            ErrorF("SelectionNotify: format is %d, proceeding as if it was 8\n", format);
231ed6184dfSmrg    }
232ed6184dfSmrg
233ed6184dfSmrg    {
234ed6184dfSmrg        char *pszAtomName;
235ed6184dfSmrg        winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
236ed6184dfSmrg        pszAtomName = get_atom_name(conn, encoding);
237ed6184dfSmrg        winDebug("Notify atom name %s\n", pszAtomName);
238ed6184dfSmrg        free(pszAtomName);
239ed6184dfSmrg    }
240ed6184dfSmrg
241ed6184dfSmrg    /* INCR reply indicates the start of a incremental transfer */
242ed6184dfSmrg    if (encoding == atoms->atomIncr) {
243ed6184dfSmrg        winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value);
244ed6184dfSmrg        data->incrsize = 0;
245ed6184dfSmrg        data->incr = malloc(*(int *)value);
246ed6184dfSmrg        // XXX: if malloc failed, we have an error
247ed6184dfSmrg        return WIN_XEVENTS_SUCCESS;
248ed6184dfSmrg    }
249ed6184dfSmrg    else if (data->incr) {
250ed6184dfSmrg        /* If an INCR transfer is in progress ... */
251ed6184dfSmrg        if (nitems == 0) {
252ed6184dfSmrg            winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
253ed6184dfSmrg            /* a zero-length property indicates the end of the data */
254ed6184dfSmrg            xtpText_value = data->incr;
255ed6184dfSmrg            xtpText_encoding = encoding;
256ed6184dfSmrg            // XXX: The type of the converted selection is the type of the first
257ed6184dfSmrg            // partial property. The remaining partial properties must have the
258ed6184dfSmrg            // same type.
259ed6184dfSmrg            xtpText_nitems = data->incrsize;
260ed6184dfSmrg        }
261ed6184dfSmrg        else {
262ed6184dfSmrg            /* Otherwise, continue appending the INCR data */
263ed6184dfSmrg            winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems);
264ed6184dfSmrg            data->incr = realloc(data->incr, data->incrsize + nitems);
265ed6184dfSmrg            memcpy(data->incr + data->incrsize, value, nitems);
266ed6184dfSmrg            data->incrsize = data->incrsize + nitems;
267ed6184dfSmrg            return WIN_XEVENTS_SUCCESS;
268ed6184dfSmrg        }
269ed6184dfSmrg    }
270ed6184dfSmrg    else {
271ed6184dfSmrg        /* Otherwise, the data is just contained in the property */
272ed6184dfSmrg        winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
273ed6184dfSmrg        xtpText_value = value;
274ed6184dfSmrg        xtpText_encoding = encoding;
275ed6184dfSmrg        xtpText_nitems = nitems;
276ed6184dfSmrg    }
277ed6184dfSmrg
278ed6184dfSmrg    if (xtpText_encoding == atoms->atomUTF8String) {
279ed6184dfSmrg        pszReturnData = malloc(xtpText_nitems + 1);
280ed6184dfSmrg        memcpy(pszReturnData, xtpText_value, xtpText_nitems);
281ed6184dfSmrg        pszReturnData[xtpText_nitems] = 0;
282ed6184dfSmrg        codepage = CP_UTF8; // code page identifier for utf8
283ed6184dfSmrg    } else if (xtpText_encoding == XCB_ATOM_STRING) {
284ed6184dfSmrg        // STRING encoding is Latin1 (ISO8859-1) plus tab and newline
285ed6184dfSmrg        pszReturnData = malloc(xtpText_nitems + 1);
286ed6184dfSmrg        memcpy(pszReturnData, xtpText_value, xtpText_nitems);
287ed6184dfSmrg        pszReturnData[xtpText_nitems] = 0;
288ed6184dfSmrg        codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
289ed6184dfSmrg    } else if (xtpText_encoding == atoms->atomCompoundText) {
290ed6184dfSmrg        // COMPOUND_TEXT is complex, based on ISO 2022
291ed6184dfSmrg        ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n");
292ed6184dfSmrg        pszReturnData = malloc(1);
293ed6184dfSmrg        pszReturnData[0] = '\0';
294ed6184dfSmrg    } else { // shouldn't happen as we accept no other encodings
295ed6184dfSmrg        pszReturnData = malloc(1);
296ed6184dfSmrg        pszReturnData[0] = '\0';
297ed6184dfSmrg    }
298ed6184dfSmrg
299ed6184dfSmrg    /* Free the data returned from xcb_get_property */
300ed6184dfSmrg    free(reply);
301ed6184dfSmrg
302ed6184dfSmrg    /* Free any INCR data */
303ed6184dfSmrg    if (data->incr) {
304ed6184dfSmrg        free(data->incr);
305ed6184dfSmrg        data->incr = NULL;
306ed6184dfSmrg        data->incrsize = 0;
307ed6184dfSmrg    }
308ed6184dfSmrg
309ed6184dfSmrg    /* Convert the X clipboard string to DOS format */
310ed6184dfSmrg    winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
311ed6184dfSmrg
312ed6184dfSmrg    /* Find out how much space needed when converted to UTF-16 */
313ed6184dfSmrg    int iUnicodeLen = MultiByteToWideChar(codepage, 0,
314ed6184dfSmrg                                          pszReturnData, -1, NULL, 0);
315ed6184dfSmrg
316ed6184dfSmrg    /* NOTE: iUnicodeLen includes space for null terminator */
317ed6184dfSmrg    pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
318ed6184dfSmrg    if (!pwszUnicodeStr) {
319ed6184dfSmrg        ErrorF("winClipboardFlushXEvents - SelectionNotify "
320ed6184dfSmrg               "malloc failed for pwszUnicodeStr, aborting.\n");
321ed6184dfSmrg
322ed6184dfSmrg        /* Abort */
323ed6184dfSmrg        goto winClipboardFlushXEvents_SelectionNotify_Done;
324ed6184dfSmrg    }
325ed6184dfSmrg
326ed6184dfSmrg    /* Do the actual conversion */
327ed6184dfSmrg    MultiByteToWideChar(codepage, 0,
328ed6184dfSmrg                        pszReturnData, -1, pwszUnicodeStr, iUnicodeLen);
329ed6184dfSmrg
330ed6184dfSmrg    /* Allocate global memory for the X clipboard data */
331ed6184dfSmrg    hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen);
332ed6184dfSmrg
333ed6184dfSmrg    free(pszReturnData);
334ed6184dfSmrg
335ed6184dfSmrg    /* Check that global memory was allocated */
336ed6184dfSmrg    if (!hGlobal) {
337ed6184dfSmrg        ErrorF("winClipboardFlushXEvents - SelectionNotify "
338ed6184dfSmrg               "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
339ed6184dfSmrg
340ed6184dfSmrg        /* Abort */
341ed6184dfSmrg        goto winClipboardFlushXEvents_SelectionNotify_Done;
342ed6184dfSmrg    }
343ed6184dfSmrg
344ed6184dfSmrg    /* Obtain a pointer to the global memory */
345ed6184dfSmrg    pszGlobalData = GlobalLock(hGlobal);
346ed6184dfSmrg    if (pszGlobalData == NULL) {
347ed6184dfSmrg        ErrorF("winClipboardFlushXEvents - Could not lock global "
348ed6184dfSmrg               "memory for clipboard transfer\n");
349ed6184dfSmrg
350ed6184dfSmrg        /* Abort */
351ed6184dfSmrg        goto winClipboardFlushXEvents_SelectionNotify_Done;
352ed6184dfSmrg    }
353ed6184dfSmrg
354ed6184dfSmrg    /* Copy the returned string into the global memory */
355ed6184dfSmrg    wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
356ed6184dfSmrg    free(pwszUnicodeStr);
357ed6184dfSmrg    pwszUnicodeStr = NULL;
358ed6184dfSmrg
359ed6184dfSmrg    /* Release the pointer to the global memory */
360ed6184dfSmrg    GlobalUnlock(hGlobal);
361ed6184dfSmrg    pszGlobalData = NULL;
362ed6184dfSmrg
363ed6184dfSmrg    /* Push the selection data to the Windows clipboard */
364ed6184dfSmrg    SetClipboardData(CF_UNICODETEXT, hGlobal);
365ed6184dfSmrg
366ed6184dfSmrg    /* Flag that SetClipboardData has been called */
367ed6184dfSmrg    fSetClipboardData = FALSE;
368ed6184dfSmrg
369ed6184dfSmrg    /*
370ed6184dfSmrg     * NOTE: Do not try to free pszGlobalData, it is owned by
371ed6184dfSmrg     * Windows after the call to SetClipboardData ().
372ed6184dfSmrg     */
373ed6184dfSmrg
374ed6184dfSmrg winClipboardFlushXEvents_SelectionNotify_Done:
375ed6184dfSmrg    /* Free allocated resources */
376ed6184dfSmrg    free(pwszUnicodeStr);
377ed6184dfSmrg    if (hGlobal && pszGlobalData)
378ed6184dfSmrg        GlobalUnlock(hGlobal);
379ed6184dfSmrg    if (fSetClipboardData) {
380ed6184dfSmrg        SetClipboardData(CF_UNICODETEXT, NULL);
381ed6184dfSmrg        SetClipboardData(CF_TEXT, NULL);
382ed6184dfSmrg    }
383ed6184dfSmrg    return WIN_XEVENTS_NOTIFY_DATA;
384ed6184dfSmrg}
385ed6184dfSmrg
38635c4bbdfSmrg/*
38735c4bbdfSmrg * Process any pending X events
38835c4bbdfSmrg */
38935c4bbdfSmrg
39035c4bbdfSmrgint
39135c4bbdfSmrgwinClipboardFlushXEvents(HWND hwnd,
392ed6184dfSmrg                         xcb_window_t iWindow, xcb_connection_t *conn,
393ed6184dfSmrg                         ClipboardConversionData *data, ClipboardAtoms *atoms)
39435c4bbdfSmrg{
395ed6184dfSmrg    xcb_atom_t atomClipboard = atoms->atomClipboard;
396ed6184dfSmrg    xcb_atom_t atomUTF8String = atoms->atomUTF8String;
397ed6184dfSmrg    xcb_atom_t atomCompoundText = atoms->atomCompoundText;
398ed6184dfSmrg    xcb_atom_t atomTargets = atoms->atomTargets;
39935c4bbdfSmrg
40035c4bbdfSmrg    /* Process all pending events */
401ed6184dfSmrg    xcb_generic_event_t *event;
402ed6184dfSmrg    while ((event = xcb_poll_for_event(conn))) {
403ed6184dfSmrg        const char *pszGlobalData = NULL;
40435c4bbdfSmrg        HGLOBAL hGlobal = NULL;
40535c4bbdfSmrg        char *pszConvertData = NULL;
406ed6184dfSmrg        BOOL fAbort = FALSE;
407ed6184dfSmrg        BOOL fCloseClipboard = FALSE;
40835c4bbdfSmrg
40935c4bbdfSmrg        /* Branch on the event type */
410ed6184dfSmrg        switch (event->response_type & ~0x80) {
411ed6184dfSmrg        case XCB_SELECTION_REQUEST:
412ed6184dfSmrg        {
413ed6184dfSmrg            char *xtpText_value = NULL;
414ed6184dfSmrg            int xtpText_nitems;
415ed6184dfSmrg            UINT codepage;
41635c4bbdfSmrg
417ed6184dfSmrg            xcb_selection_request_event_t *selection_request =  (xcb_selection_request_event_t *)event;
41835c4bbdfSmrg        {
41935c4bbdfSmrg            char *pszAtomName = NULL;
42035c4bbdfSmrg
421ed6184dfSmrg            winDebug("SelectionRequest - target %d\n", selection_request->target);
42235c4bbdfSmrg
423ed6184dfSmrg            pszAtomName = get_atom_name(conn, selection_request->target);
42435c4bbdfSmrg            winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
425ed6184dfSmrg            free(pszAtomName);
42635c4bbdfSmrg        }
42735c4bbdfSmrg
42835c4bbdfSmrg            /* Abort if invalid target type */
429ed6184dfSmrg            if (selection_request->target != XCB_ATOM_STRING
430ed6184dfSmrg                && selection_request->target != atomUTF8String
431ed6184dfSmrg                && selection_request->target != atomCompoundText
432ed6184dfSmrg                && selection_request->target != atomTargets) {
43335c4bbdfSmrg                /* Abort */
43435c4bbdfSmrg                fAbort = TRUE;
43535c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
43635c4bbdfSmrg            }
43735c4bbdfSmrg
43835c4bbdfSmrg            /* Handle targets type of request */
439ed6184dfSmrg            if (selection_request->target == atomTargets) {
440ed6184dfSmrg                xcb_atom_t atomTargetArr[] =
441ed6184dfSmrg                    {
442ed6184dfSmrg                     atomTargets,
443ed6184dfSmrg                     atomUTF8String,
444ed6184dfSmrg                     XCB_ATOM_STRING,
445ed6184dfSmrg                     // atomCompoundText, not implemented (yet?)
446ed6184dfSmrg                    };
44735c4bbdfSmrg
44835c4bbdfSmrg                /* Try to change the property */
449ed6184dfSmrg                xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
450ed6184dfSmrg                                          XCB_PROP_MODE_REPLACE,
451ed6184dfSmrg                                          selection_request->requestor,
452ed6184dfSmrg                                          selection_request->property,
453ed6184dfSmrg                                          XCB_ATOM_ATOM,
45435c4bbdfSmrg                                          32,
455ed6184dfSmrg                                          ARRAY_SIZE(atomTargetArr),
456ed6184dfSmrg                                          (unsigned char *) atomTargetArr);
457ed6184dfSmrg                xcb_generic_error_t *error;
458ed6184dfSmrg                if ((error = xcb_request_check(conn, cookie))) {
45935c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - SelectionRequest - "
460ed6184dfSmrg                           "xcb_change_property failed");
461ed6184dfSmrg                    free(error);
46235c4bbdfSmrg                }
46335c4bbdfSmrg
46435c4bbdfSmrg                /* Setup selection notify xevent */
465ed6184dfSmrg                xcb_selection_notify_event_t eventSelection;
466ed6184dfSmrg                eventSelection.response_type = XCB_SELECTION_NOTIFY;
467ed6184dfSmrg                eventSelection.requestor = selection_request->requestor;
468ed6184dfSmrg                eventSelection.selection = selection_request->selection;
469ed6184dfSmrg                eventSelection.target = selection_request->target;
470ed6184dfSmrg                eventSelection.property = selection_request->property;
471ed6184dfSmrg                eventSelection.time = selection_request->time;
47235c4bbdfSmrg
47335c4bbdfSmrg                /*
47435c4bbdfSmrg                 * Notify the requesting window that
47535c4bbdfSmrg                 * the operation has completed
47635c4bbdfSmrg                 */
477ed6184dfSmrg                cookie = xcb_send_event_checked(conn, FALSE,
478ed6184dfSmrg                                                eventSelection.requestor,
479ed6184dfSmrg                                                0, (char *) &eventSelection);
480ed6184dfSmrg                if ((error = xcb_request_check(conn, cookie))) {
48135c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - SelectionRequest - "
482ed6184dfSmrg                           "xcb_send_event() failed\n");
48335c4bbdfSmrg                }
48435c4bbdfSmrg                break;
48535c4bbdfSmrg            }
48635c4bbdfSmrg
48735c4bbdfSmrg            /* Close clipboard if we have it open already */
48835c4bbdfSmrg            if (GetOpenClipboardWindow() == hwnd) {
48935c4bbdfSmrg                CloseClipboard();
49035c4bbdfSmrg            }
49135c4bbdfSmrg
49235c4bbdfSmrg            /* Access the clipboard */
49335c4bbdfSmrg            if (!OpenClipboard(hwnd)) {
49435c4bbdfSmrg                ErrorF("winClipboardFlushXEvents - SelectionRequest - "
49535c4bbdfSmrg                       "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError());
49635c4bbdfSmrg
49735c4bbdfSmrg                /* Abort */
49835c4bbdfSmrg                fAbort = TRUE;
49935c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
50035c4bbdfSmrg            }
50135c4bbdfSmrg
50235c4bbdfSmrg            /* Indicate that clipboard was opened */
50335c4bbdfSmrg            fCloseClipboard = TRUE;
50435c4bbdfSmrg
50535c4bbdfSmrg            /* Check that clipboard format is available */
506ed6184dfSmrg            if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {
50735c4bbdfSmrg                static int count;       /* Hack to stop acroread spamming the log */
50835c4bbdfSmrg                static HWND lasthwnd;   /* I've not seen any other client get here repeatedly? */
50935c4bbdfSmrg
51035c4bbdfSmrg                if (hwnd != lasthwnd)
51135c4bbdfSmrg                    count = 0;
51235c4bbdfSmrg                count++;
51335c4bbdfSmrg                if (count < 6)
51435c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
51535c4bbdfSmrg                           "available from Win32 clipboard.  Aborting %d.\n",
51635c4bbdfSmrg                           count);
51735c4bbdfSmrg                lasthwnd = hwnd;
51835c4bbdfSmrg
51935c4bbdfSmrg                /* Abort */
52035c4bbdfSmrg                fAbort = TRUE;
52135c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
52235c4bbdfSmrg            }
52335c4bbdfSmrg
52435c4bbdfSmrg            /* Get a pointer to the clipboard text, in desired format */
525ed6184dfSmrg            /* Retrieve clipboard data */
526ed6184dfSmrg            hGlobal = GetClipboardData(CF_UNICODETEXT);
527ed6184dfSmrg
52835c4bbdfSmrg            if (!hGlobal) {
52935c4bbdfSmrg                ErrorF("winClipboardFlushXEvents - SelectionRequest - "
53035c4bbdfSmrg                       "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError());
53135c4bbdfSmrg
53235c4bbdfSmrg                /* Abort */
53335c4bbdfSmrg                fAbort = TRUE;
53435c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
53535c4bbdfSmrg            }
53635c4bbdfSmrg            pszGlobalData = (char *) GlobalLock(hGlobal);
53735c4bbdfSmrg
538ed6184dfSmrg            /* Convert to target string style */
539ed6184dfSmrg            if (selection_request->target == XCB_ATOM_STRING) {
540ed6184dfSmrg                codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
541ed6184dfSmrg            } else if (selection_request->target == atomUTF8String) {
542ed6184dfSmrg                codepage = CP_UTF8; // code page identifier for utf8
543ed6184dfSmrg            } else if (selection_request->target == atomCompoundText) {
544ed6184dfSmrg                // COMPOUND_TEXT is complex, not (yet) implemented
545ed6184dfSmrg                pszGlobalData = "COMPOUND_TEXT not implemented";
546ed6184dfSmrg                codepage = CP_UTF8; // code page identifier for utf8
547ed6184dfSmrg            }
548ed6184dfSmrg
549ed6184dfSmrg            /* Convert the UTF16 string to required encoding */
550ed6184dfSmrg            int iConvertDataLen = WideCharToMultiByte(codepage, 0,
551ed6184dfSmrg                                                      (LPCWSTR) pszGlobalData, -1,
552ed6184dfSmrg                                                      NULL, 0, NULL, NULL);
553ed6184dfSmrg            /* NOTE: iConvertDataLen includes space for null terminator */
554ed6184dfSmrg            pszConvertData = malloc(iConvertDataLen);
555ed6184dfSmrg            WideCharToMultiByte(codepage, 0,
556ed6184dfSmrg                                (LPCWSTR) pszGlobalData, -1,
557ed6184dfSmrg                                pszConvertData, iConvertDataLen, NULL, NULL);
55835c4bbdfSmrg
55935c4bbdfSmrg            /* Convert DOS string to UNIX string */
56035c4bbdfSmrg            winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
56135c4bbdfSmrg
562ed6184dfSmrg            xtpText_value = strdup(pszConvertData);
563ed6184dfSmrg            xtpText_nitems = strlen(pszConvertData);
56435c4bbdfSmrg
565ed6184dfSmrg            /* data will fit into a single X request? (INCR not yet supported) */
566ed6184dfSmrg            {
567ed6184dfSmrg                uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
56835c4bbdfSmrg
569ed6184dfSmrg                /* covert to bytes and allow for allow for X_ChangeProperty request */
570ed6184dfSmrg                maxreqsize = maxreqsize*4 - 24;
57135c4bbdfSmrg
572ed6184dfSmrg                if (xtpText_nitems > maxreqsize) {
573ed6184dfSmrg                    ErrorF("winClipboardFlushXEvents - clipboard data size %d greater than maximum %u\n", xtpText_nitems, maxreqsize);
57435c4bbdfSmrg
575ed6184dfSmrg                    /* Abort */
576ed6184dfSmrg                    fAbort = TRUE;
577ed6184dfSmrg                    goto winClipboardFlushXEvents_SelectionRequest_Done;
578ed6184dfSmrg                }
579ed6184dfSmrg            }
58035c4bbdfSmrg
58135c4bbdfSmrg            /* Copy the clipboard text to the requesting window */
582ed6184dfSmrg            xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
583ed6184dfSmrg                                      XCB_PROP_MODE_REPLACE,
584ed6184dfSmrg                                      selection_request->requestor,
585ed6184dfSmrg                                      selection_request->property,
586ed6184dfSmrg                                      selection_request->target,
58735c4bbdfSmrg                                      8,
588ed6184dfSmrg                                      xtpText_nitems, xtpText_value);
589ed6184dfSmrg            xcb_generic_error_t *error;
590ed6184dfSmrg            if ((error = xcb_request_check(conn, cookie))) {
59135c4bbdfSmrg                ErrorF("winClipboardFlushXEvents - SelectionRequest - "
592ed6184dfSmrg                       "xcb_change_property failed\n");
59335c4bbdfSmrg
59435c4bbdfSmrg                /* Abort */
59535c4bbdfSmrg                fAbort = TRUE;
59635c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
59735c4bbdfSmrg            }
59835c4bbdfSmrg
599ed6184dfSmrg            /* Free the converted string */
600ed6184dfSmrg            free(pszConvertData);
601ed6184dfSmrg            pszConvertData = NULL;
602ed6184dfSmrg
60335c4bbdfSmrg            /* Release the clipboard data */
60435c4bbdfSmrg            GlobalUnlock(hGlobal);
60535c4bbdfSmrg            pszGlobalData = NULL;
60635c4bbdfSmrg            fCloseClipboard = FALSE;
60735c4bbdfSmrg            CloseClipboard();
60835c4bbdfSmrg
60935c4bbdfSmrg            /* Clean up */
610ed6184dfSmrg            free(xtpText_value);
611ed6184dfSmrg            xtpText_value = NULL;
61235c4bbdfSmrg
61335c4bbdfSmrg            /* Setup selection notify event */
614ed6184dfSmrg            xcb_selection_notify_event_t eventSelection;
615ed6184dfSmrg            eventSelection.response_type = XCB_SELECTION_NOTIFY;
616ed6184dfSmrg            eventSelection.requestor = selection_request->requestor;
617ed6184dfSmrg            eventSelection.selection = selection_request->selection;
618ed6184dfSmrg            eventSelection.target = selection_request->target;
619ed6184dfSmrg            eventSelection.property = selection_request->property;
620ed6184dfSmrg            eventSelection.time = selection_request->time;
62135c4bbdfSmrg
62235c4bbdfSmrg            /* Notify the requesting window that the operation has completed */
623ed6184dfSmrg            cookie = xcb_send_event_checked(conn, FALSE,
624ed6184dfSmrg                                            eventSelection.requestor,
625ed6184dfSmrg                                            0, (char *) &eventSelection);
626ed6184dfSmrg            if ((error = xcb_request_check(conn, cookie))) {
62735c4bbdfSmrg                ErrorF("winClipboardFlushXEvents - SelectionRequest - "
628ed6184dfSmrg                       "xcb_send_event() failed\n");
62935c4bbdfSmrg
63035c4bbdfSmrg                /* Abort */
63135c4bbdfSmrg                fAbort = TRUE;
63235c4bbdfSmrg                goto winClipboardFlushXEvents_SelectionRequest_Done;
63335c4bbdfSmrg            }
63435c4bbdfSmrg
63535c4bbdfSmrg winClipboardFlushXEvents_SelectionRequest_Done:
63635c4bbdfSmrg            /* Free allocated resources */
637ed6184dfSmrg            if (xtpText_value) {
638ed6184dfSmrg                free(xtpText_value);
63935c4bbdfSmrg            }
640ed6184dfSmrg            if (pszConvertData)
641ed6184dfSmrg                free(pszConvertData);
64235c4bbdfSmrg            if (hGlobal && pszGlobalData)
64335c4bbdfSmrg                GlobalUnlock(hGlobal);
64435c4bbdfSmrg
64535c4bbdfSmrg            /*
64635c4bbdfSmrg             * Send a SelectionNotify event to the requesting
64735c4bbdfSmrg             * client when we abort.
64835c4bbdfSmrg             */
64935c4bbdfSmrg            if (fAbort) {
65035c4bbdfSmrg                /* Setup selection notify event */
651ed6184dfSmrg                eventSelection.response_type = XCB_SELECTION_NOTIFY;
652ed6184dfSmrg                eventSelection.requestor = selection_request->requestor;
653ed6184dfSmrg                eventSelection.selection = selection_request->selection;
654ed6184dfSmrg                eventSelection.target = selection_request->target;
655ed6184dfSmrg                eventSelection.property = XCB_NONE;
656ed6184dfSmrg                eventSelection.time = selection_request->time;
65735c4bbdfSmrg
65835c4bbdfSmrg                /* Notify the requesting window that the operation is complete */
659ed6184dfSmrg                cookie = xcb_send_event_checked(conn, FALSE,
660ed6184dfSmrg                                                eventSelection.requestor,
661ed6184dfSmrg                                                0, (char *) &eventSelection);
662ed6184dfSmrg                if ((error = xcb_request_check(conn, cookie))) {
66335c4bbdfSmrg                    /*
66435c4bbdfSmrg                     * Should not be a problem if XSendEvent fails because
66535c4bbdfSmrg                     * the client may simply have exited.
66635c4bbdfSmrg                     */
66735c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - SelectionRequest - "
668ed6184dfSmrg                           "xcb_send_event() failed for abort event.\n");
66935c4bbdfSmrg                }
67035c4bbdfSmrg            }
67135c4bbdfSmrg
67235c4bbdfSmrg            /* Close clipboard if it was opened */
67335c4bbdfSmrg            if (fCloseClipboard) {
67435c4bbdfSmrg                fCloseClipboard = FALSE;
67535c4bbdfSmrg                CloseClipboard();
67635c4bbdfSmrg            }
67735c4bbdfSmrg            break;
678ed6184dfSmrg        }
67935c4bbdfSmrg
680ed6184dfSmrg        case XCB_SELECTION_NOTIFY:
681ed6184dfSmrg        {
682ed6184dfSmrg            xcb_selection_notify_event_t *selection_notify =  (xcb_selection_notify_event_t *)event;
68335c4bbdfSmrg            winDebug("winClipboardFlushXEvents - SelectionNotify\n");
68435c4bbdfSmrg            {
68535c4bbdfSmrg                char *pszAtomName;
686ed6184dfSmrg                pszAtomName = get_atom_name(conn, selection_notify->selection);
687ed6184dfSmrg                winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
688ed6184dfSmrg                free(pszAtomName);
68935c4bbdfSmrg            }
69035c4bbdfSmrg
69135c4bbdfSmrg            /*
692ed6184dfSmrg              SelectionNotify with property of XCB_NONE indicates either:
69335c4bbdfSmrg
69435c4bbdfSmrg              (i) Generated by the X server if no owner for the specified selection exists
69535c4bbdfSmrg                  (perhaps it's disappeared on us mid-transaction), or
69635c4bbdfSmrg              (ii) Sent by the selection owner when the requested selection conversion could
69735c4bbdfSmrg                   not be performed or server errors prevented the conversion data being returned
69835c4bbdfSmrg            */
699ed6184dfSmrg            if (selection_notify->property == XCB_NONE) {
70035c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - SelectionNotify - "
701ed6184dfSmrg                           "Conversion to format %d refused.\n",
702ed6184dfSmrg                           selection_notify->target);
70335c4bbdfSmrg                    return WIN_XEVENTS_FAILED;
70435c4bbdfSmrg                }
70535c4bbdfSmrg
706ed6184dfSmrg            if (selection_notify->target == atomTargets) {
707ed6184dfSmrg              return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms);
70835c4bbdfSmrg            }
70935c4bbdfSmrg
710ed6184dfSmrg            return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
711ed6184dfSmrg        }
71235c4bbdfSmrg
713ed6184dfSmrg        case XCB_SELECTION_CLEAR:
714ed6184dfSmrg            winDebug("SelectionClear - doing nothing\n");
715ed6184dfSmrg            break;
71635c4bbdfSmrg
717ed6184dfSmrg        case XCB_PROPERTY_NOTIFY:
718ed6184dfSmrg        {
719ed6184dfSmrg            xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t *)event;
72035c4bbdfSmrg
721ed6184dfSmrg            /* If INCR is in progress, collect the data */
722ed6184dfSmrg            if (data->incr &&
723ed6184dfSmrg                (property_notify->atom == atoms->atomLocalProperty) &&
724ed6184dfSmrg                (property_notify->state == XCB_PROPERTY_NEW_VALUE))
725ed6184dfSmrg                return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
72635c4bbdfSmrg
72735c4bbdfSmrg            break;
728ed6184dfSmrg        }
72935c4bbdfSmrg
730ed6184dfSmrg        case XCB_MAPPING_NOTIFY:
73135c4bbdfSmrg            break;
73235c4bbdfSmrg
733ed6184dfSmrg        case 0:
734ed6184dfSmrg            /* This is just laziness rather than making sure we used _checked everywhere */
735ed6184dfSmrg            {
736ed6184dfSmrg                xcb_generic_error_t *err = (xcb_generic_error_t *)event;
737ed6184dfSmrg                ErrorF("winClipboardFlushXEvents - Error code: %i, ID: 0x%08x, "
738ed6184dfSmrg                       "Major opcode: %i, Minor opcode: %i\n",
739ed6184dfSmrg                       err->error_code, err->resource_id,
740ed6184dfSmrg                       err->major_code, err->minor_code);
741ed6184dfSmrg            }
74235c4bbdfSmrg            break;
74335c4bbdfSmrg
74435c4bbdfSmrg        default:
745ed6184dfSmrg            if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) {
746ed6184dfSmrg                xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event;
74735c4bbdfSmrg                winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
74835c4bbdfSmrg
74935c4bbdfSmrg                /* Save selection owners for monitored selections, ignore other selections */
750ed6184dfSmrg                if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) {
75135c4bbdfSmrg                    MonitorSelection(e, CLIP_OWN_PRIMARY);
75235c4bbdfSmrg                }
75335c4bbdfSmrg                else if (e->selection == atomClipboard) {
75435c4bbdfSmrg                    MonitorSelection(e, CLIP_OWN_CLIPBOARD);
75535c4bbdfSmrg                }
75635c4bbdfSmrg                else
75735c4bbdfSmrg                    break;
75835c4bbdfSmrg
75935c4bbdfSmrg                /* Selection is being disowned */
760ed6184dfSmrg                if (e->owner == XCB_NONE) {
761ed6184dfSmrg                    winDebug("winClipboardFlushXEvents - No window, returning.\n");
76235c4bbdfSmrg                    break;
76335c4bbdfSmrg                }
76435c4bbdfSmrg
76535c4bbdfSmrg                /*
76635c4bbdfSmrg                   XXX: there are all kinds of wacky edge cases we might need here:
76735c4bbdfSmrg                   - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
76835c4bbdfSmrg                   - root window is taking ownership?
76935c4bbdfSmrg                 */
77035c4bbdfSmrg
77135c4bbdfSmrg                /* If we are the owner of the most recently owned selection, don't go all recursive :) */
77235c4bbdfSmrg                if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
77335c4bbdfSmrg                    (s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
77435c4bbdfSmrg                    winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
77535c4bbdfSmrg                    break;
77635c4bbdfSmrg                }
77735c4bbdfSmrg
77835c4bbdfSmrg                /* Close clipboard if we have it open already (possible? correct??) */
77935c4bbdfSmrg                if (GetOpenClipboardWindow() == hwnd) {
78035c4bbdfSmrg                    CloseClipboard();
78135c4bbdfSmrg                }
78235c4bbdfSmrg
78335c4bbdfSmrg                /* Access the Windows clipboard */
78435c4bbdfSmrg                if (!OpenClipboard(hwnd)) {
78535c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
78635c4bbdfSmrg                           (int) GetLastError());
78735c4bbdfSmrg                    break;
78835c4bbdfSmrg                }
78935c4bbdfSmrg
79035c4bbdfSmrg                /* Take ownership of the Windows clipboard */
79135c4bbdfSmrg                if (!EmptyClipboard()) {
79235c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
79335c4bbdfSmrg                           (int) GetLastError());
79435c4bbdfSmrg                    break;
79535c4bbdfSmrg                }
79635c4bbdfSmrg
79735c4bbdfSmrg                /* Advertise regular text and unicode */
79835c4bbdfSmrg                SetClipboardData(CF_UNICODETEXT, NULL);
79935c4bbdfSmrg                SetClipboardData(CF_TEXT, NULL);
80035c4bbdfSmrg
80135c4bbdfSmrg                /* Release the clipboard */
80235c4bbdfSmrg                if (!CloseClipboard()) {
80335c4bbdfSmrg                    ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
80435c4bbdfSmrg                           (int) GetLastError());
80535c4bbdfSmrg                    break;
80635c4bbdfSmrg                }
80735c4bbdfSmrg            }
808ed6184dfSmrg            /* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
809ed6184dfSmrg            /* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
81035c4bbdfSmrg            else {
81135c4bbdfSmrg                ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
812ed6184dfSmrg                       event->response_type);
81335c4bbdfSmrg            }
81435c4bbdfSmrg            break;
81535c4bbdfSmrg        }
816ed6184dfSmrg
817ed6184dfSmrg        /* I/O errors etc. */
818ed6184dfSmrg        {
819ed6184dfSmrg            int e = xcb_connection_has_error(conn);
820ed6184dfSmrg            if (e) {
821ed6184dfSmrg                ErrorF("winClipboardFlushXEvents - Fatal error %d on xcb connection\n", e);
822ed6184dfSmrg                break;
823ed6184dfSmrg            }
824ed6184dfSmrg        }
82535c4bbdfSmrg    }
82635c4bbdfSmrg
82735c4bbdfSmrg    return WIN_XEVENTS_SUCCESS;
828ed6184dfSmrg
82935c4bbdfSmrg}
830