VirtualBox

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

Last change on this file since 57357 was 57357, checked in by vboxsync, 10 years ago

Additions/x11/VBoxClient: remove global VT switching handling again.

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