VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/getmode.c@ 55262

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

Additions/x11/vboxvideo: reverted temporary commit r99563.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.4 KB
Line 
1/* $Id: getmode.c 55262 2015-04-15 05:34:05Z vboxsync $ */
2/** @file
3 * VirtualBox X11 Additions graphics driver dynamic video mode functions.
4 */
5
6/*
7 * Copyright (C) 2006-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#include "vboxvideo.h"
19#include <VBox/VMMDev.h>
20
21#define NEED_XF86_TYPES
22#include <iprt/string.h>
23
24#include "xf86.h"
25#include "dixstruct.h"
26#ifdef VBOX_GUESTR3XF86MOD
27# define EXTENSION_PROC_ARGS char *name, GCPtr pGC
28#endif
29#include "extnsionst.h"
30#include "windowstr.h"
31#include <X11/extensions/randrproto.h>
32
33#ifdef XORG_7X
34# include <stdio.h>
35# include <stdlib.h>
36#endif
37
38#ifdef VBOXVIDEO_13
39# ifdef RT_OS_LINUX
40# include "randrstr.h"
41# include "xf86_OSproc.h"
42# include <linux/input.h>
43# ifndef EVIOCGRAB
44# define EVIOCGRAB _IOW('E', 0x90, int)
45# endif
46# ifndef KEY_SWITCHVIDEOMODE
47# define KEY_SWITCHVIDEOMODE 227
48# endif
49# include <dirent.h>
50# include <errno.h>
51# include <fcntl.h>
52# include <unistd.h>
53# endif /* RT_OS_LINUX */
54#endif /* VBOXVIDEO_13 */
55/**************************************************************************
56* Main functions *
57**************************************************************************/
58
59/**
60 * Fills a display mode M with a built-in mode of name pszName and dimensions
61 * cx and cy.
62 */
63static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
64 const char *pszName, unsigned cx, unsigned cy)
65{
66 VBOXPtr pVBox = pScrn->driverPrivate;
67 char szName[256];
68 DisplayModePtr pPrev = m->prev;
69 DisplayModePtr pNext = m->next;
70
71 if (!pszName)
72 {
73 sprintf(szName, "%ux%u", cx, cy);
74 pszName = szName;
75 }
76 TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
77 if (m->name)
78 free((void*)m->name);
79 memset(m, '\0', sizeof(*m));
80 m->prev = pPrev;
81 m->next = pNext;
82 m->status = MODE_OK;
83 m->type = M_T_BUILTIN;
84 /* Older versions of VBox only support screen widths which are a multiple
85 * of 8 */
86 if (pVBox->fAnyX)
87 m->HDisplay = cx;
88 else
89 m->HDisplay = cx & ~7;
90 m->HSyncStart = m->HDisplay + 2;
91 m->HSyncEnd = m->HDisplay + 4;
92 m->HTotal = m->HDisplay + 6;
93 m->VDisplay = cy;
94 m->VSyncStart = m->VDisplay + 2;
95 m->VSyncEnd = m->VDisplay + 4;
96 m->VTotal = m->VDisplay + 6;
97 m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
98 m->name = xnfstrdup(pszName);
99}
100
101/**
102 * Allocates an empty display mode and links it into the doubly linked list of
103 * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
104 * memory.
105 */
106static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
107{
108 DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
109
110 TRACE_ENTRY();
111 if (!pScrn->modes)
112 {
113 pScrn->modes = pMode;
114 pMode->next = pMode;
115 pMode->prev = pMode;
116 }
117 else
118 {
119 pMode->next = pScrn->modes;
120 pMode->prev = pScrn->modes->prev;
121 pMode->next->prev = pMode;
122 pMode->prev->next = pMode;
123 }
124 return pMode;
125}
126
127/**
128 * Create display mode entries in the screen information structure for each
129 * of the graphics modes that we wish to support, that is:
130 * - A dynamic mode in first place which will be updated by the RandR code.
131 * - Any modes that the user requested in xorg.conf/XFree86Config.
132 */
133void vboxAddModes(ScrnInfoPtr pScrn)
134{
135 unsigned cx = 0, cy = 0, cIndex = 0;
136 unsigned i;
137 DisplayModePtr pMode;
138
139 /* Add two dynamic mode entries. When we receive a new size hint we will
140 * update whichever of these is not current. */
141 pMode = vboxAddEmptyScreenMode(pScrn);
142 vboxFillDisplayMode(pScrn, pMode, NULL, 1024, 768);
143 pMode = vboxAddEmptyScreenMode(pScrn);
144 vboxFillDisplayMode(pScrn, pMode, NULL, 1024, 768);
145 /* Add any modes specified by the user. We assume here that the mode names
146 * reflect the mode sizes. */
147 for (i = 0; pScrn->display->modes && pScrn->display->modes[i]; i++)
148 {
149 if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
150 {
151 pMode = vboxAddEmptyScreenMode(pScrn);
152 vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
153 }
154 }
155}
156
157/** Set the initial values for the guest screen size hints by reading saved
158 * values from files. */
159/** @todo Actually read the files instead of setting dummies. */
160void VBoxInitialiseSizeHints(ScrnInfoPtr pScrn)
161{
162 VBOXPtr pVBox = VBOXGetRec(pScrn);
163 DisplayModePtr pMode;
164 unsigned i;
165
166 for (i = 0; i < pVBox->cScreens; ++i)
167 {
168 pVBox->pScreens[i].aPreferredSize.cx = 1024;
169 pVBox->pScreens[i].aPreferredSize.cy = 768;
170 pVBox->pScreens[i].afConnected = true;
171 }
172 /* Set up the first mode correctly to match the requested initial mode. */
173 pScrn->modes->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
174 pScrn->modes->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
175 /* RandR 1.1 quirk: make sure that the initial resolution is always present
176 * in the mode list as RandR will always advertise a mode of the initial
177 * virtual resolution via GetScreenInfo. */
178 pMode = vboxAddEmptyScreenMode(pScrn);
179 vboxFillDisplayMode(pScrn, pMode, NULL, pVBox->pScreens[0].aPreferredSize.cx,
180 pVBox->pScreens[0].aPreferredSize.cy);
181}
182
183static void updateUseHardwareCursor(VBOXPtr pVBox, uint32_t fCursorCapabilities)
184{
185 if ( !(fCursorCapabilities & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
186 && (fCursorCapabilities & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE))
187 pVBox->fUseHardwareCursor = true;
188 else
189 pVBox->fUseHardwareCursor = false;
190}
191
192# define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
193# define MOUSE_CAPABILITIES_PROPERTY "VBOX_MOUSE_CAPABILITIES"
194
195/** Read in information about the most recent size hints requested for the
196 * guest screens. A client application sets the hint information as a root
197 * window property. */
198/* TESTING: dynamic resizing and absolute pointer toggling work on old guest X servers and recent ones on Linux at the log-in screen. */
199/** @note we try to maximise code coverage by typically using all code paths (HGSMI and properties) in a single X session. */
200void VBoxUpdateSizeHints(ScrnInfoPtr pScrn)
201{
202 VBOXPtr pVBox = VBOXGetRec(pScrn);
203 size_t cModesFromProperty, cDummy;
204 int32_t *paModeHints, *pfCursorCapabilities;
205 unsigned i;
206 uint32_t fCursorCapabilities;
207 bool fOldUseHardwareCursor = pVBox->fUseHardwareCursor;
208
209 if (vbvxGetIntegerPropery(pScrn, SIZE_HINTS_PROPERTY, &cModesFromProperty, &paModeHints) != VINF_SUCCESS)
210 paModeHints = NULL;
211 if ( vbvxGetIntegerPropery(pScrn, MOUSE_CAPABILITIES_PROPERTY, &cDummy, &pfCursorCapabilities) != VINF_SUCCESS
212 || cDummy != 1)
213 pfCursorCapabilities = NULL;
214#ifdef VBOXVIDEO_13
215 if (!pVBox->fHaveReadHGSMIModeHintData && RT_SUCCESS(VBoxHGSMIGetModeHints(&pVBox->guestCtx, pVBox->cScreens,
216 pVBox->paVBVAModeHints)))
217 {
218 for (i = 0; i < pVBox->cScreens; ++i)
219 {
220 if (pVBox->paVBVAModeHints[i].magic == VBVAMODEHINT_MAGIC)
221 {
222 pVBox->pScreens[i].aPreferredSize.cx = pVBox->paVBVAModeHints[i].cx;
223 pVBox->pScreens[i].aPreferredSize.cy = pVBox->paVBVAModeHints[i].cy;
224 pVBox->pScreens[i].afConnected = pVBox->paVBVAModeHints[i].fEnabled;
225 /* Do not re-read this if we have data from HGSMI. */
226 if (paModeHints != NULL && i < cModesFromProperty)
227 pVBox->pScreens[i].lastModeHintFromProperty = paModeHints[i];
228 }
229 }
230 }
231 if (!pVBox->fHaveReadHGSMIModeHintData)
232 {
233 if (RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &fCursorCapabilities)))
234 updateUseHardwareCursor(pVBox, fCursorCapabilities);
235 else
236 pVBox->fUseHardwareCursor = false;
237 /* Do not re-read this if we have data from HGSMI. */
238 if (pfCursorCapabilities != NULL)
239 pVBox->fLastCursorCapabilitiesFromProperty = *pfCursorCapabilities;
240 }
241 pVBox->fHaveReadHGSMIModeHintData = true;
242#endif
243 if (paModeHints != NULL)
244 for (i = 0; i < cModesFromProperty && i < pVBox->cScreens; ++i)
245 {
246 if (paModeHints[i] != 0 && paModeHints[i] != pVBox->pScreens[i].lastModeHintFromProperty)
247 {
248 if (paModeHints[i] == -1)
249 pVBox->pScreens[i].afConnected = false;
250 else
251 {
252 pVBox->pScreens[i].aPreferredSize.cx = paModeHints[i] >> 16;
253 pVBox->pScreens[i].aPreferredSize.cy = paModeHints[i] & 0x8fff;
254 pVBox->pScreens[i].afConnected = true;
255 }
256 pVBox->pScreens[i].lastModeHintFromProperty = paModeHints[i];
257 }
258 }
259 if (pfCursorCapabilities != NULL && *pfCursorCapabilities != pVBox->fLastCursorCapabilitiesFromProperty)
260 {
261 updateUseHardwareCursor(pVBox, (uint32_t)*pfCursorCapabilities);
262 pVBox->fLastCursorCapabilitiesFromProperty = *pfCursorCapabilities;
263 }
264 if (pVBox->fUseHardwareCursor != fOldUseHardwareCursor)
265 vbvxReprobeCursor(pScrn);
266}
267
268static bool useHardwareCursor(uint32_t fCursorCapabilities)
269{
270 if ( !(fCursorCapabilities & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
271 && (fCursorCapabilities & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE))
272 return true;
273 return false;
274}
275
276static void compareAndMaybeSetUseHardwareCursor(VBOXPtr pVBox, uint32_t fCursorCapabilities, bool *pfChanged, bool fSet)
277{
278 if (pVBox->fUseHardwareCursor != useHardwareCursor(fCursorCapabilities))
279 *pfChanged = true;
280 if (fSet)
281 pVBox->fUseHardwareCursor = useHardwareCursor(fCursorCapabilities);
282}
283
284#define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
285#define SIZE_HINTS_MISMATCH_PROPERTY "VBOX_SIZE_HINTS_MISMATCH"
286#define MOUSE_CAPABILITIES_PROPERTY "VBOX_MOUSE_CAPABILITIES"
287
288#define COMPARE_AND_MAYBE_SET(pDest, src, pfChanged, fSet) \
289do { \
290 if (*(pDest) != (src)) \
291 { \
292 if (fSet) \
293 *(pDest) = (src); \
294 *(pfChanged) = true; \
295 } \
296} while(0)
297
298/** Read in information about the most recent size hints and cursor
299 * capabilities requested for the guest screens from a root window property set
300 * by an X11 client. Information obtained via HGSMI takes priority. */
301void vbvxReadSizesAndCursorIntegrationFromProperties(ScrnInfoPtr pScrn, bool *pfNeedUpdate)
302{
303 VBOXPtr pVBox = VBOXGetRec(pScrn);
304 size_t cPropertyElements, cDummy;
305 int32_t *paModeHints, *pfCursorCapabilities;
306 int rc;
307 unsigned i;
308 bool fChanged;
309 bool fNeedUpdate = false;
310 int32_t fSizeMismatch = false;
311
312 if (vbvxGetIntegerPropery(pScrn, SIZE_HINTS_PROPERTY, &cPropertyElements, &paModeHints) != VINF_SUCCESS)
313 paModeHints = NULL;
314 if (paModeHints != NULL)
315 for (i = 0; i < cPropertyElements / 2 && i < pVBox->cScreens; ++i)
316 {
317 VBVAMODEHINT *pVBVAModeHint = &pVBox->paVBVAModeHints[i];
318 int32_t iSizeHint = paModeHints[i * 2];
319 int32_t iLocation = paModeHints[i * 2 + 1];
320 bool fNoHGSMI = !pVBox->fHaveHGSMIModeHints || pVBVAModeHint->magic != VBVAMODEHINT_MAGIC;
321
322 fChanged = false;
323 if (iSizeHint != 0)
324 {
325 if (iSizeHint == -1)
326 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afConnected, false, &fChanged, fNoHGSMI);
327 else
328 {
329 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cx, (iSizeHint >> 16) & 0x8fff, &fChanged, fNoHGSMI);
330 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cy, iSizeHint & 0x8fff, &fChanged, fNoHGSMI);
331 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afConnected, true, &fChanged, fNoHGSMI);
332 }
333 if (iLocation == -1)
334 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, false, &fChanged, fNoHGSMI);
335 else
336 {
337 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.x, (iLocation >> 16) & 0x8fff, &fChanged,
338 fNoHGSMI);
339 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.y, iLocation & 0x8fff, &fChanged, fNoHGSMI);
340 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, true, &fChanged, fNoHGSMI);
341 }
342 if (fChanged && fNoHGSMI)
343 fNeedUpdate = true;
344 if (fChanged && !fNoHGSMI)
345 fSizeMismatch = true;
346 }
347 }
348 fChanged = false;
349 if ( vbvxGetIntegerPropery(pScrn, MOUSE_CAPABILITIES_PROPERTY, &cDummy, &pfCursorCapabilities) == VINF_SUCCESS
350 && cDummy == 1)
351 compareAndMaybeSetUseHardwareCursor(pVBox, *pfCursorCapabilities, &fChanged, !pVBox->fHaveHGSMIModeHints);
352 if (fChanged && !pVBox->fHaveHGSMIModeHints)
353 fNeedUpdate = true;
354 if (fChanged && pVBox->fHaveHGSMIModeHints)
355 fSizeMismatch = true;
356 vbvxSetIntegerPropery(pScrn, SIZE_HINTS_MISMATCH_PROPERTY, 1, &fSizeMismatch, false);
357 if (pfNeedUpdate != NULL && fNeedUpdate)
358 *pfNeedUpdate = true;
359}
360
361/** Read in information about the most recent size hints and cursor
362 * capabilities requested for the guest screens from HGSMI. */
363void vbvxReadSizesAndCursorIntegrationFromHGSMI(ScrnInfoPtr pScrn, bool *pfNeedUpdate)
364{
365 VBOXPtr pVBox = VBOXGetRec(pScrn);
366 int rc;
367 unsigned i;
368 bool fChanged = false;
369 uint32_t fCursorCapabilities;
370
371 if (!pVBox->fHaveHGSMIModeHints)
372 return;
373 rc = VBoxHGSMIGetModeHints(&pVBox->guestCtx, pVBox->cScreens, pVBox->paVBVAModeHints);
374 VBVXASSERT(rc == VINF_SUCCESS, ("VBoxHGSMIGetModeHints failed, rc=%d.\n", rc));
375 for (i = 0; i < pVBox->cScreens; ++i)
376 if (pVBox->paVBVAModeHints[i].magic == VBVAMODEHINT_MAGIC)
377 {
378 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cx, pVBox->paVBVAModeHints[i].cx & 0x8fff, &fChanged, true);
379 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredSize.cy, pVBox->paVBVAModeHints[i].cy & 0x8fff, &fChanged, true);
380 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afConnected, RT_BOOL(pVBox->paVBVAModeHints[i].fEnabled), &fChanged, true);
381 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.x, (int32_t)pVBox->paVBVAModeHints[i].dx & 0x8fff, &fChanged,
382 true);
383 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].aPreferredLocation.y, (int32_t)pVBox->paVBVAModeHints[i].dy & 0x8fff, &fChanged,
384 true);
385 if (pVBox->paVBVAModeHints[i].dx != ~(uint32_t)0 && pVBox->paVBVAModeHints[i].dy != ~(uint32_t)0)
386 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, true, &fChanged, true);
387 else
388 COMPARE_AND_MAYBE_SET(&pVBox->pScreens[i].afHaveLocation, false, &fChanged, true);
389 }
390 rc = VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &fCursorCapabilities);
391 VBVXASSERT(rc == VINF_SUCCESS, ("Getting VBOX_VBVA_CONF32_CURSOR_CAPABILITIES failed, rc=%d.\n", rc));
392 compareAndMaybeSetUseHardwareCursor(pVBox, fCursorCapabilities, &fChanged, true);
393 if (pfNeedUpdate != NULL && fChanged)
394 *pfNeedUpdate = true;
395}
396
397#undef COMPARE_AND_MAYBE_SET
398
399#ifndef VBOXVIDEO_13
400
401/** The RandR "proc" vector, which we wrap with our own in order to notice
402 * when a client sends a GetScreenInfo request. */
403static int (*g_pfnVBoxRandRProc)(ClientPtr) = NULL;
404/** The swapped RandR "proc" vector. */
405static int (*g_pfnVBoxRandRSwappedProc)(ClientPtr) = NULL;
406
407/* TESTING: dynamic resizing and toggling cursor integration work with older guest X servers (1.2 and older). */
408static void vboxRandRDispatchCore(ClientPtr pClient)
409{
410 xRRGetScreenInfoReq *pReq = (xRRGetScreenInfoReq *)pClient->requestBuffer;
411 WindowPtr pWin;
412 ScrnInfoPtr pScrn;
413 VBOXPtr pVBox;
414 DisplayModePtr pMode;
415
416 if (pClient->req_len != sizeof(xRRGetScreenInfoReq) >> 2)
417 return;
418 pWin = (WindowPtr)SecurityLookupWindow(pReq->window, pClient,
419 SecurityReadAccess);
420 if (!pWin)
421 return;
422 pScrn = xf86Screens[pWin->drawable.pScreen->myNum];
423 pVBox = VBOXGetRec(pScrn);
424 TRACE_LOG("pVBox->fUseHardwareCursor=%u\n", pVBox->fUseHardwareCursor);
425 VBoxUpdateSizeHints(pScrn);
426 pMode = pScrn->modes;
427 if (pScrn->currentMode == pMode)
428 pMode = pMode->next;
429 pMode->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
430 pMode->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
431}
432
433static int vboxRandRDispatch(ClientPtr pClient)
434{
435 xReq *pReq = (xReq *)pClient->requestBuffer;
436
437 if (pReq->data == X_RRGetScreenInfo)
438 vboxRandRDispatchCore(pClient);
439 return g_pfnVBoxRandRProc(pClient);
440}
441
442static int vboxRandRSwappedDispatch(ClientPtr pClient)
443{
444 xReq *pReq = (xReq *)pClient->requestBuffer;
445
446 if (pReq->data == X_RRGetScreenInfo)
447 vboxRandRDispatchCore(pClient);
448 return g_pfnVBoxRandRSwappedProc(pClient);
449}
450
451static Bool vboxRandRCreateScreenResources(ScreenPtr pScreen)
452{
453 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
454 VBOXPtr pVBox = VBOXGetRec(pScrn);
455 ExtensionEntry *pExt;
456
457 pScreen->CreateScreenResources = pVBox->pfnCreateScreenResources;
458 if (!pScreen->CreateScreenResources(pScreen))
459 return FALSE;
460 /* I doubt we can be loaded twice - should I fail here? */
461 if (g_pfnVBoxRandRProc)
462 return TRUE;
463 pExt = CheckExtension(RANDR_NAME);
464 if (!pExt)
465 {
466 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
467 "RandR extension not found, disabling dynamic resizing.\n");
468 return TRUE;
469 }
470 if ( !ProcVector[pExt->base]
471#if !defined(XF86_VERSION_CURRENT) \
472 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
473 /* SwappedProcVector is not exported in XFree86, so we will not support
474 * swapped byte order clients. I doubt this is a big issue. */
475 || !SwappedProcVector[pExt->base]
476#endif
477 )
478 FatalError("RandR \"proc\" vector not initialised\n");
479 g_pfnVBoxRandRProc = ProcVector[pExt->base];
480 ProcVector[pExt->base] = vboxRandRDispatch;
481#if !defined(XF86_VERSION_CURRENT) \
482 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
483 g_pfnVBoxRandRSwappedProc = SwappedProcVector[pExt->base];
484 SwappedProcVector[pExt->base] = vboxRandRSwappedDispatch;
485#endif
486 return TRUE;
487}
488
489/** Install our private RandR hook procedure, so that we can detect
490 * GetScreenInfo requests from clients to update our dynamic mode. This works
491 * by installing a wrapper around CreateScreenResources(), which will be called
492 * after RandR is initialised. The wrapper then in turn wraps the RandR "proc"
493 * vectors with its own handlers which will get called on any client RandR
494 * request. This should not be used in conjunction with RandR 1.2 or later.
495 * A couple of points of interest in our RandR 1.1 support:
496 * * We use the first two screen modes as dynamic modes. When a new mode hint
497 * arrives we update the first of the two which is not the current mode with
498 * the new size.
499 * * RandR 1.1 always advertises a mode of the size of the initial virtual
500 * resolution via GetScreenInfo(), so we make sure that a mode of that size
501 * is always present in the list.
502 * * RandR adds each new mode it sees to an internal array, but never removes
503 * entries. This array might end up getting rather long given that we can
504 * report a lot more modes than physical hardware.
505 */
506void VBoxSetUpRandR11(ScreenPtr pScreen)
507{
508 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
509
510 if (!pScreen->CreateScreenResources)
511 FatalError("called to early: CreateScreenResources not yet initialised\n");
512 pVBox->pfnCreateScreenResources = pScreen->CreateScreenResources;
513 pScreen->CreateScreenResources = vboxRandRCreateScreenResources;
514}
515
516#endif /* !VBOXVIDEO_13 */
517
518#ifdef VBOXVIDEO_13
519# ifdef RT_OS_LINUX
520/* TESTING: dynamic resizing works on recent Linux guest X servers at the log-in screen. */
521/** @note to maximise code coverage we only read data from HGSMI once, and only when responding to an ACPI event. */
522static void acpiEventHandler(int fd, void *pvData)
523{
524 ScreenPtr pScreen = (ScreenPtr)pvData;
525 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
526 struct input_event event;
527 ssize_t rc;
528
529 pVBox->fHaveReadHGSMIModeHintData = false;
530 RRGetInfo(pScreen
531# if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
532 , TRUE
533# endif
534 );
535 VBVXASSERT(pVBox->fHaveReadHGSMIModeHintData == true, ("fHaveReadHGSMIModeHintData not set.\n"));
536 do
537 rc = read(fd, &event, sizeof(event));
538 while (rc > 0 || (rc == -1 && errno == EINTR));
539 /* Why do they return EAGAIN instead of zero bytes read like everyone else does? */
540 VBVXASSERT(rc != -1 || errno == EAGAIN, ("Reading ACPI input event failed.\n"));
541}
542
543void VBoxSetUpLinuxACPI(ScreenPtr pScreen)
544{
545 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
546 struct dirent *pDirent;
547 DIR *pDir;
548 int fd = -1;
549
550 if (pVBox->fdACPIDevices != -1 || pVBox->hACPIEventHandler != NULL)
551 FatalError("ACPI input file descriptor not initialised correctly.\n");
552 pDir = opendir("/dev/input");
553 if (pDir == NULL)
554 return;
555 for (pDirent = readdir(pDir); pDirent != NULL; pDirent = readdir(pDir))
556 {
557 if (strncmp(pDirent->d_name, "event", sizeof("event") - 1) == 0)
558 {
559#define BITS_PER_BLOCK (sizeof(unsigned long) * 8)
560 char szFile[64] = "/dev/input/";
561 char szDevice[64] = "";
562 unsigned long afKeys[KEY_MAX / BITS_PER_BLOCK];
563
564 strncat(szFile, pDirent->d_name, sizeof(szFile) - sizeof("/dev/input/"));
565 if (fd != -1)
566 close(fd);
567 fd = open(szFile, O_RDONLY | O_NONBLOCK);
568 if ( fd == -1
569 || ioctl(fd, EVIOCGNAME(sizeof(szDevice)), szDevice) == -1
570 || strcmp(szDevice, "Video Bus") != 0)
571 continue;
572 if ( ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(afKeys)), afKeys) == -1
573 || (( afKeys[KEY_SWITCHVIDEOMODE / BITS_PER_BLOCK]
574 >> KEY_SWITCHVIDEOMODE % BITS_PER_BLOCK) & 1) == 0)
575 break;
576 if (ioctl(fd, EVIOCGRAB, (void *)1) != 0)
577 break;
578 pVBox->hACPIEventHandler
579 = xf86AddGeneralHandler(fd, acpiEventHandler, pScreen);
580 if (pVBox->hACPIEventHandler == NULL)
581 break;
582 pVBox->fdACPIDevices = fd;
583 fd = -1;
584 break;
585#undef BITS_PER_BLOCK
586 }
587 }
588 if (fd != -1)
589 close(fd);
590 closedir(pDir);
591}
592
593void VBoxCleanUpLinuxACPI(ScreenPtr pScreen)
594{
595 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
596 if (pVBox->fdACPIDevices != -1)
597 close(pVBox->fdACPIDevices);
598 pVBox->fdACPIDevices = -1;
599 xf86RemoveGeneralHandler(pVBox->hACPIEventHandler);
600 pVBox->hACPIEventHandler = NULL;
601}
602# endif /* RT_OS_LINUX */
603#endif /* VBOXVIDEO_13 */
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