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);
20354b5899cSmrg    if (!pPointer)
20454b5899cSmrg        return FALSE;
2054642e01fSmrg
2064642e01fSmrg    pPointer->pCursor = pCursor;
2074642e01fSmrg    pPointer->pScreen = pScreen;
2084642e01fSmrg    miPointerUpdateSprite(pDev);
20905b261ecSmrg    return TRUE;
21005b261ecSmrg}
21105b261ecSmrg
21235c4bbdfSmrg/**
21335c4bbdfSmrg * Set up the constraints for the given device. This function does not
21435c4bbdfSmrg * actually constrain the cursor but merely copies the given box to the
21535c4bbdfSmrg * internal constraint storage.
21635c4bbdfSmrg *
21735c4bbdfSmrg * @param pDev The device to constrain to the box
21835c4bbdfSmrg * @param pBox The rectangle to constrain the cursor to
21935c4bbdfSmrg * @param pScreen Used for copying screen confinement
22035c4bbdfSmrg */
22105b261ecSmrgstatic void
22235c4bbdfSmrgmiPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox)
22305b261ecSmrg{
2244642e01fSmrg    miPointerPtr pPointer;
2254642e01fSmrg
2264642e01fSmrg    pPointer = MIPOINTER(pDev);
22754b5899cSmrg    if (!pPointer)
22854b5899cSmrg        return;
2294642e01fSmrg
2304642e01fSmrg    pPointer->limits = *pBox;
2314642e01fSmrg    pPointer->confined = PointerConfinedToScreen(pDev);
23205b261ecSmrg}
23305b261ecSmrg
23435c4bbdfSmrg/**
23535c4bbdfSmrg * Should calculate the box for the given cursor, based on screen and the
23635c4bbdfSmrg * confinement given. But we assume that whatever box is passed in is valid
23735c4bbdfSmrg * anyway.
23835c4bbdfSmrg *
23935c4bbdfSmrg * @param pDev The device to calculate the cursor limits for
24035c4bbdfSmrg * @param pScreen The screen the confinement happens on
24135c4bbdfSmrg * @param pCursor The screen the confinement happens on
24235c4bbdfSmrg * @param pHotBox The confinement box for the cursor
24335c4bbdfSmrg * @param[out] pTopLeftBox The new confinement box, always *pHotBox.
24435c4bbdfSmrg */
24505b261ecSmrgstatic void
2464642e01fSmrgmiPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
2474642e01fSmrg                      BoxPtr pHotBox, BoxPtr pTopLeftBox)
24805b261ecSmrg{
24905b261ecSmrg    *pTopLeftBox = *pHotBox;
25005b261ecSmrg}
25105b261ecSmrg
25235c4bbdfSmrg/**
25335c4bbdfSmrg * Set the device's cursor position to the x/y position on the given screen.
25435c4bbdfSmrg * Generates and event if required.
25535c4bbdfSmrg *
25635c4bbdfSmrg * This function is called from:
25735c4bbdfSmrg *    - sprite init code to place onto initial position
25835c4bbdfSmrg *    - the various WarpPointer implementations (core, XI, Xinerama, dmx,…)
25935c4bbdfSmrg *    - during the cursor update path in CheckMotion
26035c4bbdfSmrg *    - in the Xinerama part of NewCurrentScreen
26135c4bbdfSmrg *    - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so
26235c4bbdfSmrg *      it's set back to the original pos)
26335c4bbdfSmrg *
26435c4bbdfSmrg * @param pDev The device to move
26535c4bbdfSmrg * @param pScreen The screen the device is on
26635c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
26735c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
26835c4bbdfSmrg * @param generateEvent True if the pointer movement should generate an
26935c4bbdfSmrg * event.
27035c4bbdfSmrg *
27135c4bbdfSmrg * @return TRUE in all cases
27235c4bbdfSmrg */
27305b261ecSmrgstatic Bool
2744642e01fSmrgmiPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
2754642e01fSmrg                           int x, int y, Bool generateEvent)
27605b261ecSmrg{
27735c4bbdfSmrg    SetupScreen(pScreen);
27835c4bbdfSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
27935c4bbdfSmrg
28054b5899cSmrg    if (!pPointer)
28154b5899cSmrg        return TRUE;
28254b5899cSmrg
28335c4bbdfSmrg    pPointer->generateEvent = generateEvent;
28435c4bbdfSmrg
28535c4bbdfSmrg    if (pScreen->ConstrainCursorHarder)
28635c4bbdfSmrg        pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y);
28705b261ecSmrg
28805b261ecSmrg    /* device dependent - must pend signal and call miPointerWarpCursor */
2894642e01fSmrg    (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
29005b261ecSmrg    if (!generateEvent)
29135c4bbdfSmrg        miPointerUpdateSprite(pDev);
29205b261ecSmrg    return TRUE;
29305b261ecSmrg}
29405b261ecSmrg
29535c4bbdfSmrgvoid
29635c4bbdfSmrgmiRecolorCursor(DeviceIntPtr pDev, ScreenPtr pScr,
29735c4bbdfSmrg                CursorPtr pCurs, Bool displayed)
29835c4bbdfSmrg{
29935c4bbdfSmrg    /*
30035c4bbdfSmrg     * This is guaranteed to correct any color-dependent state which may have
30135c4bbdfSmrg     * been bound up in private state created by RealizeCursor
30235c4bbdfSmrg     */
30335c4bbdfSmrg    pScr->UnrealizeCursor(pDev, pScr, pCurs);
30435c4bbdfSmrg    pScr->RealizeCursor(pDev, pScr, pCurs);
30535c4bbdfSmrg    if (displayed)
30635c4bbdfSmrg        pScr->DisplayCursor(pDev, pScr, pCurs);
30735c4bbdfSmrg}
30835c4bbdfSmrg
30935c4bbdfSmrg/**
31035c4bbdfSmrg * Set up sprite information for the device.
31135c4bbdfSmrg * This function will be called once for each device after it is initialized
31235c4bbdfSmrg * in the DIX.
31335c4bbdfSmrg *
31435c4bbdfSmrg * @param pDev The newly created device
31535c4bbdfSmrg * @param pScreen The initial sprite scree.
3164642e01fSmrg */
3174642e01fSmrgstatic Bool
3184642e01fSmrgmiPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
3194642e01fSmrg{
3204642e01fSmrg    miPointerPtr pPointer;
32135c4bbdfSmrg
32235c4bbdfSmrg    SetupScreen(pScreen);
3234642e01fSmrg
3246747b715Smrg    pPointer = malloc(sizeof(miPointerRec));
3254642e01fSmrg    if (!pPointer)
3264642e01fSmrg        return FALSE;
3274642e01fSmrg
3284642e01fSmrg    pPointer->pScreen = NULL;
3294642e01fSmrg    pPointer->pSpriteScreen = NULL;
3304642e01fSmrg    pPointer->pCursor = NULL;
3314642e01fSmrg    pPointer->pSpriteCursor = NULL;
3324642e01fSmrg    pPointer->limits.x1 = 0;
3334642e01fSmrg    pPointer->limits.x2 = 32767;
3344642e01fSmrg    pPointer->limits.y1 = 0;
3354642e01fSmrg    pPointer->limits.y2 = 32767;
3364642e01fSmrg    pPointer->confined = FALSE;
3374642e01fSmrg    pPointer->x = 0;
3384642e01fSmrg    pPointer->y = 0;
33935c4bbdfSmrg    pPointer->generateEvent = FALSE;
3404642e01fSmrg
34135c4bbdfSmrg    if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen))) {
3426747b715Smrg        free(pPointer);
3434642e01fSmrg        return FALSE;
3444642e01fSmrg    }
3454642e01fSmrg
3464642e01fSmrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer);
3474642e01fSmrg    return TRUE;
3484642e01fSmrg}
3494642e01fSmrg
35035c4bbdfSmrg/**
35135c4bbdfSmrg * Clean up after device.
35235c4bbdfSmrg * This function will be called once before the device is freed in the DIX
35335c4bbdfSmrg *
35435c4bbdfSmrg * @param pDev The device to be removed from the server
35535c4bbdfSmrg * @param pScreen Current screen of the device
3564642e01fSmrg */
3574642e01fSmrgstatic void
3584642e01fSmrgmiPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
3594642e01fSmrg{
3606747b715Smrg    SetupScreen(pScreen);
3616747b715Smrg
36235c4bbdfSmrg    if (!IsMaster(pDev) && !IsFloating(pDev))
3634642e01fSmrg        return;
3644642e01fSmrg
36535c4bbdfSmrg    (*pScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen);
3666747b715Smrg    free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey));
3674642e01fSmrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL);
3684642e01fSmrg}
3694642e01fSmrg
37035c4bbdfSmrg/**
37135c4bbdfSmrg * Warp the pointer to the given position on the given screen. May generate
37235c4bbdfSmrg * an event, depending on whether we're coming from miPointerSetPosition.
37335c4bbdfSmrg *
37435c4bbdfSmrg * Once signals are ignored, the WarpCursor function can call this
37535c4bbdfSmrg *
37635c4bbdfSmrg * @param pDev The device to warp
37735c4bbdfSmrg * @param pScreen Screen to warp on
37835c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
37935c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
38035c4bbdfSmrg */
38105b261ecSmrg
3826747b715Smrgvoid
38335c4bbdfSmrgmiPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
38405b261ecSmrg{
3854642e01fSmrg    miPointerPtr pPointer;
3864642e01fSmrg    BOOL changedScreen = FALSE;
3874642e01fSmrg
3886747b715Smrg    pPointer = MIPOINTER(pDev);
38954b5899cSmrg    if (!pPointer)
39054b5899cSmrg        return;
39105b261ecSmrg
39235c4bbdfSmrg    if (pPointer->pScreen != pScreen) {
39335c4bbdfSmrg        mieqSwitchScreen(pDev, pScreen, TRUE);
3944642e01fSmrg        changedScreen = TRUE;
3954642e01fSmrg    }
39605b261ecSmrg
39735c4bbdfSmrg    if (pPointer->generateEvent)
39835c4bbdfSmrg        miPointerMove(pDev, pScreen, x, y);
39905b261ecSmrg    else
4006747b715Smrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
4014642e01fSmrg
4024642e01fSmrg    /* Don't call USFS if we use Xinerama, otherwise the root window is
4034642e01fSmrg     * updated to the second screen, and we never receive any events.
4044642e01fSmrg     * (FDO bug #18668) */
4054642e01fSmrg    if (changedScreen
4064642e01fSmrg#ifdef PANORAMIX
40735c4bbdfSmrg        && noPanoramiXExtension
4084642e01fSmrg#endif
409eee80088Smrg        ) {
410eee80088Smrg            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
411eee80088Smrg            /* Hack for CVE-2023-5380: if we're moving
412eee80088Smrg             * screens PointerWindows[] keeps referring to the
413eee80088Smrg             * old window. If that gets destroyed we have a UAF
414eee80088Smrg             * bug later. Only happens when jumping from a window
415eee80088Smrg             * to the root window on the other screen.
416eee80088Smrg             * Enter/Leave events are incorrect for that case but
417eee80088Smrg             * too niche to fix.
418eee80088Smrg             */
419eee80088Smrg            LeaveWindow(pDev);
420eee80088Smrg            if (master)
421eee80088Smrg                LeaveWindow(master);
422eee80088Smrg            UpdateSpriteForScreen(pDev, pScreen);
423eee80088Smrg    }
42405b261ecSmrg}
42505b261ecSmrg
42635c4bbdfSmrg/**
427ed6184dfSmrg * Synchronize the sprite with the cursor.
42805b261ecSmrg *
42935c4bbdfSmrg * @param pDev The device to sync
43005b261ecSmrg */
43105b261ecSmrgvoid
43235c4bbdfSmrgmiPointerUpdateSprite(DeviceIntPtr pDev)
43305b261ecSmrg{
43435c4bbdfSmrg    ScreenPtr pScreen;
43535c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
43635c4bbdfSmrg    CursorPtr pCursor;
43735c4bbdfSmrg    int x, y, devx, devy;
43835c4bbdfSmrg    miPointerPtr pPointer;
43905b261ecSmrg
4404642e01fSmrg    if (!pDev || !pDev->coreEvents)
44105b261ecSmrg        return;
44205b261ecSmrg
4434642e01fSmrg    pPointer = MIPOINTER(pDev);
4444642e01fSmrg
4456747b715Smrg    if (!pPointer)
4466747b715Smrg        return;
4476747b715Smrg
4484642e01fSmrg    pScreen = pPointer->pScreen;
44905b261ecSmrg    if (!pScreen)
45035c4bbdfSmrg        return;
45105b261ecSmrg
4524642e01fSmrg    x = pPointer->x;
4534642e01fSmrg    y = pPointer->y;
4544642e01fSmrg    devx = pPointer->devx;
4554642e01fSmrg    devy = pPointer->devy;
45605b261ecSmrg
45735c4bbdfSmrg    pScreenPriv = GetScreenPrivate(pScreen);
45805b261ecSmrg    /*
45905b261ecSmrg     * if the cursor has switched screens, disable the sprite
46005b261ecSmrg     * on the old screen
46105b261ecSmrg     */
46235c4bbdfSmrg    if (pScreen != pPointer->pSpriteScreen) {
46335c4bbdfSmrg        if (pPointer->pSpriteScreen) {
46435c4bbdfSmrg            miPointerScreenPtr pOldPriv;
46535c4bbdfSmrg
46635c4bbdfSmrg            pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen);
46735c4bbdfSmrg            if (pPointer->pCursor) {
46835c4bbdfSmrg                (*pOldPriv->spriteFuncs->SetCursor)
46935c4bbdfSmrg                    (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
47035c4bbdfSmrg            }
47135c4bbdfSmrg            (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen,
47235c4bbdfSmrg                                                   FALSE);
47335c4bbdfSmrg        }
47435c4bbdfSmrg        (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
47535c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor)
47635c4bbdfSmrg            (pDev, pScreen, pPointer->pCursor, x, y);
47735c4bbdfSmrg        pPointer->devx = x;
47835c4bbdfSmrg        pPointer->devy = y;
47935c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
48035c4bbdfSmrg        pPointer->pSpriteScreen = pScreen;
48105b261ecSmrg    }
48205b261ecSmrg    /*
48305b261ecSmrg     * if the cursor has changed, display the new one
48405b261ecSmrg     */
48535c4bbdfSmrg    else if (pPointer->pCursor != pPointer->pSpriteCursor) {
48635c4bbdfSmrg        pCursor = pPointer->pCursor;
48735c4bbdfSmrg        if (!pCursor ||
48835c4bbdfSmrg            (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
48935c4bbdfSmrg            pCursor = NullCursor;
49035c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
49135c4bbdfSmrg
49235c4bbdfSmrg        pPointer->devx = x;
49335c4bbdfSmrg        pPointer->devy = y;
49435c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
49505b261ecSmrg    }
49635c4bbdfSmrg    else if (x != devx || y != devy) {
49735c4bbdfSmrg        pPointer->devx = x;
49835c4bbdfSmrg        pPointer->devy = y;
49935c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
50035c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
50105b261ecSmrg    }
50205b261ecSmrg}
50305b261ecSmrg
5041b5d61b8Smrg/**
5051b5d61b8Smrg * Invalidate the current sprite and force it to be reloaded on next cursor setting
5061b5d61b8Smrg * operation
5071b5d61b8Smrg *
5081b5d61b8Smrg * @param pDev The device to invalidate the sprite fore
5091b5d61b8Smrg */
5101b5d61b8Smrgvoid
5111b5d61b8SmrgmiPointerInvalidateSprite(DeviceIntPtr pDev)
5121b5d61b8Smrg{
5131b5d61b8Smrg    miPointerPtr pPointer;
5141b5d61b8Smrg
5151b5d61b8Smrg    pPointer = MIPOINTER(pDev);
51654b5899cSmrg    if (!pPointer)
51754b5899cSmrg        return;
51854b5899cSmrg
5191b5d61b8Smrg    pPointer->pSpriteCursor = (CursorPtr) 1;
5201b5d61b8Smrg}
5211b5d61b8Smrg
52235c4bbdfSmrg/**
52335c4bbdfSmrg * Set the device to the coordinates on the given screen.
52435c4bbdfSmrg *
52535c4bbdfSmrg * @param pDev The device to move
52635c4bbdfSmrg * @param screen_no Index of the screen to move to
52735c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
52835c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
52935c4bbdfSmrg */
53005b261ecSmrgvoid
53105b261ecSmrgmiPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
53205b261ecSmrg{
53335c4bbdfSmrg    ScreenPtr pScreen;
53435c4bbdfSmrg    miPointerPtr pPointer;
53505b261ecSmrg
53635c4bbdfSmrg    pPointer = MIPOINTER(pDev);
53754b5899cSmrg    if (!pPointer)
53854b5899cSmrg        return;
5394642e01fSmrg
54035c4bbdfSmrg    pScreen = screenInfo.screens[screen_no];
54135c4bbdfSmrg    mieqSwitchScreen(pDev, pScreen, FALSE);
54235c4bbdfSmrg    NewCurrentScreen(pDev, pScreen, x, y);
54305b261ecSmrg
54435c4bbdfSmrg    pPointer->limits.x2 = pScreen->width;
54535c4bbdfSmrg    pPointer->limits.y2 = pScreen->height;
54605b261ecSmrg}
54705b261ecSmrg
54835c4bbdfSmrg/**
54935c4bbdfSmrg * @return The current screen of the given device or NULL.
55035c4bbdfSmrg */
5516747b715SmrgScreenPtr
55205b261ecSmrgmiPointerGetScreen(DeviceIntPtr pDev)
55305b261ecSmrg{
5544642e01fSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
55535c4bbdfSmrg
5564642e01fSmrg    return (pPointer) ? pPointer->pScreen : NULL;
55705b261ecSmrg}
55805b261ecSmrg
5596747b715Smrg/* Controls whether the cursor image should be updated immediately when
5606747b715Smrg   moved (FALSE) or if something else will be responsible for updating
5616747b715Smrg   it later (TRUE).  Returns current setting.
5626747b715Smrg   Caller is responsible for calling OsBlockSignal first.
5636747b715Smrg*/
5646747b715SmrgBool
5656747b715SmrgmiPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
56605b261ecSmrg{
5676747b715Smrg    SetupScreen(pScreen);
5686747b715Smrg    Bool prevWait = pScreenPriv->waitForUpdate;
5696747b715Smrg
5706747b715Smrg    pScreenPriv->waitForUpdate = wait;
5716747b715Smrg    return prevWait;
57205b261ecSmrg}
57305b261ecSmrg
57405b261ecSmrg/* Move the pointer on the current screen,  and update the sprite. */
57505b261ecSmrgstatic void
57635c4bbdfSmrgmiPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
57705b261ecSmrg{
5784642e01fSmrg    miPointerPtr pPointer;
57935c4bbdfSmrg
58005b261ecSmrg    SetupScreen(pScreen);
58105b261ecSmrg
5824642e01fSmrg    pPointer = MIPOINTER(pDev);
58354b5899cSmrg    if (!pPointer)
58454b5899cSmrg        return;
5854642e01fSmrg
5864642e01fSmrg    /* Hack: We mustn't call into ->MoveCursor for anything but the
5871b5d61b8Smrg     * VCP, as this may cause a non-HW rendered cursor to be rendered while
5881b5d61b8Smrg     * not holding the input lock. This would race with building the command
5891b5d61b8Smrg     * buffer for other rendering.
5904642e01fSmrg     */
59135c4bbdfSmrg    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer
59235c4bbdfSmrg        &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) {
59335c4bbdfSmrg        pPointer->devx = x;
59435c4bbdfSmrg        pPointer->devy = y;
59535c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
59635c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
59705b261ecSmrg    }
59805b261ecSmrg
5994642e01fSmrg    pPointer->x = x;
6004642e01fSmrg    pPointer->y = y;
6014642e01fSmrg    pPointer->pScreen = pScreen;
60205b261ecSmrg}
60305b261ecSmrg
60435c4bbdfSmrg/**
60535c4bbdfSmrg * Set the devices' cursor position to the given x/y position.
60635c4bbdfSmrg *
60735c4bbdfSmrg * This function is called during the pointer update path in
60835c4bbdfSmrg * GetPointerEvents and friends (and the same in the xwin DDX).
60935c4bbdfSmrg *
61035c4bbdfSmrg * The coordinates provided are always absolute. The parameter mode whether
61135c4bbdfSmrg * it was relative or absolute movement that landed us at those coordinates.
61235c4bbdfSmrg *
61335c4bbdfSmrg * If the cursor was constrained by a barrier, ET_Barrier* events may be
61435c4bbdfSmrg * generated and appended to the InternalEvent list provided.
61535c4bbdfSmrg *
61635c4bbdfSmrg * @param pDev The device to move
61735c4bbdfSmrg * @param mode Movement mode (Absolute or Relative)
61835c4bbdfSmrg * @param[in,out] screenx The x coordinate in desktop coordinates
61935c4bbdfSmrg * @param[in,out] screeny The y coordinate in desktop coordinates
62035c4bbdfSmrg * @param[in,out] nevents The number of events in events (before/after)
62135c4bbdfSmrg * @param[in,out] events The list of events before/after being constrained
62235c4bbdfSmrg */
62335c4bbdfSmrgScreenPtr
62435c4bbdfSmrgmiPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
62535c4bbdfSmrg                     double *screeny,
62635c4bbdfSmrg                     int *nevents, InternalEvent* events)
62705b261ecSmrg{
62835c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
62935c4bbdfSmrg    ScreenPtr pScreen;
63035c4bbdfSmrg    ScreenPtr newScreen;
63135c4bbdfSmrg    int x, y;
63235c4bbdfSmrg    Bool switch_screen = FALSE;
63335c4bbdfSmrg    Bool should_constrain_barriers = FALSE;
63435c4bbdfSmrg    int i;
6354642e01fSmrg
63635c4bbdfSmrg    miPointerPtr pPointer;
6376747b715Smrg
6384642e01fSmrg    pPointer = MIPOINTER(pDev);
6394642e01fSmrg    pScreen = pPointer->pScreen;
64035c4bbdfSmrg
641d9252ffbSmrg    x = floor(*screenx);
642d9252ffbSmrg    y = floor(*screeny);
64335c4bbdfSmrg
64435c4bbdfSmrg    switch_screen = !point_on_screen(pScreen, x, y);
64535c4bbdfSmrg
64635c4bbdfSmrg    /* Switch to per-screen coordinates for CursorOffScreen and
64735c4bbdfSmrg     * Pointer->limits */
64835c4bbdfSmrg    x -= pScreen->x;
64935c4bbdfSmrg    y -= pScreen->y;
65035c4bbdfSmrg
65135c4bbdfSmrg    should_constrain_barriers = (mode == Relative);
65235c4bbdfSmrg
65335c4bbdfSmrg    if (should_constrain_barriers) {
65435c4bbdfSmrg        /* coordinates after clamped to a barrier */
65535c4bbdfSmrg        int constrained_x, constrained_y;
65635c4bbdfSmrg        int current_x, current_y; /* current position in per-screen coord */
65735c4bbdfSmrg
65835c4bbdfSmrg        current_x = MIPOINTER(pDev)->x - pScreen->x;
65935c4bbdfSmrg        current_y = MIPOINTER(pDev)->y - pScreen->y;
66035c4bbdfSmrg
66135c4bbdfSmrg        input_constrain_cursor(pDev, pScreen,
66235c4bbdfSmrg                               current_x, current_y, x, y,
66335c4bbdfSmrg                               &constrained_x, &constrained_y,
66435c4bbdfSmrg                               nevents, events);
66535c4bbdfSmrg
66635c4bbdfSmrg        x = constrained_x;
66735c4bbdfSmrg        y = constrained_y;
66835c4bbdfSmrg    }
66935c4bbdfSmrg
67035c4bbdfSmrg    if (switch_screen) {
67135c4bbdfSmrg        pScreenPriv = GetScreenPrivate(pScreen);
67235c4bbdfSmrg        if (!pPointer->confined) {
67335c4bbdfSmrg            newScreen = pScreen;
67435c4bbdfSmrg            (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
67535c4bbdfSmrg            if (newScreen != pScreen) {
67635c4bbdfSmrg                pScreen = newScreen;
67735c4bbdfSmrg                mieqSwitchScreen(pDev, pScreen, FALSE);
67835c4bbdfSmrg                /* Smash the confine to the new screen */
6794642e01fSmrg                pPointer->limits.x2 = pScreen->width;
6804642e01fSmrg                pPointer->limits.y2 = pScreen->height;
68135c4bbdfSmrg            }
68235c4bbdfSmrg        }
68305b261ecSmrg    }
68405b261ecSmrg    /* Constrain the sprite to the current limits. */
68535c4bbdfSmrg    if (x < pPointer->limits.x1)
68635c4bbdfSmrg        x = pPointer->limits.x1;
68735c4bbdfSmrg    if (x >= pPointer->limits.x2)
68835c4bbdfSmrg        x = pPointer->limits.x2 - 1;
68935c4bbdfSmrg    if (y < pPointer->limits.y1)
69035c4bbdfSmrg        y = pPointer->limits.y1;
69135c4bbdfSmrg    if (y >= pPointer->limits.y2)
69235c4bbdfSmrg        y = pPointer->limits.y2 - 1;
69335c4bbdfSmrg
69435c4bbdfSmrg    if (pScreen->ConstrainCursorHarder)
69535c4bbdfSmrg        pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y);
69635c4bbdfSmrg
69735c4bbdfSmrg    if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
69835c4bbdfSmrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
69935c4bbdfSmrg
70035c4bbdfSmrg    /* check if we generated any barrier events and if so, update root x/y
70135c4bbdfSmrg     * to the fully constrained coords */
70235c4bbdfSmrg    if (should_constrain_barriers) {
70335c4bbdfSmrg        for (i = 0; i < *nevents; i++) {
70435c4bbdfSmrg            if (events[i].any.type == ET_BarrierHit ||
70535c4bbdfSmrg                events[i].any.type == ET_BarrierLeave) {
70635c4bbdfSmrg                events[i].barrier_event.root_x = x;
70735c4bbdfSmrg                events[i].barrier_event.root_y = y;
70835c4bbdfSmrg            }
70935c4bbdfSmrg        }
71035c4bbdfSmrg    }
71105b261ecSmrg
71235c4bbdfSmrg    /* Convert to desktop coordinates again */
71335c4bbdfSmrg    x += pScreen->x;
71435c4bbdfSmrg    y += pScreen->y;
71535c4bbdfSmrg
71635c4bbdfSmrg    /* In the event we actually change screen or we get confined, we just
71735c4bbdfSmrg     * drop the float component on the floor
71835c4bbdfSmrg     * FIXME: only drop remainder for ConstrainCursorHarder, not for screen
71935c4bbdfSmrg     * crossings */
720d9252ffbSmrg    if (x != floor(*screenx))
72135c4bbdfSmrg        *screenx = x;
722d9252ffbSmrg    if (y != floor(*screeny))
72335c4bbdfSmrg        *screeny = y;
72435c4bbdfSmrg
72535c4bbdfSmrg    return pScreen;
72605b261ecSmrg}
72705b261ecSmrg
72835c4bbdfSmrg/**
72935c4bbdfSmrg * Get the current position of the device in desktop coordinates.
73035c4bbdfSmrg *
731ed6184dfSmrg * @param x Return value for the current x coordinate in desktop coordinates.
732ed6184dfSmrg * @param y Return value for the current y coordinate in desktop coordinates.
73335c4bbdfSmrg */
7346747b715Smrgvoid
73505b261ecSmrgmiPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
73605b261ecSmrg{
73754b5899cSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
73854b5899cSmrg    if (pPointer) {
73954b5899cSmrg        *x = pPointer->x;
74054b5899cSmrg        *y = pPointer->y;
74154b5899cSmrg    }
74254b5899cSmrg    else {
74354b5899cSmrg        *x = 0;
74454b5899cSmrg        *y = 0;
74554b5899cSmrg    }
74605b261ecSmrg}
74705b261ecSmrg
74835c4bbdfSmrg/**
74935c4bbdfSmrg * Move the device's pointer to the x/y coordinates on the given screen.
75035c4bbdfSmrg * This function generates and enqueues pointer events.
75135c4bbdfSmrg *
75235c4bbdfSmrg * @param pDev The device to move
75335c4bbdfSmrg * @param pScreen The screen the device is on
75435c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
75535c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
75635c4bbdfSmrg */
75705b261ecSmrgvoid
75835c4bbdfSmrgmiPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
75905b261ecSmrg{
76005b261ecSmrg    int i, nevents;
76105b261ecSmrg    int valuators[2];
7629ace9065Smrg    ValuatorMask mask;
76305b261ecSmrg
7646747b715Smrg    miPointerMoveNoEvent(pDev, pScreen, x, y);
76505b261ecSmrg
76605b261ecSmrg    /* generate motion notify */
76705b261ecSmrg    valuators[0] = x;
76805b261ecSmrg    valuators[1] = y;
76905b261ecSmrg
77035c4bbdfSmrg    if (!mipointermove_events) {
77135c4bbdfSmrg        mipointermove_events = InitEventList(GetMaximumEventsNum());
77205b261ecSmrg
77335c4bbdfSmrg        if (!mipointermove_events) {
77405b261ecSmrg            FatalError("Could not allocate event store.\n");
77505b261ecSmrg            return;
77605b261ecSmrg        }
77705b261ecSmrg    }
77805b261ecSmrg
7799ace9065Smrg    valuator_mask_set_range(&mask, 0, 2, valuators);
78035c4bbdfSmrg    nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0,
78135c4bbdfSmrg                               POINTER_SCREEN | POINTER_ABSOLUTE |
78235c4bbdfSmrg                               POINTER_NORAW, &mask);
78305b261ecSmrg
7841b5d61b8Smrg    input_lock();
78505b261ecSmrg    for (i = 0; i < nevents; i++)
78635c4bbdfSmrg        mieqEnqueue(pDev, &mipointermove_events[i]);
7871b5d61b8Smrg    input_unlock();
78805b261ecSmrg}
789