1 | /* $Id: vboxutils.c 46042 2013-05-13 19:45:02Z 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 <VBox/VMMDev.h>
|
---|
19 | #include <VBox/VBoxGuestLib.h>
|
---|
20 |
|
---|
21 | #ifndef PCIACCESS
|
---|
22 | # include <xf86Pci.h>
|
---|
23 | # include <Pci.h>
|
---|
24 | #endif
|
---|
25 |
|
---|
26 | #include "xf86.h"
|
---|
27 | #define NEED_XF86_TYPES
|
---|
28 | #include <iprt/string.h>
|
---|
29 | #include "compiler.h"
|
---|
30 |
|
---|
31 | #include "vboxvideo.h"
|
---|
32 |
|
---|
33 | #ifdef XORG_7X
|
---|
34 | # include <stdio.h>
|
---|
35 | # include <stdlib.h>
|
---|
36 | #endif
|
---|
37 |
|
---|
38 | /**************************************************************************
|
---|
39 | * Main functions *
|
---|
40 | **************************************************************************/
|
---|
41 |
|
---|
42 | /**
|
---|
43 | * Inform VBox that we are aware of advanced graphics functions
|
---|
44 | * (i.e. dynamic resizing, seamless).
|
---|
45 | *
|
---|
46 | * @returns TRUE for success, FALSE for failure
|
---|
47 | */
|
---|
48 | Bool
|
---|
49 | vboxEnableGraphicsCap(VBOXPtr pVBox)
|
---|
50 | {
|
---|
51 | TRACE_ENTRY();
|
---|
52 | if (!pVBox->useDevice)
|
---|
53 | return FALSE;
|
---|
54 | return RT_SUCCESS(VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0));
|
---|
55 | }
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * Inform VBox that we are no longer aware of advanced graphics functions
|
---|
59 | * (i.e. dynamic resizing, seamless).
|
---|
60 | *
|
---|
61 | * @returns TRUE for success, FALSE for failure
|
---|
62 | */
|
---|
63 | Bool
|
---|
64 | vboxDisableGraphicsCap(VBOXPtr pVBox)
|
---|
65 | {
|
---|
66 | TRACE_ENTRY();
|
---|
67 | if (!pVBox->useDevice)
|
---|
68 | return FALSE;
|
---|
69 | return RT_SUCCESS(VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
|
---|
70 | }
|
---|
71 |
|
---|
72 | /**
|
---|
73 | * Query the last display change request.
|
---|
74 | *
|
---|
75 | * @returns boolean success indicator.
|
---|
76 | * @param pScrn Pointer to the X screen info structure.
|
---|
77 | * @param pcx Where to store the horizontal pixel resolution (0 = do not change).
|
---|
78 | * @param pcy Where to store the vertical pixel resolution (0 = do not change).
|
---|
79 | * @param pcBits Where to store the bits per pixel (0 = do not change).
|
---|
80 | * @param iDisplay Where to store the display number the request was for - 0 for the
|
---|
81 | * primary display, 1 for the first secondary, etc.
|
---|
82 | */
|
---|
83 | Bool
|
---|
84 | vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
|
---|
85 | uint32_t *pcBits, uint32_t *piDisplay)
|
---|
86 | {
|
---|
87 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
88 | TRACE_ENTRY();
|
---|
89 | if (!pVBox->useDevice)
|
---|
90 | return FALSE;
|
---|
91 | int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, piDisplay, false);
|
---|
92 | if (RT_SUCCESS(rc))
|
---|
93 | return TRUE;
|
---|
94 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc);
|
---|
95 | return FALSE;
|
---|
96 | }
|
---|
97 |
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * Query the host as to whether it likes a specific video mode.
|
---|
101 | *
|
---|
102 | * @returns the result of the query
|
---|
103 | * @param cx the width of the mode being queried
|
---|
104 | * @param cy the height of the mode being queried
|
---|
105 | * @param cBits the bpp of the mode being queried
|
---|
106 | */
|
---|
107 | Bool
|
---|
108 | vboxHostLikesVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
|
---|
109 | {
|
---|
110 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
111 | TRACE_ENTRY();
|
---|
112 | if (!pVBox->useDevice)
|
---|
113 | return TRUE; /* If we can't ask the host then we like everything. */
|
---|
114 | return VbglR3HostLikesVideoMode(cx, cy, cBits);
|
---|
115 | }
|
---|
116 |
|
---|
117 | /**
|
---|
118 | * Check if any seamless mode is enabled.
|
---|
119 | * Seamless is only relevant for the newer Xorg modules.
|
---|
120 | *
|
---|
121 | * @returns the result of the query
|
---|
122 | * (true = seamless enabled, false = seamless not enabled)
|
---|
123 | * @param pScrn Screen info pointer.
|
---|
124 | */
|
---|
125 | Bool
|
---|
126 | vboxGuestIsSeamless(ScrnInfoPtr pScrn)
|
---|
127 | {
|
---|
128 | VMMDevSeamlessMode mode;
|
---|
129 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
130 | TRACE_ENTRY();
|
---|
131 | if (!pVBox->useDevice)
|
---|
132 | return FALSE;
|
---|
133 | if (RT_FAILURE(VbglR3SeamlessGetLastEvent(&mode)))
|
---|
134 | return FALSE;
|
---|
135 | return (mode != VMMDev_Seamless_Disabled);
|
---|
136 | }
|
---|
137 |
|
---|
138 | /**
|
---|
139 | * Save video mode parameters to the registry.
|
---|
140 | *
|
---|
141 | * @returns iprt status value
|
---|
142 | * @param pszName the name to save the mode parameters under
|
---|
143 | * @param cx mode width
|
---|
144 | * @param cy mode height
|
---|
145 | * @param cBits bits per pixel for the mode
|
---|
146 | */
|
---|
147 | Bool
|
---|
148 | vboxSaveVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
|
---|
149 | {
|
---|
150 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
151 | TRACE_ENTRY();
|
---|
152 | if (!pVBox->useDevice)
|
---|
153 | return FALSE;
|
---|
154 | return RT_SUCCESS(VbglR3SaveVideoMode("SavedMode", cx, cy, cBits));
|
---|
155 | }
|
---|
156 |
|
---|
157 | /**
|
---|
158 | * Retrieve video mode parameters from the registry.
|
---|
159 | *
|
---|
160 | * @returns iprt status value
|
---|
161 | * @param pszName the name under which the mode parameters are saved
|
---|
162 | * @param pcx where to store the mode width
|
---|
163 | * @param pcy where to store the mode height
|
---|
164 | * @param pcBits where to store the bits per pixel for the mode
|
---|
165 | */
|
---|
166 | Bool
|
---|
167 | vboxRetrieveVideoMode(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits)
|
---|
168 | {
|
---|
169 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
170 | int rc;
|
---|
171 | TRACE_ENTRY();
|
---|
172 | if (!pVBox->useDevice)
|
---|
173 | rc = VERR_NOT_AVAILABLE;
|
---|
174 | else
|
---|
175 | rc = VbglR3RetrieveVideoMode("SavedMode", pcx, pcy, pcBits);
|
---|
176 | if (RT_SUCCESS(rc))
|
---|
177 | TRACE_LOG("Retrieved a video mode of %dx%dx%d\n", *pcx, *pcy, *pcBits);
|
---|
178 | else
|
---|
179 | TRACE_LOG("Failed to retrieve video mode, error %d\n", rc);
|
---|
180 | return (RT_SUCCESS(rc));
|
---|
181 | }
|
---|
182 |
|
---|
183 | /**
|
---|
184 | * Fills a display mode M with a built-in mode of name pszName and dimensions
|
---|
185 | * cx and cy.
|
---|
186 | */
|
---|
187 | static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
|
---|
188 | const char *pszName, unsigned cx, unsigned cy)
|
---|
189 | {
|
---|
190 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
191 | TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
|
---|
192 | m->status = MODE_OK;
|
---|
193 | m->type = M_T_BUILTIN;
|
---|
194 | /* Older versions of VBox only support screen widths which are a multiple
|
---|
195 | * of 8 */
|
---|
196 | if (pVBox->fAnyX)
|
---|
197 | m->HDisplay = cx;
|
---|
198 | else
|
---|
199 | m->HDisplay = cx & ~7;
|
---|
200 | m->HSyncStart = m->HDisplay + 2;
|
---|
201 | m->HSyncEnd = m->HDisplay + 4;
|
---|
202 | m->HTotal = m->HDisplay + 6;
|
---|
203 | m->VDisplay = cy;
|
---|
204 | m->VSyncStart = m->VDisplay + 2;
|
---|
205 | m->VSyncEnd = m->VDisplay + 4;
|
---|
206 | m->VTotal = m->VDisplay + 6;
|
---|
207 | m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
|
---|
208 | if (pszName)
|
---|
209 | {
|
---|
210 | if (m->name)
|
---|
211 | free(m->name);
|
---|
212 | m->name = xnfstrdup(pszName);
|
---|
213 | }
|
---|
214 | }
|
---|
215 |
|
---|
216 | /** vboxvideo's list of standard video modes */
|
---|
217 | struct
|
---|
218 | {
|
---|
219 | /** mode width */
|
---|
220 | uint32_t cx;
|
---|
221 | /** mode height */
|
---|
222 | uint32_t cy;
|
---|
223 | } vboxStandardModes[] =
|
---|
224 | {
|
---|
225 | { 1600, 1200 },
|
---|
226 | { 1440, 1050 },
|
---|
227 | { 1280, 960 },
|
---|
228 | { 1024, 768 },
|
---|
229 | { 800, 600 },
|
---|
230 | { 640, 480 },
|
---|
231 | { 0, 0 }
|
---|
232 | };
|
---|
233 | enum
|
---|
234 | {
|
---|
235 | vboxNumStdModes = sizeof(vboxStandardModes) / sizeof(vboxStandardModes[0])
|
---|
236 | };
|
---|
237 |
|
---|
238 | /**
|
---|
239 | * Returns a standard mode which the host likes. Can be called multiple
|
---|
240 | * times with the index returned by the previous call to get a list of modes.
|
---|
241 | * @returns the index of the mode in the list, or 0 if no more modes are
|
---|
242 | * available
|
---|
243 | * @param pScrn the screen information structure
|
---|
244 | * @param pScrn->bitsPerPixel
|
---|
245 | * if this is non-null, only modes with this BPP will be
|
---|
246 | * returned
|
---|
247 | * @param cIndex the index of the last mode queried, or 0 to query the
|
---|
248 | * first mode available. Note: the first index is 1
|
---|
249 | * @param pcx where to store the mode's width
|
---|
250 | * @param pcy where to store the mode's height
|
---|
251 | * @param pcBits where to store the mode's BPP
|
---|
252 | */
|
---|
253 | unsigned vboxNextStandardMode(ScrnInfoPtr pScrn, unsigned cIndex,
|
---|
254 | uint32_t *pcx, uint32_t *pcy,
|
---|
255 | uint32_t *pcBits)
|
---|
256 | {
|
---|
257 | unsigned i;
|
---|
258 |
|
---|
259 | XF86ASSERT(cIndex < vboxNumStdModes,
|
---|
260 | ("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
|
---|
261 | vboxNumStdModes));
|
---|
262 | for (i = cIndex; i < vboxNumStdModes - 1; ++i)
|
---|
263 | {
|
---|
264 | uint32_t cBits = pScrn->bitsPerPixel;
|
---|
265 | uint32_t cx = vboxStandardModes[i].cx;
|
---|
266 | uint32_t cy = vboxStandardModes[i].cy;
|
---|
267 |
|
---|
268 | if (cBits != 0 && !vboxHostLikesVideoMode(pScrn, cx, cy, cBits))
|
---|
269 | continue;
|
---|
270 | if (vboxHostLikesVideoMode(pScrn, cx, cy, 32))
|
---|
271 | cBits = 32;
|
---|
272 | else if (vboxHostLikesVideoMode(pScrn, cx, cy, 16))
|
---|
273 | cBits = 16;
|
---|
274 | else
|
---|
275 | continue;
|
---|
276 | if (pcx)
|
---|
277 | *pcx = cx;
|
---|
278 | if (pcy)
|
---|
279 | *pcy = cy;
|
---|
280 | if (pcBits)
|
---|
281 | *pcBits = cBits;
|
---|
282 | return i + 1;
|
---|
283 | }
|
---|
284 | return 0;
|
---|
285 | }
|
---|
286 |
|
---|
287 | /**
|
---|
288 | * Returns the preferred video mode. The current order of preference is
|
---|
289 | * (from highest to least preferred):
|
---|
290 | * - The mode corresponding to the last size hint from the host
|
---|
291 | * - The video mode saved from the last session
|
---|
292 | * - The largest standard mode which the host likes, falling back to
|
---|
293 | * 640x480x32 as a worst case
|
---|
294 | * - If the host can't be contacted at all, we return 1024x768x32
|
---|
295 | *
|
---|
296 | * The return type is void as we guarantee we will return some mode.
|
---|
297 | */
|
---|
298 | void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t iScreen, uint32_t *pcx,
|
---|
299 | uint32_t *pcy, uint32_t *pcBits)
|
---|
300 | {
|
---|
301 | /* Query the host for the preferred resolution and colour depth */
|
---|
302 | uint32_t cx = 0, cy = 0, iScreenIn = iScreen, cBits = 32;
|
---|
303 | VBOXPtr pVBox = pScrn->driverPrivate;
|
---|
304 |
|
---|
305 | TRACE_LOG("iScreen=%u\n", iScreen);
|
---|
306 | bool found = false;
|
---|
307 | if ( pVBox->aPreferredSize[iScreen].cx
|
---|
308 | && pVBox->aPreferredSize[iScreen].cy)
|
---|
309 | {
|
---|
310 | cx = pVBox->aPreferredSize[iScreen].cx;
|
---|
311 | cy = pVBox->aPreferredSize[iScreen].cy;
|
---|
312 | found = true;
|
---|
313 | }
|
---|
314 | if (pVBox->useDevice)
|
---|
315 | {
|
---|
316 | if (!found)
|
---|
317 | found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits,
|
---|
318 | &iScreenIn);
|
---|
319 | if ((cx == 0) || (cy == 0) || iScreenIn != iScreen)
|
---|
320 | found = false;
|
---|
321 | if (!found)
|
---|
322 | found = vboxRetrieveVideoMode(pScrn, &cx, &cy, &cBits);
|
---|
323 | if ((cx == 0) || (cy == 0))
|
---|
324 | found = false;
|
---|
325 | if (!found)
|
---|
326 | found = (vboxNextStandardMode(pScrn, 0, &cx, &cy, &cBits) != 0);
|
---|
327 | if (!found)
|
---|
328 | {
|
---|
329 | /* Last resort */
|
---|
330 | cx = 640;
|
---|
331 | cy = 480;
|
---|
332 | cBits = 32;
|
---|
333 | }
|
---|
334 | }
|
---|
335 | else
|
---|
336 | {
|
---|
337 | cx = 1024;
|
---|
338 | cy = 768;
|
---|
339 | }
|
---|
340 | if (pcx)
|
---|
341 | *pcx = cx;
|
---|
342 | if (pcy)
|
---|
343 | *pcy = cy;
|
---|
344 | if (pcBits)
|
---|
345 | *pcBits = cBits;
|
---|
346 | TRACE_LOG("cx=%u, cy=%u, cBits=%u\n", cx, cy, cBits);
|
---|
347 | }
|
---|
348 |
|
---|
349 | /* Move a screen mode found to the end of the list, so that RandR will give
|
---|
350 | * it the highest priority when a mode switch is requested. Returns the mode
|
---|
351 | * that was previously before the mode in the list in order to allow the
|
---|
352 | * caller to continue walking the list. */
|
---|
353 | static DisplayModePtr vboxMoveModeToFront(ScrnInfoPtr pScrn,
|
---|
354 | DisplayModePtr pMode)
|
---|
355 | {
|
---|
356 | DisplayModePtr pPrev = pMode->prev;
|
---|
357 | if (pMode != pScrn->modes)
|
---|
358 | {
|
---|
359 | pMode->prev->next = pMode->next;
|
---|
360 | pMode->next->prev = pMode->prev;
|
---|
361 | pMode->next = pScrn->modes;
|
---|
362 | pMode->prev = pScrn->modes->prev;
|
---|
363 | pMode->next->prev = pMode;
|
---|
364 | pMode->prev->next = pMode;
|
---|
365 | pScrn->modes = pMode;
|
---|
366 | }
|
---|
367 | return pPrev;
|
---|
368 | }
|
---|
369 |
|
---|
370 | /**
|
---|
371 | * Rewrites the first dynamic mode found which is not the current screen mode
|
---|
372 | * to contain the host's currently preferred screen size, then moves that
|
---|
373 | * mode to the front of the screen information structure's mode list.
|
---|
374 | * Additionally, if the current mode is not dynamic, the second dynamic mode
|
---|
375 | * will be set to match the current mode and also added to the front. This
|
---|
376 | * ensures that the user can always reset the current size to kick the driver
|
---|
377 | * to update its mode list.
|
---|
378 | */
|
---|
379 | void vboxWriteHostModes(ScrnInfoPtr pScrn, DisplayModePtr pCurrent)
|
---|
380 | {
|
---|
381 | uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 0;
|
---|
382 | DisplayModePtr pMode;
|
---|
383 | bool found = false;
|
---|
384 |
|
---|
385 | TRACE_ENTRY();
|
---|
386 | vboxGetPreferredMode(pScrn, 0, &cx, &cy, &cBits);
|
---|
387 | #ifdef DEBUG
|
---|
388 | /* Count the number of modes for sanity */
|
---|
389 | unsigned cModes = 1, cMode = 0;
|
---|
390 | DisplayModePtr pCount;
|
---|
391 | for (pCount = pScrn->modes; ; pCount = pCount->next, ++cModes)
|
---|
392 | if (pCount->next == pScrn->modes)
|
---|
393 | break;
|
---|
394 | #endif
|
---|
395 | for (pMode = pScrn->modes; ; pMode = pMode->next)
|
---|
396 | {
|
---|
397 | #ifdef DEBUG
|
---|
398 | XF86ASSERT (cMode++ < cModes, (NULL));
|
---|
399 | #endif
|
---|
400 | if ( pMode != pCurrent
|
---|
401 | && !strcmp(pMode->name, "VBoxDynamicMode"))
|
---|
402 | {
|
---|
403 | if (!found)
|
---|
404 | vboxFillDisplayMode(pScrn, pMode, NULL, cx, cy);
|
---|
405 | else if (pCurrent)
|
---|
406 | vboxFillDisplayMode(pScrn, pMode, NULL, pCurrent->HDisplay,
|
---|
407 | pCurrent->VDisplay);
|
---|
408 | found = true;
|
---|
409 | pMode = vboxMoveModeToFront(pScrn, pMode);
|
---|
410 | }
|
---|
411 | if (pMode->next == pScrn->modes)
|
---|
412 | break;
|
---|
413 | }
|
---|
414 | XF86ASSERT (found,
|
---|
415 | ("vboxvideo: no free dynamic mode found. Exiting.\n"));
|
---|
416 | XF86ASSERT ( (pScrn->modes->HDisplay == (long) cx)
|
---|
417 | || ( (pScrn->modes->HDisplay == pCurrent->HDisplay)
|
---|
418 | && (pScrn->modes->next->HDisplay == (long) cx)),
|
---|
419 | ("pScrn->modes->HDisplay=%u, pScrn->modes->next->HDisplay=%u\n",
|
---|
420 | pScrn->modes->HDisplay, pScrn->modes->next->HDisplay));
|
---|
421 | XF86ASSERT ( (pScrn->modes->VDisplay == (long) cy)
|
---|
422 | || ( (pScrn->modes->VDisplay == pCurrent->VDisplay)
|
---|
423 | && (pScrn->modes->next->VDisplay == (long) cy)),
|
---|
424 | ("pScrn->modes->VDisplay=%u, pScrn->modes->next->VDisplay=%u\n",
|
---|
425 | pScrn->modes->VDisplay, pScrn->modes->next->VDisplay));
|
---|
426 | }
|
---|
427 |
|
---|
428 | /**
|
---|
429 | * Allocates an empty display mode and links it into the doubly linked list of
|
---|
430 | * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
|
---|
431 | * memory.
|
---|
432 | */
|
---|
433 | static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
|
---|
434 | {
|
---|
435 | DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
|
---|
436 |
|
---|
437 | TRACE_ENTRY();
|
---|
438 | if (!pScrn->modes)
|
---|
439 | {
|
---|
440 | pScrn->modes = pMode;
|
---|
441 | pMode->next = pMode;
|
---|
442 | pMode->prev = pMode;
|
---|
443 | }
|
---|
444 | else
|
---|
445 | {
|
---|
446 | pMode->next = pScrn->modes;
|
---|
447 | pMode->prev = pScrn->modes->prev;
|
---|
448 | pMode->next->prev = pMode;
|
---|
449 | pMode->prev->next = pMode;
|
---|
450 | }
|
---|
451 | return pMode;
|
---|
452 | }
|
---|
453 |
|
---|
454 | /**
|
---|
455 | * Create display mode entries in the screen information structure for each
|
---|
456 | * of the initial graphics modes that we wish to support. This includes:
|
---|
457 | * - An initial mode, of the size requested by the caller
|
---|
458 | * - Two dynamic modes, one of which will be updated to match the last size
|
---|
459 | * hint from the host on each mode switch, but initially also of the
|
---|
460 | * requested size
|
---|
461 | * - Several standard modes, if possible ones that the host likes
|
---|
462 | * - Any modes that the user requested in xorg.conf/XFree86Config
|
---|
463 | */
|
---|
464 | void vboxAddModes(ScrnInfoPtr pScrn, uint32_t cxInit, uint32_t cyInit)
|
---|
465 | {
|
---|
466 | unsigned cx = 0, cy = 0, cIndex = 0;
|
---|
467 | unsigned i;
|
---|
468 | /* For reasons related to the way RandR 1.1 is implemented, we need to
|
---|
469 | * make sure that the initial mode (more precisely, a mode equal to the
|
---|
470 | * initial virtual resolution) is always present in the mode list. RandR
|
---|
471 | * has the assumption build in that there will either be a mode of that
|
---|
472 | * size present at all times, or that the first mode in the list will
|
---|
473 | * always be smaller than the initial virtual resolution. Since our
|
---|
474 | * approach to dynamic resizing isn't quite the way RandR was intended to
|
---|
475 | * be, and breaks the second assumption, we guarantee the first. */
|
---|
476 | DisplayModePtr pMode = vboxAddEmptyScreenMode(pScrn);
|
---|
477 | vboxFillDisplayMode(pScrn, pMode, "VBoxInitialMode", cxInit, cyInit);
|
---|
478 | /* Create our two dynamic modes. */
|
---|
479 | pMode = vboxAddEmptyScreenMode(pScrn);
|
---|
480 | vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
|
---|
481 | pMode = vboxAddEmptyScreenMode(pScrn);
|
---|
482 | vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
|
---|
483 | /* Add standard modes supported by the host */
|
---|
484 | for ( ; ; )
|
---|
485 | {
|
---|
486 | char szName[256];
|
---|
487 | cIndex = vboxNextStandardMode(pScrn, cIndex, &cx, &cy, NULL);
|
---|
488 | if (cIndex == 0)
|
---|
489 | break;
|
---|
490 | sprintf(szName, "VBox-%ux%u", cx, cy);
|
---|
491 | pMode = vboxAddEmptyScreenMode(pScrn);
|
---|
492 | vboxFillDisplayMode(pScrn, pMode, szName, cx, cy);
|
---|
493 | }
|
---|
494 | /* And finally any modes specified by the user. We assume here that
|
---|
495 | * the mode names reflect the mode sizes. */
|
---|
496 | for (i = 0; pScrn->display->modes && pScrn->display->modes[i]; i++)
|
---|
497 | {
|
---|
498 | if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
|
---|
499 | {
|
---|
500 | pMode = vboxAddEmptyScreenMode(pScrn);
|
---|
501 | vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
|
---|
502 | }
|
---|
503 | }
|
---|
504 | }
|
---|