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 61extern int xfixes_event_base; 62BOOL fPrimarySelection = TRUE; 63 64/* 65 * Local variables 66 */ 67 68static xcb_window_t s_iOwners[CLIP_NUM_SELECTIONS] = { XCB_NONE, XCB_NONE }; 69static const char *szSelectionNames[CLIP_NUM_SELECTIONS] = 70 { "PRIMARY", "CLIPBOARD" }; 71 72static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; 73 74static void 75MonitorSelection(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 107xcb_atom_t 108winClipboardGetLastOwnedSelectionAtom(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 123void 124winClipboardInitMonitoredSelections(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 134static 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 150static int 151winClipboardSelectionNotifyTargets(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 188static int 189winClipboardSelectionNotifyData(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 390int 391winClipboardFlushXEvents(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} 830