VirtualBox

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

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

Additions/x11/VBoxClient: remove the host event thread and run the code on the main thread.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.1 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}
39
40SeamlessMain::~SeamlessMain()
41{
42 LogRelFlowFunc(("\n"));
43 stop();
44}
45
46/**
47 * Start the main service thread which listens for host state change
48 * notifications.
49 * @returns iprt status value. Service will be set to the stopped state on
50 * failure.
51 */
52int SeamlessMain::start(void)
53{
54 int rc;
55 const char *pszStage;
56
57 LogRelFlowFunc(("\n"));
58 do {
59 pszStage = "Testing event loop cancellation";
60 VbglR3InterruptEventWaits();
61 if (RT_FAILURE(VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)))
62 break;
63 if ( VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)
64 != VERR_TIMEOUT)
65 break;
66 pszStage = "Connecting to the X server";
67 rc = mX11Monitor.init(this);
68 if (RT_FAILURE(rc))
69 break;
70 pszStage = "Setting guest IRQ filter mask";
71 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
72 if (RT_FAILURE(rc))
73 break;
74 pszStage = "Reporting support for seamless capability";
75 rc = VbglR3SeamlessSetCap(true);
76 if (RT_FAILURE(rc))
77 break;
78 pszStage = "Running event loop";
79 /* This will only exit if something goes wrong. */
80 /** @todo Add a "stopping" variable. Actually "pausing" the service
81 * should be enough. */
82 while (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN || rc == VERR_INTERRUPTED)
83 {
84 if (RT_FAILURE(rc))
85 /* If we are not stopping, sleep for a bit to avoid using up too
86 much CPU while retrying. */
87 RTThreadYield();
88 rc = nextStateChangeEvent();
89 }
90 } while(0);
91 if (RT_FAILURE(rc))
92 {
93 LogRel(("VBoxClient (seamless): failed to start. Stage: \"%s\" Error: %Rrc\n",
94 pszStage, rc));
95 stop();
96 }
97 LogRelFlowFunc(("returning %Rrc\n", rc));
98 return rc;
99}
100
101/** Stops the service. */
102void SeamlessMain::stop()
103{
104 LogRelFlowFunc(("\n"));
105 VbglR3SeamlessSetCap(false);
106 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
107 stopX11MonitorThread();
108 mX11Monitor.uninit();
109 LogRelFlowFunc(("returning\n"));
110}
111
112/**
113 * Waits for a seamless state change events from the host and dispatch it.
114 *
115 * @returns IRPT return code.
116 */
117int SeamlessMain::nextStateChangeEvent(void)
118{
119 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
120
121 LogRelFlowFunc(("\n"));
122 int rc = VbglR3SeamlessWaitEvent(&newMode);
123 if (RT_SUCCESS(rc))
124 {
125 switch(newMode)
126 {
127 case VMMDev_Seamless_Visible_Region:
128 /* A simplified seamless mode, obtained by making the host VM window borderless and
129 making the guest desktop transparent. */
130 LogRelFlowFunc(("VMMDev_Seamless_Visible_Region request received (VBoxClient).\n"));
131 /** @todo Do something on failure, like bail out. */
132 startX11MonitorThread();
133 break;
134 case VMMDev_Seamless_Host_Window:
135 /* One host window represents one guest window. Not yet implemented. */
136 LogRelFunc(("Warning: VMMDev_Seamless_Host_Window request received (VBoxClient).\n"));
137 /* fall through to default */
138 default:
139 LogRelFunc(("Warning: unsupported VMMDev_Seamless request %d received (VBoxClient).\n", newMode));
140 /* fall through to case VMMDev_Seamless_Disabled */
141 case VMMDev_Seamless_Disabled:
142 LogRelFlowFunc(("VMMDev_Seamless_Disabled set (VBoxClient).\n"));
143 stopX11MonitorThread();
144 }
145 }
146 else
147 {
148 LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc));
149 }
150 LogRelFlowFunc(("returning %Rrc\n", rc));
151 return rc;
152}
153
154/**
155 * Update the set of visible rectangles in the host.
156 */
157void SeamlessMain::sendRegionUpdate(RTRECT *pRects, size_t cRects)
158{
159 LogRelFlowFunc(("\n"));
160 if (cRects && !pRects) /* Assertion */
161 {
162 LogRelThisFunc(("ERROR: called with null pointer!\n"));
163 return;
164 }
165 VbglR3SeamlessSendRects(cRects, pRects);
166 LogRelFlowFunc(("returning\n"));
167}
168
169
170/**
171 * The actual X11 window configuration change monitor thread function.
172 */
173int SeamlessMain::x11MonitorThread(RTTHREAD self, void *pvUser)
174{
175 SeamlessMain *pHost = (SeamlessMain *)pvUser;
176 int rc = VINF_SUCCESS;
177
178 LogRelFlowFunc(("\n"));
179 rc = pHost->mX11Monitor.start();
180 if (RT_SUCCESS(rc))
181 {
182 while (!pHost->mX11MonitorThreadStopping)
183 pHost->mX11Monitor.nextConfigurationEvent();
184 pHost->mX11Monitor.stop();
185 }
186 LogRelFlowFunc(("returning %Rrc\n", rc));
187 return rc;
188}
189
190/**
191 * Start the X11 window configuration change monitor thread.
192 */
193int SeamlessMain::startX11MonitorThread(void)
194{
195 int rc;
196
197 mX11MonitorThreadStopping = false;
198 rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
199 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
200 "X11 events");
201 if (RT_FAILURE(rc))
202 LogRelFunc(("Warning: failed to start X11 monitor thread (VBoxClient).\n"));
203 return rc;
204}
205
206/**
207 * Send a signal to the thread function that it should exit
208 */
209void SeamlessMain::stopX11MonitorThread(void)
210{
211 int rc;
212
213 mX11MonitorThreadStopping = true;
214 if (!mX11MonitorThread)
215 return;
216 mX11Monitor.interruptEventWait();
217 rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
218 if (RT_SUCCESS(rc))
219 mX11MonitorThread = NIL_RTTHREAD;
220 else
221 LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
222 rc));
223}
224
225/** @todo Re-arrange the service to support pausing and resuming. The state
226 * needs to become more complex: we need to know: whether seamless is currently
227 * requested by the host; whether we are currently in charge of the guest
228 * desktop; whether the guest monitoring thead is currently active. */
229/** VBoxClient service class wrapping the logic for the seamless service while
230 * the main VBoxClient code provides the daemon logic needed by all services.
231 */
232class SeamlessService : public VBoxClient::Service
233{
234private:
235 SeamlessMain mSeamless;
236 bool mIsInitialised;
237public:
238 virtual const char *getPidFilePath()
239 {
240 return ".vboxclient-seamless.pid";
241 }
242 virtual int run(bool fDaemonised /* = false */)
243 {
244 int rc;
245 if (mIsInitialised)
246 return VERR_INTERNAL_ERROR;
247 mIsInitialised = true;
248 rc = mSeamless.start();
249 LogRelFunc(("VBoxClient: seamless service failed to start. Error: %Rrc\n",
250 rc));
251 return rc;
252 }
253 virtual void cleanup()
254 {
255 VbglR3SeamlessSetCap(false);
256 }
257};
258
259VBoxClient::Service *VBoxClient::GetSeamlessService()
260{
261 return new SeamlessService;
262}
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