/* *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. *Copyright (C) Colin Harrison 2005-2008 * *Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the *"Software"), to deal in the Software without restriction, including *without limitation the rights to use, copy, modify, merge, publish, *distribute, sublicense, and/or sell copies of the Software, and to *permit persons to whom the Software is furnished to do so, subject to *the following conditions: * *The above copyright notice and this permission notice shall be *included in all copies or substantial portions of the Software. * *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *Except as contained in this notice, the name of the copyright holder(s) *and author(s) shall not be used in advertising or otherwise to promote *the sale, use or other dealings in this Software without prior written *authorization from the copyright holder(s) and author(s). * * Authors: Harold L Hunt II * Colin Harrison */ #ifdef HAVE_XWIN_CONFIG_H #include #endif #include #include #include #include #include "winclipboard.h" #include "internal.h" /* * Constants */ #define CLIP_NUM_SELECTIONS 2 #define CLIP_OWN_NONE -1 #define CLIP_OWN_PRIMARY 0 #define CLIP_OWN_CLIPBOARD 1 #define CP_ISO_8559_1 28591 /* * Global variables */ extern int xfixes_event_base; Bool fPrimarySelection = TRUE; /* * Local variables */ static xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE }; static const char *szSelectionNames[CLIP_NUM_SELECTIONS] = { "PRIMARY", "CLIPBOARD" }; static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; static void MonitorSelection(xcb_xfixes_selection_notify_event_t * e, unsigned int i) { /* Look for owned -> not owned transition */ if ((XCB_NONE == e->owner) && (XCB_NONE != s_iOwners[i])) { unsigned int other_index; winDebug("MonitorSelection - %s - Going from owned to not owned.\n", szSelectionNames[i]); /* If this selection is not owned, the other monitored selection must be the most recently owned, if it is owned at all */ if (i == CLIP_OWN_PRIMARY) other_index = CLIP_OWN_CLIPBOARD; if (i == CLIP_OWN_CLIPBOARD) other_index = CLIP_OWN_PRIMARY; if (XCB_NONE != s_iOwners[other_index]) lastOwnedSelectionIndex = other_index; else lastOwnedSelectionIndex = CLIP_OWN_NONE; } /* Save last owned selection */ if (XCB_NONE != e->owner) { lastOwnedSelectionIndex = i; } /* Save new selection owner or None */ s_iOwners[i] = e->owner; winDebug("MonitorSelection - %s - Now owned by XID %x\n", szSelectionNames[i], e->owner); } xcb_atom_t winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms) { if (lastOwnedSelectionIndex == CLIP_OWN_NONE) return XCB_NONE; if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) return XCB_ATOM_PRIMARY; if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) return atoms->atomClipboard; return XCB_NONE; } void winClipboardInitMonitoredSelections(void) { /* Initialize static variables */ int i; for (i = 0; i < CLIP_NUM_SELECTIONS; ++i) s_iOwners[i] = XCB_NONE; lastOwnedSelectionIndex = CLIP_OWN_NONE; } static char *get_atom_name(xcb_connection_t *conn, xcb_atom_t atom) { char *ret; xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(conn, atom); xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(conn, cookie, NULL); if (!reply) return NULL; ret = malloc(xcb_get_atom_name_name_length(reply) + 1); if (ret) { memcpy(ret, xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)); ret[xcb_get_atom_name_name_length(reply)] = '\0'; } free(reply); return ret; } static int winClipboardSelectionNotifyTargets(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms) { /* Retrieve the selection data and delete the property */ xcb_get_property_cookie_t cookie = xcb_get_property(conn, TRUE, iWindow, atoms->atomLocalProperty, XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX); xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); if (!reply) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed\n"); } else { xcb_atom_t *prop = xcb_get_property_value(reply); int nitems = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); int i; data->targetList = malloc((nitems+1)*sizeof(xcb_atom_t)); for (i = 0; i < nitems; i++) { xcb_atom_t atom = prop[i]; char *pszAtomName = get_atom_name(conn, atom); data->targetList[i] = atom; winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %d = %s\n", i, atom, pszAtomName); free(pszAtomName); } data->targetList[nitems] = 0; free(reply); } return WIN_XEVENTS_NOTIFY_TARGETS; } static int winClipboardSelectionNotifyData(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms) { xcb_atom_t encoding; int format; unsigned long int nitems; unsigned long int after; unsigned char *value; unsigned char *xtpText_value; xcb_atom_t xtpText_encoding; int xtpText_nitems; Bool fSetClipboardData = TRUE; char *pszReturnData = NULL; UINT codepage; wchar_t *pwszUnicodeStr = NULL; HGLOBAL hGlobal = NULL; char *pszGlobalData = NULL; /* Retrieve the selection data and delete the property */ xcb_get_property_cookie_t cookie = xcb_get_property(conn, TRUE, iWindow, atoms->atomLocalProperty, XCB_GET_PROPERTY_TYPE_ANY, 0, INT_MAX); xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); if (!reply) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed\n"); goto winClipboardFlushXEvents_SelectionNotify_Done; } else { nitems = xcb_get_property_value_length(reply); value = xcb_get_property_value(reply); after = reply->bytes_after; encoding = reply->type; format = reply->format; // We assume format == 8 (i.e. data is a sequence of bytes). It's not // clear how anything else should be handled. if (format != 8) ErrorF("SelectionNotify: format is %d, proceeding as if it was 8\n", format); } { char *pszAtomName; winDebug("SelectionNotify - returned data %lu left %lu\n", nitems, after); pszAtomName = get_atom_name(conn, encoding); winDebug("Notify atom name %s\n", pszAtomName); free(pszAtomName); } /* INCR reply indicates the start of a incremental transfer */ if (encoding == atoms->atomIncr) { winDebug("winClipboardSelectionNotifyData: starting INCR, anticipated size %d\n", *(int *)value); data->incrsize = 0; data->incr = malloc(*(int *)value); // XXX: if malloc failed, we have an error return WIN_XEVENTS_SUCCESS; } else if (data->incr) { /* If an INCR transfer is in progress ... */ if (nitems == 0) { winDebug("winClipboardSelectionNotifyData: ending INCR, actual size %ld\n", data->incrsize); /* a zero-length property indicates the end of the data */ xtpText_value = data->incr; xtpText_encoding = encoding; // XXX: The type of the converted selection is the type of the first // partial property. The remaining partial properties must have the // same type. xtpText_nitems = data->incrsize; } else { /* Otherwise, continue appending the INCR data */ winDebug("winClipboardSelectionNotifyData: INCR, %ld bytes\n", nitems); data->incr = realloc(data->incr, data->incrsize + nitems); memcpy(data->incr + data->incrsize, value, nitems); data->incrsize = data->incrsize + nitems; return WIN_XEVENTS_SUCCESS; } } else { /* Otherwise, the data is just contained in the property */ winDebug("winClipboardSelectionNotifyData: non-INCR, %ld bytes\n", nitems); xtpText_value = value; xtpText_encoding = encoding; xtpText_nitems = nitems; } if (xtpText_encoding == atoms->atomUTF8String) { pszReturnData = malloc(xtpText_nitems + 1); memcpy(pszReturnData, xtpText_value, xtpText_nitems); pszReturnData[xtpText_nitems] = 0; codepage = CP_UTF8; // code page identifier for utf8 } else if (xtpText_encoding == XCB_ATOM_STRING) { // STRING encoding is Latin1 (ISO8859-1) plus tab and newline pszReturnData = malloc(xtpText_nitems + 1); memcpy(pszReturnData, xtpText_value, xtpText_nitems); pszReturnData[xtpText_nitems] = 0; codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1 } else if (xtpText_encoding == atoms->atomCompoundText) { // COMPOUND_TEXT is complex, based on ISO 2022 ErrorF("SelectionNotify: data in COMPOUND_TEXT encoding which is not implemented, discarding\n"); pszReturnData = malloc(1); pszReturnData[0] = '\0'; } else { // shouldn't happen as we accept no other encodings pszReturnData = malloc(1); pszReturnData[0] = '\0'; } /* Free the data returned from xcb_get_property */ free(reply); /* Free any INCR data */ if (data->incr) { free(data->incr); data->incr = NULL; data->incrsize = 0; } /* Convert the X clipboard string to DOS format */ winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); /* Find out how much space needed when converted to UTF-16 */ int iUnicodeLen = MultiByteToWideChar(codepage, 0, pszReturnData, -1, NULL, 0); /* NOTE: iUnicodeLen includes space for null terminator */ pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen); if (!pwszUnicodeStr) { ErrorF("winClipboardFlushXEvents - SelectionNotify " "malloc failed for pwszUnicodeStr, aborting.\n"); /* Abort */ goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Do the actual conversion */ MultiByteToWideChar(codepage, 0, pszReturnData, -1, pwszUnicodeStr, iUnicodeLen); /* Allocate global memory for the X clipboard data */ hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen); free(pszReturnData); /* Check that global memory was allocated */ if (!hGlobal) { ErrorF("winClipboardFlushXEvents - SelectionNotify " "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError()); /* Abort */ goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Obtain a pointer to the global memory */ pszGlobalData = GlobalLock(hGlobal); if (pszGlobalData == NULL) { ErrorF("winClipboardFlushXEvents - Could not lock global " "memory for clipboard transfer\n"); /* Abort */ goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Copy the returned string into the global memory */ wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr); free(pwszUnicodeStr); pwszUnicodeStr = NULL; /* Release the pointer to the global memory */ GlobalUnlock(hGlobal); pszGlobalData = NULL; /* Push the selection data to the Windows clipboard */ SetClipboardData(CF_UNICODETEXT, hGlobal); /* Flag that SetClipboardData has been called */ fSetClipboardData = FALSE; /* * NOTE: Do not try to free pszGlobalData, it is owned by * Windows after the call to SetClipboardData (). */ winClipboardFlushXEvents_SelectionNotify_Done: /* Free allocated resources */ free(pwszUnicodeStr); if (hGlobal && pszGlobalData) GlobalUnlock(hGlobal); if (fSetClipboardData) { SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); } return WIN_XEVENTS_NOTIFY_DATA; } /* * Process any pending X events */ int winClipboardFlushXEvents(HWND hwnd, xcb_window_t iWindow, xcb_connection_t *conn, ClipboardConversionData *data, ClipboardAtoms *atoms) { xcb_atom_t atomClipboard = atoms->atomClipboard; xcb_atom_t atomUTF8String = atoms->atomUTF8String; xcb_atom_t atomCompoundText = atoms->atomCompoundText; xcb_atom_t atomTargets = atoms->atomTargets; /* Process all pending events */ xcb_generic_event_t *event; while ((event = xcb_poll_for_event(conn))) { const char *pszGlobalData = NULL; HGLOBAL hGlobal = NULL; char *pszConvertData = NULL; Bool fAbort = FALSE; Bool fCloseClipboard = FALSE; /* Branch on the event type */ switch (event->response_type & ~0x80) { case XCB_SELECTION_REQUEST: { char *xtpText_value = NULL; int xtpText_nitems; UINT codepage; xcb_selection_request_event_t *selection_request = (xcb_selection_request_event_t *)event; { char *pszAtomName = NULL; winDebug("SelectionRequest - target %d\n", selection_request->target); pszAtomName = get_atom_name(conn, selection_request->target); winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); free(pszAtomName); } /* Abort if invalid target type */ if (selection_request->target != XCB_ATOM_STRING && selection_request->target != atomUTF8String && selection_request->target != atomCompoundText && selection_request->target != atomTargets) { /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Handle targets type of request */ if (selection_request->target == atomTargets) { xcb_atom_t atomTargetArr[] = { atomTargets, atomUTF8String, XCB_ATOM_STRING, // atomCompoundText, not implemented (yet?) }; /* Try to change the property */ xcb_void_cookie_t cookie = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, selection_request->requestor, selection_request->property, XCB_ATOM_ATOM, 32, ARRAY_SIZE(atomTargetArr), (unsigned char *) atomTargetArr); xcb_generic_error_t *error; if ((error = xcb_request_check(conn, cookie))) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "xcb_change_property failed"); free(error); } /* Setup selection notify xevent */ xcb_selection_notify_event_t eventSelection; eventSelection.response_type = XCB_SELECTION_NOTIFY; eventSelection.requestor = selection_request->requestor; eventSelection.selection = selection_request->selection; eventSelection.target = selection_request->target; eventSelection.property = selection_request->property; eventSelection.time = selection_request->time; /* * Notify the requesting window that * the operation has completed */ cookie = xcb_send_event_checked(conn, FALSE, eventSelection.requestor, 0, (char *) &eventSelection); if ((error = xcb_request_check(conn, cookie))) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "xcb_send_event() failed\n"); } break; } /* Close clipboard if we have it open already */ if (GetOpenClipboardWindow() == hwnd) { CloseClipboard(); } /* Access the clipboard */ if (!OpenClipboard(hwnd)) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Indicate that clipboard was opened */ fCloseClipboard = TRUE; /* Check that clipboard format is available */ if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) { static int count; /* Hack to stop acroread spamming the log */ static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ if (hwnd != lasthwnd) count = 0; count++; if (count < 6) ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not " "available from Win32 clipboard. Aborting %d.\n", count); lasthwnd = hwnd; /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Get a pointer to the clipboard text, in desired format */ /* Retrieve clipboard data */ hGlobal = GetClipboardData(CF_UNICODETEXT); if (!hGlobal) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } pszGlobalData = (char *) GlobalLock(hGlobal); /* Convert to target string style */ if (selection_request->target == XCB_ATOM_STRING) { codepage = CP_ISO_8559_1; // code page identifier for iso-8559-1 } else if (selection_request->target == atomUTF8String) { codepage = CP_UTF8; // code page identifier for utf8 } else if (selection_request->target == atomCompoundText) { // COMPOUND_TEXT is complex, not (yet) implemented pszGlobalData = "COMPOUND_TEXT not implemented"; codepage = CP_UTF8; // code page identifier for utf8 } /* Convert the UTF16 string to required encoding */ int iConvertDataLen = WideCharToMultiByte(codepage, 0, (LPCWSTR) pszGlobalData, -1, NULL, 0, NULL, NULL); /* NOTE: iConvertDataLen includes space for null terminator */ pszConvertData = malloc(iConvertDataLen); WideCharToMultiByte(codepage, 0, (LPCWSTR) pszGlobalData, -1, pszConvertData, iConvertDataLen, NULL, NULL); /* Convert DOS string to UNIX string */ winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); xtpText_value = strdup(pszConvertData); xtpText_nitems = strlen(pszConvertData); /* data will fit into a single X request? (INCR not yet supported) */ { uint32_t maxreqsize = xcb_get_maximum_request_length(conn); /* covert to bytes and allow for allow for X_ChangeProperty request */ maxreqsize = maxreqsize*4 - 24; if (xtpText_nitems > maxreqsize) { ErrorF("winClipboardFlushXEvents - clipboard data size %d greater than maximum %u\n", xtpText_nitems, maxreqsize); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } } /* Copy the clipboard text to the requesting window */ xcb_void_cookie_t cookie = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, selection_request->requestor, selection_request->property, selection_request->target, 8, xtpText_nitems, xtpText_value); xcb_generic_error_t *error; if ((error = xcb_request_check(conn, cookie))) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "xcb_change_property failed\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Free the converted string */ free(pszConvertData); pszConvertData = NULL; /* Release the clipboard data */ GlobalUnlock(hGlobal); pszGlobalData = NULL; fCloseClipboard = FALSE; CloseClipboard(); /* Clean up */ free(xtpText_value); xtpText_value = NULL; /* Setup selection notify event */ xcb_selection_notify_event_t eventSelection; eventSelection.response_type = XCB_SELECTION_NOTIFY; eventSelection.requestor = selection_request->requestor; eventSelection.selection = selection_request->selection; eventSelection.target = selection_request->target; eventSelection.property = selection_request->property; eventSelection.time = selection_request->time; /* Notify the requesting window that the operation has completed */ cookie = xcb_send_event_checked(conn, FALSE, eventSelection.requestor, 0, (char *) &eventSelection); if ((error = xcb_request_check(conn, cookie))) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "xcb_send_event() failed\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } winClipboardFlushXEvents_SelectionRequest_Done: /* Free allocated resources */ if (xtpText_value) { free(xtpText_value); } if (pszConvertData) free(pszConvertData); if (hGlobal && pszGlobalData) GlobalUnlock(hGlobal); /* * Send a SelectionNotify event to the requesting * client when we abort. */ if (fAbort) { /* Setup selection notify event */ eventSelection.response_type = XCB_SELECTION_NOTIFY; eventSelection.requestor = selection_request->requestor; eventSelection.selection = selection_request->selection; eventSelection.target = selection_request->target; eventSelection.property = XCB_NONE; eventSelection.time = selection_request->time; /* Notify the requesting window that the operation is complete */ cookie = xcb_send_event_checked(conn, FALSE, eventSelection.requestor, 0, (char *) &eventSelection); if ((error = xcb_request_check(conn, cookie))) { /* * Should not be a problem if XSendEvent fails because * the client may simply have exited. */ ErrorF("winClipboardFlushXEvents - SelectionRequest - " "xcb_send_event() failed for abort event.\n"); } } /* Close clipboard if it was opened */ if (fCloseClipboard) { fCloseClipboard = FALSE; CloseClipboard(); } break; } case XCB_SELECTION_NOTIFY: { xcb_selection_notify_event_t *selection_notify = (xcb_selection_notify_event_t *)event; winDebug("winClipboardFlushXEvents - SelectionNotify\n"); { char *pszAtomName; pszAtomName = get_atom_name(conn, selection_notify->selection); winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName); free(pszAtomName); } /* SelectionNotify with property of XCB_NONE indicates either: (i) Generated by the X server if no owner for the specified selection exists (perhaps it's disappeared on us mid-transaction), or (ii) Sent by the selection owner when the requested selection conversion could not be performed or server errors prevented the conversion data being returned */ if (selection_notify->property == XCB_NONE) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "Conversion to format %d refused.\n", selection_notify->target); return WIN_XEVENTS_FAILED; } if (selection_notify->target == atomTargets) { return winClipboardSelectionNotifyTargets(hwnd, iWindow, conn, data, atoms); } return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms); } case XCB_SELECTION_CLEAR: winDebug("SelectionClear - doing nothing\n"); break; case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *property_notify = (xcb_property_notify_event_t *)event; /* If INCR is in progress, collect the data */ if (data->incr && (property_notify->atom == atoms->atomLocalProperty) && (property_notify->state == XCB_PROPERTY_NEW_VALUE)) return winClipboardSelectionNotifyData(hwnd, iWindow, conn, data, atoms); break; } case XCB_MAPPING_NOTIFY: break; case 0: /* This is just laziness rather than making sure we used _checked everywhere */ { xcb_generic_error_t *err = (xcb_generic_error_t *)event; ErrorF("winClipboardFlushXEvents - Error code: %i, ID: 0x%08x, " "Major opcode: %i, Minor opcode: %i\n", err->error_code, err->resource_id, err->major_code, err->minor_code); } break; default: if ((event->response_type & ~0x80) == XCB_XFIXES_SELECTION_EVENT_SET_SELECTION_OWNER + xfixes_event_base) { xcb_xfixes_selection_notify_event_t *e = (xcb_xfixes_selection_notify_event_t *)event; winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); /* Save selection owners for monitored selections, ignore other selections */ if ((e->selection == XCB_ATOM_PRIMARY) && fPrimarySelection) { MonitorSelection(e, CLIP_OWN_PRIMARY); } else if (e->selection == atomClipboard) { MonitorSelection(e, CLIP_OWN_CLIPBOARD); } else break; /* Selection is being disowned */ if (e->owner == XCB_NONE) { winDebug("winClipboardFlushXEvents - No window, returning.\n"); break; } /* XXX: there are all kinds of wacky edge cases we might need here: - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? - root window is taking ownership? */ /* If we are the owner of the most recently owned selection, don't go all recursive :) */ if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); break; } /* Close clipboard if we have it open already (possible? correct??) */ if (GetOpenClipboardWindow() == hwnd) { CloseClipboard(); } /* Access the Windows clipboard */ if (!OpenClipboard(hwnd)) { ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", (int) GetLastError()); break; } /* Take ownership of the Windows clipboard */ if (!EmptyClipboard()) { ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", (int) GetLastError()); break; } /* Advertise regular text and unicode */ SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); /* Release the clipboard */ if (!CloseClipboard()) { ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", (int) GetLastError()); break; } } /* XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY */ /* XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE */ else { ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", event->response_type); } break; } /* I/O errors etc. */ { int e = xcb_connection_has_error(conn); if (e) { ErrorF("winClipboardFlushXEvents - Fatal error %d on xcb connection\n", e); break; } } } return WIN_XEVENTS_SUCCESS; }