VirtualBox

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

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

Additions/x11: allow VBoxClient to send monitor disable events to the graphics driver and clean up slightly.

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