xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xevents.c (32392B)


      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 #include <limits.h>
     38 #include <wchar.h>
     39 
     40 #include <xcb/xcb.h>
     41 #include <xcb/xfixes.h>
     42 
     43 #include "winclipboard.h"
     44 #include "internal.h"
     45 
     46 /*
     47  * Constants
     48  */
     49 
     50 #define CLIP_NUM_SELECTIONS		2
     51 #define CLIP_OWN_NONE			-1
     52 #define CLIP_OWN_PRIMARY		0
     53 #define CLIP_OWN_CLIPBOARD		1
     54 
     55 #define CP_ISO_8559_1 28591
     56 
     57 /*
     58  * Global variables
     59  */
     60 
     61 extern int xfixes_event_base;
     62 BOOL fPrimarySelection = TRUE;
     63 
     64 /*
     65  * Local variables
     66  */
     67 
     68 static xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE };
     69 static const char *szSelectionNames[CLIP_NUM_SELECTIONS] =
     70     { "PRIMARY", "CLIPBOARD" };
     71 
     72 static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE;
     73 
     74 static void
     75 MonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i)
     76 {
     77     /* Look for owned -> not owned transition */
     78     if ((XCB_NONE == e->owner) && (XCB_NONE != s_iOwners[i])) {
     79         unsigned int other_index;
     80 
     81         winDebug("MonitorSelection - %s - Going from owned to not owned.\n",
     82                  szSelectionNames[i]);
     83 
     84         /* If this selection is not owned, the other monitored selection must be the most
     85            recently owned, if it is owned at all */
     86         if (i == CLIP_OWN_PRIMARY)
     87             other_index = CLIP_OWN_CLIPBOARD;
     88         if (i == CLIP_OWN_CLIPBOARD)
     89             other_index = CLIP_OWN_PRIMARY;
     90         if (XCB_NONE != s_iOwners[other_index])
     91             lastOwnedSelectionIndex = other_index;
     92         else
     93             lastOwnedSelectionIndex = CLIP_OWN_NONE;
     94     }
     95 
     96     /* Save last owned selection */
     97     if (XCB_NONE != e->owner) {
     98         lastOwnedSelectionIndex = i;
     99     }
    100 
    101     /* Save new selection owner or None */
    102     s_iOwners[i] = e->owner;
    103     winDebug("MonitorSelection - %s - Now owned by XID %x\n",
    104              szSelectionNames[i], e->owner);
    105 }
    106 
    107 xcb_atom_t
    108 winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms)
    109 {
    110     if (lastOwnedSelectionIndex == CLIP_OWN_NONE)
    111         return XCB_NONE;
    112 
    113     if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY)
    114         return XCB_ATOM_PRIMARY;
    115 
    116     if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD)
    117         return atoms->atomClipboard;
    118 
    119     return XCB_NONE;
    120 }
    121 
    122 
    123 void
    124 winClipboardInitMonitoredSelections(void)
    125 {
    126     /* Initialize static variables */
    127     int i;
    128     for (i = 0; i < CLIP_NUM_SELECTIONS; ++i)
    129       s_iOwners[i] = XCB_NONE;
    130 
    131     lastOwnedSelectionIndex = CLIP_OWN_NONE;
    132 }
    133 
    134 static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom)
    135 {
    136     char *ret;
    137     xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom);
    138     xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL);
    139     if (!reply)
    140         return NULL;
    141     ret = malloc(xcb_get_atom_name_name_length(reply) + 1);
    142     if (ret) {
    143         memcpy(ret, xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
    144         ret[xcb_get_atom_name_name_length(reply)] = '\0';
    145     }
    146     free(reply);
    147     return ret;
    148 }
    149 
    150 static int
    151 winClipboardSelectionNotifyTargets(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
    152 {
    153   /* Retrieve the selection data and delete the property */
    154   xcb_get_property_cookie_t cookie = xcb_get_property(conn,
    155                                                       TRUE,
    156                                                       iWindow,
    157                                                       atoms->atomLocalProperty,
    158                                                       XCB_GET_PROPERTY_TYPE_ANY,
    159                                                       0,
    160                                                       INT_MAX);
    161   xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
    162   if (!reply) {
    163       ErrorF("winClipboardFlushXEvents - SelectionNotify - "
    164              "XGetWindowProperty () failed\n");
    165   } else {
    166       xcb_atom_t *prop = xcb_get_property_value(reply);
    167       int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t);
    168       int i;
    169       data->targetList = malloc((nitems+1)*sizeof(xcb_atom_t));
    170 
    171       for (i = 0; i < nitems; i++)
    172           {
    173               xcb_atom_t atom = prop[i];
    174               char *pszAtomName = get_atom_name(conn, atom);
    175               data->targetList[i] = atom;
    176               winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName);
    177               free(pszAtomName);
    178       }
    179 
    180     data->targetList[nitems] = 0;
    181 
    182     free(reply);
    183   }
    184 
    185   return WIN_XEVENTS_NOTIFY_TARGETS;
    186 }
    187 
    188 static int
    189 winClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms)
    190 {
    191     xcb_atom_t encoding;
    192     int format;
    193     unsigned long int nitems;
    194     unsigned long int after;
    195     unsigned char *value;
    196 
    197     unsigned char *xtpText_value;
    198     xcb_atom_t xtpText_encoding;
    199     int xtpText_nitems;
    200 
    201     BOOL fSetClipboardData = TRUE;
    202     char *pszReturnData = NULL;
    203     UINT codepage;
    204     wchar_t *pwszUnicodeStr = NULL;
    205     HGLOBAL hGlobal = NULL;
    206     char *pszGlobalData = NULL;
    207 
    208     /* Retrieve the selection data and delete the property */
    209     xcb_get_property_cookie_t cookie = xcb_get_property(conn,
    210                                                         TRUE,
    211                                                         iWindow,
    212                                                         atoms->atomLocalProperty,
    213                                                         XCB_GET_PROPERTY_TYPE_ANY,
    214                                                         0,
    215                                                         INT_MAX);
    216     xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
    217     if (!reply) {
    218         ErrorF("winClipboardFlushXEvents - SelectionNotify - "
    219                "XGetWindowProperty () failed\n");
    220         goto winClipboardFlushXEvents_SelectionNotify_Done;
    221     } else {
    222         nitems = xcb_get_property_value_length(reply);
    223         value =  xcb_get_property_value(reply);
    224         after = reply->bytes_after;
    225         encoding = reply->type;
    226         format = reply->format;
    227         // We assume format == 8 (i.e. data is a sequence of bytes).  It's not
    228         // clear how anything else should be handled.
    229         if (format != 8)
    230             ErrorF("SelectionNotify: format is %d, proceeding as if it was 8\n", format);
    231     }
    232 
    233     {
    234         char *pszAtomName;
    235         winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after);
    236         pszAtomName = get_atom_name(conn, encoding);
    237         winDebug("Notify atom name %s\n", pszAtomName);
    238         free(pszAtomName);
    239     }
    240 
    241     /* INCR reply indicates the start of a incremental transfer */
    242     if (encoding == atoms->atomIncr) {
    243         winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value);
    244         data->incrsize = 0;
    245         data->incr = malloc(*(int *)value);
    246         // XXX: if malloc failed, we have an error
    247         return WIN_XEVENTS_SUCCESS;
    248     }
    249     else if (data->incr) {
    250         /* If an INCR transfer is in progress ... */
    251         if (nitems == 0) {
    252             winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize);
    253             /* a zero-length property indicates the end of the data */
    254             xtpText_value = data->incr;
    255             xtpText_encoding = encoding;
    256             // XXX: The type of the converted selection is the type of the first
    257             // partial property. The remaining partial properties must have the
    258             // same type.
    259             xtpText_nitems = data->incrsize;
    260         }
    261         else {
    262             /* Otherwise, continue appending the INCR data */
    263             winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems);
    264             data->incr = realloc(data->incr, data->incrsize + nitems);
    265             memcpy(data->incr + data->incrsize, value, nitems);
    266             data->incrsize = data->incrsize + nitems;
    267             return WIN_XEVENTS_SUCCESS;
    268         }
    269     }
    270     else {
    271         /* Otherwise, the data is just contained in the property */
    272         winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems);
    273         xtpText_value = value;
    274         xtpText_encoding = encoding;
    275         xtpText_nitems = nitems;
    276     }
    277 
    278     if (xtpText_encoding == atoms->atomUTF8String) {
    279         pszReturnData = malloc(xtpText_nitems + 1);
    280         memcpy(pszReturnData, xtpText_value, xtpText_nitems);
    281         pszReturnData[xtpText_nitems] = 0;
    282         codepage = CP_UTF8; // code page identifier for utf8
    283     } else if (xtpText_encoding == XCB_ATOM_STRING) {
    284         // STRING encoding is Latin1 (ISO8859-1) plus tab and newline
    285         pszReturnData = malloc(xtpText_nitems + 1);
    286         memcpy(pszReturnData, xtpText_value, xtpText_nitems);
    287         pszReturnData[xtpText_nitems] = 0;
    288         codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
    289     } else if (xtpText_encoding == atoms->atomCompoundText) {
    290         // COMPOUND_TEXT is complex, based on ISO 2022
    291         ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n");
    292         pszReturnData = malloc(1);
    293         pszReturnData[0] = '\0';
    294     } else { // shouldn't happen as we accept no other encodings
    295         pszReturnData = malloc(1);
    296         pszReturnData[0] = '\0';
    297     }
    298 
    299     /* Free the data returned from xcb_get_property */
    300     free(reply);
    301 
    302     /* Free any INCR data */
    303     if (data->incr) {
    304         free(data->incr);
    305         data->incr = NULL;
    306         data->incrsize = 0;
    307     }
    308 
    309     /* Convert the X clipboard string to DOS format */
    310     winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData));
    311 
    312     /* Find out how much space needed when converted to UTF-16 */
    313     int iUnicodeLen = MultiByteToWideChar(codepage, 0,
    314                                           pszReturnData, -1, NULL, 0);
    315 
    316     /* NOTE: iUnicodeLen includes space for null terminator */
    317     pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen);
    318     if (!pwszUnicodeStr) {
    319         ErrorF("winClipboardFlushXEvents - SelectionNotify "
    320                "malloc failed for pwszUnicodeStr, aborting.\n");
    321 
    322         /* Abort */
    323         goto winClipboardFlushXEvents_SelectionNotify_Done;
    324     }
    325 
    326     /* Do the actual conversion */
    327     MultiByteToWideChar(codepage, 0,
    328                         pszReturnData, -1, pwszUnicodeStr, iUnicodeLen);
    329 
    330     /* Allocate global memory for the X clipboard data */
    331     hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen);
    332 
    333     free(pszReturnData);
    334 
    335     /* Check that global memory was allocated */
    336     if (!hGlobal) {
    337         ErrorF("winClipboardFlushXEvents - SelectionNotify "
    338                "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError());
    339 
    340         /* Abort */
    341         goto winClipboardFlushXEvents_SelectionNotify_Done;
    342     }
    343 
    344     /* Obtain a pointer to the global memory */
    345     pszGlobalData = GlobalLock(hGlobal);
    346     if (pszGlobalData == NULL) {
    347         ErrorF("winClipboardFlushXEvents - Could not lock global "
    348                "memory for clipboard transfer\n");
    349 
    350         /* Abort */
    351         goto winClipboardFlushXEvents_SelectionNotify_Done;
    352     }
    353 
    354     /* Copy the returned string into the global memory */
    355     wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr);
    356     free(pwszUnicodeStr);
    357     pwszUnicodeStr = NULL;
    358 
    359     /* Release the pointer to the global memory */
    360     GlobalUnlock(hGlobal);
    361     pszGlobalData = NULL;
    362 
    363     /* Push the selection data to the Windows clipboard */
    364     SetClipboardData(CF_UNICODETEXT, hGlobal);
    365 
    366     /* Flag that SetClipboardData has been called */
    367     fSetClipboardData = FALSE;
    368 
    369     /*
    370      * NOTE: Do not try to free pszGlobalData, it is owned by
    371      * Windows after the call to SetClipboardData ().
    372      */
    373 
    374  winClipboardFlushXEvents_SelectionNotify_Done:
    375     /* Free allocated resources */
    376     free(pwszUnicodeStr);
    377     if (hGlobal && pszGlobalData)
    378         GlobalUnlock(hGlobal);
    379     if (fSetClipboardData) {
    380         SetClipboardData(CF_UNICODETEXT, NULL);
    381         SetClipboardData(CF_TEXT, NULL);
    382     }
    383     return WIN_XEVENTS_NOTIFY_DATA;
    384 }
    385 
    386 /*
    387  * Process any pending X events
    388  */
    389 
    390 int
    391 winClipboardFlushXEvents(HWND hwnd,
    392                          xcb_window_t iWindow, xcb_connection_t *conn,
    393                          ClipboardConversionData *data, ClipboardAtoms *atoms)
    394 {
    395     xcb_atom_t atomClipboard = atoms->atomClipboard;
    396     xcb_atom_t atomUTF8String = atoms->atomUTF8String;
    397     xcb_atom_t atomCompoundText = atoms->atomCompoundText;
    398     xcb_atom_t atomTargets = atoms->atomTargets;
    399 
    400     /* Process all pending events */
    401     xcb_generic_event_t *event;
    402     while ((event = xcb_poll_for_event(conn))) {
    403         const char *pszGlobalData = NULL;
    404         HGLOBAL hGlobal = NULL;
    405         char *pszConvertData = NULL;
    406         BOOL fAbort = FALSE;
    407         BOOL fCloseClipboard = FALSE;
    408 
    409         /* Branch on the event type */
    410         switch (event->response_type & ~0x80) {
    411         case XCB_SELECTION_REQUEST:
    412         {
    413             char *xtpText_value = NULL;
    414             int xtpText_nitems;
    415             UINT codepage;
    416 
    417             xcb_selection_request_event_t *selection_request =  (xcb_selection_request_event_t *)event;
    418         {
    419             char *pszAtomName = NULL;
    420 
    421             winDebug("SelectionRequest - target %d\n", selection_request->target);
    422 
    423             pszAtomName = get_atom_name(conn, selection_request->target);
    424             winDebug("SelectionRequest - Target atom name %s\n", pszAtomName);
    425             free(pszAtomName);
    426         }
    427 
    428             /* Abort if invalid target type */
    429             if (selection_request->target != XCB_ATOM_STRING
    430                 && selection_request->target != atomUTF8String
    431                 && selection_request->target != atomCompoundText
    432                 && selection_request->target != atomTargets) {
    433                 /* Abort */
    434                 fAbort = TRUE;
    435                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    436             }
    437 
    438             /* Handle targets type of request */
    439             if (selection_request->target == atomTargets) {
    440                 xcb_atom_t atomTargetArr[] =
    441                     {
    442                      atomTargets,
    443                      atomUTF8String,
    444                      XCB_ATOM_STRING,
    445                      // atomCompoundText, not implemented (yet?)
    446                     };
    447 
    448                 /* Try to change the property */
    449                 xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
    450                                           XCB_PROP_MODE_REPLACE,
    451                                           selection_request->requestor,
    452                                           selection_request->property,
    453                                           XCB_ATOM_ATOM,
    454                                           32,
    455                                           ARRAY_SIZE(atomTargetArr),
    456                                           (unsigned char *) atomTargetArr);
    457                 xcb_generic_error_t *error;
    458                 if ((error = xcb_request_check(conn, cookie))) {
    459                     ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    460                            "xcb_change_property failed");
    461                     free(error);
    462                 }
    463 
    464                 /* Setup selection notify xevent */
    465                 xcb_selection_notify_event_t eventSelection;
    466                 eventSelection.response_type = XCB_SELECTION_NOTIFY;
    467                 eventSelection.requestor = selection_request->requestor;
    468                 eventSelection.selection = selection_request->selection;
    469                 eventSelection.target = selection_request->target;
    470                 eventSelection.property = selection_request->property;
    471                 eventSelection.time = selection_request->time;
    472 
    473                 /*
    474                  * Notify the requesting window that
    475                  * the operation has completed
    476                  */
    477                 cookie = xcb_send_event_checked(conn, FALSE,
    478                                                 eventSelection.requestor,
    479                                                 0, (char *) &eventSelection);
    480                 if ((error = xcb_request_check(conn, cookie))) {
    481                     ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    482                            "xcb_send_event() failed\n");
    483                 }
    484                 break;
    485             }
    486 
    487             /* Close clipboard if we have it open already */
    488             if (GetOpenClipboardWindow() == hwnd) {
    489                 CloseClipboard();
    490             }
    491 
    492             /* Access the clipboard */
    493             if (!OpenClipboard(hwnd)) {
    494                 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    495                        "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError());
    496 
    497                 /* Abort */
    498                 fAbort = TRUE;
    499                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    500             }
    501 
    502             /* Indicate that clipboard was opened */
    503             fCloseClipboard = TRUE;
    504 
    505             /* Check that clipboard format is available */
    506             if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {
    507                 static int count;       /* Hack to stop acroread spamming the log */
    508                 static HWND lasthwnd;   /* I've not seen any other client get here repeatedly? */
    509 
    510                 if (hwnd != lasthwnd)
    511                     count = 0;
    512                 count++;
    513                 if (count < 6)
    514                     ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not "
    515                            "available from Win32 clipboard.  Aborting %d.\n",
    516                            count);
    517                 lasthwnd = hwnd;
    518 
    519                 /* Abort */
    520                 fAbort = TRUE;
    521                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    522             }
    523 
    524             /* Get a pointer to the clipboard text, in desired format */
    525             /* Retrieve clipboard data */
    526             hGlobal = GetClipboardData(CF_UNICODETEXT);
    527 
    528             if (!hGlobal) {
    529                 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    530                        "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError());
    531 
    532                 /* Abort */
    533                 fAbort = TRUE;
    534                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    535             }
    536             pszGlobalData = (char *) GlobalLock(hGlobal);
    537 
    538             /* Convert to target string style */
    539             if (selection_request->target == XCB_ATOM_STRING) {
    540                 codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1
    541             } else if (selection_request->target == atomUTF8String) {
    542                 codepage = CP_UTF8; // code page identifier for utf8
    543             } else if (selection_request->target == atomCompoundText) {
    544                 // COMPOUND_TEXT is complex, not (yet) implemented
    545                 pszGlobalData = "COMPOUND_TEXT not implemented";
    546                 codepage = CP_UTF8; // code page identifier for utf8
    547             }
    548 
    549             /* Convert the UTF16 string to required encoding */
    550             int iConvertDataLen = WideCharToMultiByte(codepage, 0,
    551                                                       (LPCWSTR) pszGlobalData, -1,
    552                                                       NULL, 0, NULL, NULL);
    553             /* NOTE: iConvertDataLen includes space for null terminator */
    554             pszConvertData = malloc(iConvertDataLen);
    555             WideCharToMultiByte(codepage, 0,
    556                                 (LPCWSTR) pszGlobalData, -1,
    557                                 pszConvertData, iConvertDataLen, NULL, NULL);
    558 
    559             /* Convert DOS string to UNIX string */
    560             winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData));
    561 
    562             xtpText_value = strdup(pszConvertData);
    563             xtpText_nitems = strlen(pszConvertData);
    564 
    565             /* data will fit into a single X request? (INCR not yet supported) */
    566             {
    567                 uint32_t maxreqsize = xcb_get_maximum_request_length(conn);
    568 
    569                 /* covert to bytes and allow for allow for X_ChangeProperty request */
    570                 maxreqsize = maxreqsize*4 - 24;
    571 
    572                 if (xtpText_nitems > maxreqsize) {
    573                     ErrorF("winClipboardFlushXEvents - clipboard data size %d greater than maximum %u\n", xtpText_nitems, maxreqsize);
    574 
    575                     /* Abort */
    576                     fAbort = TRUE;
    577                     goto winClipboardFlushXEvents_SelectionRequest_Done;
    578                 }
    579             }
    580 
    581             /* Copy the clipboard text to the requesting window */
    582             xcb_void_cookie_t cookie = xcb_change_property_checked(conn,
    583                                       XCB_PROP_MODE_REPLACE,
    584                                       selection_request->requestor,
    585                                       selection_request->property,
    586                                       selection_request->target,
    587                                       8,
    588                                       xtpText_nitems, xtpText_value);
    589             xcb_generic_error_t *error;
    590             if ((error = xcb_request_check(conn, cookie))) {
    591                 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    592                        "xcb_change_property failed\n");
    593 
    594                 /* Abort */
    595                 fAbort = TRUE;
    596                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    597             }
    598 
    599             /* Free the converted string */
    600             free(pszConvertData);
    601             pszConvertData = NULL;
    602 
    603             /* Release the clipboard data */
    604             GlobalUnlock(hGlobal);
    605             pszGlobalData = NULL;
    606             fCloseClipboard = FALSE;
    607             CloseClipboard();
    608 
    609             /* Clean up */
    610             free(xtpText_value);
    611             xtpText_value = NULL;
    612 
    613             /* Setup selection notify event */
    614             xcb_selection_notify_event_t eventSelection;
    615             eventSelection.response_type = XCB_SELECTION_NOTIFY;
    616             eventSelection.requestor = selection_request->requestor;
    617             eventSelection.selection = selection_request->selection;
    618             eventSelection.target = selection_request->target;
    619             eventSelection.property = selection_request->property;
    620             eventSelection.time = selection_request->time;
    621 
    622             /* Notify the requesting window that the operation has completed */
    623             cookie = xcb_send_event_checked(conn, FALSE,
    624                                             eventSelection.requestor,
    625                                             0, (char *) &eventSelection);
    626             if ((error = xcb_request_check(conn, cookie))) {
    627                 ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    628                        "xcb_send_event() failed\n");
    629 
    630                 /* Abort */
    631                 fAbort = TRUE;
    632                 goto winClipboardFlushXEvents_SelectionRequest_Done;
    633             }
    634 
    635  winClipboardFlushXEvents_SelectionRequest_Done:
    636             /* Free allocated resources */
    637             if (xtpText_value) {
    638                 free(xtpText_value);
    639             }
    640             if (pszConvertData)
    641                 free(pszConvertData);
    642             if (hGlobal && pszGlobalData)
    643                 GlobalUnlock(hGlobal);
    644 
    645             /*
    646              * Send a SelectionNotify event to the requesting
    647              * client when we abort.
    648              */
    649             if (fAbort) {
    650                 /* Setup selection notify event */
    651                 eventSelection.response_type = XCB_SELECTION_NOTIFY;
    652                 eventSelection.requestor = selection_request->requestor;
    653                 eventSelection.selection = selection_request->selection;
    654                 eventSelection.target = selection_request->target;
    655                 eventSelection.property = XCB_NONE;
    656                 eventSelection.time = selection_request->time;
    657 
    658                 /* Notify the requesting window that the operation is complete */
    659                 cookie = xcb_send_event_checked(conn, FALSE,
    660                                                 eventSelection.requestor,
    661                                                 0, (char *) &eventSelection);
    662                 if ((error = xcb_request_check(conn, cookie))) {
    663                     /*
    664                      * Should not be a problem if XSendEvent fails because
    665                      * the client may simply have exited.
    666                      */
    667                     ErrorF("winClipboardFlushXEvents - SelectionRequest - "
    668                            "xcb_send_event() failed for abort event.\n");
    669                 }
    670             }
    671 
    672             /* Close clipboard if it was opened */
    673             if (fCloseClipboard) {
    674                 fCloseClipboard = FALSE;
    675                 CloseClipboard();
    676             }
    677             break;
    678         }
    679 
    680         case XCB_SELECTION_NOTIFY:
    681         {
    682             xcb_selection_notify_event_t *selection_notify =  (xcb_selection_notify_event_t *)event;
    683             winDebug("winClipboardFlushXEvents - SelectionNotify\n");
    684             {
    685                 char *pszAtomName;
    686                 pszAtomName = get_atom_name(conn, selection_notify->selection);
    687                 winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName);
    688                 free(pszAtomName);
    689             }
    690 
    691             /*
    692               SelectionNotify with property of XCB_NONE indicates either:
    693 
    694               (i) Generated by the X server if no owner for the specified selection exists
    695                   (perhaps it's disappeared on us mid-transaction), or
    696               (ii) Sent by the selection owner when the requested selection conversion could
    697                    not be performed or server errors prevented the conversion data being returned
    698             */
    699             if (selection_notify->property == XCB_NONE) {
    700                     ErrorF("winClipboardFlushXEvents - SelectionNotify - "
    701                            "Conversion to format %d refused.\n",
    702                            selection_notify->target);
    703                     return WIN_XEVENTS_FAILED;
    704                 }
    705 
    706             if (selection_notify->target == atomTargets) {
    707               return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms);
    708             }
    709 
    710             return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
    711         }
    712 
    713         case XCB_SELECTION_CLEAR:
    714             winDebug("SelectionClear - doing nothing\n");
    715             break;
    716 
    717         case XCB_PROPERTY_NOTIFY:
    718         {
    719             xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t *)event;
    720 
    721             /* If INCR is in progress, collect the data */
    722             if (data->incr &&
    723                 (property_notify->atom == atoms->atomLocalProperty) &&
    724                 (property_notify->state == XCB_PROPERTY_NEW_VALUE))
    725                 return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms);
    726 
    727             break;
    728         }
    729 
    730         case XCB_MAPPING_NOTIFY:
    731             break;
    732 
    733         case 0:
    734             /* This is just laziness rather than making sure we used _checked everywhere */
    735             {
    736                 xcb_generic_error_t *err = (xcb_generic_error_t *)event;
    737                 ErrorF("winClipboardFlushXEvents - Error code: %i, ID: 0x%08x, "
    738                        "Major opcode: %i, Minor opcode: %i\n",
    739                        err->error_code, err->resource_id,
    740                        err->major_code, err->minor_code);
    741             }
    742             break;
    743 
    744         default:
    745             if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) {
    746                 xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event;
    747                 winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n");
    748 
    749                 /* Save selection owners for monitored selections, ignore other selections */
    750                 if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) {
    751                     MonitorSelection(e, CLIP_OWN_PRIMARY);
    752                 }
    753                 else if (e->selection == atomClipboard) {
    754                     MonitorSelection(e, CLIP_OWN_CLIPBOARD);
    755                 }
    756                 else
    757                     break;
    758 
    759                 /* Selection is being disowned */
    760                 if (e->owner == XCB_NONE) {
    761                     winDebug("winClipboardFlushXEvents - No window, returning.\n");
    762                     break;
    763                 }
    764 
    765                 /*
    766                    XXX: there are all kinds of wacky edge cases we might need here:
    767                    - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it?
    768                    - root window is taking ownership?
    769                  */
    770 
    771                 /* If we are the owner of the most recently owned selection, don't go all recursive :) */
    772                 if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) &&
    773                     (s_iOwners[lastOwnedSelectionIndex] == iWindow)) {
    774                     winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n");
    775                     break;
    776                 }
    777 
    778                 /* Close clipboard if we have it open already (possible? correct??) */
    779                 if (GetOpenClipboardWindow() == hwnd) {
    780                     CloseClipboard();
    781                 }
    782 
    783                 /* Access the Windows clipboard */
    784                 if (!OpenClipboard(hwnd)) {
    785                     ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n",
    786                            (int) GetLastError());
    787                     break;
    788                 }
    789 
    790                 /* Take ownership of the Windows clipboard */
    791                 if (!EmptyClipboard()) {
    792                     ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n",
    793                            (int) GetLastError());
    794                     break;
    795                 }
    796 
    797                 /* Advertise regular text and unicode */
    798                 SetClipboardData(CF_UNICODETEXT, NULL);
    799                 SetClipboardData(CF_TEXT, NULL);
    800 
    801                 /* Release the clipboard */
    802                 if (!CloseClipboard()) {
    803                     ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n",
    804                            (int) GetLastError());
    805                     break;
    806                 }
    807             }
    808             /* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */
    809             /* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */
    810             else {
    811                 ErrorF("winClipboardFlushXEvents - unexpected event type %d\n",
    812                        event->response_type);
    813             }
    814             break;
    815         }
    816 
    817         /* I/O errors etc. */
    818         {
    819             int e = xcb_connection_has_error(conn);
    820             if (e) {
    821                 ErrorF("winClipboardFlushXEvents - Fatal error %d on xcb connection\n", e);
    822                 break;
    823             }
    824         }
    825     }
    826 
    827     return WIN_XEVENTS_SUCCESS;
    828 
    829 }