1
/* $Id: display.cpp $ */
3
* X11 guest client - display management.
7
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
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.
17
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18
* Clara, CA 95054 USA or visit http://www.sun.com if you need
19
* additional information or have any questions.
22
/** @todo this should probably be replaced by something IPRT */
23
/* For system() and WEXITSTATUS() */
25
#include <sys/types.h>
30
#include <X11/cursorfont.h>
32
#include <iprt/assert.h>
34
#include <iprt/thread.h>
36
#include <VBox/VMMDev.h>
37
#include <VBox/VBoxGuestLib.h>
39
#include "VBoxClient.h"
41
static int initDisplay()
43
int rc = VINF_SUCCESS;
44
int rcSystem, rcErrno;
45
uint32_t fMouseFeatures = 0;
47
LogFlowFunc(("enabling dynamic resizing\n"));
48
rcSystem = system("VBoxRandR --test");
52
rc = RTErrConvertFromErrno(rcErrno);
56
if (0 != WEXITSTATUS(rcSystem))
57
rc = VERR_NOT_SUPPORTED;
60
rc = VbglR3CtlFilterMask(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
62
VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
63
/* Log and ignore the return value, as there is not much we can do with
65
LogFlowFunc(("dynamic resizing: result %Rrc\n", rc));
66
/* Enable support for switching between hardware and software cursors */
67
LogFlowFunc(("enabling relative mouse re-capturing support\n"));
68
rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
71
if (fMouseFeatures & VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR)
73
rc = VbglR3CtlFilterMask(VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED,
76
rc = VbglR3SetMouseStatus
78
& ~VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
81
rc = VERR_NOT_SUPPORTED;
85
VbglR3CtlFilterMask(0, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
86
VbglR3SetMouseStatus( fMouseFeatures
87
| VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
89
LogFlowFunc(("mouse re-capturing support: result %Rrc\n", rc));
93
void cleanupDisplay(void)
95
uint32_t fMouseFeatures = 0;
97
VbglR3CtlFilterMask(0, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
98
| VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
99
int rc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
101
VbglR3SetMouseStatus( fMouseFeatures
102
| VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
103
LogFlowFunc(("returning\n"));
106
/** This thread just runs a dummy X11 event loop to be sure that we get
107
* terminated should the X server exit. */
108
static int x11ConnectionMonitor(RTTHREAD, void *)
111
Display *pDisplay = XOpenDisplay(NULL);
113
XNextEvent(pDisplay, &ev);
118
* Display change request monitor thread function.
119
* Before entering the loop, we re-read the last request
120
* received, and if the first one received inside the
121
* loop is identical we ignore it, because it is probably
127
uint32_t cx0 = 0, cy0 = 0, cBits0 = 0, iDisplay0 = 0;
128
Display *pDisplay = XOpenDisplay(NULL);
129
if (pDisplay == NULL)
130
return VERR_NOT_FOUND;
131
Cursor hClockCursor = XCreateFontCursor(pDisplay, XC_watch);
132
Cursor hArrowCursor = XCreateFontCursor(pDisplay, XC_left_ptr);
133
int rc = RTThreadCreate(NULL, x11ConnectionMonitor, NULL, 0,
134
RTTHREADTYPE_INFREQUENT_POLLER, 0, "X11 monitor");
137
VbglR3GetDisplayChangeRequest(&cx0, &cy0, &cBits0, &iDisplay0, false);
140
uint32_t fEvents = 0, cx = 0, cy = 0, cBits = 0, iDisplay = 0;
141
rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
142
| VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED,
143
RT_INDEFINITE_WAIT, &fEvents);
144
if (RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST))
146
int rc2 = VbglR3GetDisplayChangeRequest(&cx, &cy, &cBits,
148
/* Ignore the request if it is stale */
149
if ((cx != cx0) || (cy != cy0) || RT_FAILURE(rc2))
151
/* If we are not stopping, sleep for a bit to avoid using up
152
too much CPU while retrying. */
164
&& (fEvents & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED))
166
XGrabPointer(pDisplay,
167
DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
168
GrabModeAsync, None, hClockCursor, CurrentTime);
170
XGrabPointer(pDisplay,
171
DefaultRootWindow(pDisplay), true, 0, GrabModeAsync,
172
GrabModeAsync, None, hArrowCursor, CurrentTime);
174
XUngrabPointer(pDisplay, CurrentTime);
178
LogFlowFunc(("returning VINF_SUCCESS\n"));
182
class DisplayService : public VBoxClient::Service
185
virtual const char *getPidFilePath()
187
return ".vboxclient-display.pid";
189
virtual int run(bool fDaemonised /* = false */)
191
int rc = initDisplay();
196
virtual void cleanup()
202
VBoxClient::Service *VBoxClient::GetDisplayService()
204
return new DisplayService;