pointer.c revision c58f1213e628a545081c70e26c6b67a841cff880
/** @file
* VirtualBox X11 Additions graphics driver utility functions
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <VBox/VBoxGuestLib.h>
#ifndef PCIACCESS
# include <xf86Pci.h>
# include <Pci.h>
#endif
#include "xf86.h"
#define NEED_XF86_TYPES
#include "compiler.h"
#include "cursorstr.h"
#include "servermd.h"
#include "vboxvideo.h"
#ifdef XORG_7X
# include <stdlib.h>
#endif
#define VBOX_MAX_CURSOR_WIDTH 64
#define VBOX_MAX_CURSOR_HEIGHT 64
/**************************************************************************
* Debugging functions and macros *
**************************************************************************/
/* #define DEBUG_POINTER */
#ifdef DEBUG
#else /* DEBUG_VIDEO not defined */
# define PUT_PIXEL(c) do { } while(0)
#endif /* DEBUG_VIDEO not defined */
/** Macro to printf an error message and return from a function */
do \
{ \
return RetVal; \
} \
while (0)
/** Structure to pass cursor image data between realise_cursor() and
* load_cursor_image(). The members match the parameters to
* @a VBoxHGSMIUpdatePointerShape(). */
struct vboxCursorImage
{
};
#ifdef DEBUG_POINTER
static void
{
size_t x, y;
unsigned short pitch;
unsigned char *mask;
image += sizeof(struct vboxCursorImage);
TRACE_ENTRY();
{
for (x = 0; x < w; ++x)
{
ErrorF (" ");
else
{
if (c == bg)
ErrorF("Y");
else
ErrorF("X");
}
}
ErrorF("\n");
}
}
#endif
/**************************************************************************
* Helper functions and macros *
**************************************************************************/
/* This is called by the X server every time it loads a new cursor to see
* whether our "cursor hardware" can handle the cursor. This provides us with
* a mechanism (the only one!) to switch back from a software to a hardware
* cursor. */
static Bool
{
/* We may want to force the use of a software cursor. Currently this is
* needed if the guest uses a large virtual resolution, as in this case
* the host and guest tend to disagree about the pointer location. */
if (pVBox->forceSWCursor)
/* Query information about mouse integration from the host. */
if (rc) {
if (RT_FAILURE(vrc)) {
"Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", vrc);
}
}
/* If we got the information from the host then make sure the host wants
* to draw the pointer. */
if (rc)
{
if ( (fFeatures & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
/* As of this version (server 1.6) all major Linux releases
* are known to handle USB tablets correctly. */
#endif
)
/* Assume this will never be unloaded as long as the X session is
* running. */
|| !pVBox->guestCanAbsolute
)
}
return rc;
}
/**************************************************************************
* Main functions *
**************************************************************************/
void
{
TRACE_ENTRY();
TRACE_EXIT();
}
{
int vrc;
uint32_t fMouseFeatures = 0;
TRACE_ENTRY();
vrc = VbglR3Init();
if (RT_FAILURE(vrc))
{
"Failed to initialize the VirtualBox device (rc=%d) - make sure that the VirtualBox guest additions are properly installed. If you are not sure, try reinstalling them. The X Window graphics drivers will run in compatibility mode.\n",
vrc);
}
return rc;
}
static void
{
int rc;
if (RT_FAILURE(rc))
{
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not hide the virtual mouse pointer, VBox error %d.\n", rc);
/* Play safe, and disable the hardware cursor until the next mode
* switch, since obviously something happened that we didn't
* anticipate. */
}
}
static void
{
int rc;
if (!vbox_host_uses_hwcursor(pScrn))
return;
0, 0, 0, 0, NULL, 0);
if (RT_FAILURE(rc)) {
/* Play safe, and disable the hardware cursor until the next mode
* switch, since obviously something happened that we didn't
* anticipate. */
}
}
static void
unsigned char *pvImage)
{
int rc;
struct vboxCursorImage *pImage;
#ifdef DEBUG_POINTER
#endif
if (RT_FAILURE(rc)) {
/* Play safe, and disable the hardware cursor until the next mode
* switch, since obviously something happened that we didn't
* anticipate. */
}
}
static void
{
/* ErrorF("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
}
static void
{
/* Nothing to do here, as we are telling the guest where the mouse is,
* not vice versa. */
NOREF(x);
NOREF(y);
}
static void
{
}
static void
{
}
static void
{
}
static Bool
{
return vbox_host_uses_hwcursor(pScrn);
}
static unsigned char
color_to_byte(unsigned c)
{
return (c >> 8) & 0xff;
}
static unsigned char *
{
unsigned short w, h, x, y;
struct vboxCursorImage *pImage;
if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
"Error invalid cursor dimensions %dx%d\n", w, h);
"Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
sizeRgba = w * h * 4;
if (!c)
"Error failed to alloc %lu bytes for cursor\n",
(unsigned long) sizeRequest);
pImage = (struct vboxCursorImage *)p;
TRACE_LOG ("w=%d h=%d sm=%d sr=%d p=%d\n",
/*
* Xorg:
* The mask is a bitmap indicating which parts of the cursor are
* transparent and which parts are drawn. The source is a bitmap
* indicating which parts of the non-transparent portion of the
* the cursor should be painted in the foreground color and which
* should be painted in the background color. By default, set bits
* indicate the opaque part of the mask bitmap and clear bits
* indicate the transparent part.
* VBox:
* The color data is the XOR mask. The AND mask bits determine
* which pixels of the color data (XOR mask) will replace (overwrite)
* the screen pixels (AND mask bit = 0) and which ones will be XORed
* with existing screen pixels (AND mask bit = 1).
* For example when you have the AND mask all 0, then you see the
* correct mouse pointer image surrounded by black square.
*/
y < h;
{
for (x = 0; x < w; ++x)
{
{
/* opaque, leave AND mask bit at 0 */
{
PUT_PIXEL('X');
}
else
{
PUT_PIXEL('*');
}
}
else
{
/* transparent, set AND mask bit */
m[x / 8] |= 1 << (7 - (x % 8));
/* don't change the screen pixel */
*cp++ = 0;
PUT_PIXEL(' ');
}
}
PUT_PIXEL('\n');
}
#ifdef DEBUG_POINTER
ErrorF("shape = %p\n", p);
vbox_show_shape(w, h, bc, c);
#endif
return p;
}
#ifdef ARGB_CURSOR
static Bool
{
if (!vbox_host_uses_hwcursor(pScrn))
if ( rc
)
)
#ifndef VBOXVIDEO_13
/* Evil hack - we use this as another way of poking the driver to update
* our list of video modes. */
#endif
return rc;
}
static void
{
unsigned short w, h;
unsigned char *pm;
CARD8 *p;
int scrnIndex;
int rc;
/* Mask must be generated for alpha cursors, that is required by VBox. */
/* note: (michael) the next struct must be 32bit aligned. */
if (!w || !h || w > VBOX_MAX_CURSOR_WIDTH || h > VBOX_MAX_CURSOR_HEIGHT)
"Error invalid cursor dimensions %dx%d\n", w, h);
"Error invalid cursor hotspot location %dx%d (max %dx%d)\n",
if (!p)
"Error failed to alloc %lu bytes for cursor\n",
(unsigned long)sizeData);
/* Emulate the AND mask. */
pm = p;
/* Init AND mask to 1 */
/*
* The additions driver must provide the AND mask for alpha cursors. The host frontend
* which can handle alpha channel, will ignore the AND mask and draw an alpha cursor.
* But if the host does not support ARGB, then it simply uses the AND mask and the color
* data to draw a normal color cursor.
*/
{
unsigned char bitmask = 0x80;
{
if (bitmask == 0)
bitmask = 0x80;
}
/* Point to next source and dest scans */
pc += w;
}
free(p);
}
#endif
{
TRACE_ENTRY();
if (!pVBox->fHaveHGSMI)
return FALSE;
if (!pCurs) {
"Failed to create X Window cursor information structures for virtual mouse.\n");
}
if (rc) {
#ifdef ARGB_CURSOR
#endif
/* Hide the host cursor before we initialise if we wish to use a
* software cursor. */
if (pVBox->forceSWCursor)
}
if (!rc)
"Failed to enable mouse pointer integration.\n");
return rc;
}