VirtualBox

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

Last change on this file since 102818 was 102818, checked in by vboxsync, 15 months ago

Shared Clipboard/Transfers: Use ShClTransferHttpConvertToStringList() -- removed duplicate code. bugref:9437

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

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