mipointer.c revision eee80088
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
400eee80088Smrg        ) {
401eee80088Smrg            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
402eee80088Smrg            /* Hack for CVE-2023-5380: if we're moving
403eee80088Smrg             * screens PointerWindows[] keeps referring to the
404eee80088Smrg             * old window. If that gets destroyed we have a UAF
405eee80088Smrg             * bug later. Only happens when jumping from a window
406eee80088Smrg             * to the root window on the other screen.
407eee80088Smrg             * Enter/Leave events are incorrect for that case but
408eee80088Smrg             * too niche to fix.
409eee80088Smrg             */
410eee80088Smrg            LeaveWindow(pDev);
411eee80088Smrg            if (master)
412eee80088Smrg                LeaveWindow(master);
413eee80088Smrg            UpdateSpriteForScreen(pDev, pScreen);
414eee80088Smrg    }
41505b261ecSmrg}
41605b261ecSmrg
41735c4bbdfSmrg/**
418ed6184dfSmrg * Synchronize the sprite with the cursor.
41905b261ecSmrg *
42035c4bbdfSmrg * @param pDev The device to sync
42105b261ecSmrg */
42205b261ecSmrgvoid
42335c4bbdfSmrgmiPointerUpdateSprite(DeviceIntPtr pDev)
42405b261ecSmrg{
42535c4bbdfSmrg    ScreenPtr pScreen;
42635c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
42735c4bbdfSmrg    CursorPtr pCursor;
42835c4bbdfSmrg    int x, y, devx, devy;
42935c4bbdfSmrg    miPointerPtr pPointer;
43005b261ecSmrg
4314642e01fSmrg    if (!pDev || !pDev->coreEvents)
43205b261ecSmrg        return;
43305b261ecSmrg
4344642e01fSmrg    pPointer = MIPOINTER(pDev);
4354642e01fSmrg
4366747b715Smrg    if (!pPointer)
4376747b715Smrg        return;
4386747b715Smrg
4394642e01fSmrg    pScreen = pPointer->pScreen;
44005b261ecSmrg    if (!pScreen)
44135c4bbdfSmrg        return;
44205b261ecSmrg
4434642e01fSmrg    x = pPointer->x;
4444642e01fSmrg    y = pPointer->y;
4454642e01fSmrg    devx = pPointer->devx;
4464642e01fSmrg    devy = pPointer->devy;
44705b261ecSmrg
44835c4bbdfSmrg    pScreenPriv = GetScreenPrivate(pScreen);
44905b261ecSmrg    /*
45005b261ecSmrg     * if the cursor has switched screens, disable the sprite
45105b261ecSmrg     * on the old screen
45205b261ecSmrg     */
45335c4bbdfSmrg    if (pScreen != pPointer->pSpriteScreen) {
45435c4bbdfSmrg        if (pPointer->pSpriteScreen) {
45535c4bbdfSmrg            miPointerScreenPtr pOldPriv;
45635c4bbdfSmrg
45735c4bbdfSmrg            pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen);
45835c4bbdfSmrg            if (pPointer->pCursor) {
45935c4bbdfSmrg                (*pOldPriv->spriteFuncs->SetCursor)
46035c4bbdfSmrg                    (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
46135c4bbdfSmrg            }
46235c4bbdfSmrg            (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen,
46335c4bbdfSmrg                                                   FALSE);
46435c4bbdfSmrg        }
46535c4bbdfSmrg        (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
46635c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor)
46735c4bbdfSmrg            (pDev, pScreen, pPointer->pCursor, x, y);
46835c4bbdfSmrg        pPointer->devx = x;
46935c4bbdfSmrg        pPointer->devy = y;
47035c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
47135c4bbdfSmrg        pPointer->pSpriteScreen = pScreen;
47205b261ecSmrg    }
47305b261ecSmrg    /*
47405b261ecSmrg     * if the cursor has changed, display the new one
47505b261ecSmrg     */
47635c4bbdfSmrg    else if (pPointer->pCursor != pPointer->pSpriteCursor) {
47735c4bbdfSmrg        pCursor = pPointer->pCursor;
47835c4bbdfSmrg        if (!pCursor ||
47935c4bbdfSmrg            (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
48035c4bbdfSmrg            pCursor = NullCursor;
48135c4bbdfSmrg        (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
48235c4bbdfSmrg
48335c4bbdfSmrg        pPointer->devx = x;
48435c4bbdfSmrg        pPointer->devy = y;
48535c4bbdfSmrg        pPointer->pSpriteCursor = pPointer->pCursor;
48605b261ecSmrg    }
48735c4bbdfSmrg    else if (x != devx || y != devy) {
48835c4bbdfSmrg        pPointer->devx = x;
48935c4bbdfSmrg        pPointer->devy = y;
49035c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
49135c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
49205b261ecSmrg    }
49305b261ecSmrg}
49405b261ecSmrg
4951b5d61b8Smrg/**
4961b5d61b8Smrg * Invalidate the current sprite and force it to be reloaded on next cursor setting
4971b5d61b8Smrg * operation
4981b5d61b8Smrg *
4991b5d61b8Smrg * @param pDev The device to invalidate the sprite fore
5001b5d61b8Smrg */
5011b5d61b8Smrgvoid
5021b5d61b8SmrgmiPointerInvalidateSprite(DeviceIntPtr pDev)
5031b5d61b8Smrg{
5041b5d61b8Smrg    miPointerPtr pPointer;
5051b5d61b8Smrg
5061b5d61b8Smrg    pPointer = MIPOINTER(pDev);
5071b5d61b8Smrg    pPointer->pSpriteCursor = (CursorPtr) 1;
5081b5d61b8Smrg}
5091b5d61b8Smrg
51035c4bbdfSmrg/**
51135c4bbdfSmrg * Set the device to the coordinates on the given screen.
51235c4bbdfSmrg *
51335c4bbdfSmrg * @param pDev The device to move
51435c4bbdfSmrg * @param screen_no Index of the screen to move to
51535c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
51635c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
51735c4bbdfSmrg */
51805b261ecSmrgvoid
51905b261ecSmrgmiPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
52005b261ecSmrg{
52135c4bbdfSmrg    ScreenPtr pScreen;
52235c4bbdfSmrg    miPointerPtr pPointer;
52305b261ecSmrg
52435c4bbdfSmrg    pPointer = MIPOINTER(pDev);
5254642e01fSmrg
52635c4bbdfSmrg    pScreen = screenInfo.screens[screen_no];
52735c4bbdfSmrg    mieqSwitchScreen(pDev, pScreen, FALSE);
52835c4bbdfSmrg    NewCurrentScreen(pDev, pScreen, x, y);
52905b261ecSmrg
53035c4bbdfSmrg    pPointer->limits.x2 = pScreen->width;
53135c4bbdfSmrg    pPointer->limits.y2 = pScreen->height;
53205b261ecSmrg}
53305b261ecSmrg
53435c4bbdfSmrg/**
53535c4bbdfSmrg * @return The current screen of the given device or NULL.
53635c4bbdfSmrg */
5376747b715SmrgScreenPtr
53805b261ecSmrgmiPointerGetScreen(DeviceIntPtr pDev)
53905b261ecSmrg{
5404642e01fSmrg    miPointerPtr pPointer = MIPOINTER(pDev);
54135c4bbdfSmrg
5424642e01fSmrg    return (pPointer) ? pPointer->pScreen : NULL;
54305b261ecSmrg}
54405b261ecSmrg
5456747b715Smrg/* Controls whether the cursor image should be updated immediately when
5466747b715Smrg   moved (FALSE) or if something else will be responsible for updating
5476747b715Smrg   it later (TRUE).  Returns current setting.
5486747b715Smrg   Caller is responsible for calling OsBlockSignal first.
5496747b715Smrg*/
5506747b715SmrgBool
5516747b715SmrgmiPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
55205b261ecSmrg{
5536747b715Smrg    SetupScreen(pScreen);
5546747b715Smrg    Bool prevWait = pScreenPriv->waitForUpdate;
5556747b715Smrg
5566747b715Smrg    pScreenPriv->waitForUpdate = wait;
5576747b715Smrg    return prevWait;
55805b261ecSmrg}
55905b261ecSmrg
56005b261ecSmrg/* Move the pointer on the current screen,  and update the sprite. */
56105b261ecSmrgstatic void
56235c4bbdfSmrgmiPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
56305b261ecSmrg{
5644642e01fSmrg    miPointerPtr pPointer;
56535c4bbdfSmrg
56605b261ecSmrg    SetupScreen(pScreen);
56705b261ecSmrg
5684642e01fSmrg    pPointer = MIPOINTER(pDev);
5694642e01fSmrg
5704642e01fSmrg    /* Hack: We mustn't call into ->MoveCursor for anything but the
5711b5d61b8Smrg     * VCP, as this may cause a non-HW rendered cursor to be rendered while
5721b5d61b8Smrg     * not holding the input lock. This would race with building the command
5731b5d61b8Smrg     * buffer for other rendering.
5744642e01fSmrg     */
57535c4bbdfSmrg    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer
57635c4bbdfSmrg        &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) {
57735c4bbdfSmrg        pPointer->devx = x;
57835c4bbdfSmrg        pPointer->devy = y;
57935c4bbdfSmrg        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
58035c4bbdfSmrg            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
58105b261ecSmrg    }
58205b261ecSmrg
5834642e01fSmrg    pPointer->x = x;
5844642e01fSmrg    pPointer->y = y;
5854642e01fSmrg    pPointer->pScreen = pScreen;
58605b261ecSmrg}
58705b261ecSmrg
58835c4bbdfSmrg/**
58935c4bbdfSmrg * Set the devices' cursor position to the given x/y position.
59035c4bbdfSmrg *
59135c4bbdfSmrg * This function is called during the pointer update path in
59235c4bbdfSmrg * GetPointerEvents and friends (and the same in the xwin DDX).
59335c4bbdfSmrg *
59435c4bbdfSmrg * The coordinates provided are always absolute. The parameter mode whether
59535c4bbdfSmrg * it was relative or absolute movement that landed us at those coordinates.
59635c4bbdfSmrg *
59735c4bbdfSmrg * If the cursor was constrained by a barrier, ET_Barrier* events may be
59835c4bbdfSmrg * generated and appended to the InternalEvent list provided.
59935c4bbdfSmrg *
60035c4bbdfSmrg * @param pDev The device to move
60135c4bbdfSmrg * @param mode Movement mode (Absolute or Relative)
60235c4bbdfSmrg * @param[in,out] screenx The x coordinate in desktop coordinates
60335c4bbdfSmrg * @param[in,out] screeny The y coordinate in desktop coordinates
60435c4bbdfSmrg * @param[in,out] nevents The number of events in events (before/after)
60535c4bbdfSmrg * @param[in,out] events The list of events before/after being constrained
60635c4bbdfSmrg */
60735c4bbdfSmrgScreenPtr
60835c4bbdfSmrgmiPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
60935c4bbdfSmrg                     double *screeny,
61035c4bbdfSmrg                     int *nevents, InternalEvent* events)
61105b261ecSmrg{
61235c4bbdfSmrg    miPointerScreenPtr pScreenPriv;
61335c4bbdfSmrg    ScreenPtr pScreen;
61435c4bbdfSmrg    ScreenPtr newScreen;
61535c4bbdfSmrg    int x, y;
61635c4bbdfSmrg    Bool switch_screen = FALSE;
61735c4bbdfSmrg    Bool should_constrain_barriers = FALSE;
61835c4bbdfSmrg    int i;
6194642e01fSmrg
62035c4bbdfSmrg    miPointerPtr pPointer;
6216747b715Smrg
6224642e01fSmrg    pPointer = MIPOINTER(pDev);
6234642e01fSmrg    pScreen = pPointer->pScreen;
62435c4bbdfSmrg
62535c4bbdfSmrg    x = trunc(*screenx);
62635c4bbdfSmrg    y = trunc(*screeny);
62735c4bbdfSmrg
62835c4bbdfSmrg    switch_screen = !point_on_screen(pScreen, x, y);
62935c4bbdfSmrg
63035c4bbdfSmrg    /* Switch to per-screen coordinates for CursorOffScreen and
63135c4bbdfSmrg     * Pointer->limits */
63235c4bbdfSmrg    x -= pScreen->x;
63335c4bbdfSmrg    y -= pScreen->y;
63435c4bbdfSmrg
63535c4bbdfSmrg    should_constrain_barriers = (mode == Relative);
63635c4bbdfSmrg
63735c4bbdfSmrg    if (should_constrain_barriers) {
63835c4bbdfSmrg        /* coordinates after clamped to a barrier */
63935c4bbdfSmrg        int constrained_x, constrained_y;
64035c4bbdfSmrg        int current_x, current_y; /* current position in per-screen coord */
64135c4bbdfSmrg
64235c4bbdfSmrg        current_x = MIPOINTER(pDev)->x - pScreen->x;
64335c4bbdfSmrg        current_y = MIPOINTER(pDev)->y - pScreen->y;
64435c4bbdfSmrg
64535c4bbdfSmrg        input_constrain_cursor(pDev, pScreen,
64635c4bbdfSmrg                               current_x, current_y, x, y,
64735c4bbdfSmrg                               &constrained_x, &constrained_y,
64835c4bbdfSmrg                               nevents, events);
64935c4bbdfSmrg
65035c4bbdfSmrg        x = constrained_x;
65135c4bbdfSmrg        y = constrained_y;
65235c4bbdfSmrg    }
65335c4bbdfSmrg
65435c4bbdfSmrg    if (switch_screen) {
65535c4bbdfSmrg        pScreenPriv = GetScreenPrivate(pScreen);
65635c4bbdfSmrg        if (!pPointer->confined) {
65735c4bbdfSmrg            newScreen = pScreen;
65835c4bbdfSmrg            (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
65935c4bbdfSmrg            if (newScreen != pScreen) {
66035c4bbdfSmrg                pScreen = newScreen;
66135c4bbdfSmrg                mieqSwitchScreen(pDev, pScreen, FALSE);
66235c4bbdfSmrg                /* Smash the confine to the new screen */
6634642e01fSmrg                pPointer->limits.x2 = pScreen->width;
6644642e01fSmrg                pPointer->limits.y2 = pScreen->height;
66535c4bbdfSmrg            }
66635c4bbdfSmrg        }
66705b261ecSmrg    }
66805b261ecSmrg    /* Constrain the sprite to the current limits. */
66935c4bbdfSmrg    if (x < pPointer->limits.x1)
67035c4bbdfSmrg        x = pPointer->limits.x1;
67135c4bbdfSmrg    if (x >= pPointer->limits.x2)
67235c4bbdfSmrg        x = pPointer->limits.x2 - 1;
67335c4bbdfSmrg    if (y < pPointer->limits.y1)
67435c4bbdfSmrg        y = pPointer->limits.y1;
67535c4bbdfSmrg    if (y >= pPointer->limits.y2)
67635c4bbdfSmrg        y = pPointer->limits.y2 - 1;
67735c4bbdfSmrg
67835c4bbdfSmrg    if (pScreen->ConstrainCursorHarder)
67935c4bbdfSmrg        pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y);
68035c4bbdfSmrg
68135c4bbdfSmrg    if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
68235c4bbdfSmrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
68335c4bbdfSmrg
68435c4bbdfSmrg    /* check if we generated any barrier events and if so, update root x/y
68535c4bbdfSmrg     * to the fully constrained coords */
68635c4bbdfSmrg    if (should_constrain_barriers) {
68735c4bbdfSmrg        for (i = 0; i < *nevents; i++) {
68835c4bbdfSmrg            if (events[i].any.type == ET_BarrierHit ||
68935c4bbdfSmrg                events[i].any.type == ET_BarrierLeave) {
69035c4bbdfSmrg                events[i].barrier_event.root_x = x;
69135c4bbdfSmrg                events[i].barrier_event.root_y = y;
69235c4bbdfSmrg            }
69335c4bbdfSmrg        }
69435c4bbdfSmrg    }
69505b261ecSmrg
69635c4bbdfSmrg    /* Convert to desktop coordinates again */
69735c4bbdfSmrg    x += pScreen->x;
69835c4bbdfSmrg    y += pScreen->y;
69935c4bbdfSmrg
70035c4bbdfSmrg    /* In the event we actually change screen or we get confined, we just
70135c4bbdfSmrg     * drop the float component on the floor
70235c4bbdfSmrg     * FIXME: only drop remainder for ConstrainCursorHarder, not for screen
70335c4bbdfSmrg     * crossings */
70435c4bbdfSmrg    if (x != trunc(*screenx))
70535c4bbdfSmrg        *screenx = x;
70635c4bbdfSmrg    if (y != trunc(*screeny))
70735c4bbdfSmrg        *screeny = y;
70835c4bbdfSmrg
70935c4bbdfSmrg    return pScreen;
71005b261ecSmrg}
71105b261ecSmrg
71235c4bbdfSmrg/**
71335c4bbdfSmrg * Get the current position of the device in desktop coordinates.
71435c4bbdfSmrg *
715ed6184dfSmrg * @param x Return value for the current x coordinate in desktop coordinates.
716ed6184dfSmrg * @param y Return value for the current y coordinate in desktop coordinates.
71735c4bbdfSmrg */
7186747b715Smrgvoid
71905b261ecSmrgmiPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
72005b261ecSmrg{
7214642e01fSmrg    *x = MIPOINTER(pDev)->x;
7224642e01fSmrg    *y = MIPOINTER(pDev)->y;
72305b261ecSmrg}
72405b261ecSmrg
72535c4bbdfSmrg/**
72635c4bbdfSmrg * Move the device's pointer to the x/y coordinates on the given screen.
72735c4bbdfSmrg * This function generates and enqueues pointer events.
72835c4bbdfSmrg *
72935c4bbdfSmrg * @param pDev The device to move
73035c4bbdfSmrg * @param pScreen The screen the device is on
73135c4bbdfSmrg * @param x The x coordinate in per-screen coordinates
73235c4bbdfSmrg * @param y The y coordinate in per-screen coordinates
73335c4bbdfSmrg */
73405b261ecSmrgvoid
73535c4bbdfSmrgmiPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
73605b261ecSmrg{
73705b261ecSmrg    int i, nevents;
73805b261ecSmrg    int valuators[2];
7399ace9065Smrg    ValuatorMask mask;
74005b261ecSmrg
7416747b715Smrg    miPointerMoveNoEvent(pDev, pScreen, x, y);
74205b261ecSmrg
74305b261ecSmrg    /* generate motion notify */
74405b261ecSmrg    valuators[0] = x;
74505b261ecSmrg    valuators[1] = y;
74605b261ecSmrg
74735c4bbdfSmrg    if (!mipointermove_events) {
74835c4bbdfSmrg        mipointermove_events = InitEventList(GetMaximumEventsNum());
74905b261ecSmrg
75035c4bbdfSmrg        if (!mipointermove_events) {
75105b261ecSmrg            FatalError("Could not allocate event store.\n");
75205b261ecSmrg            return;
75305b261ecSmrg        }
75405b261ecSmrg    }
75505b261ecSmrg
7569ace9065Smrg    valuator_mask_set_range(&mask, 0, 2, valuators);
75735c4bbdfSmrg    nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0,
75835c4bbdfSmrg                               POINTER_SCREEN | POINTER_ABSOLUTE |
75935c4bbdfSmrg                               POINTER_NORAW, &mask);
76005b261ecSmrg
7611b5d61b8Smrg    input_lock();
76205b261ecSmrg    for (i = 0; i < nevents; i++)
76335c4bbdfSmrg        mieqEnqueue(pDev, &mipointermove_events[i]);
7641b5d61b8Smrg    input_unlock();
76505b261ecSmrg}
766