VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp@ 96407

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.7 KB
Line 
1/* $Id: seamless.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * X11 Guest client - seamless mode: main logic, communication with the host and
4 * wrapper interface for the main code of the VBoxClient deamon. The
5 * X11-specific parts are split out into their own file for ease of testing.
6 */
7
8/*
9 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header files *
33*********************************************************************************************************************************/
34#include <new>
35
36#include <X11/Xlib.h>
37
38#include <iprt/asm.h>
39#include <iprt/errcore.h>
40#include <iprt/mem.h>
41
42#include <VBox/log.h>
43#include <VBox/VBoxGuestLib.h>
44
45#include "VBoxClient.h"
46#include "seamless.h"
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52
53/**
54 * Struct for keeping a service instance.
55 */
56struct SEAMLESSSERVICE
57{
58 /** Seamless service object. */
59 SeamlessMain mSeamless;
60};
61
62/** Service instance data. */
63static SEAMLESSSERVICE g_Svc;
64
65
66SeamlessMain::SeamlessMain(void)
67{
68 mX11MonitorThread = NIL_RTTHREAD;
69 mX11MonitorThreadStopping = false;
70
71 mMode = VMMDev_Seamless_Disabled;
72 mfPaused = true;
73}
74
75SeamlessMain::~SeamlessMain()
76{
77 /* Stopping will be done via main.cpp. */
78}
79
80/**
81 * Update the set of visible rectangles in the host.
82 */
83static void sendRegionUpdate(RTRECT *pRects, size_t cRects)
84{
85 if ( cRects
86 && !pRects) /* Assertion */
87 {
88 VBClLogError(("Region update called with NULL pointer\n"));
89 return;
90 }
91 VbglR3SeamlessSendRects(cRects, pRects);
92}
93
94/** @copydoc VBCLSERVICE::pfnInit */
95int SeamlessMain::init(void)
96{
97 int rc;
98 const char *pcszStage;
99
100 do
101 {
102 pcszStage = "Connecting to the X server";
103 rc = mX11Monitor.init(sendRegionUpdate);
104 if (RT_FAILURE(rc))
105 break;
106 pcszStage = "Setting guest IRQ filter mask";
107 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
108 if (RT_FAILURE(rc))
109 break;
110 pcszStage = "Reporting support for seamless capability";
111 rc = VbglR3SeamlessSetCap(true);
112 if (RT_FAILURE(rc))
113 break;
114 rc = startX11MonitorThread();
115 if (RT_FAILURE(rc))
116 break;
117
118 } while(0);
119
120 if (RT_FAILURE(rc))
121 VBClLogError("Failed to start in stage '%s' -- error %Rrc\n", pcszStage, rc);
122
123 return rc;
124}
125
126/** @copydoc VBCLSERVICE::pfnWorker */
127int SeamlessMain::worker(bool volatile *pfShutdown)
128{
129 int rc = VINF_SUCCESS;
130
131 /* Let the main thread know that it can continue spawning services. */
132 RTThreadUserSignal(RTThreadSelf());
133
134 /* This will only exit if something goes wrong. */
135 for (;;)
136 {
137 if (ASMAtomicReadBool(pfShutdown))
138 break;
139
140 rc = nextStateChangeEvent();
141
142 if (rc == VERR_TRY_AGAIN)
143 rc = VINF_SUCCESS;
144
145 if (RT_FAILURE(rc))
146 break;
147
148 if (ASMAtomicReadBool(pfShutdown))
149 break;
150
151 /* If we are not stopping, sleep for a bit to avoid using up too
152 much CPU while retrying. */
153 RTThreadYield();
154 }
155
156 return rc;
157}
158
159/** @copydoc VBCLSERVICE::pfnStop */
160void SeamlessMain::stop(void)
161{
162 VbglR3SeamlessSetCap(false);
163 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
164 stopX11MonitorThread();
165}
166
167/** @copydoc VBCLSERVICE::pfnTerm */
168int SeamlessMain::term(void)
169{
170 mX11Monitor.uninit();
171 return VINF_SUCCESS;
172}
173
174/**
175 * Waits for a seamless state change events from the host and dispatch it.
176 *
177 * @returns VBox return code, or
178 * VERR_TRY_AGAIN if no new status is available and we have to try it again
179 * at some later point in time.
180 */
181int SeamlessMain::nextStateChangeEvent(void)
182{
183 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
184
185 int rc = VbglR3SeamlessWaitEvent(&newMode);
186 if (RT_SUCCESS(rc))
187 {
188 mMode = newMode;
189 switch (newMode)
190 {
191 case VMMDev_Seamless_Visible_Region:
192 /* A simplified seamless mode, obtained by making the host VM window
193 * borderless and making the guest desktop transparent. */
194 VBClLogVerbose(2, "\"Visible region\" mode requested\n");
195 break;
196 case VMMDev_Seamless_Disabled:
197 VBClLogVerbose(2, "\"Disabled\" mode requested\n");
198 break;
199 case VMMDev_Seamless_Host_Window:
200 /* One host window represents one guest window. Not yet implemented. */
201 VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
202 return VERR_NOT_SUPPORTED;
203 default:
204 VBClLogError("Unsupported mode %d requested\n", newMode);
205 return VERR_NOT_SUPPORTED;
206 }
207 }
208 if ( RT_SUCCESS(rc)
209 || rc == VERR_TRY_AGAIN)
210 {
211 if (mMode == VMMDev_Seamless_Visible_Region)
212 mfPaused = false;
213 else
214 mfPaused = true;
215 mX11Monitor.interruptEventWait();
216 }
217 else
218 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
219
220 return rc;
221}
222
223/**
224 * The actual X11 window configuration change monitor thread function.
225 */
226int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
227{
228 RT_NOREF(hThreadSelf);
229
230 SeamlessMain *pThis = (SeamlessMain *)pvUser;
231 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
232
233 int rc = VINF_SUCCESS;
234
235 RTThreadUserSignal(hThreadSelf);
236
237 VBClLogVerbose(2, "X11 monitor thread started\n");
238
239 while (!pThis->mX11MonitorThreadStopping)
240 {
241 if (!pThis->mfPaused)
242 {
243 rc = pThis->mX11Monitor.start();
244 if (RT_FAILURE(rc))
245 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
246 pThis->mfPaused, rc);
247 }
248
249 pThis->mX11Monitor.nextConfigurationEvent();
250
251 if ( pThis->mfPaused
252 || pThis->mX11MonitorThreadStopping)
253 {
254 pThis->mX11Monitor.stop();
255 }
256 }
257
258 VBClLogVerbose(2, "X11 monitor thread ended\n");
259
260 return rc;
261}
262
263/**
264 * Start the X11 window configuration change monitor thread.
265 */
266int SeamlessMain::startX11MonitorThread(void)
267{
268 mX11MonitorThreadStopping = false;
269
270 if (isX11MonitorThreadRunning())
271 return VINF_SUCCESS;
272
273 int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
274 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
275 "seamless x11");
276 if (RT_SUCCESS(rc))
277 rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
278
279 if (RT_FAILURE(rc))
280 VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
281
282 return rc;
283}
284
285/**
286 * Stops the monitor thread.
287 */
288int SeamlessMain::stopX11MonitorThread(void)
289{
290 if (!isX11MonitorThreadRunning())
291 return VINF_SUCCESS;
292
293 mX11MonitorThreadStopping = true;
294 if (!mX11Monitor.interruptEventWait())
295 {
296 VBClLogError("Unable to notify X11 monitor thread\n");
297 return VERR_INVALID_STATE;
298 }
299
300 int rcThread;
301 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
302 if (RT_SUCCESS(rc))
303 rc = rcThread;
304
305 if (RT_SUCCESS(rc))
306 {
307 mX11MonitorThread = NIL_RTTHREAD;
308 }
309 else
310 VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
311
312 return rc;
313}
314
315/**
316 * @interface_method_impl{VBCLSERVICE,pfnInit}
317 */
318static DECLCALLBACK(int) vbclSeamlessInit(void)
319{
320 return g_Svc.mSeamless.init();
321}
322
323/**
324 * @interface_method_impl{VBCLSERVICE,pfnWorker}
325 */
326static DECLCALLBACK(int) vbclSeamlessWorker(bool volatile *pfShutdown)
327{
328 return g_Svc.mSeamless.worker(pfShutdown);
329}
330
331/**
332 * @interface_method_impl{VBCLSERVICE,pfnStop}
333 */
334static DECLCALLBACK(void) vbclSeamlessStop(void)
335{
336 return g_Svc.mSeamless.stop();
337}
338
339/**
340 * @interface_method_impl{VBCLSERVICE,pfnTerm}
341 */
342static DECLCALLBACK(int) vbclSeamlessTerm(void)
343{
344 return g_Svc.mSeamless.term();
345}
346
347VBCLSERVICE g_SvcSeamless =
348{
349 "seamless", /* szName */
350 "Seamless Mode Support", /* pszDescription */
351 ".vboxclient-seamless.pid", /* pszPidFilePath */
352 NULL, /* pszUsage */
353 NULL, /* pszOptions */
354 NULL, /* pfnOption */
355 vbclSeamlessInit, /* pfnInit */
356 vbclSeamlessWorker, /* pfnWorker */
357 vbclSeamlessStop, /* pfnStop*/
358 vbclSeamlessTerm /* pfnTerm */
359};
360
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