- Timestamp:
- May 14, 2009 4:05:11 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp
r19553 r19704 55 55 #include <VBox/HostServices/VBoxClipboardSvc.h> 56 56 57 static Atom clipGetAtom(Widget widget, const char *pszName); 58 57 59 /** The different clipboard formats which we support. */ 58 60 enum CLIPFORMAT … … 77 79 } g_aFormats[] = 78 80 { 81 { "INVALID", INVALID, 0 }, 79 82 { "UTF8_STRING", UTF8, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT }, 80 83 { "text/plain;charset=UTF-8", UTF8, … … 88 91 }; 89 92 93 typedef unsigned CLIPX11FORMAT; 94 95 enum 96 { 97 NIL_CLIPX11FORMAT = 0, 98 MAX_CLIP_X11_FORMATS = RT_ELEMENTS(g_aFormats) 99 }; 100 101 /** Return the atom corresponding to a supported X11 format. 102 * @param widget a valid Xt widget 103 */ 104 static Atom clipAtomForX11Format(Widget widget, CLIPX11FORMAT format) 105 { 106 return clipGetAtom(widget, g_aFormats[format].pcszAtom); 107 } 108 109 /** Return the CLIPFORMAT corresponding to a supported X11 format. */ 110 static CLIPFORMAT clipRealFormatForX11Format(CLIPX11FORMAT format) 111 { 112 return g_aFormats[format].enmFormat; 113 } 114 115 /** Return the atom corresponding to a supported X11 format. */ 116 static uint32_t clipVBoxFormatForX11Format(CLIPX11FORMAT format) 117 { 118 return g_aFormats[format].u32VBoxFormat; 119 } 120 121 /** Lookup the X11 format matching a given X11 atom. 122 * @returns the format on success, NIL_CLIPX11FORMAT on failure 123 * @param widget a valid Xt widget 124 */ 125 static CLIPX11FORMAT clipFindX11FormatByAtom(Widget widget, Atom atomFormat) 126 { 127 for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i) 128 if (clipAtomForX11Format(widget, i) == atomFormat) 129 return i; 130 return NIL_CLIPX11FORMAT; 131 } 132 133 /** 134 * Enumerates supported X11 clipboard formats corresponding to a given VBox 135 * format. 136 * @returns the next matching X11 format in the list, or NIL_CLIPX11FORMAT if 137 * there are no more 138 * @param lastFormat The value returned from the last call of this function. 139 * Use NIL_CLIPX11FORMAT to start the enumeration. 140 */ 141 static CLIPX11FORMAT clipNextX11Format(uint32_t u32VBoxFormat, 142 CLIPX11FORMAT lastFormat) 143 { 144 for (unsigned i = lastFormat + 1; i < RT_ELEMENTS(g_aFormats); ++i) 145 if (clipVBoxFormatForX11Format(i) == u32VBoxFormat) 146 return i; 147 return NIL_CLIPX11FORMAT; 148 } 149 90 150 /** Global context information used by the X11 clipboard backend */ 91 151 struct _CLIPBACKEND … … 93 153 /** Opaque data structure describing the front-end. */ 94 154 VBOXCLIPBOARDCONTEXT *pFrontend; 155 /** Is an X server actually available? */ 156 bool fHaveX11; 95 157 /** The X Toolkit application context structure */ 96 158 XtAppContext appContext; … … 105 167 bool fOwnsClipboard; 106 168 107 /** What is the best text format X11 has to offer? INVALID for none. */ 108 CLIPFORMAT X11TextFormat; 109 /** Atom corresponding to the X11 text format */ 110 Atom atomX11TextFormat; 111 /** What is the best bitmap format X11 has to offer? INVALID for none. 112 */ 113 CLIPFORMAT X11BitmapFormat; 114 /** Atom corresponding to the X11 Bitmap format */ 115 Atom atomX11BitmapFormat; 169 /** The best text format X11 has to offer, as an index into the formats 170 * table */ 171 CLIPX11FORMAT X11TextFormat; 172 /** The best bitmap format X11 has to offer, as an index into the formats 173 * table */ 174 CLIPX11FORMAT X11BitmapFormat; 116 175 /** What formats does VBox have on offer? */ 117 176 uint32_t vboxFormats; … … 220 279 } 221 280 222 /* Are we actually connected to the X server? */ 223 static bool g_fHaveX11; 281 /** 282 * Send a message to VBox that new data is available to prevent the other 283 * side of the shared clipboard from caching the data we send to it. We need 284 * to do this because we can't always tell ourselves when the clipboard 285 * contents change on our side. 286 */ 287 static void clipInvalidateVBoxCache(CLIPBACKEND *pCtx) 288 { 289 pCtx->notifyVBox = true; 290 } 291 292 /** 293 * Forget any information about valid data in the X11 clipboard. To be used 294 * when the X11 clipboard contents go away, or if an error occurs accessing 295 * them. 296 */ 297 static void clipInvalidateX11Contents(CLIPBACKEND *pCtx) 298 { 299 pCtx->X11TextFormat = 0; 300 pCtx->X11BitmapFormat = 0; 301 } 224 302 225 303 /** … … 443 521 /** The buffer to write X11 clipboard data to (valid during a request 444 522 * for the clipboard contents) */ 445 void * pv;523 void *mBuffer; 446 524 /** The size of the buffer to write X11 clipboard data to (valid during 447 525 * a request for the clipboard contents) */ 448 unsigned cb;526 unsigned mSize; 449 527 /** The size of the X11 clipboard data written to the buffer (valid 450 528 * during a request for the clipboard contents) */ 451 uint32_t * pcbActual;529 uint32_t *mActual; 452 530 /** The format VBox would like the data in */ 453 uint32_t format; 531 uint32_t mFormat; 532 /** The text format we requested from X11 if we requested text */ 533 CLIPX11FORMAT mTextFormat; 454 534 /** Return code for the request processing code */ 455 int rc;535 int mRC; 456 536 /** Semaphore which is signalled when the request is completed */ 457 RTSEMEVENT finished;537 RTSEMEVENT mSem; 458 538 /** The clipboard context this request is associated with */ 459 CLIPBACKEND * pCtx;539 CLIPBACKEND *mCtx; 460 540 }; 461 541 … … 474 554 { 475 555 CLIPX11CLIPBOARDREQ *pReq = (CLIPX11CLIPBOARDREQ *) pClientData; 476 LogFlowFunc(("pReq->pv=%p, pReq->cb=%u, pReq->format=%02X, pReq->pCtx=%p\n", 477 pReq->pv, pReq->cb, pReq->format, pReq->pCtx)); 478 AssertPtr(pReq->pv); /* We can't really return either... */ 479 AssertPtr(pReq->pCtx); 480 Assert(pReq->format != 0); /* sanity */ 556 LogFlowFunc(("pReq->mBuffer=%p, pReq->mSize=%u, pReq->mFormat=%02X, pReq->mTextFormat=%u, pReq->mCtx=%p\n", 557 pReq->mBuffer, pReq->mSize, pReq->mFormat, 558 pReq->mTextFormat, pReq->mCtx)); 559 AssertPtr(pReq->mBuffer); /* We can't really return either... */ 560 AssertPtr(pReq->mCtx); 561 Assert(pReq->mFormat != 0); /* sanity */ 481 562 int rc = VINF_SUCCESS; 482 CLIPBACKEND *pCtx = pReq-> pCtx;563 CLIPBACKEND *pCtx = pReq->mCtx; 483 564 unsigned cbSrc = (*pcLen) * (*piFormat) / 8; 484 565 485 if ( pCtx->fOwnsClipboard 486 /* We don't want to request data from ourselves! */ 487 || (pvSrc == NULL) 566 if (pvSrc == NULL) 488 567 /* The clipboard selection may have changed before we could get it. */ 489 )490 568 rc = VERR_NO_DATA; 491 569 else if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */ 492 570 rc = VERR_TIMEOUT; 493 else 571 else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 494 572 { 495 573 /* In which format is the clipboard data? */ 496 switch ( pCtx->X11TextFormat)574 switch (clipRealFormatForX11Format(pReq->mTextFormat)) 497 575 { 498 576 case CTEXT: 499 577 rc = clipCTextToWinTxt(widget, (unsigned char *)pvSrc, cbSrc, 500 pReq->pv, pReq->cb, pReq->pcbActual); 578 pReq->mBuffer, pReq->mSize, 579 pReq->mActual); 501 580 break; 502 581 case UTF8: … … 504 583 /* If we are given broken Utf-8, we treat it as Latin1. Is 505 584 * this acceptable? */ 506 if (RT_SUCCESS(RTStrValidateEncoding((char *)pvSrc))) 585 if (RT_SUCCESS(RTStrValidateEncodingEx((char *)pvSrc, cbSrc, 586 0))) 507 587 rc = clipUtf8ToWinTxt((const char *)pvSrc, cbSrc, 508 pReq-> pv, pReq->cb,509 pReq-> pcbActual);588 pReq->mBuffer, pReq->mSize, 589 pReq->mActual); 510 590 else 511 591 rc = clipLatin1ToWinTxt((char *) pvSrc, cbSrc, 512 pReq-> pv, pReq->cb,513 pReq-> pcbActual);592 pReq->mBuffer, pReq->mSize, 593 pReq->mActual); 514 594 break; 515 595 } … … 518 598 } 519 599 } 600 else 601 rc = VERR_NOT_IMPLEMENTED; 520 602 if (RT_SUCCESS(rc)) 521 603 /* The other end may cache the data, so invalidate it again. */ 522 pCtx->notifyVBox = true;604 clipInvalidateVBoxCache(pCtx); 523 605 else 524 { 525 pCtx->X11TextFormat = INVALID; 526 pCtx->X11BitmapFormat = INVALID; 527 } 606 /* We failed to retrieve the X11 clipboard contents, mark them as 607 * invalid. */ 608 clipInvalidateX11Contents(pCtx); 528 609 XtFree((char *)pvSrc); 529 pReq-> rc= rc;530 RTSemEventSignal(pReq-> finished);610 pReq->mRC = rc; 611 RTSemEventSignal(pReq->mSem); 531 612 LogFlowFunc(("rc=%Rrc\n", rc)); 532 613 } … … 539 620 * poll for available targets. 540 621 */ 541 static void vboxClipboardGetTargetsFromX11(Widget, 542 XtPointer pClientData, 543 Atom * /* selection */, 544 Atom *atomType, 545 XtPointer pValue, 546 long unsigned int *pcLen, 547 int *piFormat) 622 static void clipConvertX11Targets(Widget, XtPointer pClientData, 623 Atom * /* selection */, Atom *atomType, 624 XtPointer pValue, long unsigned int *pcLen, 625 int *piFormat) 548 626 { 549 627 CLIPBACKEND *pCtx = … … 552 630 unsigned cAtoms = *pcLen; 553 631 CLIPFORMAT enmBestTarget = INVALID; 554 Atom atomBestTarget = None;632 CLIPX11FORMAT bestFormat = NIL_CLIPX11FORMAT; 555 633 556 634 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); … … 560 638 ) 561 639 { 562 pCtx->atomX11TextFormat = None; 563 pCtx->X11TextFormat = INVALID; 640 clipInvalidateX11Contents(pCtx); 564 641 return; 565 642 } … … 567 644 for (unsigned i = 0; i < cAtoms; ++i) 568 645 { 569 for (unsigned j = 0; j < RT_ELEMENTS(g_aFormats); ++j) 646 CLIPX11FORMAT format = clipFindX11FormatByAtom(pCtx->widget, 647 atomTargets[i]); 648 if (format != NIL_CLIPX11FORMAT) 570 649 { 571 Atom formatAtom = clipGetAtom(pCtx->widget, 572 g_aFormats[j].pcszAtom); 573 if (atomTargets[i] == formatAtom) 650 if (enmBestTarget < clipRealFormatForX11Format(format)) 574 651 { 575 if ( enmBestTarget < g_aFormats[j].enmFormat) 576 { 577 enmBestTarget = g_aFormats[j].enmFormat; 578 atomBestTarget = formatAtom; 579 } 580 break; 652 enmBestTarget = clipRealFormatForX11Format(format); 653 bestFormat = format; 581 654 } 582 655 } 583 656 } 584 pCtx->atomX11TextFormat = atomBestTarget;585 if ((enmBestTarget != pCtx->X11TextFormat) || (pCtx->notifyVBox == true))586 {587 uint32_t u32Formats = 0;588 pCtx->X11TextFormat = enmBestTarget;589 if (enmBestTarget != INVALID)590 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;591 VBoxX11ClipboardReportX11Formats(pCtx->pFrontend, u32 Formats);657 uint32_t u32VBoxFormat = clipVBoxFormatForX11Format(bestFormat); 658 uint32_t u32OldVBoxFormat 659 = clipVBoxFormatForX11Format(pCtx->X11TextFormat); 660 /* Notify VBox if something has changed or if a forced notification was 661 * scheduled. */ 662 if ((u32VBoxFormat != u32OldVBoxFormat) || (pCtx->notifyVBox)) 663 { 664 VBoxX11ClipboardReportX11Formats(pCtx->pFrontend, u32VBoxFormat); 592 665 pCtx->notifyVBox = false; 593 666 } 667 pCtx->X11TextFormat = bestFormat; 594 668 XtFree(reinterpret_cast<char *>(pValue)); 595 669 } … … 597 671 enum { TIMER_FREQ = 200 /* ms */ }; 598 672 599 static void vboxClipboardPollX11ForTargets(XtPointer pUserData,600 673 static void clipPollX11CBFormats(XtPointer pUserData, 674 XtIntervalId * /* hTimerId */); 601 675 static void clipSchedulePoller(CLIPBACKEND *pCtx, 602 676 XtTimerCallbackProc proc); … … 618 692 * available. 619 693 */ 620 void vboxClipboardPollX11ForTargets(XtPointer pUserData, 621 XtIntervalId * /* hTimerId */) 622 { 623 CLIPBACKEND *pCtx = 624 reinterpret_cast<CLIPBACKEND *>(pUserData); 694 void clipPollX11CBFormats(XtPointer pUserData, XtIntervalId * /* hTimerId */) 695 { 696 CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData; 625 697 Log3 (("%s: called\n", __PRETTY_FUNCTION__)); 626 698 /* Get the current clipboard contents if we don't own it ourselves */ … … 629 701 Log3 (("%s: requesting the targets that the host clipboard offers\n", 630 702 __PRETTY_FUNCTION__)); 631 XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), 703 XtGetSelectionValue(pCtx->widget, 704 clipGetAtom(pCtx->widget, "CLIPBOARD"), 632 705 clipGetAtom(pCtx->widget, "TARGETS"), 633 vboxClipboardGetTargetsFromX11, pCtx,706 clipConvertX11Targets, pCtx, 634 707 CurrentTime); 635 708 } 636 709 /* Re-arm our timer */ 637 clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets);710 clipSchedulePoller(pCtx, clipPollX11CBFormats); 638 711 } 639 712 … … 643 716 * @note X11 backend code. 644 717 */ 645 static int vboxClipboardThread(RTTHREAD self, void *pvUser)718 static int clipEventThread(RTTHREAD self, void *pvUser) 646 719 { 647 720 LogRel(("Shared clipboard: starting host clipboard thread\n")); 648 721 649 CLIPBACKEND *pCtx = 650 reinterpret_cast<CLIPBACKEND *>(pvUser); 722 CLIPBACKEND *pCtx = (CLIPBACKEND *)pvUser; 651 723 while (XtAppGetExitFlag(pCtx->appContext) == FALSE) 652 724 XtAppProcessEvent(pCtx->appContext, XtIMAll); … … 659 731 * @note X11 backend code. 660 732 */ 661 static void vboxClipboardUninitX11(CLIPBACKEND *pCtx)733 static void clipUninit(CLIPBACKEND *pCtx) 662 734 { 663 735 AssertPtrReturnVoid(pCtx); … … 683 755 /** Worker function for stopping the clipboard which runs on the event 684 756 * thread. */ 685 static void vboxClipboardStopWorker(XtPointer pUserData, int * /* source */,686 XtInputId * /* id */)757 static void clipStopEventThreadWorker(XtPointer pUserData, int * /* source */, 758 XtInputId * /* id */) 687 759 { 688 760 … … 697 769 XtAppSetExitFlag(pCtx->appContext); 698 770 pCtx->fOwnsClipboard = false; 699 pCtx->X11TextFormat = INVALID; 700 pCtx->X11BitmapFormat = INVALID; 771 clipInvalidateX11Contents(pCtx); 701 772 } 702 773 … … 704 775 * @note X11 backend code. 705 776 */ 706 static int vboxClipboardInitX11(CLIPBACKEND *pCtx)777 static int clipInit(CLIPBACKEND *pCtx) 707 778 { 708 779 /* Create a window and make it a clipboard viewer. */ … … 714 785 /* Make sure we are thread safe */ 715 786 XtToolkitThreadInitialize(); 716 /* Set up the Clipbard application context and main window. We call all these functions717 directly instead of calling XtOpenApplication() so that we can fail gracefully if we718 787 /* Set up the Clipbard application context and main window. We call all 788 * these functions directly instead of calling XtOpenApplication() so 789 * that we can fail gracefully if we can't get an X11 display. */ 719 790 XtToolkitInitialize(); 720 791 pCtx->appContext = XtCreateApplicationContext(); … … 727 798 if (RT_SUCCESS(rc)) 728 799 { 729 pCtx->widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay, 730 XtNwidth, 1, XtNheight, 1, NULL); 800 pCtx->widget = XtVaAppCreateShell(0, "VBoxClipboard", 801 applicationShellWidgetClass, 802 pDisplay, XtNwidth, 1, XtNheight, 803 1, NULL); 731 804 if (NULL == pCtx->widget) 732 805 { … … 742 815 XtRealizeWidget(pCtx->widget); 743 816 /* Set up a timer to poll the host clipboard */ 744 clipSchedulePoller(pCtx, vboxClipboardPollX11ForTargets);817 clipSchedulePoller(pCtx, clipPollX11CBFormats); 745 818 } 746 819 /* Create the pipes */ … … 752 825 if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead, 753 826 (XtPointer) XtInputReadMask, 754 vboxClipboardStopWorker, (XtPointer) pCtx))827 clipStopEventThreadWorker, (XtPointer) pCtx)) 755 828 rc = VERR_NO_MEMORY; /* What failure means is not doc'ed. */ 756 829 } … … 758 831 rc = RTErrConvertFromErrno(errno); 759 832 if (RT_FAILURE(rc)) 760 vboxClipboardUninitX11(pCtx);833 clipUninit(pCtx); 761 834 return rc; 762 835 } … … 766 839 * @note X11 backend code 767 840 */ 768 CLIPBACKEND *VBoxX11ClipboardConstructX11 769 (VBOXCLIPBOARDCONTEXT *pFrontend) 841 CLIPBACKEND *VBoxX11ClipboardConstructX11(VBOXCLIPBOARDCONTEXT *pFrontend) 770 842 { 771 843 int rc; … … 782 854 */ 783 855 LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n")); 784 g_fHaveX11 = false;856 pCtx->fHaveX11 = false; 785 857 return pCtx; 786 858 } 787 859 788 g_fHaveX11 = true;860 pCtx->fHaveX11 = true; 789 861 790 862 LogRel(("Initializing X11 clipboard backend\n")); … … 803 875 * Immediately return if we are not connected to the host X server. 804 876 */ 805 if (! g_fHaveX11)877 if (!pCtx->fHaveX11) 806 878 return; 807 879 … … 822 894 * Immediately return if we are not connected to the host X server. 823 895 */ 824 if (! g_fHaveX11)896 if (!pCtx->fHaveX11) 825 897 return VINF_SUCCESS; 826 898 827 rc = vboxClipboardInitX11(pCtx);899 rc = clipInit(pCtx); 828 900 #ifndef TESTCASE 829 901 if (RT_SUCCESS(rc)) 830 902 { 831 rc = RTThreadCreate(&pCtx->thread, vboxClipboardThread, pCtx, 0,903 rc = RTThreadCreate(&pCtx->thread, clipEventThread, pCtx, 0, 832 904 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP"); 833 905 if (RT_FAILURE(rc)) … … 838 910 { 839 911 pCtx->fOwnsClipboard = false; 840 pCtx->notifyVBox = true;912 clipInvalidateVBoxCache(pCtx); 841 913 } 842 914 return rc; … … 863 935 * Immediately return if we are not connected to the host X server. 864 936 */ 865 if (! g_fHaveX11)937 if (!pCtx->fHaveX11) 866 938 return VINF_SUCCESS; 867 939 … … 879 951 else 880 952 LogRelFunc(("rc=%Rrc\n", rc)); 881 vboxClipboardUninitX11(pCtx);953 clipUninit(pCtx); 882 954 LogFlowFunc(("returning %Rrc.\n", rc)); 883 955 return rc; … … 899 971 * @note X11 backend code, called by the XtOwnSelection callback. 900 972 */ 901 static Boolean vboxClipboardConvertTargetsForX11(CLIPBACKEND 902 *pCtx, 903 Atom *atomTypeReturn, 904 XtPointer *pValReturn, 905 unsigned long *pcLenReturn, 906 int *piFormatReturn) 907 { 908 unsigned uListSize = RT_ELEMENTS(g_aFormats); 909 Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom))); 973 static Boolean clipCreateX11Targets(CLIPBACKEND *pCtx, Atom *atomTypeReturn, 974 XtPointer *pValReturn, 975 unsigned long *pcLenReturn, 976 int *piFormatReturn) 977 { 978 Atom *atomTargets = (Atom *)XtMalloc( (MAX_CLIP_X11_FORMATS + 3) 979 * sizeof(Atom)); 910 980 unsigned cTargets = 0; 911 912 981 LogFlowFunc (("called\n")); 913 for (unsigned i = 0; i < uListSize; ++i) 914 { 915 if ( (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 916 && ( g_aFormats[i].u32VBoxFormat 917 == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)) 982 CLIPX11FORMAT format = NIL_CLIPX11FORMAT; 983 do 984 { 985 format = clipNextX11Format(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 986 format); 987 if (format != NIL_CLIPX11FORMAT) 918 988 { 919 atomTargets[cTargets] = clip GetAtom(pCtx->widget,920 g_aFormats[i].pcszAtom);989 atomTargets[cTargets] = clipAtomForX11Format(pCtx->widget, 990 format); 921 991 ++cTargets; 922 992 } 923 } 993 } while (format != NIL_CLIPX11FORMAT); 994 /* We always offer these */ 924 995 atomTargets[cTargets] = clipGetAtom(pCtx->widget, "TARGETS"); 925 996 atomTargets[cTargets + 1] = clipGetAtom(pCtx->widget, "MULTIPLE"); 926 997 atomTargets[cTargets + 2] = clipGetAtom(pCtx->widget, "TIMESTAMP"); 927 998 *atomTypeReturn = XA_ATOM; 928 *pValReturn = reinterpret_cast<XtPointer>(atomTargets);999 *pValReturn = (XtPointer)atomTargets; 929 1000 *pcLenReturn = cTargets + 3; 930 1001 *piFormatReturn = 32; … … 941 1012 * @todo any ideas about how to do this better are welcome. 942 1013 */ 943 static int vboxClipboardReadVBoxData (CLIPBACKEND *pCtx, 944 uint32_t u32Format, void **ppv, 945 uint32_t *pcb) 1014 static int clipReadVBoxClipboard(CLIPBACKEND *pCtx, uint32_t u32Format, 1015 void **ppv, uint32_t *pcb) 946 1016 { 947 1017 int rc = VINF_SUCCESS; … … 971 1041 } 972 1042 1043 973 1044 /** 974 * Satisfy a request from X11 to convert the clipboard text to Utf8. We 975 * return non-zero terminated text. 976 * @todo that works, but it is bad. Change it to return zero-terminated 977 * text. 1045 * Convert text from Windows format (UCS-2 with CRLF line endings) to standard 1046 * Utf-8. 1047 * 1048 * @returns iprt status code 1049 * 1050 * @param pwszSrc the text to be converted 1051 * @param cbSrc the length of @a pwszSrc in bytes 1052 * @param pszBuf where to write the converted string 1053 * @param cbBuf the size of the buffer pointed to by @a pszBuf 1054 * @param pcbActual where to store the size of the converted string. 1055 * optional. 1056 */ 1057 static int clipWinTxtToUtf8(PRTUTF16 pwszSrc, size_t cbSrc, char *pszBuf, 1058 size_t cbBuf, size_t *pcbActual) 1059 { 1060 PRTUTF16 pwszTmp = NULL; 1061 size_t cwSrc = cbSrc / 2, cwTmp = 0, cbDest = 0; 1062 int rc = VINF_SUCCESS; 1063 1064 LogFlowFunc (("pwszSrc=%.*ls, cbSrc=%u\n", cbSrc, pwszSrc, cbSrc)); 1065 /* How long will the converted text be? */ 1066 AssertPtr(pwszSrc); 1067 AssertPtr(pszBuf); 1068 rc = vboxClipboardUtf16GetLinSize(pwszSrc, cwSrc, &cwTmp); 1069 if (RT_SUCCESS(rc) && cwTmp == 0) 1070 rc = VERR_NO_DATA; 1071 if (RT_SUCCESS(rc)) 1072 pwszTmp = (PRTUTF16)RTMemAlloc(cwTmp * 2); 1073 if (!pwszTmp) 1074 rc = VERR_NO_MEMORY; 1075 /* Convert the text. */ 1076 if (RT_SUCCESS(rc)) 1077 rc = vboxClipboardUtf16WinToLin(pwszSrc, cwSrc, pwszTmp, cwTmp); 1078 if (RT_SUCCESS(rc)) 1079 /* Convert the Utf16 string to Utf8. */ 1080 rc = RTUtf16ToUtf8Ex(pwszTmp + 1, cwTmp - 1, &pszBuf, cbBuf, 1081 &cbDest); 1082 RTMemFree(reinterpret_cast<void *>(pwszTmp)); 1083 if (pcbActual) 1084 *pcbActual = cbDest + 1; 1085 LogFlowFunc(("returning %Rrc\n", rc)); 1086 if (RT_SUCCESS(rc)) 1087 LogFlowFunc (("converted string is %.*s. Returning.\n", cbDest, 1088 pszBuf)); 1089 return rc; 1090 } 1091 1092 /** 1093 * Satisfy a request from X11 to convert the clipboard text to 1094 * COMPOUND_TEXT. We return null-terminated text, but can cope with non-null- 1095 * terminated input. 978 1096 * 979 1097 * @returns true if we successfully convert the data to the format 980 1098 * requested, false otherwise. 981 1099 * 982 * @param atomTypeReturn Where to store the atom for the type of the data 1100 * @param pDisplay an X11 display structure, needed for conversions 1101 * performed by Xlib 1102 * @param pv the text to be converted (UCS-2 with Windows EOLs) 1103 * @param cb the length of the text in @cb in bytes 1104 * @param atomTypeReturn where to store the atom for the type of the data 983 1105 * we are returning 984 * @param pValReturn Where to store the pointer to the data we are1106 * @param pValReturn where to store the pointer to the data we are 985 1107 * returning. This should be to memory allocated by 986 1108 * XtMalloc, which will be freed by the Xt toolkit 987 1109 * later. 988 * @param pcLenReturn Where to store the length of the data we are1110 * @param pcLenReturn where to store the length of the data we are 989 1111 * returning 990 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the1112 * @param piFormatReturn where to store the bit width (8, 16, 32) of the 991 1113 * data we are returning 992 * @note X11 backend code, called by the callback for XtOwnSelection. 993 */ 994 static Boolean vboxClipboardConvertToUtf8ForX11(CLIPBACKEND 995 *pCtx, 996 Atom *atomTarget, 997 Atom *atomTypeReturn, 998 XtPointer *pValReturn, 999 unsigned long *pcLenReturn, 1000 int *piFormatReturn) 1001 { 1002 PRTUTF16 pu16SrcText, pu16DestText; 1003 char *pu8DestText; 1004 void *pvVBox = NULL; 1005 uint32_t cbVBox = 0; 1006 size_t cwSrcLen, cwDestLen, cbDestLen; 1007 int rc; 1008 1009 LogFlowFunc (("called\n")); 1010 /* Read the clipboard data from the guest. */ 1011 rc = vboxClipboardReadVBoxData(pCtx, 1012 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1013 &pvVBox, &cbVBox); 1014 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1015 { 1016 /* If vboxClipboardReadVBoxData fails then we may be terminating */ 1017 LogRelFunc (("vboxClipboardReadVBoxData returned %Rrc%s\n", rc, 1018 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1019 RTMemFree(pvVBox); 1020 return false; 1021 } 1022 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox); 1023 cwSrcLen = cbVBox / 2; 1024 /* How long will the converted text be? */ 1025 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen); 1026 if (RT_FAILURE(rc)) 1027 { 1028 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc)); 1029 RTMemFree(pvVBox); 1030 AssertRCReturn(rc, false); 1031 } 1032 if (cwDestLen == 0) 1033 { 1034 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n")); 1035 RTMemFree(pvVBox); 1036 return false; 1037 } 1038 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2)); 1039 if (pu16DestText == 0) 1040 { 1041 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2)); 1042 RTMemFree(pvVBox); 1043 return false; 1044 } 1045 /* Convert the text. */ 1046 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen); 1047 if (RT_FAILURE(rc)) 1048 { 1049 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc)); 1050 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1051 RTMemFree(pvVBox); 1052 return false; 1053 } 1054 /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the 1055 space is too tightly calculated. */ 1056 pu8DestText = XtMalloc(cwDestLen * 4); 1057 if (pu8DestText == 0) 1058 { 1059 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4)); 1060 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1061 RTMemFree(pvVBox); 1062 return false; 1063 } 1064 /* Convert the Utf16 string to Utf8. */ 1065 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4, 1066 &cbDestLen); 1067 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1068 if (RT_FAILURE(rc)) 1069 { 1070 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc)); 1071 XtFree(pu8DestText); 1072 RTMemFree(pvVBox); 1073 return false; 1074 } 1075 LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText)); 1076 RTMemFree(pvVBox); 1077 *atomTypeReturn = *atomTarget; 1078 *pValReturn = reinterpret_cast<XtPointer>(pu8DestText); 1079 *pcLenReturn = cbDestLen + 1; 1080 *piFormatReturn = 8; 1081 return true; 1082 } 1083 1084 /** 1085 * Satisfy a request from X11 to convert the clipboard text to 1086 * COMPOUND_TEXT. We return non-zero terminated text. 1087 * @todo that works, but it is bad. Change it to return zero-terminated 1088 * text. 1089 * 1090 * @returns true if we successfully convert the data to the format 1091 * requested, false otherwise. 1092 * 1093 * @param atomTypeReturn Where to store the atom for the type of the data 1094 * we are returning 1095 * @param pValReturn Where to store the pointer to the data we are 1096 * returning. This should be to memory allocated by 1097 * XtMalloc, which will be freed by the Xt toolkit 1098 * later. 1099 * @param pcLenReturn Where to store the length of the data we are 1100 * returning 1101 * @param piFormatReturn Where to store the bit width (8, 16, 32) of the 1102 * data we are returning 1103 * @note X11 backend code, called by the callback for XtOwnSelection. 1104 */ 1105 static Boolean vboxClipboardConvertToCTextForX11(CLIPBACKEND 1106 *pCtx, 1107 Atom *atomTypeReturn, 1108 XtPointer *pValReturn, 1109 unsigned long *pcLenReturn, 1110 int *piFormatReturn) 1111 { 1112 PRTUTF16 pu16SrcText, pu16DestText; 1113 void *pvVBox = NULL; 1114 uint32_t cbVBox = 0; 1115 char *pu8DestText = 0; 1116 size_t cwSrcLen, cwDestLen, cbDestLen; 1114 */ 1115 static Boolean clipConvertToCTextForX11(Display *pDisplay, PRTUTF16 pwszSrc, 1116 size_t cbSrc, Atom *atomTypeReturn, 1117 XtPointer *pValReturn, 1118 unsigned long *pcLenReturn, 1119 int *piFormatReturn) 1120 { 1121 char *pszTmp = NULL; 1122 size_t cbTmp = 0, cbActual = 0; 1117 1123 XTextProperty property; 1118 int rc; 1119 1120 LogFlowFunc (("called\n")); 1121 /* Read the clipboard data from the guest. */ 1122 rc = vboxClipboardReadVBoxData(pCtx, 1123 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1124 &pvVBox, &cbVBox); 1125 if ((rc != VINF_SUCCESS) || (cbVBox == 0)) 1126 { 1127 /* If vboxClipboardReadVBoxData fails then we may be terminating */ 1128 LogRelFunc (("vboxClipboardReadVBoxData returned %Rrc%s\n", rc, 1129 RT_SUCCESS(rc) ? ", cbVBox == 0" : "")); 1130 RTMemFree(pvVBox); 1131 return false; 1132 } 1133 pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox); 1134 cwSrcLen = cbVBox / 2; 1135 /* How long will the converted text be? */ 1136 rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen); 1137 if (RT_FAILURE(rc)) 1138 { 1139 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16GetLinSize returned %Rrc. Abandoning.\n", rc)); 1140 RTMemFree(pvVBox); 1141 AssertRCReturn(rc, false); 1142 } 1143 if (cwDestLen == 0) 1144 { 1145 LogFlowFunc(("received empty clipboard data from the guest, returning false.\n")); 1146 RTMemFree(pvVBox); 1147 return false; 1148 } 1149 pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2)); 1150 if (pu16DestText == 0) 1151 { 1152 LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2)); 1153 RTMemFree(pvVBox); 1154 return false; 1155 } 1156 /* Convert the text. */ 1157 rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen); 1158 if (RT_FAILURE(rc)) 1159 { 1160 LogRelFunc (("clipboard conversion failed. vboxClipboardUtf16WinToLin() returned %Rrc. Abandoning.\n", rc)); 1161 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1162 RTMemFree(pvVBox); 1163 return false; 1164 } 1165 /* Convert the Utf16 string to Utf8. */ 1166 rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, 0, &cbDestLen); 1167 RTMemFree(reinterpret_cast<void *>(pu16DestText)); 1168 if (RT_FAILURE(rc)) 1169 { 1170 LogRelFunc (("clipboard conversion failed. RTUtf16ToUtf8Ex() returned %Rrc. Abandoning.\n", rc)); 1171 RTMemFree(pvVBox); 1172 return false; 1173 } 1124 int rc = VINF_SUCCESS, xrc = 0; 1125 1126 /* This may slightly overestimate the space needed. */ 1127 rc = RTUtf16CalcUtf8LenEx(pwszSrc, cbSrc / 2, &cbTmp); 1128 ++cbTmp; /* Null terminator */ 1129 if (RT_SUCCESS(rc)) 1130 { 1131 pszTmp = (char *)RTMemAlloc(cbTmp); 1132 if (!pszTmp) 1133 rc = VERR_NO_MEMORY; 1134 } 1135 if (RT_SUCCESS(rc)) 1136 rc = clipWinTxtToUtf8(pwszSrc, cbSrc, pszTmp, cbTmp + 1, 1137 &cbActual); 1174 1138 /* And finally (!) convert the Utf8 text to compound text. */ 1175 #ifdef RT_OS_SOLARIS 1176 rc = XmbTextListToTextProperty(XtDisplay(pCtx->widget), &pu8DestText, 1, 1177 XCompoundTextStyle, &property); 1139 #ifdef X_HAVE_UTF8_STRING 1140 if (RT_SUCCESS(rc)) 1141 xrc = Xutf8TextListToTextProperty(pDisplay, &pszTmp, 1, 1142 XCompoundTextStyle, &property); 1178 1143 #else 1179 rc = Xutf8TextListToTextProperty(XtDisplay(pCtx->widget), &pu8DestText, 1, 1180 XCompoundTextStyle, &property); 1144 if (RT_SUCCESS(rc)) 1145 xrc = XmbTextListToTextProperty(pDisplay, &pszTmp, 1, 1146 XCompoundTextStyle, &property); 1181 1147 #endif 1182 RTMemFree(pu8DestText); 1183 if (rc < 0) 1184 { 1185 const char *pcReason; 1186 switch(rc) 1187 { 1188 case XNoMemory: 1189 pcReason = "out of memory"; 1190 break; 1191 case XLocaleNotSupported: 1192 pcReason = "locale (Utf8) not supported"; 1193 break; 1194 case XConverterNotFound: 1195 pcReason = "converter not found"; 1196 break; 1197 default: 1198 pcReason = "unknown error"; 1199 } 1200 LogRelFunc (("Xutf8TextListToTextProperty failed. Reason: %s\n", 1201 pcReason)); 1202 RTMemFree(pvVBox); 1203 return false; 1204 } 1205 LogFlowFunc (("converted string is %s. Returning.\n", property.value)); 1206 RTMemFree(pvVBox); 1148 if (RT_SUCCESS(rc) && xrc < 0) 1149 rc = ( xrc == XNoMemory ? VERR_NO_MEMORY 1150 : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED 1151 : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED 1152 : VERR_UNRESOLVED_ERROR); 1153 RTMemFree(pszTmp); 1207 1154 *atomTypeReturn = property.encoding; 1208 1155 *pValReturn = reinterpret_cast<XtPointer>(property.value); 1209 1156 *pcLenReturn = property.nitems + 1; 1210 1157 *piFormatReturn = property.format; 1211 return true; 1158 LogFlowFunc(("returning, internal rc=%Rrc\n")); 1159 if (RT_SUCCESS(rc)) 1160 LogFlowFunc (("converted string is %s\n", property.value)); 1161 return RT_SUCCESS(rc); 1212 1162 } 1213 1163 … … 1225 1175 CLIPFORMAT enmFormat = INVALID; 1226 1176 CLIPBACKEND *pCtx = clipLookupContext(widget); 1177 int rc = VINF_SUCCESS; 1178 bool retval = false; 1227 1179 1228 1180 LogFlowFunc(("\n")); … … 1256 1208 { 1257 1209 case TARGETS: 1258 return vboxClipboardConvertTargetsForX11(pCtx, atomTypeReturn, 1259 pValReturn, pcLenReturn, 1260 piFormatReturn); 1210 return clipCreateX11Targets(pCtx, atomTypeReturn, pValReturn, 1211 pcLenReturn, piFormatReturn); 1261 1212 case UTF8: 1262 return vboxClipboardConvertToUtf8ForX11(pCtx, atomTarget, 1263 atomTypeReturn, 1264 pValReturn, pcLenReturn, 1265 piFormatReturn); 1213 { 1214 /* Read the clipboard data from the guest. */ 1215 void *pv = NULL; 1216 uint32_t cb = 0; 1217 rc = clipReadVBoxClipboard(pCtx, 1218 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1219 &pv, &cb); 1220 if (RT_SUCCESS(rc) && (cb != 0)) 1221 { 1222 /* This may slightly overestimate the space needed. */ 1223 size_t cbDest = 0; 1224 rc = RTUtf16CalcUtf8LenEx((PRTUTF16)pv, cb / 2, &cbDest); 1225 if (RT_SUCCESS(rc)) 1226 { 1227 char *pszDest = (char *)XtMalloc(cbDest + 1); 1228 size_t cbActual = 0; 1229 if (pszDest) 1230 rc = clipWinTxtToUtf8((PRTUTF16)pv, cb, pszDest, 1231 cbDest + 1, &cbActual); 1232 if (RT_SUCCESS(rc)) 1233 { 1234 *atomTypeReturn = *atomTarget; 1235 *pValReturn = (XtPointer)pszDest; 1236 *pcLenReturn = cbActual; 1237 *piFormatReturn = 8; 1238 retval = true; 1239 } 1240 } 1241 } 1242 RTMemFree(pv); 1243 break; 1244 } 1266 1245 case CTEXT: 1267 return vboxClipboardConvertToCTextForX11(pCtx, atomTypeReturn, 1268 pValReturn, pcLenReturn, 1269 piFormatReturn); 1246 { 1247 /* Read the clipboard data from the guest. */ 1248 void *pv = NULL; 1249 uint32_t cb = 0; 1250 rc = clipReadVBoxClipboard(pCtx, 1251 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, 1252 &pv, &cb); 1253 if (RT_SUCCESS(rc) && (cb != 0)) 1254 retval = clipConvertToCTextForX11(XtDisplay(pCtx->widget), 1255 (PRTUTF16)pv, cb, 1256 atomTypeReturn, pValReturn, 1257 pcLenReturn, piFormatReturn); 1258 RTMemFree(pv); 1259 break; 1260 } 1270 1261 default: 1271 1262 LogFunc (("bad format\n")); 1272 1263 return false; 1273 1264 } 1265 return retval; 1274 1266 } 1275 1267 … … 1285 1277 LogFlowFunc (("called, giving X11 clipboard ownership\n")); 1286 1278 /* These should be set to the right values as soon as we start polling */ 1287 pCtx->X11TextFormat = INVALID; 1288 pCtx->X11BitmapFormat = INVALID; 1279 clipInvalidateX11Contents(pCtx); 1289 1280 pCtx->fOwnsClipboard = false; 1290 pCtx->notifyVBox = true;1281 clipInvalidateVBoxCache(pCtx); 1291 1282 } 1292 1283 … … 1354 1345 /* VBox thinks it currently owns the clipboard, so we must notify it 1355 1346 * as soon as we know what formats X11 has to offer. */ 1356 pCtx->notifyVBox = true;1347 clipInvalidateVBoxCache(pCtx); 1357 1348 pCtx->fOwnsClipboard = false; 1358 1349 } … … 1372 1363 * Immediately return if we are not connected to the host X server. 1373 1364 */ 1374 if (! g_fHaveX11)1365 if (!pCtx->fHaveX11) 1375 1366 return; 1376 1367 /* This must be freed by the worker callback */ … … 1391 1382 XtIntervalId * /* interval */) 1392 1383 { 1393 CLIPX11CLIPBOARDREQ *pReq uest= (CLIPX11CLIPBOARDREQ *)pUserData;1394 CLIPBACKEND *pCtx = pReq uest->pCtx;1395 LogFlowFunc ((" u32Format = %d, cb = %d\n", pRequest->format,1396 pReq uest->cb));1384 CLIPX11CLIPBOARDREQ *pReq = (CLIPX11CLIPBOARDREQ *)pUserData; 1385 CLIPBACKEND *pCtx = pReq->mCtx; 1386 LogFlowFunc (("pReq->mFormat = %02X, pReq->mSize = %d\n", pReq->mFormat, 1387 pReq->mSize)); 1397 1388 1398 1389 int rc = VINF_SUCCESS; 1399 1390 /* Set this to start with, just in case */ 1400 *pReq uest->pcbActual = 0;1391 *pReq->mActual = 0; 1401 1392 /* Do not continue if we already own the clipboard */ 1402 1393 if (pCtx->fOwnsClipboard == true) … … 1407 1398 * VBox wants to read data in the given format. 1408 1399 */ 1409 if (pReq uest->format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)1400 if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1410 1401 { 1411 if (pCtx->atomX11TextFormat == None) 1402 pReq->mTextFormat = pCtx->X11TextFormat; 1403 if (pReq->mTextFormat == 0) 1412 1404 /* VBox thinks we have data and we don't */ 1413 1405 rc = VERR_NO_DATA; … … 1416 1408 * owner */ 1417 1409 XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), 1418 pCtx->atomX11TextFormat, 1410 clipGetAtom(pCtx->widget, 1411 g_aFormats[pCtx->X11TextFormat].pcszAtom), 1419 1412 clipConvertX11CB, 1420 reinterpret_cast<XtPointer>(pReq uest),1413 reinterpret_cast<XtPointer>(pReq), 1421 1414 CurrentTime); 1422 1415 } … … 1426 1419 if (RT_FAILURE(rc)) 1427 1420 { 1428 pReq uest->rc= rc;1421 pReq->mRC = rc; 1429 1422 /* The clipboard callback was never scheduled, so we must signal 1430 1423 * that the request processing is finished ourselves. */ 1431 RTSemEventSignal(pReq uest->finished);1424 RTSemEventSignal(pReq->mSem); 1432 1425 } 1433 1426 LogFlowFunc(("status %Rrc\n", rc)); … … 1455 1448 * Immediately return if we are not connected to the host X server. 1456 1449 */ 1457 if (! g_fHaveX11)1450 if (!pCtx->fHaveX11) 1458 1451 return VINF_SUCCESS; 1459 1452 1460 CLIPX11CLIPBOARDREQ req uest;1461 req uest.rc= VERR_WRONG_ORDER;1462 req uest.pv= pv;1463 req uest.cb= cb;1464 req uest.pcbActual = pcbActual;1465 req uest.format = u32Format;1466 req uest.pCtx = pCtx;1453 CLIPX11CLIPBOARDREQ req = { 0 }; 1454 req.mRC = VERR_WRONG_ORDER; 1455 req.mBuffer = pv; 1456 req.mSize = cb; 1457 req.mActual = pcbActual; 1458 req.mFormat = u32Format; 1459 req.mCtx = pCtx; 1467 1460 /* The worker function will signal this when it has finished. */ 1468 int rc = RTSemEventCreate(&req uest.finished);1461 int rc = RTSemEventCreate(&req.mSem); 1469 1462 if (RT_SUCCESS(rc)) 1470 1463 { 1471 1464 /* We use this to schedule a worker function on the event thread. */ 1472 1465 clipSchedule(pCtx->appContext, vboxClipboardReadX11Worker, 1473 (XtPointer) &req uest);1474 rc = RTSemEventWait(req uest.finished, RT_INDEFINITE_WAIT);1466 (XtPointer) &req); 1467 rc = RTSemEventWait(req.mSem, RT_INDEFINITE_WAIT); 1475 1468 if (RT_SUCCESS(rc)) 1476 rc = req uest.rc;1477 RTSemEventDestroy(req uest.finished);1469 rc = req.mRC; 1470 RTSemEventDestroy(req.mSem); 1478 1471 } 1479 1472 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.