[7007] | 1 | /** $Id: clipboard-x11.cpp 104317 2024-04-12 14:11:08Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[99590] | 3 | * Guest Additions - X11 Shared Clipboard implementation.
|
---|
[7007] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2007-2023 Oracle and/or its affiliates.
|
---|
[7007] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[7007] | 26 | */
|
---|
| 27 |
|
---|
[57358] | 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[7007] | 32 | #include <iprt/alloc.h>
|
---|
| 33 | #include <iprt/asm.h>
|
---|
| 34 | #include <iprt/assert.h>
|
---|
| 35 | #include <iprt/initterm.h>
|
---|
| 36 | #include <iprt/mem.h>
|
---|
| 37 | #include <iprt/string.h>
|
---|
[82882] | 38 | #include <iprt/path.h>
|
---|
[7007] | 39 | #include <iprt/process.h>
|
---|
| 40 | #include <iprt/semaphore.h>
|
---|
| 41 |
|
---|
[21227] | 42 | #include <VBox/VBoxGuestLib.h>
|
---|
[20552] | 43 | #include <VBox/HostServices/VBoxClipboardSvc.h>
|
---|
| 44 | #include <VBox/GuestHost/SharedClipboard.h>
|
---|
[82156] | 45 | #include <VBox/GuestHost/SharedClipboard-x11.h>
|
---|
[7007] | 46 |
|
---|
[18360] | 47 | #include "VBoxClient.h"
|
---|
[86967] | 48 | #include "clipboard.h"
|
---|
[7007] | 49 |
|
---|
[100285] | 50 | #ifdef LOG_GROUP
|
---|
| 51 | # undef LOG_GROUP
|
---|
| 52 | #endif
|
---|
| 53 | #define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
|
---|
| 54 | #include <iprt/log.h>
|
---|
[82287] | 55 |
|
---|
[100285] | 56 |
|
---|
[100204] | 57 | #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
|
---|
| 58 | /**
|
---|
[103442] | 59 | * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialize
|
---|
[100367] | 60 | *
|
---|
| 61 | * @thread Clipboard main thread.
|
---|
[100204] | 62 | */
|
---|
[103442] | 63 | static DECLCALLBACK(int) vbclX11OnTransferInitializeCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
|
---|
[100204] | 64 | {
|
---|
| 65 | LogFlowFuncEnter();
|
---|
| 66 |
|
---|
[100367] | 67 | PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
|
---|
| 68 | AssertPtr(pCtx);
|
---|
[100204] | 69 |
|
---|
[100367] | 70 | PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
|
---|
| 71 | AssertPtr(pTransfer);
|
---|
[100204] | 72 |
|
---|
[100367] | 73 | int rc = VINF_SUCCESS;
|
---|
[100204] | 74 |
|
---|
[100367] | 75 | /* If this is a G->H transfer, we need to set the root list entries here, as the host
|
---|
| 76 | * will start reading those as soon as we report the INITIALIZED status. */
|
---|
| 77 | switch (ShClTransferGetDir(pTransfer))
|
---|
[100204] | 78 | {
|
---|
[100367] | 79 | case SHCLTRANSFERDIR_TO_REMOTE: /* G->H */
|
---|
[100204] | 80 | {
|
---|
[103323] | 81 | void *pvData;
|
---|
| 82 | uint32_t cbData;
|
---|
| 83 | rc = ShClX11ReadDataFromX11Ex(&g_Ctx.X11, &pCtx->EventSrc, SHCL_TIMEOUT_DEFAULT_MS, VBOX_SHCL_FMT_URI_LIST,
|
---|
| 84 | &pvData, &cbData);
|
---|
[100367] | 85 | if (RT_SUCCESS(rc))
|
---|
| 86 | {
|
---|
[104317] | 87 | rc = ShClTransferRootsSetFromStringListEx(pTransfer, (const char *)pvData, cbData,
|
---|
| 88 | "\n" /* X11-based Desktop environments separate entries with "\n" */);
|
---|
[103323] | 89 | RTMemFree(pvData);
|
---|
[100367] | 90 | }
|
---|
[100204] | 91 | break;
|
---|
| 92 | }
|
---|
[100367] | 93 |
|
---|
| 94 | case SHCLTRANSFERDIR_FROM_REMOTE: /* H->G */
|
---|
| 95 | {
|
---|
| 96 | /* Retrieve the root entries as a first action, so that the transfer is ready to go
|
---|
| 97 | * once it gets registered to HTTP server. */
|
---|
| 98 | int rc2 = ShClTransferRootListRead(pTransfer);
|
---|
| 99 | if ( RT_SUCCESS(rc2)
|
---|
| 100 | /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
|
---|
| 101 | && ShClTransferRootsCount(pTransfer))
|
---|
| 102 | {
|
---|
| 103 | rc2 = ShClTransferHttpServerRegisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
|
---|
| 104 | }
|
---|
| 105 | break;
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | default:
|
---|
| 109 | break;
|
---|
[100204] | 110 | }
|
---|
| 111 |
|
---|
[100367] | 112 | LogFlowFuncLeaveRC(rc);
|
---|
[103442] | 113 | return rc;
|
---|
[100204] | 114 | }
|
---|
| 115 |
|
---|
| 116 | /**
|
---|
[100205] | 117 | * @copydoc SHCLTRANSFERCALLBACKS::pfnOnRegistered
|
---|
[100204] | 118 | *
|
---|
| 119 | * This starts the HTTP server if not done yet and registers the transfer with it.
|
---|
| 120 | *
|
---|
[100284] | 121 | * @thread Clipboard main thread.
|
---|
[100204] | 122 | */
|
---|
[100367] | 123 | static DECLCALLBACK(void) vbclX11OnTransferRegisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
|
---|
[100204] | 124 | {
|
---|
| 125 | RT_NOREF(pTransferCtx);
|
---|
| 126 |
|
---|
| 127 | LogFlowFuncEnter();
|
---|
| 128 |
|
---|
| 129 | PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
|
---|
| 130 | AssertPtr(pCtx);
|
---|
| 131 |
|
---|
| 132 | PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
|
---|
| 133 | AssertPtr(pTransfer);
|
---|
| 134 |
|
---|
| 135 | /* We only need to start the HTTP server when we actually receive data from the remote (host). */
|
---|
[100367] | 136 | if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
|
---|
[100204] | 137 | {
|
---|
[100367] | 138 | int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
|
---|
[100204] | 139 | if (RT_FAILURE(rc2))
|
---|
| 140 | LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | LogFlowFuncLeave();
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | /**
|
---|
| 147 | * Unregisters a transfer from a HTTP server.
|
---|
| 148 | *
|
---|
| 149 | * This also stops the HTTP server if no active transfers are found anymore.
|
---|
| 150 | *
|
---|
| 151 | * @param pCtx Shared clipboard context to unregister transfer for.
|
---|
| 152 | * @param pTransfer Transfer to unregister.
|
---|
| 153 | *
|
---|
[100284] | 154 | * @thread Clipboard main thread.
|
---|
[100204] | 155 | */
|
---|
[100367] | 156 | static void vbclX11TransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
|
---|
[100204] | 157 | {
|
---|
| 158 | if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
|
---|
| 159 | {
|
---|
[100367] | 160 | if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
|
---|
| 161 | {
|
---|
| 162 | ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
|
---|
| 163 | ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
|
---|
| 164 | }
|
---|
[100204] | 165 | }
|
---|
| 166 | }
|
---|
| 167 |
|
---|
| 168 | /**
|
---|
[100205] | 169 | * @copydoc SHCLTRANSFERCALLBACKS::pfnOnUnregistered
|
---|
[100204] | 170 | *
|
---|
| 171 | * Unregisters a (now) unregistered transfer from the HTTP server.
|
---|
| 172 | *
|
---|
[100284] | 173 | * @thread Clipboard main thread.
|
---|
[100204] | 174 | */
|
---|
[100367] | 175 | static DECLCALLBACK(void) vbclX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
|
---|
[100204] | 176 | {
|
---|
| 177 | RT_NOREF(pTransferCtx);
|
---|
[100367] | 178 | vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
|
---|
[100204] | 179 | }
|
---|
| 180 |
|
---|
| 181 | /**
|
---|
[100205] | 182 | * @copydoc SHCLTRANSFERCALLBACKS::pfnOnCompleted
|
---|
[100204] | 183 | *
|
---|
| 184 | * Unregisters a complete transfer from the HTTP server.
|
---|
| 185 | *
|
---|
[100284] | 186 | * @thread Clipboard main thread.
|
---|
[100204] | 187 | */
|
---|
[100367] | 188 | static DECLCALLBACK(void) vbclX11OnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
|
---|
[100204] | 189 | {
|
---|
| 190 | RT_NOREF(rc);
|
---|
[100367] | 191 | vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
|
---|
[100204] | 192 | }
|
---|
| 193 |
|
---|
[100205] | 194 | /** @copydoc SHCLTRANSFERCALLBACKS::pfnOnError
|
---|
[100204] | 195 | *
|
---|
| 196 | * Unregisters a failed transfer from the HTTP server.
|
---|
| 197 | *
|
---|
[100284] | 198 | * @thread Clipboard main thread.
|
---|
[100204] | 199 | */
|
---|
[100367] | 200 | static DECLCALLBACK(void) vbclX11OnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
|
---|
[100204] | 201 | {
|
---|
[100367] | 202 | return vbclX11OnTransferCompletedCallback(pCtx, rc);
|
---|
[100204] | 203 | }
|
---|
| 204 | #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
|
---|
| 205 |
|
---|
| 206 | /**
|
---|
| 207 | * Worker for a reading clipboard from the host.
|
---|
| 208 | */
|
---|
[103365] | 209 | static DECLCALLBACK(int) vbclX11ReadDataWorker(PSHCLCONTEXT pCtx,
|
---|
| 210 | SHCLFORMAT uFmt, void **ppvData, uint32_t *pcbData, void *pvUser)
|
---|
[100204] | 211 | {
|
---|
[93505] | 212 | RT_NOREF(pvUser);
|
---|
| 213 |
|
---|
[103365] | 214 | return VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, ppvData, pcbData);
|
---|
[100204] | 215 | }
|
---|
[81843] | 216 |
|
---|
[100204] | 217 | /**
|
---|
| 218 | * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
|
---|
| 219 | *
|
---|
[100367] | 220 | * Requests data from the host.
|
---|
[100204] | 221 | *
|
---|
[100367] | 222 | * For transfers: This requests a transfer from the host. Most of the handling will be done VbglR3 then.
|
---|
| 223 | *
|
---|
[100204] | 224 | * @thread X11 event thread.
|
---|
| 225 | */
|
---|
| 226 | static DECLCALLBACK(int) vbclX11OnRequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
|
---|
| 227 | SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
|
---|
| 228 | {
|
---|
| 229 | RT_NOREF(pvUser);
|
---|
[85834] | 230 |
|
---|
[100204] | 231 | LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt));
|
---|
| 232 |
|
---|
[100235] | 233 | int rc;
|
---|
[100204] | 234 |
|
---|
| 235 | #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
|
---|
| 236 | if (uFmt == VBOX_SHCL_FMT_URI_LIST)
|
---|
| 237 | {
|
---|
[100235] | 238 | rc = vbclX11ReadDataWorker(pCtx, uFmt, ppv, pcb, pvUser);
|
---|
[81871] | 239 | if (RT_SUCCESS(rc))
|
---|
| 240 | {
|
---|
[100367] | 241 | /* Request a new H->G transfer from the host.
|
---|
| 242 | * This is needed in order to get a transfer ID from the host we can initialize our own local transfer with.
|
---|
| 243 | * Transfer creation and set up will be done in VbglR3. */
|
---|
| 244 | rc = VbglR3ClipboardTransferRequest(&pCtx->CmdCtx);
|
---|
| 245 | if (RT_SUCCESS(rc))
|
---|
[100204] | 246 | {
|
---|
[100367] | 247 | PSHCLHTTPSERVER pSrv = &pCtx->X11.HttpCtx.HttpServer;
|
---|
| 248 |
|
---|
| 249 | /* Wait until the HTTP server got the transfer registered, so that we have something to work with. */
|
---|
| 250 | rc = ShClTransferHttpServerWaitForStatusChange(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED, SHCL_TIMEOUT_DEFAULT_MS);
|
---|
[100204] | 251 | if (RT_SUCCESS(rc))
|
---|
| 252 | {
|
---|
[100367] | 253 | PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferLast(pSrv);
|
---|
| 254 | if (pTransfer)
|
---|
| 255 | {
|
---|
| 256 | rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
|
---|
| 257 | if (RT_SUCCESS(rc))
|
---|
| 258 | {
|
---|
[102818] | 259 | char *pszData;
|
---|
| 260 | size_t cbData;
|
---|
| 261 | rc = ShClTransferHttpConvertToStringList(pSrv, pTransfer, &pszData, &cbData);
|
---|
[100676] | 262 | if (RT_SUCCESS(rc))
|
---|
| 263 | {
|
---|
[102818] | 264 | *ppv = pszData;
|
---|
| 265 | *pcb = cbData;
|
---|
| 266 | /* ppv has ownership of pszData now. */
|
---|
[100367] | 267 | }
|
---|
| 268 | }
|
---|
| 269 | }
|
---|
| 270 | else
|
---|
| 271 | AssertMsgFailed(("No registered transfer found for HTTP server\n"));
|
---|
[100204] | 272 | }
|
---|
[100367] | 273 | else
|
---|
| 274 | LogRel(("Shared Clipboard: Could not start transfer, as no new HTTP transfer was registered in time\n"));
|
---|
[100204] | 275 | }
|
---|
[81871] | 276 | }
|
---|
[7007] | 277 | }
|
---|
[100235] | 278 | else /* Anything else */
|
---|
[100204] | 279 | #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
|
---|
[100235] | 280 | {
|
---|
| 281 | rc = vbclX11ReadDataWorker(pCtx, uFmt, ppv, pcb, pvUser);
|
---|
| 282 | }
|
---|
[81843] | 283 |
|
---|
[87082] | 284 | if (RT_FAILURE(rc))
|
---|
[100367] | 285 | LogRel(("Shared Clipboard: Requesting data in format %#x from host failed with %Rrc\n", uFmt, rc));
|
---|
[87082] | 286 |
|
---|
[81173] | 287 | LogFlowFuncLeaveRC(rc);
|
---|
[7007] | 288 | return rc;
|
---|
| 289 | }
|
---|
| 290 |
|
---|
[81843] | 291 | /**
|
---|
[100204] | 292 | * @copydoc SHCLCALLBACKS::pfnReportFormats
|
---|
| 293 | *
|
---|
| 294 | * Reports clipboard formats to the host.
|
---|
| 295 | *
|
---|
| 296 | * @thread X11 event thread.
|
---|
| 297 | */
|
---|
| 298 | static DECLCALLBACK(int) vbclX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
|
---|
[7007] | 299 | {
|
---|
[100235] | 300 | RT_NOREF(pvUser);
|
---|
[81843] | 301 |
|
---|
[100235] | 302 | LogFlowFunc(("fFormats=%#x\n", fFormats));
|
---|
| 303 |
|
---|
| 304 | int rc = VbglR3ClipboardReportFormats(pCtx->CmdCtx.idClient, fFormats);
|
---|
| 305 |
|
---|
[100204] | 306 | LogFlowFuncLeaveRC(rc);
|
---|
| 307 | return rc;
|
---|
[7007] | 308 | }
|
---|
| 309 |
|
---|
| 310 | /**
|
---|
[99590] | 311 | * Initializes the X11-specifc Shared Clipboard code.
|
---|
[7007] | 312 | *
|
---|
[81843] | 313 | * @returns VBox status code.
|
---|
[7007] | 314 | */
|
---|
[99590] | 315 | int VBClX11ClipboardInit(void)
|
---|
[7007] | 316 | {
|
---|
[81060] | 317 | LogFlowFuncEnter();
|
---|
[7007] | 318 |
|
---|
[100286] | 319 | int rc = ShClEventSourceCreate(&g_Ctx.EventSrc, 0 /* uID */);
|
---|
| 320 | AssertRCReturn(rc, rc);
|
---|
| 321 |
|
---|
[93505] | 322 | SHCLCALLBACKS Callbacks;
|
---|
| 323 | RT_ZERO(Callbacks);
|
---|
[99590] | 324 | Callbacks.pfnReportFormats = vbclX11ReportFormatsCallback;
|
---|
| 325 | Callbacks.pfnOnRequestDataFromSource = vbclX11OnRequestDataFromSourceCallback;
|
---|
[93505] | 326 |
|
---|
[100286] | 327 | rc = ShClX11Init(&g_Ctx.X11, &Callbacks, &g_Ctx, false /* fHeadless */);
|
---|
[82156] | 328 | if (RT_SUCCESS(rc))
|
---|
[81060] | 329 | {
|
---|
[82156] | 330 | rc = ShClX11ThreadStart(&g_Ctx.X11, false /* grab */);
|
---|
[81060] | 331 | if (RT_SUCCESS(rc))
|
---|
[7007] | 332 | {
|
---|
[82525] | 333 | rc = VbglR3ClipboardConnectEx(&g_Ctx.CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID);
|
---|
[81960] | 334 | if (RT_FAILURE(rc))
|
---|
[82156] | 335 | ShClX11ThreadStop(&g_Ctx.X11);
|
---|
[7007] | 336 | }
|
---|
| 337 | }
|
---|
[81060] | 338 | else
|
---|
[102920] | 339 | VBClLogError("Initializing clipboard failed with %Rrc\n", rc);
|
---|
[7007] | 340 |
|
---|
[81843] | 341 | if (RT_FAILURE(rc))
|
---|
| 342 | {
|
---|
| 343 | VbglR3ClipboardDisconnectEx(&g_Ctx.CmdCtx);
|
---|
[82156] | 344 | ShClX11Destroy(&g_Ctx.X11);
|
---|
[81843] | 345 | }
|
---|
| 346 |
|
---|
[81173] | 347 | LogFlowFuncLeaveRC(rc);
|
---|
[20552] | 348 | return rc;
|
---|
[7007] | 349 | }
|
---|
| 350 |
|
---|
| 351 | /**
|
---|
[99590] | 352 | * Destroys the X11-specifc Shared Clipboard code.
|
---|
| 353 | *
|
---|
| 354 | * @returns VBox status code.
|
---|
[7007] | 355 | */
|
---|
[99590] | 356 | int VBClX11ClipboardDestroy(void)
|
---|
[7007] | 357 | {
|
---|
[100286] | 358 | return ShClEventSourceDestroy(&g_Ctx.EventSrc);
|
---|
[99590] | 359 | }
|
---|
| 360 |
|
---|
| 361 | /**
|
---|
| 362 | * The main loop of the X11-specifc Shared Clipboard code.
|
---|
| 363 | *
|
---|
| 364 | * @returns VBox status code.
|
---|
[100204] | 365 | *
|
---|
| 366 | * @thread Clipboard service worker thread.
|
---|
[99590] | 367 | */
|
---|
| 368 | int VBClX11ClipboardMain(void)
|
---|
| 369 | {
|
---|
[82156] | 370 | PSHCLCONTEXT pCtx = &g_Ctx;
|
---|
[81843] | 371 |
|
---|
| 372 | bool fShutdown = false;
|
---|
| 373 |
|
---|
[99987] | 374 | #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
|
---|
| 375 | # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
|
---|
| 376 | /*
|
---|
| 377 | * Set callbacks.
|
---|
| 378 | * Those will be registered within VbglR3 when a new transfer gets initialized.
|
---|
| 379 | *
|
---|
| 380 | * Used for starting / stopping the HTTP server.
|
---|
| 381 | */
|
---|
| 382 | RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
|
---|
| 383 |
|
---|
| 384 | pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
|
---|
| 385 | pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
|
---|
| 386 |
|
---|
[103442] | 387 | pCtx->CmdCtx.Transfers.Callbacks.pfnOnInitialize = vbclX11OnTransferInitializeCallback;
|
---|
[100367] | 388 | pCtx->CmdCtx.Transfers.Callbacks.pfnOnRegistered = vbclX11OnTransferRegisteredCallback;
|
---|
| 389 | pCtx->CmdCtx.Transfers.Callbacks.pfnOnUnregistered = vbclX11OnTransferUnregisteredCallback;
|
---|
| 390 | pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted = vbclX11OnTransferCompletedCallback;
|
---|
| 391 | pCtx->CmdCtx.Transfers.Callbacks.pfnOnError = vbclX11OnTransferErrorCallback;
|
---|
[99987] | 392 | # endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
|
---|
| 393 | #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
|
---|
| 394 |
|
---|
[100204] | 395 | LogFlowFunc(("fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64 ...\n",
|
---|
| 396 | pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
|
---|
| 397 |
|
---|
[100235] | 398 | int rc;
|
---|
| 399 |
|
---|
| 400 | /* The thread waits for incoming messages from the host. */
|
---|
[81843] | 401 | for (;;)
|
---|
[7007] | 402 | {
|
---|
[100235] | 403 | PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
|
---|
[82527] | 404 | AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
|
---|
[81843] | 405 |
|
---|
[82527] | 406 | uint32_t idMsg = 0;
|
---|
| 407 | uint32_t cParms = 0;
|
---|
[100235] | 408 | rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
|
---|
[82527] | 409 | if (RT_SUCCESS(rc))
|
---|
[7007] | 410 | {
|
---|
[81843] | 411 | #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
|
---|
[82527] | 412 | rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
|
---|
[81843] | 413 | #else
|
---|
[82527] | 414 | rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
|
---|
[81843] | 415 | #endif
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 | if (RT_FAILURE(rc))
|
---|
| 419 | {
|
---|
| 420 | LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
|
---|
| 421 |
|
---|
| 422 | VbglR3ClipboardEventFree(pEvent);
|
---|
| 423 | pEvent = NULL;
|
---|
| 424 |
|
---|
| 425 | if (fShutdown)
|
---|
| 426 | break;
|
---|
| 427 |
|
---|
| 428 | /* Wait a bit before retrying. */
|
---|
[100204] | 429 | RTThreadSleep(RT_MS_1SEC);
|
---|
[81843] | 430 | continue;
|
---|
| 431 | }
|
---|
| 432 | else
|
---|
| 433 | {
|
---|
| 434 | AssertPtr(pEvent);
|
---|
| 435 | LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
|
---|
| 436 |
|
---|
| 437 | switch (pEvent->enmType)
|
---|
| 438 | {
|
---|
| 439 | case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
|
---|
| 440 | {
|
---|
[100204] | 441 | ShClX11ReportFormatsToX11Async(&g_Ctx.X11, pEvent->u.fReportedFormats);
|
---|
[7007] | 442 | break;
|
---|
| 443 | }
|
---|
| 444 |
|
---|
[81843] | 445 | case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
|
---|
[7007] | 446 | {
|
---|
[103323] | 447 | void *pvData;
|
---|
| 448 | uint32_t cbData;
|
---|
| 449 | rc = ShClX11ReadDataFromX11Ex(&g_Ctx.X11, &pCtx->EventSrc, SHCL_TIMEOUT_DEFAULT_MS, pEvent->u.fReadData,
|
---|
| 450 | &pvData, &cbData);
|
---|
[100204] | 451 | if (RT_SUCCESS(rc))
|
---|
[20552] | 452 | {
|
---|
[103323] | 453 | rc = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData, pvData, cbData);
|
---|
| 454 | RTMemFree(pvData);
|
---|
[20552] | 455 | }
|
---|
[100204] | 456 |
|
---|
| 457 | if (RT_FAILURE(rc))
|
---|
| 458 | VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData, NULL, 0);
|
---|
| 459 |
|
---|
[7007] | 460 | break;
|
---|
| 461 | }
|
---|
| 462 |
|
---|
[81843] | 463 | case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
|
---|
[7007] | 464 | {
|
---|
[86871] | 465 | VBClLogVerbose(2, "Host requested termination\n");
|
---|
[81843] | 466 | fShutdown = true;
|
---|
[7007] | 467 | break;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
[81843] | 470 | #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
|
---|
| 471 | case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
|
---|
[81040] | 472 | {
|
---|
[100204] | 473 | if (pEvent->u.TransferStatus.Report.uStatus == SHCLTRANSFERSTATUS_STARTED)
|
---|
| 474 | {
|
---|
| 475 |
|
---|
| 476 | }
|
---|
[81843] | 477 | rc = VINF_SUCCESS;
|
---|
[81040] | 478 | break;
|
---|
| 479 | }
|
---|
[81843] | 480 | #endif
|
---|
| 481 | case VBGLR3CLIPBOARDEVENTTYPE_NONE:
|
---|
| 482 | {
|
---|
| 483 | /* Nothing to do here. */
|
---|
| 484 | rc = VINF_SUCCESS;
|
---|
| 485 | break;
|
---|
| 486 | }
|
---|
| 487 |
|
---|
| 488 | default:
|
---|
| 489 | {
|
---|
| 490 | AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
|
---|
| 491 | }
|
---|
[7007] | 492 | }
|
---|
[81843] | 493 |
|
---|
| 494 | if (pEvent)
|
---|
| 495 | {
|
---|
| 496 | VbglR3ClipboardEventFree(pEvent);
|
---|
| 497 | pEvent = NULL;
|
---|
| 498 | }
|
---|
[7007] | 499 | }
|
---|
| 500 |
|
---|
[81843] | 501 | if (fShutdown)
|
---|
| 502 | break;
|
---|
[7007] | 503 | }
|
---|
[81843] | 504 |
|
---|
[81173] | 505 | LogFlowFuncLeaveRC(rc);
|
---|
[7007] | 506 | return rc;
|
---|
| 507 | }
|
---|