VirtualBox

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

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

Additions/x11/vboxvideo: small fix

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

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