VirtualBox

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

Last change on this file since 69206 was 69080, checked in by vboxsync, 7 years ago

Additions/x11/vboxvideo: Replace custom VBVXASSERT with IPRT assertion syntax.
bugref:9017: Additions/x11: put vboxvideo into upstream X.Org

At some point we started using custom assertion code in X.Org vboxvideo.
This change removes that and switches assertions in the code to use IPRT
assertions, albeit provided by our IPRT replacement header and not by IPRT
itself.

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