vboxutils-new.c revision b0dfb334954c0552bb583967a3077ec88fd00471
/** @file
*
* Linux Additions X11 graphics driver helper module
*/
/*
* Copyright (C) 2006-2007 innotek GmbH
*
* 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/VBoxGuest.h>
#include <xf86Pci.h>
#include <Pci.h>
#include "xf86.h"
#define NEED_XF86_TYPES
#include "xf86_ansic.h"
#include "compiler.h"
#include "cursorstr.h"
#include "vboxvideo.h"
#define VBOX_MAX_CURSOR_WIDTH 64
#define VBOX_MAX_CURSOR_HEIGHT 64
#if 0
#define DEBUG_X
#endif
#ifdef DEBUG_X
#define TRACE_ENTRY() for (;;) \
{ \
break; \
}
#else
#define PUT_PIXEL(c) (void) c
#define TRACE_ENTRY() (void) 0
#define dolog(...)
#endif
/** Macro to printf an error message and return from a function */
do \
{ \
return RetVal; \
} \
while (0)
#ifdef DEBUG_X
static void
{
size_t x, y;
unsigned short pitch;
unsigned char *mask;
TRACE_ENTRY ();
{
for (x = 0; x < w; ++x)
{
ErrorF (" ");
else
{
if (c == bg)
ErrorF ("Y");
else
ErrorF ("X");
}
}
ErrorF ("\n");
}
}
#endif
static Bool
{
int rc;
if (VBOX_FAILURE(rc))
"Unable to determine whether the virtual machine supports mouse pointer integration - request initialization failed with return code %d\n", rc);
}
void
{
TRACE_ENTRY ();
VbglR3Term();
}
/**
* Macro to disable VBVA extensions and return, for use when an
* unexplained error occurs.
*/
#define DISABLE_VBVA_AND_RETURN(pScrn, ...) \
do \
{ \
vboxDisableVbva(pScrn); \
return; \
} \
while (0)
/**
* Callback function called by the X server to tell us about dirty
* rectangles in the video buffer.
*
* @param pScreen pointer to the information structure for the current
* screen
* @param iRects Number of dirty rectangles to update
* @param aRects Array of structures containing the coordinates of the
* rectangles
*/
static void
{
int scrnIndex;
int i;
return;
/* Just return quietly if VBVA is not currently active. */
return;
for (i = 0; i < iRects; i++)
{
/* Get the active record and move the pointer along */
{
/* All slots in the records queue are used. */
if (VbglR3VideoAccelFlush() < 0)
"Unable to clear the VirtualBox graphics acceleration queue "
"- the request to the virtual machine failed. Switching to "
"unaccelerated mode.\n");
}
"Failed to clear the VirtualBox graphics acceleration queue. "
"Switching to unaccelerated mode.\n");
/* Mark the record as being updated. */
/* Compute how many bytes we have in the ring buffer. */
/* Free is writing position. Data is reading position.
* Data == Free means buffer is free.
* There must be always gap between free and data when data
* are in the buffer.
* Guest only changes free, host only changes data.
*/
+ i32Diff;
{
if (VbglR3VideoAccelFlush() < 0)
"Unable to clear the VirtualBox graphics acceleration queue "
"- the request to the virtual machine failed. Switching to "
"unaccelerated mode.\n");
/* Calculate the free space again. */
"No space left in the VirtualBox graphics acceleration command buffer, "
"despite clearing the queue. Switching to unaccelerated mode.\n");
}
/* Now copy the data into the buffer */
{
sizeof(cmdHdr));
}
else
{
/* The following is impressively ugly! */
if (u32Second)
}
/* Mark the record completed. */
}
}
/**
* Initialise VirtualBox's accelerated video extensions.
* Note that we assume that the PCI memory is 32bit mapped,
* as X doesn't seem to support mapping 64bit memory.
*
* @returns TRUE on success, FALSE on failure
*/
static Bool
{
/* Locate the device. It should already have been enabled by
the kernel driver. */
(CARD32) ~0);
if (pciTag == PCI_NOT_FOUND)
{
"Could not find the VirtualBox base device on the PCI bus.\n");
return FALSE;
}
/* Read the address and size of the second I/O region. */
"The VirtualBox base device contains an invalid memory address.\n");
if (PCI_MAP_IS64BITMEM(pciAddress))
"The VirtualBox base device has a 64bit mapping address. "
"This is currently not supported.\n");
/* Map it. We hardcode the size as X does not export the
function needed to determine it. */
sizeof(VMMDevMemory));
{
"Failed to map VirtualBox video extension memory.\n");
return FALSE;
}
/* Set up the dirty rectangle handler. Since this seems to be a
delicate operation, and removing it doubly so, this will
remain in place whether it is needed or not, and will simply
return if VBVA is not active. I assume that it will be active
most of the time. */
{
"Unable to install dirty rectangle handler for VirtualBox graphics acceleration.\n");
return FALSE;
}
return TRUE;
}
{
int rc;
void *p;
TRACE_ENTRY ();
{
/* still open, just re-enable VBVA after CloseScreen was called */
return TRUE;
}
rc = VbglR3Init();
if (RT_FAILURE(rc))
{
return FALSE;
}
if (p)
{
if (RT_SUCCESS(rc))
{
return TRUE;
}
xfree(p);
}
xf86DrvMsg(scrnIndex, X_ERROR, "Could not allocate %lu bytes for VMM request\n", (unsigned long)size);
VbglR3Term();
return FALSE;
}
static void
{
int rc;
if (RT_FAILURE(rc))
}
static void
{
int rc;
if (RT_FAILURE(rc))
}
static void
unsigned char *image)
{
int rc;
#ifdef DEBUG_X
#endif
if (RT_FAILURE(rc))
}
static void
{
TRACE_ENTRY ();
(void) pScrn;
(void) bg;
(void) fg;
/* ErrorF ("vbox_set_cursor_colors NOT IMPLEMENTED\n"); */
}
static void
{
/* VBOXPtr pVBox = pScrn->driverPrivate; */
/* TRACE_ENTRY (); */
/* don't disable the mouse cursor if we go out of our visible area
* since the mouse cursor is drawn by the host anyway */
#if 0
{
if (!pVBox->pointer_offscreen)
{
}
}
else
{
if (pVBox->pointer_offscreen)
{
}
}
#endif
}
static void
{
TRACE_ENTRY ();
}
static void
{
TRACE_ENTRY ();
}
static void
{
TRACE_ENTRY ();
}
static Bool
{
return pVBox->use_hw_cursor;
}
static unsigned char
color_to_byte(unsigned c)
{
return (c >> 8) & 0xff;
}
static unsigned char *
{
unsigned short w, h, x, y;
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",
size_rgba = w * h * 4;
if (!c)
"Error failed to alloc %lu bytes for cursor\n",
(unsigned long) size);
if (VBOX_FAILURE (rc))
{
xfree(p);
return NULL;
}
dolog ("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');
}
reqp = (VMMDevReqMousePointer *)p;
#ifdef DEBUG_X
ErrorF ("shape = %p\n", p);
vbox_show_shape (w, h, bc, c);
#endif
return p;
}
#ifdef ARGB_CURSOR
static Bool
{
}
static void
{
unsigned short w, h;
unsigned char *pm;
CARD8 *p;
int scrnIndex;
/* 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) size);
reqp = (VMMDevReqMousePointer *)p;
/* Emulate the AND mask. */
/* 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;
}
VbglR3SetPointerShape(VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA, bitsp->xhot, bitsp->yhot, w, h,
xfree (p);
}
#endif
{
if (pVBox->use_hw_cursor)
{
"The host system is drawing the mouse cursor.\n");
}
else
{
"The guest system is drawing the mouse cursor.\n");
return TRUE;
}
if (!pCurs)
"Failed to create X Window cursor information structures for virtual mouse.\n");
#ifdef ARGB_CURSOR
#endif
return TRUE;
}
/**
* Inform VBox that we will supply it with dirty rectangle information
* and install the dirty rectangle handler.
*
* @returns TRUE for success, FALSE for failure
* @param pScreen Pointer to a structure describing the X screen in use
*/
{
int rc;
return FALSE;
if (RT_FAILURE(rc))
{
/* Request not accepted - disable for old hosts. */
"Unable to activate VirtualBox graphics acceleration "
"- the request to the virtual machine failed. "
"You may be running an old version of VirtualBox.\n");
return FALSE;
}
return TRUE;
}
/**
* Inform VBox that we will stop supplying it with dirty rectangle
* information. This function is intended to be called when an X
* virtual terminal is disabled, or the X server is terminated.
*
* @returns TRUE for success, FALSE for failure
* @param pScreen Pointer to a structure describing the X screen in use
*/
{
int rc;
return FALSE;
rc = VbglR3VideoAccelEnable(0);
if (RT_FAILURE(rc))
{
"Unable to disable VirtualBox graphics acceleration "
"- the request to the virtual machine failed.\n");
}
else
return TRUE;
}
/**
* Query the last display change request.
*
* @returns iprt status value
* @retval xres horizontal pixel resolution (0 = do not change)
* @retval yres vertical pixel resolution (0 = do not change)
* @retval bpp bits per pixel (0 = do not change)
* @param eventAck Flag that the request is an acknowlegement for the
* VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST.
* Values:
* 0 - just querying,
* VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST - event acknowledged.
* @param display 0 for primary display, 1 for the first secondary, etc.
*/
{
if (RT_SUCCESS(rc))
return TRUE;
xf86DrvMsg(scrnIndex, X_ERROR, "Failed to request the last resolution requested from the guest, rc=%d.\n", rc);
return FALSE;
}