VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/wayland-helper-gtk.cpp

Last change on this file was 102025, checked in by vboxsync, 6 months ago

Additions: X11/Wayland: Attempt to address build issues, bugref:10194.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.2 KB
Line 
1/* $Id: wayland-helper-gtk.cpp 102025 2023-11-09 12:00:24Z vboxsync $ */
2/** @file
3 * Guest Additions - Gtk helper for Wayland.
4 *
5 * This module implements Shared Clipboard and Drag-n-Drop
6 * support for Wayland guests using Gtk library.
7 */
8
9/*
10 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31#include <iprt/localipc.h>
32#include <iprt/rand.h>
33#include <iprt/semaphore.h>
34
35#include <VBox/GuestHost/DisplayServerType.h>
36#include <VBox/GuestHost/clipboard-helper.h>
37#include <VBox/GuestHost/mime-type-converter.h>
38
39#include "VBoxClient.h"
40#include "clipboard.h"
41#include "wayland-helper.h"
42#include "wayland-helper-ipc.h"
43
44#include "vbox-gtk.h"
45
46/** Gtk session data.
47 *
48 * A structure which accumulates all the necessary data required to
49 * maintain session between host and Wayland for clipboard sharing
50 * and drag-n-drop.*/
51typedef struct
52{
53 /* Generic VBoxClient Wayland session data (synchronization point). */
54 vbcl_wl_session_t Base;
55 /** Randomly generated session ID, should be used by
56 * both VBoxClient and vboxwl tool. */
57 uint32_t uSessionId;
58 /** IPC connection flow control between VBoxClient and vboxwl tool. */
59 vbcl::ipc::clipboard::ClipboardIpc *oClipboardIpc;
60 /** IPC connection handle. */
61 RTLOCALIPCSESSION hIpcSession;
62 /** Popup window process handle. */
63 RTPROCESS popupProc;
64} vbox_wl_gtk_ipc_session_t;
65
66/**
67 * A set of objects required to handle clipboard sharing over
68 * and drag-n-drop using Gtk library. */
69typedef struct
70{
71 /** Wayland event loop thread. */
72 RTTHREAD Thread;
73
74 /** A flag which indicates that Wayland event loop should terminate. */
75 volatile bool fShutdown;
76
77 /** Communication session between host event loop and Wayland. */
78 vbox_wl_gtk_ipc_session_t Session;
79
80 /** Connection to the host clipboard service. */
81 PVBGLR3SHCLCMDCTX pClipboardCtx;
82
83 /** Local IPC server object. */
84 RTLOCALIPCSERVER hIpcServer;
85} vbox_wl_gtk_ctx_t;
86
87/** Helper context. */
88static vbox_wl_gtk_ctx_t g_GtkCtx;
89
90/**
91 * Start popup process.
92 *
93 * @returns IPRT status code.
94 * @param pSession Session data.
95 */
96static int vbcl_wayland_hlp_gtk_session_popup(vbox_wl_gtk_ipc_session_t *pSession)
97{
98 int rc = VINF_SUCCESS;
99
100 /* Make sure valid session is in progress. */
101 AssertReturn(pSession->uSessionId > 0, VERR_INVALID_PARAMETER);
102
103 char *pszSessionId = RTStrAPrintf2("%u", pSession->uSessionId);
104 if (RT_VALID_PTR(pszSessionId))
105 {
106 /* List of vboxwl command line arguments.*/
107 const char *apszArgs[] =
108 {
109 VBOXWL_PATH,
110 NULL,
111 VBOXWL_ARG_SESSION_ID,
112 pszSessionId,
113 NULL,
114 NULL
115 };
116
117 /* Log verbosity level to be passed to vboxwl. */
118 char pszVerobsity[ VBOXWL_VERBOSITY_MAX
119 + 2 /* add space for '-' and '\0' */];
120 RT_ZERO(pszVerobsity);
121
122 /* Select vboxwl action depending on session type. */
123 if (pSession->Base.enmType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_GUEST)
124 apszArgs[1] = VBOXWL_ARG_CLIP_HG_COPY;
125 else if (pSession->Base.enmType == VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST)
126 apszArgs[1] = VBOXWL_ARG_CLIP_GH_ANNOUNCE;
127 else if (pSession->Base.enmType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_HOST)
128 apszArgs[1] = VBOXWL_ARG_CLIP_GH_COPY;
129 else
130 rc = VERR_INVALID_PARAMETER;
131
132 /* Once VBoxClient was started with log verbosity level, pass the
133 * same verbosity level to vboxwl as well. */
134 if ( RT_SUCCESS(rc)
135 && g_cVerbosity > 0)
136 {
137 pszVerobsity[0] = '-';
138
139 memset(&pszVerobsity[1], 'v',
140 RT_MIN(g_cVerbosity, VBOXWL_VERBOSITY_MAX));
141
142 /* Insert verbosity level into the rest of vboxwl
143 * command line arguments. */
144 apszArgs[4] = pszVerobsity;
145 }
146
147 /* Run vboxwl in background. */
148 if (RT_SUCCESS(rc))
149 rc = RTProcCreate(VBOXWL_PATH,
150 apszArgs, RTENV_DEFAULT,
151 RTPROC_FLAGS_SEARCH_PATH, &pSession->popupProc);
152
153 VBClLogVerbose(2, "start '%s' command [sid=%u]: rc=%Rrc\n",
154 VBOXWL_PATH, pSession->uSessionId, rc);
155
156 RTStrFree(pszSessionId);
157 }
158 else
159 rc = VERR_NO_MEMORY;
160
161 return rc;
162}
163
164/**
165 * Prepare new session and start popup process.
166 *
167 * @returns IPRT status code.
168 * @param pSession Session data.
169 */
170static int vbcl_wayland_hlp_gtk_session_prepare(vbox_wl_gtk_ipc_session_t *pSession)
171{
172 int rc = VINF_SUCCESS;
173
174 /* Make sure there is no leftovers from previous session. */
175 Assert(pSession->uSessionId == 0);
176
177 /* Initialize session. */
178 pSession->uSessionId = RTRandU32Ex(1, 0xFFFFFFFF);
179
180 pSession->oClipboardIpc = new vbcl::ipc::clipboard::ClipboardIpc();
181 if (RT_VALID_PTR(pSession->oClipboardIpc))
182 {
183 pSession->oClipboardIpc->init(vbcl::ipc::FLOW_DIRECTION_SERVER,
184 pSession->uSessionId);
185 }
186 else
187 rc = VERR_NO_MEMORY;
188
189 /* Start helper tool. */
190 if (RT_SUCCESS(rc))
191 {
192 rc = vbcl_wayland_hlp_gtk_session_popup(pSession);
193 VBClLogVerbose(1, "session id=%u: started: rc=%Rrc\n",
194 pSession->uSessionId, rc);
195 }
196
197 return rc;
198}
199
200/**
201 * Session callback: Generic session initializer.
202 *
203 * This callback starts new session.
204 *
205 * @returns IPRT status code.
206 * @param enmSessionType Session type (unused).
207 * @param pvUser User data (unused).
208 */
209static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_session_start_generic_cb(
210 vbcl_wl_session_type_t enmSessionType, void *pvUser)
211{
212 RT_NOREF(enmSessionType, pvUser);
213
214 VBCL_LOG_CALLBACK;
215
216 return vbcl_wayland_hlp_gtk_session_prepare(&g_GtkCtx.Session);
217}
218
219/**
220 * Reset session, terminate popup process and free allocated resources.
221 *
222 * @returns IPRT status code.
223 * @param enmSessionType Session type (unused).
224 * @param pvUser User data (session to reset).
225 */
226static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_session_end_cb(
227 vbcl_wl_session_type_t enmSessionType, void *pvUser)
228{
229 vbox_wl_gtk_ipc_session_t *pSession = (vbox_wl_gtk_ipc_session_t *)pvUser;
230 AssertPtrReturn(pSession, VERR_INVALID_PARAMETER);
231
232 int rc;
233
234 RT_NOREF(enmSessionType);
235
236 /* Make sure valid session is in progress. */
237 AssertReturn(pSession->uSessionId > 0, VERR_INVALID_PARAMETER);
238
239 rc = RTProcWait(pSession->popupProc, RTPROCWAIT_FLAGS_BLOCK, NULL);
240 if (RT_FAILURE(rc))
241 rc = RTProcTerminate(pSession->popupProc);
242 if (RT_FAILURE(rc))
243 {
244 VBClLogError("session %u: unable to stop popup window process: rc=%Rrc\n",
245 pSession->uSessionId, rc);
246 }
247
248 if (RT_SUCCESS(rc))
249 {
250 pSession->uSessionId = 0;
251
252 pSession->oClipboardIpc->reset();
253 delete pSession->oClipboardIpc;
254 }
255
256 return rc;
257}
258
259/**
260 * Session callback: Handle sessions started by host events.
261 *
262 * @returns IPRT status code.
263 * @param enmSessionType Session type, must be verified as
264 * a consistency check.
265 * @param pvUser User data (IPC connection handle
266 * to vboxwl tool).
267 */
268static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_worker_join_cb(
269 vbcl_wl_session_type_t enmSessionType, void *pvUser)
270{
271 PRTLOCALIPCSESSION phIpcSession = (RTLOCALIPCSESSION *)pvUser;
272 AssertPtrReturn(phIpcSession, VERR_INVALID_PARAMETER);
273
274 const vbcl::ipc::flow_t *pFlow;
275
276 int rc = VINF_SUCCESS;
277
278 VBCL_LOG_CALLBACK;
279
280 /* Make sure valid session is in progress. */
281 AssertReturn(g_GtkCtx.Session.uSessionId > 0, VERR_INVALID_PARAMETER);
282
283 /* Select corresponding IPC flow depending on session type. */
284 if (enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_GUEST)
285 pFlow = vbcl::ipc::clipboard::HGCopyFlow;
286 else if (enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST)
287 pFlow = vbcl::ipc::clipboard::GHAnnounceAndCopyFlow;
288 else if (enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_HOST)
289 pFlow = vbcl::ipc::clipboard::GHCopyFlow;
290 else
291 {
292 pFlow = NULL;
293 rc = VERR_INVALID_PARAMETER;
294 }
295
296 /* Proceed with selected flow. */
297 if (RT_VALID_PTR(pFlow))
298 rc = g_GtkCtx.Session.oClipboardIpc->flow(pFlow, *phIpcSession);
299
300 return rc;
301}
302
303/**
304 * IPC server thread worker.
305 *
306 * @returns IPRT status code.
307 * @param hThreadSelf IPRT thread handle.
308 * @param pvUser Helper context data.
309 */
310static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_worker(RTTHREAD hThreadSelf, void *pvUser)
311{
312 int rc;
313
314 vbox_wl_gtk_ctx_t *pCtx = (vbox_wl_gtk_ctx_t *)pvUser;
315 char szIpcServerName[128];
316
317 RTThreadUserSignal(hThreadSelf);
318
319 VBClLogVerbose(1, "starting IPC\n");
320
321 rc = vbcl_wayland_hlp_gtk_ipc_srv_name(szIpcServerName, sizeof(szIpcServerName));
322
323 if (RT_SUCCESS(rc))
324 rc = RTLocalIpcServerCreate(&pCtx->hIpcServer, szIpcServerName, 0);
325
326 if (RT_SUCCESS(rc))
327 rc = RTLocalIpcServerSetAccessMode(pCtx->hIpcServer, RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
328
329 if (RT_SUCCESS(rc))
330 {
331 VBClLogVerbose(1, "started IPC server '%s'\n", szIpcServerName);
332
333 vbcl_wayland_session_init(&pCtx->Session.Base);
334
335 while (!ASMAtomicReadBool(&pCtx->fShutdown))
336 {
337 RTLOCALIPCSESSION hClientSession;
338
339 rc = RTLocalIpcServerListen(pCtx->hIpcServer, &hClientSession);
340 if (RT_SUCCESS(rc))
341 {
342 RTUID uUid;
343
344 /* Authenticate remote user. Only allow connection from
345 * process who belongs to the same UID. */
346 rc = RTLocalIpcSessionQueryUserId(hClientSession, &uUid);
347 if (RT_SUCCESS(rc))
348 {
349 RTUID uLocalUID = geteuid();
350 if ( uLocalUID != 0
351 && uLocalUID == uUid)
352 {
353 VBClLogVerbose(1, "new IPC connection\n");
354
355 rc = vbcl_wayland_session_join(&pCtx->Session.Base,
356 &vbcl_wayland_hlp_gtk_worker_join_cb,
357 &hClientSession);
358
359 VBClLogVerbose(1, "IPC flow completed, rc=%Rrc\n", rc);
360
361 rc = vbcl_wayland_session_end(&pCtx->Session.Base,
362 &vbcl_wayland_hlp_gtk_session_end_cb,
363 &pCtx->Session);
364 VBClLogVerbose(1, "IPC session ended, rc=%Rrc\n", rc);
365
366 }
367 else
368 VBClLogError("incoming IPC connection rejected: UID mismatch: %d/%d\n",
369 uLocalUID, uUid);
370 }
371 else
372 VBClLogError("failed to get remote IPC UID, rc=%Rrc\n", rc);
373
374 RTLocalIpcSessionClose(hClientSession);
375 }
376 else if (rc != VERR_CANCELLED)
377 VBClLogVerbose(1, "IPC connection has failed, rc=%Rrc\n", rc);
378 }
379
380 rc = RTLocalIpcServerDestroy(pCtx->hIpcServer);
381 }
382 else
383 VBClLogError("failed to start IPC, rc=%Rrc\n", rc);
384
385 VBClLogVerbose(1, "IPC stopped\n");
386
387 return rc;
388}
389
390/**
391 * @interface_method_impl{VBCLWAYLANDHELPER,pfnProbe}
392 */
393static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_probe(void)
394{
395 int fCaps = VBOX_WAYLAND_HELPER_CAP_NONE;
396
397 if (VBGHDisplayServerTypeIsGtkAvailable())
398 fCaps |= VBOX_WAYLAND_HELPER_CAP_CLIPBOARD;
399
400 return fCaps;
401}
402
403/**
404 * @interface_method_impl{VBCLWAYLANDHELPER,pfnInit}
405 */
406RTDECL(int) vbcl_wayland_hlp_gtk_init(void)
407{
408 VBCL_LOG_CALLBACK;
409
410 RT_ZERO(g_GtkCtx);
411
412 return VBClClipboardThreadStart(&g_GtkCtx.Thread, vbcl_wayland_hlp_gtk_worker, "wl-gtk-ipc", &g_GtkCtx);
413}
414
415/**
416 * @interface_method_impl{VBCLWAYLANDHELPER,pfnTerm}
417 */
418RTDECL(int) vbcl_wayland_hlp_gtk_term(void)
419{
420 int rc;
421 int rcThread = 0;
422
423 /* Set termination flag. */
424 g_GtkCtx.fShutdown = true;
425
426 /* Cancel IPC loop. */
427 rc = RTLocalIpcServerCancel(g_GtkCtx.hIpcServer);
428 if (RT_FAILURE(rc))
429 VBClLogError("unable to notify IPC server about shutdown, rc=%Rrc\n", rc);
430
431 if (RT_SUCCESS(rc))
432 {
433 /* Wait for Gtk event loop thread to shutdown. */
434 rc = RTThreadWait(g_GtkCtx.Thread, RT_MS_30SEC, &rcThread);
435 VBClLogInfo("gtk event thread exited with status, rc=%Rrc\n", rcThread);
436 }
437 else
438 VBClLogError("unable to stop gtk thread, rc=%Rrc\n", rc);
439
440 return rc;
441}
442
443/**
444 * @interface_method_impl{VBCLWAYLANDHELPER,pfnSetClipboardCtx}
445 */
446static DECLCALLBACK(void) vbcl_wayland_hlp_gtk_set_clipboard_ctx(PVBGLR3SHCLCMDCTX pCtx)
447{
448 g_GtkCtx.pClipboardCtx = pCtx;
449}
450
451/**
452 * Session callback: Announce clipboard to the host.
453 *
454 * This callback (1) waits for the guest to report its clipboard content
455 * via IPC connection from vboxwl tool, and (2) reports these formats
456 * to the host.
457 *
458 * @returns IPRT status code.
459 * @param enmSessionType Session type, must be verified as
460 * a consistency check.
461 * @param pvUser User data (unused).
462 */
463static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_popup_join_cb(
464 vbcl_wl_session_type_t enmSessionType, void *pvUser)
465{
466 int rc = (enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST)
467 ? VINF_SUCCESS : VERR_WRONG_ORDER;
468
469 RT_NOREF(pvUser);
470
471 VBCL_LOG_CALLBACK;
472
473 if (RT_SUCCESS(rc))
474 {
475 SHCLFORMATS fFmts = g_GtkCtx.Session.oClipboardIpc->m_fFmts.wait();
476 if (fFmts != g_GtkCtx.Session.oClipboardIpc->m_fFmts.defaults())
477 rc = VbglR3ClipboardReportFormats(g_GtkCtx.pClipboardCtx->idClient, fFmts);
478 else
479 rc = VERR_TIMEOUT;
480 }
481
482 return rc;
483}
484
485/**
486 * @interface_method_impl{VBCLWAYLANDHELPER,pfnPopup}
487 */
488static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_popup(void)
489{
490 int rc;
491
492 VBCL_LOG_CALLBACK;
493
494 rc = vbcl_wayland_session_start(&g_GtkCtx.Session.Base,
495 VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST,
496 &vbcl_wayland_hlp_gtk_session_start_generic_cb,
497 &g_GtkCtx.Session);
498 if (RT_SUCCESS(rc))
499 {
500 rc = vbcl_wayland_session_join(&g_GtkCtx.Session.Base,
501 &vbcl_wayland_hlp_gtk_popup_join_cb,
502 NULL);
503 }
504
505 return rc;
506}
507
508/**
509 * Session callback: Copy clipboard from the host.
510 *
511 * This callback (1) sets host clipboard formats list to the session,
512 * (2) waits for guest to request clipboard in specific format, (3) read
513 * host clipboard in this format, and (4) sets clipboard data to the session,
514 * so Gtk event thread can inject it into the guest.
515 *
516 * This callback should not return until clipboard data is read from
517 * the host or error occurred. It must block host events loop until
518 * current host event is fully processed.
519 *
520 * @returns IPRT status code.
521 * @param enmSessionType Session type, must be verified as
522 * a consistency check.
523 * @param pvUser User data (host clipboard formats).
524 */
525static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_hg_clip_report_join_cb(
526 vbcl_wl_session_type_t enmSessionType, void *pvUser)
527{
528 SHCLFORMATS *pfFmts = (SHCLFORMATS *)pvUser;
529 AssertPtrReturn(pfFmts, VERR_INVALID_PARAMETER);
530
531 SHCLFORMAT uFmt;
532
533 int rc = (enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_GUEST)
534 ? VINF_SUCCESS : VERR_WRONG_ORDER;
535
536 VBCL_LOG_CALLBACK;
537
538 if (RT_SUCCESS(rc))
539 {
540 g_GtkCtx.Session.oClipboardIpc->m_fFmts.set(*pfFmts);
541
542 uFmt = g_GtkCtx.Session.oClipboardIpc->m_uFmt.wait();
543 if (uFmt != g_GtkCtx.Session.oClipboardIpc->m_uFmt.defaults())
544 {
545 void *pvData;
546 uint32_t cbData;
547
548 rc = VBClClipboardReadHostClipboard(g_GtkCtx.pClipboardCtx, uFmt, &pvData, &cbData);
549 if (RT_SUCCESS(rc))
550 {
551 g_GtkCtx.Session.oClipboardIpc->m_pvClipboardBuf.set((uint64_t)pvData);
552 g_GtkCtx.Session.oClipboardIpc->m_cbClipboardBuf.set((uint64_t)cbData);
553 }
554 }
555 else
556 rc = VERR_TIMEOUT;
557 }
558
559 return rc;
560}
561
562/**
563 * @interface_method_impl{VBCLWAYLANDHELPER,pfnHGClipReport}
564 */
565static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_hg_clip_report(SHCLFORMATS fFormats)
566{
567 int rc = VERR_NO_DATA;
568
569 VBCL_LOG_CALLBACK;
570
571 if (fFormats != VBOX_SHCL_FMT_NONE)
572 {
573 rc = vbcl_wayland_session_start(&g_GtkCtx.Session.Base,
574 VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_GUEST,
575 &vbcl_wayland_hlp_gtk_session_start_generic_cb,
576 &g_GtkCtx.Session);
577 if (RT_SUCCESS(rc))
578 {
579 rc = vbcl_wayland_session_join(&g_GtkCtx.Session.Base,
580 &vbcl_wayland_hlp_gtk_hg_clip_report_join_cb,
581 &fFormats);
582 }
583 }
584
585 return rc;
586}
587
588/**
589 * Session callback: Copy clipboard to the host.
590 *
591 * This callback sets clipboard format to the session as requested
592 * by host, waits for guest clipboard data in requested format and
593 * sends data to the host.
594 *
595 * This callback should not return until clipboard data is sent to
596 * the host or error occurred. It must block host events loop until
597 * current host event is fully processed.
598 *
599 * @returns IPRT status code.
600 * @param enmSessionType Session type, must be verified as
601 * a consistency check.
602 * @param pvUser User data (requested format).
603 */
604static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_gh_clip_read_join_cb(
605 vbcl_wl_session_type_t enmSessionType, void *pvUser)
606{
607 SHCLFORMAT *puFmt = (SHCLFORMAT *)pvUser;
608 AssertPtrReturn(puFmt, VERR_INVALID_PARAMETER);
609
610 int rc = ( enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_HOST
611 || enmSessionType == VBCL_WL_CLIPBOARD_SESSION_TYPE_ANNOUNCE_TO_HOST)
612 ? VINF_SUCCESS : VERR_WRONG_ORDER;
613
614 VBCL_LOG_CALLBACK;
615
616 if (RT_SUCCESS(rc))
617 {
618 void *pvData;
619 uint32_t cbData;
620
621 /* Store requested clipboard format to the session. */
622 g_GtkCtx.Session.oClipboardIpc->m_uFmt.set(*puFmt);
623
624 /* Wait for data in requested format. */
625 pvData = (void *)g_GtkCtx.Session.oClipboardIpc->m_pvClipboardBuf.wait();
626 cbData = g_GtkCtx.Session.oClipboardIpc->m_cbClipboardBuf.wait();
627 if ( cbData != g_GtkCtx.Session.oClipboardIpc->m_cbClipboardBuf.defaults()
628 && pvData != (void *)g_GtkCtx.Session.oClipboardIpc->m_pvClipboardBuf.defaults())
629 {
630 /* Send clipboard data to the host. */
631 rc = VbglR3ClipboardWriteDataEx(g_GtkCtx.pClipboardCtx, *puFmt, pvData, cbData);
632 }
633 else
634 rc = VERR_TIMEOUT;
635 }
636
637 return rc;
638}
639
640/**
641 * @interface_method_impl{VBCLWAYLANDHELPER,pfnGHClipRead}
642 */
643static DECLCALLBACK(int) vbcl_wayland_hlp_gtk_gh_clip_read(SHCLFORMAT uFmt)
644{
645 int rc = VINF_SUCCESS;
646
647 VBCL_LOG_CALLBACK;
648
649 if (uFmt != VBOX_SHCL_FMT_NONE)
650 {
651 VBClLogVerbose(2, "host wants fmt 0x%x\n", uFmt);
652
653 /* This callback can be called in two cases:
654 *
655 * 1. Guest has just announced a list of its clipboard
656 * formats to the host, and vboxwl tool is still running,
657 * IPC session is still active as well. In this case the
658 * host can immediately ask for content in specified format.
659 *
660 * 2. Guest has already announced list of its clipboard
661 * formats to the host some time ago, vboxwl tool is no
662 * longer running and IPC session is not active. In this
663 * case some app on the host side might want to read
664 * clipboard in specific format.
665 *
666 * In case (2), we need to start new IPC session and restart
667 * vboxwl tool again
668 */
669 if (!vbcl_wayland_session_is_started(&g_GtkCtx.Session.Base))
670 {
671 rc = vbcl_wayland_session_start(&g_GtkCtx.Session.Base,
672 VBCL_WL_CLIPBOARD_SESSION_TYPE_COPY_TO_HOST,
673 &vbcl_wayland_hlp_gtk_session_start_generic_cb,
674 NULL);
675 }
676
677 if (RT_SUCCESS(rc))
678 {
679 rc = vbcl_wayland_session_join(&g_GtkCtx.Session.Base,
680 &vbcl_wayland_hlp_gtk_gh_clip_read_join_cb,
681 &uFmt);
682 }
683 }
684
685 VBClLogVerbose(2, "vbcl_wayland_hlp_gtk_gh_clip_read ended rc=%Rrc\n", rc);
686
687 return rc;
688}
689
690/* Helper callbacks. */
691const VBCLWAYLANDHELPER g_WaylandHelperGtk =
692{
693 "wayland-gtk", /* .pszName */
694 vbcl_wayland_hlp_gtk_probe, /* .pfnProbe */
695 vbcl_wayland_hlp_gtk_init, /* .pfnInit */
696 vbcl_wayland_hlp_gtk_term, /* .pfnTerm */
697 vbcl_wayland_hlp_gtk_set_clipboard_ctx, /* .pfnSetClipboardCtx */
698 vbcl_wayland_hlp_gtk_popup, /* .pfnPopup */
699 vbcl_wayland_hlp_gtk_hg_clip_report, /* .pfnHGClipReport */
700 vbcl_wayland_hlp_gtk_gh_clip_read, /* .pfnGHClipRead */
701};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use