Cleanup dmxcursor.c and implement proper pointer warping.

This commit is contained in:
David Reveman 2008-11-12 09:32:26 -05:00
parent 2681b50b44
commit b6dd1a68b6
3 changed files with 123 additions and 91 deletions

View file

@ -33,51 +33,10 @@
*
*/
/** \file
* This file contains code than supports cursor movement, including the
* code that initializes and reinitializes the screen positions and
* computes screen overlap.
*
* "This code is based very closely on the XFree86 equivalent
* (xfree86/common/xf86Cursor.c)." --David Dawes.
*
* "This code was then extensively re-written, as explained here."
* --Rik Faith
*
* The code in xf86Cursor.c used edge lists to implement the
* CursorOffScreen function. The edge list computation was complex
* (especially in the face of arbitrarily overlapping screens) compared
* with the speed savings in the CursorOffScreen function. The new
* implementation has erred on the side of correctness, readability, and
* maintainability over efficiency. For the common (non-edge) case, the
* dmxCursorOffScreen function does avoid a loop over all the screens.
* When the cursor has left the screen, all the screens are searched,
* and the first screen (in dmxScreens order) containing the cursor will
* be returned. If run-time profiling shows that this routing is a
* performance bottle-neck, then an edge list may have to be
* reimplemented. An edge list algorithm is O(edges) whereas the new
* algorithm is O(dmxNumScreens). Since edges is usually 1-3 and
* dmxNumScreens may be 30-60 for large backend walls, this trade off
* may be compelling.
*
* The xf86InitOrigins routine uses bit masks during the computation and
* is therefore limited to the length of a word (e.g., 32 or 64 bits)
* screens. Because Xdmx is expected to be used with a large number of
* backend displays, this limitation was removed. The new
* implementation has erred on the side of readability over efficiency,
* using the dmxSL* routines to manage a screen list instead of a
* bitmap, and a function call to decrease the length of the main
* routine. Both algorithms are of the same order, and both are called
* only at server generation time, so trading clarity and long-term
* maintainability for efficiency does not seem justified in this case.
*/
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#define DMX_CURSOR_DEBUG 0
#include "dmx.h"
#include "dmxsync.h"
#include "dmxcursor.h"
@ -90,50 +49,38 @@
#include "windowstr.h"
#include "globals.h"
#include "cursorstr.h"
#include "dixevents.h" /* For GetSpriteCursor() */
#if DMX_CURSOR_DEBUG
#define DMXDBG0(f) dmxLog(dmxDebug,f)
#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a)
#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d)
#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g)
#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
#else
#define DMXDBG0(f)
#define DMXDBG1(f,a)
#define DMXDBG2(f,a,b)
#define DMXDBG3(f,a,b,c)
#define DMXDBG4(f,a,b,c,d)
#define DMXDBG5(f,a,b,c,d,e)
#define DMXDBG6(f,a,b,c,d,e,g)
#define DMXDBG7(f,a,b,c,d,e,g,h)
#endif
/** Initialize the private area for the cursor functions. */
Bool dmxInitCursor(ScreenPtr pScreen)
Bool
dmxInitCursor (ScreenPtr pScreen)
{
if (!dixRequestPrivate(CursorScreenKey(pScreen), sizeof(dmxCursorPrivRec)))
if (!dixRequestPrivate (CursorScreenKey (pScreen), sizeof (dmxCursorPrivRec)))
return FALSE;
if (!dixRequestPrivate (dmxDevicePrivateKey, sizeof(dmxDevicePrivRec)))
if (!dixRequestPrivate (dmxDevicePrivateKey, sizeof (dmxDevicePrivRec)))
return FALSE;
return TRUE;
}
static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
static Bool
dmxCursorOffScreen (ScreenPtr *ppScreen,
int *x,
int *y)
{
return FALSE;
}
static void dmxCrossScreen(ScreenPtr pScreen, Bool entering)
static void
dmxCrossScreen (ScreenPtr pScreen,
Bool entering)
{
}
static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
static void
dmxWarpCursor (DeviceIntPtr pDev,
ScreenPtr pScreen,
int x,
int y)
{
int i;
@ -144,10 +91,7 @@ static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
if (!dmxScreen->beDisplay)
continue;
XLIB_PROLOGUE (dmxScreen);
XWarpPointer (dmxScreen->beDisplay, None, dmxScreen->scrnWin,
0, 0, 0, 0, x, y);
XLIB_EPILOGUE (dmxScreen);
dmxInputWarpPointer (&dmxScreen->input, pDev, x, y);
}
}
@ -166,7 +110,9 @@ dmxCreateARGBCursor (ScreenPtr pScreen,
#endif
/** Create \a pCursor on the back-end associated with \a pScreen. */
void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
void
dmxBECreateCursor (ScreenPtr pScreen,
CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
@ -291,33 +237,36 @@ void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
XLIB_EPILOGUE (dmxScreen);
}
static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
static Bool
_dmxRealizeCursor (ScreenPtr pScreen,
CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv;
dmxCursorPrivPtr pCursorPriv;
DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
pCursorPriv->cursor = (Cursor)0;
pCursorPriv = DMX_GET_CURSOR_PRIV (pCursor, pScreen);
pCursorPriv->cursor = (Cursor) 0;
if (dmxScreen->beDisplay)
dmxBECreateCursor(pScreen, pCursor);
dmxBECreateCursor (pScreen, pCursor);
return TRUE;
}
/** Free \a pCursor on the back-end associated with \a pScreen. */
Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
Bool
dmxBEFreeCursor (ScreenPtr pScreen,
CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV (pCursor, pScreen);
if (pCursorPriv->cursor)
{
XLIB_PROLOGUE (dmxScreen);
XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
XFreeCursor (dmxScreen->beDisplay, pCursorPriv->cursor);
XLIB_EPILOGUE (dmxScreen);
pCursorPriv->cursor = (Cursor) 0;
if (IsAnimCur (pCursor))
@ -336,18 +285,17 @@ Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
}
static Bool
_dmxUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
_dmxUnrealizeCursor (ScreenPtr pScreen,
CursorPtr pCursor)
{
DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n",
pScreen->myNum, pCursor);
dmxBEFreeCursor(pScreen, pCursor);
dmxBEFreeCursor (pScreen, pCursor);
return TRUE;
}
static Bool
dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
dmxRealizeCursor (DeviceIntPtr pDev,
ScreenPtr pScreen,
CursorPtr pCursor)
{
if (pDev == inputInfo.pointer)
return _dmxRealizeCursor (pScreen, pCursor);

View file

@ -543,6 +543,26 @@ dmxInputGrabDeviceReply (ScreenPtr pScreen,
}
/* not in xcb-xinput yet */
#define DMX_XCB_WARP_DEVICE_POINTER 41
typedef struct dmx_xcb_warp_device_pointer_request_t {
uint8_t major_opcode;
uint8_t minor_opcode;
uint16_t length;
xcb_window_t src_win;
xcb_window_t dst_win;
int16_t src_x;
int16_t src_y;
uint16_t src_width;
uint16_t src_height;
int16_t dst_x;
int16_t dst_y;
uint8_t deviceid;
uint8_t pad0;
uint16_t pad1;
} dmx_xcb_warp_device_pointer_request_t;
#define DMX_XCB_INPUT_EXTENDED_GRAB_DEVICE 45
typedef struct dmx_xcb_input_extended_grab_device_request_t {
@ -1507,6 +1527,64 @@ dmxInputUngrabPointer (DMXInputInfo *dmxInput,
}
}
void
dmxInputWarpPointer (DMXInputInfo *dmxInput,
DeviceIntPtr pDevice,
int x,
int y)
{
DMXScreenInfo *dmxScreen = (DMXScreenInfo *) dmxInput;
int i;
for (i = 0; i < dmxInput->numDevs; i++)
{
DeviceIntPtr pExtDevice = dmxInput->devs[i];
dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pExtDevice);
if (pExtDevice->u.master != pDevice)
continue;
if (!pExtDevice->button)
continue;
if (!pDevPriv->active)
continue;
if (pDevPriv->deviceId >= 0)
{
dmx_xcb_warp_device_pointer_request_t warp = {
.src_win = dmxScreen->rootWin,
.dst_win = dmxScreen->rootWin,
.dst_x = x,
.dst_y = y,
.deviceid = pDevPriv->deviceId
};
xcb_protocol_request_t request = {
1,
&xcb_input_id,
DMX_XCB_WARP_DEVICE_POINTER,
FALSE
};
struct iovec vector[] = {
{ &warp, sizeof (warp) }
};
xcb_send_request (dmxScreen->connection,
0,
vector,
&request);
}
else
{
xcb_warp_pointer (dmxScreen->connection,
dmxScreen->rootWin, dmxScreen->rootWin,
0, 0,
0, 0,
x, y);
}
}
}
static void
dmxKeyboardBell (int volume,
DeviceIntPtr pDevice,

View file

@ -94,6 +94,12 @@ dmxInputUngrabPointer (DMXInputInfo *dmxInput,
DeviceIntPtr pDevice,
WindowPtr pWindow);
void
dmxInputWarpPointer (DMXInputInfo *dmxInput,
DeviceIntPtr pDevice,
int x,
int y);
int
dmxInputEnable (DMXInputInfo *dmxInput);