VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceDisplay.cpp@ 52890

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

Additions/VBoxService: add first skeleton of display service.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.7 KB
Line 
1/* $Id: VBoxServiceDisplay.cpp 52890 2014-09-29 16:00:24Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Video Mode Hint Monitoring Service.
4 */
5
6/*
7 * Copyright (C) 2014 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/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <VBox/VBoxGuestLib.h>
22#include "VBoxServiceInternal.h"
23
24/*******************************************************************************
25* Defined Constants And Macros *
26*******************************************************************************/
27/**
28 * Convenience macro for returning an error.
29 * @todo It would be nice to have something which displayed the error more
30 * visibly to the user, say as a host notification.
31 */
32#define RETURN_ERROR(msg, val) \
33do { \
34 VBoxServiceError msg; \
35 return (val); \
36while(0)
37
38#define ERROR_PREFIX "VBoxService/Display: "
39
40#define MAX_CLIENTS 16
41
42/** Structure for keeping track of previously received mode hints. */
43struct videoMode
44{
45 int cx; /** Width */
46 int cy; /** Height */
47 int x; /** X offset, -1 if none. */
48 int y; /** Y offset, -1 if none. */
49 bool fEnabled; /** Should this virtual screen be enabled? */
50};
51
52struct serviceState
53{
54 /** FDs of currently connected clients, empty slots set to -1. */
55 int fdClients[MAX_CLIENTS]; /* Limit number of connections for now. */
56 /** FD of the socket we listen to for connections */
57 int fdSocket;
58 /** Array of video mode hints received up to now or saved in previous runs.
59 */
60 struct videoMode *paLastModeHintsReceived;
61 /** Size of paLastModeHintsReceived structure. */
62 size_t cModeHints;
63};
64
65void initialiseServiceState(struct serviceState *pState)
66{
67 unsigned i;
68
69 for (i = 0; i < MAX_CLIENTS; ++i)
70 pState->fdClients[i] = -1;
71 pState->fdSocket = -1;
72 pState->paLastModeHintsReceived = NULL;
73 pState->cModeHints = 0;
74}
75
76/** Set up a socket to pass on size hints to interested clients. */
77static int setUpSocket(int *pfdSocket)
78{
79 struct sockaddr_un address;
80 int fdSocket;
81 socklen_t cbAddress;
82b
83 fdSocket = socket(PF_UNIX, SOCK_STREAM, 0);
84 if(fdSocket < 0)
85 RETURN_ERROR((ERROR_PREFIX "failed to create a socket: %s\n",
86 strerror(errno), RTErrConvertFromErrno(errno));
87 unlink(VBGLR3HOSTDISPSOCKET); /* Catch relevant failures later. */
88 RT_ZERO(address);
89 mkdir(VBGLR3HOSTDISPSOCKETPATH, 0755); /* Root-only later? */
90 address.sun_family = AF_UNIX;
91 snprintf(address.sun_path, sizeof(address.sun_path),
92 VBGLR3HOSTDISPSOCKET);
93 if (bind(fdSocket, (struct sockaddr *) &address,
94 sizeof(struct sockaddr_un)) != 0)
95 RETURN_ERROR((ERROR_PREFIX "Failed to bind socket: %s\n",
96 strerror(errno), RTErrConvertFromErrno(errno));
97 if (listen(fdSocket, MAX_CLIENTS) != 0)
98 RETURN_ERROR((ERROR_PREFIX "Failed to start listening to socket: %s\n",
99 strerror(errno), RTErrConvertFromErrno(errno));
100 *pfdSocket = fdSocket;
101 return VINF_SUCCESS;
102}
103
104/** Tell the VBoxGuest driver which events we want to listen out for. */
105static int registerForHostEvents()
106{
107 int rc = VbglR3CtlFilterMask( VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED
108 | VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, 0);
109 if (RT_FAILURE(rc))
110 RETURN_ERROR((ERROR_PREFIX "failed to set filter mask, rc=%Rrc.\n", rc),
111 rc);
112 return VINF_SUCCESS;
113}
114
115int setUpServiceState(struct serviceState *pState)
116{
117 int rc;
118
119 rc = setUpSocket(&pState->fdSocket);
120 if (RT_FAILURE(rc))
121 return rc;
122 rc = registerForHostEvents();
123 if (RT_FAILURE(rc))
124 return rc;
125 rc = readSavedVideoModes(&pState->paLastModeHintsReceived);
126 if (RT_FAILURE(rc))
127 return rc;
128 for (rc = VINF_SUCCESS; rc == VINF_SUCCESS;)
129 rc = getVideoModeHintFromHost(pState, NULL);
130 if (RT_FAILURE(rc))
131 return rc;
132 return VINF_SUCCESS;
133}
134
135int sendInitialSizeHintsToKernelDriver(struct serviceState *pState)
136{
137 unsigned iScreen;
138 int rc;
139
140 for (iScreen = 0; iScreen < pState->cModeHints; ++iScreen)
141 {
142 rc = sendModeHintToKernelDriver(pState, i);
143 if (RT_FAILURE(rc))
144 return rc;
145 }
146 return VINF_SUCCESS;
147}
148
149int runMainServiceLoop(struct serviceState *pState, bool volatile *pfShutdown)
150{
151 int rc;
152
153 for (;;)
154 {
155 uint32_t fEventsFromHost;
156
157 if (RT_FAILURE(rc))
158 return rc;
159 /** @todo We really want to be able to poll for events and new clients
160 * in one system call. */
161 rc = VbglR3WaitEvent( VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
162 | VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED
163 | VMMDEV_EVENT_MOUSE_POSITION_CHANGED,
164 RT_INDEFINITE_WAIT, &fEventsFromHost);
165 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
166 RETURN_ERROR((ERROR_PREFIX "VbglR3WaitEvent returned %Rrc\n",
167 rc), rc);
168 if (pfShutdown)
169 return VINF_SUCCESS;
170 rc = updateClientConnectionsAndSendInitialSizeHints(pState);
171 if (RT_FAILURE(rc))
172 return rc;
173 rc = updateKernelDriverMasterState(pState);
174 if (RT_FAILURE(rc))
175 return rc;
176 rc = updateGraphicsCapabilityAndTellHost(pState);
177 /** @note We only pass on display change information to other user space
178 * processes, as it can't safely be polled by several processes. */
179 if (fEventsFromHost & VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED)
180 {
181 rc = sendMouseCapabilitiesToKernelDriver(pState);
182 if (RT_FAILURE(rc))
183 return rc;
184 }
185 if (fEventsFromHost & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
186 {
187 rc = sendMousePositionToKernelDriver(pState);
188 if (RT_FAILURE(rc))
189 return rc;
190 }
191 if (fEventsFromHost & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
192 {
193 while (rc == VINF_SUCCESS)
194 {
195 unsigned iScreen;
196
197 rc = fetchNewModeHintFromHost(&paLastModeHintsReceived,
198 &iScreen);
199 if (RT_FAILURE(rc))
200 return rc;
201 rc = sendModeHintToKernelDriver(pState, iScreen);
202 if (RT_FAILURE(rc))
203 return rc;
204 rc = sendModeHintToClients(pState, iScreen);
205 if (RT_FAILURE(rc))
206 return rc;
207 }
208 }
209 }
210}
211
212/** @copydoc VBOXSERVICE::pfnWorker */
213static DECLCALLBACK(int) serviceWorker(bool volatile *pfShutdown)
214{
215 struct serviceState State;
216 int rc;
217
218 /*
219 * Tell the control thread that it can continue spawning services.
220 */
221 RTThreadUserSignal(RTThreadSelf());
222
223 initialiseServiceState(&State);
224 /** @todo Set guest capabilities and mouse status (doesn't need host
225 * cursor) when we support this in the kernel driver. We should do
226 * this when any process acquires DRM_MASTER and release them when
227 * it is released. We need a way of detecting this. */
228 /** @note Update: sysfs attributes can be polled, and the kernel API
229 * sysfs_notify() releases the poll.
230 * http://lwn.net/Articles/174660/
231 */
232 rc = setUpServiceState(pState);
233 if (RT_SUCCESS(rc))
234 rc = sendInitialSizeHintsToKernelDriver(pState);
235 if (RT_SUCCESS(rc))
236 rc = runMainServiceLoop(pState);
237
238 cleanUpServiceState(pState);
239 return rc;
240}
241
242
243/** @copydoc VBOXSERVICE::pfnStop */
244static DECLCALLBACK(void) serviceStop(void)
245{
246 VbglR3InterruptEventWaits();
247 return;
248}
249
250
251/**
252 * The 'DisplayService' service description.
253 */
254VBOXSERVICE g_Display =
255{
256 /* pszName. */
257 "display",
258 /* pszDescription. */
259 "Connect display drivers to VMM device",
260 /* pszUsage. */
261 NULL,
262 /* pszOptions. */
263 NULL,
264 /* methods */
265 VBoxServiceDefaultPreInit,
266 VBoxServiceDefaultOption,
267 VBoxServiceDefaultInit,
268 serviceWorker,
269 serviceStop,
270 VBoxServiceDefaultTerm
271};
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