xevents.c revision 1b5d61b8
114b11b2bSmrg/* 214b11b2bSmrg *Copyright (C) 2003-2004 Harold L Hunt II All Rights Reserved. 314b11b2bSmrg *Copyright (C) Colin Harrison 2005-2008 414b11b2bSmrg * 514b11b2bSmrg *Permission is hereby granted, free of charge, to any person obtaining 614b11b2bSmrg * a copy of this software and associated documentation files (the 714b11b2bSmrg *"Software"), to deal in the Software without restriction, including 814b11b2bSmrg *without limitation the rights to use, copy, modify, merge, publish, 914b11b2bSmrg *distribute, sublicense, and/or sell copies of the Software, and to 1014b11b2bSmrg *permit persons to whom the Software is furnished to do so, subject to 1114b11b2bSmrg *the following conditions: 1214b11b2bSmrg * 1314b11b2bSmrg *The above copyright notice and this permission notice shall be 1414b11b2bSmrg *included in all copies or substantial portions of the Software. 1514b11b2bSmrg * 1614b11b2bSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1714b11b2bSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1814b11b2bSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1914b11b2bSmrg *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR 2014b11b2bSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 2114b11b2bSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2214b11b2bSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2314b11b2bSmrg * 2414b11b2bSmrg *Except as contained in this notice, the name of the copyright holder(s) 2514b11b2bSmrg *and author(s) shall not be used in advertising or otherwise to promote 2614b11b2bSmrg *the sale, use or other dealings in this Software without prior written 2714b11b2bSmrg *authorization from the copyright holder(s) and author(s). 2814b11b2bSmrg * 2914b11b2bSmrg * Authors: Harold L Hunt II 3014b11b2bSmrg * Colin Harrison 3114b11b2bSmrg */ 3214b11b2bSmrg 3314b11b2bSmrg#ifdef HAVE_XWIN_CONFIG_H 3414b11b2bSmrg#include <xwin-config.h> 3514b11b2bSmrg#endif 3614b11b2bSmrg 3714b11b2bSmrg/* 3814b11b2bSmrg * Including any server header might define the macro _XSERVER64 on 64 bit machines. 3914b11b2bSmrg * That macro must _NOT_ be defined for Xlib client code, otherwise bad things happen. 4014b11b2bSmrg * So let's undef that macro if necessary. 4114b11b2bSmrg */ 4214b11b2bSmrg#ifdef _XSERVER64 4314b11b2bSmrg#undef _XSERVER64 4414b11b2bSmrg#endif 4514b11b2bSmrg 4614b11b2bSmrg#include <limits.h> 4714b11b2bSmrg#include <wchar.h> 4814b11b2bSmrg#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 ARRAY_SIZE(atomTargetArr)); 271 if (iReturn == BadAlloc 272 || iReturn == BadAtom 273 || iReturn == BadMatch 274 || iReturn == BadValue || iReturn == BadWindow) { 275 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 276 "XChangeProperty failed: %d\n", iReturn); 277 } 278 279 /* Setup selection notify xevent */ 280 eventSelection.type = SelectionNotify; 281 eventSelection.send_event = True; 282 eventSelection.display = pDisplay; 283 eventSelection.requestor = event.xselectionrequest.requestor; 284 eventSelection.selection = event.xselectionrequest.selection; 285 eventSelection.target = event.xselectionrequest.target; 286 eventSelection.property = event.xselectionrequest.property; 287 eventSelection.time = event.xselectionrequest.time; 288 289 /* 290 * Notify the requesting window that 291 * the operation has completed 292 */ 293 iReturn = XSendEvent(pDisplay, 294 eventSelection.requestor, 295 False, 0L, (XEvent *) &eventSelection); 296 if (iReturn == BadValue || iReturn == BadWindow) { 297 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 298 "XSendEvent () failed\n"); 299 } 300 break; 301 } 302 303 /* Close clipboard if we have it open already */ 304 if (GetOpenClipboardWindow() == hwnd) { 305 CloseClipboard(); 306 } 307 308 /* Access the clipboard */ 309 if (!OpenClipboard(hwnd)) { 310 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 311 "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError()); 312 313 /* Abort */ 314 fAbort = TRUE; 315 goto winClipboardFlushXEvents_SelectionRequest_Done; 316 } 317 318 /* Indicate that clipboard was opened */ 319 fCloseClipboard = TRUE; 320 321 /* Check that clipboard format is available */ 322 if (data->fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { 323 static int count; /* Hack to stop acroread spamming the log */ 324 static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ 325 326 if (hwnd != lasthwnd) 327 count = 0; 328 count++; 329 if (count < 6) 330 ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not " 331 "available from Win32 clipboard. Aborting %d.\n", 332 count); 333 lasthwnd = hwnd; 334 335 /* Abort */ 336 fAbort = TRUE; 337 goto winClipboardFlushXEvents_SelectionRequest_Done; 338 } 339 else if (!data->fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { 340 ErrorF("winClipboardFlushXEvents - CF_TEXT is not " 341 "available from Win32 clipboard. Aborting.\n"); 342 343 /* Abort */ 344 fAbort = TRUE; 345 goto winClipboardFlushXEvents_SelectionRequest_Done; 346 } 347 348 /* Setup the string style */ 349 if (event.xselectionrequest.target == XA_STRING) 350 xiccesStyle = XStringStyle; 351#ifdef X_HAVE_UTF8_STRING 352 else if (event.xselectionrequest.target == atomUTF8String) 353 xiccesStyle = XUTF8StringStyle; 354#endif 355 else if (event.xselectionrequest.target == atomCompoundText) 356 xiccesStyle = XCompoundTextStyle; 357 else 358 xiccesStyle = XStringStyle; 359 360 /* Get a pointer to the clipboard text, in desired format */ 361 if (data->fUseUnicode) { 362 /* Retrieve clipboard data */ 363 hGlobal = GetClipboardData(CF_UNICODETEXT); 364 } 365 else { 366 /* Retrieve clipboard data */ 367 hGlobal = GetClipboardData(CF_TEXT); 368 } 369 if (!hGlobal) { 370 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 371 "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError()); 372 373 /* Abort */ 374 fAbort = TRUE; 375 goto winClipboardFlushXEvents_SelectionRequest_Done; 376 } 377 pszGlobalData = (char *) GlobalLock(hGlobal); 378 379 /* Convert the Unicode string to UTF8 (MBCS) */ 380 if (data->fUseUnicode) { 381 int iConvertDataLen = WideCharToMultiByte(CP_UTF8, 382 0, 383 (LPCWSTR) pszGlobalData, 384 -1, NULL, 0, NULL, NULL); 385 /* NOTE: iConvertDataLen includes space for null terminator */ 386 pszConvertData = malloc(iConvertDataLen); 387 WideCharToMultiByte(CP_UTF8, 388 0, 389 (LPCWSTR) pszGlobalData, 390 -1, 391 pszConvertData, 392 iConvertDataLen, NULL, NULL); 393 } 394 else { 395 pszConvertData = strdup(pszGlobalData); 396 } 397 398 /* Convert DOS string to UNIX string */ 399 winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); 400 401 /* Setup our text list */ 402 pszTextList[0] = pszConvertData; 403 pszTextList[1] = NULL; 404 405 /* Initialize the text property */ 406 xtpText.value = NULL; 407 xtpText.nitems = 0; 408 409 /* Create the text property from the text list */ 410 if (data->fUseUnicode) { 411#ifdef X_HAVE_UTF8_STRING 412 iReturn = Xutf8TextListToTextProperty(pDisplay, 413 pszTextList, 414 1, xiccesStyle, &xtpText); 415#endif 416 } 417 else { 418 iReturn = XmbTextListToTextProperty(pDisplay, 419 pszTextList, 420 1, xiccesStyle, &xtpText); 421 } 422 if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { 423 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 424 "X*TextListToTextProperty failed: %d\n", iReturn); 425 426 /* Abort */ 427 fAbort = TRUE; 428 goto winClipboardFlushXEvents_SelectionRequest_Done; 429 } 430 431 /* Free the converted string */ 432 free(pszConvertData); 433 pszConvertData = NULL; 434 435 /* Copy the clipboard text to the requesting window */ 436 iReturn = XChangeProperty(pDisplay, 437 event.xselectionrequest.requestor, 438 event.xselectionrequest.property, 439 event.xselectionrequest.target, 440 8, 441 PropModeReplace, 442 xtpText.value, xtpText.nitems); 443 if (iReturn == BadAlloc || iReturn == BadAtom 444 || iReturn == BadMatch || iReturn == BadValue 445 || iReturn == BadWindow) { 446 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 447 "XChangeProperty failed: %d\n", iReturn); 448 449 /* Abort */ 450 fAbort = TRUE; 451 goto winClipboardFlushXEvents_SelectionRequest_Done; 452 } 453 454 /* Release the clipboard data */ 455 GlobalUnlock(hGlobal); 456 pszGlobalData = NULL; 457 fCloseClipboard = FALSE; 458 CloseClipboard(); 459 460 /* Clean up */ 461 XFree(xtpText.value); 462 xtpText.value = NULL; 463 xtpText.nitems = 0; 464 465 /* Setup selection notify event */ 466 eventSelection.type = SelectionNotify; 467 eventSelection.send_event = True; 468 eventSelection.display = pDisplay; 469 eventSelection.requestor = event.xselectionrequest.requestor; 470 eventSelection.selection = event.xselectionrequest.selection; 471 eventSelection.target = event.xselectionrequest.target; 472 eventSelection.property = event.xselectionrequest.property; 473 eventSelection.time = event.xselectionrequest.time; 474 475 /* Notify the requesting window that the operation has completed */ 476 iReturn = XSendEvent(pDisplay, 477 eventSelection.requestor, 478 False, 0L, (XEvent *) &eventSelection); 479 if (iReturn == BadValue || iReturn == BadWindow) { 480 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 481 "XSendEvent () failed\n"); 482 483 /* Abort */ 484 fAbort = TRUE; 485 goto winClipboardFlushXEvents_SelectionRequest_Done; 486 } 487 488 winClipboardFlushXEvents_SelectionRequest_Done: 489 /* Free allocated resources */ 490 if (xtpText.value) { 491 XFree(xtpText.value); 492 xtpText.value = NULL; 493 xtpText.nitems = 0; 494 } 495 free(pszConvertData); 496 if (hGlobal && pszGlobalData) 497 GlobalUnlock(hGlobal); 498 499 /* 500 * Send a SelectionNotify event to the requesting 501 * client when we abort. 502 */ 503 if (fAbort) { 504 /* Setup selection notify event */ 505 eventSelection.type = SelectionNotify; 506 eventSelection.send_event = True; 507 eventSelection.display = pDisplay; 508 eventSelection.requestor = event.xselectionrequest.requestor; 509 eventSelection.selection = event.xselectionrequest.selection; 510 eventSelection.target = event.xselectionrequest.target; 511 eventSelection.property = None; 512 eventSelection.time = event.xselectionrequest.time; 513 514 /* Notify the requesting window that the operation is complete */ 515 iReturn = XSendEvent(pDisplay, 516 eventSelection.requestor, 517 False, 0L, (XEvent *) &eventSelection); 518 if (iReturn == BadValue || iReturn == BadWindow) { 519 /* 520 * Should not be a problem if XSendEvent fails because 521 * the client may simply have exited. 522 */ 523 ErrorF("winClipboardFlushXEvents - SelectionRequest - " 524 "XSendEvent () failed for abort event.\n"); 525 } 526 } 527 528 /* Close clipboard if it was opened */ 529 if (fCloseClipboard) { 530 fCloseClipboard = FALSE; 531 CloseClipboard(); 532 } 533 break; 534 535 /* 536 * SelectionNotify 537 */ 538 539 case SelectionNotify: 540 winDebug("winClipboardFlushXEvents - SelectionNotify\n"); 541 { 542 char *pszAtomName; 543 544 pszAtomName = XGetAtomName(pDisplay, 545 event.xselection.selection); 546 547 winDebug 548 ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", 549 pszAtomName); 550 XFree(pszAtomName); 551 } 552 553 /* 554 SelectionNotify with property of None indicates either: 555 556 (i) Generated by the X server if no owner for the specified selection exists 557 (perhaps it's disappeared on us mid-transaction), or 558 (ii) Sent by the selection owner when the requested selection conversion could 559 not be performed or server errors prevented the conversion data being returned 560 */ 561 if (event.xselection.property == None) { 562 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 563 "Conversion to format %ld refused.\n", 564 event.xselection.target); 565 return WIN_XEVENTS_FAILED; 566 } 567 568 if (event.xselection.target == atomTargets) { 569 return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms); 570 } 571 572 /* Retrieve the selection data and delete the property */ 573 iReturn = XGetWindowProperty(pDisplay, 574 iWindow, 575 atomLocalProperty, 576 0, 577 INT_MAX, 578 True, 579 AnyPropertyType, 580 &xtpText.encoding, 581 &xtpText.format, 582 &xtpText.nitems, 583 &ulReturnBytesLeft, &xtpText.value); 584 if (iReturn != Success) { 585 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 586 "XGetWindowProperty () failed, aborting: %d\n", iReturn); 587 goto winClipboardFlushXEvents_SelectionNotify_Done; 588 } 589 590 { 591 char *pszAtomName = NULL; 592 593 winDebug("SelectionNotify - returned data %lu left %lu\n", 594 xtpText.nitems, ulReturnBytesLeft); 595 pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); 596 winDebug("Notify atom name %s\n", pszAtomName); 597 XFree(pszAtomName); 598 pszAtomName = NULL; 599 } 600 601 if (data->fUseUnicode) { 602#ifdef X_HAVE_UTF8_STRING 603 /* Convert the text property to a text list */ 604 iReturn = Xutf8TextPropertyToTextList(pDisplay, 605 &xtpText, 606 &ppszTextList, &iCount); 607#endif 608 } 609 else { 610 iReturn = XmbTextPropertyToTextList(pDisplay, 611 &xtpText, 612 &ppszTextList, &iCount); 613 } 614 if (iReturn == Success || iReturn > 0) { 615 /* Conversion succeeded or some unconvertible characters */ 616 if (ppszTextList != NULL) { 617 int i; 618 int iReturnDataLen = 0; 619 for (i = 0; i < iCount; i++) { 620 iReturnDataLen += strlen(ppszTextList[i]); 621 } 622 pszReturnData = malloc(iReturnDataLen + 1); 623 pszReturnData[0] = '\0'; 624 for (i = 0; i < iCount; i++) { 625 strcat(pszReturnData, ppszTextList[i]); 626 } 627 } 628 else { 629 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 630 "X*TextPropertyToTextList list_return is NULL.\n"); 631 pszReturnData = malloc(1); 632 pszReturnData[0] = '\0'; 633 } 634 } 635 else { 636 ErrorF("winClipboardFlushXEvents - SelectionNotify - " 637 "X*TextPropertyToTextList returned: "); 638 switch (iReturn) { 639 case XNoMemory: 640 ErrorF("XNoMemory\n"); 641 break; 642 case XLocaleNotSupported: 643 ErrorF("XLocaleNotSupported\n"); 644 break; 645 case XConverterNotFound: 646 ErrorF("XConverterNotFound\n"); 647 break; 648 default: 649 ErrorF("%d\n", iReturn); 650 break; 651 } 652 pszReturnData = malloc(1); 653 pszReturnData[0] = '\0'; 654 } 655 656 /* Free the data returned from XGetWindowProperty */ 657 if (ppszTextList) 658 XFreeStringList(ppszTextList); 659 ppszTextList = NULL; 660 XFree(xtpText.value); 661 xtpText.value = NULL; 662 xtpText.nitems = 0; 663 664 /* Convert the X clipboard string to DOS format */ 665 winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); 666 667 if (data->fUseUnicode) { 668 /* Find out how much space needed to convert MBCS to Unicode */ 669 int iUnicodeLen = MultiByteToWideChar(CP_UTF8, 670 0, 671 pszReturnData, -1, NULL, 0); 672 673 /* NOTE: iUnicodeLen includes space for null terminator */ 674 pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen); 675 if (!pwszUnicodeStr) { 676 ErrorF("winClipboardFlushXEvents - SelectionNotify " 677 "malloc failed for pwszUnicodeStr, aborting.\n"); 678 679 /* Abort */ 680 fAbort = TRUE; 681 goto winClipboardFlushXEvents_SelectionNotify_Done; 682 } 683 684 /* Do the actual conversion */ 685 MultiByteToWideChar(CP_UTF8, 686 0, 687 pszReturnData, 688 -1, pwszUnicodeStr, iUnicodeLen); 689 690 /* Allocate global memory for the X clipboard data */ 691 hGlobal = GlobalAlloc(GMEM_MOVEABLE, 692 sizeof(wchar_t) * iUnicodeLen); 693 } 694 else { 695 int iConvertDataLen = 0; 696 pszConvertData = strdup(pszReturnData); 697 iConvertDataLen = strlen(pszConvertData) + 1; 698 699 /* Allocate global memory for the X clipboard data */ 700 hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen); 701 } 702 703 free(pszReturnData); 704 705 /* Check that global memory was allocated */ 706 if (!hGlobal) { 707 ErrorF("winClipboardFlushXEvents - SelectionNotify " 708 "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError()); 709 710 /* Abort */ 711 fAbort = TRUE; 712 goto winClipboardFlushXEvents_SelectionNotify_Done; 713 } 714 715 /* Obtain a pointer to the global memory */ 716 pszGlobalData = GlobalLock(hGlobal); 717 if (pszGlobalData == NULL) { 718 ErrorF("winClipboardFlushXEvents - Could not lock global " 719 "memory for clipboard transfer\n"); 720 721 /* Abort */ 722 fAbort = TRUE; 723 goto winClipboardFlushXEvents_SelectionNotify_Done; 724 } 725 726 /* Copy the returned string into the global memory */ 727 if (data->fUseUnicode) { 728 wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr); 729 free(pwszUnicodeStr); 730 pwszUnicodeStr = NULL; 731 } 732 else { 733 strcpy(pszGlobalData, pszConvertData); 734 free(pszConvertData); 735 pszConvertData = NULL; 736 } 737 738 /* Release the pointer to the global memory */ 739 GlobalUnlock(hGlobal); 740 pszGlobalData = NULL; 741 742 /* Push the selection data to the Windows clipboard */ 743 if (data->fUseUnicode) 744 SetClipboardData(CF_UNICODETEXT, hGlobal); 745 else 746 SetClipboardData(CF_TEXT, hGlobal); 747 748 /* Flag that SetClipboardData has been called */ 749 fSetClipboardData = FALSE; 750 751 /* 752 * NOTE: Do not try to free pszGlobalData, it is owned by 753 * Windows after the call to SetClipboardData (). 754 */ 755 756 winClipboardFlushXEvents_SelectionNotify_Done: 757 /* Free allocated resources */ 758 if (ppszTextList) 759 XFreeStringList(ppszTextList); 760 if (xtpText.value) { 761 XFree(xtpText.value); 762 xtpText.value = NULL; 763 xtpText.nitems = 0; 764 } 765 free(pszConvertData); 766 free(pwszUnicodeStr); 767 if (hGlobal && pszGlobalData) 768 GlobalUnlock(hGlobal); 769 if (fSetClipboardData) { 770 SetClipboardData(CF_UNICODETEXT, NULL); 771 SetClipboardData(CF_TEXT, NULL); 772 } 773 return WIN_XEVENTS_NOTIFY_DATA; 774 775 case SelectionClear: 776 winDebug("SelectionClear - doing nothing\n"); 777 break; 778 779 case PropertyNotify: 780 break; 781 782 case MappingNotify: 783 break; 784 785 default: 786 if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { 787 XFixesSelectionNotifyEvent *e = 788 (XFixesSelectionNotifyEvent *) & event; 789 790 winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); 791 792 /* Save selection owners for monitored selections, ignore other selections */ 793 if ((e->selection == XA_PRIMARY) && fPrimarySelection) { 794 MonitorSelection(e, CLIP_OWN_PRIMARY); 795 } 796 else if (e->selection == atomClipboard) { 797 MonitorSelection(e, CLIP_OWN_CLIPBOARD); 798 } 799 else 800 break; 801 802 /* Selection is being disowned */ 803 if (e->owner == None) { 804 winDebug 805 ("winClipboardFlushXEvents - No window, returning.\n"); 806 break; 807 } 808 809 /* 810 XXX: there are all kinds of wacky edge cases we might need here: 811 - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? 812 - root window is taking ownership? 813 */ 814 815 /* If we are the owner of the most recently owned selection, don't go all recursive :) */ 816 if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && 817 (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { 818 winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); 819 break; 820 } 821 822 /* Close clipboard if we have it open already (possible? correct??) */ 823 if (GetOpenClipboardWindow() == hwnd) { 824 CloseClipboard(); 825 } 826 827 /* Access the Windows clipboard */ 828 if (!OpenClipboard(hwnd)) { 829 ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", 830 (int) GetLastError()); 831 break; 832 } 833 834 /* Take ownership of the Windows clipboard */ 835 if (!EmptyClipboard()) { 836 ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", 837 (int) GetLastError()); 838 break; 839 } 840 841 /* Advertise regular text and unicode */ 842 SetClipboardData(CF_UNICODETEXT, NULL); 843 SetClipboardData(CF_TEXT, NULL); 844 845 /* Release the clipboard */ 846 if (!CloseClipboard()) { 847 ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", 848 (int) GetLastError()); 849 break; 850 } 851 } 852 /* XFixesSelectionWindowDestroyNotifyMask */ 853 /* XFixesSelectionClientCloseNotifyMask */ 854 else { 855 ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", 856 event.type); 857 } 858 break; 859 } 860 } 861 862 return WIN_XEVENTS_SUCCESS; 863} 864