VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/vboxutils.c@ 51374

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

Additions/x11/vboxvideo: change size hint logic to take hints from a root window property and to notice RandR GetScreenInfo requests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.6 KB
Line 
1/* $Id: vboxutils.c 51242 2014-05-13 14:07:00Z 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(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->aPreferredSize[i].cx = 1024;
218 pVBox->aPreferredSize[i].cy = 768;
219 }
220 /* Set up the first mode correctly to match the requested initial mode. */
221 pScrn->modes->HDisplay = pVBox->aPreferredSize[0].cx;
222 pScrn->modes->VDisplay = pVBox->aPreferredSize[0].cy;
223 /* RandR 1.1 quirk: make sure that the initial resolution is always present
224 * in the mode list as RandR will always advertise a mode of the initial
225 * virtual resolution via GetScreenInfo. */
226 pMode = vboxAddEmptyScreenMode(pScrn);
227 vboxFillDisplayMode(pScrn, pMode, NULL, pVBox->aPreferredSize[0].cx,
228 pVBox->aPreferredSize[0].cy);
229}
230
231# define SIZE_HINTS_PROPERTY "VBOX_SIZE_HINTS"
232
233/** Read in information about the most recent size hints requested for the
234 * guest screens. A client application sets the hint information as a root
235 * window property. */
236void VBoxUpdateSizeHints(ScrnInfoPtr pScrn)
237{
238 VBOXPtr pVBox = VBOXGetRec(pScrn);
239 Atom atom = MakeAtom(SIZE_HINTS_PROPERTY, sizeof(SIZE_HINTS_PROPERTY) - 1,
240 FALSE);
241 PropertyPtr prop = NULL;
242 unsigned i;
243
244 /* We can get called early, before the root window is created. */
245 if (!ROOT_WINDOW(pScrn))
246 return;
247 if (atom != BAD_RESOURCE)
248 {
249 for (prop = wUserProps(ROOT_WINDOW(pScrn));
250 prop != NULL && prop->propertyName != atom; prop = prop->next);
251 }
252 if (prop && prop->type == XA_INTEGER && prop->format == 32)
253 for (i = 0; i < prop->size && i < pVBox->cScreens; ++i)
254 {
255 if (!((int32_t *)prop->data)[i])
256 continue;
257 pVBox->aPreferredSize[i].cx = ((int32_t *)prop->data)[i] >> 16;
258 pVBox->aPreferredSize[i].cy = ((int32_t *)prop->data)[i] & 0xffff;
259 }
260}
261
262#ifndef VBOXVIDEO_13
263
264/** The RandR "proc" vector, which we wrap with our own in order to notice
265 * when a client sends a GetScreenInfo request. */
266static int (*g_pfnVBoxRandRProc)(ClientPtr) = NULL;
267/** The swapped RandR "proc" vector. */
268static int (*g_pfnVBoxRandRSwappedProc)(ClientPtr) = NULL;
269
270static void vboxRandRDispatchCore(ClientPtr pClient)
271{
272 xRRGetScreenInfoReq *pReq = (xRRGetScreenInfoReq *)pClient->requestBuffer;
273 WindowPtr pWin;
274 ScrnInfoPtr pScrn;
275 VBOXPtr pVBox;
276 DisplayModePtr pMode;
277
278 if (pClient->req_len != sizeof(xRRGetScreenInfoReq) >> 2)
279 return;
280 pWin = (WindowPtr)SecurityLookupWindow(pReq->window, pClient,
281 SecurityReadAccess);
282 if (!pWin)
283 return;
284 pScrn = xf86Screens[pWin->drawable.pScreen->myNum];
285 pVBox = VBOXGetRec(pScrn);
286 VBoxUpdateSizeHints(pScrn);
287 pMode = pScrn->modes;
288 if (pScrn->currentMode == pMode)
289 pMode = pMode->next;
290 pMode->HDisplay = pVBox->aPreferredSize[0].cx;
291 pMode->VDisplay = pVBox->aPreferredSize[0].cy;
292}
293
294static int vboxRandRDispatch(ClientPtr pClient)
295{
296 xReq *pReq = (xReq *)pClient->requestBuffer;
297
298 if (pReq->data == X_RRGetScreenInfo)
299 vboxRandRDispatchCore(pClient);
300 return g_pfnVBoxRandRProc(pClient);
301}
302
303static int vboxRandRSwappedDispatch(ClientPtr pClient)
304{
305 xReq *pReq = (xReq *)pClient->requestBuffer;
306
307 if (pReq->data == X_RRGetScreenInfo)
308 vboxRandRDispatchCore(pClient);
309 return g_pfnVBoxRandRSwappedProc(pClient);
310}
311
312static Bool vboxRandRCreateScreenResources(ScreenPtr pScreen)
313{
314 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
315 VBOXPtr pVBox = VBOXGetRec(pScrn);
316 ExtensionEntry *pExt;
317
318 pScreen->CreateScreenResources = pVBox->pfnCreateScreenResources;
319 if (!pScreen->CreateScreenResources(pScreen))
320 return FALSE;
321 /* I doubt we can be loaded twice - should I fail here? */
322 if (g_pfnVBoxRandRProc)
323 return TRUE;
324 pExt = CheckExtension(RANDR_NAME);
325 if (!pExt)
326 {
327 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
328 "RandR extension not found, disabling dynamic resizing.\n");
329 return TRUE;
330 }
331 if ( !ProcVector[pExt->base]
332#if !defined(XF86_VERSION_CURRENT) \
333 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
334 /* SwappedProcVector is not exported in XFree86, so we will not support
335 * swapped byte order clients. I doubt this is a big issue. */
336 || !SwappedProcVector[pExt->base]
337#endif
338 )
339 FatalError("RandR \"proc\" vector not initialised\n");
340 g_pfnVBoxRandRProc = ProcVector[pExt->base];
341 ProcVector[pExt->base] = vboxRandRDispatch;
342#if !defined(XF86_VERSION_CURRENT) \
343 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
344 g_pfnVBoxRandRSwappedProc = SwappedProcVector[pExt->base];
345 SwappedProcVector[pExt->base] = vboxRandRSwappedDispatch;
346#endif
347 return TRUE;
348}
349
350/** Install our private RandR hook procedure, so that we can detect
351 * GetScreenInfo requests from clients to update our dynamic mode. This works
352 * by installing a wrapper around CreateScreenResources(), which will be called
353 * after RandR is initialised. The wrapper then in turn wraps the RandR "proc"
354 * vectors with its own handlers which will get called on any client RandR
355 * request. This should not be used in conjunction with RandR 1.2 or later.
356 * A couple of points of interest in our RandR 1.1 support:
357 * * We use the first two screen modes as dynamic modes. When a new mode hint
358 * arrives we update the first of the two which is not the current mode with
359 * the new size.
360 * * RandR 1.1 always advertises a mode of the size of the initial virtual
361 * resolution via GetScreenInfo(), so we make sure that a mode of that size
362 * is always present in the list.
363 * * RandR adds each new mode it sees to an internal array, but never removes
364 * entries. This array might end up getting rather long given that we can
365 * report a lot more modes than physical hardware.
366 */
367void VBoxSetUpRandR11(ScreenPtr pScreen)
368{
369 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
370
371 if (!pScreen->CreateScreenResources)
372 FatalError("called to early: CreateScreenResources not yet initialised\n");
373 pVBox->pfnCreateScreenResources = pScreen->CreateScreenResources;
374 pScreen->CreateScreenResources = vboxRandRCreateScreenResources;
375}
376
377#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