xserver-multidpi/hw/dmx/dmxcursor.c
Keith Packard 9838b7032e Introduce a consistent coding style
This is strictly the application of the script 'x-indent-all.sh'
from util/modular. Compared to the patch that Daniel posted in
January, I've added a few indent flags:

	-bap
	-psl
	-T PrivatePtr
	-T pmWait
	-T _XFUNCPROTOBEGIN
	-T _XFUNCPROTOEND
	-T _X_EXPORT

The typedefs were needed to make the output of sdksyms.sh match the
previous output, otherwise, the code is formatted badly enough that
sdksyms.sh generates incorrect output.

The generated code was compared with the previous version and found to
be essentially identical -- "assert" line numbers and BUILD_TIME were
the only differences found.

The comparison was done with this script:

dir1=$1
dir2=$2

for dir in $dir1 $dir2; do
	(cd $dir && find . -name '*.o' | while read file; do
		dir=`dirname $file`
		base=`basename $file .o`
		dump=$dir/$base.dump
		objdump -d $file > $dump
	done)
done

find $dir1 -name '*.dump' | while read dump; do
	otherdump=`echo $dump | sed "s;$dir1;$dir2;"`
	diff -u $dump $otherdump
done

Signed-off-by: Keith Packard <keithp@keithp.com>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Acked-by: Alan Coopersmith <alan.coopersmith@oracle.com>
2012-03-21 13:54:42 -07:00

1024 lines
32 KiB
C

