VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/display.cpp@ 51243

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

Additions/x11/VBoxClient: make VBoxClient --display use the new interface to the X.Org video driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Id: display.cpp 51243 2014-05-13 14:16:56Z vboxsync $ */
2/** @file
3 * X11 guest client - display management.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @todo this should probably be replaced by something IPRT */
19/* For system() and WEXITSTATUS() */
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23#include <errno.h>
24
25#include <X11/Xlib.h>
26#include <X11/Xatom.h>
27#include <X11/cursorfont.h>
28
29#include <iprt/assert.h>
30#include <iprt/err.h>
31#include <iprt/file.h>
32#include <iprt/mem.h>
33#include <iprt/string.h>
34#include <iprt/thread.h>
35#include <VBox/log.h>
36#include <VBox/VMMDev.h>
37#include <VBox/VBoxGuestLib.h>
38
39#include "VBoxClient.h"
40
41/** Exit with a fatal error.
42 * @todo Make this application global. */
43#define FatalError(format) \
44do { \
45 char *pszMessage = RTStrAPrintf2 format; \
46 LogRel(format); \
47 doFatalError(pszMessage); \
48} while(0)
49
50static void doFatalError(char *pszMessage)
51{
52 char *pszCommand;
53 if (pszMessage)
54 {
55 pszCommand = RTStrAPrintf2("notify-send \"VBoxClient: %s\"",
56 pszMessage);
57 if (pszCommand)
58 system(pszCommand);
59 }
60 exit(1);
61}
62
63/** Tell the VBoxGuest driver we no longer want any events and tell the host
64 * we no longer support any capabilities. */
65static int disableEventsAndCaps()
66{
67 int rc = VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS);
68 if (RT_FAILURE(rc))
69 FatalError(("Failed to unset graphics capability, rc=%Rrc.\n", rc));
70 rc = VbglR3SetMouseStatus(VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
71 if (RT_FAILURE(rc))
72 FatalError(("Failed to unset mouse status, rc=%Rrc.\n", rc));
73 rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED
74 | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
75 if (RT_FAILURE(rc))
76 FatalError(("Failed to unset filter mask, rc=%Rrc.\n", rc));
77 return VINF_SUCCESS;
78}
79
80/** Tell the VBoxGuest driver which events we want and tell the host which
81 * capabilities we support. */
82static int enableEventsAndCaps(Display *pDisplay)
83{
84 int rc = VbglR3CtlFilterMask( VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED
85 | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
86 if (RT_FAILURE(rc))
87 FatalError(("Failed to set filter mask, rc=%Rrc.\n", rc));
88 rc = VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0);
89 if (RT_FAILURE(rc))
90 FatalError(("Failed to set graphics capability, rc=%Rrc.\n", rc));
91 rc = VbglR3SetMouseStatus(0);
92 if (RT_FAILURE(rc))
93 FatalError(("Failed to set mouse status, rc=%Rrc.\n", rc));
94 return VINF_SUCCESS;
95}
96
97/**
98 * Display change request monitor thread function.
99 * Before entering the loop, we re-read the last request
100 * received, and if the first one received inside the
101 * loop is identical we ignore it, because it is probably
102 * stale.
103 */
104static void runDisplay(Display *pDisplay)
105{
106 int status, rc;
107 char szCommand[256];
108 Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch);
109 Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr);
110 LogRelFlowFunc(("\n"));
111 bool fExtDispReqSupport = true, fHaveRandR12 = false;
112 const char *pcszXrandr = "xrandr";
113 if (RTFileExists("/usr/X11/bin/xrandr"))
114 pcszXrandr = "/usr/X11/bin/xrandr";
115 status = system(pcszXrandr);
116 if (WEXITSTATUS(status) != 0) /* Utility or extension not available. */
117 FatalError(("Failed to execute the xrandr utility.\n"));
118 RTStrPrintf(szCommand, sizeof(szCommand), "%s --q12", pcszXrandr);
119 status = system(szCommand);
120 if (WEXITSTATUS(status) == 0)
121 fHaveRandR12 = true;
122 while (true)
123 {
124 uint32_t fEvents;
125 /** The size of our array of size hints. */
126 unsigned cSizeHints = 0;
127 /** Array of size hints. Large enough to hold the highest display
128 * number we have had a hint for so far, reallocated when a higher one
129 * comes. Zero means no hint for that display. */
130 long *paSizeHints = NULL;
131 do
132 rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
133 | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED,
134 RT_INDEFINITE_WAIT, &fEvents);
135 while(rc == VERR_INTERRUPTED);
136 if (RT_FAILURE(rc)) /* VERR_NO_MEMORY? */
137 FatalError(("event wait failed, rc=%Rrc\n", rc));
138 if (fEvents & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED)
139 {
140 /* Jiggle the mouse pointer to trigger a switch to a software
141 * cursor if necessary. */
142 XGrabPointer(pDisplay,
143 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
144 GrabModeAsync, None, hClockCursor, CurrentTime);
145 XFlush(pDisplay);
146 XGrabPointer(pDisplay,
147 DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
148 GrabModeAsync, None, hArrowCursor, CurrentTime);
149 XFlush(pDisplay);
150 XUngrabPointer(pDisplay, CurrentTime);
151 XFlush(pDisplay);
152 }
153 /* And if it is a size hint, set the new size. */
154 if (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
155 {
156 uint32_t cx = 0, cy = 0, cBits = 0, iDisplay = 0, cxOrg = 0,
157 cyOrg = 0;
158 bool fEnabled = false;
159 if (fExtDispReqSupport)
160 {
161 int rc2 = VbglR3GetDisplayChangeRequestEx(&cx, &cy, &cBits,
162 &iDisplay, &cxOrg,
163 &cyOrg, &fEnabled,
164 true);
165 /* Extended display version not supported on host */
166 if (RT_FAILURE(rc2))
167 {
168 if (rc2 != VERR_NOT_IMPLEMENTED)
169 FatalError(("Failed to get display change request, rc=%Rrc\n",
170 rc));
171 LogRel(("Extended display change request not supported.\n"));
172 fExtDispReqSupport = false;
173 }
174 else
175 LogRelFlowFunc(("Got Extended Param from Host cx=%d, cy=%d, bpp=%d, iDisp=%d, OrgX=%d, OrgY=%d Enb=%d\n",
176 cx, cy, cBits, iDisplay, cxOrg, cyOrg,
177 fEnabled));
178 }
179 if (!fExtDispReqSupport)
180 rc = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits, &iDisplay,
181 true);
182 if (RT_FAILURE(rc))
183 FatalError(("Failed to retrieve size hint, rc=%Rrc\n", rc));
184 if (iDisplay > INT32_MAX)
185 FatalError(("Received a hint for too high display number %u\n",
186 (unsigned) iDisplay));
187 if (iDisplay >= cSizeHints)
188 {
189 uint32_t i;
190
191 paSizeHints = (long *)RTMemRealloc(paSizeHints,
192 (iDisplay + 1)
193 * sizeof(*paSizeHints));
194 if (!paSizeHints)
195 FatalError(("Failed to re-allocate size hint memory.\n"));
196 for (i = cSizeHints; i < iDisplay + 1; ++i)
197 paSizeHints[i] = 0;
198 cSizeHints = iDisplay + 1;
199 }
200 if ((!fExtDispReqSupport || fEnabled) && cx != 0 && cy != 0)
201 {
202 paSizeHints[iDisplay] = (cx & 0xffff) << 16 | (cy & 0xffff);
203 XChangeProperty(pDisplay, DefaultRootWindow(pDisplay),
204 XInternAtom(pDisplay, "VBOX_SIZE_HINTS", 0),
205 XA_INTEGER, 32, PropModeReplace,
206 (unsigned char *)paSizeHints, cSizeHints);
207 XFlush(pDisplay);
208 }
209 if (!fHaveRandR12)
210 {
211 RTStrPrintf(szCommand, sizeof(szCommand),
212 "%s -s %ux%u", pcszXrandr, cx, cy);
213 status = system(szCommand);
214 if (WEXITSTATUS(status) != 0)
215 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand));
216 }
217 else
218 {
219 if (fExtDispReqSupport && fEnabled)
220 {
221 /* Extended Display support possible . Secondary monitor
222 * position supported */
223 RTStrPrintf(szCommand, sizeof(szCommand),
224 "%s --output VGA-%u --auto --pos %dx%d",
225 pcszXrandr, iDisplay, cxOrg, cyOrg);
226 status = system(szCommand);
227 if (WEXITSTATUS(status) != 0)
228 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand));
229 }
230 if ((!fExtDispReqSupport || fEnabled) && cx != 0 && cy != 0)
231 {
232 RTStrPrintf(szCommand, sizeof(szCommand),
233 "%s --output VGA-%u --preferred",
234 pcszXrandr, iDisplay);
235 status = system(szCommand);
236 if (WEXITSTATUS(status) != 0)
237 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand));
238 }
239 if (fExtDispReqSupport && !fEnabled)
240 {
241 /* disable the virtual monitor */
242 RTStrPrintf(szCommand, sizeof(szCommand),
243 "%s --output VGA-%u --off",
244 pcszXrandr, iDisplay);
245 status = system(szCommand);
246 if (WEXITSTATUS(status) != 0)
247 FatalError(("Failed to execute \\\"%s\\\".\n", szCommand));
248 }
249 }
250 }
251 }
252}
253
254class DisplayService : public VBoxClient::Service
255{
256 Display *mDisplay;
257 bool mfInit;
258public:
259 virtual const char *getPidFilePath()
260 {
261 return ".vboxclient-display.pid";
262 }
263 virtual int init()
264 {
265 int rc;
266
267 if (mfInit)
268 return VERR_WRONG_ORDER;
269 mDisplay = XOpenDisplay(NULL);
270 if (!mDisplay)
271 return VERR_NOT_FOUND;
272 rc = enableEventsAndCaps(mDisplay);
273 if (RT_SUCCESS(rc))
274 mfInit = true;
275 return rc;
276 }
277 virtual int run(bool fDaemonised /* = false */)
278 {
279 if (!mfInit)
280 return VERR_WRONG_ORDER;
281 runDisplay(mDisplay);
282 return VERR_INTERNAL_ERROR; /* "Should never reach here." */
283 }
284 virtual int pause()
285 {
286 if (!mfInit)
287 return VERR_WRONG_ORDER;
288 return disableEventsAndCaps();
289 }
290 virtual int resume()
291 {
292 if (!mfInit)
293 return VERR_WRONG_ORDER;
294 return enableEventsAndCaps(mDisplay);
295 }
296 virtual void cleanup()
297 {
298 disableEventsAndCaps();
299 }
300 DisplayService() { mfInit = false; }
301};
302
303VBoxClient::Service *VBoxClient::GetDisplayService()
304{
305 return new DisplayService;
306}
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