VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/clipboard-x11.cpp@ 102462

Last change on this file since 102462 was 102462, checked in by vboxsync, 14 months ago

Shared Clipboard: Make sure to check the event's rc when waiting for ShClX11ReadDataFromX11Async() to complete [build fix]. bugref:10384

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.9 KB
Line 
1/** $Id: clipboard-x11.cpp 102462 2023-12-05 08:36:07Z vboxsync $ */
2/** @file
3 * Guest Additions - X11 Shared Clipboard implementation.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
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>
38#include <iprt/path.h>
39#include <iprt/process.h>
40#include <iprt/semaphore.h>
41
42#include <VBox/VBoxGuestLib.h>
43#include <VBox/HostServices/VBoxClipboardSvc.h>
44#include <VBox/GuestHost/SharedClipboard.h>
45#include <VBox/GuestHost/SharedClipboard-x11.h>
46
47#include "VBoxClient.h"
48#include "clipboard.h"
49
50#ifdef LOG_GROUP
51# undef LOG_GROUP
52#endif
53#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
54#include <iprt/log.h>
55
56
57#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
58/**
59 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialized
60 *
61 * @thread Clipboard main thread.
62 */
63static DECLCALLBACK(void) vbclX11OnTransferInitializedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
64{
65 LogFlowFuncEnter();
66
67 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
68 AssertPtr(pCtx);
69
70 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
71 AssertPtr(pTransfer);
72
73 int rc = VINF_SUCCESS;
74
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))
78 {
79 case SHCLTRANSFERDIR_TO_REMOTE: /* G->H */
80 {
81 PSHCLEVENT pEvent;
82 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->EventSrc, &pEvent);
83 if (RT_SUCCESS(rc))
84 {
85 rc = ShClX11ReadDataFromX11Async(&g_Ctx.X11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
86 if (RT_SUCCESS(rc))
87 {
88 int rcEvent;
89 PSHCLEVENTPAYLOAD pPayload;
90 rc = ShClEventWaitEx(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &rcEvent, &pPayload);
91 if (RT_SUCCESS(rc))
92 {
93 if (pPayload)
94 {
95 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
96 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
97
98 rc = ShClTransferRootsInitFromStringListEx(pTransfer, (const char *)pResp->Read.pvData, pResp->Read.cbData,
99 "\n" /* X11-based Desktop environments separate entries with "\n" */);
100
101 RTMemFree(pResp->Read.pvData);
102 pResp->Read.cbData = 0;
103
104 ShClPayloadFree(pPayload);
105 }
106 else /* No payload given; could happen on invalid / not-expected formats. */
107 rc = VERR_NO_DATA;
108 }
109 else if (rc == VERR_SHCLPB_EVENT_FAILED)
110 rc = rcEvent;
111 }
112 }
113 break;
114 }
115
116 case SHCLTRANSFERDIR_FROM_REMOTE: /* H->G */
117 {
118 /* Retrieve the root entries as a first action, so that the transfer is ready to go
119 * once it gets registered to HTTP server. */
120 int rc2 = ShClTransferRootListRead(pTransfer);
121 if ( RT_SUCCESS(rc2)
122 /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
123 && ShClTransferRootsCount(pTransfer))
124 {
125 rc2 = ShClTransferHttpServerRegisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
126 }
127 break;
128 }
129
130 default:
131 break;
132 }
133
134 LogFlowFuncLeaveRC(rc);
135}
136
137/**
138 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnRegistered
139 *
140 * This starts the HTTP server if not done yet and registers the transfer with it.
141 *
142 * @thread Clipboard main thread.
143 */
144static DECLCALLBACK(void) vbclX11OnTransferRegisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
145{
146 RT_NOREF(pTransferCtx);
147
148 LogFlowFuncEnter();
149
150 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
151 AssertPtr(pCtx);
152
153 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
154 AssertPtr(pTransfer);
155
156 /* We only need to start the HTTP server when we actually receive data from the remote (host). */
157 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
158 {
159 int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
160 if (RT_FAILURE(rc2))
161 LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
162 }
163
164 LogFlowFuncLeave();
165}
166
167/**
168 * Unregisters a transfer from a HTTP server.
169 *
170 * This also stops the HTTP server if no active transfers are found anymore.
171 *
172 * @param pCtx Shared clipboard context to unregister transfer for.
173 * @param pTransfer Transfer to unregister.
174 *
175 * @thread Clipboard main thread.
176 */
177static void vbclX11TransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
178{
179 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
180 {
181 if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
182 {
183 ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
184 ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
185 }
186 }
187}
188
189/**
190 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnUnregistered
191 *
192 * Unregisters a (now) unregistered transfer from the HTTP server.
193 *
194 * @thread Clipboard main thread.
195 */
196static DECLCALLBACK(void) vbclX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
197{
198 RT_NOREF(pTransferCtx);
199 vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
200}
201
202/**
203 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnCompleted
204 *
205 * Unregisters a complete transfer from the HTTP server.
206 *
207 * @thread Clipboard main thread.
208 */
209static DECLCALLBACK(void) vbclX11OnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
210{
211 RT_NOREF(rc);
212 vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
213}
214
215/** @copydoc SHCLTRANSFERCALLBACKS::pfnOnError
216 *
217 * Unregisters a failed transfer from the HTTP server.
218 *
219 * @thread Clipboard main thread.
220 */
221static DECLCALLBACK(void) vbclX11OnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
222{
223 return vbclX11OnTransferCompletedCallback(pCtx, rc);
224}
225#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
226
227/**
228 * Worker for a reading clipboard from the host.
229 */
230static DECLCALLBACK(int) vbclX11ReadDataWorker(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
231{
232 RT_NOREF(pvUser);
233
234 LogFlowFuncEnter();
235
236 int rc = VERR_NO_DATA; /* Play safe. */
237
238 uint32_t cbRead = 0;
239
240 uint32_t cbData = _4K; /** @todo Make this dynamic. */
241 void *pvData = RTMemAlloc(cbData);
242 if (pvData)
243 {
244 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
245 }
246 else
247 rc = VERR_NO_MEMORY;
248
249 /*
250 * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
251 * larger buffer. The size of the buffer needed is placed in *pcb.
252 * So we start all over again.
253 */
254 if (rc == VINF_BUFFER_OVERFLOW)
255 {
256 /* cbRead contains the size required. */
257
258 cbData = cbRead;
259 pvData = RTMemRealloc(pvData, cbRead);
260 if (pvData)
261 {
262 rc = VbglR3ClipboardReadDataEx(&pCtx->CmdCtx, uFmt, pvData, cbData, &cbRead);
263 if (rc == VINF_BUFFER_OVERFLOW)
264 rc = VERR_BUFFER_OVERFLOW;
265 }
266 else
267 rc = VERR_NO_MEMORY;
268 }
269
270 if (!cbRead)
271 rc = VERR_NO_DATA;
272
273 if (RT_SUCCESS(rc))
274 {
275 if (ppv)
276 *ppv = pvData;
277 if (pcb)
278 *pcb = cbRead; /* Actual bytes read. */
279 }
280 else
281 {
282 /*
283 * Catch other errors. This also catches the case in which the buffer was
284 * too small a second time, possibly because the clipboard contents
285 * changed half-way through the operation. Since we can't say whether or
286 * not this is actually an error, we just return size 0.
287 */
288 RTMemFree(pvData);
289 }
290
291 LogFlowFuncLeaveRC(rc);
292 return rc;
293}
294
295/**
296 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
297 *
298 * Requests data from the host.
299 *
300 * For transfers: This requests a transfer from the host. Most of the handling will be done VbglR3 then.
301 *
302 * @thread X11 event thread.
303 */
304static DECLCALLBACK(int) vbclX11OnRequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
305 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
306{
307 RT_NOREF(pvUser);
308
309 LogFlowFunc(("pCtx=%p, uFmt=%#x\n", pCtx, uFmt));
310
311 int rc;
312
313#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
314 if (uFmt == VBOX_SHCL_FMT_URI_LIST)
315 {
316 rc = vbclX11ReadDataWorker(pCtx, uFmt, ppv, pcb, pvUser);
317 if (RT_SUCCESS(rc))
318 {
319 /* Request a new H->G transfer from the host.
320 * This is needed in order to get a transfer ID from the host we can initialize our own local transfer with.
321 * Transfer creation and set up will be done in VbglR3. */
322 rc = VbglR3ClipboardTransferRequest(&pCtx->CmdCtx);
323 if (RT_SUCCESS(rc))
324 {
325 PSHCLHTTPSERVER pSrv = &pCtx->X11.HttpCtx.HttpServer;
326
327 /* Wait until the HTTP server got the transfer registered, so that we have something to work with. */
328 rc = ShClTransferHttpServerWaitForStatusChange(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED, SHCL_TIMEOUT_DEFAULT_MS);
329 if (RT_SUCCESS(rc))
330 {
331 PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferLast(pSrv);
332 if (pTransfer)
333 {
334 rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
335 if (RT_SUCCESS(rc))
336 {
337 char *pszURL = NULL;
338
339 uint64_t const cRoots = ShClTransferRootsCount(pTransfer);
340 for (uint32_t i = 0; i < cRoots; i++)
341 {
342 char *pszEntry = ShClTransferHttpServerGetUrlA(pSrv, ShClTransferGetID(pTransfer), i /* Entry index */);
343 AssertPtrBreakStmt(pszEntry, rc = VERR_NO_MEMORY);
344
345 if (i > 0)
346 {
347 rc = RTStrAAppend(&pszURL, "\n"); /* Separate entries with a newline. */
348 AssertRCBreak(rc);
349 }
350
351 rc = RTStrAAppend(&pszURL, pszEntry);
352 AssertRCBreak(rc);
353
354 RTStrFree(pszEntry);
355 }
356
357 if (RT_SUCCESS(rc))
358 {
359 *ppv = pszURL;
360 *pcb = strlen(pszURL) + 1 /* Include terminator */;
361
362 LogFlowFunc(("URL is '%s'\n", pszURL));
363
364 /* ppv has ownership of pszURL. */
365 }
366 }
367 }
368 else
369 AssertMsgFailed(("No registered transfer found for HTTP server\n"));
370 }
371 else
372 LogRel(("Shared Clipboard: Could not start transfer, as no new HTTP transfer was registered in time\n"));
373 }
374 }
375 }
376 else /* Anything else */
377#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
378 {
379 rc = vbclX11ReadDataWorker(pCtx, uFmt, ppv, pcb, pvUser);
380 }
381
382 if (RT_FAILURE(rc))
383 LogRel(("Shared Clipboard: Requesting data in format %#x from host failed with %Rrc\n", uFmt, rc));
384
385 LogFlowFuncLeaveRC(rc);
386 return rc;
387}
388
389/**
390 * @copydoc SHCLCALLBACKS::pfnReportFormats
391 *
392 * Reports clipboard formats to the host.
393 *
394 * @thread X11 event thread.
395 */
396static DECLCALLBACK(int) vbclX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
397{
398 RT_NOREF(pvUser);
399
400 LogFlowFunc(("fFormats=%#x\n", fFormats));
401
402 int rc = VbglR3ClipboardReportFormats(pCtx->CmdCtx.idClient, fFormats);
403
404 LogFlowFuncLeaveRC(rc);
405 return rc;
406}
407
408/**
409 * Initializes the X11-specifc Shared Clipboard code.
410 *
411 * @returns VBox status code.
412 */
413int VBClX11ClipboardInit(void)
414{
415 LogFlowFuncEnter();
416
417 int rc = ShClEventSourceCreate(&g_Ctx.EventSrc, 0 /* uID */);
418 AssertRCReturn(rc, rc);
419
420 SHCLCALLBACKS Callbacks;
421 RT_ZERO(Callbacks);
422 Callbacks.pfnReportFormats = vbclX11ReportFormatsCallback;
423 Callbacks.pfnOnRequestDataFromSource = vbclX11OnRequestDataFromSourceCallback;
424
425 rc = ShClX11Init(&g_Ctx.X11, &Callbacks, &g_Ctx, false /* fHeadless */);
426 if (RT_SUCCESS(rc))
427 {
428 rc = ShClX11ThreadStart(&g_Ctx.X11, false /* grab */);
429 if (RT_SUCCESS(rc))
430 {
431 rc = VbglR3ClipboardConnectEx(&g_Ctx.CmdCtx, VBOX_SHCL_GF_0_CONTEXT_ID);
432 if (RT_FAILURE(rc))
433 ShClX11ThreadStop(&g_Ctx.X11);
434 }
435 }
436 else
437 rc = VERR_NO_MEMORY;
438
439 if (RT_FAILURE(rc))
440 {
441 VBClLogError("Error connecting to host service, rc=%Rrc\n", rc);
442
443 VbglR3ClipboardDisconnectEx(&g_Ctx.CmdCtx);
444 ShClX11Destroy(&g_Ctx.X11);
445 }
446
447 LogFlowFuncLeaveRC(rc);
448 return rc;
449}
450
451/**
452 * Destroys the X11-specifc Shared Clipboard code.
453 *
454 * @returns VBox status code.
455 */
456int VBClX11ClipboardDestroy(void)
457{
458 return ShClEventSourceDestroy(&g_Ctx.EventSrc);
459}
460
461/**
462 * The main loop of the X11-specifc Shared Clipboard code.
463 *
464 * @returns VBox status code.
465 *
466 * @thread Clipboard service worker thread.
467 */
468int VBClX11ClipboardMain(void)
469{
470 PSHCLCONTEXT pCtx = &g_Ctx;
471
472 bool fShutdown = false;
473
474#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
475# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
476 /*
477 * Set callbacks.
478 * Those will be registered within VbglR3 when a new transfer gets initialized.
479 *
480 * Used for starting / stopping the HTTP server.
481 */
482 RT_ZERO(pCtx->CmdCtx.Transfers.Callbacks);
483
484 pCtx->CmdCtx.Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
485 pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
486
487 pCtx->CmdCtx.Transfers.Callbacks.pfnOnInitialized = vbclX11OnTransferInitializedCallback;
488 pCtx->CmdCtx.Transfers.Callbacks.pfnOnRegistered = vbclX11OnTransferRegisteredCallback;
489 pCtx->CmdCtx.Transfers.Callbacks.pfnOnUnregistered = vbclX11OnTransferUnregisteredCallback;
490 pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted = vbclX11OnTransferCompletedCallback;
491 pCtx->CmdCtx.Transfers.Callbacks.pfnOnError = vbclX11OnTransferErrorCallback;
492# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
493#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
494
495 LogFlowFunc(("fUseLegacyProtocol=%RTbool, fHostFeatures=%#RX64 ...\n",
496 pCtx->CmdCtx.fUseLegacyProtocol, pCtx->CmdCtx.fHostFeatures));
497
498 int rc;
499
500 /* The thread waits for incoming messages from the host. */
501 for (;;)
502 {
503 PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
504 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
505
506 uint32_t idMsg = 0;
507 uint32_t cParms = 0;
508 rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &idMsg, &cParms, NULL /* pidRestoreCheck */);
509 if (RT_SUCCESS(rc))
510 {
511#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
512 rc = VbglR3ClipboardEventGetNextEx(idMsg, cParms, &pCtx->CmdCtx, &pCtx->TransferCtx, pEvent);
513#else
514 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, &pCtx->CmdCtx, pEvent);
515#endif
516 }
517
518 if (RT_FAILURE(rc))
519 {
520 LogFlowFunc(("Getting next event failed with %Rrc\n", rc));
521
522 VbglR3ClipboardEventFree(pEvent);
523 pEvent = NULL;
524
525 if (fShutdown)
526 break;
527
528 /* Wait a bit before retrying. */
529 RTThreadSleep(RT_MS_1SEC);
530 continue;
531 }
532 else
533 {
534 AssertPtr(pEvent);
535 LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
536
537 switch (pEvent->enmType)
538 {
539 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
540 {
541 ShClX11ReportFormatsToX11Async(&g_Ctx.X11, pEvent->u.fReportedFormats);
542 break;
543 }
544
545 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
546 {
547 PSHCLEVENT pReadDataEvent;
548 rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->EventSrc, &pReadDataEvent);
549 if (RT_SUCCESS(rc))
550 {
551 rc = ShClX11ReadDataFromX11Async(&g_Ctx.X11, pEvent->u.fReadData, UINT32_MAX, pReadDataEvent);
552 if (RT_SUCCESS(rc))
553 {
554 int rcEvent;
555 PSHCLEVENTPAYLOAD pPayload;
556 rc = ShClEventWaitEx(pReadDataEvent, SHCL_TIMEOUT_DEFAULT_MS, &rcEvent, &pPayload);
557 if (RT_SUCCESS(rc))
558 {
559 if (pPayload)
560 {
561 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
562 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
563
564 rc = VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData,
565 pResp->Read.pvData, pResp->Read.cbData);
566
567 RTMemFree(pResp->Read.pvData);
568 pResp->Read.cbData = 0;
569
570 ShClPayloadFree(pPayload);
571 }
572 else /* No payload given; could happen on invalid / not-expected formats. */
573 rc = VERR_NO_DATA;
574 }
575 else if (rc == VERR_SHCLPB_EVENT_FAILED)
576 rc = rcEvent;
577 }
578
579 ShClEventRelease(pReadDataEvent);
580 pReadDataEvent = NULL;
581 }
582
583 if (RT_FAILURE(rc))
584 VbglR3ClipboardWriteDataEx(&pCtx->CmdCtx, pEvent->u.fReadData, NULL, 0);
585
586 break;
587 }
588
589 case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
590 {
591 VBClLogVerbose(2, "Host requested termination\n");
592 fShutdown = true;
593 break;
594 }
595
596#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
597 case VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS:
598 {
599 if (pEvent->u.TransferStatus.Report.uStatus == SHCLTRANSFERSTATUS_STARTED)
600 {
601
602 }
603 rc = VINF_SUCCESS;
604 break;
605 }
606#endif
607 case VBGLR3CLIPBOARDEVENTTYPE_NONE:
608 {
609 /* Nothing to do here. */
610 rc = VINF_SUCCESS;
611 break;
612 }
613
614 default:
615 {
616 AssertMsgFailedBreakStmt(("Event type %RU32 not implemented\n", pEvent->enmType), rc = VERR_NOT_SUPPORTED);
617 }
618 }
619
620 if (pEvent)
621 {
622 VbglR3ClipboardEventFree(pEvent);
623 pEvent = NULL;
624 }
625 }
626
627 if (fShutdown)
628 break;
629 }
630
631 LogFlowFuncLeaveRC(rc);
632 return rc;
633}
Note: See TracBrowser for help on using the repository browser.

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