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