VirtualBox

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

Last change on this file since 87685 was 86873, checked in by vboxsync, 4 years ago

Additions/VBoxClient: Big revamp of the internal service handling and termination fixes. A service now runs as part of a worker thread, while the main thread is used for initialization / shutdown and signal handling [build fix].

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