VirtualBox

Changeset 18612 in vbox


Ignore:
Timestamp:
Apr 1, 2009 6:08:01 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
45518
Message:

GuestHost/SharedClipboard: recommitted x11-clipboard.cpp with more history

File:
1 copied

Legend:

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

    r18596 r18612  
    22 *
    33 * Shared Clipboard:
    4  * Linux host.
     4 * X11 backend code.
    55 */
    66
     
    2424#define LOG_GROUP LOG_GROUP_HGCM
    2525
    26 #include <string.h>
    27 
    28 #include <iprt/asm.h>        /* For atomic operations */
    29 #include <iprt/assert.h>
     26#include <vector>
     27
     28#ifdef RT_OS_SOLARIS
     29#include <tsol/label.h>
     30#endif
     31
     32#include <X11/Xlib.h>
     33#include <X11/Xatom.h>
     34#include <X11/Intrinsic.h>
     35#include <X11/Shell.h>
     36#include <X11/Xproto.h>
     37#include <X11/StringDefs.h>
     38
     39#include <iprt/env.h>
    3040#include <iprt/mem.h>
    3141#include <iprt/semaphore.h>
     42#include <iprt/thread.h>
    3243
    3344#include <VBox/log.h>
    3445
    3546#include <VBox/GuestHost/SharedClipboard.h>
     47#include <VBox/GuestHost/clipboard-helper.h>
    3648#include <VBox/HostServices/VBoxClipboardSvc.h>
    3749
    38 #include "VBoxClipboard.h"
    39 
    40 /** Global context information used by the host glue for the X11 clipboard
    41  * backend */
    42 struct _VBOXCLIPBOARDCONTEXT
    43 {
     50/** Do we want to test Utf16 by disabling other text formats? */
     51static bool g_testUtf16 = false;
     52/** Do we want to test Utf8 by disabling other text formats? */
     53static bool g_testUtf8 = false;
     54/** Do we want to test compount text by disabling other text formats? */
     55static bool g_testCText = false;
     56/** Are we currently debugging the clipboard code? */
     57static bool g_debugClipboard = false;
     58
     59/** The different clipboard formats which we support. */
     60enum g_eClipboardFormats
     61{
     62    INVALID = 0,
     63    TARGETS,
     64    CTEXT,
     65    UTF8,
     66    UTF16
     67};
     68
     69/** The X11 clipboard uses several names for the same format.  This
     70 * structure maps an X11 name to a format. */
     71typedef struct {
     72    Atom atom;
     73    g_eClipboardFormats format;
     74    unsigned guestFormat;
     75} VBOXCLIPBOARDFORMAT;
     76
     77/** Global context information used by the X11 clipboard backend */
     78struct _VBOXCLIPBOARDCONTEXTX11
     79{
     80    /** Opaque data structure describing the front-end. */
     81    VBOXCLIPBOARDCONTEXT *pFrontend;
     82    /** The X Toolkit application context structure */
     83    XtAppContext appContext;
     84
     85    /** We have a separate thread to wait for Window and Clipboard events */
     86    RTTHREAD thread;
     87    /** The X Toolkit widget which we use as our clipboard client.  It is never made visible. */
     88    Widget widget;
     89
     90    /** X11 atom refering to the clipboard: CLIPBOARD */
     91    Atom atomClipboard;
     92    /** X11 atom refering to the selection: PRIMARY */
     93    Atom atomPrimary;
     94    /** X11 atom refering to the clipboard targets: TARGETS */
     95    Atom atomTargets;
     96    /** X11 atom refering to the clipboard multiple target: MULTIPLE */
     97    Atom atomMultiple;
     98    /** X11 atom refering to the clipboard timestamp target: TIMESTAMP */
     99    Atom atomTimestamp;
     100    /** X11 atom refering to the clipboard utf16 text format: text/plain;charset=ISO-10646-UCS-2 */
     101    Atom atomUtf16;
     102    /** X11 atom refering to the clipboard utf8 text format: UTF8_STRING */
     103    Atom atomUtf8;
     104    /** X11 atom refering to the clipboard compound text format: COMPOUND_TEXT */
     105    Atom atomCText;
     106
     107    /** A list of the X11 formats which we support, mapped to our identifier for them, in the
     108        order we prefer to have them in. */
     109    std::vector<VBOXCLIPBOARDFORMAT> formatList;
     110
     111    /** Does VBox or X11 currently own the clipboard? */
     112    volatile enum g_eOwner eOwner;
     113
     114    /** What is the best text format X11 has to offer?  INVALID for none. */
     115    g_eClipboardFormats X11TextFormat;
     116    /** Atom corresponding to the X11 text format */
     117    Atom atomX11TextFormat;
     118    /** What is the best bitmap format X11 has to offer?  INVALID for none. */
     119    g_eClipboardFormats X11BitmapFormat;
     120    /** Atom corresponding to the X11 Bitmap format */
     121    Atom atomX11BitmapFormat;
     122    /** What formats does VBox have on offer? */
     123    int vboxFormats;
     124    /** Windows hosts and guests cache the clipboard data they receive.
     125     * Since we have no way of knowing whether their cache is still valid,
     126     * we always send a "data changed" message after a successful transfer
     127     * to invalidate it. */
     128    bool notifyVBox;
     129
    44130    /** Since the clipboard data moves asynchronously, we use an event
    45131     * semaphore to wait for it.  When a function issues a request for
     
    47133     * when the data arrives. */
    48134    RTSEMEVENT waitForData;
    49     /** Who (if anyone) is currently waiting for data?  Used for sanity
    50      * checks when data arrives. */
    51     volatile uint32_t waiter;
    52     /** This mutex is grabbed during any critical operations on the clipboard
    53      * which might clash with others. */
    54     RTSEMMUTEX clipboardMutex;
    55 
    56     /** Pointer to the opaque X11 backend structure */
    57     VBOXCLIPBOARDCONTEXTX11 *pBackend;
    58     /** Pointer to the client data structure */
    59     VBOXCLIPBOARDCLIENTDATA *pClient;
    60135};
    61136
    62137/* Only one client is supported. There seems to be no need for more clients.
    63138 */
    64 static VBOXCLIPBOARDCONTEXT g_ctxHost;
    65 
    66 /**
    67  * Send a request to VBox to transfer the contents of its clipboard to X11.
    68  *
    69  * @param  pCtx      Pointer to the host clipboard structure
    70  * @param  u32Format The format in which the data should be transfered
    71  * @param  ppv       On success and if pcb > 0, this will point to a buffer
    72  *                   to be freed with RTMemFree containing the data read.
    73  * @param  pcb       On success, this contains the number of bytes of data
    74  *                   returned
    75  * @note   Host glue code.
    76  */
    77 int VBoxX11ClipboardReadVBoxData (VBOXCLIPBOARDCONTEXT *pCtx,
    78                                    uint32_t u32Format, void **ppv,
    79                                    uint32_t *pcb)
    80 {
    81     volatile VBOXCLIPBOARDCLIENTDATA *pClient = pCtx->pClient;
    82 
    83     LogFlowFunc(("u32Format=%02X\n", u32Format));
    84     if (pClient == NULL)
    85     {
    86         /* This can legitimately happen if we disconnect during a request for
    87          * data from X11. */
    88         LogFunc(("host requested guest clipboard data after guest had disconnected.\n"));
    89         VBoxX11ClipboardAnnounceVBoxFormat(pCtx->pBackend, 0);
    90         pCtx->waiter = NONE;
    91         return VERR_TIMEOUT;
    92     }
    93     /* Assert that no other transfer is in process (requests are serialised)
    94      * and that the last transfer cleaned up properly. */
    95     AssertLogRelReturn(   pClient->data.pv == NULL
    96                        && pClient->data.cb == 0
    97                        && pClient->data.u32Format == 0,
    98                        VERR_WRONG_ORDER
    99                       );
    100     /* No one else (X11 or VBox) should currently be waiting.  The first because
    101      * requests from X11 are serialised and the second because VBox previously
    102      * grabbed the clipboard, so it should not be waiting for data from us. */
    103     AssertLogRelReturn (ASMAtomicCmpXchgU32(&pCtx->waiter, X11, NONE), VERR_DEADLOCK);
    104     /* Request data from VBox */
    105     vboxSvcClipboardReportMsg(pCtx->pClient,
    106                               VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA,
    107                               u32Format);
    108     /* Which will signal us when it is ready.  We use a timeout here because
    109      * we can't be sure that the guest will behave correctly. */
    110     int rc = RTSemEventWait(pCtx->waitForData, CLIPBOARDTIMEOUT);
    111     if (rc == VERR_TIMEOUT)
    112         rc = VINF_SUCCESS;  /* Timeout handling follows. */
    113     /* Now we have a potential race between the HGCM thread delivering the data
    114      * and our setting waiter to NONE to say that we are no longer waiting for
    115      * it.  We solve this as follows: both of these operations are done under
    116      * the clipboard mutex.  The HGCM thread will only deliver the data if we
    117      * are still waiting after it acquires the mutex.  After we release the
    118      * mutex, we finally do our check to see whether the data was delivered. */
    119     RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT);
    120     pCtx->waiter = NONE;
    121     RTSemMutexRelease(g_ctxHost.clipboardMutex);
    122     AssertLogRelRCSuccess(rc);
     139static VBOXCLIPBOARDCONTEXTX11 g_ctxX11;
     140
     141/* Are we actually connected to the X server? */
     142static bool g_fHaveX11;
     143
     144/**
     145 * Convert the UTF-16 text obtained from the X11 clipboard to UTF-16LE with
     146 * Windows EOLs, place it in the buffer supplied and signal that data has
     147 * arrived.
     148 *
     149 * @param pValue      Source UTF-16 text
     150 * @param cwSourceLen Length in 16-bit words of the source text
     151 * @param pv          Where to store the converted data
     152 * @param cb          Length in bytes of the buffer pointed to by cb
     153 * @param pcbActual   Where to store the size of the converted data
     154 * @param pClient     Pointer to the client context structure
     155 * @note  X11 backend code, called from the Xt callback when we wish to read
     156 *        the X11 clipboard.
     157 */
     158static void vboxClipboardGetUtf16(XtPointer pValue, unsigned cwSrcLen,
     159                                  void *pv, unsigned cb,
     160                                  uint32_t *pcbActual)
     161{
     162    size_t cwDestLen;
     163    PRTUTF16 pu16SrcText = reinterpret_cast<PRTUTF16>(pValue);
     164    PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
     165
     166    LogFlowFunc (("converting Utf-16 to Utf-16LE.  cwSrcLen=%d, cb=%d, pu16SrcText+1=%.*ls\n",
     167                   cwSrcLen, cb, cwSrcLen - 1, pu16SrcText + 1));
     168    *pcbActual = 0;  /* Only set this to the right value on success. */
     169    /* How long will the converted text be? */
     170    int rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
     171    if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
     172    {
     173        /* Not enough buffer space provided - report the amount needed. */
     174        LogFlowFunc (("guest buffer too small: size %d bytes, needed %d.  Returning.\n",
     175                       cb, cwDestLen * 2));
     176        *pcbActual = cwDestLen * 2;
     177        rc = VERR_BUFFER_OVERFLOW;
     178    }
     179    /* Convert the text. */
     180    if (RT_SUCCESS(rc))
     181        rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
     182    if (RT_SUCCESS(rc))
     183    {
     184        LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));
     185        *pcbActual = cwDestLen * 2;
     186    }
     187    /* We need to do this whether we succeed or fail. */
     188    XtFree(reinterpret_cast<char *>(pValue));
     189    RTSemEventSignal(g_ctxX11.waitForData);
     190    LogFlowFunc(("Returning.  Status is %Rrc\n", rc));
     191}
     192
     193/**
     194 * Convert the UTF-8 text obtained from the X11 clipboard to UTF-16LE with
     195 * Windows EOLs, place it in the buffer supplied and signal that data has
     196 * arrived.
     197 *
     198 * @param pValue      Source UTF-8 text
     199 * @param cbSourceLen Length in 8-bit bytes of the source text
     200 * @param pv          Where to store the converted data
     201 * @param cb          Length in bytes of the buffer pointed to by pv
     202 * @param pcbActual   Where to store the size of the converted data
     203 * @param pClient     Pointer to the client context structure
     204 * @note  X11 backend code, called from the Xt callback when we wish to read
     205 *        the X11 clipboard.
     206 */
     207static void vboxClipboardGetUtf8FromX11(XtPointer pValue, unsigned cbSrcLen,
     208                                        void *pv, unsigned cb,
     209                                        uint32_t *pcbActual)
     210{
     211    size_t cwSrcLen, cwDestLen;
     212    char *pu8SrcText = reinterpret_cast<char *>(pValue);
     213    PRTUTF16 pu16SrcText = NULL;
     214    PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
     215
     216    LogFlowFunc (("converting Utf-8 to Utf-16LE.  cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
     217                   cbSrcLen, cb, cbSrcLen, pu8SrcText));
     218    *pcbActual = 0;  /* Only set this to the right value on success. */
     219    /* First convert the UTF8 to UTF16 */
     220    int rc = RTStrToUtf16Ex(pu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
     221    /* Check how much longer will the converted text will be. */
     222    if (RT_SUCCESS(rc))
     223        rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
     224    if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
     225    {
     226        /* Not enough buffer space provided - report the amount needed. */
     227        LogFlowFunc (("guest buffer too small: size %d bytes, needed %d.  Returning.\n",
     228                       cb, cwDestLen * 2));
     229        *pcbActual = cwDestLen * 2;
     230        rc = VERR_BUFFER_OVERFLOW;
     231    }
     232    /* Convert the text. */
     233    if (RT_SUCCESS(rc))
     234        rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
     235    if (RT_SUCCESS(rc))
     236    {
     237        LogFlowFunc (("converted string is %.*ls.\n", cwDestLen, pu16DestText));
     238        *pcbActual = cwDestLen * 2;
     239    }
     240    XtFree(reinterpret_cast<char *>(pValue));
     241    RTUtf16Free(pu16SrcText);
     242    RTSemEventSignal(g_ctxX11.waitForData);
     243    LogFlowFunc(("Returning.  Status is %Rrc", rc));
     244}
     245
     246/**
     247 * Convert the COMPOUND_TEXT obtained from the X11 clipboard to UTF-16LE with
     248 * Windows EOLs, place it in the buffer supplied and signal that data has
     249 * arrived.
     250 *
     251 * @param pValue      Source COMPOUND_TEXT
     252 * @param cbSourceLen Length in 8-bit bytes of the source text
     253 * @param pv          Where to store the converted data
     254 * @param cb          Length in bytes of the buffer pointed to by pv
     255 * @param pcbActual   Where to store the size of the converted data
     256 * @param pClient     Pointer to the client context structure
     257 * @note  X11 backend code, called from the Xt callback when we wish to read
     258 *        the X11 clipboard.
     259 */
     260static void vboxClipboardGetCTextFromX11(XtPointer pValue, unsigned cbSrcLen,
     261                                         void *pv, unsigned cb,
     262                                         uint32_t *pcbActual)
     263{
     264    size_t cwSrcLen, cwDestLen;
     265    char **ppu8SrcText = NULL;
     266    PRTUTF16 pu16SrcText = NULL;
     267    PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
     268    XTextProperty property;
     269    int rc = VINF_SUCCESS;
     270    int cProps;
     271
     272    LogFlowFunc (("converting COMPOUND TEXT to Utf-16LE.  cbSrcLen=%d, cb=%d, pu8SrcText=%.*s\n",
     273                   cbSrcLen, cb, cbSrcLen, reinterpret_cast<char *>(pValue)));
     274    *pcbActual = 0;  /* Only set this to the right value on success. */
     275    /* First convert the compound text to Utf8 */
     276    property.value = reinterpret_cast<unsigned char *>(pValue);
     277    property.encoding = g_ctxX11.atomCText;
     278    property.format = 8;
     279    property.nitems = cbSrcLen;
     280#ifdef RT_OS_SOLARIS
     281    int xrc = XmbTextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps);
     282#else
     283    int xrc = Xutf8TextPropertyToTextList(XtDisplay(g_ctxX11.widget), &property, &ppu8SrcText, &cProps);
     284#endif
     285    XtFree(reinterpret_cast<char *>(pValue));
     286    if (xrc < 0)
     287        switch(xrc)
     288        {
     289        case XNoMemory:
     290            rc = VERR_NO_MEMORY;
     291            break;
     292        case XLocaleNotSupported:
     293        case XConverterNotFound:
     294            rc = VERR_NOT_SUPPORTED;
     295            break;
     296        default:
     297            rc = VERR_UNRESOLVED_ERROR;
     298        }
     299    /* Now convert the UTF8 to UTF16 */
     300    if (RT_SUCCESS(rc))
     301        rc = RTStrToUtf16Ex(*ppu8SrcText, cbSrcLen, &pu16SrcText, 0, &cwSrcLen);
     302    /* Check how much longer will the converted text will be. */
     303    if (RT_SUCCESS(rc))
     304        rc = vboxClipboardUtf16GetWinSize(pu16SrcText, cwSrcLen, &cwDestLen);
     305    if (RT_SUCCESS(rc) && (cb < cwDestLen * 2))
     306    {
     307        /* Not enough buffer space provided - report the amount needed. */
     308        LogFlowFunc (("guest buffer too small: size %d bytes, needed %d.  Returning.\n",
     309                       cb, cwDestLen * 2));
     310        *pcbActual = cwDestLen * 2;
     311        rc = VERR_BUFFER_OVERFLOW;
     312    }
     313    /* Convert the text. */
     314    if (RT_SUCCESS(rc))
     315        rc = vboxClipboardUtf16LinToWin(pu16SrcText, cwSrcLen, pu16DestText, cb / 2);
     316    if (RT_SUCCESS(rc))
     317    {
     318        LogFlowFunc (("converted string is %.*ls\n", cwDestLen, pu16DestText));
     319        *pcbActual = cwDestLen * 2;
     320    }
     321    if (ppu8SrcText != NULL)
     322        XFreeStringList(ppu8SrcText);
     323    RTUtf16Free(pu16SrcText);
     324    LogFlowFunc(("Returning.  Status is %Rrc\n", rc));
     325    RTSemEventSignal(g_ctxX11.waitForData);
     326}
     327
     328/**
     329 * Convert the Latin1 text obtained from the X11 clipboard to UTF-16LE with
     330 * Windows EOLs, place it in the buffer supplied and signal that data has
     331 * arrived.
     332 *
     333 * @param pValue      Source Latin1 text
     334 * @param cbSourceLen Length in 8-bit bytes of the source text
     335 * @param pv          Where to store the converted data
     336 * @param cb          Length in bytes of the buffer pointed to by cb
     337 * @param pcbActual   Where to store the size of the converted data
     338 * @param pClient     Pointer to the client context structure
     339 * @note  X11 backend code, called from the Xt callback when we wish to read
     340 *        the X11 clipboard.
     341 */
     342static void vboxClipboardGetLatin1FromX11(XtPointer pValue,
     343                                          unsigned cbSourceLen, void *pv,
     344                                          unsigned cb, uint32_t *pcbActual)
     345{
     346    unsigned cwDestLen = cbSourceLen + 1;
     347    char *pu8SourceText = reinterpret_cast<char *>(pValue);
     348    PRTUTF16 pu16DestText = reinterpret_cast<PRTUTF16>(pv);
     349    int rc = VINF_SUCCESS;
     350
     351    LogFlowFunc (("converting Latin1 to Utf-16LE.  Original is %.*s\n",
     352                  cbSourceLen, pu8SourceText));
     353    *pcbActual = 0;  /* Only set this to the right value on success. */
     354    for (unsigned i = 0; i < cbSourceLen; i++)
     355        if (pu8SourceText[i] == LINEFEED)
     356            ++cwDestLen;
     357    if (cb < cwDestLen * 2)
     358    {
     359        /* Not enough buffer space provided - report the amount needed. */
     360        LogFlowFunc (("guest buffer too small: size %d bytes\n", cb));
     361        *pcbActual = cwDestLen * 2;
     362        rc = VERR_BUFFER_OVERFLOW;
     363    }
     364    if (RT_SUCCESS(rc))
     365    {
     366        for (unsigned i = 0, j = 0; i < cbSourceLen; ++i, ++j)
     367            if (pu8SourceText[i] != LINEFEED)
     368                pu16DestText[j] = pu8SourceText[i];  /* latin1 < utf-16LE */
     369            else
     370            {
     371                pu16DestText[j] = CARRIAGERETURN;
     372                ++j;
     373                pu16DestText[j] = LINEFEED;
     374            }
     375        pu16DestText[cwDestLen - 1] = 0;
     376        *pcbActual = cwDestLen * 2;
     377        LogFlowFunc (("converted text is %.*ls\n", cwDestLen, pu16DestText));
     378    }
     379    XtFree(reinterpret_cast<char *>(pValue));
     380    RTSemEventSignal(g_ctxX11.waitForData);
     381    LogFlowFunc(("Returning.  Status is %Rrc\n", rc));
     382}
     383
     384/**
     385 * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows
     386 * EOLs, place it in the buffer supplied and signal that data has arrived.
     387 * @note  X11 backend code, callback for XtGetSelectionValue, for use when
     388 *        the X11 clipboard contains a text format we understand.
     389 */
     390static void vboxClipboardGetDataFromX11(Widget, XtPointer pClientData,
     391                                        Atom * /* selection */,
     392                                        Atom *atomType,
     393                                        XtPointer pValue,
     394                                        long unsigned int *pcLen,
     395                                        int *piFormat)
     396{
     397    VBOXCLIPBOARDREQUEST *pRequest
     398        = reinterpret_cast<VBOXCLIPBOARDREQUEST *>(pClientData);
     399    LogFlowFunc(("pClientData=%p, *pcLen=%lu, *piFormat=%d\n", pClientData,
     400                 *pcLen, *piFormat));
     401    LogFlowFunc(("g_ctxX11.X11TextFormat=%d, pRequest->cb=%d\n",
     402                 g_ctxX11.X11TextFormat, pRequest->cb));
     403    unsigned cTextLen = (*pcLen) * (*piFormat) / 8;
     404    /* The X Toolkit may have failed to get the clipboard selection for us. */
     405    if (*atomType == XT_CONVERT_FAIL)
     406        return;
     407    /* The clipboard selection may have changed before we could get it. */
     408    if (NULL == pValue)
     409        return;
     410    /* In which format is the clipboard data? */
     411    switch (g_ctxX11.X11TextFormat)
     412    {
     413    case UTF16:
     414        vboxClipboardGetUtf16(pValue, cTextLen / 2, pRequest->pv,
     415                              pRequest->cb, pRequest->pcbActual);
     416        break;
     417    case CTEXT:
     418        vboxClipboardGetCTextFromX11(pValue, cTextLen, pRequest->pv,
     419                                     pRequest->cb, pRequest->pcbActual);
     420        break;
     421    case UTF8:
     422    {
     423        /* If we are given broken Utf-8, we treat it as Latin1.  Is this acceptable? */
     424        size_t cStringLen;
     425        char *pu8SourceText = reinterpret_cast<char *>(pValue);
     426
     427        if ((g_ctxX11.X11TextFormat == UTF8)
     428            && (RTStrUniLenEx(pu8SourceText, *pcLen, &cStringLen) == VINF_SUCCESS))
     429        {
     430            vboxClipboardGetUtf8FromX11(pValue, cTextLen, pRequest->pv,
     431                                     pRequest->cb, pRequest->pcbActual);
     432            break;
     433        }
     434        else
     435        {
     436            vboxClipboardGetLatin1FromX11(pValue, cTextLen, pRequest->pv,
     437                                     pRequest->cb, pRequest->pcbActual);
     438            break;
     439        }
     440    }
     441    default:
     442        LogFunc (("bad target format\n"));
     443        XtFree(reinterpret_cast<char *>(pValue));
     444        return;
     445    }
     446    g_ctxX11.notifyVBox = true;
     447}
     448
     449/**
     450 * Notify the host clipboard about the data formats we support, based on the
     451 * "targets" (available data formats) information obtained from the X11
     452 * clipboard.
     453 * @note  X11 backend code, callback for XtGetSelectionValue, called when we
     454 *        poll for available targets.
     455 */
     456static void vboxClipboardGetTargetsFromX11(Widget,
     457                                           XtPointer /* pClientData */,
     458                                           Atom * /* selection */,
     459                                           Atom *atomType,
     460                                           XtPointer pValue,
     461                                           long unsigned int *pcLen,
     462                                           int *piFormat)
     463{
     464    Atom *atomTargets = reinterpret_cast<Atom *>(pValue);
     465    unsigned cAtoms = *pcLen;
     466    g_eClipboardFormats eBestTarget = INVALID;
     467    Atom atomBestTarget = None;
     468
     469    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
     470    if (*atomType == XT_CONVERT_FAIL)
     471    {
     472        LogFunc (("reading clipboard from host, X toolkit failed to convert the selection\n"));
     473        return;
     474    }
     475
     476    for (unsigned i = 0; i < cAtoms; ++i)
     477    {
     478        for (unsigned j = 0; j != g_ctxX11.formatList.size(); ++j)
     479            if (g_ctxX11.formatList[j].atom == atomTargets[i])
     480            {
     481                if (eBestTarget < g_ctxX11.formatList[j].format)
     482                {
     483                    eBestTarget = g_ctxX11.formatList[j].format;
     484                    atomBestTarget = g_ctxX11.formatList[j].atom;
     485                }
     486                break;
     487            }
     488        if (g_debugClipboard)
     489        {
     490            char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);
     491            if (szAtomName != 0)
     492            {
     493                Log2 (("%s: the host offers target %s\n", __PRETTY_FUNCTION__,
     494                       szAtomName));
     495                XFree(szAtomName);
     496            }
     497        }
     498    }
     499    g_ctxX11.atomX11TextFormat = atomBestTarget;
     500    if ((eBestTarget != g_ctxX11.X11TextFormat) || (g_ctxX11.notifyVBox == true))
     501    {
     502        uint32_t u32Formats = 0;
     503        if (g_debugClipboard)
     504        {
     505            if (atomBestTarget != None)
     506            {
     507                char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomBestTarget);
     508                Log2 (("%s: switching to host text target %s.  Available targets are:\n",
     509                       __PRETTY_FUNCTION__, szAtomName));
     510                XFree(szAtomName);
     511            }
     512            else
     513                Log2(("%s: no supported host text target found.  Available targets are:\n",
     514                      __PRETTY_FUNCTION__));
     515            for (unsigned i = 0; i < cAtoms; ++i)
     516            {
     517                char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);
     518                if (szAtomName != 0)
     519                {
     520                    Log2 (("%s:     %s\n", __PRETTY_FUNCTION__, szAtomName));
     521                    XFree(szAtomName);
     522                }
     523            }
     524        }
     525        g_ctxX11.X11TextFormat = eBestTarget;
     526        if (eBestTarget != INVALID)
     527            u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
     528        VBoxX11ClipboardReportX11Formats(g_ctxX11.pFrontend, u32Formats);
     529        g_ctxX11.notifyVBox = false;
     530    }
     531    XtFree(reinterpret_cast<char *>(pValue));
     532}
     533
     534/**
     535 * This timer callback is called every 200ms to check the contents of the X11
     536 * clipboard.
     537 * @note  X11 backend code, callback for XtAppAddTimeOut, recursively
     538 *        re-armed.
     539 * @todo  Use the XFIXES extension to check for new clipboard data when
     540 *        available.
     541 */
     542static void vboxClipboardPollX11ForTargets(XtPointer /* pUserData */, XtIntervalId * /* hTimerId */)
     543{
     544    Log3 (("%s: called\n", __PRETTY_FUNCTION__));
     545    /* Get the current clipboard contents */
     546    if (g_ctxX11.eOwner == X11)
     547    {
     548        Log3 (("%s: requesting the targets that the host clipboard offers\n",
     549               __PRETTY_FUNCTION__));
     550        XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard,
     551                            g_ctxX11.atomTargets,
     552                            vboxClipboardGetTargetsFromX11, NULL,
     553                            CurrentTime);
     554    }
     555    /* Re-arm our timer */
     556    XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */,
     557                    vboxClipboardPollX11ForTargets, 0);
     558}
     559
     560/** We store information about the target formats we can handle in a global
     561 * vector for internal use.
     562 * @note  X11 backend code.
     563 */
     564static void vboxClipboardAddFormat(const char *pszName, g_eClipboardFormats eFormat,
     565                                   unsigned guestFormat)
     566{
     567    VBOXCLIPBOARDFORMAT sFormat;
     568    /* Get an atom from the X server for that target format */
     569    Atom atomFormat = XInternAtom(XtDisplay(g_ctxX11.widget), pszName, false);
     570    sFormat.atom   = atomFormat;
     571    sFormat.format = eFormat;
     572    sFormat.guestFormat = guestFormat;
     573    g_ctxX11.formatList.push_back(sFormat);
     574    LogFlow (("vboxClipboardAddFormat: added format %s (%d)\n", pszName, eFormat));
     575}
     576
     577/**
     578 * The main loop of our clipboard reader.
     579 * @note  X11 backend code.
     580 */
     581static int vboxClipboardThread(RTTHREAD self, void * /* pvUser */)
     582{
     583    LogRel(("Shared clipboard: starting host clipboard thread\n"));
     584
     585    /* Set up a timer to poll the host clipboard */
     586    XtAppAddTimeOut(g_ctxX11.appContext, 200 /* ms */, vboxClipboardPollX11ForTargets, 0);
     587
     588    XtAppMainLoop(g_ctxX11.appContext);
     589    g_ctxX11.formatList.clear();
     590    LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
     591    return VINF_SUCCESS;
     592}
     593
     594/** X11 specific initialisation for the shared clipboard.
     595 * @note  X11 backend code.
     596 */
     597static int vboxClipboardInitX11 (void)
     598{
     599    /* Create a window and make it a clipboard viewer. */
     600    int cArgc = 0;
     601    char *pcArgv = 0;
     602    int rc = VINF_SUCCESS;
     603    // static String szFallbackResources[] = { (char*)"*.width: 1", (char*)"*.height: 1", NULL };
     604    Display *pDisplay;
     605
     606    /* Make sure we are thread safe */
     607    XtToolkitThreadInitialize();
     608    /* Set up the Clipbard application context and main window.  We call all these functions
     609       directly instead of calling XtOpenApplication() so that we can fail gracefully if we
     610       can't get an X11 display. */
     611    XtToolkitInitialize();
     612    g_ctxX11.appContext = XtCreateApplicationContext();
     613    // XtAppSetFallbackResources(g_ctxX11.appContext, szFallbackResources);
     614    pDisplay = XtOpenDisplay(g_ctxX11.appContext, 0, 0, "VBoxClipboard", 0, 0, &cArgc, &pcArgv);
     615    if (NULL == pDisplay)
     616    {
     617        LogRel(("Shared clipboard: failed to connect to the host clipboard - the window system may not be running.\n"));
     618        rc = VERR_NOT_SUPPORTED;
     619    }
     620    if (RT_SUCCESS(rc))
     621    {
     622        g_ctxX11.widget = XtVaAppCreateShell(0, "VBoxClipboard", applicationShellWidgetClass, pDisplay,
     623                                          XtNwidth, 1, XtNheight, 1, NULL);
     624        if (NULL == g_ctxX11.widget)
     625        {
     626            LogRel(("Shared clipboard: failed to construct the X11 window for the host clipboard manager.\n"));
     627            rc = VERR_NO_MEMORY;
     628        }
     629    }
     630    if (RT_SUCCESS(rc))
     631    {
     632        XtSetMappedWhenManaged(g_ctxX11.widget, false);
     633        XtRealizeWidget(g_ctxX11.widget);
     634
     635        /* Get hold of the atoms which we need */
     636        g_ctxX11.atomClipboard = XInternAtom(XtDisplay(g_ctxX11.widget), "CLIPBOARD", false /* only_if_exists */);
     637        g_ctxX11.atomPrimary   = XInternAtom(XtDisplay(g_ctxX11.widget), "PRIMARY",   false);
     638        g_ctxX11.atomTargets   = XInternAtom(XtDisplay(g_ctxX11.widget), "TARGETS",   false);
     639        g_ctxX11.atomMultiple  = XInternAtom(XtDisplay(g_ctxX11.widget), "MULTIPLE",  false);
     640        g_ctxX11.atomTimestamp = XInternAtom(XtDisplay(g_ctxX11.widget), "TIMESTAMP", false);
     641        g_ctxX11.atomUtf16     = XInternAtom(XtDisplay(g_ctxX11.widget),
     642                                          "text/plain;charset=ISO-10646-UCS-2", false);
     643        g_ctxX11.atomUtf8      = XInternAtom(XtDisplay(g_ctxX11.widget), "UTF_STRING", false);
     644        /* And build up the vector of supported formats */
     645        g_ctxX11.atomCText     = XInternAtom(XtDisplay(g_ctxX11.widget), "COMPOUND_TEXT", false);
     646        /* And build up the vector of supported formats */
     647        if (!g_testUtf8 && !g_testCText)
     648            vboxClipboardAddFormat("text/plain;charset=ISO-10646-UCS-2", UTF16,
     649                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     650        if (!g_testUtf16 && !g_testCText)
     651        {
     652            vboxClipboardAddFormat("UTF8_STRING", UTF8,
     653                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     654            vboxClipboardAddFormat("text/plain;charset=UTF-8", UTF8,
     655                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     656            vboxClipboardAddFormat("text/plain;charset=utf-8", UTF8,
     657                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     658            vboxClipboardAddFormat("STRING", UTF8,
     659                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     660            vboxClipboardAddFormat("TEXT", UTF8,
     661                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     662            vboxClipboardAddFormat("text/plain", UTF8,
     663                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     664}
     665        if (!g_testUtf16 && !g_testUtf8)
     666            vboxClipboardAddFormat("COMPOUND_TEXT", CTEXT,
     667                                   VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT);
     668    }
     669    return rc;
     670}
     671
     672/**
     673 * Initialise the X11 backend of the shared clipboard.
     674 * @note  X11 backend code
     675 */
     676int VBoxX11ClipboardInitX11(VBOXCLIPBOARDCONTEXT *pFrontend,
     677                            VBOXCLIPBOARDCONTEXTX11 **ppBackend)
     678{
     679    int rc;
     680
     681    if (!RTEnvGet("DISPLAY"))
     682    {
     683        /*
     684         * If we don't find the DISPLAY environment variable we assume that we are not
     685         * connected to an X11 server. Don't actually try to do this then, just fail
     686         * silently and report success on every call. This is important for VBoxHeadless.
     687         */
     688        LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n"));
     689        g_fHaveX11 = false;
     690        return VINF_SUCCESS;
     691    }
     692
     693    if (RTEnvGet("VBOX_CBTEST_UTF16"))
     694    {
     695        g_testUtf16 = true;
     696        LogRel(("Host clipboard: testing Utf16\n"));
     697    }
     698    else if (RTEnvGet("VBOX_CBTEST_UTF8"))
     699    {
     700        g_testUtf8 = true;
     701        LogRel(("Host clipboard: testing Utf8\n"));
     702    }
     703    else if (RTEnvGet("VBOX_CBTEST_CTEXT"))
     704    {
     705        g_testCText = true;
     706        LogRel(("Host clipboard: testing compound text\n"));
     707    }
     708    else if (RTEnvGet("VBOX_CBDEBUG"))
     709    {
     710        g_debugClipboard = true;
     711        LogRel(("Host clipboard: enabling additional debugging output\n"));
     712    }
     713
     714    g_fHaveX11 = true;
     715
     716    LogRel(("Initializing X11 clipboard backend\n"));
     717    g_ctxX11.pFrontend = pFrontend;
     718    RTSemEventCreate(&g_ctxX11.waitForData);
     719    rc = vboxClipboardInitX11();
     720    if (RT_SUCCESS(rc))
     721    {
     722        rc = RTThreadCreate(&g_ctxX11.thread, vboxClipboardThread, 0, 0,
     723                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
     724        if (RT_FAILURE(rc))
     725            LogRel(("Failed to initialise the shared clipboard X11 backend.\n"));
     726    }
    123727    if (RT_FAILURE(rc))
    124     {
    125         /* I believe this should not happen.  Wait until the assertions arrive
    126          * to prove the contrary. */
    127         RTMemFree(pClient->data.pv);
    128         g_ctxHost.pClient->data.pv = 0;
    129         g_ctxHost.pClient->data.cb = 0;
    130         g_ctxHost.pClient->data.u32Format = 0;
    131         vboxClipboardFormatAnnounce(NULL, 0);
    132         return rc;
    133     }
    134     if (pClient->data.pv == NULL)
    135         return VERR_TIMEOUT;
    136     LogFlowFunc(("wait completed.  Returning.\n"));
    137     *ppv = pClient->data.pv;
    138     *pcb = pClient->data.cb;
    139     g_ctxHost.pClient->data.pv = 0;
    140     g_ctxHost.pClient->data.cb = 0;
    141     g_ctxHost.pClient->data.u32Format = 0;
     728        RTSemEventDestroy(g_ctxX11.waitForData);
     729    return rc;
     730}
     731
     732/**
     733 * Terminate the shared clipboard X11 backend.
     734 * @note  X11 backend code
     735 */
     736int VBoxX11ClipboardTermX11(VBOXCLIPBOARDCONTEXTX11 *pBackend)
     737{
     738    int rc, rcThread;
     739    unsigned count = 0;
     740    XEvent ev;
     741
     742    /*
     743     * Immediately return if we are not connected to the host X server.
     744     */
     745    if (!g_fHaveX11)
     746        return VINF_SUCCESS;
     747
     748    LogRelFunc(("shutting down the shared clipboard X11 backend\n"));
     749
     750    /* Set the termination flag.  This has been observed to block if it was set
     751     * during a request for clipboard data coming from X11, so only we do it
     752     * after releasing any such requests. */
     753    XtAppSetExitFlag(g_ctxX11.appContext);
     754    /* Wake up the event loop */
     755    memset(&ev, 0, sizeof(ev));
     756    ev.xclient.type = ClientMessage;
     757    ev.xclient.format = 8;
     758    XSendEvent(XtDisplay(g_ctxX11.widget), XtWindow(g_ctxX11.widget), false, 0, &ev);
     759    XFlush(XtDisplay(g_ctxX11.widget));
     760    do
     761    {
     762        rc = RTThreadWait(g_ctxX11.thread, 1000, &rcThread);
     763        ++count;
     764        Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
     765    } while ((VERR_TIMEOUT == rc) && (count < 300));
     766    if (RT_SUCCESS(rc))
     767    {
     768        /* We can safely destroy this now, as only this thread ever waits
     769         * for it. */
     770        RTSemEventDestroy(g_ctxX11.waitForData);
     771        AssertRC(rcThread);
     772    }
     773    else
     774        LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc));
     775    XtCloseDisplay(XtDisplay(g_ctxX11.widget));
     776    LogFlowFunc(("returning %Rrc.\n", rc));
     777    return rc;
     778}
     779
     780/**
     781 * Announce to the X11 backend that we are ready to start.
     782 * @param  owner who is the initial clipboard owner
     783 */
     784int VBoxX11ClipboardStartX11(VBOXCLIPBOARDCONTEXTX11 *pBackend,
     785                             enum g_eOwner owner)
     786{
     787    LogFlowFunc(("\n"));
     788    /*
     789     * Immediately return if we are not connected to the host X server.
     790     */
     791    if (!g_fHaveX11)
     792        return VINF_SUCCESS;
     793
     794    g_ctxX11.eOwner = owner;
     795    if (owner == X11)
     796        g_ctxX11.notifyVBox = true;
     797    else
     798    {
     799        /** @todo Check whether the guest gets a format announcement at
     800          *       startup. */
     801        VBoxX11ClipboardAnnounceVBoxFormat(pBackend, 0);
     802    }
    142803    return VINF_SUCCESS;
    143804}
    144805
    145806/**
    146  * Report formats available in the X11 clipboard to VBox.
    147  * @param  pCtx        Opaque context pointer for the glue code
    148  * @param  u32Formats  The formats available
    149  * @note  Host glue code
    150  */
    151 void VBoxX11ClipboardReportX11Formats(VBOXCLIPBOARDCONTEXT *pCtx,
    152                                       uint32_t u32Formats)
    153 {
    154     vboxSvcClipboardReportMsg(pCtx->pClient,
    155                               VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS,
    156                               u32Formats);
    157 }
    158 
    159 /**
    160  * Initialise the host side of the shared clipboard.
    161  * @note  Host glue code
    162  */
    163 int vboxClipboardInit (void)
    164 {
    165     int rc = VINF_SUCCESS;
    166     VBOXCLIPBOARDCONTEXTX11 *pBackend = NULL;
    167 
    168     LogRel(("Initializing host clipboard service\n"));
    169     RTSemEventCreate(&g_ctxHost.waitForData);
    170     RTSemMutexCreate(&g_ctxHost.clipboardMutex);
    171     rc = VBoxX11ClipboardInitX11(&g_ctxHost, &pBackend);
     807 * Called when the VBox may have fallen out of sync with the backend.
     808 * @note  X11 backend code
     809 */
     810void VBoxX11ClipboardRequestSyncX11(VBOXCLIPBOARDCONTEXTX11 *pBackend)
     811{
     812    /*
     813     * Immediately return if we are not connected to the host X server.
     814     */
     815    if (!g_fHaveX11)
     816        return;
     817    g_ctxX11.notifyVBox = true;
     818}
     819
     820/**
     821 * Shut down the shared clipboard X11 backend.
     822 * @note  X11 backend code
     823 */
     824void VBoxX11ClipboardStopX11(VBOXCLIPBOARDCONTEXTX11 *pBackend)
     825{
     826    /*
     827     * Immediately return if we are not connected to the host X server.
     828     */
     829    if (!g_fHaveX11)
     830        return;
     831
     832    g_ctxX11.eOwner = NONE;
     833    g_ctxX11.X11TextFormat = INVALID;
     834    g_ctxX11.X11BitmapFormat = INVALID;
     835}
     836
     837/**
     838 * Satisfy a request from X11 for clipboard targets supported by VBox.
     839 *
     840 * @returns true if we successfully convert the data to the format
     841 *          requested, false otherwise.
     842 *
     843 * @param  atomTypeReturn The type of the data we are returning
     844 * @param  pValReturn     A pointer to the data we are returning.  This
     845 *                        should be set to memory allocated by XtMalloc,
     846 *                        which will be freed later by the Xt toolkit.
     847 * @param  pcLenReturn    The length of the data we are returning
     848 * @param  piFormatReturn The format (8bit, 16bit, 32bit) of the data we are
     849 *                        returning
     850 * @note  X11 backend code, called by the XtOwnSelection callback.
     851 */
     852static Boolean vboxClipboardConvertTargetsForX11(Atom *atomTypeReturn,
     853                                                 XtPointer *pValReturn,
     854                                                 unsigned long *pcLenReturn,
     855                                                 int *piFormatReturn)
     856{
     857    unsigned uListSize = g_ctxX11.formatList.size();
     858    Atom *atomTargets = reinterpret_cast<Atom *>(XtMalloc((uListSize + 3) * sizeof(Atom)));
     859    unsigned cTargets = 0;
     860
     861    LogFlowFunc (("called\n"));
     862    for (unsigned i = 0; i < uListSize; ++i)
     863    {
     864        if (   ((g_ctxX11.vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) != 0)
     865            && (g_ctxX11.formatList[i].guestFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT))
     866        {
     867            atomTargets[cTargets] = g_ctxX11.formatList[i].atom;
     868            ++cTargets;
     869        }
     870    }
     871    atomTargets[cTargets] = g_ctxX11.atomTargets;
     872    atomTargets[cTargets + 1] = g_ctxX11.atomMultiple;
     873    atomTargets[cTargets + 2] = g_ctxX11.atomTimestamp;
     874    if (g_debugClipboard)
     875    {
     876        for (unsigned i = 0; i < cTargets + 3; i++)
     877        {
     878            char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), atomTargets[i]);
     879            if (szAtomName != 0)
     880            {
     881                Log2 (("%s: returning target %s\n", __PRETTY_FUNCTION__,
     882                       szAtomName));
     883                XFree(szAtomName);
     884            }
     885            else
     886            {
     887                Log(("%s: invalid atom %d in the list!\n", __PRETTY_FUNCTION__,
     888                     atomTargets[i]));
     889            }
     890        }
     891    }
     892    *atomTypeReturn = XA_ATOM;
     893    *pValReturn = reinterpret_cast<XtPointer>(atomTargets);
     894    *pcLenReturn = cTargets + 3;
     895    *piFormatReturn = 32;
     896    return true;
     897}
     898
     899/**
     900 * Satisfy a request from X11 to convert the clipboard text to Utf16.  We
     901 * return non-zero terminated text.
     902 * @todo that works, but it is bad.  Change it to return zero-terminated
     903 *       text.
     904 *
     905 * @returns true if we successfully convert the data to the format
     906 * requested, false otherwise.
     907 *
     908 * @param  atomTypeReturn  Where to store the atom for the type of the data
     909 *                         we are returning
     910 * @param  pValReturn      Where to store the pointer to the data we are
     911 *                         returning.  This should be to memory allocated by
     912 *                         XtMalloc, which will be freed by the Xt toolkit
     913 *                         later.
     914 * @param  pcLenReturn     Where to store the length of the data we are
     915 *                         returning
     916 * @param  piFormatReturn  Where to store the bit width (8, 16, 32) of the
     917 *                         data we are returning
     918 * @note  X11 backend code, called by the callback for XtOwnSelection.
     919 */
     920static Boolean vboxClipboardConvertUtf16(Atom *atomTypeReturn,
     921                                         XtPointer *pValReturn,
     922                                         unsigned long *pcLenReturn,
     923                                         int *piFormatReturn)
     924{
     925    PRTUTF16 pu16SrcText, pu16DestText;
     926    void *pvVBox;
     927    uint32_t cbVBox;
     928    size_t cwSrcLen, cwDestLen;
     929    int rc;
     930
     931    LogFlowFunc (("called\n"));
     932    rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);
     933    if ((RT_FAILURE(rc)) || (cbVBox == 0))
     934    {
     935        /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */
     936        LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,
     937                    RT_SUCCESS(rc) ? ", cbVBox == 0" :  ""));
     938        RTMemFree(pvVBox);
     939        return false;
     940    }
     941    pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);
     942    cwSrcLen = cbVBox / 2;
     943    /* How long will the converted text be? */
     944    rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
    172945    if (RT_FAILURE(rc))
    173946    {
    174         RTSemEventDestroy(g_ctxHost.waitForData);
    175         RTSemMutexDestroy(g_ctxHost.clipboardMutex);
    176         LogRel(("Failed to start the host shared clipboard service.\n"));
     947        LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed.  vboxClipboardUtf16GetLinSize returned %Rrc.  Abandoning.\n", rc));
     948        RTMemFree(pvVBox);
     949        AssertRCReturn(rc, false);
     950    }
     951    if (cwDestLen == 0)
     952    {
     953        LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
     954        RTMemFree(pvVBox);
     955        return false;
     956    }
     957    pu16DestText = reinterpret_cast<PRTUTF16>(XtMalloc(cwDestLen * 2));
     958    if (pu16DestText == 0)
     959    {
     960        LogRel(("vboxClipboardConvertUtf16: failed to allocate %d bytes\n", cwDestLen * 2));
     961        RTMemFree(pvVBox);
     962        return false;
     963    }
     964    /* Convert the text. */
     965    rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
     966    if (RT_FAILURE(rc))
     967    {
     968        LogRel(("vboxClipboardConvertUtf16: clipboard conversion failed.  vboxClipboardUtf16WinToLin returned %Rrc.  Abandoning.\n", rc));
     969        XtFree(reinterpret_cast<char *>(pu16DestText));
     970        RTMemFree(pvVBox);
     971        return false;
     972    }
     973    LogFlowFunc (("converted string is %.*ls. Returning.\n", cwDestLen, pu16DestText));
     974    RTMemFree(pvVBox);
     975    *atomTypeReturn = g_ctxX11.atomUtf16;
     976    *pValReturn = reinterpret_cast<XtPointer>(pu16DestText);
     977    *pcLenReturn = cwDestLen;
     978    *piFormatReturn = 16;
     979    return true;
     980}
     981
     982/**
     983 * Satisfy a request from X11 to convert the clipboard text to Utf8.  We
     984 * return non-zero terminated text.
     985 * @todo that works, but it is bad.  Change it to return zero-terminated
     986 *       text.
     987 *
     988 * @returns true if we successfully convert the data to the format
     989 * requested, false otherwise.
     990 *
     991 * @param  atomTypeReturn  Where to store the atom for the type of the data
     992 *                         we are returning
     993 * @param  pValReturn      Where to store the pointer to the data we are
     994 *                         returning.  This should be to memory allocated by
     995 *                         XtMalloc, which will be freed by the Xt toolkit
     996 *                         later.
     997 * @param  pcLenReturn     Where to store the length of the data we are
     998 *                         returning
     999 * @param  piFormatReturn  Where to store the bit width (8, 16, 32) of the
     1000 *                         data we are returning
     1001 * @note  X11 backend code, called by the callback for XtOwnSelection.
     1002 */
     1003static Boolean vboxClipboardConvertToUtf8ForX11(Atom *atomTypeReturn,
     1004                                                XtPointer *pValReturn,
     1005                                                unsigned long *pcLenReturn,
     1006                                                int *piFormatReturn)
     1007{
     1008    PRTUTF16 pu16SrcText, pu16DestText;
     1009    char *pu8DestText;
     1010    void *pvVBox;
     1011    uint32_t cbVBox;
     1012    size_t cwSrcLen, cwDestLen, cbDestLen;
     1013    int rc;
     1014
     1015    LogFlowFunc (("called\n"));
     1016    /* Read the clipboard data from the guest. */
     1017    rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);
     1018    if ((rc != VINF_SUCCESS) || (cbVBox == 0))
     1019    {
     1020        /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */
     1021        LogRelFunc (("VBoxX11ClipboardReadVBoxData returned %Rrc%s\n", rc,
     1022                     RT_SUCCESS(rc) ? ", cbVBox == 0" :  ""));
     1023        RTMemFree(pvVBox);
     1024        return false;
     1025    }
     1026    pu16SrcText = reinterpret_cast<PRTUTF16>(pvVBox);
     1027    cwSrcLen = cbVBox / 2;
     1028    /* How long will the converted text be? */
     1029    rc = vboxClipboardUtf16GetLinSize(pu16SrcText, cwSrcLen, &cwDestLen);
     1030    if (RT_FAILURE(rc))
     1031    {
     1032        LogRelFunc (("clipboard conversion failed.  vboxClipboardUtf16GetLinSize returned %Rrc.  Abandoning.\n", rc));
     1033        RTMemFree(pvVBox);
     1034        AssertRCReturn(rc, false);
     1035    }
     1036    if (cwDestLen == 0)
     1037    {
     1038        LogFlowFunc(("received empty clipboard data from the guest, returning false.\n"));
     1039        RTMemFree(pvVBox);
     1040        return false;
     1041    }
     1042    pu16DestText = reinterpret_cast<PRTUTF16>(RTMemAlloc(cwDestLen * 2));
     1043    if (pu16DestText == 0)
     1044    {
     1045        LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 2));
     1046        RTMemFree(pvVBox);
     1047        return false;
     1048    }
     1049    /* Convert the text. */
     1050    rc = vboxClipboardUtf16WinToLin(pu16SrcText, cwSrcLen, pu16DestText, cwDestLen);
     1051    if (RT_FAILURE(rc))
     1052    {
     1053        LogRelFunc (("clipboard conversion failed.  vboxClipboardUtf16WinToLin() returned %Rrc.  Abandoning.\n", rc));
     1054        RTMemFree(reinterpret_cast<void *>(pu16DestText));
     1055        RTMemFree(pvVBox);
     1056        return false;
     1057    }
     1058    /* Allocate enough space, as RTUtf16ToUtf8Ex may fail if the
     1059       space is too tightly calculated. */
     1060    pu8DestText = XtMalloc(cwDestLen * 4);
     1061    if (pu8DestText == 0)
     1062    {
     1063        LogRelFunc (("failed to allocate %d bytes\n", cwDestLen * 4));
     1064        RTMemFree(reinterpret_cast<void *>(pu16DestText));
     1065        RTMemFree(pvVBox);
     1066        return false;
     1067    }
     1068    /* Convert the Utf16 string to Utf8. */
     1069    rc = RTUtf16ToUtf8Ex(pu16DestText + 1, cwDestLen - 1, &pu8DestText, cwDestLen * 4,
     1070                         &cbDestLen);
     1071    RTMemFree(reinterpret_cast<void *>(pu16DestText));
     1072    if (RT_FAILURE(rc))
     1073    {
     1074        LogRelFunc (("clipboard conversion failed.  RTUtf16ToUtf8Ex() returned %Rrc.  Abandoning.\n", rc));
     1075        XtFree(pu8DestText);
     1076        RTMemFree(pvVBox);
     1077        return false;
     1078    }
     1079    LogFlowFunc (("converted string is %.*s. Returning.\n", cbDestLen, pu8DestText));
     1080    RTMemFree(pvVBox);
     1081    *atomTypeReturn = g_ctxX11.atomUtf8;
     1082    *pValReturn = reinterpret_cast<XtPointer>(pu8DestText);
     1083    *pcLenReturn = cbDestLen;
     1084    *piFormatReturn = 8;
     1085    return true;
     1086}
     1087
     1088/**
     1089 * Satisfy a request from X11 to convert the clipboard text to
     1090 * COMPOUND_TEXT.  We return non-zero terminated text.
     1091 * @todo that works, but it is bad.  Change it to return zero-terminated
     1092 *       text.
     1093 *
     1094 * @returns true if we successfully convert the data to the format
     1095 * requested, false otherwise.
     1096 *
     1097 * @param  atomTypeReturn  Where to store the atom for the type of the data
     1098 *                         we are returning
     1099 * @param  pValReturn      Where to store the pointer to the data we are
     1100 *                         returning.  This should be to memory allocated by
     1101 *                         XtMalloc, which will be freed by the Xt toolkit
     1102 *                         later.
     1103 * @param  pcLenReturn     Where to store the length of the data we are
     1104 *                         returning
     1105 * @param  piFormatReturn  Where to store the bit width (8, 16, 32) of the
     1106 *                         data we are returning
     1107 * @note  X11 backend code, called by the callback for XtOwnSelection.
     1108 */
     1109static Boolean vboxClipboardConvertToCTextForX11(Atom *atomTypeReturn,
     1110                                                 XtPointer *pValReturn,
     1111                                                 unsigned long *pcLenReturn,
     1112                                                 int *piFormatReturn)
     1113{
     1114    PRTUTF16 pu16SrcText, pu16DestText;
     1115    void *pvVBox;
     1116    uint32_t cbVBox;
     1117    char *pu8DestText = 0;
     1118    size_t cwSrcLen, cwDestLen, cbDestLen;
     1119    XTextProperty property;
     1120    int rc;
     1121
     1122    LogFlowFunc (("called\n"));
     1123    /* Read the clipboard data from the guest. */
     1124    rc = VBoxX11ClipboardReadVBoxData(g_ctxX11.pFrontend, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &pvVBox, &cbVBox);
     1125    if ((rc != VINF_SUCCESS) || (cbVBox == 0))
     1126    {
     1127        /* If VBoxX11ClipboardReadVBoxData fails then pClient may be invalid */
     1128        LogRelFunc (("VBoxX11ClipboardReadVBoxData 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    }
     1174    /* And finally (!) convert the Utf8 text to compound text. */
     1175#ifdef RT_OS_SOLARIS
     1176    rc = XmbTextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1,
     1177                                     XCompoundTextStyle, &property);
     1178#else
     1179    rc = Xutf8TextListToTextProperty(XtDisplay(g_ctxX11.widget), &pu8DestText, 1,
     1180                                     XCompoundTextStyle, &property);
     1181#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);
     1207    *atomTypeReturn = property.encoding;
     1208    *pValReturn = reinterpret_cast<XtPointer>(property.value);
     1209    *pcLenReturn = property.nitems;
     1210    *piFormatReturn = property.format;
     1211    return true;
     1212}
     1213
     1214/**
     1215 * Return VBox's clipboard data for an X11 client.
     1216 * @note  X11 backend code, callback for XtOwnSelection
     1217 */
     1218static Boolean vboxClipboardConvertForX11(Widget, Atom *atomSelection,
     1219                                          Atom *atomTarget,
     1220                                          Atom *atomTypeReturn,
     1221                                          XtPointer *pValReturn,
     1222                                          unsigned long *pcLenReturn,
     1223                                          int *piFormatReturn)
     1224{
     1225    g_eClipboardFormats eFormat = INVALID;
     1226
     1227    LogFlowFunc(("\n"));
     1228    /* Drop requests that we receive too late. */
     1229    if (g_ctxX11.eOwner != VB)
     1230        return false;
     1231    if (   (*atomSelection != g_ctxX11.atomClipboard)
     1232        && (*atomSelection != g_ctxX11.atomPrimary)
     1233       )
     1234    {
     1235        LogFlowFunc(("rc = false\n"));
     1236        return false;
     1237    }
     1238    if (g_debugClipboard)
     1239    {
     1240        char *szAtomName = XGetAtomName(XtDisplay(g_ctxX11.widget), *atomTarget);
     1241        if (szAtomName != 0)
     1242        {
     1243            Log2 (("%s: request for format %s\n", __PRETTY_FUNCTION__, szAtomName));
     1244            XFree(szAtomName);
     1245        }
     1246        else
     1247        {
     1248            LogFunc (("request for invalid target atom %d!\n", *atomTarget));
     1249        }
     1250    }
     1251    if (*atomTarget == g_ctxX11.atomTargets)
     1252    {
     1253        eFormat = TARGETS;
    1771254    }
    1781255    else
    179         g_ctxHost.pBackend = pBackend;
    180     return rc;
    181 }
    182 
    183 /**
    184  * Terminate the host side of the shared clipboard.
    185  * @note  host glue code
    186  */
    187 void vboxClipboardDestroy (void)
    188 {
    189     int rc = VINF_SUCCESS;
    190     LogRelFunc(("shutting down host clipboard\n"));
    191     /* Drop the reference to the client, in case it is still there.  This
    192      * will cause any outstanding clipboard data requests from X11 to fail
    193      * immediately. */
    194     g_ctxHost.pClient = NULL;
    195     /* The backend may be waiting for data from VBox.  At this point it is no
    196      * longer going to arrive, and we must release it to allow the event
    197      * loop to terminate.  In this case the buffer where VBox would have
    198      * written the clipboard data will still be empty and we will just
    199      * return "no data" to the backend.  Any subsequent attempts to get the
    200      * data from VBox will fail immediately as the client reference is gone.
     1256    {
     1257        for (unsigned i = 0; i != g_ctxX11.formatList.size(); ++i)
     1258        {
     1259            if (g_ctxX11.formatList[i].atom == *atomTarget)
     1260            {
     1261                eFormat = g_ctxX11.formatList[i].format;
     1262                break;
     1263            }
     1264        }
     1265    }
     1266    switch (eFormat)
     1267    {
     1268    case TARGETS:
     1269        return vboxClipboardConvertTargetsForX11(atomTypeReturn, pValReturn,
     1270                                                 pcLenReturn, piFormatReturn);
     1271    case UTF16:
     1272        return vboxClipboardConvertUtf16(atomTypeReturn, pValReturn, pcLenReturn,
     1273                                         piFormatReturn);
     1274    case UTF8:
     1275        return vboxClipboardConvertToUtf8ForX11(atomTypeReturn, pValReturn,
     1276                                                pcLenReturn, piFormatReturn);
     1277    case CTEXT:
     1278        return vboxClipboardConvertToCTextForX11(atomTypeReturn, pValReturn,
     1279                                                 pcLenReturn, piFormatReturn);
     1280    default:
     1281        LogFunc (("bad format\n"));
     1282        return false;
     1283    }
     1284}
     1285
     1286/**
     1287 * This is called by the X toolkit intrinsics to let us know that another
     1288 * X11 client has taken the clipboard.  In this case we notify VBox that
     1289 * we want ownership of the clipboard.
     1290 * @note  X11 backend code, callback for XtOwnSelection
     1291 */
     1292static void vboxClipboardReturnToX11(Widget, Atom *)
     1293{
     1294    LogFlowFunc (("called, giving VBox clipboard ownership\n"));
     1295    g_ctxX11.eOwner = X11;
     1296    g_ctxX11.notifyVBox = true;
     1297}
     1298
     1299/**
     1300 * VBox is taking possession of the shared clipboard.
     1301 *
     1302 * @param u32Formats Clipboard formats the guest is offering
     1303 * @note  X11 backend code
     1304 */
     1305void VBoxX11ClipboardAnnounceVBoxFormat(VBOXCLIPBOARDCONTEXTX11 *pBackend,
     1306                                        uint32_t u32Formats)
     1307{
     1308    /*
     1309     * Immediately return if we are not connected to the host X server.
    2011310     */
    202     /** @note  This has been made unconditional, as it should do no harm
    203      *         even if we are not waiting. */
    204     RTSemEventSignal(g_ctxHost.waitForData);
    205     rc = VBoxX11ClipboardTermX11(g_ctxHost.pBackend);
    206     if (RT_SUCCESS(rc))
    207     {
    208         /* We can safely destroy these as the backend has exited
    209          * successfully and no other calls from the host code should be
    210          * forthcoming. */
    211         /** @todo  can the backend fail to exit successfully?  What then? */
    212         RTSemEventDestroy(g_ctxHost.waitForData);
    213         RTSemMutexDestroy(g_ctxHost.clipboardMutex);
    214     }
    215 }
    216 
    217 /**
    218  * Connect a guest to the shared clipboard.
    219  * @note  host glue code
    220  * @note  on the host, we assume that some other application already owns
    221  *        the clipboard and leave ownership to X11.
    222  */
    223 int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient)
    224 {
    225     int rc = VINF_SUCCESS;
    226     LogFlowFunc(("\n"));
    227     /* Only one client is supported for now */
    228     AssertLogRelReturn(g_ctxHost.pClient == 0, VERR_NOT_SUPPORTED);
    229     pClient->pCtx = &g_ctxHost;
    230     pClient->pCtx->pClient = pClient;
    231     /** The pClient pointer is a dummy anyway, as we only support a single
    232      * client at a time. */
    233     rc = VBoxX11ClipboardStartX11(g_ctxHost.pBackend,
    234                                   X11 /* initial owner */);
    235     return rc;
    236 }
    237 
    238 /**
    239  * Synchronise the contents of the host clipboard with the guest, called
    240  * after a save and restore of the guest.
    241  * @note  Host glue code
    242  */
    243 int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
    244 {
    245 
    246     /* On a Linux host, the guest should never synchronise/cache its
    247      * clipboard contents, as we have no way of reliably telling when the
    248      * host clipboard data changes.  So instead of synchronising, we tell
    249      * the guest to empty its clipboard, and we set the cached flag so that
    250      * we report formats to the guest next time we poll for them. */
    251     /** @note  This has been changed so that the message is sent even if
    252      *         X11 is not available. */
    253     vboxSvcClipboardReportMsg (g_ctxHost.pClient,
    254                                VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0);
    255     VBoxX11ClipboardRequestSyncX11(g_ctxHost.pBackend);
    256 
    257     return VINF_SUCCESS;
    258 }
    259 
    260 /**
    261  * Shut down the shared clipboard service and "disconnect" the guest.
    262  * @note  Host glue code
    263  */
    264 void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *)
    265 {
    266     LogFlow(("vboxClipboardDisconnect\n"));
    267 
    268     RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT);
    269     g_ctxHost.pClient = NULL;
    270     VBoxX11ClipboardStopX11(g_ctxHost.pBackend);
    271     RTSemMutexRelease(g_ctxHost.clipboardMutex);
    272 }
    273 
    274 /**
    275  * VBox is taking possession of the shared clipboard.
    276  *
    277  * @param pClient    Context data for the guest system
    278  * @param u32Formats Clipboard formats the guest is offering
    279  * @note  Host glue code
    280  */
    281 void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
    282 {
    283     VBoxX11ClipboardAnnounceVBoxFormat (g_ctxHost.pBackend, u32Formats);
     1311    if (!g_fHaveX11)
     1312        return;
     1313
     1314    g_ctxX11.vboxFormats = u32Formats;
     1315    LogFlowFunc (("u32Formats=%d\n", u32Formats));
     1316    if (u32Formats == 0)
     1317    {
     1318        /* This is just an automatism, not a genuine anouncement */
     1319        LogFlowFunc(("returning\n"));
     1320        return;
     1321    }
     1322    if (g_ctxX11.eOwner == VB)
     1323    {
     1324        /* We already own the clipboard, so no need to grab it, especially as that can lead
     1325           to races due to the asynchronous nature of the X11 clipboard.  This event may also
     1326           have been sent out by the guest to invalidate the Windows clipboard cache. */
     1327        LogFlowFunc(("returning\n"));
     1328        return;
     1329    }
     1330    Log2 (("%s: giving the guest clipboard ownership\n", __PRETTY_FUNCTION__));
     1331    g_ctxX11.eOwner = VB;
     1332    g_ctxX11.X11TextFormat = INVALID;
     1333    g_ctxX11.X11BitmapFormat = INVALID;
     1334    if (XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomClipboard, CurrentTime, vboxClipboardConvertForX11,
     1335                       vboxClipboardReturnToX11, 0) != True)
     1336    {
     1337        Log2 (("%s: returning clipboard ownership to the host\n", __PRETTY_FUNCTION__));
     1338        /* We set this so that the guest gets notified when we take the clipboard, even if no
     1339          guest formats are found which we understand. */
     1340        g_ctxX11.notifyVBox = true;
     1341        g_ctxX11.eOwner = X11;
     1342    }
     1343    XtOwnSelection(g_ctxX11.widget, g_ctxX11.atomPrimary, CurrentTime, vboxClipboardConvertForX11,
     1344                   NULL, 0);
     1345    LogFlowFunc(("returning\n"));
     1346
    2841347}
    2851348
     
    2921355 * @param  cb        The size of the buffer to write the data to
    2931356 * @param  pcbActual Where to write the actual size of the written data
    294  * @note   Host glue code
    295  */
    296 int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient,
    297                            uint32_t u32Format, void *pv, uint32_t cb,
    298                            uint32_t *pcbActual)
    299 {
    300     int rc = VINF_SUCCESS;
    301     VBOXCLIPBOARDREQUEST request;
    302     /* No one else (VBox or X11) should currently be waiting.  The first
    303      * because requests from VBox are serialised and the second because X11
    304      * previously grabbed the clipboard, so it should not be waiting for
    305      * data from us. */
    306     AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctxHost.waiter, VB, NONE),
    307                         VERR_DEADLOCK);
    308     request.pv = pv;
    309     request.cb = cb;
    310     request.pcbActual = pcbActual;
    311     rc = VBoxX11ClipboardReadX11Data(g_ctxHost.pBackend, u32Format, &request);
    312     g_ctxHost.waiter = NONE;
    313     return rc;
    314 }
    315 
    316 /**
    317  * Called when we have requested data from VBox and that data has arrived.
    318  *
    319  * @param  pClient   Context information about the guest VM
    320  * @param  pv        Buffer to which the data was written
    321  * @param  cb        The size of the data written
    322  * @param  u32Format The format of the data written
    323  * @note   Host glue code
    324  */
    325 void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient,
    326                              void *pv, uint32_t cb, uint32_t u32Format)
    327 {
    328 /* Assume that if this gets called at all then the X11 backend is running. */
    329 #if 0
     1357 * @note   X11 backend code
     1358 */
     1359int VBoxX11ClipboardReadX11Data(VBOXCLIPBOARDCONTEXTX11 *pBackend,
     1360                                uint32_t u32Format,
     1361                                VBOXCLIPBOARDREQUEST *pRequest)
     1362{
     1363    /*
     1364     * Immediately return if we are not connected to the host X server.
     1365     */
    3301366    if (!g_fHaveX11)
    331         return;
    332 #endif
    333 
    334     LogFlowFunc (("called\n"));
    335 
    336     /* Assert that no other transfer is in process (requests are serialised)
    337      * or has not cleaned up properly. */
    338     AssertLogRelReturnVoid (   pClient->data.pv == NULL
    339                             && pClient->data.cb == 0
    340                             && pClient->data.u32Format == 0);
    341 
    342     /* Grab the mutex and check that X11 is still waiting for the data before
    343      * delivering it.  See the explanation in VBoxX11ClipboardReadVBoxData. */
    344     RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT);
    345     if (g_ctxHost.waiter == X11 && cb > 0)
    346     {
    347         pClient->data.pv = RTMemAlloc (cb);
    348 
    349         if (pClient->data.pv)
     1367    {
     1368        /* no data available */
     1369        *pRequest->pcbActual = 0;
     1370        return VINF_SUCCESS;
     1371    }
     1372
     1373    LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb));
     1374
     1375    /*
     1376     * The guest wants to read data in the given format.
     1377     */
     1378    if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     1379    {
     1380        if (g_ctxX11.X11TextFormat == INVALID)
    3501381        {
    351             memcpy (pClient->data.pv, pv, cb);
    352             pClient->data.cb = cb;
    353             pClient->data.u32Format = u32Format;
     1382            /* No data available. */
     1383            *pRequest->pcbActual = 0;
     1384            return VERR_NO_DATA;  /* The guest thinks we have data and we don't */
    3541385        }
    355     }
    356     RTSemMutexRelease(g_ctxHost.clipboardMutex);
    357 
    358     RTSemEventSignal(g_ctxHost.waitForData);
    359 }
    360 
     1386        /* Initially set the size of the data read to zero in case we fail
     1387         * somewhere. */
     1388        *pRequest->pcbActual = 0;
     1389        /* Send out a request for the data to the current clipboard owner */
     1390        XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard,
     1391                            g_ctxX11.atomX11TextFormat,
     1392                            vboxClipboardGetDataFromX11,
     1393                            reinterpret_cast<XtPointer>(pRequest),
     1394                            CurrentTime);
     1395        /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called.  The
     1396           callback will signal the event semaphore when it has processed the data for us. */
     1397
     1398        int rc = RTSemEventWait(g_ctxX11.waitForData, RT_INDEFINITE_WAIT);
     1399        if (RT_FAILURE(rc))
     1400            return rc;
     1401    }
     1402    else
     1403    {
     1404        return VERR_NOT_IMPLEMENTED;
     1405    }
     1406    return VINF_SUCCESS;
     1407}
     1408
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