VirtualBox

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

Last change on this file since 35125 was 35125, checked in by vboxsync, 14 years ago

Additions/x11/vboxvide: logging adjustments

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 40.3 KB
Line 
1/** @file
2 * VirtualBox X11 Additions graphics driver utility functions
3 */
4
5/*
6 * Copyright (C) 2006-2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include <VBox/VMMDev.h>
18#include <VBox/VBoxGuestLib.h>
19
20#ifndef PCIACCESS
21# include <xf86Pci.h>
22# include <Pci.h>
23#endif
24
25#include "xf86.h"
26#define NEED_XF86_TYPES
27#ifdef NO_ANSIC
28# include <string.h>
29#else
30# include "xf86_ansic.h"
31#endif
32#include "compiler.h"
33#include "cursorstr.h"
34
35#include "vboxvideo.h"
36
37#define VBOX_MAX_CURSOR_WIDTH 64
38#define VBOX_MAX_CURSOR_HEIGHT 64
39
40/**************************************************************************
41* Debugging functions and macros *
42**************************************************************************/
43
44/* #define DEBUG_POINTER */
45
46#ifdef DEBUG
47# define PUT_PIXEL(c) ErrorF ("%c", c)
48#else /* DEBUG_VIDEO not defined */
49# define PUT_PIXEL(c) do { } while(0)
50#endif /* DEBUG_VIDEO not defined */
51
52/** Macro to printf an error message and return from a function */
53#define RETERROR(scrnIndex, RetVal, ...) \
54 do \
55 { \
56 xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
57 return RetVal; \
58 } \
59 while (0)
60
61/** Structure to pass cursor image data between realise_cursor() and
62 * load_cursor_image(). The members match the parameters to
63 * @a VBoxHGSMIUpdatePointerShape(). */
64struct vboxCursorImage
65{
66 uint32_t fFlags;
67 uint32_t cHotX;
68 uint32_t cHotY;
69 uint32_t cWidth;
70 uint32_t cHeight;
71 uint8_t *pPixels;
72 uint32_t cbLength;
73};
74
75#ifdef DEBUG_POINTER
76static void
77vbox_show_shape(unsigned short w, unsigned short h, CARD32 bg, unsigned char *image)
78{
79 size_t x, y;
80 unsigned short pitch;
81 CARD32 *color;
82 unsigned char *mask;
83 size_t sizeMask;
84
85 image += sizeof(struct vboxCursorImage);
86 mask = image;
87 pitch = (w + 7) / 8;
88 sizeMask = (pitch * h + 3) & ~3;
89 color = (CARD32 *)(image + sizeMask);
90
91 TRACE_ENTRY();
92 for (y = 0; y < h; ++y, mask += pitch, color += w)
93 {
94 for (x = 0; x < w; ++x)
95 {
96 if (mask[x / 8] & (1 << (7 - (x % 8))))
97 ErrorF (" ");
98 else
99 {
100 CARD32 c = color[x];
101 if (c == bg)
102 ErrorF("Y");
103 else
104 ErrorF("X");
105 }
106 }
107 ErrorF("\n");
108 }
109}
110#endif
111
112/**************************************************************************
113* Helper functions and macros *
114**************************************************************************/
115
116/* This is called by the X server every time it loads a new cursor to see
117 * whether our "cursor hardware" can handle the cursor. This provides us with
118 * a mechanism (the only one!) to switch back from a software to a hardware
119 * cursor. */
120static Bool
121vbox_host_uses_hwcursor(ScrnInfoPtr pScrn)
122{
123 Bool rc = TRUE;
124 uint32_t fFeatures = 0;
125 VBOXPtr pVBox = pScrn->driverPrivate;
126
127 /* We may want to force the use of a software cursor. Currently this is
128 * needed if the guest uses a large virtual resolution, as in this case
129 * the host and guest tend to disagree about the pointer location. */
130 if (pVBox->forceSWCursor)
131 rc = FALSE;
132 /* Query information about mouse integration from the host. */
133 if (rc) {
134 int vrc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
135 if (RT_FAILURE(vrc)) {
136 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
137 "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", vrc);
138 rc = FALSE;
139 }
140 }
141 /* If we got the information from the host then make sure the host wants
142 * to draw the pointer. */
143 if (rc)
144 {
145 if ( (fFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
146#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
147 /* As of this version (server 1.6) all major Linux releases
148 * are known to handle USB tablets correctly. */
149 || (fFeatures & VMMDEV_MOUSE_HOST_HAS_ABS_DEV)
150#endif
151 )
152 /* Assume this will never be unloaded as long as the X session is
153 * running. */
154 pVBox->guestCanAbsolute = TRUE;
155 if ( (fFeatures & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
156 || !pVBox->guestCanAbsolute
157 || !(fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
158 )
159 rc = FALSE;
160 }
161 return rc;
162}
163
164/**************************************************************************
165* Main functions *
166**************************************************************************/
167
168void
169vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
170{
171 TRACE_ENTRY();
172
173 xf86DestroyCursorInfoRec(pVBox->pCurs);
174 pVBox->pCurs = NULL;
175 TRACE_EXIT();
176}
177
178/**
179 * Callback function called by the X server to tell us about dirty
180 * rectangles in the video buffer.
181 *
182 * @param pScreen pointer to the information structure for the current
183 * screen
184 * @param iRects Number of dirty rectangles to update
185 * @param aRects Array of structures containing the coordinates of the
186 * rectangles
187 */
188static void
189vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
190{
191 VBVACMDHDR cmdHdr;
192 VBOXPtr pVBox;
193 int i;
194 unsigned j;
195
196 pVBox = pScrn->driverPrivate;
197 if (pVBox->fHaveHGSMI == FALSE)
198 return;
199
200 for (i = 0; i < iRects; ++i)
201 for (j = 0; j < pVBox->cScreens; ++j)
202 {
203 /* Just continue quietly if VBVA is not currently active. */
204 struct VBVABUFFER *pVBVA = pVBox->aVbvaCtx[j].pVBVA;
205 if ( !pVBVA
206 || !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
207 continue;
208 if ( aRects[i].x1 > pVBox->aScreenLocation[j].x
209 + pVBox->aScreenLocation[j].cx
210 || aRects[i].y1 > pVBox->aScreenLocation[j].y
211 + pVBox->aScreenLocation[j].cy
212 || aRects[i].x2 < pVBox->aScreenLocation[j].x
213 || aRects[i].y2 < pVBox->aScreenLocation[j].y)
214 continue;
215 cmdHdr.x = (int16_t)aRects[i].x1;
216 cmdHdr.y = (int16_t)aRects[i].y1;
217 cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
218 cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
219
220#if 0
221 TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n",
222 j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h);
223#endif
224
225 VBoxVBVABufferBeginUpdate(&pVBox->aVbvaCtx[j], &pVBox->guestCtx);
226 VBoxVBVAWrite(&pVBox->aVbvaCtx[j], &pVBox->guestCtx, &cmdHdr,
227 sizeof(cmdHdr));
228 VBoxVBVABufferEndUpdate(&pVBox->aVbvaCtx[j]);
229 }
230}
231
232/** Callback to fill in the view structures */
233static int
234vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews)
235{
236 VBOXPtr pVBox = (VBOXPtr)pvVBox;
237 unsigned i;
238 for (i = 0; i < cViews; ++i)
239 {
240 pViews[i].u32ViewIndex = i;
241 pViews[i].u32ViewOffset = 0;
242 pViews[i].u32ViewSize = pVBox->cbView;
243 pViews[i].u32MaxScreenSize = pVBox->cbFramebuffer;
244 }
245 return VINF_SUCCESS;
246}
247
248/**
249 * Initialise VirtualBox's accelerated video extensions.
250 *
251 * @returns TRUE on success, FALSE on failure
252 */
253static Bool
254vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
255{
256 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
257 int rc = VINF_SUCCESS;
258 unsigned i;
259 uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory,
260 cScreens;
261 void *pvGuestHeapMemory;
262
263 pVBox->cScreens = 1;
264 if (!VBoxHGSMIIsSupported())
265 {
266 xf86DrvMsg(scrnIndex, X_ERROR, "The graphics device does not seem to support HGSMI. Disableing video acceleration.\n");
267 return FALSE;
268 }
269 VBoxHGSMIGetBaseMappingInfo(pScrn->videoRam * 1024, &offVRAMBaseMapping,
270 NULL, &offGuestHeapMemory, &cbGuestHeapMemory,
271 NULL);
272 pvGuestHeapMemory = ((uint8_t *)pVBox->base) + offVRAMBaseMapping
273 + offGuestHeapMemory;
274 TRACE_LOG("video RAM: %u KB, guest heap offset: 0x%x, cbGuestHeapMemory: %u\n",
275 pScrn->videoRam, offVRAMBaseMapping + offGuestHeapMemory,
276 cbGuestHeapMemory);
277 rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory,
278 cbGuestHeapMemory,
279 offVRAMBaseMapping + offGuestHeapMemory);
280 if (RT_FAILURE(rc))
281 {
282 xf86DrvMsg(scrnIndex, X_ERROR, "Failed to set up the guest-to-host communication context, rc=%d\n", rc);
283 return FALSE;
284 }
285 pVBox->cbView = pVBox->cbFramebuffer = offVRAMBaseMapping;
286 pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
287 xf86DrvMsg(scrnIndex, X_INFO, "Requested monitor count: %u\n",
288 pVBox->cScreens);
289 for (i = 0; i < pVBox->cScreens; ++i)
290 {
291 pVBox->cbFramebuffer -= VBVA_MIN_BUFFER_SIZE;
292 pVBox->aoffVBVABuffer[i] = pVBox->cbFramebuffer;
293 TRACE_LOG("VBVA buffer offset for screen %u: 0x%lx\n", i,
294 (unsigned long) pVBox->cbFramebuffer);
295 VBoxVBVASetupBufferContext(&pVBox->aVbvaCtx[i],
296 pVBox->aoffVBVABuffer[i],
297 VBVA_MIN_BUFFER_SIZE);
298 }
299 TRACE_LOG("Maximum framebuffer size: %lu (0x%lx)\n",
300 (unsigned long) pVBox->cbFramebuffer,
301 (unsigned long) pVBox->cbFramebuffer);
302 rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens,
303 vboxFillViewInfo, (void *)pVBox);
304
305 /* Set up the dirty rectangle handler. It will be added into a function
306 * chain and gets removed when the screen is cleaned up. */
307 if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
308 {
309 xf86DrvMsg(scrnIndex, X_ERROR,
310 "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
311 return FALSE;
312 }
313 return TRUE;
314}
315
316Bool
317vbox_init(int scrnIndex, VBOXPtr pVBox)
318{
319 Bool rc = TRUE;
320 int vrc;
321 uint32_t fMouseFeatures = 0;
322
323 TRACE_ENTRY();
324 vrc = VbglR3Init();
325 if (RT_FAILURE(vrc))
326 {
327 xf86DrvMsg(scrnIndex, X_ERROR,
328 "Failed to initialize the VirtualBox device (rc=%d) - make sure that the VirtualBox guest additions are properly installed. If you are not sure, try reinstalling them. The X Window graphics drivers will run in compatibility mode.\n",
329 vrc);
330 rc = FALSE;
331 }
332 pVBox->useDevice = rc;
333 /* We can't switch to a software cursor at will without help from
334 * VBoxClient. So tell that to the host and wait for VBoxClient to
335 * change this. */
336 vrc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
337 if (RT_SUCCESS(vrc))
338 VbglR3SetMouseStatus( fMouseFeatures
339 | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
340 return rc;
341}
342
343Bool
344vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
345{
346 TRACE_ENTRY();
347
348 if (!pVBox->useDevice)
349 return FALSE;
350 pVBox->fHaveHGSMI = vboxInitVbva(pScrn->scrnIndex, pScreen, pVBox);
351 return TRUE;
352}
353
354Bool
355vbox_device_available(VBOXPtr pVBox)
356{
357 return pVBox->useDevice;
358}
359
360static void
361vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
362{
363 int rc;
364
365 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
366 if (RT_FAILURE(rc))
367 {
368 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer, VBox error %d.\n", rc);
369 /* Play safe, and disable the hardware cursor until the next mode
370 * switch, since obviously something happened that we didn't
371 * anticipate. */
372 pVBox->forceSWCursor = TRUE;
373 }
374}
375
376static void
377vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
378{
379 int rc;
380
381 if (!vbox_host_uses_hwcursor(pScrn))
382 return;
383 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
384 0, 0, 0, 0, NULL, 0);
385 if (RT_FAILURE(rc)) {
386 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
387 /* Play safe, and disable the hardware cursor until the next mode
388 * switch, since obviously something happened that we didn't
389 * anticipate. */
390 pVBox->forceSWCursor = TRUE;
391 }
392}
393
394static void
395vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
396 unsigned char *pvImage)
397{
398 int rc;
399 struct vboxCursorImage *pImage;
400 pImage = (struct vboxCursorImage *)pvImage;
401
402#ifdef DEBUG_POINTER
403 vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
404#endif
405
406 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
407 pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
408 pImage->pPixels, pImage->cbLength);
409 if (RT_FAILURE(rc)) {
410 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
411 /* Play safe, and disable the hardware cursor until the next mode
412 * switch, since obviously something happened that we didn't
413 * anticipate. */
414 pVBox->forceSWCursor = TRUE;
415 }
416}
417
418static void
419vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
420{
421 NOREF(pScrn);
422 NOREF(bg);
423 NOREF(fg);
424 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
425}
426
427
428static void
429vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
430{
431 /* Nothing to do here, as we are telling the guest where the mouse is,
432 * not vice versa. */
433 NOREF(pScrn);
434 NOREF(x);
435 NOREF(y);
436}
437
438static void
439vbox_hide_cursor(ScrnInfoPtr pScrn)
440{
441 VBOXPtr pVBox = pScrn->driverPrivate;
442
443 vbox_vmm_hide_cursor(pScrn, pVBox);
444}
445
446static void
447vbox_show_cursor(ScrnInfoPtr pScrn)
448{
449 VBOXPtr pVBox = pScrn->driverPrivate;
450
451 vbox_vmm_show_cursor(pScrn, pVBox);
452}
453
454static void
455vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
456{
457 VBOXPtr pVBox = pScrn->driverPrivate;
458
459 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
460}
461
462static Bool
463vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
464{
465 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
466 return vbox_host_uses_hwcursor(pScrn);
467}
468
469static unsigned char
470color_to_byte(unsigned c)
471{
472 return (c >> 8) & 0xff;
473}
474
475static unsigned char *
476vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
477{
478 VBOXPtr pVBox;
479 CursorBitsPtr bitsp;
480 unsigned short w, h, x, y;
481 unsigned char *c, *p, *pm, *ps, *m;
482 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
483 CARD32 fc, bc, *cp;
484 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
485 struct vboxCursorImage *pImage;
486
487 pVBox = infoPtr->pScrn->driverPrivate;
488 bitsp = pCurs->bits;
489 w = bitsp->width;
490 h = bitsp->height;
491
492 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
493 RETERROR(scrnIndex, NULL,
494 "Error invalid cursor dimensions %dx%d\n", w, h);
495
496 if ((bitsp->xhot > w) || (bitsp->yhot > h))
497 RETERROR(scrnIndex, NULL,
498 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
499 bitsp->xhot, bitsp->yhot, w, h);
500
501 srcPitch = PixmapBytePad (bitsp->width, 1);
502 dstPitch = (w + 7) / 8;
503 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
504 sizeRgba = w * h * 4;
505 sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
506
507 p = c = calloc (1, sizeRequest);
508 if (!c)
509 RETERROR(scrnIndex, NULL,
510 "Error failed to alloc %lu bytes for cursor\n",
511 (unsigned long) sizeRequest);
512
513 pImage = (struct vboxCursorImage *)p;
514 pImage->pPixels = m = p + sizeof(*pImage);
515 cp = (CARD32 *)(m + sizeMask);
516
517 TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
518 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
519 TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
520
521 fc = color_to_byte (pCurs->foreBlue)
522 | (color_to_byte (pCurs->foreGreen) << 8)
523 | (color_to_byte (pCurs->foreRed) << 16);
524
525 bc = color_to_byte (pCurs->backBlue)
526 | (color_to_byte (pCurs->backGreen) << 8)
527 | (color_to_byte (pCurs->backRed) << 16);
528
529 /*
530 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
531 * Xorg:
532 * The mask is a bitmap indicating which parts of the cursor are
533 * transparent and which parts are drawn. The source is a bitmap
534 * indicating which parts of the non-transparent portion of the
535 * the cursor should be painted in the foreground color and which
536 * should be painted in the background color. By default, set bits
537 * indicate the opaque part of the mask bitmap and clear bits
538 * indicate the transparent part.
539 * VBox:
540 * The color data is the XOR mask. The AND mask bits determine
541 * which pixels of the color data (XOR mask) will replace (overwrite)
542 * the screen pixels (AND mask bit = 0) and which ones will be XORed
543 * with existing screen pixels (AND mask bit = 1).
544 * For example when you have the AND mask all 0, then you see the
545 * correct mouse pointer image surrounded by black square.
546 */
547 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
548 y < h;
549 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
550 {
551 for (x = 0; x < w; ++x)
552 {
553 if (pm[x / 8] & (1 << (x % 8)))
554 {
555 /* opaque, leave AND mask bit at 0 */
556 if (ps[x / 8] & (1 << (x % 8)))
557 {
558 *cp++ = fc;
559 PUT_PIXEL('X');
560 }
561 else
562 {
563 *cp++ = bc;
564 PUT_PIXEL('*');
565 }
566 }
567 else
568 {
569 /* transparent, set AND mask bit */
570 m[x / 8] |= 1 << (7 - (x % 8));
571 /* don't change the screen pixel */
572 *cp++ = 0;
573 PUT_PIXEL(' ');
574 }
575 }
576 PUT_PIXEL('\n');
577 }
578
579 pImage->cWidth = w;
580 pImage->cHeight = h;
581 pImage->cHotX = bitsp->xhot;
582 pImage->cHotY = bitsp->yhot;
583 pImage->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
584 pImage->cbLength = sizeRequest - sizeof(*pImage);
585
586#ifdef DEBUG_POINTER
587 ErrorF("shape = %p\n", p);
588 vbox_show_shape(w, h, bc, c);
589#endif
590
591 return p;
592}
593
594#ifdef ARGB_CURSOR
595static Bool
596vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
597{
598 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
599 Bool rc = TRUE;
600
601 if (!vbox_host_uses_hwcursor(pScrn))
602 rc = FALSE;
603 if ( rc
604 && ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
605 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
606 || (pScrn->bitsPerPixel <= 8)
607 )
608 )
609 rc = FALSE;
610#ifndef VBOXVIDEO_13
611 /* Evil hack - we use this as another way of poking the driver to update
612 * our list of video modes. */
613 vboxWriteHostModes(pScrn, pScrn->currentMode);
614#endif
615 return rc;
616}
617
618
619static void
620vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
621{
622 VBOXPtr pVBox;
623 VMMDevReqMousePointer *reqp;
624 CursorBitsPtr bitsp;
625 unsigned short w, h;
626 unsigned short cx, cy;
627 unsigned char *pm;
628 CARD32 *pc;
629 size_t sizeData, sizeMask;
630 CARD8 *p;
631 int scrnIndex;
632 uint32_t fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
633 | VBOX_MOUSE_POINTER_ALPHA;
634 int rc;
635
636 pVBox = pScrn->driverPrivate;
637 bitsp = pCurs->bits;
638 w = bitsp->width;
639 h = bitsp->height;
640 scrnIndex = pScrn->scrnIndex;
641
642 /* Mask must be generated for alpha cursors, that is required by VBox. */
643 /* note: (michael) the next struct must be 32bit aligned. */
644 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
645
646 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
647 RETERROR(scrnIndex, ,
648 "Error invalid cursor dimensions %dx%d\n", w, h);
649
650 if ((bitsp->xhot > w) || (bitsp->yhot > h))
651 RETERROR(scrnIndex, ,
652 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
653 bitsp->xhot, bitsp->yhot, w, h);
654
655 sizeData = w * h * 4 + sizeMask;
656 p = calloc(1, sizeData);
657 if (!p)
658 RETERROR(scrnIndex, ,
659 "Error failed to alloc %lu bytes for cursor\n",
660 (unsigned long)sizeData);
661
662 memcpy(p + sizeMask, bitsp->argb, w * h * 4);
663
664 /* Emulate the AND mask. */
665 pm = p;
666 pc = bitsp->argb;
667
668 /* Init AND mask to 1 */
669 memset(pm, 0xFF, sizeMask);
670
671 /*
672 * The additions driver must provide the AND mask for alpha cursors. The host frontend
673 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
674 * But if the host does not support ARGB, then it simply uses the AND mask and the color
675 * data to draw a normal color cursor.
676 */
677 for (cy = 0; cy < h; cy++)
678 {
679 unsigned char bitmask = 0x80;
680
681 for (cx = 0; cx < w; cx++, bitmask >>= 1)
682 {
683 if (bitmask == 0)
684 bitmask = 0x80;
685
686 if (pc[cx] >= 0xF0000000)
687 pm[cx / 8] &= ~bitmask;
688 }
689
690 /* Point to next source and dest scans */
691 pc += w;
692 pm += (w + 7) / 8;
693 }
694
695 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
696 bitsp->yhot, w, h, p, sizeData);
697 free(p);
698}
699#endif
700
701Bool
702vbox_cursor_init(ScreenPtr pScreen)
703{
704 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
705 VBOXPtr pVBox = pScrn->driverPrivate;
706 xf86CursorInfoPtr pCurs = NULL;
707 Bool rc = TRUE;
708
709 TRACE_ENTRY();
710 if (!pVBox->fHaveHGSMI)
711 return FALSE;
712 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
713 if (!pCurs) {
714 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
715 "Failed to create X Window cursor information structures for virtual mouse.\n");
716 rc = FALSE;
717 }
718 if (rc) {
719 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
720 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
721 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
722 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
723 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
724
725 pCurs->SetCursorColors = vbox_set_cursor_colors;
726 pCurs->SetCursorPosition = vbox_set_cursor_position;
727 pCurs->LoadCursorImage = vbox_load_cursor_image;
728 pCurs->HideCursor = vbox_hide_cursor;
729 pCurs->ShowCursor = vbox_show_cursor;
730 pCurs->UseHWCursor = vbox_use_hw_cursor;
731 pCurs->RealizeCursor = vbox_realize_cursor;
732
733#ifdef ARGB_CURSOR
734 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
735 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
736#endif
737
738 /* Hide the host cursor before we initialise if we wish to use a
739 * software cursor. */
740 if (pVBox->forceSWCursor)
741 vbox_vmm_hide_cursor(pScrn, pVBox);
742 rc = xf86InitCursor(pScreen, pCurs);
743 }
744 if (!rc)
745 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
746 "Failed to enable mouse pointer integration.\n");
747 if (!rc && (pCurs != NULL))
748 xf86DestroyCursorInfoRec(pCurs);
749 return rc;
750}
751
752/**
753 * Inform VBox that we will supply it with dirty rectangle information
754 * and install the dirty rectangle handler.
755 *
756 * @returns TRUE for success, FALSE for failure
757 * @param pScrn Pointer to a structure describing the X screen in use
758 */
759Bool
760vboxEnableVbva(ScrnInfoPtr pScrn)
761{
762 bool rc = TRUE;
763 int scrnIndex = pScrn->scrnIndex;
764 unsigned i;
765 VBOXPtr pVBox = pScrn->driverPrivate;
766
767 TRACE_ENTRY();
768 if (!pVBox->fHaveHGSMI)
769 return FALSE;
770 for (i = 0; i < pVBox->cScreens; ++i)
771 {
772 struct VBVABUFFER *pVBVA;
773
774 pVBVA = (struct VBVABUFFER *) ( ((uint8_t *)pVBox->base)
775 + pVBox->aoffVBVABuffer[i]);
776 if (!VBoxVBVAEnable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, pVBVA, i))
777 rc = FALSE;
778 }
779 if (!rc)
780 {
781 /* Request not accepted - disable for old hosts. */
782 xf86DrvMsg(scrnIndex, X_ERROR,
783 "Failed to enable screen update reporting for at least one virtual monitor.\n");
784 vboxDisableVbva(pScrn);
785 }
786 return rc;
787}
788
789/**
790 * Inform VBox that we will stop supplying it with dirty rectangle
791 * information. This function is intended to be called when an X
792 * virtual terminal is disabled, or the X server is terminated.
793 *
794 * @returns TRUE for success, FALSE for failure
795 * @param pScrn Pointer to a structure describing the X screen in use
796 */
797void
798vboxDisableVbva(ScrnInfoPtr pScrn)
799{
800 int rc;
801 int scrnIndex = pScrn->scrnIndex;
802 unsigned i;
803 VBOXPtr pVBox = pScrn->driverPrivate;
804
805 TRACE_ENTRY();
806 if (!pVBox->fHaveHGSMI) /* Ths function should not have been called */
807 return;
808 for (i = 0; i < pVBox->cScreens; ++i)
809 VBoxVBVADisable(&pVBox->aVbvaCtx[i], &pVBox->guestCtx, i);
810}
811
812/**
813 * Inform VBox that we are aware of advanced graphics functions
814 * (i.e. dynamic resizing, seamless).
815 *
816 * @returns TRUE for success, FALSE for failure
817 */
818Bool
819vboxEnableGraphicsCap(VBOXPtr pVBox)
820{
821 TRACE_ENTRY();
822 if (!pVBox->useDevice)
823 return FALSE;
824 return RT_SUCCESS(VbglR3SetGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0));
825}
826
827/**
828 * Inform VBox that we are no longer aware of advanced graphics functions
829 * (i.e. dynamic resizing, seamless).
830 *
831 * @returns TRUE for success, FALSE for failure
832 */
833Bool
834vboxDisableGraphicsCap(VBOXPtr pVBox)
835{
836 TRACE_ENTRY();
837 if (!pVBox->useDevice)
838 return FALSE;
839 return RT_SUCCESS(VbglR3SetGuestCaps(0, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
840}
841
842/**
843 * Query the last display change request.
844 *
845 * @returns boolean success indicator.
846 * @param pScrn Pointer to the X screen info structure.
847 * @param pcx Where to store the horizontal pixel resolution (0 = do not change).
848 * @param pcy Where to store the vertical pixel resolution (0 = do not change).
849 * @param pcBits Where to store the bits per pixel (0 = do not change).
850 * @param iDisplay Where to store the display number the request was for - 0 for the
851 * primary display, 1 for the first secondary, etc.
852 */
853Bool
854vboxGetDisplayChangeRequest(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy,
855 uint32_t *pcBits, uint32_t *piDisplay)
856{
857 VBOXPtr pVBox = pScrn->driverPrivate;
858 TRACE_ENTRY();
859 if (!pVBox->useDevice)
860 return FALSE;
861 int rc = VbglR3GetDisplayChangeRequest(pcx, pcy, pcBits, piDisplay, true);
862 if (RT_SUCCESS(rc))
863 return TRUE;
864 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to obtain the last resolution requested by the guest, rc=%d.\n", rc);
865 return FALSE;
866}
867
868
869/**
870 * Query the host as to whether it likes a specific video mode.
871 *
872 * @returns the result of the query
873 * @param cx the width of the mode being queried
874 * @param cy the height of the mode being queried
875 * @param cBits the bpp of the mode being queried
876 */
877Bool
878vboxHostLikesVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
879{
880 VBOXPtr pVBox = pScrn->driverPrivate;
881 TRACE_ENTRY();
882 if (!pVBox->useDevice)
883 return TRUE; /* If we can't ask the host then we like everything. */
884 return VbglR3HostLikesVideoMode(cx, cy, cBits);
885}
886
887/**
888 * Check if any seamless mode is enabled.
889 * Seamless is only relevant for the newer Xorg modules.
890 *
891 * @returns the result of the query
892 * (true = seamless enabled, false = seamless not enabled)
893 * @param pScrn Screen info pointer.
894 */
895Bool
896vboxGuestIsSeamless(ScrnInfoPtr pScrn)
897{
898 VMMDevSeamlessMode mode;
899 VBOXPtr pVBox = pScrn->driverPrivate;
900 TRACE_ENTRY();
901 if (!pVBox->useDevice)
902 return FALSE;
903 if (RT_FAILURE(VbglR3SeamlessGetLastEvent(&mode)))
904 return FALSE;
905 return (mode != VMMDev_Seamless_Disabled);
906}
907
908/**
909 * Save video mode parameters to the registry.
910 *
911 * @returns iprt status value
912 * @param pszName the name to save the mode parameters under
913 * @param cx mode width
914 * @param cy mode height
915 * @param cBits bits per pixel for the mode
916 */
917Bool
918vboxSaveVideoMode(ScrnInfoPtr pScrn, uint32_t cx, uint32_t cy, uint32_t cBits)
919{
920 VBOXPtr pVBox = pScrn->driverPrivate;
921 TRACE_ENTRY();
922 if (!pVBox->useDevice)
923 return FALSE;
924 return RT_SUCCESS(VbglR3SaveVideoMode("SavedMode", cx, cy, cBits));
925}
926
927/**
928 * Retrieve video mode parameters from the registry.
929 *
930 * @returns iprt status value
931 * @param pszName the name under which the mode parameters are saved
932 * @param pcx where to store the mode width
933 * @param pcy where to store the mode height
934 * @param pcBits where to store the bits per pixel for the mode
935 */
936Bool
937vboxRetrieveVideoMode(ScrnInfoPtr pScrn, uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits)
938{
939 VBOXPtr pVBox = pScrn->driverPrivate;
940 TRACE_ENTRY();
941 if (!pVBox->useDevice)
942 return FALSE;
943 int rc = VbglR3RetrieveVideoMode("SavedMode", pcx, pcy, pcBits);
944 if (RT_SUCCESS(rc))
945 TRACE_LOG("Retrieved a video mode of %dx%dx%d\n", *pcx, *pcy, *pcBits);
946 else
947 TRACE_LOG("Failed to retrieve video mode, error %d\n", rc);
948 return (RT_SUCCESS(rc));
949}
950
951/**
952 * Fills a display mode M with a built-in mode of name pszName and dimensions
953 * cx and cy.
954 */
955static void vboxFillDisplayMode(ScrnInfoPtr pScrn, DisplayModePtr m,
956 const char *pszName, unsigned cx, unsigned cy)
957{
958 VBOXPtr pVBox = pScrn->driverPrivate;
959 TRACE_LOG("pszName=%s, cx=%u, cy=%u\n", pszName, cx, cy);
960 m->status = MODE_OK;
961 m->type = M_T_BUILTIN;
962 /* Older versions of VBox only support screen widths which are a multiple
963 * of 8 */
964 if (pVBox->fAnyX)
965 m->HDisplay = cx;
966 else
967 m->HDisplay = cx & ~7;
968 m->HSyncStart = m->HDisplay + 2;
969 m->HSyncEnd = m->HDisplay + 4;
970 m->HTotal = m->HDisplay + 6;
971 m->VDisplay = cy;
972 m->VSyncStart = m->VDisplay + 2;
973 m->VSyncEnd = m->VDisplay + 4;
974 m->VTotal = m->VDisplay + 6;
975 m->Clock = m->HTotal * m->VTotal * 60 / 1000; /* kHz */
976 if (pszName)
977 {
978 if (m->name)
979 free(m->name);
980 m->name = xnfstrdup(pszName);
981 }
982}
983
984/** vboxvideo's list of standard video modes */
985struct
986{
987 /** mode width */
988 uint32_t cx;
989 /** mode height */
990 uint32_t cy;
991} vboxStandardModes[] =
992{
993 { 1600, 1200 },
994 { 1440, 1050 },
995 { 1280, 960 },
996 { 1024, 768 },
997 { 800, 600 },
998 { 640, 480 },
999 { 0, 0 }
1000};
1001enum
1002{
1003 vboxNumStdModes = sizeof(vboxStandardModes) / sizeof(vboxStandardModes[0])
1004};
1005
1006/**
1007 * Returns a standard mode which the host likes. Can be called multiple
1008 * times with the index returned by the previous call to get a list of modes.
1009 * @returns the index of the mode in the list, or 0 if no more modes are
1010 * available
1011 * @param pScrn the screen information structure
1012 * @param pScrn->bitsPerPixel
1013 * if this is non-null, only modes with this BPP will be
1014 * returned
1015 * @param cIndex the index of the last mode queried, or 0 to query the
1016 * first mode available. Note: the first index is 1
1017 * @param pcx where to store the mode's width
1018 * @param pcy where to store the mode's height
1019 * @param pcBits where to store the mode's BPP
1020 */
1021static unsigned vboxNextStandardMode(ScrnInfoPtr pScrn, unsigned cIndex,
1022 uint32_t *pcx, uint32_t *pcy,
1023 uint32_t *pcBits)
1024{
1025 XF86ASSERT(cIndex < vboxNumStdModes,
1026 ("cIndex = %d, vboxNumStdModes = %d\n", cIndex,
1027 vboxNumStdModes));
1028 for (unsigned i = cIndex; i < vboxNumStdModes - 1; ++i)
1029 {
1030 uint32_t cBits = pScrn->bitsPerPixel;
1031 uint32_t cx = vboxStandardModes[i].cx;
1032 uint32_t cy = vboxStandardModes[i].cy;
1033
1034 if (cBits != 0 && !vboxHostLikesVideoMode(pScrn, cx, cy, cBits))
1035 continue;
1036 if (vboxHostLikesVideoMode(pScrn, cx, cy, 32))
1037 cBits = 32;
1038 else if (vboxHostLikesVideoMode(pScrn, cx, cy, 16))
1039 cBits = 16;
1040 else
1041 continue;
1042 if (pcx)
1043 *pcx = cx;
1044 if (pcy)
1045 *pcy = cy;
1046 if (pcBits)
1047 *pcBits = cBits;
1048 return i + 1;
1049 }
1050 return 0;
1051}
1052
1053/**
1054 * Returns the preferred video mode. The current order of preference is
1055 * (from highest to least preferred):
1056 * - The mode corresponding to the last size hint from the host
1057 * - The video mode saved from the last session
1058 * - The largest standard mode which the host likes, falling back to
1059 * 640x480x32 as a worst case
1060 * - If the host can't be contacted at all, we return 1024x768x32
1061 *
1062 * The return type is void as we guarantee we will return some mode.
1063 */
1064void vboxGetPreferredMode(ScrnInfoPtr pScrn, uint32_t *pcx,
1065 uint32_t *pcy, uint32_t *pcBits)
1066{
1067 /* Query the host for the preferred resolution and colour depth */
1068 uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 32;
1069 VBOXPtr pVBox = pScrn->driverPrivate;
1070
1071 TRACE_ENTRY();
1072 if (pVBox->useDevice)
1073 {
1074 bool found = vboxGetDisplayChangeRequest(pScrn, &cx, &cy, &cBits, &iDisplay);
1075 if ((cx == 0) || (cy == 0))
1076 found = false;
1077 if (!found)
1078 found = vboxRetrieveVideoMode(pScrn, &cx, &cy, &cBits);
1079 if ((cx == 0) || (cy == 0))
1080 found = false;
1081 if (!found)
1082 found = (vboxNextStandardMode(pScrn, 0, &cx, &cy, &cBits) != 0);
1083 if (!found)
1084 {
1085 /* Last resort */
1086 cx = 640;
1087 cy = 480;
1088 cBits = 32;
1089 }
1090 }
1091 else
1092 {
1093 cx = 1024;
1094 cy = 768;
1095 }
1096 if (pcx)
1097 *pcx = cx;
1098 if (pcy)
1099 *pcy = cy;
1100 if (pcx)
1101 *pcBits = cBits;
1102}
1103
1104/* Move a screen mode found to the end of the list, so that RandR will give
1105 * it the highest priority when a mode switch is requested. Returns the mode
1106 * that was previously before the mode in the list in order to allow the
1107 * caller to continue walking the list. */
1108static DisplayModePtr vboxMoveModeToFront(ScrnInfoPtr pScrn,
1109 DisplayModePtr pMode)
1110{
1111 DisplayModePtr pPrev = pMode->prev;
1112 if (pMode != pScrn->modes)
1113 {
1114 pMode->prev->next = pMode->next;
1115 pMode->next->prev = pMode->prev;
1116 pMode->next = pScrn->modes;
1117 pMode->prev = pScrn->modes->prev;
1118 pMode->next->prev = pMode;
1119 pMode->prev->next = pMode;
1120 pScrn->modes = pMode;
1121 }
1122 return pPrev;
1123}
1124
1125/**
1126 * Rewrites the first dynamic mode found which is not the current screen mode
1127 * to contain the host's currently preferred screen size, then moves that
1128 * mode to the front of the screen information structure's mode list.
1129 * Additionally, if the current mode is not dynamic, the second dynamic mode
1130 * will be set to match the current mode and also added to the front. This
1131 * ensures that the user can always reset the current size to kick the driver
1132 * to update its mode list.
1133 */
1134void vboxWriteHostModes(ScrnInfoPtr pScrn, DisplayModePtr pCurrent)
1135{
1136 uint32_t cx = 0, cy = 0, iDisplay = 0, cBits = 0;
1137 DisplayModePtr pMode;
1138 bool found = false;
1139
1140 TRACE_ENTRY();
1141 vboxGetPreferredMode(pScrn, &cx, &cy, &cBits);
1142#ifdef DEBUG
1143 /* Count the number of modes for sanity */
1144 unsigned cModes = 1, cMode = 0;
1145 DisplayModePtr pCount;
1146 for (pCount = pScrn->modes; ; pCount = pCount->next, ++cModes)
1147 if (pCount->next == pScrn->modes)
1148 break;
1149#endif
1150 for (pMode = pScrn->modes; ; pMode = pMode->next)
1151 {
1152#ifdef DEBUG
1153 XF86ASSERT (cMode++ < cModes, (NULL));
1154#endif
1155 if ( pMode != pCurrent
1156 && !strcmp(pMode->name, "VBoxDynamicMode"))
1157 {
1158 if (!found)
1159 vboxFillDisplayMode(pScrn, pMode, NULL, cx, cy);
1160 else if (pCurrent)
1161 vboxFillDisplayMode(pScrn, pMode, NULL, pCurrent->HDisplay,
1162 pCurrent->VDisplay);
1163 found = true;
1164 pMode = vboxMoveModeToFront(pScrn, pMode);
1165 }
1166 if (pMode->next == pScrn->modes)
1167 break;
1168 }
1169 XF86ASSERT (found,
1170 ("vboxvideo: no free dynamic mode found. Exiting.\n"));
1171 XF86ASSERT ( (pScrn->modes->HDisplay == (long) cx)
1172 || ( (pScrn->modes->HDisplay == pCurrent->HDisplay)
1173 && (pScrn->modes->next->HDisplay == (long) cx)),
1174 ("pScrn->modes->HDisplay=%u, pScrn->modes->next->HDisplay=%u\n",
1175 pScrn->modes->HDisplay, pScrn->modes->next->HDisplay));
1176 XF86ASSERT ( (pScrn->modes->VDisplay == (long) cy)
1177 || ( (pScrn->modes->VDisplay == pCurrent->VDisplay)
1178 && (pScrn->modes->next->VDisplay == (long) cy)),
1179 ("pScrn->modes->VDisplay=%u, pScrn->modes->next->VDisplay=%u\n",
1180 pScrn->modes->VDisplay, pScrn->modes->next->VDisplay));
1181}
1182
1183/**
1184 * Allocates an empty display mode and links it into the doubly linked list of
1185 * modes pointed to by pScrn->modes. Returns a pointer to the newly allocated
1186 * memory.
1187 */
1188static DisplayModePtr vboxAddEmptyScreenMode(ScrnInfoPtr pScrn)
1189{
1190 DisplayModePtr pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
1191
1192 TRACE_ENTRY();
1193 if (!pScrn->modes)
1194 {
1195 pScrn->modes = pMode;
1196 pMode->next = pMode;
1197 pMode->prev = pMode;
1198 }
1199 else
1200 {
1201 pMode->next = pScrn->modes;
1202 pMode->prev = pScrn->modes->prev;
1203 pMode->next->prev = pMode;
1204 pMode->prev->next = pMode;
1205 }
1206 return pMode;
1207}
1208
1209/**
1210 * Create display mode entries in the screen information structure for each
1211 * of the initial graphics modes that we wish to support. This includes:
1212 * - An initial mode, of the size requested by the caller
1213 * - Two dynamic modes, one of which will be updated to match the last size
1214 * hint from the host on each mode switch, but initially also of the
1215 * requested size
1216 * - Several standard modes, if possible ones that the host likes
1217 * - Any modes that the user requested in xorg.conf/XFree86Config
1218 */
1219void vboxAddModes(ScrnInfoPtr pScrn, uint32_t cxInit, uint32_t cyInit)
1220{
1221 unsigned cx = 0, cy = 0, cIndex = 0;
1222 /* For reasons related to the way RandR 1.1 is implemented, we need to
1223 * make sure that the initial mode (more precisely, a mode equal to the
1224 * initial virtual resolution) is always present in the mode list. RandR
1225 * has the assumption build in that there will either be a mode of that
1226 * size present at all times, or that the first mode in the list will
1227 * always be smaller than the initial virtual resolution. Since our
1228 * approach to dynamic resizing isn't quite the way RandR was intended to
1229 * be, and breaks the second assumption, we guarantee the first. */
1230 DisplayModePtr pMode = vboxAddEmptyScreenMode(pScrn);
1231 vboxFillDisplayMode(pScrn, pMode, "VBoxInitialMode", cxInit, cyInit);
1232 /* Create our two dynamic modes. */
1233 pMode = vboxAddEmptyScreenMode(pScrn);
1234 vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
1235 pMode = vboxAddEmptyScreenMode(pScrn);
1236 vboxFillDisplayMode(pScrn, pMode, "VBoxDynamicMode", cxInit, cyInit);
1237 /* Add standard modes supported by the host */
1238 for ( ; ; )
1239 {
1240 char szName[256];
1241 cIndex = vboxNextStandardMode(pScrn, cIndex, &cx, &cy, NULL);
1242 if (cIndex == 0)
1243 break;
1244 sprintf(szName, "VBox-%ux%u", cx, cy);
1245 pMode = vboxAddEmptyScreenMode(pScrn);
1246 vboxFillDisplayMode(pScrn, pMode, szName, cx, cy);
1247 }
1248 /* And finally any modes specified by the user. We assume here that
1249 * the mode names reflect the mode sizes. */
1250 for (unsigned i = 0; pScrn->display->modes != NULL
1251 && pScrn->display->modes[i] != NULL; i++)
1252 {
1253 if (sscanf(pScrn->display->modes[i], "%ux%u", &cx, &cy) == 2)
1254 {
1255 pMode = vboxAddEmptyScreenMode(pScrn);
1256 vboxFillDisplayMode(pScrn, pMode, pScrn->display->modes[i], cx, cy);
1257 }
1258 }
1259}
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