VirtualBox

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

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

Additions/x11/vboxvideo: report monitor connected status to X11, based on the enabled state in the last mode hint.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.8 KB
Line 
1/* $Id: getmode.c 53527 2014-12-12 17:26:17Z vboxsync $ */
2/** @file
3 * VirtualBox X11 Additions graphics driver utility functions
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#include "vboxvideo.h"
19
20#define NEED_XF86_TYPES
21#include <iprt/string.h>
22
23#include "xf86.h"
24#include "dixstruct.h"
25#include "extnsionst.h"
26#include "windowstr.h"
27#include <X11/extensions/randrproto.h>
28#include <X11/Xatom.h>
29
30#ifdef XORG_7X
31# include <stdio.h>
32# include <stdlib.h>
33#endif
34
35/**************************************************************************
36* Main functions *
37**************************************************************************/
38
39/**
40 * Fills a display mode M with a built-in mode of name pszName and dimensions
41 * cx and cy.
42 */
43static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
44 const char *pszName, unsigned cx, unsigned cy)
45{
46 VBOXPtr pVBox = pScrn->driverPrivate;
47 char szName[256];
48 DisplayModePtr pPrev = m->prev;
49 DisplayModePtr pNext = m->next;
50
51 if (!pszName)
52 {
53 sprintf(szName, "%ux%u", cx, cy);
54 pszName = szName;
55 }
56 TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
57 if (m->name)
58 free((void*)m->name);
59 memset(m, '\0', sizeof(*m));
60 m->prev = pPrev;
61 m->next = pNext;
62 m->status = MODE_OK;
63 m->type = M_T_BUILTIN;
64 /* Older versions of VBox only support screen widths which are a multiple
65 * of 8 */
66 if (pVBox->fAnyX)
67 m->HDisplay = cx;
68 else
69 m->HDisplay = cx & ~7;
70 m->HSyncStart = m->HDisplay + 2;
71 m->HSyncEnd = m->HDisplay + 4;
72 m->HTotal = m->HDisplay + 6;
73 m->VDisplay = cy;
74 m->VSyncStart = m->VDisplay + 2;
75 m->VSyncEnd = m->VDisplay + 4;
76 m->VTotal = m->VDisplay + 6;
77 m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
78 m->name = xnfstrdup(pszName);
79}
80
81/** vboxvideo's list of standard video modes */
82struct
83{
84 /** mode width */
85 uint32_t cx;
86 /** mode height */
87 uint32_t cy;
88} vboxStandardModes[] =
89{
90 { 1600, 1200 },
91 { 1440, 1050 },
92 { 1280, 960 },
93 { 1024, 768 },
94 { 800, 600 },
95 { 640, 480 },
96 { 0, 0 }
97};
98enum
99{
100 vboxNumStdModes = sizeof(vboxStandardModes) / sizeof(vboxStandardModes[0])
101};
102
103/**
104 * Returns a standard mode which the host likes. Can be called multiple
105 * times with the index returned by the previous call to get a list of modes.
106 * @returns the index of the mode in the list, or 0 if no more modes are
107 * available
108 * @param pScrn the screen information structure
109 * @param pScrn->bitsPerPixel
110 * if this is non-null, only modes with this BPP will be
111 * returned
112 * @param cIndex the index of the last mode queried, or 0 to query the
113 * first mode available. Note: the first index is 1
114 * @param pcx where to store the mode's width
115 * @param pcy where to store the mode's height
116 * @param pcBits where to store the mode's BPP
117 */
118unsigned vboxNextStandardMode(ScrnInfoPtr pScrn, unsigned cIndex,
119 uint32_t *pcx, uint32_t *pcy)
120{
121 unsigned i;
122
123 XF86ASSERT(cIndex < vboxNumStdModes,
124 ("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
125 vboxNumStdModes));
126 for (i = cIndex; i < vboxNumStdModes - 1; ++i)
127 {
128 uint32_t cx = vboxStandardModes[i].cx;
129 uint32_t cy = vboxStandardModes[i].cy;
130
131 if (pcx)
132 *pcx = cx;
133 if (pcy)
134 *pcy = cy;
135 return i + 1;
136 }
137 return 0;
138}
139
140/**
141 * Allocates an empty display mode and links it into the doubly linked list of
142 * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
143 * memory.
144 */
145static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
146{
147 DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
148
149 TRACE_ENTRY();
150 if (!pScrn->modes)
151 {
152 pScrn->modes = pMode;
153 pMode->next = pMode;
154 pMode->prev = pMode;
155 }
156 else
157 {
158 pMode->next = pScrn->modes;
159 pMode->prev = pScrn->modes->prev;
160 pMode->next->prev = pMode;
161 pMode->prev->next = pMode;
162 }
163 return pMode;
164}
165
166/**
167 * Create display mode entries in the screen information structure for each
168 * of the graphics modes that we wish to support, that is:
169 * - A dynamic mode in first place which will be updated by the RandR code.
170 * - Several standard modes.
171 * - Any modes that the user requested in xorg.conf/XFree86Config.
172 */
173void vboxAddModes(ScrnInfoPtr pScrn)
174{
175 unsigned cx = 0, cy = 0, cIndex = 0;
176 unsigned i;
177 DisplayModePtr pMode;
178
179 /* Add two dynamic mode entries. When we receive a new size hint we will
180 * update whichever of these is not current. */
181 pMode = vboxAddEmptyScreenMode(pScrn);
182 vboxFillDisplayMode(pScrn, pMode, NULL, 1024, 768);
183 pMode = vboxAddEmptyScreenMode(pScrn);
184 vboxFillDisplayMode(pScrn, pMode, NULL, 1024, 768);
185 /* Add standard modes supported by the host */
186 for ( ; ; )
187 {
188 cIndex = vboxNextStandardMode(pScrn, cIndex, &cx, &cy);
189 if (cIndex == 0)
190 break;
191 pMode = vboxAddEmptyScreenMode(pScrn);
192 vboxFillDisplayMode(pScrn, pMode, NULL, cx, cy);
193 }
194 /* And finally any modes specified by the user. We assume here that
195 * the mode names reflect the mode sizes. */
196 for (i = 0; pScrn->display->modes && pScrn->display->modes[i]; i++)
197 {
198 if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
199 {
200 pMode = vboxAddEmptyScreenMode(pScrn);
201 vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
202 }
203 }
204}
205
206/** Set the initial values for the guest screen size hints by reading saved
207 * values from files. */
208/** @todo Actually read the files instead of setting dummies. */
209void VBoxInitialiseSizeHints(ScrnInfoPtr pScrn)
210{
211 VBOXPtr pVBox = VBOXGetRec(pScrn);
212 DisplayModePtr pMode;
213 unsigned i;
214
215 for (i = 0; i < pVBox->cScreens; ++i)
216 {
217 pVBox->pScreens[i].aPreferredSize.cx = 1024;
218 pVBox->pScreens[i].aPreferredSize.cy = 768;
219 pVBox->pScreens[i].afConnected = true;
220 }
221 /* Set up the first mode correctly to match the requested initial mode. */
222 pScrn->modes->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
223 pScrn->modes->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
224 /* RandR 1.1 quirk: make sure that the initial resolution is always present
225 * in the mode list as RandR will always advertise a mode of the initial
226 * virtual resolution via GetScreenInfo. */
227 pMode = vboxAddEmptyScreenMode(pScrn);
228 vboxFillDisplayMode(pScrn, pMode, NULL, pVBox->pScreens[0].aPreferredSize.cx,
229 pVBox->pScreens[0].aPreferredSize.cy);
230}
231
232# define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
233
234/** Read in information about the most recent size hints requested for the
235 * guest screens. A client application sets the hint information as a root
236 * window property. */
237void VBoxUpdateSizeHints(ScrnInfoPtr pScrn)
238{
239 VBOXPtr pVBox = VBOXGetRec(pScrn);
240 Atom atom = MakeAtom(SIZE_HINTS_PROPERTY, sizeof(SIZE_HINTS_PROPERTY) - 1,
241 FALSE);
242 PropertyPtr prop = NULL;
243 unsigned i;
244
245 /* We can get called early, before the root window is created. */
246 if (!ROOT_WINDOW(pScrn))
247 return;
248 if (atom != BAD_RESOURCE)
249 {
250 for (prop = wUserProps(ROOT_WINDOW(pScrn));
251 prop != NULL && prop->propertyName != atom; prop = prop->next);
252 }
253 if (prop && prop->type == XA_INTEGER && prop->format == 32)
254 for (i = 0; i < prop->size && i < pVBox->cScreens; ++i)
255 {
256 if (((int32_t *)prop->data)[i] != 0)
257 {
258 pVBox->pScreens[i].aPreferredSize.cx =
259 ((int32_t *)prop->data)[i] >> 16;
260 pVBox->pScreens[i].aPreferredSize.cy =
261 ((int32_t *)prop->data)[i] & 0x8fff;
262 }
263 }
264}
265
266#ifndef VBOXVIDEO_13
267
268/** The RandR "proc" vector, which we wrap with our own in order to notice
269 * when a client sends a GetScreenInfo request. */
270static int (*g_pfnVBoxRandRProc)(ClientPtr) = NULL;
271/** The swapped RandR "proc" vector. */
272static int (*g_pfnVBoxRandRSwappedProc)(ClientPtr) = NULL;
273
274static void vboxRandRDispatchCore(ClientPtr pClient)
275{
276 xRRGetScreenInfoReq *pReq = (xRRGetScreenInfoReq *)pClient->requestBuffer;
277 WindowPtr pWin;
278 ScrnInfoPtr pScrn;
279 VBOXPtr pVBox;
280 DisplayModePtr pMode;
281
282 if (pClient->req_len != sizeof(xRRGetScreenInfoReq) >> 2)
283 return;
284 pWin = (WindowPtr)SecurityLookupWindow(pReq->window, pClient,
285 SecurityReadAccess);
286 if (!pWin)
287 return;
288 pScrn = xf86Screens[pWin->drawable.pScreen->myNum];
289 pVBox = VBOXGetRec(pScrn);
290 VBoxUpdateSizeHints(pScrn);
291 pMode = pScrn->modes;
292 if (pScrn->currentMode == pMode)
293 pMode = pMode->next;
294 pMode->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
295 pMode->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
296}
297
298static int vboxRandRDispatch(ClientPtr pClient)
299{
300 xReq *pReq = (xReq *)pClient->requestBuffer;
301
302 if (pReq->data == X_RRGetScreenInfo)
303 vboxRandRDispatchCore(pClient);
304 return g_pfnVBoxRandRProc(pClient);
305}
306
307static int vboxRandRSwappedDispatch(ClientPtr pClient)
308{
309 xReq *pReq = (xReq *)pClient->requestBuffer;
310
311 if (pReq->data == X_RRGetScreenInfo)
312 vboxRandRDispatchCore(pClient);
313 return g_pfnVBoxRandRSwappedProc(pClient);
314}
315
316static Bool vboxRandRCreateScreenResources(ScreenPtr pScreen)
317{
318 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
319 VBOXPtr pVBox = VBOXGetRec(pScrn);
320 ExtensionEntry *pExt;
321
322 pScreen->CreateScreenResources = pVBox->pfnCreateScreenResources;
323 if (!pScreen->CreateScreenResources(pScreen))
324 return FALSE;
325 /* I doubt we can be loaded twice - should I fail here? */
326 if (g_pfnVBoxRandRProc)
327 return TRUE;
328 pExt = CheckExtension(RANDR_NAME);
329 if (!pExt)
330 {
331 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
332 "RandR extension not found, disabling dynamic resizing.\n");
333 return TRUE;
334 }
335 if ( !ProcVector[pExt->base]
336#if !defined(XF86_VERSION_CURRENT) \
337 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
338 /* SwappedProcVector is not exported in XFree86, so we will not support
339 * swapped byte order clients. I doubt this is a big issue. */
340 || !SwappedProcVector[pExt->base]
341#endif
342 )
343 FatalError("RandR \"proc\" vector not initialised\n");
344 g_pfnVBoxRandRProc = ProcVector[pExt->base];
345 ProcVector[pExt->base] = vboxRandRDispatch;
346#if !defined(XF86_VERSION_CURRENT) \
347 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
348 g_pfnVBoxRandRSwappedProc = SwappedProcVector[pExt->base];
349 SwappedProcVector[pExt->base] = vboxRandRSwappedDispatch;
350#endif
351 return TRUE;
352}
353
354/** Install our private RandR hook procedure, so that we can detect
355 * GetScreenInfo requests from clients to update our dynamic mode. This works
356 * by installing a wrapper around CreateScreenResources(), which will be called
357 * after RandR is initialised. The wrapper then in turn wraps the RandR "proc"
358 * vectors with its own handlers which will get called on any client RandR
359 * request. This should not be used in conjunction with RandR 1.2 or later.
360 * A couple of points of interest in our RandR 1.1 support:
361 * * We use the first two screen modes as dynamic modes. When a new mode hint
362 * arrives we update the first of the two which is not the current mode with
363 * the new size.
364 * * RandR 1.1 always advertises a mode of the size of the initial virtual
365 * resolution via GetScreenInfo(), so we make sure that a mode of that size
366 * is always present in the list.
367 * * RandR adds each new mode it sees to an internal array, but never removes
368 * entries. This array might end up getting rather long given that we can
369 * report a lot more modes than physical hardware.
370 */
371void VBoxSetUpRandR11(ScreenPtr pScreen)
372{
373 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
374
375 if (!pScreen->CreateScreenResources)
376 FatalError("called to early: CreateScreenResources not yet initialised\n");
377 pVBox->pfnCreateScreenResources = pScreen->CreateScreenResources;
378 pScreen->CreateScreenResources = vboxRandRCreateScreenResources;
379}
380
381#endif /* !VBOXVIDEO_13 */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette