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