VirtualBox

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

Last change on this file since 68080 was 63221, checked in by vboxsync, 8 years ago

GA/X11: warnings

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