VirtualBox

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

最後變更 在這個檔案從53442是 53440,由 vboxsync 提交於 10 年 前

Additions/x11: fix recently re-introduced mode hint regression which caused guest screens to disappear (again).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 12.8 KB
 
1/* $Id: vboxutils.c 53440 2014-12-03 21:06:24Z 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.alldomusa.eu.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 }
220 /* Set up the first mode correctly to match the requested initial mode. */
221 pScrn->modes->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
222 pScrn->modes->VDisplay = pVBox->pScreens[0].aPreferredSize.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->pScreens[0].aPreferredSize.cx,
228 pVBox->pScreens[0].aPreferredSize.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] == 0)
256 continue;
257 else
258 {
259 pVBox->pScreens[i].aPreferredSize.cx =
260 ((int32_t *)prop->data)[i] >> 16;
261 pVBox->pScreens[i].aPreferredSize.cy =
262 ((int32_t *)prop->data)[i] & 0x8fff;
263 }
264 }
265}
266
267#ifndef VBOXVIDEO_13
268
269/** The RandR "proc" vector, which we wrap with our own in order to notice
270 * when a client sends a GetScreenInfo request. */
271static int (*g_pfnVBoxRandRProc)(ClientPtr) = NULL;
272/** The swapped RandR "proc" vector. */
273static int (*g_pfnVBoxRandRSwappedProc)(ClientPtr) = NULL;
274
275static void vboxRandRDispatchCore(ClientPtr pClient)
276{
277 xRRGetScreenInfoReq *pReq = (xRRGetScreenInfoReq *)pClient->requestBuffer;
278 WindowPtr pWin;
279 ScrnInfoPtr pScrn;
280 VBOXPtr pVBox;
281 DisplayModePtr pMode;
282
283 if (pClient->req_len != sizeof(xRRGetScreenInfoReq) >> 2)
284 return;
285 pWin = (WindowPtr)SecurityLookupWindow(pReq->window, pClient,
286 SecurityReadAccess);
287 if (!pWin)
288 return;
289 pScrn = xf86Screens[pWin->drawable.pScreen->myNum];
290 pVBox = VBOXGetRec(pScrn);
291 VBoxUpdateSizeHints(pScrn);
292 pMode = pScrn->modes;
293 if (pScrn->currentMode == pMode)
294 pMode = pMode->next;
295 pMode->HDisplay = pVBox->pScreens[0].aPreferredSize.cx;
296 pMode->VDisplay = pVBox->pScreens[0].aPreferredSize.cy;
297}
298
299static int vboxRandRDispatch(ClientPtr pClient)
300{
301 xReq *pReq = (xReq *)pClient->requestBuffer;
302
303 if (pReq->data == X_RRGetScreenInfo)
304 vboxRandRDispatchCore(pClient);
305 return g_pfnVBoxRandRProc(pClient);
306}
307
308static int vboxRandRSwappedDispatch(ClientPtr pClient)
309{
310 xReq *pReq = (xReq *)pClient->requestBuffer;
311
312 if (pReq->data == X_RRGetScreenInfo)
313 vboxRandRDispatchCore(pClient);
314 return g_pfnVBoxRandRSwappedProc(pClient);
315}
316
317static Bool vboxRandRCreateScreenResources(ScreenPtr pScreen)
318{
319 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
320 VBOXPtr pVBox = VBOXGetRec(pScrn);
321 ExtensionEntry *pExt;
322
323 pScreen->CreateScreenResources = pVBox->pfnCreateScreenResources;
324 if (!pScreen->CreateScreenResources(pScreen))
325 return FALSE;
326 /* I doubt we can be loaded twice - should I fail here? */
327 if (g_pfnVBoxRandRProc)
328 return TRUE;
329 pExt = CheckExtension(RANDR_NAME);
330 if (!pExt)
331 {
332 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
333 "RandR extension not found, disabling dynamic resizing.\n");
334 return TRUE;
335 }
336 if ( !ProcVector[pExt->base]
337#if !defined(XF86_VERSION_CURRENT) \
338 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
339 /* SwappedProcVector is not exported in XFree86, so we will not support
340 * swapped byte order clients. I doubt this is a big issue. */
341 || !SwappedProcVector[pExt->base]
342#endif
343 )
344 FatalError("RandR \"proc\" vector not initialised\n");
345 g_pfnVBoxRandRProc = ProcVector[pExt->base];
346 ProcVector[pExt->base] = vboxRandRDispatch;
347#if !defined(XF86_VERSION_CURRENT) \
348 || XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4, 3, 99, 0, 0)
349 g_pfnVBoxRandRSwappedProc = SwappedProcVector[pExt->base];
350 SwappedProcVector[pExt->base] = vboxRandRSwappedDispatch;
351#endif
352 return TRUE;
353}
354
355/** Install our private RandR hook procedure, so that we can detect
356 * GetScreenInfo requests from clients to update our dynamic mode. This works
357 * by installing a wrapper around CreateScreenResources(), which will be called
358 * after RandR is initialised. The wrapper then in turn wraps the RandR "proc"
359 * vectors with its own handlers which will get called on any client RandR
360 * request. This should not be used in conjunction with RandR 1.2 or later.
361 * A couple of points of interest in our RandR 1.1 support:
362 * * We use the first two screen modes as dynamic modes. When a new mode hint
363 * arrives we update the first of the two which is not the current mode with
364 * the new size.
365 * * RandR 1.1 always advertises a mode of the size of the initial virtual
366 * resolution via GetScreenInfo(), so we make sure that a mode of that size
367 * is always present in the list.
368 * * RandR adds each new mode it sees to an internal array, but never removes
369 * entries. This array might end up getting rather long given that we can
370 * report a lot more modes than physical hardware.
371 */
372void VBoxSetUpRandR11(ScreenPtr pScreen)
373{
374 VBOXPtr pVBox = VBOXGetRec(xf86Screens[pScreen->myNum]);
375
376 if (!pScreen->CreateScreenResources)
377 FatalError("called to early: CreateScreenResources not yet initialised\n");
378 pVBox->pfnCreateScreenResources = pScreen->CreateScreenResources;
379 pScreen->CreateScreenResources = vboxRandRCreateScreenResources;
380}
381
382#endif /* !VBOXVIDEO_13 */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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