/*
* Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* David H. Dawes <dawes@xfree86.org>
* Kevin E. Martin <kem@redhat.com>
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \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"
#include "dmxlog.h"
#include "dmxprop.h"
#include "dmxinput.h"
#include "mipointer.h"
#include "windowstr.h"
#include "globals.h"
#include "cursorstr.h"
#include "dixevents.h" /* For GetSpriteCursor() */
#include "inputstr.h" /* for inputInfo.pointer */
#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
static int dmxCursorDoMultiCursors = 1;
/** Turn off support for displaying multiple cursors on overlapped
back-end displays. See #dmxCursorDoMultiCursors. */
void
dmxCursorNoMulti(void)
{
dmxCursorDoMultiCursors = 0;
}
static Bool
dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
{
DMXScreenInfo *dmxScreen;
int i;
int localX = *x;
int localY = *y;
int globalX;
int globalY;
if (screenInfo.numScreens == 1)
return FALSE;
/* On current screen? */
dmxScreen = &dmxScreens[(*ppScreen)->myNum];
if (localX >= 0
&& localX < dmxScreen->rootWidth
&& localY >= 0 && localY < dmxScreen->rootHeight)
return FALSE;
/* Convert to global coordinate space */
globalX = dmxScreen->rootXOrigin + localX;
globalY = dmxScreen->rootYOrigin + localY;
/* Is cursor on the current screen?
* This efficiently exits this routine
* for the most common case. */
if (ppScreen && *ppScreen) {
dmxScreen = &dmxScreens[(*ppScreen)->myNum];
if (globalX >= dmxScreen->rootXOrigin
&& globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
&& globalY >= dmxScreen->rootYOrigin
&& globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
return FALSE;
}
/* Find first screen cursor is on */
for (i = 0; i < dmxNumScreens; i++) {
dmxScreen = &dmxScreens[i];
if (globalX >= dmxScreen->rootXOrigin
&& globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
&& globalY >= dmxScreen->rootYOrigin
&& globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) {
if (dmxScreen->index == (*ppScreen)->myNum)
return FALSE;
*ppScreen = screenInfo.screens[dmxScreen->index];
*x = globalX - dmxScreen->rootXOrigin;
*y = globalY - dmxScreen->rootYOrigin;
return TRUE;
}
}
return FALSE;
}
static void
dmxCrossScreen(ScreenPtr pScreen, Bool entering)
{
}
static void
dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
{
DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
#if 11 /*BP*/
/* This call is depracated. Replace with???? */
miPointerWarpCursor(pDev, pScreen, x, y);
#else
pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE);
#endif
}
miPointerScreenFuncRec dmxPointerCursorFuncs = {
dmxCursorOffScreen,
dmxCrossScreen,
dmxWarpCursor,
NULL,
NULL,
};
/** Create a list of screens that we'll manipulate. */
static int *
dmxSLCreate(void)
{
int *list = malloc(dmxNumScreens * sizeof(*list));
int i;
for (i = 0; i < dmxNumScreens; i++)
list[i] = 1;
return list;
}
/** Free list. */
static void
dmxSLFree(int *list)
{
free(list);
}
/** Find next uninitialized entry in list. */
static int
dmxSLFindNext(int *list)
{
int i;
for (i = 0; i < dmxNumScreens; i++)
if (list[i])
return i;
return -1;
}
/** Make one pass over all the screens and return the number updated. */
static int
dmxTryComputeScreenOrigins(int *screensLeft)
{
ScreenPtr pScreen, refScreen;
DMXScreenInfo *screen;
int i, ref;
int changed = 0;
for (i = 0; i < dmxNumScreens; i++) {
if (!screensLeft[i])
continue;
screen = &dmxScreens[i];
pScreen = screenInfo.screens[i];
switch (screen->where) {
case PosAbsolute:
pScreen->x = screen->whereX;
pScreen->y = screen->whereY;
++changed, screensLeft[i] = 0;
break;
case PosRelative:
ref = screen->whereRefScreen;
if (screensLeft[ref])
break;
refScreen = screenInfo.screens[ref];
pScreen->x = refScreen->x + screen->whereX;
pScreen->y = refScreen->y + screen->whereY;
++changed, screensLeft[i] = 0;
break;
case PosRightOf:
ref = screen->whereRefScreen;
if (screensLeft[ref])
break;
refScreen = screenInfo.screens[ref];
pScreen->x = refScreen->x + refScreen->width;
pScreen->y = refScreen->y;
++changed, screensLeft[i] = 0;
break;
case PosLeftOf:
ref = screen->whereRefScreen;
if (screensLeft[ref])
break;
refScreen = screenInfo.screens[ref];
pScreen->x = refScreen->x - pScreen->width;
pScreen->y = refScreen->y;
++changed, screensLeft[i] = 0;
break;
case PosBelow:
ref = screen->whereRefScreen;
if (screensLeft[ref])
break;
refScreen = screenInfo.screens[ref];
pScreen->x = refScreen->x;
pScreen->y = refScreen->y + refScreen->height;
++changed, screensLeft[i] = 0;
break;
case PosAbove:
ref = screen->whereRefScreen;
if (screensLeft[ref])
break;
refScreen = screenInfo.screens[ref];
pScreen->x = refScreen->x;
pScreen->y = refScreen->y - pScreen->height;
++changed, screensLeft[i] = 0;
break;
case PosNone:
dmxLog(dmxFatal, "No position information for screen %d\n", i);
}
}
return changed;
}
static void
dmxComputeScreenOrigins(void)
{
ScreenPtr pScreen;
int *screensLeft;
int i, ref;
int minX, minY;
/* Compute origins based on
* configuration information. */
screensLeft = dmxSLCreate();
while ((i = dmxSLFindNext(screensLeft)) >= 0) {
while (dmxTryComputeScreenOrigins(screensLeft));
if ((i = dmxSLFindNext(screensLeft)) >= 0) {
/* All of the remaining screens are referencing each other.
* Assign a value to one of them and go through again. This
* guarantees that we will eventually terminate.
*/
ref = dmxScreens[i].whereRefScreen;
pScreen = screenInfo.screens[ref];
pScreen->x = pScreen->y = 0;
screensLeft[ref] = 0;
}
}
dmxSLFree(screensLeft);
/* Justify the topmost and leftmost to
* (0,0). */
minX = screenInfo.screens[0]->x;
minY = screenInfo.screens[0]->y;
for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
if (screenInfo.screens[i]->x < minX)
minX = screenInfo.screens[i]->x;
if (screenInfo.screens[i]->y < minY)
minY = screenInfo.screens[i]->y;
}
if (minX || minY) {
for (i = 0; i < dmxNumScreens; i++) {
screenInfo.screens[i]->x -= minX;
screenInfo.screens[i]->y -= minY;
}
}
}
/** Recompute origin information in the #dmxScreens list. This is
* called from #dmxInitOrigins. */
void
dmxReInitOrigins(void)
{
int i;
if (dmxNumScreens > MAXSCREENS)
dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
dmxNumScreens, MAXSCREENS);
for (i = 0; i < dmxNumScreens; i++) {
DMXScreenInfo *dmxScreen = &dmxScreens[i];
dmxLogOutput(dmxScreen,
"s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
" (be=%dx%d depth=%d bpp=%d)\n",
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
dmxScreen->scrnX, dmxScreen->scrnY,
dmxScreen->rootWidth, dmxScreen->rootHeight,
dmxScreen->rootX, dmxScreen->rootY,
dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
dmxScreen->beWidth, dmxScreen->beHeight,
dmxScreen->beDepth, dmxScreen->beBPP);
}
}
/** Initialize screen origins (and relative position). This is called
* for each server generation. For dynamic reconfiguration, use
* #dmxReInitOrigins() instead. */
void
dmxInitOrigins(void)
{
int i;
if (dmxNumScreens > MAXSCREENS)
dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
dmxNumScreens, MAXSCREENS);
for (i = 0; i < dmxNumScreens; i++) {
DMXScreenInfo *dmxScreen = &dmxScreens[i];
dmxLogOutput(dmxScreen,
"(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
" (be=%dx%d depth=%d bpp=%d)\n",
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
dmxScreen->scrnX, dmxScreen->scrnY,
dmxScreen->rootWidth, dmxScreen->rootHeight,
dmxScreen->rootX, dmxScreen->rootY,
dmxScreen->whereX, dmxScreen->whereY,
dmxScreen->where,
dmxScreen->beWidth, dmxScreen->beHeight,
dmxScreen->beDepth, dmxScreen->beBPP);
}
dmxComputeScreenOrigins();
for (i = 0; i < dmxNumScreens; i++) {
DMXScreenInfo *dmxScreen = &dmxScreens[i];
dmxScreen->rootXOrigin = screenInfo.screens[i]->x;
dmxScreen->rootYOrigin = screenInfo.screens[i]->y;
}
dmxReInitOrigins();
}
/** Returns non-zero if the global \a x, \a y coordinate is on the
* screen window of the \a dmxScreen. */
int
dmxOnScreen(int x, int y, DMXScreenInfo * dmxScreen)
{
#if DMX_CURSOR_DEBUG > 1
dmxLog(dmxDebug,
"dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
dmxScreen->index, x, y,
dmxScreen->rootWidth, dmxScreen->rootHeight,
dmxScreen->rootX, dmxScreen->rootY,
dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
dmxScreen->scrnX, dmxScreen->scrnY);
#endif
if (x >= dmxScreen->rootXOrigin
&& x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
&& y >= dmxScreen->rootYOrigin
&& y < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
return 1;
return 0;
}
/** Returns non-zero if \a a overlaps \a b. */
static int
dmxDoesOverlap(DMXScreenInfo * a, DMXScreenInfo * b)
{
if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin, b))
return 1;
if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin + a->scrnWidth, b))
return 1;
if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, a->rootYOrigin, b))
return 1;
if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
a->rootYOrigin + a->scrnWidth, b))
return 1;
if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin, a))
return 1;
if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin + b->scrnWidth, a))
return 1;
if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, b->rootYOrigin, a))
return 1;
if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
b->rootYOrigin + b->scrnWidth, a))
return 1;
return 0;
}
/** Used with \a dmxInterateOverlap to print out a list of screens which
* overlap each other. */
static void *
dmxPrintOverlap(DMXScreenInfo * dmxScreen, void *closure)
{
DMXScreenInfo *a = closure;
if (dmxScreen != a) {
if (dmxScreen->cursorNotShared)
dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
else
dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
}
return NULL;
}
/** Iterate over the screens which overlap with the \a start screen,
* calling \a f with the \a closure for each argument. Often used with
* #dmxPrintOverlap. */
static void *
dmxIterateOverlap(DMXScreenInfo * start,
void *(*f) (DMXScreenInfo * dmxScreen, void *), void *closure)
{
DMXScreenInfo *pt;
if (!start->over)
return f(start, closure);
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
void *retval;
if ((retval = f(pt, closure)))
return retval;
if (pt == start)
break;
}
return NULL;
}
/** Used with #dmxPropertyIterate to determine if screen \a a is the
* same as the screen \a closure. */
static void *
dmxTestSameDisplay(DMXScreenInfo * a, void *closure)
{
DMXScreenInfo *b = closure;
if (a == b)
return a;
return NULL;
}
/** Detects overlapping dmxScreens and creates circular lists. This
* uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
* the computation only needs to be performed for every server
* generation or dynamic reconfiguration . */
void
dmxInitOverlap(void)
{
int i, j;
DMXScreenInfo *a, *b, *pt;
for (i = 0; i < dmxNumScreens; i++)
dmxScreens[i].over = NULL;
for (i = 0; i < dmxNumScreens; i++) {
a = &dmxScreens[i];
for (j = i + 1; j < dmxNumScreens; j++) {
b = &dmxScreens[j];
if (b->over)
continue;
if (dmxDoesOverlap(a, b)) {
DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
a->index, b->index, a, a->over, b, b->over);
b->over = (a->over ? a->over : a);
a->over = b;
}
}
}
for (i = 0; i < dmxNumScreens; i++) {
a = &dmxScreens[i];
if (!a->over)
continue;
/* Flag all pairs that are on same display */
for (pt = a->over; pt != a; pt = pt->over) {
if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
/* The ->over sets contain the transitive set of screens
* that overlap. For screens that are on the same
* backend display, we only want to exclude pairs of
* screens that mutually overlap on the backend display,
* so we call dmxDoesOverlap, which is stricter than the
* ->over set. */
if (!dmxDoesOverlap(a, pt))
continue;
a->cursorNotShared = 1;
pt->cursorNotShared = 1;
dmxLog(dmxInfo,
"Screen %d and %d overlap on %s\n",
a->index, pt->index, a->name);
}
}
}
for (i = 0; i < dmxNumScreens; i++) {
a = &dmxScreens[i];
if (a->over) {
dmxLogOutput(a, "Overlaps");
dmxIterateOverlap(a, dmxPrintOverlap, a);
dmxLogOutputCont(a, "\n");
}
}
}
/** Create \a pCursor on the back-end associated with \a pScreen. */
void
dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
CursorBitsPtr pBits = pCursor->bits;
Pixmap src, msk;
XColor fg, bg;
XImage *img;
XlibGC gc = NULL;
XGCValues v;
unsigned long m;
int i;
if (!pCursorPriv)
return;
m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
v.function = GXcopy;
v.plane_mask = AllPlanes;
v.foreground = 1L;
v.background = 0L;
v.clip_mask = None;
for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
if (dmxScreen->bePixmapFormats[i].depth == 1) {
/* Create GC in the back-end servers */
gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i],
m, &v);
break;
}
}
if (!gc)
dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
pBits->width, pBits->height, 1);
msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
pBits->width, pBits->height, 1);
img = XCreateImage(dmxScreen->beDisplay,
dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
1, XYBitmap, 0, (char *) pBits->source,
pBits->width, pBits->height,
BitmapPad(dmxScreen->beDisplay), 0);
XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
pBits->width, pBits->height);
XFree(img);
img = XCreateImage(dmxScreen->beDisplay,
dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
1, XYBitmap, 0, (char *) pBits->mask,
pBits->width, pBits->height,
BitmapPad(dmxScreen->beDisplay), 0);
XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
pBits->width, pBits->height);
XFree(img);
fg.red = pCursor->foreRed;
fg.green = pCursor->foreGreen;
fg.blue = pCursor->foreBlue;
bg.red = pCursor->backRed;
bg.green = pCursor->backGreen;
bg.blue = pCursor->backBlue;
pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
src, msk,
&fg, &bg,
pBits->xhot, pBits->yhot);
XFreePixmap(dmxScreen->beDisplay, src);
XFreePixmap(dmxScreen->beDisplay, msk);
XFreeGC(dmxScreen->beDisplay, gc);
dmxSync(dmxScreen, FALSE);
}
static Bool
_dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv;
DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv)));
if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen))
return FALSE;
pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
pCursorPriv->cursor = (Cursor) 0;
if (!dmxScreen->beDisplay)
return TRUE;
dmxBECreateCursor(pScreen, pCursor);
return TRUE;
}
/** Free \a pCursor on the back-end associated with \a pScreen. */
Bool
dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
if (pCursorPriv) {
XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
pCursorPriv->cursor = (Cursor) 0;
return TRUE;
}
return FALSE;
}
static Bool
_dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
if (dmxScreen->beDisplay) {
if (dmxBEFreeCursor(pScreen, pCursor))
free(DMX_GET_CURSOR_PRIV(pCursor, pScreen));
}
DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL);
return TRUE;
}
static void
_dmxMoveCursor(ScreenPtr pScreen, int x, int y)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
int newX = x + dmxScreen->rootX;
int newY = y + dmxScreen->rootY;
if (newX < 0)
newX = 0;
if (newY < 0)
newY = 0;
DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
pScreen->myNum, x, y, newX, newY);
if (dmxScreen->beDisplay) {
XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin,
0, 0, 0, 0, newX, newY);
dmxSync(dmxScreen, TRUE);
}
}
static void
_dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
if (pCursor) {
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) {
if (dmxScreen->beDisplay)
XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
pCursorPriv->cursor);
dmxScreen->cursor = pCursor;
dmxScreen->curCursor = pCursorPriv->cursor;
dmxScreen->cursorVisible = 1;
}
_dmxMoveCursor(pScreen, x, y);
}
else {
if (dmxScreen->beDisplay)
XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
dmxScreen->noCursor);
dmxScreen->cursor = NULL;
dmxScreen->curCursor = (Cursor) 0;
dmxScreen->cursorVisible = 0;
}
if (dmxScreen->beDisplay)
dmxSync(dmxScreen, TRUE);
}
static Bool
dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
DMXScreenInfo *pt;
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
return _dmxRealizeCursor(pScreen, pCursor);
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
if (pt->cursorNotShared)
continue;
_dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
if (pt == start)
break;
}
return TRUE;
}
static Bool
dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
{
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
DMXScreenInfo *pt;
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
return _dmxUnrealizeCursor(pScreen, pCursor);
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
if (pt->cursorNotShared)
continue;
_dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
if (pt == start)
break;
}
return TRUE;
}
static CursorPtr
dmxFindCursor(DMXScreenInfo * start)
{
DMXScreenInfo *pt;
if (!start || !start->over)
return GetSpriteCursor(inputInfo.pointer);
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
if (pt->cursor)
return pt->cursor;
if (pt == start)
break;
}
return GetSpriteCursor(inputInfo.pointer);
}
/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This
* function is usually called via #dmxPointerSpriteFuncs, except during
* reconfiguration when the cursor is repositioned to force an update on
* newley overlapping screens and on screens that no longer overlap.
*
* The coords (x,y) are in global coord space. We'll loop over the
* back-end screens and see if they contain the global coord. If so, call
* _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
*/
void
dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
{
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
DMXScreenInfo *pt;
DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
_dmxMoveCursor(pScreen, x, y);
return;
}
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
if (pt->cursorNotShared)
continue;
if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
if ( /* pt != start && */ !pt->cursorVisible) {
if (!pt->cursor) {
/* This only happens during
* reconfiguration when a new overlap
* occurs. */
CursorPtr pCursor;
if ((pCursor = dmxFindCursor(start)))
_dmxRealizeCursor(screenInfo.screens[pt->index],
pt->cursor = pCursor);
}
_dmxSetCursor(screenInfo.screens[pt->index],
pt->cursor,
x + start->rootXOrigin - pt->rootXOrigin,
y + start->rootYOrigin - pt->rootYOrigin);
}
_dmxMoveCursor(screenInfo.screens[pt->index],
x + start->rootXOrigin - pt->rootXOrigin,
y + start->rootYOrigin - pt->rootYOrigin);
}
else if ( /* pt != start && */ pt->cursorVisible) {
_dmxSetCursor(screenInfo.screens[pt->index],
NULL,
x + start->rootXOrigin - pt->rootXOrigin,
y + start->rootYOrigin - pt->rootYOrigin);
}
if (pt == start)
break;
}
}
static void
dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
int y)
{
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
DMXScreenInfo *pt;
int GX, GY, gx, gy;
DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
pScreen->myNum, start, pCursor, x, y);
/* We do this check here because of two cases:
*
* 1) if a client calls XWarpPointer()
* and Xinerama is not running, we can
* have mi's notion of the pointer
* position out of phase with DMX's
* notion.
*
* 2) if a down button is held while the
* cursor moves outside the root window,
* mi's notion of the pointer position
* is out of phase with DMX's notion and
* the cursor can remain visible when it
* shouldn't be. */
dmxGetGlobalPosition(&GX, &GY);
gx = start->rootXOrigin + x;
gy = start->rootYOrigin + y;
if (x && y && (GX != gx || GY != gy))
dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK);
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
_dmxSetCursor(pScreen, pCursor, x, y);
return;
}
for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
if (pt->cursorNotShared)
continue;
if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
_dmxSetCursor(screenInfo.screens[pt->index], pCursor,
x + start->rootXOrigin - pt->rootXOrigin,
y + start->rootYOrigin - pt->rootYOrigin);
}
else {
_dmxSetCursor(screenInfo.screens[pt->index], NULL,
x + start->rootXOrigin - pt->rootXOrigin,
y + start->rootYOrigin - pt->rootYOrigin);
}
if (pt == start)
break;
}
}
/** This routine is used by the backend input routines to hide the
* cursor on a screen that is being used for relative input. \see
* dmxbackend.c */
void
dmxHideCursor(DMXScreenInfo * dmxScreen)
{
int x, y;
ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
dmxGetGlobalPosition(&x, &y);
_dmxSetCursor(pScreen, NULL, x, y);
}
/** This routine is called during reconfiguration to make sure the
* cursor is visible. */
void
dmxCheckCursor(void)
{
int i;
int x, y;
ScreenPtr pScreen;
DMXScreenInfo *firstScreen;
dmxGetGlobalPosition(&x, &y);
firstScreen = dmxFindFirstScreen(x, y);
DMXDBG2("dmxCheckCursor %d %d\n", x, y);
for (i = 0; i < dmxNumScreens; i++) {
DMXScreenInfo *dmxScreen = &dmxScreens[i];
pScreen = screenInfo.screens[dmxScreen->index];
if (!dmxOnScreen(x, y, dmxScreen)) {
if (firstScreen &&
i == miPointerGetScreen(inputInfo.pointer)->myNum)
miPointerSetScreen(inputInfo.pointer, firstScreen->index, x,
y);
_dmxSetCursor(pScreen, NULL, x - dmxScreen->rootXOrigin,
y - dmxScreen->rootYOrigin);
}
else {
if (!dmxScreen->cursor) {
CursorPtr pCursor;
if ((pCursor = dmxFindCursor(dmxScreen))) {
_dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
}
}
_dmxSetCursor(pScreen, dmxScreen->cursor,
x - dmxScreen->rootXOrigin,
y - dmxScreen->rootYOrigin);
}
}
DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y);
}
static Bool
dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
{
return TRUE;
}
static void
dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
{
}
miPointerSpriteFuncRec dmxPointerSpriteFuncs = {
dmxRealizeCursor,
dmxUnrealizeCursor,
dmxSetCursor,
dmxMoveCursor,
dmxDeviceCursorInitialize,
dmxDeviceCursorCleanup
};