VirtualBox

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

Last change on this file since 65641 was 62883, checked in by vboxsync, 8 years ago

Additions/*: gcc warnings.

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