VirtualBox

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

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

added a couple of missing Id headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.0 KB
Line 
1/* $Id: seamless.cpp 55401 2015-04-23 10:03: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-2014 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.215389.xyz. 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 = false;
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 } while(0);
90 if (RT_FAILURE(rc))
91 LogRel(("VBoxClient (seamless): failed to start. Stage: \"%s\" Error: %Rrc\n",
92 pcszStage, rc));
93 return rc;
94}
95
96/**
97 * Run the main service thread which listens for host state change
98 * notifications.
99 * @returns iprt status value. Service will be set to the stopped state on
100 * failure.
101 */
102int SeamlessMain::run(void)
103{
104 int rc = VINF_SUCCESS;
105
106 LogRelFlowFunc(("\n"));
107 /* This will only exit if something goes wrong. */
108 while (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
109 {
110 if (RT_FAILURE(rc))
111 /* If we are not stopping, sleep for a bit to avoid using up too
112 much CPU while retrying. */
113 RTThreadYield();
114 rc = nextStateChangeEvent();
115 }
116 if (RT_FAILURE(rc))
117 {
118 LogRel(("VBoxClient (seamless): event loop failed with error: %Rrc\n",
119 rc));
120 stop();
121 }
122 return rc;
123}
124
125/** Stops the service. */
126void SeamlessMain::stop()
127{
128 LogRelFlowFunc(("\n"));
129 VbglR3SeamlessSetCap(false);
130 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
131 stopX11MonitorThread();
132 mX11Monitor.uninit();
133 LogRelFlowFunc(("returning\n"));
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 LogRelFlowFunc(("\n"));
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 && !mfPaused)
173 /* This does it's own logging on failure. */
174 rc = startX11MonitorThread();
175 else
176 /* This does it's own logging on failure. */
177 rc = stopX11MonitorThread();
178 }
179 else
180 {
181 LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc));
182 }
183 LogRelFlowFunc(("returning %Rrc\n", rc));
184 return rc;
185}
186
187int SeamlessMain::cancelEvent(void)
188{
189 return VbglR3InterruptEventWaits();
190}
191
192/**
193 * The actual X11 window configuration change monitor thread function.
194 */
195int SeamlessMain::x11MonitorThread(RTTHREAD self, void *pvUser)
196{
197 SeamlessMain *pHost = (SeamlessMain *)pvUser;
198 int rc = VINF_SUCCESS;
199
200 LogRelFlowFunc(("\n"));
201 rc = pHost->mX11Monitor.start();
202 if (RT_SUCCESS(rc))
203 {
204 while (!pHost->mX11MonitorThreadStopping)
205 pHost->mX11Monitor.nextConfigurationEvent();
206 pHost->mX11Monitor.stop();
207 }
208 LogRelFlowFunc(("returning %Rrc\n", rc));
209 return rc;
210}
211
212/**
213 * Start the X11 window configuration change monitor thread.
214 */
215int SeamlessMain::startX11MonitorThread(void)
216{
217 int rc;
218
219 mX11MonitorThreadStopping = false;
220 if (isX11MonitorThreadRunning())
221 return VINF_SUCCESS;
222 rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
223 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
224 "X11 events");
225 if (RT_FAILURE(rc))
226 LogRelFunc(("Warning: failed to start X11 monitor thread (VBoxClient).\n"));
227 return rc;
228}
229
230/**
231 * Send a signal to the thread function that it should exit
232 */
233int SeamlessMain::stopX11MonitorThread(void)
234{
235 int rc;
236
237 mX11MonitorThreadStopping = true;
238 if (!isX11MonitorThreadRunning())
239 return VINF_SUCCESS;
240 mX11Monitor.interruptEventWait();
241 rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
242 if (RT_SUCCESS(rc))
243 mX11MonitorThread = NIL_RTTHREAD;
244 else
245 LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
246 rc));
247 return rc;
248}
249
250/** Pause the service loop. */
251int SeamlessMain::pause()
252{
253 int rc;
254 const char *pcszStage;
255
256 LogRelFlowFunc(("\n"));
257 mfPaused = true;
258 do {
259 pcszStage = "Reporting end of support for seamless capability";
260 rc = VbglR3SeamlessSetCap(false);
261 if (RT_FAILURE(rc))
262 break;
263 pcszStage = "Interrupting the event loop";
264 rc = cancelEvent();
265 if (RT_FAILURE(rc))
266 break;
267 } while (0);
268 if (RT_FAILURE(rc))
269 LogRelFunc(("Failure. Stage: \"%s\" Error: %Rrc (VBoxClient)\n",
270 pcszStage, rc));
271 return rc;
272}
273
274/** Resume after pausing. */
275int SeamlessMain::resume()
276{
277 int rc;
278 const char *pcszStage;
279
280 LogRelFlowFunc(("\n"));
281 mfPaused = false;
282 do {
283 pcszStage = "Reporting support for seamless capability";
284 rc = VbglR3SeamlessSetCap(true);
285 if (RT_FAILURE(rc))
286 break;
287 pcszStage = "Interrupting the event loop";
288 rc = cancelEvent();
289 if (RT_FAILURE(rc))
290 break;
291 } while (0);
292 if (RT_FAILURE(rc))
293 LogRelFunc(("Failure. Stage: \"%s\" Error: %Rrc (VBoxClient)\n",
294 pcszStage, rc));
295 return rc;
296}
297
298/** @todo Expand this? */
299int SeamlessMain::selfTest()
300{
301 int rc = VERR_INTERNAL_ERROR;
302 const char *pcszStage;
303
304 LogRelFlowFunc(("\n"));
305 do {
306 pcszStage = "Testing event loop cancellation";
307 VbglR3InterruptEventWaits();
308 if (RT_FAILURE(VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)))
309 break;
310 if ( VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)
311 != VERR_TIMEOUT)
312 break;
313 rc = VINF_SUCCESS;
314 } while(0);
315 if (RT_FAILURE(rc))
316 LogRel(("VBoxClient (seamless): self test failed. Stage: \"%s\"\n",
317 pcszStage));
318 return rc;
319}
320
321/** Service magic number, start of a UUID. */
322#define SEAMLESSSERVICE_MAGIC 0xd28ba727
323
324/** VBoxClient service class wrapping the logic for the seamless service while
325 * the main VBoxClient code provides the daemon logic needed by all services.
326 */
327struct SEAMLESSSERVICE
328{
329 /** The service interface. */
330 struct VBCLSERVICE *pInterface;
331 /** Magic number for sanity checks. */
332 uint32_t magic;
333 /** Seamless service object. */
334 SeamlessMain mSeamless;
335 /** Are we initialised yet? */
336 bool mIsInitialised;
337};
338
339static const char *getPidFilePath(void)
340{
341 return ".vboxclient-seamless.pid";
342}
343
344static struct SEAMLESSSERVICE *getClassFromInterface(struct VBCLSERVICE **
345 ppInterface)
346{
347 struct SEAMLESSSERVICE *pSelf = (struct SEAMLESSSERVICE *)ppInterface;
348 if (pSelf->magic != SEAMLESSSERVICE_MAGIC)
349 VBClFatalError(("Bad seamless service object!\n"));
350 return pSelf;
351}
352
353static int init(struct VBCLSERVICE **ppInterface)
354{
355 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
356 int rc;
357
358 if (pSelf->mIsInitialised)
359 return VERR_INTERNAL_ERROR;
360 /* Initialise the guest library. */
361 rc = VbglR3InitUser();
362 if (RT_FAILURE(rc))
363 VBClFatalError(("Failed to connect to the VirtualBox kernel service, rc=%Rrc\n", rc));
364 rc = pSelf->mSeamless.init();
365 if (RT_FAILURE(rc))
366 return rc;
367 rc = pSelf->mSeamless.selfTest();
368 if (RT_FAILURE(rc))
369 {
370 pSelf->mSeamless.stop();
371 return rc;
372 }
373 pSelf->mIsInitialised = true;
374 return VINF_SUCCESS;
375}
376
377static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
378{
379 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
380 int rc;
381
382 if (!pSelf->mIsInitialised)
383 return VERR_INTERNAL_ERROR;
384 rc = VBClStartVTMonitor();
385 if (RT_FAILURE(rc))
386 VBClFatalError(("Failed to start the VT monitor thread: %Rrc\n", rc));
387 /* This only exits on error. */
388 rc = pSelf->mSeamless.run();
389 pSelf->mIsInitialised = false;
390 return rc;
391}
392
393static int pause(struct VBCLSERVICE **ppInterface)
394{
395 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
396
397 return pSelf->mSeamless.pause();
398}
399
400static int resume(struct VBCLSERVICE **ppInterface)
401{
402 struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
403
404 return pSelf->mSeamless.resume();
405}
406
407static void cleanup(struct VBCLSERVICE **ppInterface)
408{
409 NOREF(ppInterface);
410 VbglR3SeamlessSetCap(false);
411 VbglR3Term();
412}
413
414struct VBCLSERVICE vbclSeamlessInterface =
415{
416 getPidFilePath,
417 init,
418 run,
419 pause,
420 resume,
421 cleanup
422};
423
424struct VBCLSERVICE **VBClGetSeamlessService()
425{
426 struct SEAMLESSSERVICE *pService =
427 (struct SEAMLESSSERVICE *)RTMemAlloc(sizeof(*pService));
428
429 if (!pService)
430 VBClFatalError(("Out of memory\n"));
431 pService->pInterface = &vbclSeamlessInterface;
432 pService->magic = SEAMLESSSERVICE_MAGIC;
433 new(&pService->mSeamless) SeamlessMain();
434 pService->mIsInitialised = false;
435 return &pService->pInterface;
436}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette