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