VirtualBox

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

Last change on this file since 95478 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.4 KB
Line 
1/* $Id: seamless.cpp 93115 2022-01-01 11:31:46Z 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 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 mX11Monitor.uninit();
161 return VINF_SUCCESS;
162}
163
164/**
165 * Waits for a seamless state change events from the host and dispatch it.
166 *
167 * @returns VBox return code, or
168 * VERR_TRY_AGAIN if no new status is available and we have to try it again
169 * at some later point in time.
170 */
171int SeamlessMain::nextStateChangeEvent(void)
172{
173 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
174
175 int rc = VbglR3SeamlessWaitEvent(&newMode);
176 if (RT_SUCCESS(rc))
177 {
178 mMode = newMode;
179 switch (newMode)
180 {
181 case VMMDev_Seamless_Visible_Region:
182 /* A simplified seamless mode, obtained by making the host VM window
183 * borderless and making the guest desktop transparent. */
184 VBClLogVerbose(2, "\"Visible region\" mode requested\n");
185 break;
186 case VMMDev_Seamless_Disabled:
187 VBClLogVerbose(2, "\"Disabled\" mode requested\n");
188 break;
189 case VMMDev_Seamless_Host_Window:
190 /* One host window represents one guest window. Not yet implemented. */
191 VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
192 return VERR_NOT_SUPPORTED;
193 default:
194 VBClLogError("Unsupported mode %d requested\n", newMode);
195 return VERR_NOT_SUPPORTED;
196 }
197 }
198 if ( RT_SUCCESS(rc)
199 || rc == VERR_TRY_AGAIN)
200 {
201 if (mMode == VMMDev_Seamless_Visible_Region)
202 mfPaused = false;
203 else
204 mfPaused = true;
205 mX11Monitor.interruptEventWait();
206 }
207 else
208 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
209
210 return rc;
211}
212
213/**
214 * The actual X11 window configuration change monitor thread function.
215 */
216int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
217{
218 RT_NOREF(hThreadSelf);
219
220 SeamlessMain *pThis = (SeamlessMain *)pvUser;
221 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
222
223 int rc = VINF_SUCCESS;
224
225 RTThreadUserSignal(hThreadSelf);
226
227 VBClLogVerbose(2, "X11 monitor thread started\n");
228
229 while (!pThis->mX11MonitorThreadStopping)
230 {
231 if (!pThis->mfPaused)
232 {
233 rc = pThis->mX11Monitor.start();
234 if (RT_FAILURE(rc))
235 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
236 pThis->mfPaused, rc);
237 }
238
239 pThis->mX11Monitor.nextConfigurationEvent();
240
241 if ( pThis->mfPaused
242 || pThis->mX11MonitorThreadStopping)
243 {
244 pThis->mX11Monitor.stop();
245 }
246 }
247
248 VBClLogVerbose(2, "X11 monitor thread ended\n");
249
250 return rc;
251}
252
253/**
254 * Start the X11 window configuration change monitor thread.
255 */
256int SeamlessMain::startX11MonitorThread(void)
257{
258 mX11MonitorThreadStopping = false;
259
260 if (isX11MonitorThreadRunning())
261 return VINF_SUCCESS;
262
263 int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
264 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
265 "seamless x11");
266 if (RT_SUCCESS(rc))
267 rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
268
269 if (RT_FAILURE(rc))
270 VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
271
272 return rc;
273}
274
275/**
276 * Stops the monitor thread.
277 */
278int SeamlessMain::stopX11MonitorThread(void)
279{
280 if (!isX11MonitorThreadRunning())
281 return VINF_SUCCESS;
282
283 mX11MonitorThreadStopping = true;
284 if (!mX11Monitor.interruptEventWait())
285 {
286 VBClLogError("Unable to notify X11 monitor thread\n");
287 return VERR_INVALID_STATE;
288 }
289
290 int rcThread;
291 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
292 if (RT_SUCCESS(rc))
293 rc = rcThread;
294
295 if (RT_SUCCESS(rc))
296 {
297 mX11MonitorThread = NIL_RTTHREAD;
298 }
299 else
300 VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
301
302 return rc;
303}
304
305/**
306 * @interface_method_impl{VBCLSERVICE,pfnInit}
307 */
308static DECLCALLBACK(int) vbclSeamlessInit(void)
309{
310 return g_Svc.mSeamless.init();
311}
312
313/**
314 * @interface_method_impl{VBCLSERVICE,pfnWorker}
315 */
316static DECLCALLBACK(int) vbclSeamlessWorker(bool volatile *pfShutdown)
317{
318 return g_Svc.mSeamless.worker(pfShutdown);
319}
320
321/**
322 * @interface_method_impl{VBCLSERVICE,pfnStop}
323 */
324static DECLCALLBACK(void) vbclSeamlessStop(void)
325{
326 return g_Svc.mSeamless.stop();
327}
328
329/**
330 * @interface_method_impl{VBCLSERVICE,pfnTerm}
331 */
332static DECLCALLBACK(int) vbclSeamlessTerm(void)
333{
334 return g_Svc.mSeamless.term();
335}
336
337VBCLSERVICE g_SvcSeamless =
338{
339 "seamless", /* szName */
340 "Seamless Mode Support", /* pszDescription */
341 ".vboxclient-seamless.pid", /* pszPidFilePath */
342 NULL, /* pszUsage */
343 NULL, /* pszOptions */
344 NULL, /* pfnOption */
345 vbclSeamlessInit, /* pfnInit */
346 vbclSeamlessWorker, /* pfnWorker */
347 vbclSeamlessStop, /* pfnStop*/
348 vbclSeamlessTerm /* pfnTerm */
349};
350
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