xevents.c revision 35c4bbdf
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/* 38 * Including any server header might define the macro _XSERVER64 on 64 bit machines. 39 * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen. 40 * So let's undef that macro if necessary. 41 */ 42#ifdef _XSERVER64 43#undef _XSERVER64 44#endif 45 46#include <limits.h> 47#include <wchar.h> 48#include <X11/Xutil.h> 49#include <X11/Xatom.h> 50#include <X11/extensions/Xfixes.h> 51 52#include "winclipboard.h" 53#include "internal.h" 54 55/* 56 * Constants 57 */ 58 59#define CLIP_NUM_SELECTIONS 2 60#define CLIP_OWN_NONE -1 61#define CLIP_OWN_PRIMARY 0 62#define CLIP_OWN_CLIPBOARD 1 63 64/* 65 * Global variables 66 */ 67 68extern int xfixes_event_base; 69Bool fPrimarySelection = TRUE; 70 71/* 72 * Local variables 73 */ 74 75static Window s_iOwners[CLIP_NUM_SELECTIONS] = { None, None }; 76static const char *szSelectionNames[CLIP_NUM_SELECTIONS] = 77 { "PRIMARY", "CLIPBOARD" }; 78 79static unsigned int lastOwnedSelectionIndex = CLIP_OWN_NONE; 80 81static void 82MonitorSelection(XFixesSelectionNotifyEvent * e, unsigned int i) 83{ 84 /* Look for owned -> not owned transition */ 85 if (None == e->owner && None != s_iOwners[i]) { 86 unsigned int other_index; 87 88 winDebug("MonitorSelection - %s - Going from owned to not owned.\n", 89 szSelectionNames[i]); 90 91 /* If this selection is not owned, the other monitored selection must be the most 92 recently owned, if it is owned at all */ 93 if (i == CLIP_OWN_PRIMARY) 94 other_index = CLIP_OWN_CLIPBOARD; 95 if (i == CLIP_OWN_CLIPBOARD) 96 other_index = CLIP_OWN_PRIMARY; 97 if (None != s_iOwners[other_index]) 98 lastOwnedSelectionIndex = other_index; 99 else 100 lastOwnedSelectionIndex = CLIP_OWN_NONE; 101 } 102 103 /* Save last owned selection */ 104 if (None != e->owner) { 105 lastOwnedSelectionIndex = i; 106 } 107 108 /* Save new selection owner or None */ 109 s_iOwners[i] = e->owner; 110 winDebug("MonitorSelection - %s - Now owned by XID %lx\n", 111 szSelectionNames[i], e->owner); 112} 113 114Atom 115winClipboardGetLastOwnedSelectionAtom(ClipboardAtoms *atoms) 116{ 117 if (lastOwnedSelectionIndex == CLIP_OWN_NONE) 118 return None; 119 120 if (lastOwnedSelectionIndex == CLIP_OWN_PRIMARY) 121 return XA_PRIMARY; 122 123 if (lastOwnedSelectionIndex == CLIP_OWN_CLIPBOARD) 124 return atoms->atomClipboard; 125 126 return None; 127} 128 129 130void 131winClipboardInitMonitoredSelections(void) 132{ 133 /* Initialize static variables */ 134 int i; 135 for (i = 0; i < CLIP_NUM_SELECTIONS; ++i) 136 s_iOwners[i] = None; 137 138 lastOwnedSelectionIndex = CLIP_OWN_NONE; 139} 140 141static int 142winClipboardSelectionNotifyTargets(HWND hwnd, Window iWindow, Display *pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms) 143{ 144 Atom type; 145 int format; 146 unsigned long nitems; 147 unsigned long after; 148 Atom *prop; 149 150 /* Retrieve the selection data and delete the property */ 151 int iReturn = XGetWindowProperty(pDisplay, 152 iWindow, 153 atoms->atomLocalProperty, 154 0, 155 INT_MAX, 156 True, 157 AnyPropertyType, 158 &type, 159 &format, 160 &nitems, 161 &after, 162 (unsigned char **)&prop); 163 if (iReturn != Success) { 164 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 165 "XGetWindowProperty () failed, aborting: %d\n", iReturn); 166 } else { 167 int i; 168 data->targetList = malloc((nitems+1)*sizeof(Atom)); 169 170 for (i = 0; i < nitems; i++) 171 { 172 Atom atom = prop[i]; 173 char *pszAtomName = XGetAtomName(pDisplay, atom); 174 data->targetList[i] = atom; 175 winDebug("winClipboardFlushXEvents - SelectionNotify - target[%d] %ld = %s\n", i, atom, pszAtomName); 176 XFree(pszAtomName); 177 } 178 179 data->targetList[nitems] = 0; 180 181 XFree(prop); 182 } 183 184 return WIN_XEVENTS_NOTIFY_TARGETS; 185} 186 187/* 188 * Process any pending X events 189 */ 190 191int 192winClipboardFlushXEvents(HWND hwnd, 193 Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms) 194{ 195 Atom atomClipboard = atoms->atomClipboard; 196 Atom atomLocalProperty = atoms->atomLocalProperty; 197 Atom atomUTF8String = atoms->atomUTF8String; 198 Atom atomCompoundText = atoms->atomCompoundText; 199 Atom atomTargets = atoms->atomTargets; 200 201 /* Process all pending events */ 202 while (XPending(pDisplay)) { 203 XTextProperty xtpText = { 0 }; 204 XEvent event; 205 XSelectionEvent eventSelection; 206 unsigned long ulReturnBytesLeft; 207 char *pszReturnData = NULL; 208 char *pszGlobalData = NULL; 209 int iReturn; 210 HGLOBAL hGlobal = NULL; 211 XICCEncodingStyle xiccesStyle; 212 char *pszConvertData = NULL; 213 char *pszTextList[2] = { NULL }; 214 int iCount; 215 char **ppszTextList = NULL; 216 wchar_t *pwszUnicodeStr = NULL; 217 Bool fAbort = FALSE; 218 Bool fCloseClipboard = FALSE; 219 Bool fSetClipboardData = TRUE; 220 221 /* Get the next event - will not block because one is ready */ 222 XNextEvent(pDisplay, &event); 223 224 /* Branch on the event type */ 225 switch (event.type) { 226 /* 227 * SelectionRequest 228 */ 229 230 case SelectionRequest: 231 { 232 char *pszAtomName = NULL; 233 234 winDebug("SelectionRequest - target %ld\n", 235 event.xselectionrequest.target); 236 237 pszAtomName = XGetAtomName(pDisplay, 238 event.xselectionrequest.target); 239 winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); 240 XFree(pszAtomName); 241 pszAtomName = NULL; 242 } 243 244 /* Abort if invalid target type */ 245 if (event.xselectionrequest.target != XA_STRING 246 && event.xselectionrequest.target != atomUTF8String 247 && event.xselectionrequest.target != atomCompoundText 248 && event.xselectionrequest.target != atomTargets) { 249 /* Abort */ 250 fAbort = TRUE; 251 goto winClipboardFlushXEvents_SelectionRequest_Done; 252 } 253 254 /* Handle targets type of request */ 255 if (event.xselectionrequest.target == atomTargets) { 256 Atom atomTargetArr[] = { atomTargets, 257 atomCompoundText, 258 atomUTF8String, 259 XA_STRING 260 }; 261 262 /* Try to change the property */ 263 iReturn = XChangeProperty(pDisplay, 264 event.xselectionrequest.requestor, 265 event.xselectionrequest.property, 266 XA_ATOM, 267 32, 268 PropModeReplace, 269 (unsigned char *) atomTargetArr, 270 (sizeof(atomTargetArr) 271 / sizeof(atomTargetArr[0]))); 272 if (iReturn == BadAlloc 273 || iReturn == BadAtom 274 || iReturn == BadMatch 275 || iReturn == BadValue || iReturn == BadWindow) { 276 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 277 "XChangeProperty failed: %d\n", iReturn); 278 } 279 280 /* Setup selection notify xevent */ 281 eventSelection.type = SelectionNotify; 282 eventSelection.send_event = True; 283 eventSelection.display = pDisplay; 284 eventSelection.requestor = event.xselectionrequest.requestor; 285 eventSelection.selection = event.xselectionrequest.selection; 286 eventSelection.target = event.xselectionrequest.target; 287 eventSelection.property = event.xselectionrequest.property; 288 eventSelection.time = event.xselectionrequest.time; 289 290 /* 291 * Notify the requesting window that 292 * the operation has completed 293 */ 294 iReturn = XSendEvent(pDisplay, 295 eventSelection.requestor, 296 False, 0L, (XEvent *) &eventSelection); 297 if (iReturn == BadValue || iReturn == BadWindow) { 298 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 299 "XSendEvent () failed\n"); 300 } 301 break; 302 } 303 304 /* Close clipboard if we have it open already */ 305 if (GetOpenClipboardWindow() == hwnd) { 306 CloseClipboard(); 307 } 308 309 /* Access the clipboard */ 310 if (!OpenClipboard(hwnd)) { 311 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 312 "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError()); 313 314 /* Abort */ 315 fAbort = TRUE; 316 goto winClipboardFlushXEvents_SelectionRequest_Done; 317 } 318 319 /* Indicate that clipboard was opened */ 320 fCloseClipboard = TRUE; 321 322 /* Check that clipboard format is available */ 323 if (data->fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { 324 static int count; /* Hack to stop acroread spamming the log */ 325 static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ 326 327 if (hwnd != lasthwnd) 328 count = 0; 329 count++; 330 if (count < 6) 331 ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not " 332 "available from Win32 clipboard. Aborting %d.\n", 333 count); 334 lasthwnd = hwnd; 335 336 /* Abort */ 337 fAbort = TRUE; 338 goto winClipboardFlushXEvents_SelectionRequest_Done; 339 } 340 else if (!data->fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { 341 ErrorF("winClipboardFlushXEvents - CF_TEXT is not " 342 "available from Win32 clipboard. Aborting.\n"); 343 344 /* Abort */ 345 fAbort = TRUE; 346 goto winClipboardFlushXEvents_SelectionRequest_Done; 347 } 348 349 /* Setup the string style */ 350 if (event.xselectionrequest.target == XA_STRING) 351 xiccesStyle = XStringStyle; 352#ifdef X_HAVE_UTF8_STRING 353 else if (event.xselectionrequest.target == atomUTF8String) 354 xiccesStyle = XUTF8StringStyle; 355#endif 356 else if (event.xselectionrequest.target == atomCompoundText) 357 xiccesStyle = XCompoundTextStyle; 358 else 359 xiccesStyle = XStringStyle; 360 361 /* Get a pointer to the clipboard text, in desired format */ 362 if (data->fUseUnicode) { 363 /* Retrieve clipboard data */ 364 hGlobal = GetClipboardData(CF_UNICODETEXT); 365 } 366 else { 367 /* Retrieve clipboard data */ 368 hGlobal = GetClipboardData(CF_TEXT); 369 } 370 if (!hGlobal) { 371 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 372 "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError()); 373 374 /* Abort */ 375 fAbort = TRUE; 376 goto winClipboardFlushXEvents_SelectionRequest_Done; 377 } 378 pszGlobalData = (char *) GlobalLock(hGlobal); 379 380 /* Convert the Unicode string to UTF8 (MBCS) */ 381 if (data->fUseUnicode) { 382 int iConvertDataLen = WideCharToMultiByte(CP_UTF8, 383 0, 384 (LPCWSTR) pszGlobalData, 385 -1, NULL, 0, NULL, NULL); 386 /* NOTE: iConvertDataLen includes space for null terminator */ 387 pszConvertData = malloc(iConvertDataLen); 388 WideCharToMultiByte(CP_UTF8, 389 0, 390 (LPCWSTR) pszGlobalData, 391 -1, 392 pszConvertData, 393 iConvertDataLen, NULL, NULL); 394 } 395 else { 396 pszConvertData = strdup(pszGlobalData); 397 } 398 399 /* Convert DOS string to UNIX string */ 400 winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); 401 402 /* Setup our text list */ 403 pszTextList[0] = pszConvertData; 404 pszTextList[1] = NULL; 405 406 /* Initialize the text property */ 407 xtpText.value = NULL; 408 xtpText.nitems = 0; 409 410 /* Create the text property from the text list */ 411 if (data->fUseUnicode) { 412#ifdef X_HAVE_UTF8_STRING 413 iReturn = Xutf8TextListToTextProperty(pDisplay, 414 pszTextList, 415 1, xiccesStyle, &xtpText); 416#endif 417 } 418 else { 419 iReturn = XmbTextListToTextProperty(pDisplay, 420 pszTextList, 421 1, xiccesStyle, &xtpText); 422 } 423 if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { 424 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 425 "X*TextListToTextProperty failed: %d\n", iReturn); 426 427 /* Abort */ 428 fAbort = TRUE; 429 goto winClipboardFlushXEvents_SelectionRequest_Done; 430 } 431 432 /* Free the converted string */ 433 free(pszConvertData); 434 pszConvertData = NULL; 435 436 /* Copy the clipboard text to the requesting window */ 437 iReturn = XChangeProperty(pDisplay, 438 event.xselectionrequest.requestor, 439 event.xselectionrequest.property, 440 event.xselectionrequest.target, 441 8, 442 PropModeReplace, 443 xtpText.value, xtpText.nitems); 444 if (iReturn == BadAlloc || iReturn == BadAtom 445 || iReturn == BadMatch || iReturn == BadValue 446 || iReturn == BadWindow) { 447 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 448 "XChangeProperty failed: %d\n", iReturn); 449 450 /* Abort */ 451 fAbort = TRUE; 452 goto winClipboardFlushXEvents_SelectionRequest_Done; 453 } 454 455 /* Release the clipboard data */ 456 GlobalUnlock(hGlobal); 457 pszGlobalData = NULL; 458 fCloseClipboard = FALSE; 459 CloseClipboard(); 460 461 /* Clean up */ 462 XFree(xtpText.value); 463 xtpText.value = NULL; 464 xtpText.nitems = 0; 465 466 /* Setup selection notify event */ 467 eventSelection.type = SelectionNotify; 468 eventSelection.send_event = True; 469 eventSelection.display = pDisplay; 470 eventSelection.requestor = event.xselectionrequest.requestor; 471 eventSelection.selection = event.xselectionrequest.selection; 472 eventSelection.target = event.xselectionrequest.target; 473 eventSelection.property = event.xselectionrequest.property; 474 eventSelection.time = event.xselectionrequest.time; 475 476 /* Notify the requesting window that the operation has completed */ 477 iReturn = XSendEvent(pDisplay, 478 eventSelection.requestor, 479 False, 0L, (XEvent *) &eventSelection); 480 if (iReturn == BadValue || iReturn == BadWindow) { 481 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 482 "XSendEvent () failed\n"); 483 484 /* Abort */ 485 fAbort = TRUE; 486 goto winClipboardFlushXEvents_SelectionRequest_Done; 487 } 488 489 winClipboardFlushXEvents_SelectionRequest_Done: 490 /* Free allocated resources */ 491 if (xtpText.value) { 492 XFree(xtpText.value); 493 xtpText.value = NULL; 494 xtpText.nitems = 0; 495 } 496 free(pszConvertData); 497 if (hGlobal && pszGlobalData) 498 GlobalUnlock(hGlobal); 499 500 /* 501 * Send a SelectionNotify event to the requesting 502 * client when we abort. 503 */ 504 if (fAbort) { 505 /* Setup selection notify event */ 506 eventSelection.type = SelectionNotify; 507 eventSelection.send_event = True; 508 eventSelection.display = pDisplay; 509 eventSelection.requestor = event.xselectionrequest.requestor; 510 eventSelection.selection = event.xselectionrequest.selection; 511 eventSelection.target = event.xselectionrequest.target; 512 eventSelection.property = None; 513 eventSelection.time = event.xselectionrequest.time; 514 515 /* Notify the requesting window that the operation is complete */ 516 iReturn = XSendEvent(pDisplay, 517 eventSelection.requestor, 518 False, 0L, (XEvent *) &eventSelection); 519 if (iReturn == BadValue || iReturn == BadWindow) { 520 /* 521 * Should not be a problem if XSendEvent fails because 522 * the client may simply have exited. 523 */ 524 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 525 "XSendEvent () failed for abort event.\n"); 526 } 527 } 528 529 /* Close clipboard if it was opened */ 530 if (fCloseClipboard) { 531 fCloseClipboard = FALSE; 532 CloseClipboard(); 533 } 534 break; 535 536 /* 537 * SelectionNotify 538 */ 539 540 case SelectionNotify: 541 winDebug("winClipboardFlushXEvents - SelectionNotify\n"); 542 { 543 char *pszAtomName; 544 545 pszAtomName = XGetAtomName(pDisplay, 546 event.xselection.selection); 547 548 winDebug 549 ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", 550 pszAtomName); 551 XFree(pszAtomName); 552 } 553 554 /* 555 SelectionNotify with property of None indicates either: 556 557 (i) Generated by the X server if no owner for the specified selection exists 558 (perhaps it's disappeared on us mid-transaction), or 559 (ii) Sent by the selection owner when the requested selection conversion could 560 not be performed or server errors prevented the conversion data being returned 561 */ 562 if (event.xselection.property == None) { 563 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 564 "Conversion to format %ld refused.\n", 565 event.xselection.target); 566 return WIN_XEVENTS_FAILED; 567 } 568 569 if (event.xselection.target == atomTargets) { 570 return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms); 571 } 572 573 /* Retrieve the selection data and delete the property */ 574 iReturn = XGetWindowProperty(pDisplay, 575 iWindow, 576 atomLocalProperty, 577 0, 578 INT_MAX, 579 True, 580 AnyPropertyType, 581 &xtpText.encoding, 582 &xtpText.format, 583 &xtpText.nitems, 584 &ulReturnBytesLeft, &xtpText.value); 585 if (iReturn != Success) { 586 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 587 "XGetWindowProperty () failed, aborting: %d\n", iReturn); 588 goto winClipboardFlushXEvents_SelectionNotify_Done; 589 } 590 591 { 592 char *pszAtomName = NULL; 593 594 winDebug("SelectionNotify - returned data %lu left %lu\n", 595 xtpText.nitems, ulReturnBytesLeft); 596 pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); 597 winDebug("Notify atom name %s\n", pszAtomName); 598 XFree(pszAtomName); 599 pszAtomName = NULL; 600 } 601 602 if (data->fUseUnicode) { 603#ifdef X_HAVE_UTF8_STRING 604 /* Convert the text property to a text list */ 605 iReturn = Xutf8TextPropertyToTextList(pDisplay, 606 &xtpText, 607 &ppszTextList, &iCount); 608#endif 609 } 610 else { 611 iReturn = XmbTextPropertyToTextList(pDisplay, 612 &xtpText, 613 &ppszTextList, &iCount); 614 } 615 if (iReturn == Success || iReturn > 0) { 616 /* Conversion succeeded or some unconvertible characters */ 617 if (ppszTextList != NULL) { 618 int i; 619 int iReturnDataLen = 0; 620 for (i = 0; i < iCount; i++) { 621 iReturnDataLen += strlen(ppszTextList[i]); 622 } 623 pszReturnData = malloc(iReturnDataLen + 1); 624 pszReturnData[0] = '\0'; 625 for (i = 0; i < iCount; i++) { 626 strcat(pszReturnData, ppszTextList[i]); 627 } 628 } 629 else { 630 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 631 "X*TextPropertyToTextList list_return is NULL.\n"); 632 pszReturnData = malloc(1); 633 pszReturnData[0] = '\0'; 634 } 635 } 636 else { 637 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 638 "X*TextPropertyToTextList returned: "); 639 switch (iReturn) { 640 case XNoMemory: 641 ErrorF("XNoMemory\n"); 642 break; 643 case XLocaleNotSupported: 644 ErrorF("XLocaleNotSupported\n"); 645 break; 646 case XConverterNotFound: 647 ErrorF("XConverterNotFound\n"); 648 break; 649 default: 650 ErrorF("%d\n", iReturn); 651 break; 652 } 653 pszReturnData = malloc(1); 654 pszReturnData[0] = '\0'; 655 } 656 657 /* Free the data returned from XGetWindowProperty */ 658 if (ppszTextList) 659 XFreeStringList(ppszTextList); 660 ppszTextList = NULL; 661 XFree(xtpText.value); 662 xtpText.value = NULL; 663 xtpText.nitems = 0; 664 665 /* Convert the X clipboard string to DOS format */ 666 winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); 667 668 if (data->fUseUnicode) { 669 /* Find out how much space needed to convert MBCS to Unicode */ 670 int iUnicodeLen = MultiByteToWideChar(CP_UTF8, 671 0, 672 pszReturnData, -1, NULL, 0); 673 674 /* NOTE: iUnicodeLen includes space for null terminator */ 675 pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen); 676 if (!pwszUnicodeStr) { 677 ErrorF("winClipboardFlushXEvents - SelectionNotify " 678 "malloc failed for pwszUnicodeStr, aborting.\n"); 679 680 /* Abort */ 681 fAbort = TRUE; 682 goto winClipboardFlushXEvents_SelectionNotify_Done; 683 } 684 685 /* Do the actual conversion */ 686 MultiByteToWideChar(CP_UTF8, 687 0, 688 pszReturnData, 689 -1, pwszUnicodeStr, iUnicodeLen); 690 691 /* Allocate global memory for the X clipboard data */ 692 hGlobal = GlobalAlloc(GMEM_MOVEABLE, 693 sizeof(wchar_t) * iUnicodeLen); 694 } 695 else { 696 int iConvertDataLen = 0; 697 pszConvertData = strdup(pszReturnData); 698 iConvertDataLen = strlen(pszConvertData) + 1; 699 700 /* Allocate global memory for the X clipboard data */ 701 hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen); 702 } 703 704 free(pszReturnData); 705 706 /* Check that global memory was allocated */ 707 if (!hGlobal) { 708 ErrorF("winClipboardFlushXEvents - SelectionNotify " 709 "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError()); 710 711 /* Abort */ 712 fAbort = TRUE; 713 goto winClipboardFlushXEvents_SelectionNotify_Done; 714 } 715 716 /* Obtain a pointer to the global memory */ 717 pszGlobalData = GlobalLock(hGlobal); 718 if (pszGlobalData == NULL) { 719 ErrorF("winClipboardFlushXEvents - Could not lock global " 720 "memory for clipboard transfer\n"); 721 722 /* Abort */ 723 fAbort = TRUE; 724 goto winClipboardFlushXEvents_SelectionNotify_Done; 725 } 726 727 /* Copy the returned string into the global memory */ 728 if (data->fUseUnicode) { 729 wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr); 730 free(pwszUnicodeStr); 731 pwszUnicodeStr = NULL; 732 } 733 else { 734 strcpy(pszGlobalData, pszConvertData); 735 free(pszConvertData); 736 pszConvertData = NULL; 737 } 738 739 /* Release the pointer to the global memory */ 740 GlobalUnlock(hGlobal); 741 pszGlobalData = NULL; 742 743 /* Push the selection data to the Windows clipboard */ 744 if (data->fUseUnicode) 745 SetClipboardData(CF_UNICODETEXT, hGlobal); 746 else 747 SetClipboardData(CF_TEXT, hGlobal); 748 749 /* Flag that SetClipboardData has been called */ 750 fSetClipboardData = FALSE; 751 752 /* 753 * NOTE: Do not try to free pszGlobalData, it is owned by 754 * Windows after the call to SetClipboardData (). 755 */ 756 757 winClipboardFlushXEvents_SelectionNotify_Done: 758 /* Free allocated resources */ 759 if (ppszTextList) 760 XFreeStringList(ppszTextList); 761 if (xtpText.value) { 762 XFree(xtpText.value); 763 xtpText.value = NULL; 764 xtpText.nitems = 0; 765 } 766 free(pszConvertData); 767 free(pwszUnicodeStr); 768 if (hGlobal && pszGlobalData) 769 GlobalUnlock(hGlobal); 770 if (fSetClipboardData) { 771 SetClipboardData(CF_UNICODETEXT, NULL); 772 SetClipboardData(CF_TEXT, NULL); 773 } 774 return WIN_XEVENTS_NOTIFY_DATA; 775 776 case SelectionClear: 777 winDebug("SelectionClear - doing nothing\n"); 778 break; 779 780 case PropertyNotify: 781 break; 782 783 case MappingNotify: 784 break; 785 786 default: 787 if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { 788 XFixesSelectionNotifyEvent *e = 789 (XFixesSelectionNotifyEvent *) & event; 790 791 winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); 792 793 /* Save selection owners for monitored selections, ignore other selections */ 794 if ((e->selection == XA_PRIMARY) && fPrimarySelection) { 795 MonitorSelection(e, CLIP_OWN_PRIMARY); 796 } 797 else if (e->selection == atomClipboard) { 798 MonitorSelection(e, CLIP_OWN_CLIPBOARD); 799 } 800 else 801 break; 802 803 /* Selection is being disowned */ 804 if (e->owner == None) { 805 winDebug 806 ("winClipboardFlushXEvents - No window, returning.\n"); 807 break; 808 } 809 810 /* 811 XXX: there are all kinds of wacky edge cases we might need here: 812 - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? 813 - root window is taking ownership? 814 */ 815 816 /* If we are the owner of the most recently owned selection, don't go all recursive :) */ 817 if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && 818 (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { 819 winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); 820 break; 821 } 822 823 /* Close clipboard if we have it open already (possible? correct??) */ 824 if (GetOpenClipboardWindow() == hwnd) { 825 CloseClipboard(); 826 } 827 828 /* Access the Windows clipboard */ 829 if (!OpenClipboard(hwnd)) { 830 ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", 831 (int) GetLastError()); 832 break; 833 } 834 835 /* Take ownership of the Windows clipboard */ 836 if (!EmptyClipboard()) { 837 ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", 838 (int) GetLastError()); 839 break; 840 } 841 842 /* Advertise regular text and unicode */ 843 SetClipboardData(CF_UNICODETEXT, NULL); 844 SetClipboardData(CF_TEXT, NULL); 845 846 /* Release the clipboard */ 847 if (!CloseClipboard()) { 848 ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", 849 (int) GetLastError()); 850 break; 851 } 852 } 853 /* XFixesSelectionWindowDestroyNotifyMask */ 854 /* XFixesSelectionClientCloseNotifyMask */ 855 else { 856 ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", 857 event.type); 858 } 859 break; 860 } 861 } 862 863 return WIN_XEVENTS_SUCCESS; 864} 865