VirtualBox

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

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

Additions/x11/vboxvideo: do not force the origin of the first monitor to zero and only set valid video modes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 40.1 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 TRACE_ENTRY();
128 /* We may want to force the use of a software cursor. Currently this is
129 * needed if the guest uses a large virtual resolution, as in this case
130 * the host and guest tend to disagree about the pointer location. */
131 if (pVBox->forceSWCursor)
132 rc = FALSE;
133 /* Query information about mouse integration from the host. */
134 if (rc) {
135 int vrc = VbglR3GetMouseStatus(&fFeatures, NULL, NULL);
136 if (RT_FAILURE(vrc)) {
137 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
138 "Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", vrc);
139 rc = FALSE;
140 }
141 }
142 /* If we got the information from the host then make sure the host wants
143 * to draw the pointer. */
144 if (rc)
145 {
146 if ( (fFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
147#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5
148 /* As of this version (server 1.6) all major Linux releases
149 * are known to handle USB tablets correctly. */
150 || (fFeatures & VMMDEV_MOUSE_HOST_HAS_ABS_DEV)
151#endif
152 )
153 /* Assume this will never be unloaded as long as the X session is
154 * running. */
155 pVBox->guestCanAbsolute = TRUE;
156 if ( (fFeatures & VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER)
157 || !pVBox->guestCanAbsolute
158 || !(fFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
159 )
160 rc = FALSE;
161 }
162 TRACE_LOG("rc=%s\n", BOOL_STR(rc));
163 return rc;
164}
165
166/**************************************************************************
167* Main functions *
168**************************************************************************/
169
170void
171vbox_close(ScrnInfoPtr pScrn, VBOXPtr pVBox)
172{
173 TRACE_ENTRY();
174
175 xf86DestroyCursorInfoRec(pVBox->pCurs);
176 pVBox->pCurs = NULL;
177 TRACE_EXIT();
178}
179
180/**
181 * Callback function called by the X server to tell us about dirty
182 * rectangles in the video buffer.
183 *
184 * @param pScreen pointer to the information structure for the current
185 * screen
186 * @param iRects Number of dirty rectangles to update
187 * @param aRects Array of structures containing the coordinates of the
188 * rectangles
189 */
190static void
191vboxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects)
192{
193 VBVACMDHDR cmdHdr;
194 VBOXPtr pVBox;
195 int i;
196 unsigned j;
197
198 pVBox = pScrn->driverPrivate;
199 if (pVBox->fHaveHGSMI == FALSE)
200 return;
201
202 for (i = 0; i < iRects; ++i)
203 for (j = 0; j < pVBox->cScreens; ++j)
204 {
205 /* Just continue quietly if VBVA is not currently active. */
206 struct VBVABUFFER *pVBVA = pVBox->aVbvaCtx[j].pVBVA;
207 if ( !pVBVA
208 || !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
209 continue;
210 if ( aRects[i].x1 > pVBox->aScreenLocation[j].x
211 + pVBox->aScreenLocation[j].cx
212 || aRects[i].y1 > pVBox->aScreenLocation[j].y
213 + pVBox->aScreenLocation[j].cy
214 || aRects[i].x2 < pVBox->aScreenLocation[j].x
215 || aRects[i].y2 < pVBox->aScreenLocation[j].y)
216 continue;
217 cmdHdr.x = (int16_t)aRects[i].x1;
218 cmdHdr.y = (int16_t)aRects[i].y1;
219 cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1);
220 cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1);
221
222#if 0
223 TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n",
224 j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h);
225#endif
226
227 VBoxVBVABufferBeginUpdate(&pVBox->aVbvaCtx[j], &pVBox->guestCtx);
228 VBoxVBVAWrite(&pVBox->aVbvaCtx[j], &pVBox->guestCtx, &cmdHdr,
229 sizeof(cmdHdr));
230 VBoxVBVABufferEndUpdate(&pVBox->aVbvaCtx[j]);
231 }
232}
233
234/** Callback to fill in the view structures */
235static int
236vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews)
237{
238 VBOXPtr pVBox = (VBOXPtr)pvVBox;
239 unsigned i;
240 for (i = 0; i < cViews; ++i)
241 {
242 pViews[i].u32ViewIndex = i;
243 pViews[i].u32ViewOffset = 0;
244 pViews[i].u32ViewSize = pVBox->cbFramebuffer;
245 pViews[i].u32MaxScreenSize = pVBox->cbFramebuffer;
246 }
247 return VINF_SUCCESS;
248}
249
250/**
251 * Initialise VirtualBox's accelerated video extensions.
252 *
253 * @returns TRUE on success, FALSE on failure
254 */
255static Bool
256vboxInitVbva(int scrnIndex, ScreenPtr pScreen, VBOXPtr pVBox)
257{
258 ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
259 int rc = VINF_SUCCESS;
260 unsigned i;
261 uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory,
262 cScreens;
263 void *pvGuestHeapMemory;
264
265 pVBox->cScreens = 1;
266 if (!VBoxHGSMIIsSupported())
267 {
268 xf86DrvMsg(scrnIndex, X_ERROR, "The graphics device does not seem to support HGSMI. Disableing video acceleration.\n");
269 return FALSE;
270 }
271 VBoxHGSMIGetBaseMappingInfo(pScrn->videoRam * 1024, &offVRAMBaseMapping,
272 NULL, &offGuestHeapMemory, &cbGuestHeapMemory,
273 NULL);
274 pvGuestHeapMemory = ((uint8_t *)pVBox->base) + offVRAMBaseMapping
275 + offGuestHeapMemory;
276 rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory,
277 cbGuestHeapMemory,
278 offVRAMBaseMapping + offGuestHeapMemory);
279 if (RT_FAILURE(rc))
280 {
281 xf86DrvMsg(scrnIndex, X_ERROR, "Failed to set up the guest-to-host communication context, rc=%d\n", rc);
282 return FALSE;
283 }
284 pVBox->cbFramebuffer = offVRAMBaseMapping;
285 pVBox->cScreens = VBoxHGSMIGetMonitorCount(&pVBox->guestCtx);
286 xf86DrvMsg(scrnIndex, X_INFO, "Requested monitor count: %u\n",
287 pVBox->cScreens);
288 rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens,
289 vboxFillViewInfo, (void *)pVBox);
290 for (i = 0; i < pVBox->cScreens; ++i)
291 {
292 pVBox->cbFramebuffer -= VBVA_MIN_BUFFER_SIZE;
293 pVBox->aoffVBVABuffer[i] = pVBox->cbFramebuffer;
294 VBoxVBVASetupBufferContext(&pVBox->aVbvaCtx[i],
295 pVBox->aoffVBVABuffer[i],
296 VBVA_MIN_BUFFER_SIZE);
297 }
298
299 /* Set up the dirty rectangle handler. Since this seems to be a
300 delicate operation, and removing it doubly so, this will
301 remain in place whether it is needed or not, and will simply
302 return if VBVA is not active. I assume that it will be active
303 most of the time. */
304 if (ShadowFBInit2(pScreen, NULL, vboxHandleDirtyRect) != TRUE)
305 {
306 xf86DrvMsg(scrnIndex, X_ERROR,
307 "Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
308 return FALSE;
309 }
310 return TRUE;
311}
312
313Bool
314vbox_init(int scrnIndex, VBOXPtr pVBox)
315{
316 Bool rc = TRUE;
317 int vrc;
318 uint32_t fMouseFeatures = 0;
319
320 TRACE_ENTRY();
321 vrc = VbglR3Init();
322 if (RT_FAILURE(vrc))
323 {
324 xf86DrvMsg(scrnIndex, X_ERROR,
325 "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",
326 vrc);
327 rc = FALSE;
328 }
329 pVBox->useDevice = rc;
330 /* We can't switch to a software cursor at will without help from
331 * VBoxClient. So tell that to the host and wait for VBoxClient to
332 * change this. */
333 vrc = VbglR3GetMouseStatus(&fMouseFeatures, NULL, NULL);
334 if (RT_SUCCESS(vrc))
335 VbglR3SetMouseStatus( fMouseFeatures
336 | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
337 return rc;
338}
339
340Bool
341vbox_open(ScrnInfoPtr pScrn, ScreenPtr pScreen, VBOXPtr pVBox)
342{
343 TRACE_ENTRY();
344
345 if (!pVBox->useDevice)
346 return FALSE;
347 pVBox->fHaveHGSMI = vboxInitVbva(pScrn->scrnIndex, pScreen, pVBox);
348 return TRUE;
349}
350
351Bool
352vbox_device_available(VBOXPtr pVBox)
353{
354 return pVBox->useDevice;
355}
356
357static void
358vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
359{
360 int rc;
361
362 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
363 if (RT_FAILURE(rc))
364 {
365 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer, VBox error %d.\n", rc);
366 /* Play safe, and disable the hardware cursor until the next mode
367 * switch, since obviously something happened that we didn't
368 * anticipate. */
369 pVBox->forceSWCursor = TRUE;
370 }
371}
372
373static void
374vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
375{
376 int rc;
377
378 if (!vbox_host_uses_hwcursor(pScrn))
379 return;
380 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
381 0, 0, 0, 0, NULL, 0);
382 if (RT_FAILURE(rc)) {
383 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not unhide the virtual mouse pointer.\n");
384 /* Play safe, and disable the hardware cursor until the next mode
385 * switch, since obviously something happened that we didn't
386 * anticipate. */
387 pVBox->forceSWCursor = TRUE;
388 }
389}
390
391static void
392vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
393 unsigned char *pvImage)
394{
395 int rc;
396 struct vboxCursorImage *pImage;
397 pImage = (struct vboxCursorImage *)pvImage;
398
399#ifdef DEBUG_POINTER
400 vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
401#endif
402
403 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
404 pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
405 pImage->pPixels, pImage->cbLength);
406 if (RT_FAILURE(rc)) {
407 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the virtual mouse pointer image.\n");
408 /* Play safe, and disable the hardware cursor until the next mode
409 * switch, since obviously something happened that we didn't
410 * anticipate. */
411 pVBox->forceSWCursor = TRUE;
412 }
413}
414
415static void
416vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
417{
418 NOREF(pScrn);
419 NOREF(bg);
420 NOREF(fg);
421 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
422}
423
424
425static void
426vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
427{
428 /* Nothing to do here, as we are telling the guest where the mouse is,
429 * not vice versa. */
430 NOREF(pScrn);
431 NOREF(x);
432 NOREF(y);
433}
434
435static void
436vbox_hide_cursor(ScrnInfoPtr pScrn)
437{
438 VBOXPtr pVBox = pScrn->driverPrivate;
439
440 vbox_vmm_hide_cursor(pScrn, pVBox);
441}
442
443static void
444vbox_show_cursor(ScrnInfoPtr pScrn)
445{
446 VBOXPtr pVBox = pScrn->driverPrivate;
447
448 vbox_vmm_show_cursor(pScrn, pVBox);
449}
450
451static void
452vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
453{
454 VBOXPtr pVBox = pScrn->driverPrivate;
455
456 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
457}
458
459static Bool
460vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
461{
462 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
463 return vbox_host_uses_hwcursor(pScrn);
464}
465
466static unsigned char
467color_to_byte(unsigned c)
468{
469 return (c >> 8) & 0xff;
470}
471
472static unsigned char *
473vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
474{
475 VBOXPtr pVBox;
476 CursorBitsPtr bitsp;
477 unsigned short w, h, x, y;
478 unsigned char *c, *p, *pm, *ps, *m;
479 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
480 CARD32 fc, bc, *cp;
481 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
482 struct vboxCursorImage *pImage;
483
484 pVBox = infoPtr->pScrn->driverPrivate;
485 bitsp = pCurs->bits;
486 w = bitsp->width;
487 h = bitsp->height;
488
489 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
490 RETERROR(scrnIndex, NULL,
491 "Error invalid cursor dimensions %dx%d\n", w, h);
492
493 if ((bitsp->xhot > w) || (bitsp->yhot > h))
494 RETERROR(scrnIndex, NULL,
495 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
496 bitsp->xhot, bitsp->yhot, w, h);
497
498 srcPitch = PixmapBytePad (bitsp->width, 1);
499 dstPitch = (w + 7) / 8;
500 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
501 sizeRgba = w * h * 4;
502 sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
503
504 p = c = calloc (1, sizeRequest);
505 if (!c)
506 RETERROR(scrnIndex, NULL,
507 "Error failed to alloc %lu bytes for cursor\n",
508 (unsigned long) sizeRequest);
509
510 pImage = (struct vboxCursorImage *)p;
511 pImage->pPixels = m = p + sizeof(*pImage);
512 cp = (CARD32 *)(m + sizeMask);
513
514 TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
515 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
516 TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
517
518 fc = color_to_byte (pCurs->foreBlue)
519 | (color_to_byte (pCurs->foreGreen) << 8)
520 | (color_to_byte (pCurs->foreRed) << 16);
521
522 bc = color_to_byte (pCurs->backBlue)
523 | (color_to_byte (pCurs->backGreen) << 8)
524 | (color_to_byte (pCurs->backRed) << 16);
525
526 /*
527 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
528 * Xorg:
529 * The mask is a bitmap indicating which parts of the cursor are
530 * transparent and which parts are drawn. The source is a bitmap
531 * indicating which parts of the non-transparent portion of the
532 * the cursor should be painted in the foreground color and which
533 * should be painted in the background color. By default, set bits
534 * indicate the opaque part of the mask bitmap and clear bits
535 * indicate the transparent part.
536 * VBox:
537 * The color data is the XOR mask. The AND mask bits determine
538 * which pixels of the color data (XOR mask) will replace (overwrite)
539 * the screen pixels (AND mask bit = 0) and which ones will be XORed
540 * with existing screen pixels (AND mask bit = 1).
541 * For example when you have the AND mask all 0, then you see the
542 * correct mouse pointer image surrounded by black square.
543 */
544 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
545 y < h;
546 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
547 {
548 for (x = 0; x < w; ++x)
549 {
550 if (pm[x / 8] & (1 << (x % 8)))
551 {
552 /* opaque, leave AND mask bit at 0 */
553 if (ps[x / 8] & (1 << (x % 8)))
554 {
555 *cp++ = fc;
556 PUT_PIXEL('X');
557 }
558 else
559 {
560 *cp++ = bc;
561 PUT_PIXEL('*');
562 }
563 }
564 else
565 {
566 /* transparent, set AND mask bit */
567 m[x / 8] |= 1 << (7 - (x % 8));
568 /* don't change the screen pixel */
569 *cp++ = 0;
570 PUT_PIXEL(' ');
571 }
572 }
573 PUT_PIXEL('\n');
574 }
575
576 pImage->cWidth = w;
577 pImage->cHeight = h;
578 pImage->cHotX = bitsp->xhot;
579 pImage->cHotY = bitsp->yhot;
580 pImage->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
581 pImage->cbLength = sizeRequest - sizeof(*pImage);
582
583#ifdef DEBUG_POINTER
584 ErrorF("shape = %p\n", p);
585 vbox_show_shape(w, h, bc, c);
586#endif
587
588 return p;
589}
590
591#ifdef ARGB_CURSOR
592static Bool
593vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
594{
595 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
596 Bool rc = TRUE;
597
598 if (!vbox_host_uses_hwcursor(pScrn))
599 rc = FALSE;
600 if ( rc
601 && ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
602 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
603 || (pScrn->bitsPerPixel <= 8)
604 )
605 )
606 rc = FALSE;
607#ifndef VBOXVIDEO_13
608 /* Evil hack - we use this as another way of poking the driver to update
609 * our list of video modes. */
610 vboxWriteHostModes(pScrn, pScrn->currentMode);
611#endif
612 TRACE_LOG("rc=%s\n", BOOL_STR(rc));
613 return rc;
614}
615
616
617static void
618vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
619{
620 VBOXPtr pVBox;
621 VMMDevReqMousePointer *reqp;
622 CursorBitsPtr bitsp;
623 unsigned short w, h;
624 unsigned short cx, cy;
625 unsigned char *pm;
626 CARD32 *pc;
627 size_t sizeData, sizeMask;
628 CARD8 *p;
629 int scrnIndex;
630 uint32_t fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
631 | VBOX_MOUSE_POINTER_ALPHA;
632 int rc;
633
634 TRACE_ENTRY();
635 pVBox = pScrn->driverPrivate;
636 bitsp = pCurs->bits;
637 w = bitsp->width;
638 h = bitsp->height;
639 scrnIndex = pScrn->scrnIndex;
640
641 /* Mask must be generated for alpha cursors, that is required by VBox. */
642 /* note: (michael) the next struct must be 32bit aligned. */
643 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
644
645 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
646 RETERROR(scrnIndex, ,
647 "Error invalid cursor dimensions %dx%d\n", w, h);
648
649 if ((bitsp->xhot > w) || (bitsp->yhot > h))
650 RETERROR(scrnIndex, ,
651 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
652 bitsp->xhot, bitsp->yhot, w, h);
653
654 sizeData = w * h * 4 + sizeMask;
655 p = calloc(1, sizeData);
656 if (!p)
657 RETERROR(scrnIndex, ,
658 "Error failed to alloc %lu bytes for cursor\n",
659 (unsigned long)sizeData);
660
661 memcpy(p + sizeMask, bitsp->argb, w * h * 4);
662
663 /* Emulate the AND mask. */
664 pm = p;
665 pc = bitsp->argb;
666
667 /* Init AND mask to 1 */
668 memset(pm, 0xFF, sizeMask);
669
670 /*
671 * The additions driver must provide the AND mask for alpha cursors. The host frontend
672 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
673 * But if the host does not support ARGB, then it simply uses the AND mask and the color
674 * data to draw a normal color cursor.
675 */
676 for (cy = 0; cy < h; cy++)
677 {
678 unsigned char bitmask = 0x80;
679
680 for (cx = 0; cx < w; cx++, bitmask >>= 1)
681 {
682 if (bitmask == 0)
683 bitmask = 0x80;
684
685 if (pc[cx] >= 0xF0000000)
686 pm[cx / 8] &= ~bitmask;
687 }
688
689 /* Point to next source and dest scans */
690 pc += w;
691 pm += (w + 7) / 8;
692 }
693
694 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
695 bitsp->yhot, w, h, p, sizeData);
696 TRACE_LOG(": leaving, returning %d\n", rc);
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