VirtualBox

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

Last change on this file since 78351 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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