VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxvideo/pointer.c@ 55393

Last change on this file since 55393 was 55391, checked in by vboxsync, 9 years ago

Additions/x11/vboxvideo: cursor function naming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.9 KB
Line 
1/** @file
2 * VirtualBox X11 Additions graphics driver utility functions
3 */
4
5/*
6 * Copyright (C) 2006-2012 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/VBoxGuestLib.h>
18
19#ifndef PCIACCESS
20# include <xf86Pci.h>
21# include <Pci.h>
22#endif
23
24#include "xf86.h"
25#define NEED_XF86_TYPES
26#include <iprt/string.h>
27#include "compiler.h"
28#include "cursorstr.h"
29#include "servermd.h"
30
31#include "vboxvideo.h"
32
33#ifdef XORG_7X
34# include <stdlib.h>
35#endif
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* Main functions *
114**************************************************************************/
115
116void vbvxCursorTerm(VBOXPtr pVBox)
117{
118 TRACE_ENTRY();
119
120 xf86DestroyCursorInfoRec(pVBox->pCurs);
121 pVBox->pCurs = NULL;
122 TRACE_EXIT();
123}
124
125static void
126vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
127{
128 int rc;
129
130 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
131 VBVXASSERT(rc == VINF_SUCCESS, ("Could not hide the virtual mouse pointer, VBox error %d.\n", rc));
132}
133
134static void
135vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
136{
137 int rc;
138
139 if (!pVBox->fUseHardwareCursor)
140 return;
141 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
142 0, 0, 0, 0, NULL, 0);
143 VBVXASSERT(rc == VINF_SUCCESS, ("Could not unhide the virtual mouse pointer.\n"));
144}
145
146static void
147vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
148 unsigned char *pvImage)
149{
150 int rc;
151 struct vboxCursorImage *pImage;
152 pImage = (struct vboxCursorImage *)pvImage;
153
154#ifdef DEBUG_POINTER
155 vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
156#endif
157
158 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
159 pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
160 pImage->pPixels, pImage->cbLength);
161 VBVXASSERT(rc == VINF_SUCCESS, ("Unable to set the virtual mouse pointer image.\n"));
162}
163
164static void
165vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
166{
167 NOREF(pScrn);
168 NOREF(bg);
169 NOREF(fg);
170 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
171}
172
173
174static void
175vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
176{
177 VBOXPtr pVBox = pScrn->driverPrivate;
178
179 /* This currently does nothing. */
180 VBoxHGSMICursorPosition(&pVBox->guestCtx, true, x, y, NULL, NULL);
181}
182
183static void
184vbox_hide_cursor(ScrnInfoPtr pScrn)
185{
186 VBOXPtr pVBox = pScrn->driverPrivate;
187
188 vbox_vmm_hide_cursor(pScrn, pVBox);
189}
190
191static void
192vbox_show_cursor(ScrnInfoPtr pScrn)
193{
194 VBOXPtr pVBox = pScrn->driverPrivate;
195
196 vbox_vmm_show_cursor(pScrn, pVBox);
197}
198
199static void
200vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
201{
202 VBOXPtr pVBox = pScrn->driverPrivate;
203
204 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
205}
206
207static Bool
208vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
209{
210 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
211 VBOXPtr pVBox = pScrn->driverPrivate;
212 return pVBox->fUseHardwareCursor;
213}
214
215static unsigned char
216color_to_byte(unsigned c)
217{
218 return (c >> 8) & 0xff;
219}
220
221static unsigned char *
222vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
223{
224 VBOXPtr pVBox;
225 CursorBitsPtr bitsp;
226 unsigned short w, h, x, y;
227 unsigned char *c, *p, *pm, *ps, *m;
228 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
229 CARD32 fc, bc, *cp;
230 int rc, scrnIndex = infoPtr->pScrn->scrnIndex;
231 struct vboxCursorImage *pImage;
232
233 pVBox = infoPtr->pScrn->driverPrivate;
234 bitsp = pCurs->bits;
235 w = bitsp->width;
236 h = bitsp->height;
237
238 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
239 RETERROR(scrnIndex, NULL,
240 "Error invalid cursor dimensions %dx%d\n", w, h);
241
242 if ((bitsp->xhot > w) || (bitsp->yhot > h))
243 RETERROR(scrnIndex, NULL,
244 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
245 bitsp->xhot, bitsp->yhot, w, h);
246
247 srcPitch = PixmapBytePad (bitsp->width, 1);
248 dstPitch = (w + 7) / 8;
249 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
250 sizeRgba = w * h * 4;
251 sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
252
253 p = c = calloc (1, sizeRequest);
254 if (!c)
255 RETERROR(scrnIndex, NULL,
256 "Error failed to alloc %lu bytes for cursor\n",
257 (unsigned long) sizeRequest);
258
259 pImage = (struct vboxCursorImage *)p;
260 pImage->pPixels = m = p + sizeof(*pImage);
261 cp = (CARD32 *)(m + sizeMask);
262
263 TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
264 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
265 TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
266
267 fc = color_to_byte (pCurs->foreBlue)
268 | (color_to_byte (pCurs->foreGreen) << 8)
269 | (color_to_byte (pCurs->foreRed) << 16);
270
271 bc = color_to_byte (pCurs->backBlue)
272 | (color_to_byte (pCurs->backGreen) << 8)
273 | (color_to_byte (pCurs->backRed) << 16);
274
275 /*
276 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
277 * Xorg:
278 * The mask is a bitmap indicating which parts of the cursor are
279 * transparent and which parts are drawn. The source is a bitmap
280 * indicating which parts of the non-transparent portion of the
281 * the cursor should be painted in the foreground color and which
282 * should be painted in the background color. By default, set bits
283 * indicate the opaque part of the mask bitmap and clear bits
284 * indicate the transparent part.
285 * VBox:
286 * The color data is the XOR mask. The AND mask bits determine
287 * which pixels of the color data (XOR mask) will replace (overwrite)
288 * the screen pixels (AND mask bit = 0) and which ones will be XORed
289 * with existing screen pixels (AND mask bit = 1).
290 * For example when you have the AND mask all 0, then you see the
291 * correct mouse pointer image surrounded by black square.
292 */
293 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
294 y < h;
295 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
296 {
297 for (x = 0; x < w; ++x)
298 {
299 if (pm[x / 8] & (1 << (x % 8)))
300 {
301 /* opaque, leave AND mask bit at 0 */
302 if (ps[x / 8] & (1 << (x % 8)))
303 {
304 *cp++ = fc;
305 PUT_PIXEL('X');
306 }
307 else
308 {
309 *cp++ = bc;
310 PUT_PIXEL('*');
311 }
312 }
313 else
314 {
315 /* transparent, set AND mask bit */
316 m[x / 8] |= 1 << (7 - (x % 8));
317 /* don't change the screen pixel */
318 *cp++ = 0;
319 PUT_PIXEL(' ');
320 }
321 }
322 PUT_PIXEL('\n');
323 }
324
325 pImage->cWidth = w;
326 pImage->cHeight = h;
327 pImage->cHotX = bitsp->xhot;
328 pImage->cHotY = bitsp->yhot;
329 pImage->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
330 pImage->cbLength = sizeRequest - sizeof(*pImage);
331
332#ifdef DEBUG_POINTER
333 ErrorF("shape = %p\n", p);
334 vbox_show_shape(w, h, bc, c);
335#endif
336
337 return p;
338}
339
340#ifdef ARGB_CURSOR
341static Bool
342vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
343{
344 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
345 VBOXPtr pVBox = pScrn->driverPrivate;
346
347 if (!pVBox->fUseHardwareCursor)
348 return FALSE;
349 if ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
350 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
351 || (pScrn->bitsPerPixel <= 8))
352 return FALSE;
353 return TRUE;
354}
355
356
357static void
358vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
359{
360 VBOXPtr pVBox;
361 VMMDevReqMousePointer *reqp;
362 CursorBitsPtr bitsp;
363 unsigned short w, h;
364 unsigned short cx, cy;
365 unsigned char *pm;
366 CARD32 *pc;
367 size_t sizeData, sizeMask;
368 CARD8 *p;
369 int scrnIndex;
370 uint32_t fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE
371 | VBOX_MOUSE_POINTER_ALPHA;
372 int rc;
373
374 pVBox = pScrn->driverPrivate;
375 bitsp = pCurs->bits;
376 w = bitsp->width;
377 h = bitsp->height;
378 scrnIndex = pScrn->scrnIndex;
379
380 /* Mask must be generated for alpha cursors, that is required by VBox. */
381 /* note: (michael) the next struct must be 32bit aligned. */
382 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
383
384 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
385 RETERROR(scrnIndex, ,
386 "Error invalid cursor dimensions %dx%d\n", w, h);
387
388 if ((bitsp->xhot > w) || (bitsp->yhot > h))
389 RETERROR(scrnIndex, ,
390 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
391 bitsp->xhot, bitsp->yhot, w, h);
392
393 sizeData = w * h * 4 + sizeMask;
394 p = calloc(1, sizeData);
395 if (!p)
396 RETERROR(scrnIndex, ,
397 "Error failed to alloc %lu bytes for cursor\n",
398 (unsigned long)sizeData);
399
400 memcpy(p + sizeMask, bitsp->argb, w * h * 4);
401
402 /* Emulate the AND mask. */
403 pm = p;
404 pc = bitsp->argb;
405
406 /* Init AND mask to 1 */
407 memset(pm, 0xFF, sizeMask);
408
409 /*
410 * The additions driver must provide the AND mask for alpha cursors. The host frontend
411 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
412 * But if the host does not support ARGB, then it simply uses the AND mask and the color
413 * data to draw a normal color cursor.
414 */
415 for (cy = 0; cy < h; cy++)
416 {
417 unsigned char bitmask = 0x80;
418
419 for (cx = 0; cx < w; cx++, bitmask >>= 1)
420 {
421 if (bitmask == 0)
422 bitmask = 0x80;
423
424 if (pc[cx] >= 0xF0000000)
425 pm[cx / 8] &= ~bitmask;
426 }
427
428 /* Point to next source and dest scans */
429 pc += w;
430 pm += (w + 7) / 8;
431 }
432
433 VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
434 bitsp->yhot, w, h, p, sizeData);
435 free(p);
436}
437#endif
438
439Bool vbvxCursorInit(ScreenPtr pScreen)
440{
441 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
442 VBOXPtr pVBox = pScrn->driverPrivate;
443 xf86CursorInfoPtr pCurs = NULL;
444 Bool rc = TRUE;
445
446 TRACE_ENTRY();
447 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
448 if (!pCurs) {
449 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
450 "Failed to create X Window cursor information structures for virtual mouse.\n");
451 rc = FALSE;
452 }
453 if (rc) {
454 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
455 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
456 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
457 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
458 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
459 | HARDWARE_CURSOR_UPDATE_UNHIDDEN;
460
461 pCurs->SetCursorColors = vbox_set_cursor_colors;
462 pCurs->SetCursorPosition = vbox_set_cursor_position;
463 pCurs->LoadCursorImage = vbox_load_cursor_image;
464 pCurs->HideCursor = vbox_hide_cursor;
465 pCurs->ShowCursor = vbox_show_cursor;
466 pCurs->UseHWCursor = vbox_use_hw_cursor;
467 pCurs->RealizeCursor = vbox_realize_cursor;
468
469#ifdef ARGB_CURSOR
470 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
471 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
472#endif
473
474 rc = xf86InitCursor(pScreen, pCurs);
475 }
476 if (!rc)
477 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
478 "Failed to enable mouse pointer integration.\n");
479 if (!rc && (pCurs != NULL))
480 xf86DestroyCursorInfoRec(pCurs);
481 return rc;
482}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use