VirtualBox

Ignore:
Timestamp:
Nov 14, 2019 4:30:44 PM (5 years ago)
Author:
vboxsync
Message:

Shared Clipboard/Transfers: Update.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp

    r81820 r81843  
    4646struct _SHCLCONTEXT
    4747{
    48     /** Client ID for the clipboard subsystem */
    49     uint32_t client;
    50 
    51     /** Pointer to the X11 clipboard backend */
    52     CLIPBACKEND *pBackend;
     48    /** Client command context */
     49    VBGLR3SHCLCMDCTX CmdCtx;
     50#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     51    /** Associated transfer data. */
     52    SHCLTRANSFERCTX  TransferCtx;
     53#endif
     54    /** Pointer to the X11 clipboard backend. */
     55    CLIPBACKEND     *pBackend;
    5356};
    5457
    5558/** Only one client is supported. There seems to be no need for more clients. */
    56 static SHCLCONTEXT g_ctx;
    57 
    58 
    59 /**
    60  * Transfer clipboard data from the guest to the host.
    61  *
    62  * @returns VBox result code
    63  * @param   u32Format The format of the data being sent
    64  * @param   pv        Pointer to the data being sent
    65  * @param   cb        Size of the data being sent in bytes
    66  */
    67 static int vboxClipboardSendData(uint32_t u32Format, void *pv, uint32_t cb)
    68 {
    69     int rc;
    70     LogFlowFunc(("u32Format=%d, pv=%p, cb=%d\n", u32Format, pv, cb));
    71     rc = VbglR3ClipboardWriteData(g_ctx.client, u32Format, pv, cb);
    72     LogFlowFuncLeaveRC(rc);
    73     return rc;
    74 }
     59static SHCLCONTEXT g_Ctx;
    7560
    7661
     
    7964 *
    8065 * @returns VBox result code
    81  * @param   pCtx      Our context information
    82  * @param   u32Format The format of the data being requested
    83  * @param   ppv       On success and if pcb > 0, this will point to a buffer
    84  *                    to be freed with RTMemFree containing the data read.
    85  * @param   pcb       On success, this contains the number of bytes of data
    86  *                    returned
    87  */
    88 DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb)
     66 * @param   pCtx                Our context information.
     67 * @param   Format              The format of the data being requested.
     68 * @param   ppv                 On success and if pcb > 0, this will point to a buffer
     69 *                              to be freed with RTMemFree containing the data read.
     70 * @param   pcb                 On success, this contains the number of bytes of data
     71 *                              returned.
     72 */
     73DECLCALLBACK(int) ClipRequestDataForX11Callback(SHCLCONTEXT *pCtx, SHCLFORMAT Format, void **ppv, uint32_t *pcb)
    8974{
    9075    RT_NOREF(pCtx);
     76
     77    LogFlowFunc(("Format=0x%x\n", Format));
     78
    9179    int rc = VINF_SUCCESS;
    92     uint32_t cb = 1024;
    93     void *pv = RTMemAlloc(cb);
    94 
    95     *ppv = 0;
    96     LogFlowFunc(("u32Format=%u\n", u32Format));
    97     if (RT_UNLIKELY(!pv))
    98         rc = VERR_NO_MEMORY;
    99     if (RT_SUCCESS(rc))
    100         rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
    101     if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
    102         *ppv = pv;
    103     /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
    104      * larger buffer.  The size of the buffer needed is placed in *pcb.
    105      * So we start all over again. */
    106     if (rc == VINF_BUFFER_OVERFLOW)
    107     {
    108         cb = *pcb;
    109         RTMemFree(pv);
    110         pv = RTMemAlloc(cb);
    111         if (RT_UNLIKELY(!pv))
     80
     81    uint32_t cbRead = 0;
     82
     83#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     84    if (Format == VBOX_SHCL_FMT_URI_LIST)
     85    {
     86        //rc = VbglR3ClipboardRootListRead()
     87    }
     88    else
     89#endif
     90    {
     91        SHCLDATABLOCK dataBlock;
     92        RT_ZERO(dataBlock);
     93
     94        dataBlock.uFormat = Format;
     95        dataBlock.cbData  = _4K;
     96        dataBlock.pvData  = RTMemAlloc(dataBlock.cbData);
     97        if (dataBlock.pvData)
     98        {
     99            rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead);
     100        }
     101        else
    112102            rc = VERR_NO_MEMORY;
    113         if (RT_SUCCESS(rc))
    114             rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb);
    115         if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
    116             *ppv = pv;
    117     }
    118     /* Catch other errors. This also catches the case in which the buffer was
    119      * too small a second time, possibly because the clipboard contents
    120      * changed half-way through the operation.  Since we can't say whether or
    121      * not this is actually an error, we just return size 0.
    122      */
    123     if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc))
    124     {
    125         *pcb = 0;
    126         if (pv != NULL)
    127             RTMemFree(pv);
    128     }
     103
     104        /*
     105         * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
     106         * larger buffer.  The size of the buffer needed is placed in *pcb.
     107         * So we start all over again.
     108         */
     109        if (rc == VINF_BUFFER_OVERFLOW)
     110        {
     111            /* cbRead contains the size required. */
     112
     113            dataBlock.cbData = cbRead;
     114            dataBlock.pvData = RTMemRealloc(dataBlock.pvData, cbRead);
     115            if (dataBlock.pvData)
     116            {
     117                rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, &dataBlock, &cbRead);
     118                if (    RT_SUCCESS(rc)
     119                     && (rc != VINF_BUFFER_OVERFLOW))
     120                {
     121                    *pcb = cbRead; /* Actual bytes read. */
     122                    *ppv = dataBlock.pvData;
     123                }
     124            }
     125            else
     126                rc = VERR_NO_MEMORY;
     127        }
     128
     129        /*
     130         * Catch other errors. This also catches the case in which the buffer was
     131         * too small a second time, possibly because the clipboard contents
     132         * changed half-way through the operation.  Since we can't say whether or
     133         * not this is actually an error, we just return size 0.
     134         */
     135        if (   RT_FAILURE(rc)
     136            || (VINF_BUFFER_OVERFLOW == rc))
     137        {
     138            RTMemFree(dataBlock.pvData);
     139        }
     140    }
     141
    129142    LogFlowFuncLeaveRC(rc);
    130     if (RT_SUCCESS(rc))
    131         LogFlow(("    *pcb=%d\n", *pcb));
    132143    return rc;
    133144}
    134145
    135 /** Opaque data structure describing a request from the host for clipboard
     146/**
     147 * Opaque data structure describing a request from the host for clipboard
    136148 * data, passed in when the request is forwarded to the X11 backend so that
    137  * it can be completed correctly. */
     149 * it can be completed correctly.
     150 */
    138151struct _CLIPREADCBREQ
    139152{
    140153    /** The data format that was requested. */
    141     uint32_t u32Format;
     154    SHCLFORMAT Format;
    142155};
    143156
     
    146159 *
    147160 * @param pCtx                  Our context information.
    148  * @param u32Formats            The formats to report.
    149  */
    150 DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, uint32_t u32Formats)
     161 * @param Formats               The formats to report.
     162 */
     163DECLCALLBACK(void) ClipReportX11FormatsCallback(SHCLCONTEXT *pCtx, SHCLFORMATS Formats)
    151164{
    152165    RT_NOREF(pCtx);
    153166
    154     LogFlowFunc(("u32Formats=%RU32\n", u32Formats));
    155 
    156     int rc = VbglR3ClipboardFormatsReport(g_ctx.client, u32Formats);
    157     RT_NOREF(rc);
    158 
    159     LogFlowFuncLeaveRC(rc);
    160 }
    161 
    162 /** This is called by the backend to tell us that a request for data from
     167    LogFlowFunc(("Formats=0x%x\n", Formats));
     168
     169    SHCLFORMATDATA formatData;
     170    RT_ZERO(formatData);
     171
     172    formatData.Formats = Formats;
     173
     174    int rc2 = VbglR3ClipboardFormatsReportEx(&pCtx->CmdCtx, &formatData);
     175    RT_NOREF(rc2);
     176    LogFlowFuncLeaveRC(rc2);
     177}
     178
     179/**
     180 * This is called by the backend to tell us that a request for data from
    163181 * X11 has completed.
    164  * @param  pCtx      Our context information
    165  * @param  rc        the iprt result code of the request
    166  * @param  pReq      the request structure that we passed in when we started
    167  *                   the request.  We RTMemFree() this in this function.
    168  * @param  pv        the clipboard data returned from X11 if the request
    169  *                   succeeded (see @a rc)
    170  * @param  cb        the size of the data in @a pv
     182 *
     183 * @param  pCtx                 Our context information.
     184 * @param  rc                   The IPRT result code of the request.
     185 * @param  pReq                 The request structure that we passed in when we started
     186 *                              the request.  We RTMemFree() this in this function.
     187 * @param  pv                   The clipboard data returned from X11 if the request succeeded (see @a rc).
     188 * @param  cb                   The size of the data in @a pv.
    171189 */
    172190DECLCALLBACK(void) ClipRequestFromX11CompleteCallback(SHCLCONTEXT *pCtx, int rc, CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
    173191{
    174192    RT_NOREF(pCtx);
     193
     194    LogFlowFunc(("rc=%Rrc, Format=0x%x, pv=%p, cb=%RU32\n", rc, pReq->Format, pv, cb));
     195
     196    SHCLDATABLOCK dataBlock;
     197    RT_ZERO(dataBlock);
     198
     199    dataBlock.uFormat = pReq->Format;
     200
    175201    if (RT_SUCCESS(rc))
    176         vboxClipboardSendData(pReq->u32Format, pv, cb);
    177     else
    178         vboxClipboardSendData(0, NULL, 0);
     202    {
     203        dataBlock.pvData = pv;
     204        dataBlock.cbData = cb;
     205    }
     206
     207    int rc2 = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, &dataBlock);
     208    RT_NOREF(rc2);
     209
    179210    RTMemFree(pReq);
     211
     212    LogFlowFuncLeaveRC(rc2);
    180213}
    181214
     
    183216 * Connect the guest clipboard to the host.
    184217 *
    185  * @returns VBox status code
     218 * @returns VBox status code.
    186219 */
    187220static int vboxClipboardConnect(void)
     
    189222    LogFlowFuncEnter();
    190223
    191     /* Sanity */
    192     AssertReturn(g_ctx.client   == 0,    VERR_WRONG_ORDER);
    193     AssertReturn(g_ctx.pBackend == NULL, VERR_WRONG_ORDER);
    194 
    195224    int rc;
    196225
    197     g_ctx.pBackend = ClipConstructX11(&g_ctx, false);
    198     if (g_ctx.pBackend)
    199     {
    200         rc = ClipStartX11(g_ctx.pBackend, false /* grab */);
     226    g_Ctx.pBackend = ClipConstructX11(&g_Ctx, false);
     227    if (g_Ctx.pBackend)
     228    {
     229        rc = ClipStartX11(g_Ctx.pBackend, false /* grab */);
    201230        if (RT_SUCCESS(rc))
    202231        {
    203             rc = VbglR3ClipboardConnect(&g_ctx.client);
    204             if (RT_SUCCESS(rc))
    205             {
    206                 Assert(g_ctx.client);
    207             }
    208             else
    209                 VBClLogError("Error connecting to host, rc=%Rrc\n", rc);
     232            rc = VbglR3ClipboardConnectEx(&g_Ctx.CmdCtx);
    210233        }
    211234    }
     
    213236        rc = VERR_NO_MEMORY;
    214237
    215     if (rc != VINF_SUCCESS && g_ctx.pBackend)
    216         ClipDestructX11(g_ctx.pBackend);
     238    if (RT_FAILURE(rc))
     239    {
     240        VBClLogError("Error connecting to host service, rc=%Rrc\n", rc);
     241
     242        VbglR3ClipboardDisconnectEx(&g_Ctx.CmdCtx);
     243        ClipDestructX11(g_Ctx.pBackend);
     244    }
    217245
    218246    LogFlowFuncLeaveRC(rc);
     
    225253int vboxClipboardMain(void)
    226254{
     255    LogRel2(("Worker loop running\n"));
     256
    227257    int rc;
    228     LogFlowFunc(("Starting guest clipboard service\n"));
    229     bool fExiting = false;
    230 
    231     while (!fExiting)
    232     {
    233         uint32_t Msg;
    234         uint32_t fFormats;
    235         rc = VbglR3ClipboardGetHostMsgOld(g_ctx.client, &Msg, &fFormats);
    236         if (RT_SUCCESS(rc))
    237         {
    238             switch (Msg)
    239             {
    240                 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
    241                 {
    242                     /* The host has announced available clipboard formats.
    243                      * Save the information so that it is available for
    244                      * future requests from guest applications.
    245                      */
    246                     LogFlowFunc(("VBOX_SHCL_HOST_MSG_FORMATS_WRITE fFormats=%x\n", fFormats));
    247                     ClipAnnounceFormatToX11(g_ctx.pBackend, fFormats);
    248                     break;
    249                 }
    250 
    251                 case VBOX_SHCL_HOST_MSG_READ_DATA:
     258
     259    SHCLCONTEXT *pCtx = &g_Ctx;
     260
     261    bool fShutdown = false;
     262
     263    /* The thread waits for incoming messages from the host. */
     264    for (;;)
     265    {
     266        PVBGLR3CLIPBOARDEVENT pEvent = NULL;
     267
     268        LogFlowFunc(("Waiting for host message (fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64) ...\n",
     269                     pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
     270
     271        if (pCtx->CmdCtx.fUseLegacyProtocol)
     272        {
     273            uint32_t uMsg;
     274            uint32_t uFormats;
     275
     276            rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.uClientID, &uMsg, &uFormats);
     277            if (RT_FAILURE(rc))
     278            {
     279                if (rc == VERR_INTERRUPTED)
     280                    break;
     281
     282                LogFunc(("Error getting host message, rc=%Rrc\n", rc));
     283            }
     284            else
     285            {
     286                pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
     287                AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
     288
     289                switch (uMsg)
     290                {
     291                    case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
     292                    {
     293                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
     294                        pEvent->u.ReportedFormats.Formats = uFormats;
     295                        break;
     296                    }
     297
     298                    case VBOX_SHCL_HOST_MSG_READ_DATA:
     299                    {
     300                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
     301                        pEvent->u.ReadData.uFmt = uFormats;
     302                        break;
     303                    }
     304
     305                    case VBOX_SHCL_HOST_MSG_QUIT:
     306                    {
     307                        pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
     308                        break;
     309                    }
     310
     311                    default:
     312                        rc = VERR_NOT_SUPPORTED;
     313                        break;
     314                }
     315
     316                if (RT_SUCCESS(rc))
     317                {
     318                    /* Copy over our command context to the event. */
     319                    pEvent->cmdCtx = pCtx->CmdCtx;
     320                }
     321            }
     322        }
     323        else /* Host service has peeking for messages support. */
     324        {
     325            pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
     326            AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
     327
     328            uint32_t uMsg   = 0;
     329            uint32_t cParms = 0;
     330            rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */);
     331            if (RT_SUCCESS(rc))
     332            {
     333#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     334                rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
     335#else
     336                rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent);
     337#endif
     338            }
     339        }
     340
     341        if (RT_FAILURE(rc))
     342        {
     343            LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
     344
     345            VbglR3ClipboardEventFree(pEvent);
     346            pEvent = NULL;
     347
     348            if (fShutdown)
     349                break;
     350
     351            /* Wait a bit before retrying. */
     352            RTThreadSleep(1000);
     353            continue;
     354        }
     355        else
     356        {
     357            AssertPtr(pEvent);
     358            LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
     359
     360            switch (pEvent->enmType)
     361            {
     362                case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
     363                {
     364                    ClipAnnounceFormatToX11(g_Ctx.pBackend, pEvent->u.ReportedFormats.Formats);
     365                    break;
     366                }
     367
     368                case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
    252369                {
    253370                    /* The host needs data in the specified format. */
    254                     LogFlowFunc(("VBOX_SHCL_HOST_MSG_READ_DATA fFormats=%x\n", fFormats));
    255371                    CLIPREADCBREQ *pReq;
    256                     pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(*pReq));
    257                     if (!pReq)
     372                    pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
     373                    if (pReq)
    258374                    {
    259                         rc = VERR_NO_MEMORY;
    260                         fExiting = true;
     375                        pReq->Format = pEvent->u.ReadData.uFmt;
     376                        ClipReadDataFromX11(g_Ctx.pBackend, pReq->Format, pReq);
    261377                    }
    262378                    else
    263                     {
    264                         pReq->u32Format = fFormats;
    265                         ClipReadDataFromX11(g_ctx.pBackend, fFormats,
    266                                                pReq);
    267                     }
    268                     break;
    269                 }
    270 
    271                 case VBOX_SHCL_HOST_MSG_QUIT:
    272                 {
    273                     /* The host is terminating. */
    274                     LogFlowFunc(("VBOX_SHCL_HOST_MSG_QUIT\n"));
    275                     if (RT_SUCCESS(ClipStopX11(g_ctx.pBackend)))
    276                         ClipDestructX11(g_ctx.pBackend);
    277                     fExiting = true;
     379                        rc = VERR_NO_MEMORY;
     380                    break;
     381                }
     382
     383                case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
     384                {
     385                    LogRel2(("Host requested termination\n"));
     386                    fShutdown = true;
     387                    break;
     388                }
     389
     390#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     391                case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
     392                {
     393                    /* Nothing to do here. */
     394                    rc = VINF_SUCCESS;
     395                    break;
     396                }
     397#endif
     398                case VBGLR3CLIPBOARDEVENTTYPE_NONE:
     399                {
     400                    /* Nothing to do here. */
     401                    rc = VINF_SUCCESS;
    278402                    break;
    279403                }
     
    281405                default:
    282406                {
    283                     VBClLogInfo("Unsupported message from host (%RU32)\n", Msg);
    284                     break;
    285                 }
    286             }
    287         }
    288 
    289         LogFlow(("processed host event rc = %d\n", rc));
    290     }
     407                    AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
     408                }
     409            }
     410
     411            if (pEvent)
     412            {
     413                VbglR3ClipboardEventFree(pEvent);
     414                pEvent = NULL;
     415            }
     416        }
     417
     418        if (fShutdown)
     419            break;
     420    }
     421
     422    LogRel(("Worker loop ended\n"));
     423
    291424    LogFlowFuncLeaveRC(rc);
    292425    return rc;
     
    343476};
    344477
    345 struct VBCLSERVICE **VBClGetClipboardService()
     478struct VBCLSERVICE **VBClGetClipboardService(void)
    346479{
    347480    struct CLIPBOARDSERVICE *pService =
Note: See TracChangeset for help on using the changeset viewer.

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