VirtualBox

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

Last change on this file since 50460 was 50374, checked in by vboxsync, 11 years ago

Additions/x11/VBoxClient: aesthetics.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.8 KB
Line 
1/** @file
2 * X11 Guest client - seamless mode: main logic, communication with the host and
3 * wrapper interface for the main code of the VBoxClient deamon. The
4 * X11-specific parts are split out into their own file for ease of testing.
5 */
6
7/*
8 * Copyright (C) 2006-2014 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*****************************************************************************
20* Header files *
21*****************************************************************************/
22
23#include <X11/Xlib.h>
24
25#include <VBox/log.h>
26#include <VBox/VMMDev.h>
27#include <VBox/VBoxGuestLib.h>
28#include <iprt/err.h>
29
30#include "VBoxClient.h"
31#include "seamless.h"
32
33SeamlessMain::SeamlessMain(void)
34{
35 LogRelFlowFunc(("\n"));
36 mX11MonitorThread = NIL_RTTHREAD;
37 mX11MonitorThreadStopping = false;
38 mHostEventThread = NIL_RTTHREAD;
39 mHostEventThreadRunning = false;
40 mHostEventThreadStopping = false;
41}
42
43SeamlessMain::~SeamlessMain()
44{
45 LogRelFlowFunc(("\n"));
46 stop();
47}
48
49/**
50 * Start the main service thread which listens for host state change
51 * notifications.
52 * @returns iprt status value. Service will be set to the stopped state on
53 * failure.
54 */
55int SeamlessMain::start(void)
56{
57 int rc;
58 const char *pszStage;
59
60 LogRelFlowFunc(("\n"));
61 do {
62 pszStage = "Checking that we are not already running";
63 rc = VERR_INTERNAL_ERROR;
64 if (mHostEventThread) /* Assertion */
65 break;
66 pszStage = "Testing event loop cancellation";
67 VbglR3InterruptEventWaits();
68 if (RT_FAILURE(VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)))
69 break;
70 if ( VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)
71 != VERR_TIMEOUT)
72 break;
73 pszStage = "Connecting to the X server";
74 rc = mX11Monitor.init(this);
75 if (RT_FAILURE(rc))
76 break;
77 /* Create a thread to wait for requests from the host. This is currently
78 * done on a separate thread as the main thread monitors the X11 server
79 * for disconnections. */
80 /** @todo Move the disconnection monitoring to its own thread (better, the
81 * VT monitor thread) and run this logic on the main service thread. */
82 pszStage = "Starting host event thread";
83 rc = startHostEventThread();
84 if (RT_FAILURE(rc))
85 break;
86 pszStage = "Setting guest IRQ filter mask";
87 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
88 if (RT_FAILURE(rc))
89 break;
90 pszStage = "Reporting support for seamless capability";
91 rc = VbglR3SeamlessSetCap(true);
92 if (RT_FAILURE(rc))
93 break;
94 } while(0);
95 if (RT_FAILURE(rc))
96 {
97 LogRel(("VBoxClient (seamless): failed to start. Stage: \"%s\" Error: %Rrc\n",
98 pszStage, rc));
99 stop();
100 }
101 LogRelFlowFunc(("returning %Rrc\n", rc));
102 return rc;
103}
104
105/** Stops the service. */
106void SeamlessMain::stop()
107{
108 LogRelFlowFunc(("\n"));
109 VbglR3SeamlessSetCap(false);
110 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
111 if (mHostEventThread)
112 stopHostEventThread();
113 stopX11MonitorThread();
114 mX11Monitor.uninit();
115 LogRelFlowFunc(("returning\n"));
116}
117
118/**
119 * Waits for a seamless state change events from the host and dispatch it.
120 *
121 * @returns IRPT return code.
122 */
123int SeamlessMain::nextStateChangeEvent(void)
124{
125 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
126
127 LogRelFlowFunc(("\n"));
128 int rc = VbglR3SeamlessWaitEvent(&newMode);
129 if (RT_SUCCESS(rc))
130 {
131 switch(newMode)
132 {
133 case VMMDev_Seamless_Visible_Region:
134 /* A simplified seamless mode, obtained by making the host VM window borderless and
135 making the guest desktop transparent. */
136 LogRelFlowFunc(("VMMDev_Seamless_Visible_Region request received (VBoxClient).\n"));
137 /** @todo Do something on failure, like bail out. */
138 startX11MonitorThread();
139 break;
140 case VMMDev_Seamless_Host_Window:
141 /* One host window represents one guest window. Not yet implemented. */
142 LogRelFunc(("Warning: VMMDev_Seamless_Host_Window request received (VBoxClient).\n"));
143 /* fall through to default */
144 default:
145 LogRelFunc(("Warning: unsupported VMMDev_Seamless request %d received (VBoxClient).\n", newMode));
146 /* fall through to case VMMDev_Seamless_Disabled */
147 case VMMDev_Seamless_Disabled:
148 LogRelFlowFunc(("VMMDev_Seamless_Disabled set (VBoxClient).\n"));
149 stopX11MonitorThread();
150 }
151 }
152 else
153 {
154 LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc));
155 }
156 LogRelFlowFunc(("returning %Rrc\n", rc));
157 return rc;
158}
159
160/**
161 * Update the set of visible rectangles in the host.
162 */
163void SeamlessMain::sendRegionUpdate(RTRECT *pRects, size_t cRects)
164{
165 LogRelFlowFunc(("\n"));
166 if (cRects && !pRects) /* Assertion */
167 {
168 LogRelThisFunc(("ERROR: called with null pointer!\n"));
169 return;
170 }
171 VbglR3SeamlessSendRects(cRects, pRects);
172 LogRelFlowFunc(("returning\n"));
173}
174
175
176/**
177 * Thread to listen for seamless state change notifications from the host.
178 */
179int SeamlessMain::hostEventThread(RTTHREAD self, void *pvUser)
180{
181 SeamlessMain *pHost = (SeamlessMain *)pvUser;
182
183 LogRelFlowFunc(("\n"));
184 pHost->mHostEventThreadRunning = true;
185 if (0 != pHost)
186 {
187 while (!pHost->mHostEventThreadStopping)
188 {
189 /* This thread is stopped by setting @a mHostEventThreadStopping
190 * and sending a cancel to the state change event wait, see below.
191 */
192 int rc = pHost->nextStateChangeEvent();
193 if (RT_FAILURE(rc) && !pHost->mHostEventThreadStopping)
194 {
195 /* If we are not stopping, sleep for a bit to avoid using up too
196 much CPU while retrying. */
197 RTThreadYield();
198 }
199 }
200 }
201 pHost->mHostEventThreadRunning = false;
202 return VINF_SUCCESS;
203}
204
205/**
206 * Start the seamless state change notification listener thread.
207 */
208int SeamlessMain::startHostEventThread()
209{
210 int rc;
211
212 mHostEventThreadStopping = false;
213 rc = RTThreadCreate(&mHostEventThread, hostEventThread, this, 0,
214 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
215 "Host events");
216 if (RT_FAILURE(rc))
217 LogRel(("VBoxClient: failed to start seamless event thread, rc=%Rrc.\n",
218 rc));
219 return rc;
220}
221
222/**
223 * Send a signal to the host event thread that it should exit and poke it.
224 */
225void SeamlessMain::stopHostEventThread()
226{
227 int rc;
228
229 LogRelFlowFunc(("\n"));
230 mHostEventThreadStopping = true;
231 cancelEvent();
232 rc = RTThreadWait(mHostEventThread, RT_INDEFINITE_WAIT, NULL);
233 if (RT_SUCCESS(rc))
234 mHostEventThread = NIL_RTTHREAD;
235 else
236 LogRelThisFunc(("Failed to stop seamless event thread, rc=%Rrc!\n",
237 rc));
238 LogRelFlowFunc(("returning\n"));
239}
240
241/**
242 * The actual X11 window configuration change monitor thread function.
243 */
244int SeamlessMain::x11MonitorThread(RTTHREAD self, void *pvUser)
245{
246 SeamlessMain *pHost = (SeamlessMain *)pvUser;
247 int rc = VINF_SUCCESS;
248
249 LogRelFlowFunc(("\n"));
250 rc = pHost->mX11Monitor.start();
251 if (RT_SUCCESS(rc))
252 {
253 while (!pHost->mX11MonitorThreadStopping)
254 pHost->mX11Monitor.nextConfigurationEvent();
255 pHost->mX11Monitor.stop();
256 }
257 LogRelFlowFunc(("returning %Rrc\n", rc));
258 return rc;
259}
260
261/**
262 * Start the X11 window configuration change monitor thread.
263 */
264int SeamlessMain::startX11MonitorThread(void)
265{
266 int rc;
267
268 mX11MonitorThreadStopping = false;
269 rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
270 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
271 "X11 events");
272 if (RT_FAILURE(rc))
273 LogRelFunc(("Warning: failed to start X11 monitor thread (VBoxClient).\n"));
274 return rc;
275}
276
277/**
278 * Send a signal to the thread function that it should exit
279 */
280void SeamlessMain::stopX11MonitorThread(void)
281{
282 int rc;
283
284 mX11MonitorThreadStopping = true;
285 if (!mX11MonitorThread)
286 return;
287 mX11Monitor.interruptEventWait();
288 rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
289 if (RT_SUCCESS(rc))
290 mX11MonitorThread = NIL_RTTHREAD;
291 else
292 LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
293 rc));
294}
295
296/** VBoxClient service class wrapping the logic for the seamless service while
297 * the main VBoxClient code provides the daemon logic needed by all services.
298 */
299class SeamlessService : public VBoxClient::Service
300{
301private:
302 SeamlessMain mSeamless;
303 bool mIsInitialised;
304public:
305 virtual const char *getPidFilePath()
306 {
307 return ".vboxclient-seamless.pid";
308 }
309 virtual int run(bool fDaemonised /* = false */)
310 {
311 Display *pDisplay = NULL;
312 const char *pszStage;
313 XEvent ev;
314 int rc;
315
316 do {
317 pszStage = "Checking that we are not already running";
318 rc = VERR_INTERNAL_ERROR;
319 if (mIsInitialised) /* Assertion */
320 break;
321 pszStage = "Connecting to the X server";
322 rc = VERR_INTERNAL_ERROR;
323 pDisplay = XOpenDisplay(NULL);
324 if (!pDisplay)
325 break;
326 pszStage = "Starting the service";
327 rc = mSeamless.start();
328 if (RT_FAILURE(rc))
329 break;
330 } while(0);
331 if (RT_FAILURE(rc))
332 {
333 LogRelFunc(("VBoxClient seamless service control: failed at stage: \"%s\". Error: %Rrc\n",
334 pszStage, rc));
335 mSeamless.stop();
336 if (pDisplay)
337 XCloseDisplay(pDisplay);
338 return rc;
339 }
340 mIsInitialised = true;
341 /* Stay running as long as X does... */
342 while (true)
343 XNextEvent(pDisplay, &ev);
344 return VERR_INTERRUPTED;
345 }
346 virtual void cleanup()
347 {
348 VbglR3SeamlessSetCap(false);
349 }
350};
351
352VBoxClient::Service *VBoxClient::GetSeamlessService()
353{
354 return new SeamlessService;
355}
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