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