VirtualBox

Ignore:
Timestamp:
May 15, 2009 10:41:36 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
47375
Message:

GuestHost/SharedClipboard/x11: more cleanups

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp

    r19704 r19754  
    139139 *                    Use NIL_CLIPX11FORMAT to start the enumeration.
    140140 */
    141 static CLIPX11FORMAT clipNextX11Format(uint32_t u32VBoxFormat,
    142                                        CLIPX11FORMAT lastFormat)
     141static CLIPX11FORMAT clipEnumX11Formats(uint32_t u32VBoxFormats,
     142                                        CLIPX11FORMAT lastFormat)
    143143{
    144144    for (unsigned i = lastFormat + 1; i < RT_ELEMENTS(g_aFormats); ++i)
    145         if (clipVBoxFormatForX11Format(i) == u32VBoxFormat)
     145        if (u32VBoxFormats & clipVBoxFormatForX11Format(i))
    146146            return i;
    147147    return NIL_CLIPX11FORMAT;
     
    279279}
    280280
    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;
     281static void clipQueueToEventThread(XtAppContext app_context,
     282                                   XtTimerCallbackProc proc,
     283                                   XtPointer client_data);
     284#ifndef TESTCASE
     285void clipQueueToEventThread(XtAppContext app_context,
     286                            XtTimerCallbackProc proc,
     287                            XtPointer client_data)
     288{
     289    XtAppAddTimeOut(app_context, 0, proc, client_data);
     290}
     291#endif
     292
     293/**
     294 * Report the formats currently supported by the X11 clipboard to VBox.
     295 */
     296static void clipReportFormatsToVBox(CLIPBACKEND *pCtx)
     297{
     298    uint32_t u32VBoxFormats = clipVBoxFormatForX11Format(pCtx->X11TextFormat);
     299    VBoxX11ClipboardReportX11Formats(pCtx->pFrontend, u32VBoxFormats);
     300}
     301
     302/**
     303 * Forget which formats were previously in the X11 clipboard.  Should be
     304 * called when we grab the clipboard, so that when we lose it again the poller
     305 * will notify us when new formats become available. */
     306static void clipResetX11Formats(CLIPBACKEND *pCtx)
     307{
     308    pCtx->X11TextFormat = INVALID;
     309    pCtx->X11BitmapFormat = INVALID;
     310}
     311
     312/** Tell VBox that X11 currently has nothing in its clipboard. */
     313static void clipReportEmptyX11CB(CLIPBACKEND *pCtx)
     314{
     315    clipResetX11Formats(pCtx);
     316    clipReportFormatsToVBox(pCtx);
     317}
     318
     319/**
     320 * Go through an array of X11 clipboard targets to see if we can support any
     321 * of them and if relevant to choose the ones we prefer (e.g. we like Utf8
     322 * better than compound text).
     323 * @param  pCtx      the clipboard backend context structure
     324 * @param  pTargets  the list of targets
     325 * @param  cTargets  the size of the list in @a pTargets
     326 * @param  pChanged  This is set to true if the formats available have changed
     327 *                   from VBox's point of view, and to false otherwise.
     328 *                   Somehow this didn't feel right as a return value.
     329 */
     330void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, Atom *pTargets,
     331                               size_t cTargets, bool *pChanged)
     332{
     333    bool changed = false;
     334    CLIPX11FORMAT bestTextFormat = NIL_CLIPX11FORMAT;
     335    AssertPtrReturnVoid(pCtx);
     336    AssertPtrReturnVoid(pTargets);
     337    for (unsigned i = 0; i < cTargets; ++i)
     338    {
     339        CLIPFORMAT enmBestTextTarget = INVALID;
     340        CLIPX11FORMAT format = clipFindX11FormatByAtom(pCtx->widget,
     341                                                       pTargets[i]);
     342        if (format != NIL_CLIPX11FORMAT)
     343        {
     344            if (   (clipVBoxFormatForX11Format(format)
     345                            == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     346                    && enmBestTextTarget < clipRealFormatForX11Format(format))
     347            {
     348                enmBestTextTarget = clipRealFormatForX11Format(format);
     349                bestTextFormat = format;
     350            }
     351        }
     352    }
     353    if (pCtx->X11TextFormat != bestTextFormat)
     354    {
     355        changed = true;
     356        pCtx->X11TextFormat = bestTextFormat;
     357    }
     358    pCtx->X11BitmapFormat = INVALID;  /* not yet supported */
     359    if (pChanged)
     360        *pChanged = changed;
     361}
     362
     363/**
     364 * Notify the VBox clipboard about available data formats, based on the
     365 * "targets" information obtained from the X11 clipboard.
     366 * @note  callback for XtGetSelectionValue, called on a polling loop
     367 */
     368static void clipConvertX11Targets(Widget, XtPointer pClientData,
     369                                  Atom * /* selection */, Atom *atomType,
     370                                  XtPointer pValue, long unsigned int *pcLen,
     371                                  int *piFormat)
     372{
     373    CLIPBACKEND *pCtx =
     374            reinterpret_cast<CLIPBACKEND *>(pClientData);
     375    Atom *pTargets = reinterpret_cast<Atom *>(pValue);
     376    size_t cTargets = *pcLen;
     377    bool changed = true;
     378
     379    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
     380    if (pCtx->fOwnsClipboard)
     381        /* VBox raced us and we lost.  So we don't want to report anything. */
     382        changed = false;
     383    else if (*atomType == XT_CONVERT_FAIL)  /* timeout */
     384        clipResetX11Formats(pCtx);
     385    else
     386        clipGetFormatsFromTargets(pCtx, pTargets, cTargets, &changed);
     387    if (changed)
     388        clipReportFormatsToVBox(pCtx);
     389    XtFree(reinterpret_cast<char *>(pValue));
     390}
     391
     392enum { TIMER_FREQ = 200 /* ms */ };
     393
     394static void clipPollX11CBFormats(XtPointer pUserData,
     395                                 XtIntervalId * /* hTimerId */);
     396static void clipSchedulePoller(CLIPBACKEND *pCtx,
     397                               XtTimerCallbackProc proc);
     398
     399#ifndef TESTCASE
     400void clipSchedulePoller(CLIPBACKEND *pCtx,
     401                        XtTimerCallbackProc proc)
     402{
     403    XtAppAddTimeOut(pCtx->appContext, TIMER_FREQ, proc, pCtx);
     404}
     405#endif
     406
     407/**
     408 * This timer callback is called every 200ms to check the contents of the X11
     409 * clipboard.
     410 * @note  X11 backend code, callback for XtAppAddTimeOut, recursively
     411 *        re-armed.
     412 * @todo  Use the XFIXES extension to check for new clipboard data when
     413 *        available.
     414 */
     415void clipPollX11CBFormats(XtPointer pUserData, XtIntervalId * /* hTimerId */)
     416{
     417    CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData;
     418    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
     419    /* Get the current clipboard contents if we don't own it ourselves */
     420    if (!pCtx->fOwnsClipboard)
     421    {
     422        Log3 (("%s: requesting the targets that the X11 clipboard offers\n",
     423               __PRETTY_FUNCTION__));
     424        XtGetSelectionValue(pCtx->widget,
     425                            clipGetAtom(pCtx->widget, "CLIPBOARD"),
     426                            clipGetAtom(pCtx->widget, "TARGETS"),
     427                            clipConvertX11Targets, pCtx,
     428                            CurrentTime);
     429    }
     430    /* Re-arm our timer */
     431    clipSchedulePoller(pCtx, clipPollX11CBFormats);
     432}
     433
     434#ifndef TESTCASE
     435/**
     436 * The main loop of our clipboard reader.
     437 * @note  X11 backend code.
     438 */
     439static int clipEventThread(RTTHREAD self, void *pvUser)
     440{
     441    LogRel(("Shared clipboard: starting shared clipboard thread\n"));
     442
     443    CLIPBACKEND *pCtx = (CLIPBACKEND *)pvUser;
     444    while (XtAppGetExitFlag(pCtx->appContext) == FALSE)
     445        XtAppProcessEvent(pCtx->appContext, XtIMAll);
     446    LogRel(("Shared clipboard: shared clipboard thread terminated successfully\n"));
     447    return VINF_SUCCESS;
     448}
     449#endif
     450
     451/** X11 specific uninitialisation for the shared clipboard.
     452 * @note  X11 backend code.
     453 */
     454static void clipUninit(CLIPBACKEND *pCtx)
     455{
     456    AssertPtrReturnVoid(pCtx);
     457    if (pCtx->widget)
     458    {
     459        /* Valid widget + invalid appcontext = bug.  But don't return yet. */
     460        AssertPtr(pCtx->appContext);
     461        clipUnregisterContext(pCtx);
     462        XtDestroyWidget(pCtx->widget);
     463    }
     464    pCtx->widget = NULL;
     465    if (pCtx->appContext)
     466        XtDestroyApplicationContext(pCtx->appContext);
     467    pCtx->appContext = NULL;
     468    if (pCtx->wakeupPipeRead != 0)
     469        close(pCtx->wakeupPipeRead);
     470    if (pCtx->wakeupPipeWrite != 0)
     471        close(pCtx->wakeupPipeWrite);
     472    pCtx->wakeupPipeRead = 0;
     473    pCtx->wakeupPipeWrite = 0;
     474}
     475
     476/** Worker function for stopping the clipboard which runs on the event
     477 * thread. */
     478static void clipStopEventThreadWorker(XtPointer pUserData, int * /* source */,
     479                                      XtInputId * /* id */)
     480{
     481   
     482    CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData;
     483
     484    /* This might mean that we are getting stopped twice. */
     485    Assert(pCtx->widget != NULL);
     486
     487    /* Set the termination flag to tell the Xt event loop to exit.  We
     488     * reiterate that any outstanding requests from the X11 event loop to
     489     * the VBox part *must* have returned before we do this. */
     490    XtAppSetExitFlag(pCtx->appContext);
     491}
     492
     493/** X11 specific initialisation for the shared clipboard.
     494 * @note  X11 backend code.
     495 */
     496static int clipInit(CLIPBACKEND *pCtx)
     497{
     498    /* Create a window and make it a clipboard viewer. */
     499    int cArgc = 0;
     500    char *pcArgv = 0;
     501    int rc = VINF_SUCCESS;
     502    Display *pDisplay;
     503
     504    /* Make sure we are thread safe */
     505    XtToolkitThreadInitialize();
     506    /* Set up the Clipbard application context and main window.  We call all
     507     * these functions directly instead of calling XtOpenApplication() so
     508     * that we can fail gracefully if we can't get an X11 display. */
     509    XtToolkitInitialize();
     510    pCtx->appContext = XtCreateApplicationContext();
     511    pDisplay = XtOpenDisplay(pCtx->appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);
     512    if (NULL == pDisplay)
     513    {
     514        LogRel(("Shared clipboard: failed to connect to the X11 clipboard - the window system may not be running.\n"));
     515        rc = VERR_NOT_SUPPORTED;
     516    }
     517    if (RT_SUCCESS(rc))
     518    {
     519        pCtx->widget = XtVaAppCreateShell(0, "VBoxClipboard",
     520                                          applicationShellWidgetClass,
     521                                          pDisplay, XtNwidth, 1, XtNheight,
     522                                          1, NULL);
     523        if (NULL == pCtx->widget)
     524        {
     525            LogRel(("Shared clipboard: failed to construct the X11 window for the shared clipboard manager.\n"));
     526            rc = VERR_NO_MEMORY;
     527        }
     528        else
     529            rc = clipRegisterContext(pCtx);
     530    }
     531    if (RT_SUCCESS(rc))
     532    {
     533        XtSetMappedWhenManaged(pCtx->widget, false);
     534        XtRealizeWidget(pCtx->widget);
     535        /* Set up a timer to poll the X11 clipboard */
     536        clipSchedulePoller(pCtx, clipPollX11CBFormats);
     537    }
     538    /* Create the pipes */
     539    int pipes[2];
     540    if (!pipe(pipes))
     541    {
     542        pCtx->wakeupPipeRead = pipes[0];
     543        pCtx->wakeupPipeWrite = pipes[1];
     544        if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
     545                           (XtPointer) XtInputReadMask,
     546                           clipStopEventThreadWorker, (XtPointer) pCtx))
     547            rc = VERR_NO_MEMORY;  /* What failure means is not doc'ed. */
     548    }
     549    else
     550        rc = RTErrConvertFromErrno(errno);
     551    if (RT_FAILURE(rc))
     552        clipUninit(pCtx);
     553    return rc;
     554}
     555
     556/**
     557 * Construct the X11 backend of the shared clipboard.
     558 * @note  X11 backend code
     559 */
     560CLIPBACKEND *VBoxX11ClipboardConstructX11(VBOXCLIPBOARDCONTEXT *pFrontend)
     561{
     562    int rc;
     563
     564    CLIPBACKEND *pCtx = (CLIPBACKEND *)
     565                    RTMemAllocZ(sizeof(CLIPBACKEND));
     566    if (pCtx && !RTEnvGet("DISPLAY"))
     567    {
     568        /*
     569         * If we don't find the DISPLAY environment variable we assume that
     570         * we are not connected to an X11 server. Don't actually try to do
     571         * this then, just fail silently and report success on every call.
     572         * This is important for VBoxHeadless.
     573         */
     574        LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n"));
     575        pCtx->fHaveX11 = false;
     576        return pCtx;
     577    }
     578
     579    pCtx->fHaveX11 = true;
     580
     581    LogRel(("Initializing X11 clipboard backend\n"));
     582    if (pCtx)
     583        pCtx->pFrontend = pFrontend;
     584    return pCtx;
     585}
     586
     587/**
     588 * Destruct the shared clipboard X11 backend.
     589 * @note  X11 backend code
     590 */
     591void VBoxX11ClipboardDestructX11(CLIPBACKEND *pCtx)
     592{
     593    /*
     594     * Immediately return if we are not connected to the X server.
     595     */
     596    if (!pCtx->fHaveX11)
     597        return;
     598
     599    /* We set this to NULL when the event thread exits.  It really should
     600     * have exited at this point, when we are about to unload the code from
     601     * memory. */
     602    Assert(pCtx->widget == NULL);
     603}
     604
     605/**
     606 * Announce to the X11 backend that we are ready to start.
     607 */
     608int VBoxX11ClipboardStartX11(CLIPBACKEND *pCtx)
     609{
     610    int rc = VINF_SUCCESS;
     611    LogFlowFunc(("\n"));
     612    /*
     613     * Immediately return if we are not connected to the X server.
     614     */
     615    if (!pCtx->fHaveX11)
     616        return VINF_SUCCESS;
     617
     618    rc = clipInit(pCtx);
     619#ifndef TESTCASE
     620    if (RT_SUCCESS(rc))
     621    {
     622        rc = RTThreadCreate(&pCtx->thread, clipEventThread, pCtx, 0,
     623                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
     624        if (RT_FAILURE(rc))
     625            LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));
     626    }
     627#endif
     628    if (RT_SUCCESS(rc))
     629    {
     630        pCtx->fOwnsClipboard = false;
     631        clipResetX11Formats(pCtx);
     632    }
     633    return rc;
     634}
     635
     636/** String written to the wakeup pipe. */
     637#define WAKE_UP_STRING      "WakeUp!"
     638/** Length of the string written. */
     639#define WAKE_UP_STRING_LEN  ( sizeof(WAKE_UP_STRING) - 1 )
     640
     641/**
     642 * Shut down the shared clipboard X11 backend.
     643 * @note  X11 backend code
     644 * @note  Any requests from this object to get clipboard data from VBox
     645 *        *must* have completed or aborted before we are called, as
     646 *        otherwise the X11 event loop will still be waiting for the request
     647 *        to return and will not be able to terminate.
     648 */
     649int VBoxX11ClipboardStopX11(CLIPBACKEND *pCtx)
     650{
     651    int rc, rcThread;
     652    unsigned count = 0;
     653    /*
     654     * Immediately return if we are not connected to the X server.
     655     */
     656    if (!pCtx->fHaveX11)
     657        return VINF_SUCCESS;
     658
     659    LogRelFunc(("stopping the shared clipboard X11 backend\n"));
     660    /* Write to the "stop" pipe */
     661    rc = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN);
     662    do
     663    {
     664        rc = RTThreadWait(pCtx->thread, 1000, &rcThread);
     665        ++count;
     666        Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
     667    } while ((VERR_TIMEOUT == rc) && (count < 300));
     668    if (RT_SUCCESS(rc))
     669        AssertRC(rcThread);
     670    else
     671        LogRelFunc(("rc=%Rrc\n", rc));
     672    clipUninit(pCtx);
     673    LogFlowFunc(("returning %Rrc.\n", rc));
     674    return rc;
     675}
     676
     677/**
     678 * Satisfy a request from X11 for clipboard targets supported by VBox.
     679 *
     680 * @returns iprt status code
     681 * @param  atomTypeReturn The type of the data we are returning
     682 * @param  pValReturn     A pointer to the data we are returning.  This
     683 *                        should be set to memory allocated by XtMalloc,
     684 *                        which will be freed later by the Xt toolkit.
     685 * @param  pcLenReturn    The length of the data we are returning
     686 * @param  piFormatReturn The format (8bit, 16bit, 32bit) of the data we are
     687 *                        returning
     688 * @note  X11 backend code, called by the XtOwnSelection callback.
     689 */
     690static int clipCreateX11Targets(CLIPBACKEND *pCtx, Atom *atomTypeReturn,
     691                                XtPointer *pValReturn,
     692                                unsigned long *pcLenReturn,
     693                                int *piFormatReturn)
     694{
     695    Atom *atomTargets = (Atom *)XtMalloc(  (MAX_CLIP_X11_FORMATS + 3)
     696                                         * sizeof(Atom));
     697    unsigned cTargets = 0;
     698    LogFlowFunc (("called\n"));
     699    CLIPX11FORMAT format = NIL_CLIPX11FORMAT;
     700    do
     701    {
     702        format = clipEnumX11Formats(pCtx->vboxFormats, format);
     703        if (format != NIL_CLIPX11FORMAT)
     704        {
     705            atomTargets[cTargets] = clipAtomForX11Format(pCtx->widget,
     706                                                          format);
     707            ++cTargets;
     708        }
     709    } while (format != NIL_CLIPX11FORMAT);
     710    /* We always offer these */
     711    atomTargets[cTargets] = clipGetAtom(pCtx->widget, "TARGETS");
     712    atomTargets[cTargets + 1] = clipGetAtom(pCtx->widget, "MULTIPLE");
     713    atomTargets[cTargets + 2] = clipGetAtom(pCtx->widget, "TIMESTAMP");
     714    *atomTypeReturn = XA_ATOM;
     715    *pValReturn = (XtPointer)atomTargets;
     716    *pcLenReturn = cTargets + 3;
     717    *piFormatReturn = 32;
     718    return VINF_SUCCESS;
     719}
     720
     721/** This is a wrapper around VBoxX11ClipboardReadVBoxData that will cache the
     722 * data returned.  This is unfortunately necessary, because if the other side
     723 * of the shared clipboard is also an X11 system, it may send a format
     724 * announcement message every time its clipboard is read, for reasons that
     725 * are explained elsewhere.  Unfortunately, some applications on our side
     726 * like to read the clipboard several times in short succession in different
     727 * formats.  This can fail if it collides with a format announcement message.
     728 * @todo any ideas about how to do this better are welcome.
     729 */
     730static int clipReadVBoxClipboard(CLIPBACKEND *pCtx, uint32_t u32Format,
     731                                 void **ppv, uint32_t *pcb)
     732{
     733    int rc = VINF_SUCCESS;
     734    LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx,
     735                 u32Format, ppv, pcb));
     736    if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     737    {
     738        if (pCtx->pvUnicodeCache == NULL)
     739            rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format,
     740                                              &pCtx->pvUnicodeCache,
     741                                              &pCtx->cbUnicodeCache);
     742        if (RT_SUCCESS(rc))
     743        {
     744            *ppv = RTMemDup(pCtx->pvUnicodeCache, pCtx->cbUnicodeCache);
     745            *pcb = pCtx->cbUnicodeCache;
     746            if (*ppv == NULL)
     747                rc = VERR_NO_MEMORY;
     748        }
     749    }
     750    else
     751        rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format,
     752                                          ppv, pcb);
     753    LogFlowFunc(("returning %Rrc\n", rc));
     754    if (RT_SUCCESS(rc))
     755        LogFlowFunc(("*ppv=%.*ls, *pcb=%u\n", *pcb, *ppv, *pcb));
     756    return rc;
     757}
     758
     759/**
     760 * Calculate a buffer size large enough to hold the source Windows format
     761 * text converted into Unix Utf8, including the null terminator
     762 * @returns iprt status code
     763 * @param  pwsz       the source text in UCS-2 with Windows EOLs
     764 * @param  cwc        the size in USC-2 elements of the source text, with or
     765 *                    without the terminator
     766 * @param  pcbActual  where to store the buffer size needed
     767 */
     768static int clipWinTxtBufSizeForUtf8(PRTUTF16 pwsz, size_t cwc,
     769                                    size_t *pcbActual)
     770{
     771    size_t cbRet = 0;
     772    int rc = RTUtf16CalcUtf8LenEx(pwsz, cwc, &cbRet);
     773    if (RT_SUCCESS(rc))
     774        *pcbActual = cbRet + 1;  /* null terminator */
     775    return rc;
     776}
     777
     778/**
     779 * Convert text from Windows format (UCS-2 with CRLF line endings) to standard
     780 * Utf-8.
     781 *
     782 * @returns iprt status code
     783 *
     784 * @param  pwszSrc    the text to be converted
     785 * @param  cbSrc      the length of @a pwszSrc in bytes
     786 * @param  pszBuf     where to write the converted string
     787 * @param  cbBuf      the size of the buffer pointed to by @a pszBuf
     788 * @param  pcbActual  where to store the size of the converted string.
     789 *                    optional.
     790 */
     791static int clipWinTxtToUtf8(PRTUTF16 pwszSrc, size_t cbSrc, char *pszBuf,
     792                            size_t cbBuf, size_t *pcbActual)
     793{
     794    PRTUTF16 pwszTmp = NULL;
     795    size_t cwSrc = cbSrc / 2, cwTmp = 0, cbDest = 0;
     796    int rc = VINF_SUCCESS;
     797
     798    LogFlowFunc (("pwszSrc=%.*ls, cbSrc=%u\n", cbSrc, pwszSrc, cbSrc));
     799    /* How long will the converted text be? */
     800    AssertPtr(pwszSrc);
     801    AssertPtr(pszBuf);
     802    rc = vboxClipboardUtf16GetLinSize(pwszSrc, cwSrc, &cwTmp);
     803    if (RT_SUCCESS(rc) && cwTmp == 0)
     804        rc = VERR_NO_DATA;
     805    if (RT_SUCCESS(rc))
     806        pwszTmp = (PRTUTF16)RTMemAlloc(cwTmp * 2);
     807    if (!pwszTmp)
     808        rc = VERR_NO_MEMORY;
     809    /* Convert the text. */
     810    if (RT_SUCCESS(rc))
     811        rc = vboxClipboardUtf16WinToLin(pwszSrc, cwSrc, pwszTmp, cwTmp);
     812    if (RT_SUCCESS(rc))
     813        /* Convert the Utf16 string to Utf8. */
     814        rc = RTUtf16ToUtf8Ex(pwszTmp + 1, cwTmp - 1, &pszBuf, cbBuf,
     815                             &cbDest);
     816    RTMemFree(reinterpret_cast<void *>(pwszTmp));
     817    if (pcbActual)
     818        *pcbActual = cbDest + 1;
     819    LogFlowFunc(("returning %Rrc\n", rc));
     820    if (RT_SUCCESS(rc))
     821        LogFlowFunc (("converted string is %.*s. Returning.\n", cbDest,
     822                      pszBuf));
     823    return rc;
     824}
     825
     826/**
     827 * Satisfy a request from X11 to convert the clipboard text to Utf-8.  We
     828 * return null-terminated text, but can cope with non-null-terminated input.
     829 *
     830 * @returns iprt status code
     831 * @param  pDisplay        an X11 display structure, needed for conversions
     832 *                         performed by Xlib
     833 * @param  pv              the text to be converted (UCS-2 with Windows EOLs)
     834 * @param  cb              the length of the text in @cb in bytes
     835 * @param  atomTypeReturn  where to store the atom for the type of the data
     836 *                         we are returning
     837 * @param  pValReturn      where to store the pointer to the data we are
     838 *                         returning.  This should be to memory allocated by
     839 *                         XtMalloc, which will be freed by the Xt toolkit
     840 *                         later.
     841 * @param  pcLenReturn     where to store the length of the data we are
     842 *                         returning
     843 * @param  piFormatReturn  where to store the bit width (8, 16, 32) of the
     844 *                         data we are returning
     845 */
     846static int clipWinTxtToUtf8ForX11CB(Display *pDisplay, PRTUTF16 pwszSrc,
     847                                    size_t cbSrc, Atom *atomTarget,
     848                                    Atom *atomTypeReturn,
     849                                    XtPointer *pValReturn,
     850                                    unsigned long *pcLenReturn,
     851                                    int *piFormatReturn)
     852{
     853    /* This may slightly overestimate the space needed. */
     854    size_t cbDest = 0;
     855    int rc = clipWinTxtBufSizeForUtf8(pwszSrc, cbSrc / 2, &cbDest);
     856    if (RT_SUCCESS(rc))
     857    {
     858        char *pszDest = (char *)XtMalloc(cbDest);
     859        size_t cbActual = 0;
     860        if (pszDest)
     861            rc = clipWinTxtToUtf8(pwszSrc, cbSrc, pszDest, cbDest,
     862                                  &cbActual);
     863        if (RT_SUCCESS(rc))
     864        {
     865            *atomTypeReturn = *atomTarget;
     866            *pValReturn = (XtPointer)pszDest;
     867            *pcLenReturn = cbActual;
     868            *piFormatReturn = 8;
     869        }
     870    }
     871    return rc;
     872}
     873
     874/**
     875 * Satisfy a request from X11 to convert the clipboard text to
     876 * COMPOUND_TEXT.  We return null-terminated text, but can cope with non-null-
     877 * terminated input.
     878 *
     879 * @returns iprt status code
     880 * @param  pDisplay        an X11 display structure, needed for conversions
     881 *                         performed by Xlib
     882 * @param  pv              the text to be converted (UCS-2 with Windows EOLs)
     883 * @param  cb              the length of the text in @cb in bytes
     884 * @param  atomTypeReturn  where to store the atom for the type of the data
     885 *                         we are returning
     886 * @param  pValReturn      where to store the pointer to the data we are
     887 *                         returning.  This should be to memory allocated by
     888 *                         XtMalloc, which will be freed by the Xt toolkit
     889 *                         later.
     890 * @param  pcLenReturn     where to store the length of the data we are
     891 *                         returning
     892 * @param  piFormatReturn  where to store the bit width (8, 16, 32) of the
     893 *                         data we are returning
     894 */
     895static int clipWinTxtToCTextForX11CB(Display *pDisplay, PRTUTF16 pwszSrc,
     896                                     size_t cbSrc, Atom *atomTypeReturn,
     897                                     XtPointer *pValReturn,
     898                                     unsigned long *pcLenReturn,
     899                                         int *piFormatReturn)
     900{
     901    char *pszTmp = NULL;
     902    size_t cbTmp = 0, cbActual = 0;
     903    XTextProperty property;
     904    int rc = VINF_SUCCESS, xrc = 0;
     905
     906    LogFlowFunc(("pwszSrc=%.*ls, cbSrc=%u\n", cbSrc / 2, pwszSrc, cbSrc));
     907    AssertPtrReturn(pDisplay, false);
     908    AssertPtrReturn(pwszSrc, false);
     909    rc = clipWinTxtBufSizeForUtf8(pwszSrc, cbSrc / 2, &cbTmp);
     910    if (RT_SUCCESS(rc))
     911    {
     912        pszTmp = (char *)RTMemAlloc(cbTmp);
     913        if (!pszTmp)
     914            rc = VERR_NO_MEMORY;
     915    }
     916    if (RT_SUCCESS(rc))
     917        rc = clipWinTxtToUtf8(pwszSrc, cbSrc, pszTmp, cbTmp + 1,
     918                              &cbActual);
     919    /* And finally (!) convert the Utf8 text to compound text. */
     920#ifdef X_HAVE_UTF8_STRING
     921    if (RT_SUCCESS(rc))
     922        xrc = Xutf8TextListToTextProperty(pDisplay, &pszTmp, 1,
     923                                          XCompoundTextStyle, &property);
     924#else
     925    if (RT_SUCCESS(rc))
     926        xrc = XmbTextListToTextProperty(pDisplay, &pszTmp, 1,
     927                                        XCompoundTextStyle, &property);
     928#endif
     929    if (RT_SUCCESS(rc) && xrc < 0)
     930        rc = (  xrc == XNoMemory           ? VERR_NO_MEMORY
     931              : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED
     932              : xrc == XConverterNotFound  ? VERR_NOT_SUPPORTED
     933              :                              VERR_UNRESOLVED_ERROR);
     934    RTMemFree(pszTmp);
     935    *atomTypeReturn = property.encoding;
     936    *pValReturn = reinterpret_cast<XtPointer>(property.value);
     937    *pcLenReturn = property.nitems + 1;
     938    *piFormatReturn = property.format;
     939    LogFlowFunc(("returning %Rrc\n", rc));
     940    if (RT_SUCCESS(rc))
     941        LogFlowFunc (("converted string is %s\n", property.value));
     942    return rc;
     943}
     944
     945/**
     946 * Does this atom correspond to one of the two selection types we support?
     947 * @param  widget   a valid Xt widget
     948 * @param  selType  the atom in question
     949 */
     950static bool clipIsSupportedSelectionType(Widget widget, Atom selType)
     951{
     952    return(   (selType == clipGetAtom(widget, "CLIPBOARD"))
     953           || (selType == clipGetAtom(widget, "PRIMARY")));
     954}
     955
     956static int clipConvertVBoxCBForX11(CLIPBACKEND *pCtx, Atom *atomTarget,
     957                                   Atom *atomTypeReturn,
     958                                   XtPointer *pValReturn,
     959                                   unsigned long *pcLenReturn,
     960                                   int *piFormatReturn)
     961{
     962    int rc = VINF_SUCCESS;
     963    CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx->widget,
     964                                                      *atomTarget);
     965    CLIPFORMAT format = clipRealFormatForX11Format(x11Format);
     966    if ((format == UTF8) || (format == CTEXT))
     967    {
     968        void *pv = NULL;
     969        uint32_t cb = 0;
     970        rc = clipReadVBoxClipboard(pCtx,
     971                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
     972                                   &pv, &cb);
     973        if (RT_SUCCESS(rc) && (cb == 0))
     974            rc = VERR_NO_DATA;
     975        if (RT_SUCCESS(rc) && (format == UTF8))
     976            rc = clipWinTxtToUtf8ForX11CB(XtDisplay(pCtx->widget),
     977                                          (PRTUTF16)pv, cb, atomTarget,
     978                                          atomTypeReturn, pValReturn,
     979                                          pcLenReturn, piFormatReturn);
     980        else if (RT_SUCCESS(rc) && (format == CTEXT))
     981            rc = clipWinTxtToCTextForX11CB(XtDisplay(pCtx->widget),
     982                                           (PRTUTF16)pv, cb,
     983                                           atomTypeReturn, pValReturn,
     984                                           pcLenReturn, piFormatReturn);
     985        RTMemFree(pv);
     986    }
     987    else
     988        rc = VERR_NOT_SUPPORTED;
     989    return rc;
     990}
     991
     992/**
     993 * Return VBox's clipboard data for an X11 client.
     994 * @note  X11 backend code, callback for XtOwnSelection
     995 */
     996static Boolean clipXtConvertSelectionProc(Widget widget, Atom *atomSelection,
     997                                          Atom *atomTarget,
     998                                          Atom *atomTypeReturn,
     999                                          XtPointer *pValReturn,
     1000                                          unsigned long *pcLenReturn,
     1001                                          int *piFormatReturn)
     1002{
     1003    CLIPBACKEND *pCtx = clipLookupContext(widget);
     1004    int rc = VINF_SUCCESS;
     1005
     1006    LogFlowFunc(("\n"));
     1007    if (   !pCtx->fOwnsClipboard   /* Drop requests we receive too late. */
     1008        || !clipIsSupportedSelectionType(pCtx->widget, *atomSelection))
     1009        return false;
     1010    if (*atomTarget == clipGetAtom(pCtx->widget, "TARGETS"))
     1011        rc = clipCreateX11Targets(pCtx, atomTypeReturn, pValReturn,
     1012                                  pcLenReturn, piFormatReturn);
     1013    else
     1014        rc = clipConvertVBoxCBForX11(pCtx, atomTarget, atomTypeReturn,
     1015                                     pValReturn, pcLenReturn, piFormatReturn);
     1016    LogFlowFunc(("returning, internal status code %Rrc\n", rc));
     1017    return RT_SUCCESS(rc);
     1018}
     1019
     1020/**
     1021 * This is called by the X toolkit intrinsics to let us know that another
     1022 * X11 client has taken the clipboard.  In this case we notify VBox that
     1023 * we want ownership of the clipboard.
     1024 * @note  X11 backend code, callback for XtOwnSelection
     1025 */
     1026static void clipXtLoseSelectionProc(Widget widget, Atom *)
     1027{
     1028    CLIPBACKEND *pCtx = clipLookupContext(widget);
     1029    LogFlowFunc (("\n"));
     1030    /* These should be set to the right values as soon as we start polling */
     1031    clipResetX11Formats(pCtx);
     1032    pCtx->fOwnsClipboard = false;
     1033}
     1034
     1035/** Structure used to pass information about formats that VBox supports */
     1036typedef struct _CLIPNEWVBOXFORMATS
     1037{
     1038    /** Context information for the X11 clipboard */
     1039    CLIPBACKEND *pCtx;
     1040    /** Formats supported by VBox */
     1041    uint32_t formats;
     1042} CLIPNEWVBOXFORMATS;
     1043
     1044/** Invalidates the local cache of the data in the VBox clipboard. */
     1045static void clipInvalidateVBoxCBCache(CLIPBACKEND *pCtx)
     1046{
     1047    if (pCtx->pvUnicodeCache != NULL)
     1048    {
     1049        RTMemFree(pCtx->pvUnicodeCache);
     1050        pCtx->pvUnicodeCache = NULL;
     1051    }
     1052}
     1053
     1054/** Gives up ownership of the X11 clipboard */
     1055static void clipGiveUpX11CB(CLIPBACKEND *pCtx)
     1056{
     1057    XtDisownSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"),
     1058                      CurrentTime);
     1059    XtDisownSelection(pCtx->widget, clipGetAtom(pCtx->widget, "PRIMARY"),
     1060                      CurrentTime);
     1061    pCtx->fOwnsClipboard = false;
     1062    pCtx->vboxFormats = 0;
     1063}
     1064
     1065/**
     1066 * Take possession of the X11 clipboard (and middle-button selection).
     1067 */
     1068static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats)
     1069{
     1070    if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"),
     1071                       CurrentTime, clipXtConvertSelectionProc,
     1072                       clipXtLoseSelectionProc, 0))
     1073    {
     1074        pCtx->fOwnsClipboard = true;
     1075        pCtx->vboxFormats = u32Formats;
     1076        /* Grab the middle-button paste selection too. */
     1077        XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "PRIMARY"),
     1078                       CurrentTime, clipXtConvertSelectionProc, NULL, 0);
     1079    }
     1080    else
     1081        /* Someone raced us to get the clipboard and they won. */
     1082        pCtx->fOwnsClipboard = false;
     1083}
     1084
     1085/**
     1086 * Worker function for VBoxX11ClipboardAnnounceVBoxFormat which runs on the
     1087 * event thread.
     1088 * @param pUserData  Pointer to a CLIPNEWVBOXFORMATS structure containing
     1089 *                   information about the VBox formats available and the
     1090 *                   clipboard context data.  Must be freed by the worker.
     1091 */
     1092static void clipNewVBoxFormatsWorker(XtPointer pUserData,
     1093                                     XtIntervalId * /* interval */)
     1094{
     1095    CLIPNEWVBOXFORMATS *pFormats = (CLIPNEWVBOXFORMATS *)pUserData;
     1096    CLIPBACKEND *pCtx = pFormats->pCtx;
     1097    uint32_t u32Formats = pFormats->formats;
     1098    RTMemFree(pFormats);
     1099    LogFlowFunc (("u32Formats=%d\n", u32Formats));
     1100    clipInvalidateVBoxCBCache(pCtx);
     1101    if (u32Formats == 0)
     1102        clipGiveUpX11CB(pCtx);
     1103    else
     1104        clipGrabX11CB(pCtx, u32Formats);
     1105    clipResetX11Formats(pCtx);
     1106    LogFlowFunc(("returning\n"));
     1107}
     1108
     1109/**
     1110 * VBox is taking possession of the shared clipboard.
     1111 *
     1112 * @param u32Formats Clipboard formats that VBox is offering
     1113 * @note  X11 backend code
     1114 */
     1115void VBoxX11ClipboardAnnounceVBoxFormat(CLIPBACKEND *pCtx,
     1116                                        uint32_t u32Formats)
     1117{
     1118    /*
     1119     * Immediately return if we are not connected to the X server.
     1120     */
     1121    if (!pCtx->fHaveX11)
     1122        return;
     1123    /* This must be freed by the worker callback */
     1124    CLIPNEWVBOXFORMATS *pFormats =
     1125        (CLIPNEWVBOXFORMATS *) RTMemAlloc(sizeof(CLIPNEWVBOXFORMATS));
     1126    if (pFormats != NULL)  /* if it is we will soon have other problems */
     1127    {
     1128        pFormats->pCtx = pCtx;
     1129        pFormats->formats = u32Formats;
     1130        clipQueueToEventThread(pCtx->appContext, clipNewVBoxFormatsWorker,
     1131                               (XtPointer) pFormats);
     1132    }
    3011133}
    3021134
     
    5171349/** A structure containing information about where to store a request
    5181350 * for the X11 clipboard contents. */
    519 struct _CLIPX11CLIPBOARDREQ
     1351struct _CLIPREADX11CBREQ
    5201352{
    5211353    /** The buffer to write X11 clipboard data to (valid during a request
     
    5401372};
    5411373
    542 typedef struct _CLIPX11CLIPBOARDREQ CLIPX11CLIPBOARDREQ;
     1374typedef struct _CLIPREADX11CBREQ CLIPREADX11CBREQ;
    5431375
    5441376/**
     
    5531385                             int *piFormat)
    5541386{
    555     CLIPX11CLIPBOARDREQ *pReq = (CLIPX11CLIPBOARDREQ *) pClientData;
     1387    CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *) pClientData;
    5561388    LogFlowFunc(("pReq->mBuffer=%p, pReq->mSize=%u, pReq->mFormat=%02X, pReq->mTextFormat=%u, pReq->mCtx=%p\n",
    5571389                 pReq->mBuffer, pReq->mSize, pReq->mFormat,
     
    6001432    else
    6011433        rc = VERR_NOT_IMPLEMENTED;
    602     if (RT_SUCCESS(rc))
    603         /* The other end may cache the data, so invalidate it again. */
    604         clipInvalidateVBoxCache(pCtx);
    605     else
    606         /* We failed to retrieve the X11 clipboard contents, mark them as
    607          * invalid. */
    608         clipInvalidateX11Contents(pCtx);
    6091434    XtFree((char *)pvSrc);
    6101435    pReq->mRC = rc;
    6111436    RTSemEventSignal(pReq->mSem);
     1437    /* Don't try to call VBox until after we have released the inbound call
     1438     * from VBox! */
     1439    /** @todo make this safer */
     1440    if (RT_SUCCESS(rc))
     1441        /* The other end may want to cache the data, so pretend we have new
     1442         * data, as we have no way of telling when new data really does
     1443         * arrive. */
     1444        clipReportFormatsToVBox(pCtx);
     1445    else
     1446        clipReportEmptyX11CB(pCtx);
    6121447    LogFlowFunc(("rc=%Rrc\n", rc));
    613 }
    614 
    615 /**
    616  * Notify the host clipboard about the data formats we support, based on the
    617  * "targets" (available data formats) information obtained from the X11
    618  * clipboard.
    619  * @note  X11 backend code, callback for XtGetSelectionValue, called when we
    620  *        poll for available targets.
    621  */
    622 static void clipConvertX11Targets(Widget, XtPointer pClientData,
    623                                   Atom * /* selection */, Atom *atomType,
    624                                   XtPointer pValue, long unsigned int *pcLen,
    625                                   int *piFormat)
    626 {
    627     CLIPBACKEND *pCtx =
    628             reinterpret_cast<CLIPBACKEND *>(pClientData);
    629     Atom *atomTargets = reinterpret_cast<Atom *>(pValue);
    630     unsigned cAtoms = *pcLen;
    631     CLIPFORMAT enmBestTarget = INVALID;
    632     CLIPX11FORMAT bestFormat = NIL_CLIPX11FORMAT;
    633 
    634     Log3 (("%s: called\n", __PRETTY_FUNCTION__));
    635     if (   (*atomType == XT_CONVERT_FAIL) /* timeout */
    636         || (pCtx->fOwnsClipboard == true) /* VBox currently owns the
    637                                            * clipboard */
    638        )
    639     {
    640         clipInvalidateX11Contents(pCtx);
    641         return;
    642     }
    643 
    644     for (unsigned i = 0; i < cAtoms; ++i)
    645     {
    646         CLIPX11FORMAT format = clipFindX11FormatByAtom(pCtx->widget,
    647                                                        atomTargets[i]);
    648         if (format != NIL_CLIPX11FORMAT)
    649         {
    650             if (enmBestTarget < clipRealFormatForX11Format(format))
    651             {
    652                 enmBestTarget = clipRealFormatForX11Format(format);
    653                 bestFormat = format;
    654             }
    655         }
    656     }
    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);
    665         pCtx->notifyVBox = false;
    666     }
    667     pCtx->X11TextFormat = bestFormat;
    668     XtFree(reinterpret_cast<char *>(pValue));
    669 }
    670 
    671 enum { TIMER_FREQ = 200 /* ms */ };
    672 
    673 static void clipPollX11CBFormats(XtPointer pUserData,
    674                                  XtIntervalId * /* hTimerId */);
    675 static void clipSchedulePoller(CLIPBACKEND *pCtx,
    676                                XtTimerCallbackProc proc);
    677 
    678 #ifndef TESTCASE
    679 void clipSchedulePoller(CLIPBACKEND *pCtx,
    680                         XtTimerCallbackProc proc)
    681 {
    682     XtAppAddTimeOut(pCtx->appContext, TIMER_FREQ, proc, pCtx);
    683 }
    684 #endif
    685 
    686 /**
    687  * This timer callback is called every 200ms to check the contents of the X11
    688  * clipboard.
    689  * @note  X11 backend code, callback for XtAppAddTimeOut, recursively
    690  *        re-armed.
    691  * @todo  Use the XFIXES extension to check for new clipboard data when
    692  *        available.
    693  */
    694 void clipPollX11CBFormats(XtPointer pUserData, XtIntervalId * /* hTimerId */)
    695 {
    696     CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData;
    697     Log3 (("%s: called\n", __PRETTY_FUNCTION__));
    698     /* Get the current clipboard contents if we don't own it ourselves */
    699     if (!pCtx->fOwnsClipboard)
    700     {
    701         Log3 (("%s: requesting the targets that the host clipboard offers\n",
    702                __PRETTY_FUNCTION__));
    703         XtGetSelectionValue(pCtx->widget,
    704                             clipGetAtom(pCtx->widget, "CLIPBOARD"),
    705                             clipGetAtom(pCtx->widget, "TARGETS"),
    706                             clipConvertX11Targets, pCtx,
    707                             CurrentTime);
    708     }
    709     /* Re-arm our timer */
    710     clipSchedulePoller(pCtx, clipPollX11CBFormats);
    711 }
    712 
    713 #ifndef TESTCASE
    714 /**
    715  * The main loop of our clipboard reader.
    716  * @note  X11 backend code.
    717  */
    718 static int clipEventThread(RTTHREAD self, void *pvUser)
    719 {
    720     LogRel(("Shared clipboard: starting host clipboard thread\n"));
    721 
    722     CLIPBACKEND *pCtx = (CLIPBACKEND *)pvUser;
    723     while (XtAppGetExitFlag(pCtx->appContext) == FALSE)
    724         XtAppProcessEvent(pCtx->appContext, XtIMAll);
    725     LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
    726     return VINF_SUCCESS;
    727 }
    728 #endif
    729 
    730 /** X11 specific uninitialisation for the shared clipboard.
    731  * @note  X11 backend code.
    732  */
    733 static void clipUninit(CLIPBACKEND *pCtx)
    734 {
    735     AssertPtrReturnVoid(pCtx);
    736     if (pCtx->widget)
    737     {
    738         /* Valid widget + invalid appcontext = bug.  But don't return yet. */
    739         AssertPtr(pCtx->appContext);
    740         clipUnregisterContext(pCtx);
    741         XtDestroyWidget(pCtx->widget);
    742     }
    743     pCtx->widget = NULL;
    744     if (pCtx->appContext)
    745         XtDestroyApplicationContext(pCtx->appContext);
    746     pCtx->appContext = NULL;
    747     if (pCtx->wakeupPipeRead != 0)
    748         close(pCtx->wakeupPipeRead);
    749     if (pCtx->wakeupPipeWrite != 0)
    750         close(pCtx->wakeupPipeWrite);
    751     pCtx->wakeupPipeRead = 0;
    752     pCtx->wakeupPipeWrite = 0;
    753 }
    754 
    755 /** Worker function for stopping the clipboard which runs on the event
    756  * thread. */
    757 static void clipStopEventThreadWorker(XtPointer pUserData, int * /* source */,
    758                                       XtInputId * /* id */)
    759 {
    760    
    761     CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData;
    762 
    763     /* This might mean that we are getting stopped twice. */
    764     Assert(pCtx->widget != NULL);
    765 
    766     /* Set the termination flag to tell the Xt event loop to exit.  We
    767      * reiterate that any outstanding requests from the X11 event loop to
    768      * the VBox part *must* have returned before we do this. */
    769     XtAppSetExitFlag(pCtx->appContext);
    770     pCtx->fOwnsClipboard = false;
    771     clipInvalidateX11Contents(pCtx);
    772 }
    773 
    774 /** X11 specific initialisation for the shared clipboard.
    775  * @note  X11 backend code.
    776  */
    777 static int clipInit(CLIPBACKEND *pCtx)
    778 {
    779     /* Create a window and make it a clipboard viewer. */
    780     int cArgc = 0;
    781     char *pcArgv = 0;
    782     int rc = VINF_SUCCESS;
    783     Display *pDisplay;
    784 
    785     /* Make sure we are thread safe */
    786     XtToolkitThreadInitialize();
    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. */
    790     XtToolkitInitialize();
    791     pCtx->appContext = XtCreateApplicationContext();
    792     pDisplay = XtOpenDisplay(pCtx->appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);
    793     if (NULL == pDisplay)
    794     {
    795         LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));
    796         rc = VERR_NOT_SUPPORTED;
    797     }
    798     if (RT_SUCCESS(rc))
    799     {
    800         pCtx->widget = XtVaAppCreateShell(0, "VBoxClipboard",
    801                                           applicationShellWidgetClass,
    802                                           pDisplay, XtNwidth, 1, XtNheight,
    803                                           1, NULL);
    804         if (NULL == pCtx->widget)
    805         {
    806             LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));
    807             rc = VERR_NO_MEMORY;
    808         }
    809         else
    810             rc = clipRegisterContext(pCtx);
    811     }
    812     if (RT_SUCCESS(rc))
    813     {
    814         XtSetMappedWhenManaged(pCtx->widget, false);
    815         XtRealizeWidget(pCtx->widget);
    816         /* Set up a timer to poll the host clipboard */
    817         clipSchedulePoller(pCtx, clipPollX11CBFormats);
    818     }
    819     /* Create the pipes */
    820     int pipes[2];
    821     if (!pipe(pipes))
    822     {
    823         pCtx->wakeupPipeRead = pipes[0];
    824         pCtx->wakeupPipeWrite = pipes[1];
    825         if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
    826                            (XtPointer) XtInputReadMask,
    827                            clipStopEventThreadWorker, (XtPointer) pCtx))
    828             rc = VERR_NO_MEMORY;  /* What failure means is not doc'ed. */
    829     }
    830     else
    831         rc = RTErrConvertFromErrno(errno);
    832     if (RT_FAILURE(rc))
    833         clipUninit(pCtx);
    834     return rc;
    835 }
    836 
    837 /**
    838  * Construct the X11 backend of the shared clipboard.
    839  * @note  X11 backend code
    840  */
    841 CLIPBACKEND *VBoxX11ClipboardConstructX11(VBOXCLIPBOARDCONTEXT *pFrontend)
    842 {
    843     int rc;
    844 
    845     CLIPBACKEND *pCtx = (CLIPBACKEND *)
    846                     RTMemAllocZ(sizeof(CLIPBACKEND));
    847     if (pCtx && !RTEnvGet("DISPLAY"))
    848     {
    849         /*
    850          * If we don't find the DISPLAY environment variable we assume that
    851          * we are not connected to an X11 server. Don't actually try to do
    852          * this then, just fail silently and report success on every call.
    853          * This is important for VBoxHeadless.
    854          */
    855         LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n"));
    856         pCtx->fHaveX11 = false;
    857         return pCtx;
    858     }
    859 
    860     pCtx->fHaveX11 = true;
    861 
    862     LogRel(("Initializing X11 clipboard backend\n"));
    863     if (pCtx)
    864         pCtx->pFrontend = pFrontend;
    865     return pCtx;
    866 }
    867 
    868 /**
    869  * Destruct the shared clipboard X11 backend.
    870  * @note  X11 backend code
    871  */
    872 void VBoxX11ClipboardDestructX11(CLIPBACKEND *pCtx)
    873 {
    874     /*
    875      * Immediately return if we are not connected to the host X server.
    876      */
    877     if (!pCtx->fHaveX11)
    878         return;
    879 
    880     /* We set this to NULL when the event thread exits.  It really should
    881      * have exited at this point, when we are about to unload the code from
    882      * memory. */
    883     Assert(pCtx->widget == NULL);
    884 }
    885 
    886 /**
    887  * Announce to the X11 backend that we are ready to start.
    888  */
    889 int VBoxX11ClipboardStartX11(CLIPBACKEND *pCtx)
    890 {
    891     int rc = VINF_SUCCESS;
    892     LogFlowFunc(("\n"));
    893     /*
    894      * Immediately return if we are not connected to the host X server.
    895      */
    896     if (!pCtx->fHaveX11)
    897         return VINF_SUCCESS;
    898 
    899     rc = clipInit(pCtx);
    900 #ifndef TESTCASE
    901     if (RT_SUCCESS(rc))
    902     {
    903         rc = RTThreadCreate(&pCtx->thread, clipEventThread, pCtx, 0,
    904                             RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
    905         if (RT_FAILURE(rc))
    906             LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));
    907     }
    908 #endif
    909     if (RT_SUCCESS(rc))
    910     {
    911         pCtx->fOwnsClipboard = false;
    912         clipInvalidateVBoxCache(pCtx);
    913     }
    914     return rc;
    915 }
    916 
    917 /** String written to the wakeup pipe. */
    918 #define WAKE_UP_STRING      "WakeUp!"
    919 /** Length of the string written. */
    920 #define WAKE_UP_STRING_LEN  ( sizeof(WAKE_UP_STRING) - 1 )
    921 
    922 /**
    923  * Shut down the shared clipboard X11 backend.
    924  * @note  X11 backend code
    925  * @note  Any requests from this object to get clipboard data from VBox
    926  *        *must* have completed or aborted before we are called, as
    927  *        otherwise the X11 event loop will still be waiting for the request
    928  *        to return and will not be able to terminate.
    929  */
    930 int VBoxX11ClipboardStopX11(CLIPBACKEND *pCtx)
    931 {
    932     int rc, rcThread;
    933     unsigned count = 0;
    934     /*
    935      * Immediately return if we are not connected to the host X server.
    936      */
    937     if (!pCtx->fHaveX11)
    938         return VINF_SUCCESS;
    939 
    940     LogRelFunc(("stopping the shared clipboard X11 backend\n"));
    941     /* Write to the "stop" pipe */
    942     rc = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN);
    943     do
    944     {
    945         rc = RTThreadWait(pCtx->thread, 1000, &rcThread);
    946         ++count;
    947         Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
    948     } while ((VERR_TIMEOUT == rc) && (count < 300));
    949     if (RT_SUCCESS(rc))
    950         AssertRC(rcThread);
    951     else
    952         LogRelFunc(("rc=%Rrc\n", rc));
    953     clipUninit(pCtx);
    954     LogFlowFunc(("returning %Rrc.\n", rc));
    955     return rc;
    956 }
    957 
    958 /**
    959  * Satisfy a request from X11 for clipboard targets supported by VBox.
    960  *
    961  * @returns true if we successfully convert the data to the format
    962  *          requested, false otherwise.
    963  *
    964  * @param  atomTypeReturn The type of the data we are returning
    965  * @param  pValReturn     A pointer to the data we are returning.  This
    966  *                        should be set to memory allocated by XtMalloc,
    967  *                        which will be freed later by the Xt toolkit.
    968  * @param  pcLenReturn    The length of the data we are returning
    969  * @param  piFormatReturn The format (8bit, 16bit, 32bit) of the data we are
    970  *                        returning
    971  * @note  X11 backend code, called by the XtOwnSelection callback.
    972  */
    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));
    980     unsigned cTargets = 0;
    981     LogFlowFunc (("called\n"));
    982     CLIPX11FORMAT format = NIL_CLIPX11FORMAT;
    983     do
    984     {
    985         format = clipNextX11Format(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
    986                                    format);
    987         if (format != NIL_CLIPX11FORMAT)
    988         {
    989             atomTargets[cTargets] = clipAtomForX11Format(pCtx->widget,
    990                                                           format);
    991             ++cTargets;
    992         }
    993     } while (format != NIL_CLIPX11FORMAT);
    994     /* We always offer these */
    995     atomTargets[cTargets] = clipGetAtom(pCtx->widget, "TARGETS");
    996     atomTargets[cTargets + 1] = clipGetAtom(pCtx->widget, "MULTIPLE");
    997     atomTargets[cTargets + 2] = clipGetAtom(pCtx->widget, "TIMESTAMP");
    998     *atomTypeReturn = XA_ATOM;
    999     *pValReturn = (XtPointer)atomTargets;
    1000     *pcLenReturn = cTargets + 3;
    1001     *piFormatReturn = 32;
    1002     return true;
    1003 }
    1004 
    1005 /** This is a wrapper around VBoxX11ClipboardReadVBoxData that will cache the
    1006  * data returned.  This is unfortunately necessary, because if the other side
    1007  * of the shared clipboard is also an X11 system, it may send a format
    1008  * announcement message every time its clipboard is read, for reasons that
    1009  * are explained elsewhere.  Unfortunately, some applications on our side
    1010  * like to read the clipboard several times in short succession in different
    1011  * formats.  This can fail if it collides with a format announcement message.
    1012  * @todo any ideas about how to do this better are welcome.
    1013  */
    1014 static int clipReadVBoxClipboard(CLIPBACKEND *pCtx, uint32_t u32Format,
    1015                                  void **ppv, uint32_t *pcb)
    1016 {
    1017     int rc = VINF_SUCCESS;
    1018     LogFlowFunc(("pCtx=%p, u32Format=%02X, ppv=%p, pcb=%p\n", pCtx,
    1019                  u32Format, ppv, pcb));
    1020     if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
    1021     {
    1022         if (pCtx->pvUnicodeCache == NULL)
    1023             rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format,
    1024                                               &pCtx->pvUnicodeCache,
    1025                                               &pCtx->cbUnicodeCache);
    1026         if (RT_SUCCESS(rc))
    1027         {
    1028             *ppv = RTMemDup(pCtx->pvUnicodeCache, pCtx->cbUnicodeCache);
    1029             *pcb = pCtx->cbUnicodeCache;
    1030             if (*ppv == NULL)
    1031                 rc = VERR_NO_MEMORY;
    1032         }
    1033     }
    1034     else
    1035         rc = VBoxX11ClipboardReadVBoxData(pCtx->pFrontend, u32Format,
    1036                                           ppv, pcb);
    1037     LogFlowFunc(("returning %Rrc\n", rc));
    1038     if (RT_SUCCESS(rc))
    1039         LogFlowFunc(("*ppv=%.*ls, *pcb=%u\n", *pcb, *ppv, *pcb));
    1040     return rc;
    1041 }
    1042 
    1043 
    1044 /**
    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.
    1096  *
    1097  * @returns true if we successfully convert the data to the format
    1098  * requested, false otherwise.
    1099  *
    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
    1105  *                         we are returning
    1106  * @param  pValReturn      where to store the pointer to the data we are
    1107  *                         returning.  This should be to memory allocated by
    1108  *                         XtMalloc, which will be freed by the Xt toolkit
    1109  *                         later.
    1110  * @param  pcLenReturn     where to store the length of the data we are
    1111  *                         returning
    1112  * @param  piFormatReturn  where to store the bit width (8, 16, 32) of the
    1113  *                         data we are returning
    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;
    1123     XTextProperty property;
    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);
    1138     /* And finally (!) convert the Utf8 text to compound text. */
    1139 #ifdef X_HAVE_UTF8_STRING
    1140     if (RT_SUCCESS(rc))
    1141         xrc = Xutf8TextListToTextProperty(pDisplay, &pszTmp, 1,
    1142                                           XCompoundTextStyle, &property);
    1143 #else
    1144     if (RT_SUCCESS(rc))
    1145         xrc = XmbTextListToTextProperty(pDisplay, &pszTmp, 1,
    1146                                         XCompoundTextStyle, &property);
    1147 #endif
    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);
    1154     *atomTypeReturn = property.encoding;
    1155     *pValReturn = reinterpret_cast<XtPointer>(property.value);
    1156     *pcLenReturn = property.nitems + 1;
    1157     *piFormatReturn = property.format;
    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);
    1162 }
    1163 
    1164 /**
    1165  * Return VBox's clipboard data for an X11 client.
    1166  * @note  X11 backend code, callback for XtOwnSelection
    1167  */
    1168 static Boolean vboxClipboardConvertForX11(Widget widget, Atom *atomSelection,
    1169                                           Atom *atomTarget,
    1170                                           Atom *atomTypeReturn,
    1171                                           XtPointer *pValReturn,
    1172                                           unsigned long *pcLenReturn,
    1173                                           int *piFormatReturn)
    1174 {
    1175     CLIPFORMAT enmFormat = INVALID;
    1176     CLIPBACKEND *pCtx = clipLookupContext(widget);
    1177     int rc = VINF_SUCCESS;
    1178     bool retval = false;
    1179 
    1180     LogFlowFunc(("\n"));
    1181     /* Drop requests that we receive too late. */
    1182     if (!pCtx->fOwnsClipboard)
    1183         return false;
    1184     if (   (*atomSelection != clipGetAtom(pCtx->widget, "CLIPBOARD"))
    1185         && (*atomSelection != clipGetAtom(pCtx->widget, "PRIMARY"))
    1186        )
    1187     {
    1188         LogFlowFunc(("rc = false\n"));
    1189         return false;
    1190     }
    1191     if (*atomTarget == clipGetAtom(pCtx->widget, "TARGETS"))
    1192     {
    1193         enmFormat = TARGETS;
    1194     }
    1195     else
    1196     {
    1197         for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i)
    1198         {
    1199             if (*atomTarget == clipGetAtom(pCtx->widget,
    1200                                            g_aFormats[i].pcszAtom))
    1201             {
    1202                 enmFormat = g_aFormats[i].enmFormat;
    1203                 break;
    1204             }
    1205         }
    1206     }
    1207     switch (enmFormat)
    1208     {
    1209     case TARGETS:
    1210         return clipCreateX11Targets(pCtx, atomTypeReturn, pValReturn,
    1211                                     pcLenReturn, piFormatReturn);
    1212     case UTF8:
    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     }
    1245     case CTEXT:
    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     }
    1261     default:
    1262         LogFunc (("bad format\n"));
    1263         return false;
    1264     }
    1265     return retval;
    1266 }
    1267 
    1268 /**
    1269  * This is called by the X toolkit intrinsics to let us know that another
    1270  * X11 client has taken the clipboard.  In this case we notify VBox that
    1271  * we want ownership of the clipboard.
    1272  * @note  X11 backend code, callback for XtOwnSelection
    1273  */
    1274 static void vboxClipboardReturnToX11(Widget widget, Atom *)
    1275 {
    1276     CLIPBACKEND *pCtx = clipLookupContext(widget);
    1277     LogFlowFunc (("called, giving X11 clipboard ownership\n"));
    1278     /* These should be set to the right values as soon as we start polling */
    1279     clipInvalidateX11Contents(pCtx);
    1280     pCtx->fOwnsClipboard = false;
    1281     clipInvalidateVBoxCache(pCtx);
    1282 }
    1283 
    1284 static void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
    1285                          XtPointer client_data);
    1286 #ifndef TESTCASE
    1287 void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
    1288                   XtPointer client_data)
    1289 {
    1290     XtAppAddTimeOut(app_context, 0, proc, client_data);
    1291 }
    1292 #endif
    1293 
    1294 /** Structure used to pass information about formats that VBox supports */
    1295 typedef struct _VBOXCLIPBOARDFORMATS
    1296 {
    1297     /** Context information for the X11 clipboard */
    1298     CLIPBACKEND *pCtx;
    1299     /** Formats supported by VBox */
    1300     uint32_t formats;
    1301 } VBOXCLIPBOARDFORMATS;
    1302 
    1303 /** Worker function for VBoxX11ClipboardAnnounceVBoxFormat which runs on the
    1304  * event thread. */
    1305 static void vboxClipboardAnnounceWorker(XtPointer pUserData,
    1306                                         XtIntervalId * /* interval */)
    1307 {
    1308     /* Extract and free the user data */
    1309     VBOXCLIPBOARDFORMATS *pFormats = (VBOXCLIPBOARDFORMATS *)pUserData;
    1310     CLIPBACKEND *pCtx = pFormats->pCtx;
    1311     uint32_t u32Formats = pFormats->formats;
    1312     RTMemFree(pFormats);
    1313     LogFlowFunc (("u32Formats=%d\n", u32Formats));
    1314     pCtx->vboxFormats = u32Formats;
    1315     /* Invalidate the clipboard cache */
    1316     if (pCtx->pvUnicodeCache != NULL)
    1317     {
    1318         RTMemFree(pCtx->pvUnicodeCache);
    1319         pCtx->pvUnicodeCache = NULL;
    1320     }
    1321     if (u32Formats == 0)
    1322     {
    1323         /* This is just an automatism, not a genuine anouncement */
    1324         XtDisownSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), CurrentTime);
    1325         pCtx->fOwnsClipboard = false;
    1326         LogFlowFunc(("returning\n"));
    1327         return;
    1328     }
    1329     Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__));
    1330     if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), CurrentTime,
    1331                        vboxClipboardConvertForX11, vboxClipboardReturnToX11,
    1332                        0) == True)
    1333     {
    1334         pCtx->fOwnsClipboard = true;
    1335         /* Grab the middle-button paste selection too. */
    1336         XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "PRIMARY"), CurrentTime,
    1337                        vboxClipboardConvertForX11, NULL, 0);
    1338     }
    1339     else
    1340     {
    1341         /* Another X11 client claimed the clipboard just after us, so let it
    1342          * go again. */
    1343         Log2 (("%s: returning clipboard ownership to the X11\n",
    1344                __PRETTY_FUNCTION__));
    1345         /* VBox thinks it currently owns the clipboard, so we must notify it
    1346          * as soon as we know what formats X11 has to offer. */
    1347         clipInvalidateVBoxCache(pCtx);
    1348         pCtx->fOwnsClipboard = false;
    1349     }
    1350     LogFlowFunc(("returning\n"));
    1351 }
    1352 
    1353 /**
    1354  * VBox is taking possession of the shared clipboard.
    1355  *
    1356  * @param u32Formats Clipboard formats the guest is offering
    1357  * @note  X11 backend code
    1358  */
    1359 void VBoxX11ClipboardAnnounceVBoxFormat(CLIPBACKEND *pCtx,
    1360                                         uint32_t u32Formats)
    1361 {
    1362     /*
    1363      * Immediately return if we are not connected to the host X server.
    1364      */
    1365     if (!pCtx->fHaveX11)
    1366         return;
    1367     /* This must be freed by the worker callback */
    1368     VBOXCLIPBOARDFORMATS *pFormats =
    1369         (VBOXCLIPBOARDFORMATS *) RTMemAlloc(sizeof(VBOXCLIPBOARDFORMATS));
    1370     if (pFormats != NULL)  /* if it is we will soon have other problems */
    1371     {
    1372         pFormats->pCtx = pCtx;
    1373         pFormats->formats = u32Formats;
    1374         clipSchedule(pCtx->appContext, vboxClipboardAnnounceWorker,
    1375                      (XtPointer) pFormats);
    1376     }
    13771448}
    13781449
     
    13821453                                       XtIntervalId * /* interval */)
    13831454{
    1384     CLIPX11CLIPBOARDREQ *pReq = (CLIPX11CLIPBOARDREQ *)pUserData;
     1455    CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pUserData;
    13851456    CLIPBACKEND *pCtx = pReq->mCtx;
    13861457    LogFlowFunc (("pReq->mFormat = %02X, pReq->mSize = %d\n", pReq->mFormat,
     
    14011472        {
    14021473            pReq->mTextFormat = pCtx->X11TextFormat;
    1403             if (pReq->mTextFormat == 0)
     1474            if (pReq->mTextFormat == INVALID)
    14041475                /* VBox thinks we have data and we don't */
    14051476                rc = VERR_NO_DATA;
     
    14081479                 * owner */
    14091480                XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"),
    1410                                     clipGetAtom(pCtx->widget,
    1411                                         g_aFormats[pCtx->X11TextFormat].pcszAtom),
     1481                                    clipAtomForX11Format(pCtx->widget,
     1482                                                         pCtx->X11TextFormat),
    14121483                                    clipConvertX11CB,
    14131484                                    reinterpret_cast<XtPointer>(pReq),
     
    14301501 * Called when VBox wants to read the X11 clipboard.
    14311502 *
    1432  * @param  pClient   Context information about the guest VM
    1433  * @param  u32Format The format that the guest would like to receive the data in
     1503 * @param  pCtx      Context data for the clipboard backend
     1504 * @param  u32Format The format that the VBox would like to receive the data
     1505 *                   in
    14341506 * @param  pv        Where to write the data to
    14351507 * @param  cb        The size of the buffer to write the data to
     
    14461518
    14471519    /*
    1448      * Immediately return if we are not connected to the host X server.
     1520     * Immediately return if we are not connected to the X server.
    14491521     */
    14501522    if (!pCtx->fHaveX11)
    14511523        return VINF_SUCCESS;
    14521524
    1453     CLIPX11CLIPBOARDREQ req = { 0 };
     1525    CLIPREADX11CBREQ req = { 0 };
    14541526    req.mRC = VERR_WRONG_ORDER;
    14551527    req.mBuffer = pv;
     
    14631535    {
    14641536        /* We use this to schedule a worker function on the event thread. */
    1465         clipSchedule(pCtx->appContext, vboxClipboardReadX11Worker,
    1466                      (XtPointer) &req);
     1537        clipQueueToEventThread(pCtx->appContext, vboxClipboardReadX11Worker,
     1538                               (XtPointer) &req);
    14671539        rc = RTSemEventWait(req.mSem, RT_INDEFINITE_WAIT);
    14681540        if (RT_SUCCESS(rc))
     
    15061578/* For the purpose of the test case, we just execute the procedure to be
    15071579 * scheduled, as we are running single threaded. */
    1508 void clipSchedule(XtAppContext app_context, XtTimerCallbackProc proc,
    1509                   XtPointer client_data)
     1580void clipQueueToEventThread(XtAppContext app_context,
     1581                            XtTimerCallbackProc proc,
     1582                            XtPointer client_data)
    15101583{
    15111584    proc(client_data, NULL);
     
    18501923        g_pfnSelLose(TEST_WIDGET, &clipAtom);
    18511924    g_ownsSel = false;
    1852     g_fX11Formats = 0;
    18531925}
    18541926
     
    22012273
    22022274    /*** request for an invalid VBox format from X11 ***/
    2203     RTPrintf(TEST_NAME ": TESTING a request for an invalid host format from X11\n");
     2275    RTPrintf(TEST_NAME ": TESTING a request for an invalid VBox format from X11\n");
    22042276    rc = VBoxX11ClipboardReadX11Data(pCtx, 0xffff, (void *) pc,
    22052277                                     sizeof(pc), &cbActual);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette