VirtualBox

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

Last change on this file since 63100 was 62530, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.8 KB
Line 
1/* $Id: pointer.c 62530 2016-07-22 19:25:14Z vboxsync $ */
2/** @file
3 * VirtualBox X11 Additions graphics driver utility functions
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <VBox/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#include <iprt/string.h>
28#include "compiler.h"
29#include "cursorstr.h"
30#include "servermd.h"
31
32#include "vboxvideo.h"
33
34#ifdef XORG_7X
35# include <stdlib.h>
36#endif
37
38#define VBOX_MAX_CURSOR_WIDTH 64
39#define VBOX_MAX_CURSOR_HEIGHT 64
40
41/**************************************************************************
42* Debugging functions and macros *
43**************************************************************************/
44
45/* #define DEBUG_POINTER */
46
47#ifdef DEBUG
48# define PUT_PIXEL(c) ErrorF ("%c", c)
49#else /* DEBUG_VIDEO not defined */
50# define PUT_PIXEL(c) do { } while(0)
51#endif /* DEBUG_VIDEO not defined */
52
53/** Macro to printf an error message and return from a function */
54#define RETERROR(scrnIndex, RetVal, ...) \
55 do \
56 { \
57 xf86DrvMsg(scrnIndex, X_ERROR, __VA_ARGS__); \
58 return RetVal; \
59 } \
60 while (0)
61
62/** Structure to pass cursor image data between realise_cursor() and
63 * load_cursor_image(). The members match the parameters to
64 * @a VBoxHGSMIUpdatePointerShape(). */
65struct vboxCursorImage
66{
67 uint32_t fFlags;
68 uint32_t cHotX;
69 uint32_t cHotY;
70 uint32_t cWidth;
71 uint32_t cHeight;
72 uint8_t *pPixels;
73 uint32_t cbLength;
74};
75
76#ifdef DEBUG_POINTER
77static void
78vbox_show_shape(unsigned short w, unsigned short h, CARD32 bg, unsigned char *image)
79{
80 size_t x, y;
81 unsigned short pitch;
82 CARD32 *color;
83 unsigned char *mask;
84 size_t sizeMask;
85
86 image += sizeof(struct vboxCursorImage);
87 mask = image;
88 pitch = (w + 7) / 8;
89 sizeMask = (pitch * h + 3) & ~3;
90 color = (CARD32 *)(image + sizeMask);
91
92 TRACE_ENTRY();
93 for (y = 0; y < h; ++y, mask += pitch, color += w)
94 {
95 for (x = 0; x < w; ++x)
96 {
97 if (mask[x / 8] & (1 << (7 - (x % 8))))
98 ErrorF (" ");
99 else
100 {
101 CARD32 c = color[x];
102 if (c == bg)
103 ErrorF("Y");
104 else
105 ErrorF("X");
106 }
107 }
108 ErrorF("\n");
109 }
110}
111#endif
112
113/**************************************************************************
114* Main functions *
115**************************************************************************/
116
117void vbvxCursorTerm(VBOXPtr pVBox)
118{
119 TRACE_ENTRY();
120
121 xf86DestroyCursorInfoRec(pVBox->pCurs);
122 pVBox->pCurs = NULL;
123 TRACE_EXIT();
124}
125
126static void
127vbox_vmm_hide_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
128{
129 int rc;
130
131 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, 0, 0, 0, 0, 0, NULL, 0);
132 VBVXASSERT(rc == VINF_SUCCESS, ("Could not hide the virtual mouse pointer, VBox error %d.\n", rc));
133}
134
135static void
136vbox_vmm_show_cursor(ScrnInfoPtr pScrn, VBOXPtr pVBox)
137{
138 int rc;
139
140 if (!pVBox->fUseHardwareCursor)
141 return;
142 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, VBOX_MOUSE_POINTER_VISIBLE,
143 0, 0, 0, 0, NULL, 0);
144 VBVXASSERT(rc == VINF_SUCCESS, ("Could not unhide the virtual mouse pointer.\n"));
145}
146
147static void
148vbox_vmm_load_cursor_image(ScrnInfoPtr pScrn, VBOXPtr pVBox,
149 unsigned char *pvImage)
150{
151 int rc;
152 struct vboxCursorImage *pImage;
153 pImage = (struct vboxCursorImage *)pvImage;
154
155#ifdef DEBUG_POINTER
156 vbox_show_shape(pImage->cWidth, pImage->cHeight, 0, pvImage);
157#endif
158
159 rc = VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, pImage->fFlags,
160 pImage->cHotX, pImage->cHotY, pImage->cWidth, pImage->cHeight,
161 pImage->pPixels, pImage->cbLength);
162 VBVXASSERT(rc == VINF_SUCCESS, ("Unable to set the virtual mouse pointer image.\n"));
163}
164
165static void
166vbox_set_cursor_colors(ScrnInfoPtr pScrn, int bg, int fg)
167{
168 NOREF(pScrn);
169 NOREF(bg);
170 NOREF(fg);
171 /* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
172}
173
174
175static void
176vbox_set_cursor_position(ScrnInfoPtr pScrn, int x, int y)
177{
178 VBOXPtr pVBox = pScrn->driverPrivate;
179
180 /* This currently does nothing. */
181 VBoxHGSMICursorPosition(&pVBox->guestCtx, true, x, y, NULL, NULL);
182}
183
184static void
185vbox_hide_cursor(ScrnInfoPtr pScrn)
186{
187 VBOXPtr pVBox = pScrn->driverPrivate;
188
189 vbox_vmm_hide_cursor(pScrn, pVBox);
190}
191
192static void
193vbox_show_cursor(ScrnInfoPtr pScrn)
194{
195 VBOXPtr pVBox = pScrn->driverPrivate;
196
197 vbox_vmm_show_cursor(pScrn, pVBox);
198}
199
200static void
201vbox_load_cursor_image(ScrnInfoPtr pScrn, unsigned char *image)
202{
203 VBOXPtr pVBox = pScrn->driverPrivate;
204
205 vbox_vmm_load_cursor_image(pScrn, pVBox, image);
206}
207
208static Bool
209vbox_use_hw_cursor(ScreenPtr pScreen, CursorPtr pCurs)
210{
211 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
212 VBOXPtr pVBox = pScrn->driverPrivate;
213 return pVBox->fUseHardwareCursor;
214}
215
216static unsigned char
217color_to_byte(unsigned c)
218{
219 return (c >> 8) & 0xff;
220}
221
222static unsigned char *
223vbox_realize_cursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
224{
225 VBOXPtr pVBox;
226 CursorBitsPtr bitsp;
227 unsigned short w, h, x, y;
228 unsigned char *c, *p, *pm, *ps, *m;
229 size_t sizeRequest, sizeRgba, sizeMask, srcPitch, dstPitch;
230 CARD32 fc, bc, *cp;
231 int scrnIndex = infoPtr->pScrn->scrnIndex;
232 struct vboxCursorImage *pImage;
233
234 pVBox = infoPtr->pScrn->driverPrivate;
235 bitsp = pCurs->bits;
236 w = bitsp->width;
237 h = bitsp->height;
238
239 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
240 RETERROR(scrnIndex, NULL,
241 "Error invalid cursor dimensions %dx%d\n", w, h);
242
243 if ((bitsp->xhot > w) || (bitsp->yhot > h))
244 RETERROR(scrnIndex, NULL,
245 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
246 bitsp->xhot, bitsp->yhot, w, h);
247
248 srcPitch = PixmapBytePad (bitsp->width, 1);
249 dstPitch = (w + 7) / 8;
250 sizeMask = ((dstPitch * h) + 3) & (size_t) ~3;
251 sizeRgba = w * h * 4;
252 sizeRequest = sizeMask + sizeRgba + sizeof(*pImage);
253
254 p = c = calloc (1, sizeRequest);
255 if (!c)
256 RETERROR(scrnIndex, NULL,
257 "Error failed to alloc %lu bytes for cursor\n",
258 (unsigned long) sizeRequest);
259
260 pImage = (struct vboxCursorImage *)p;
261 pImage->pPixels = m = p + sizeof(*pImage);
262 cp = (CARD32 *)(m + sizeMask);
263
264 TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
265 w, h, (int) sizeMask, (int) sizeRgba, (int) dstPitch);
266 TRACE_LOG ("m=%p c=%p cp=%p\n", m, c, (void *)cp);
267
268 fc = color_to_byte (pCurs->foreBlue)
269 | (color_to_byte (pCurs->foreGreen) << 8)
270 | (color_to_byte (pCurs->foreRed) << 16);
271
272 bc = color_to_byte (pCurs->backBlue)
273 | (color_to_byte (pCurs->backGreen) << 8)
274 | (color_to_byte (pCurs->backRed) << 16);
275
276 /*
277 * Convert the Xorg source/mask bits to the and/xor bits VBox needs.
278 * Xorg:
279 * The mask is a bitmap indicating which parts of the cursor are
280 * transparent and which parts are drawn. The source is a bitmap
281 * indicating which parts of the non-transparent portion of the
282 * the cursor should be painted in the foreground color and which
283 * should be painted in the background color. By default, set bits
284 * indicate the opaque part of the mask bitmap and clear bits
285 * indicate the transparent part.
286 * VBox:
287 * The color data is the XOR mask. The AND mask bits determine
288 * which pixels of the color data (XOR mask) will replace (overwrite)
289 * the screen pixels (AND mask bit = 0) and which ones will be XORed
290 * with existing screen pixels (AND mask bit = 1).
291 * For example when you have the AND mask all 0, then you see the
292 * correct mouse pointer image surrounded by black square.
293 */
294 for (pm = bitsp->mask, ps = bitsp->source, y = 0;
295 y < h;
296 ++y, pm += srcPitch, ps += srcPitch, m += dstPitch)
297 {
298 for (x = 0; x < w; ++x)
299 {
300 if (pm[x / 8] & (1 << (x % 8)))
301 {
302 /* opaque, leave AND mask bit at 0 */
303 if (ps[x / 8] & (1 << (x % 8)))
304 {
305 *cp++ = fc;
306 PUT_PIXEL('X');
307 }
308 else
309 {
310 *cp++ = bc;
311 PUT_PIXEL('*');
312 }
313 }
314 else
315 {
316 /* transparent, set AND mask bit */
317 m[x / 8] |= 1 << (7 - (x % 8));
318 /* don't change the screen pixel */
319 *cp++ = 0;
320 PUT_PIXEL(' ');
321 }
322 }
323 PUT_PIXEL('\n');
324 }
325
326 pImage->cWidth = w;
327 pImage->cHeight = h;
328 pImage->cHotX = bitsp->xhot;
329 pImage->cHotY = bitsp->yhot;
330 pImage->fFlags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE;
331 pImage->cbLength = sizeRequest - sizeof(*pImage);
332
333#ifdef DEBUG_POINTER
334 ErrorF("shape = %p\n", p);
335 vbox_show_shape(w, h, bc, c);
336#endif
337
338 return p;
339}
340
341#ifdef ARGB_CURSOR
342static Bool
343vbox_use_hw_cursor_argb(ScreenPtr pScreen, CursorPtr pCurs)
344{
345 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
346 VBOXPtr pVBox = pScrn->driverPrivate;
347
348 if (!pVBox->fUseHardwareCursor)
349 return FALSE;
350 if ( (pCurs->bits->height > VBOX_MAX_CURSOR_HEIGHT)
351 || (pCurs->bits->width > VBOX_MAX_CURSOR_WIDTH)
352 || (pScrn->bitsPerPixel <= 8))
353 return FALSE;
354 return TRUE;
355}
356
357
358static void
359vbox_load_cursor_argb(ScrnInfoPtr pScrn, CursorPtr pCurs)
360{
361 VBOXPtr pVBox;
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
373 pVBox = pScrn->driverPrivate;
374 bitsp = pCurs->bits;
375 w = bitsp->width;
376 h = bitsp->height;
377 scrnIndex = pScrn->scrnIndex;
378
379 /* Mask must be generated for alpha cursors, that is required by VBox. */
380 /* note: (michael) the next struct must be 32bit aligned. */
381 sizeMask = ((w + 7) / 8 * h + 3) & ~3;
382
383 if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
384 RETERROR(scrnIndex, ,
385 "Error invalid cursor dimensions %dx%d\n", w, h);
386
387 if ((bitsp->xhot > w) || (bitsp->yhot > h))
388 RETERROR(scrnIndex, ,
389 "Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
390 bitsp->xhot, bitsp->yhot, w, h);
391
392 sizeData = w * h * 4 + sizeMask;
393 p = calloc(1, sizeData);
394 if (!p)
395 RETERROR(scrnIndex, ,
396 "Error failed to alloc %lu bytes for cursor\n",
397 (unsigned long)sizeData);
398
399 memcpy(p + sizeMask, bitsp->argb, w * h * 4);
400
401 /* Emulate the AND mask. */
402 pm = p;
403 pc = bitsp->argb;
404
405 /* Init AND mask to 1 */
406 memset(pm, 0xFF, sizeMask);
407
408 /*
409 * The additions driver must provide the AND mask for alpha cursors. The host frontend
410 * which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
411 * But if the host does not support ARGB, then it simply uses the AND mask and the color
412 * data to draw a normal color cursor.
413 */
414 for (cy = 0; cy < h; cy++)
415 {
416 unsigned char bitmask = 0x80;
417
418 for (cx = 0; cx < w; cx++, bitmask >>= 1)
419 {
420 if (bitmask == 0)
421 bitmask = 0x80;
422
423 if (pc[cx] >= 0xF0000000)
424 pm[cx / 8] &= ~bitmask;
425 }
426
427 /* Point to next source and dest scans */
428 pc += w;
429 pm += (w + 7) / 8;
430 }
431
432 VBoxHGSMIUpdatePointerShape(&pVBox->guestCtx, fFlags, bitsp->xhot,
433 bitsp->yhot, w, h, p, sizeData);
434 free(p);
435}
436#endif
437
438Bool vbvxCursorInit(ScreenPtr pScreen)
439{
440 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
441 VBOXPtr pVBox = pScrn->driverPrivate;
442 xf86CursorInfoPtr pCurs = NULL;
443 Bool rc = TRUE;
444
445 TRACE_ENTRY();
446 pVBox->pCurs = pCurs = xf86CreateCursorInfoRec();
447 if (!pCurs) {
448 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
449 "Failed to create X Window cursor information structures for virtual mouse.\n");
450 rc = FALSE;
451 }
452 if (rc) {
453 pCurs->MaxWidth = VBOX_MAX_CURSOR_WIDTH;
454 pCurs->MaxHeight = VBOX_MAX_CURSOR_HEIGHT;
455 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
456 | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1
457 | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
458 | HARDWARE_CURSOR_UPDATE_UNHIDDEN;
459
460 pCurs->SetCursorColors = vbox_set_cursor_colors;
461 pCurs->SetCursorPosition = vbox_set_cursor_position;
462 pCurs->LoadCursorImage = vbox_load_cursor_image;
463 pCurs->HideCursor = vbox_hide_cursor;
464 pCurs->ShowCursor = vbox_show_cursor;
465 pCurs->UseHWCursor = vbox_use_hw_cursor;
466 pCurs->RealizeCursor = vbox_realize_cursor;
467
468#ifdef ARGB_CURSOR
469 pCurs->UseHWCursorARGB = vbox_use_hw_cursor_argb;
470 pCurs->LoadCursorARGB = vbox_load_cursor_argb;
471#endif
472
473 rc = xf86InitCursor(pScreen, pCurs);
474 }
475 if (!rc)
476 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
477 "Failed to enable mouse pointer integration.\n");
478 if (!rc && (pCurs != NULL))
479 xf86DestroyCursorInfoRec(pCurs);
480 return rc;
481}
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