mipointer.c revision 1b5d61b8
105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1989, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg*/
2505b261ecSmrg
2635c4bbdfSmrg/**
2735c4bbdfSmrg * @file
2835c4bbdfSmrg * This file contains functions to move the pointer on the screen and/or
2935c4bbdfSmrg * restrict its movement. These functions are divided into two sets:
3035c4bbdfSmrg * Screen-specific functions that are used as function pointers from other
3135c4bbdfSmrg * parts of the server (and end up heavily wrapped by e.g. animcur and
3235c4bbdfSmrg * xfixes):
3335c4bbdfSmrg *      miPointerConstrainCursor
3435c4bbdfSmrg *      miPointerCursorLimits
3535c4bbdfSmrg *      miPointerDisplayCursor
3635c4bbdfSmrg *      miPointerRealizeCursor
3735c4bbdfSmrg *      miPointerUnrealizeCursor
3835c4bbdfSmrg *      miPointerSetCursorPosition
3935c4bbdfSmrg *      miRecolorCursor
4035c4bbdfSmrg *      miPointerDeviceInitialize
4135c4bbdfSmrg *      miPointerDeviceCleanup
4235c4bbdfSmrg * If wrapped, these are the last element in the wrapping chain. They may
4335c4bbdfSmrg * call into sprite-specific code through further function pointers though.
4435c4bbdfSmrg *
4535c4bbdfSmrg * The second type of functions are those that are directly called by the
4635c4bbdfSmrg * DIX, DDX and some drivers.
4735c4bbdfSmrg */
4835c4bbdfSmrg
4905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5005b261ecSmrg#include <dix-config.h>
5105b261ecSmrg#endif
5205b261ecSmrg
5335c4bbdfSmrg#include   <X11/X.h>
5435c4bbdfSmrg#include   <X11/Xmd.h>
5535c4bbdfSmrg#include   <X11/Xproto.h>
5635c4bbdfSmrg#include   "misc.h"
5735c4bbdfSmrg#include   "windowstr.h"
5835c4bbdfSmrg#include   "pixmapstr.h"
5935c4bbdfSmrg#include   "mi.h"
6035c4bbdfSmrg#include   "scrnintstr.h"
6135c4bbdfSmrg#include   "mipointrst.h"
6235c4bbdfSmrg#include   "cursorstr.h"
6335c4bbdfSmrg#include   "dixstruct.h"
6435c4bbdfSmrg#include   "inputstr.h"
6535c4bbdfSmrg#include   "inpututils.h"
6635c4bbdfSmrg#include   "eventstr.h"
6705b261ecSmrg
681b5d61b8Smrgtypedef struct {
691b5d61b8Smrg    ScreenPtr pScreen;          /* current screen */
701b5d61b8Smrg    ScreenPtr pSpriteScreen;    /* screen containing current sprite */
711b5d61b8Smrg    CursorPtr pCursor;          /* current cursor */
721b5d61b8Smrg    CursorPtr pSpriteCursor;    /* cursor on screen */
731b5d61b8Smrg    BoxRec limits;              /* current constraints */
741b5d61b8Smrg    Bool confined;              /* pointer can't change screens */
751b5d61b8Smrg    int x, y;                   /* hot spot location */
761b5d61b8Smrg    int devx, devy;             /* sprite position */
771b5d61b8Smrg    Bool generateEvent;         /* generate an event during warping? */
781b5d61b8Smrg} miPointerRec, *miPointerPtr;
791b5d61b8Smrg
806747b715SmrgDevPrivateKeyRec miPointerScreenKeyRec;
8105b261ecSmrg
824642e01fSmrg#define GetScreenPrivate(s) ((miPointerScreenPtr) \
834642e01fSmrg    dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey))
8405b261ecSmrg#define SetupScreen(s)	miPointerScreenPtr  pScreenPriv = GetScreenPrivate(s)
8505b261ecSmrg
866747b715SmrgDevPrivateKeyRec miPointerPrivKeyRec;
874642e01fSmrg
884642e01fSmrg#define MIPOINTER(dev) \
8935c4bbdfSmrg    (IsFloating(dev) ? \
904642e01fSmrg        (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \
916747b715Smrg        (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey))
924642e01fSmrg
9335c4bbdfSmrgstatic Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
944642e01fSmrg                                   CursorPtr pCursor);
9535c4bbdfSmrgstatic Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
964642e01fSmrg                                     CursorPtr pCursor);
9735c4bbdfSmrgstatic Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
984642e01fSmrg                                   CursorPtr pCursor);
994642e01fSmrgstatic void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
10035c4bbdfSmrg                                     BoxPtr pBox);
1014642e01fSmrgstatic void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen,
10235c4bbdfSmrg                                  CursorPtr pCursor, BoxPtr pHotBox,
1034642e01fSmrg                                  BoxPtr pTopLeftBox);
10435c4bbdfSmrgstatic Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
10535c4bbdfSmrg                                       int x, int y, Bool generateEvent);
10635c4bbdfSmrgstatic Bool miPointerCloseScreen(ScreenPtr pScreen);
10735c4bbdfSmrgstatic void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
1084642e01fSmrgstatic Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen);
10935c4bbdfSmrgstatic void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
11035c4bbdfSmrgstatic void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x,
11135c4bbdfSmrg                                 int y);
11205b261ecSmrg
11335c4bbdfSmrgstatic InternalEvent *mipointermove_events;   /* for WarpPointer MotionNotifies */
11405b261ecSmrg
1156747b715SmrgBool
11635c4bbdfSmrgmiPointerInitialize(ScreenPtr pScreen,
11735c4bbdfSmrg                    miPointerSpriteFuncPtr spriteFuncs,
11835c4bbdfSmrg                    miPointerScreenFuncPtr screenFuncs, Bool waitForUpdate)
11905b261ecSmrg{
12035c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
12105b261ecSmrg
1226747b715Smrg    if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0))
12335c4bbdfSmrg        return FALSE;
1246747b715Smrg
1256747b715Smrg    if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0))
12635c4bbdfSmrg        return FALSE;
1276747b715Smrg
12835c4bbdfSmrg    pScreenPriv = malloc(sizeof(miPointerScreenRec));
12905b261ecSmrg    if (!pScreenPriv)
13035c4bbdfSmrg        return FALSE;
13105b261ecSmrg    pScreenPriv->spriteFuncs = spriteFuncs;
13205b261ecSmrg    pScreenPriv->screenFuncs = screenFuncs;
13305b261ecSmrg    pScreenPriv->waitForUpdate = waitForUpdate;
13405b261ecSmrg    pScreenPriv->showTransparent = FALSE;
13505b261ecSmrg    pScreenPriv->CloseScreen = pScreen->CloseScreen;
13605b261ecSmrg    pScreen->CloseScreen = miPointerCloseScreen;
1374642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv);
13805b261ecSmrg    /*
13905b261ecSmrg     * set up screen cursor method table
14005b261ecSmrg     */
14105b261ecSmrg    pScreen->ConstrainCursor = miPointerConstrainCursor;
14205b261ecSmrg    pScreen->CursorLimits = miPointerCursorLimits;
14305b261ecSmrg    pScreen->DisplayCursor = miPointerDisplayCursor;
14405b261ecSmrg    pScreen->RealizeCursor = miPointerRealizeCursor;
14505b261ecSmrg    pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
14605b261ecSmrg    pScreen->SetCursorPosition = miPointerSetCursorPosition;
14705b261ecSmrg    pScreen->RecolorCursor = miRecolorCursor;
1484642e01fSmrg    pScreen->DeviceCursorInitialize = miPointerDeviceInitialize;
1494642e01fSmrg    pScreen->DeviceCursorCleanup = miPointerDeviceCleanup;
15005b261ecSmrg
15135c4bbdfSmrg    mipointermove_events = NULL;
15205b261ecSmrg    return TRUE;
15305b261ecSmrg}
15405b261ecSmrg
15535c4bbdfSmrg/**
15635c4bbdfSmrg * Destroy screen-specific information.
15735c4bbdfSmrg *
15835c4bbdfSmrg * @param index Screen index of the screen in screenInfo.screens[]
15935c4bbdfSmrg * @param pScreen The actual screen pointer
16035c4bbdfSmrg */
16105b261ecSmrgstatic Bool
16235c4bbdfSmrgmiPointerCloseScreen(ScreenPtr pScreen)
16305b261ecSmrg{
16405b261ecSmrg    SetupScreen(pScreen);
16505b261ecSmrg
16605b261ecSmrg    pScreen->CloseScreen = pScreenPriv->CloseScreen;
16735c4bbdfSmrg    free((void *) pScreenPriv);
16835c4bbdfSmrg    FreeEventList(mipointermove_events, GetMaximumEventsNum());
16935c4bbdfSmrg    mipointermove_events = NULL;
17035c4bbdfSmrg    return (*pScreen->CloseScreen) (pScreen);
17105b261ecSmrg}
17205b261ecSmrg
17305b261ecSmrg/*
17405b261ecSmrg * DIX/DDX interface routines
17505b261ecSmrg */
17605b261ecSmrg
17705b261ecSmrgstatic Bool
17835c4bbdfSmrgmiPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
17905b261ecSmrg{
18005b261ecSmrg    SetupScreen(pScreen);
1814642e01fSmrg    return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor);
18205b261ecSmrg}
18305b261ecSmrg
18405b261ecSmrgstatic Bool
18535c4bbdfSmrgmiPointerUnrealizeCursor(DeviceIntPtr pDev,
18635c4bbdfSmrg                         ScreenPtr pScreen, CursorPtr pCursor)
18705b261ecSmrg{
18805b261ecSmrg    SetupScreen(pScreen);
18935c4bbdfSmrg    return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen,
19035c4bbdfSmrg                                                         pCursor);
19105b261ecSmrg}
19205b261ecSmrg
19305b261ecSmrgstatic Bool
19435c4bbdfSmrgmiPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
19505b261ecSmrg{
1964642e01fSmrg    miPointerPtr pPointer;
1974642e01fSmrg
1984642e01fSmrg    /* return for keyboards */
19935c4bbdfSmrg    if (!IsPointerDevice(pDev))
20035c4bbdfSmrg        return FALSE;
2014642e01fSmrg
2024642e01fSmrg    pPointer = MIPOINTER(pDev);
2034642e01fSmrg
2044642e01fSmrg    pPointer->pCursor = pCursor;
2054642e01fSmrg    pPointer->pScreen = pScreen;
2064642e01fSmrg    miPointerUpdateSprite(pDev);
20705b261ecSmrg    return TRUE;
20805b261ecSmrg}
20905b261ecSmrg
21035c4bbdfSmrg/**
21135c4bbdfSmrg * Set up the constraints for the given device. This function does not
21235c4bbdfSmrg * actually constrain the cursor but merely copies the given box to the
21335c4bbdfSmrg * internal constraint storage.
21435c4bbdfSmrg *
21535c4bbdfSmrg * @param pDev The device to constrain to the box
21635c4bbdfSmrg * @param pBox The rectangle to constrain the cursor to
21735c4bbdfSmrg * @param pScreen Used for copying screen confinement
21835c4bbdfSmrg */
21905b261ecSmrgstatic void
22035c4bbdfSmrgmiPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox)
22105b261ecSmrg{
2224642e01fSmrg    miPointerPtr pPointer;
2234642e01fSmrg
2244642e01fSmrg    pPointer = MIPOINTER(pDev);
2254642e01fSmrg
2264642e01fSmrg    pPointer->limits = *pBox;
2274642e01fSmrg    pPointer->confined = PointerConfinedToScreen(pDev);
22805b261ecSmrg}
22905b261ecSmrg
23035c4bbdfSmrg/**
23135c4bbdfSmrg * Should calculate the box for the given cursor, based on screen and the
23235c4bbdfSmrg * confinement given. But we assume that whatever box is passed in is valid
23335c4bbdfSmrg * anyway.
23435c4bbdfSmrg *
23535c4bbdfSmrg * @param pDev The device to calculate the cursor limits for
23635c4bbdfSmrg * @param pScreen The screen the confinement happens on
23735c4bbdfSmrg * @param pCursor The screen the confinement happens on
23835c4bbdfSmrg * @param pHotBox The confinement box for the cursor
23935c4bbdfSmrg * @param[out] pTopLeftBox The new confinement box, always *pHotBox.
24035c4bbdfSmrg */
24105b261ecSmrgstatic void
2424642e01fSmrgmiPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
2434642e01fSmrg                      BoxPtr pHotBox, BoxPtr pTopLeftBox)
24405b261ecSmrg{
24505b261ecSmrg    *pTopLeftBox = *pHotBox;
24605b261ecSmrg}
24705b261ecSmrg
24835c4bbdfSmrg/**
24935c4bbdfSmrg * Set the device's cursor position to the x/y position on the given screen.
25035c4bbdfSmrg * Generates and event if required.
25135c4bbdfSmrg *
25235c4bbdfSmrg * This function is called from:
25335c4bbdfSmrg *    - sprite init code to place onto initial position
25435c4bbdfSmrg *    - the various WarpPointer implementations (core, XI, Xinerama, dmx,…)
25535c4bbdfSmrg *    - during the cursor update path in CheckMotion
25635c4bbdfSmrg *    - in the Xinerama part of NewCurrentScreen
25735c4bbdfSmrg *    - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so
25835c4bbdfSmrg *      it's set back to the original pos)
25935c4bbdfSmrg *
26035c4bbdfSmrg * @param pDev The device to move
26135c4bbdfSmrg * @param pScreen The screen the device is on
26235c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
26335c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
26435c4bbdfSmrg * @param generateEvent True if the pointer movement should generate an
26535c4bbdfSmrg * event.
26635c4bbdfSmrg *
26735c4bbdfSmrg * @return TRUE in all cases
26835c4bbdfSmrg */
26905b261ecSmrgstatic Bool
2704642e01fSmrgmiPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
2714642e01fSmrg                           int x, int y, Bool generateEvent)
27205b261ecSmrg{
27335c4bbdfSmrg    SetupScreen(pScreen);
27435c4bbdfSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
27535c4bbdfSmrg
27635c4bbdfSmrg    pPointer->generateEvent = generateEvent;
27735c4bbdfSmrg
27835c4bbdfSmrg    if (pScreen->ConstrainCursorHarder)
27935c4bbdfSmrg        pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y);
28005b261ecSmrg
28105b261ecSmrg    /* device dependent - must pend signal and call miPointerWarpCursor */
2824642e01fSmrg    (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
28305b261ecSmrg    if (!generateEvent)
28435c4bbdfSmrg        miPointerUpdateSprite(pDev);
28505b261ecSmrg    return TRUE;
28605b261ecSmrg}
28705b261ecSmrg
28835c4bbdfSmrgvoid
28935c4bbdfSmrgmiRecolorCursor(DeviceIntPtr pDev, ScreenPtr pScr,
29035c4bbdfSmrg                CursorPtr pCurs, Bool displayed)
29135c4bbdfSmrg{
29235c4bbdfSmrg    /*
29335c4bbdfSmrg     * This is guaranteed to correct any color-dependent state which may have
29435c4bbdfSmrg     * been bound up in private state created by RealizeCursor
29535c4bbdfSmrg     */
29635c4bbdfSmrg    pScr->UnrealizeCursor(pDev, pScr, pCurs);
29735c4bbdfSmrg    pScr->RealizeCursor(pDev, pScr, pCurs);
29835c4bbdfSmrg    if (displayed)
29935c4bbdfSmrg        pScr->DisplayCursor(pDev, pScr, pCurs);
30035c4bbdfSmrg}
30135c4bbdfSmrg
30235c4bbdfSmrg/**
30335c4bbdfSmrg * Set up sprite information for the device.
30435c4bbdfSmrg * This function will be called once for each device after it is initialized
30535c4bbdfSmrg * in the DIX.
30635c4bbdfSmrg *
30735c4bbdfSmrg * @param pDev The newly created device
30835c4bbdfSmrg * @param pScreen The initial sprite scree.
3094642e01fSmrg */
3104642e01fSmrgstatic Bool
3114642e01fSmrgmiPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
3124642e01fSmrg{
3134642e01fSmrg    miPointerPtr pPointer;
31435c4bbdfSmrg
31535c4bbdfSmrg    SetupScreen(pScreen);
3164642e01fSmrg
3176747b715Smrg    pPointer = malloc(sizeof(miPointerRec));
3184642e01fSmrg    if (!pPointer)
3194642e01fSmrg        return FALSE;
3204642e01fSmrg
3214642e01fSmrg    pPointer->pScreen = NULL;
3224642e01fSmrg    pPointer->pSpriteScreen = NULL;
3234642e01fSmrg    pPointer->pCursor = NULL;
3244642e01fSmrg    pPointer->pSpriteCursor = NULL;
3254642e01fSmrg    pPointer->limits.x1 = 0;
3264642e01fSmrg    pPointer->limits.x2 = 32767;
3274642e01fSmrg    pPointer->limits.y1 = 0;
3284642e01fSmrg    pPointer->limits.y2 = 32767;
3294642e01fSmrg    pPointer->confined = FALSE;
3304642e01fSmrg    pPointer->x = 0;
3314642e01fSmrg    pPointer->y = 0;
33235c4bbdfSmrg    pPointer->generateEvent = FALSE;
3334642e01fSmrg
33435c4bbdfSmrg    if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen))) {
3356747b715Smrg        free(pPointer);
3364642e01fSmrg        return FALSE;
3374642e01fSmrg    }
3384642e01fSmrg
3394642e01fSmrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer);
3404642e01fSmrg    return TRUE;
3414642e01fSmrg}
3424642e01fSmrg
34335c4bbdfSmrg/**
34435c4bbdfSmrg * Clean up after device.
34535c4bbdfSmrg * This function will be called once before the device is freed in the DIX
34635c4bbdfSmrg *
34735c4bbdfSmrg * @param pDev The device to be removed from the server
34835c4bbdfSmrg * @param pScreen Current screen of the device
3494642e01fSmrg */
3504642e01fSmrgstatic void
3514642e01fSmrgmiPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
3524642e01fSmrg{
3536747b715Smrg    SetupScreen(pScreen);
3546747b715Smrg
35535c4bbdfSmrg    if (!IsMaster(pDev) && !IsFloating(pDev))
3564642e01fSmrg        return;
3574642e01fSmrg
35835c4bbdfSmrg    (*pScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen);
3596747b715Smrg    free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey));
3604642e01fSmrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL);
3614642e01fSmrg}
3624642e01fSmrg
36335c4bbdfSmrg/**
36435c4bbdfSmrg * Warp the pointer to the given position on the given screen. May generate
36535c4bbdfSmrg * an event, depending on whether we're coming from miPointerSetPosition.
36635c4bbdfSmrg *
36735c4bbdfSmrg * Once signals are ignored, the WarpCursor function can call this
36835c4bbdfSmrg *
36935c4bbdfSmrg * @param pDev The device to warp
37035c4bbdfSmrg * @param pScreen Screen to warp on
37135c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
37235c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
37335c4bbdfSmrg */
37405b261ecSmrg
3756747b715Smrgvoid
37635c4bbdfSmrgmiPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
37705b261ecSmrg{
3784642e01fSmrg    miPointerPtr pPointer;
3794642e01fSmrg    BOOL changedScreen = FALSE;
3804642e01fSmrg
3816747b715Smrg    pPointer = MIPOINTER(pDev);
38205b261ecSmrg
38335c4bbdfSmrg    if (pPointer->pScreen != pScreen) {
38435c4bbdfSmrg        mieqSwitchScreen(pDev, pScreen, TRUE);
3854642e01fSmrg        changedScreen = TRUE;
3864642e01fSmrg    }
38705b261ecSmrg
38835c4bbdfSmrg    if (pPointer->generateEvent)
38935c4bbdfSmrg        miPointerMove(pDev, pScreen, x, y);
39005b261ecSmrg    else
3916747b715Smrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
3924642e01fSmrg
3934642e01fSmrg    /* Don't call USFS if we use Xinerama, otherwise the root window is
3944642e01fSmrg     * updated to the second screen, and we never receive any events.
3954642e01fSmrg     * (FDO bug #18668) */
3964642e01fSmrg    if (changedScreen
3974642e01fSmrg#ifdef PANORAMIX
39835c4bbdfSmrg        && noPanoramiXExtension
3994642e01fSmrg#endif
40035c4bbdfSmrg        )
40135c4bbdfSmrg        UpdateSpriteForScreen(pDev, pScreen);
40205b261ecSmrg}
40305b261ecSmrg
40435c4bbdfSmrg/**
40535c4bbdfSmrg * Syncronize the sprite with the cursor.
40605b261ecSmrg *
40735c4bbdfSmrg * @param pDev The device to sync
40805b261ecSmrg */
40905b261ecSmrgvoid
41035c4bbdfSmrgmiPointerUpdateSprite(DeviceIntPtr pDev)
41105b261ecSmrg{
41235c4bbdfSmrg    ScreenPtr pScreen;
41335c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
41435c4bbdfSmrg    CursorPtr pCursor;
41535c4bbdfSmrg    int x, y, devx, devy;
41635c4bbdfSmrg    miPointerPtr pPointer;
41705b261ecSmrg
4184642e01fSmrg    if (!pDev || !pDev->coreEvents)
41905b261ecSmrg        return;
42005b261ecSmrg
4214642e01fSmrg    pPointer = MIPOINTER(pDev);
4224642e01fSmrg
4236747b715Smrg    if (!pPointer)
4246747b715Smrg        return;
4256747b715Smrg
4264642e01fSmrg    pScreen = pPointer->pScreen;
42705b261ecSmrg    if (!pScreen)
42835c4bbdfSmrg        return;
42905b261ecSmrg
4304642e01fSmrg    x = pPointer->x;
4314642e01fSmrg    y = pPointer->y;
4324642e01fSmrg    devx = pPointer->devx;
4334642e01fSmrg    devy = pPointer->devy;
43405b261ecSmrg
43535c4bbdfSmrg    pScreenPriv = GetScreenPrivate(pScreen);
43605b261ecSmrg    /*
43705b261ecSmrg     * if the cursor has switched screens, disable the sprite
43805b261ecSmrg     * on the old screen
43905b261ecSmrg     */
44035c4bbdfSmrg    if (pScreen != pPointer->pSpriteScreen) {
44135c4bbdfSmrg        if (pPointer->pSpriteScreen) {
44235c4bbdfSmrg            miPointerScreenPtr pOldPriv;
44335c4bbdfSmrg
44435c4bbdfSmrg            pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen);
44535c4bbdfSmrg            if (pPointer->pCursor) {
44635c4bbdfSmrg                (*pOldPriv->spriteFuncs->SetCursor)
44735c4bbdfSmrg                    (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
44835c4bbdfSmrg            }
44935c4bbdfSmrg            (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen,
45035c4bbdfSmrg                                                   FALSE);
45135c4bbdfSmrg        }
45235c4bbdfSmrg        (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
45335c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor)
45435c4bbdfSmrg            (pDev, pScreen, pPointer->pCursor, x, y);
45535c4bbdfSmrg        pPointer->devx = x;
45635c4bbdfSmrg        pPointer->devy = y;
45735c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
45835c4bbdfSmrg        pPointer->pSpriteScreen = pScreen;
45905b261ecSmrg    }
46005b261ecSmrg    /*
46105b261ecSmrg     * if the cursor has changed, display the new one
46205b261ecSmrg     */
46335c4bbdfSmrg    else if (pPointer->pCursor != pPointer->pSpriteCursor) {
46435c4bbdfSmrg        pCursor = pPointer->pCursor;
46535c4bbdfSmrg        if (!pCursor ||
46635c4bbdfSmrg            (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
46735c4bbdfSmrg            pCursor = NullCursor;
46835c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
46935c4bbdfSmrg
47035c4bbdfSmrg        pPointer->devx = x;
47135c4bbdfSmrg        pPointer->devy = y;
47235c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
47305b261ecSmrg    }
47435c4bbdfSmrg    else if (x != devx || y != devy) {
47535c4bbdfSmrg        pPointer->devx = x;
47635c4bbdfSmrg        pPointer->devy = y;
47735c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
47835c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
47905b261ecSmrg    }
48005b261ecSmrg}
48105b261ecSmrg
4821b5d61b8Smrg/**
4831b5d61b8Smrg * Invalidate the current sprite and force it to be reloaded on next cursor setting
4841b5d61b8Smrg * operation
4851b5d61b8Smrg *
4861b5d61b8Smrg * @param pDev The device to invalidate the sprite fore
4871b5d61b8Smrg */
4881b5d61b8Smrgvoid
4891b5d61b8SmrgmiPointerInvalidateSprite(DeviceIntPtr pDev)
4901b5d61b8Smrg{
4911b5d61b8Smrg    miPointerPtr pPointer;
4921b5d61b8Smrg
4931b5d61b8Smrg    pPointer = MIPOINTER(pDev);
4941b5d61b8Smrg    pPointer->pSpriteCursor = (CursorPtr) 1;
4951b5d61b8Smrg}
4961b5d61b8Smrg
49735c4bbdfSmrg/**
49835c4bbdfSmrg * Set the device to the coordinates on the given screen.
49935c4bbdfSmrg *
50035c4bbdfSmrg * @param pDev The device to move
50135c4bbdfSmrg * @param screen_no Index of the screen to move to
50235c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
50335c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
50435c4bbdfSmrg */
50505b261ecSmrgvoid
50605b261ecSmrgmiPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
50705b261ecSmrg{
50835c4bbdfSmrg    ScreenPtr pScreen;
50935c4bbdfSmrg    miPointerPtr pPointer;
51005b261ecSmrg
51135c4bbdfSmrg    pPointer = MIPOINTER(pDev);
5124642e01fSmrg
51335c4bbdfSmrg    pScreen = screenInfo.screens[screen_no];
51435c4bbdfSmrg    mieqSwitchScreen(pDev, pScreen, FALSE);
51535c4bbdfSmrg    NewCurrentScreen(pDev, pScreen, x, y);
51605b261ecSmrg
51735c4bbdfSmrg    pPointer->limits.x2 = pScreen->width;
51835c4bbdfSmrg    pPointer->limits.y2 = pScreen->height;
51905b261ecSmrg}
52005b261ecSmrg
52135c4bbdfSmrg/**
52235c4bbdfSmrg * @return The current screen of the given device or NULL.
52335c4bbdfSmrg */
5246747b715SmrgScreenPtr
52505b261ecSmrgmiPointerGetScreen(DeviceIntPtr pDev)
52605b261ecSmrg{
5274642e01fSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
52835c4bbdfSmrg
5294642e01fSmrg    return (pPointer) ? pPointer->pScreen : NULL;
53005b261ecSmrg}
53105b261ecSmrg
5326747b715Smrg/* Controls whether the cursor image should be updated immediately when
5336747b715Smrg   moved (FALSE) or if something else will be responsible for updating
5346747b715Smrg   it later (TRUE).  Returns current setting.
5356747b715Smrg   Caller is responsible for calling OsBlockSignal first.
5366747b715Smrg*/
5376747b715SmrgBool
5386747b715SmrgmiPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
53905b261ecSmrg{
5406747b715Smrg    SetupScreen(pScreen);
5416747b715Smrg    Bool prevWait = pScreenPriv->waitForUpdate;
5426747b715Smrg
5436747b715Smrg    pScreenPriv->waitForUpdate = wait;
5446747b715Smrg    return prevWait;
54505b261ecSmrg}
54605b261ecSmrg
54705b261ecSmrg/* Move the pointer on the current screen,  and update the sprite. */
54805b261ecSmrgstatic void
54935c4bbdfSmrgmiPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
55005b261ecSmrg{
5514642e01fSmrg    miPointerPtr pPointer;
55235c4bbdfSmrg
55305b261ecSmrg    SetupScreen(pScreen);
55405b261ecSmrg
5554642e01fSmrg    pPointer = MIPOINTER(pDev);
5564642e01fSmrg
5574642e01fSmrg    /* Hack: We mustn't call into ->MoveCursor for anything but the
5581b5d61b8Smrg     * VCP, as this may cause a non-HW rendered cursor to be rendered while
5591b5d61b8Smrg     * not holding the input lock. This would race with building the command
5601b5d61b8Smrg     * buffer for other rendering.
5614642e01fSmrg     */
56235c4bbdfSmrg    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer
56335c4bbdfSmrg        &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) {
56435c4bbdfSmrg        pPointer->devx = x;
56535c4bbdfSmrg        pPointer->devy = y;
56635c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
56735c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
56805b261ecSmrg    }
56905b261ecSmrg
5704642e01fSmrg    pPointer->x = x;
5714642e01fSmrg    pPointer->y = y;
5724642e01fSmrg    pPointer->pScreen = pScreen;
57305b261ecSmrg}
57405b261ecSmrg
57535c4bbdfSmrg/**
57635c4bbdfSmrg * Set the devices' cursor position to the given x/y position.
57735c4bbdfSmrg *
57835c4bbdfSmrg * This function is called during the pointer update path in
57935c4bbdfSmrg * GetPointerEvents and friends (and the same in the xwin DDX).
58035c4bbdfSmrg *
58135c4bbdfSmrg * The coordinates provided are always absolute. The parameter mode whether
58235c4bbdfSmrg * it was relative or absolute movement that landed us at those coordinates.
58335c4bbdfSmrg *
58435c4bbdfSmrg * If the cursor was constrained by a barrier, ET_Barrier* events may be
58535c4bbdfSmrg * generated and appended to the InternalEvent list provided.
58635c4bbdfSmrg *
58735c4bbdfSmrg * @param pDev The device to move
58835c4bbdfSmrg * @param mode Movement mode (Absolute or Relative)
58935c4bbdfSmrg * @param[in,out] screenx The x coordinate in desktop coordinates
59035c4bbdfSmrg * @param[in,out] screeny The y coordinate in desktop coordinates
59135c4bbdfSmrg * @param[in,out] nevents The number of events in events (before/after)
59235c4bbdfSmrg * @param[in,out] events The list of events before/after being constrained
59335c4bbdfSmrg */
59435c4bbdfSmrgScreenPtr
59535c4bbdfSmrgmiPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
59635c4bbdfSmrg                     double *screeny,
59735c4bbdfSmrg                     int *nevents, InternalEvent* events)
59805b261ecSmrg{
59935c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
60035c4bbdfSmrg    ScreenPtr pScreen;
60135c4bbdfSmrg    ScreenPtr newScreen;
60235c4bbdfSmrg    int x, y;
60335c4bbdfSmrg    Bool switch_screen = FALSE;
60435c4bbdfSmrg    Bool should_constrain_barriers = FALSE;
60535c4bbdfSmrg    int i;
6064642e01fSmrg
60735c4bbdfSmrg    miPointerPtr pPointer;
6086747b715Smrg
6094642e01fSmrg    pPointer = MIPOINTER(pDev);
6104642e01fSmrg    pScreen = pPointer->pScreen;
61135c4bbdfSmrg
61235c4bbdfSmrg    x = trunc(*screenx);
61335c4bbdfSmrg    y = trunc(*screeny);
61435c4bbdfSmrg
61535c4bbdfSmrg    switch_screen = !point_on_screen(pScreen, x, y);
61635c4bbdfSmrg
61735c4bbdfSmrg    /* Switch to per-screen coordinates for CursorOffScreen and
61835c4bbdfSmrg     * Pointer->limits */
61935c4bbdfSmrg    x -= pScreen->x;
62035c4bbdfSmrg    y -= pScreen->y;
62135c4bbdfSmrg
62235c4bbdfSmrg    should_constrain_barriers = (mode == Relative);
62335c4bbdfSmrg
62435c4bbdfSmrg    if (should_constrain_barriers) {
62535c4bbdfSmrg        /* coordinates after clamped to a barrier */
62635c4bbdfSmrg        int constrained_x, constrained_y;
62735c4bbdfSmrg        int current_x, current_y; /* current position in per-screen coord */
62835c4bbdfSmrg
62935c4bbdfSmrg        current_x = MIPOINTER(pDev)->x - pScreen->x;
63035c4bbdfSmrg        current_y = MIPOINTER(pDev)->y - pScreen->y;
63135c4bbdfSmrg
63235c4bbdfSmrg        input_constrain_cursor(pDev, pScreen,
63335c4bbdfSmrg                               current_x, current_y, x, y,
63435c4bbdfSmrg                               &constrained_x, &constrained_y,
63535c4bbdfSmrg                               nevents, events);
63635c4bbdfSmrg
63735c4bbdfSmrg        x = constrained_x;
63835c4bbdfSmrg        y = constrained_y;
63935c4bbdfSmrg    }
64035c4bbdfSmrg
64135c4bbdfSmrg    if (switch_screen) {
64235c4bbdfSmrg        pScreenPriv = GetScreenPrivate(pScreen);
64335c4bbdfSmrg        if (!pPointer->confined) {
64435c4bbdfSmrg            newScreen = pScreen;
64535c4bbdfSmrg            (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
64635c4bbdfSmrg            if (newScreen != pScreen) {
64735c4bbdfSmrg                pScreen = newScreen;
64835c4bbdfSmrg                mieqSwitchScreen(pDev, pScreen, FALSE);
64935c4bbdfSmrg                /* Smash the confine to the new screen */
6504642e01fSmrg                pPointer->limits.x2 = pScreen->width;
6514642e01fSmrg                pPointer->limits.y2 = pScreen->height;
65235c4bbdfSmrg            }
65335c4bbdfSmrg        }
65405b261ecSmrg    }
65505b261ecSmrg    /* Constrain the sprite to the current limits. */
65635c4bbdfSmrg    if (x < pPointer->limits.x1)
65735c4bbdfSmrg        x = pPointer->limits.x1;
65835c4bbdfSmrg    if (x >= pPointer->limits.x2)
65935c4bbdfSmrg        x = pPointer->limits.x2 - 1;
66035c4bbdfSmrg    if (y < pPointer->limits.y1)
66135c4bbdfSmrg        y = pPointer->limits.y1;
66235c4bbdfSmrg    if (y >= pPointer->limits.y2)
66335c4bbdfSmrg        y = pPointer->limits.y2 - 1;
66435c4bbdfSmrg
66535c4bbdfSmrg    if (pScreen->ConstrainCursorHarder)
66635c4bbdfSmrg        pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y);
66735c4bbdfSmrg
66835c4bbdfSmrg    if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
66935c4bbdfSmrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
67035c4bbdfSmrg
67135c4bbdfSmrg    /* check if we generated any barrier events and if so, update root x/y
67235c4bbdfSmrg     * to the fully constrained coords */
67335c4bbdfSmrg    if (should_constrain_barriers) {
67435c4bbdfSmrg        for (i = 0; i < *nevents; i++) {
67535c4bbdfSmrg            if (events[i].any.type == ET_BarrierHit ||
67635c4bbdfSmrg                events[i].any.type == ET_BarrierLeave) {
67735c4bbdfSmrg                events[i].barrier_event.root_x = x;
67835c4bbdfSmrg                events[i].barrier_event.root_y = y;
67935c4bbdfSmrg            }
68035c4bbdfSmrg        }
68135c4bbdfSmrg    }
68205b261ecSmrg
68335c4bbdfSmrg    /* Convert to desktop coordinates again */
68435c4bbdfSmrg    x += pScreen->x;
68535c4bbdfSmrg    y += pScreen->y;
68635c4bbdfSmrg
68735c4bbdfSmrg    /* In the event we actually change screen or we get confined, we just
68835c4bbdfSmrg     * drop the float component on the floor
68935c4bbdfSmrg     * FIXME: only drop remainder for ConstrainCursorHarder, not for screen
69035c4bbdfSmrg     * crossings */
69135c4bbdfSmrg    if (x != trunc(*screenx))
69235c4bbdfSmrg        *screenx = x;
69335c4bbdfSmrg    if (y != trunc(*screeny))
69435c4bbdfSmrg        *screeny = y;
69535c4bbdfSmrg
69635c4bbdfSmrg    return pScreen;
69705b261ecSmrg}
69805b261ecSmrg
69935c4bbdfSmrg/**
70035c4bbdfSmrg * Get the current position of the device in desktop coordinates.
70135c4bbdfSmrg *
70235c4bbdfSmrg * @param x Return value for the current x coordinate in desktop coordiates.
70335c4bbdfSmrg * @param y Return value for the current y coordinate in desktop coordiates.
70435c4bbdfSmrg */
7056747b715Smrgvoid
70605b261ecSmrgmiPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
70705b261ecSmrg{
7084642e01fSmrg    *x = MIPOINTER(pDev)->x;
7094642e01fSmrg    *y = MIPOINTER(pDev)->y;
71005b261ecSmrg}
71105b261ecSmrg
71235c4bbdfSmrg/**
71335c4bbdfSmrg * Move the device's pointer to the x/y coordinates on the given screen.
71435c4bbdfSmrg * This function generates and enqueues pointer events.
71535c4bbdfSmrg *
71635c4bbdfSmrg * @param pDev The device to move
71735c4bbdfSmrg * @param pScreen The screen the device is on
71835c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
71935c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
72035c4bbdfSmrg */
72105b261ecSmrgvoid
72235c4bbdfSmrgmiPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
72305b261ecSmrg{
72405b261ecSmrg    int i, nevents;
72505b261ecSmrg    int valuators[2];
7269ace9065Smrg    ValuatorMask mask;
72705b261ecSmrg
7286747b715Smrg    miPointerMoveNoEvent(pDev, pScreen, x, y);
72905b261ecSmrg
73005b261ecSmrg    /* generate motion notify */
73105b261ecSmrg    valuators[0] = x;
73205b261ecSmrg    valuators[1] = y;
73305b261ecSmrg
73435c4bbdfSmrg    if (!mipointermove_events) {
73535c4bbdfSmrg        mipointermove_events = InitEventList(GetMaximumEventsNum());
73605b261ecSmrg
73735c4bbdfSmrg        if (!mipointermove_events) {
73805b261ecSmrg            FatalError("Could not allocate event store.\n");
73905b261ecSmrg            return;
74005b261ecSmrg        }
74105b261ecSmrg    }
74205b261ecSmrg
7439ace9065Smrg    valuator_mask_set_range(&mask, 0, 2, valuators);
74435c4bbdfSmrg    nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0,
74535c4bbdfSmrg                               POINTER_SCREEN | POINTER_ABSOLUTE |
74635c4bbdfSmrg                               POINTER_NORAW, &mask);
74705b261ecSmrg
7481b5d61b8Smrg    input_lock();
74905b261ecSmrg    for (i = 0; i < nevents; i++)
75035c4bbdfSmrg        mieqEnqueue(pDev, &mipointermove_events[i]);
7511b5d61b8Smrg    input_unlock();
75205b261ecSmrg}
753