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