VirtualBox

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

Last change on this file since 86117 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.7 KB
Line 
1/* $Id: seamless.cpp 82968 2020-02-04 10:35:17Z 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 <X11/Xlib.h>
25
26#include <VBox/log.h>
27#include <VBox/VBoxGuestLib.h>
28#include <iprt/errcore.h>
29#include <iprt/mem.h>
30
31#include "VBoxClient.h"
32#include "seamless.h"
33
34#include <new>
35
36SeamlessMain::SeamlessMain(void)
37{
38 LogRelFlowFuncEnter();
39 mX11MonitorThread = NIL_RTTHREAD;
40 mX11MonitorThreadStopping = false;
41 mMode = VMMDev_Seamless_Disabled;
42 mfPaused = true;
43}
44
45SeamlessMain::~SeamlessMain()
46{
47 LogRelFlowFuncEnter();
48 stop();
49}
50
51/**
52 * Update the set of visible rectangles in the host.
53 */
54static void sendRegionUpdate(RTRECT *pRects, size_t cRects)
55{
56 LogRelFlowFuncEnter();
57 if (cRects && !pRects) /* Assertion */
58 {
59 VBClLogError(("Region update called with NULL pointer!\n"));
60 return;
61 }
62 VbglR3SeamlessSendRects(cRects, pRects);
63 LogRelFlowFuncLeave();
64}
65
66/**
67 * initialise the service.
68 */
69int SeamlessMain::init(void)
70{
71 int rc;
72 const char *pcszStage;
73
74 LogRelFlowFuncEnter();
75 do {
76 pcszStage = "Connecting to the X server";
77 rc = mX11Monitor.init(sendRegionUpdate);
78 if (RT_FAILURE(rc))
79 break;
80 pcszStage = "Setting guest IRQ filter mask";
81 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
82 if (RT_FAILURE(rc))
83 break;
84 pcszStage = "Reporting support for seamless capability";
85 rc = VbglR3SeamlessSetCap(true);
86 if (RT_FAILURE(rc))
87 break;
88 rc = startX11MonitorThread();
89 if (RT_FAILURE(rc))
90 break;
91 } while(0);
92 if (RT_FAILURE(rc))
93 VBClLogError("Failed to start in stage '%s' -- error: %Rrc\n", pcszStage, rc);
94 return rc;
95}
96
97/**
98 * Run the main service thread which listens for host state change
99 * notifications.
100 * @returns iprt status value. Service will be set to the stopped state on
101 * failure.
102 */
103int SeamlessMain::run(void)
104{
105 int rc = VINF_SUCCESS;
106
107 LogRelFlowFuncEnter();
108 /* This will only exit if something goes wrong. */
109 while (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
110 {
111 if (RT_FAILURE(rc))
112 /* If we are not stopping, sleep for a bit to avoid using up too
113 much CPU while retrying. */
114 RTThreadYield();
115 rc = nextStateChangeEvent();
116 }
117 if (RT_FAILURE(rc))
118 {
119 VBClLogError("Event loop failed with error: %Rrc\n", rc);
120 stop();
121 }
122 return rc;
123}
124
125/** Stops the service. */
126void SeamlessMain::stop()
127{
128 LogRelFlowFuncEnter();
129 VbglR3SeamlessSetCap(false);
130 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
131 stopX11MonitorThread();
132 mX11Monitor.uninit();
133 LogRelFlowFuncLeave();
134}
135
136/**
137 * Waits for a seamless state change events from the host and dispatch it.
138 *
139 * @returns IRPT return code.
140 */
141int SeamlessMain::nextStateChangeEvent(void)
142{
143 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
144
145 LogRelFlowFuncEnter();
146 int rc = VbglR3SeamlessWaitEvent(&newMode);
147 if (RT_SUCCESS(rc))
148 {
149 mMode = newMode;
150 switch (newMode)
151 {
152 case VMMDev_Seamless_Visible_Region:
153 /* A simplified seamless mode, obtained by making the host VM window
154 * borderless and making the guest desktop transparent. */
155 LogRelFlowFunc(("\"Visible region\" mode requested (VBoxClient)\n"));
156 break;
157 case VMMDev_Seamless_Disabled:
158 LogRelFlowFunc(("\"Disabled\" mode requested (VBoxClient)\n"));
159 break;
160 case VMMDev_Seamless_Host_Window:
161 /* One host window represents one guest window. Not yet implemented. */
162 LogRelFunc(("Unsupported \"host window\" mode requested (VBoxClient)\n"));
163 return VERR_NOT_SUPPORTED;
164 default:
165 LogRelFunc(("Unsupported mode %d requested (VBoxClient)\n",
166 newMode));
167 return VERR_NOT_SUPPORTED;
168 }
169 }
170 if (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN)
171 {
172 if (mMode == VMMDev_Seamless_Visible_Region)
173 mfPaused = false;
174 else
175 mfPaused = true;
176 mX11Monitor.interruptEventWait();
177 }
178 else
179 {
180 LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc));
181 }
182 LogRelFlowFuncLeaveRC(rc);
183 return rc;
184}
185
186/**
187 * The actual X11 window configuration change monitor thread function.
188 */
189int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
190{
191 RT_NOREF1(hThreadSelf);
192 SeamlessMain *pHost = (SeamlessMain *)pvUser;
193 int rc = VINF_SUCCESS;
194
195 LogRelFlowFuncEnter();
196 while (!pHost->mX11MonitorThreadStopping)
197 {
198 if (!pHost->mfPaused)
199 {
200 rc = pHost->mX11Monitor.start();
201 if (RT_FAILURE(rc))
202 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
203 pHost->mfPaused, rc);
204 }
205 pHost->mX11Monitor.nextConfigurationEvent();
206 if (pHost->mfPaused || pHost->mX11MonitorThreadStopping)
207 pHost->mX11Monitor.stop();
208 }
209 LogRelFlowFuncLeaveRC(rc);
210 return rc;
211}
212
213/**
214 * Start the X11 window configuration change monitor thread.
215 */
216int SeamlessMain::startX11MonitorThread(void)
217{
218 int rc;
219
220 mX11MonitorThreadStopping = false;
221 if (isX11MonitorThreadRunning())
222 return VINF_SUCCESS;
223 rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
224 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
225 "X11 events");
226 if (RT_FAILURE(rc))
227 LogRelFunc(("Warning: failed to start X11 monitor thread (VBoxClient)\n"));
228 return rc;
229}
230
231/**
232 * Send a signal to the thread function that it should exit
233 */
234int SeamlessMain::stopX11MonitorThread(void)
235{
236 int rc;
237
238 mX11MonitorThreadStopping = true;
239 if (!isX11MonitorThreadRunning())
240 return VINF_SUCCESS;
241 mX11Monitor.interruptEventWait();
242 rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
243 if (RT_SUCCESS(rc))
244 mX11MonitorThread = NIL_RTTHREAD;
245 else
246 LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
247 rc));
248 return rc;
249}
250
251/** Service magic number, start of a UUID. */
252#define SEAMLESSSERVICE_MAGIC 0xd28ba727
253
254/** VBoxClient service class wrapping the logic for the seamless service while
255 * the main VBoxClient code provides the daemon logic needed by all services.
256 */
257struct SEAMLESSSERVICE
258{
259 /** The service interface. */
260 struct VBCLSERVICE *pInterface;
261 /** Magic number for sanity checks. */
262 uint32_t magic;
263 /** Seamless service object. */
264 SeamlessMain mSeamless;
265 /** Are we initialised yet? */
266 bool mIsInitialised;
267};
268
269static const char *getName()
270{
271 return "Seamless";
272}
273
274static const char *getPidFilePath(void)
275{
276 return ".vboxclient-seamless.pid";
277}
278
279static struct SEAMLESSSERVICE *getClassFromInterface(struct VBCLSERVICE **
280 ppInterface)
281{
282 struct SEAMLESSSERVICE *pSelf = (struct SEAMLESSSERVICE *)ppInterface;
283 if (pSelf->magic != SEAMLESSSERVICE_MAGIC)
284 VBClLogFatalError("Bad seamless service object!\n");
285 return pSelf;
286}
287
288static int init(struct VBCLSERVICE **ppInterface)
289{
290 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
291
292 if (pSelf->mIsInitialised)
293 return VERR_INTERNAL_ERROR;
294
295 int rc = pSelf->mSeamless.init();
296 if (RT_FAILURE(rc))
297 return rc;
298 pSelf->mIsInitialised = true;
299 return VINF_SUCCESS;
300}
301
302static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
303{
304 RT_NOREF1(fDaemonised);
305 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
306 int rc;
307
308 if (!pSelf->mIsInitialised)
309 return VERR_INTERNAL_ERROR;
310 /* This only exits on error. */
311 rc = pSelf->mSeamless.run();
312 pSelf->mIsInitialised = false;
313 return rc;
314}
315
316static void cleanup(struct VBCLSERVICE **ppInterface)
317{
318 RT_NOREF(ppInterface);
319 VbglR3SeamlessSetCap(false);
320 VbglR3Term();
321}
322
323struct VBCLSERVICE vbclSeamlessInterface =
324{
325 getName,
326 getPidFilePath,
327 init,
328 run,
329 cleanup
330};
331
332struct VBCLSERVICE **VBClGetSeamlessService()
333{
334 struct SEAMLESSSERVICE *pService =
335 (struct SEAMLESSSERVICE *)RTMemAlloc(sizeof(*pService));
336
337 if (!pService)
338 VBClLogFatalError("Out of memory\n");
339 pService->pInterface = &vbclSeamlessInterface;
340 pService->magic = SEAMLESSSERVICE_MAGIC;
341 new(&pService->mSeamless) SeamlessMain();
342 pService->mIsInitialised = false;
343 return &pService->pInterface;
344}
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