From 5e633abcca598289d0423d89bb400b41e6417259 Mon Sep 17 00:00:00 2001 From: marha Date: Tue, 15 Mar 2011 21:35:41 +0000 Subject: xserver libX11 libxcb mesa git update 15 Mar 2011 --- xorg-server/mi/mipointer.c | 1386 ++++++++++++++++++++++---------------------- 1 file changed, 698 insertions(+), 688 deletions(-) (limited to 'xorg-server/mi/mipointer.c') diff --git a/xorg-server/mi/mipointer.c b/xorg-server/mi/mipointer.c index 209ea06be..e8ed106ea 100644 --- a/xorg-server/mi/mipointer.c +++ b/xorg-server/mi/mipointer.c @@ -1,688 +1,698 @@ -/* - -Copyright 1989, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. -*/ - -/** - * @file - * This file contains functions to move the pointer on the screen and/or - * restrict its movement. These functions are divided into two sets: - * Screen-specific functions that are used as function pointers from other - * parts of the server (and end up heavily wrapped by e.g. animcur and - * xfixes): - * miPointerConstrainCursor - * miPointerCursorLimits - * miPointerDisplayCursor - * miPointerRealizeCursor - * miPointerUnrealizeCursor - * miPointerSetCursorPosition - * miRecolorCursor - * miPointerDeviceInitialize - * miPointerDeviceCleanup - * If wrapped, these are the last element in the wrapping chain. They may - * call into sprite-specific code through further function pointers though. - * - * The second type of functions are those that are directly called by the - * DIX, DDX and some drivers. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -# include -# include -# include -# include "misc.h" -# include "windowstr.h" -# include "pixmapstr.h" -# include "mi.h" -# include "scrnintstr.h" -# include "mipointrst.h" -# include "cursorstr.h" -# include "dixstruct.h" -# include "inputstr.h" -# include "inpututils.h" - -DevPrivateKeyRec miPointerScreenKeyRec; - -#define GetScreenPrivate(s) ((miPointerScreenPtr) \ - dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) -#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) - -DevPrivateKeyRec miPointerPrivKeyRec; - -#define MIPOINTER(dev) \ - (IsFloating(dev) ? \ - (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ - (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) - -static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor); -static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, - BoxPtr pBox); -static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, - CursorPtr pCursor, BoxPtr pHotBox, - BoxPtr pTopLeftBox); -static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, - Bool generateEvent); -static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); -static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y); -static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); -static void miPointerDeviceCleanup(DeviceIntPtr pDev, - ScreenPtr pScreen); -static void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); - -static EventList* events; /* for WarpPointer MotionNotifies */ - -Bool -miPointerInitialize (ScreenPtr pScreen, - miPointerSpriteFuncPtr spriteFuncs, - miPointerScreenFuncPtr screenFuncs, - Bool waitForUpdate) -{ - miPointerScreenPtr pScreenPriv; - - if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) - return FALSE; - - if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) - return FALSE; - - pScreenPriv = malloc(sizeof (miPointerScreenRec)); - if (!pScreenPriv) - return FALSE; - pScreenPriv->spriteFuncs = spriteFuncs; - pScreenPriv->screenFuncs = screenFuncs; - /* - * check for uninitialized methods - */ - if (!screenFuncs->EnqueueEvent) - screenFuncs->EnqueueEvent = mieqEnqueue; - if (!screenFuncs->NewEventScreen) - screenFuncs->NewEventScreen = mieqSwitchScreen; - pScreenPriv->waitForUpdate = waitForUpdate; - pScreenPriv->showTransparent = FALSE; - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = miPointerCloseScreen; - dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); - /* - * set up screen cursor method table - */ - pScreen->ConstrainCursor = miPointerConstrainCursor; - pScreen->CursorLimits = miPointerCursorLimits; - pScreen->DisplayCursor = miPointerDisplayCursor; - pScreen->RealizeCursor = miPointerRealizeCursor; - pScreen->UnrealizeCursor = miPointerUnrealizeCursor; - pScreen->SetCursorPosition = miPointerSetCursorPosition; - pScreen->RecolorCursor = miRecolorCursor; - pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; - pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; - - events = NULL; - return TRUE; -} - -/** - * Destroy screen-specific information. - * - * @param index Screen index of the screen in screenInfo.screens[] - * @param pScreen The actual screen pointer - */ -static Bool -miPointerCloseScreen (int index, ScreenPtr pScreen) -{ - SetupScreen(pScreen); - - pScreen->CloseScreen = pScreenPriv->CloseScreen; - free((pointer) pScreenPriv); - FreeEventList(events, GetMaximumEventsNum()); - events = NULL; - return (*pScreen->CloseScreen) (index, pScreen); -} - -/* - * DIX/DDX interface routines - */ - -static Bool -miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - SetupScreen(pScreen); - return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); -} - -static Bool -miPointerUnrealizeCursor (DeviceIntPtr pDev, - ScreenPtr pScreen, - CursorPtr pCursor) -{ - SetupScreen(pScreen); - return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); -} - -static Bool -miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - miPointerPtr pPointer; - - /* return for keyboards */ - if (!IsPointerDevice(pDev)) - return FALSE; - - pPointer = MIPOINTER(pDev); - - pPointer->pCursor = pCursor; - pPointer->pScreen = pScreen; - miPointerUpdateSprite(pDev); - return TRUE; -} - -/** - * Set up the constraints for the given device. This function does not - * actually constrain the cursor but merely copies the given box to the - * internal constraint storage. - * - * @param pDev The device to constrain to the box - * @param pBox The rectangle to constrain the cursor to - * @param pScreen Used for copying screen confinement - */ -static void -miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) -{ - miPointerPtr pPointer; - - pPointer = MIPOINTER(pDev); - - pPointer->limits = *pBox; - pPointer->confined = PointerConfinedToScreen(pDev); -} - -/** - * Should calculate the box for the given cursor, based on screen and the - * confinement given. But we assume that whatever box is passed in is valid - * anyway. - * - * @param pDev The device to calculate the cursor limits for - * @param pScreen The screen the confinement happens on - * @param pCursor The screen the confinement happens on - * @param pHotBox The confinement box for the cursor - * @param[out] pTopLeftBox The new confinement box, always *pHotBox. - */ -static void -miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, - BoxPtr pHotBox, BoxPtr pTopLeftBox) -{ - *pTopLeftBox = *pHotBox; -} - -/** - * Set the device's cursor position to the x/y position on the given screen. - * Generates and event if required. - * - * This function is called from: - * - sprite init code to place onto initial position - * - the various WarpPointer implementations (core, XI, Xinerama, dmx,…) - * - during the cursor update path in CheckMotion - * - in the Xinerama part of NewCurrentScreen - * - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so - * it's set back to the original pos) - * - * @param pDev The device to move - * @param pScreen The screen the device is on - * @param x The x coordinate in per-screen coordinates - * @param y The y coordinate in per-screen coordinates - * @param generateEvent True if the pointer movement should generate an - * event. - * - * @return TRUE in all cases - */ -static Bool -miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y, Bool generateEvent) -{ - SetupScreen (pScreen); - miPointerPtr pPointer = MIPOINTER(pDev); - - pPointer->generateEvent = generateEvent; - - /* device dependent - must pend signal and call miPointerWarpCursor */ - (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); - if (!generateEvent) - miPointerUpdateSprite(pDev); - return TRUE; -} - -/** - * Set up sprite information for the device. - * This function will be called once for each device after it is initialized - * in the DIX. - * - * @param pDev The newly created device - * @param pScreen The initial sprite scree. - */ -static Bool -miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - miPointerPtr pPointer; - SetupScreen (pScreen); - - pPointer = malloc(sizeof(miPointerRec)); - if (!pPointer) - return FALSE; - - pPointer->pScreen = NULL; - pPointer->pSpriteScreen = NULL; - pPointer->pCursor = NULL; - pPointer->pSpriteCursor = NULL; - pPointer->limits.x1 = 0; - pPointer->limits.x2 = 32767; - pPointer->limits.y1 = 0; - pPointer->limits.y2 = 32767; - pPointer->confined = FALSE; - pPointer->x = 0; - pPointer->y = 0; - pPointer->generateEvent = FALSE; - - if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) - { - free(pPointer); - return FALSE; - } - - dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); - return TRUE; -} - -/** - * Clean up after device. - * This function will be called once before the device is freed in the DIX - * - * @param pDev The device to be removed from the server - * @param pScreen Current screen of the device - */ -static void -miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SetupScreen(pScreen); - - if (!IsMaster(pDev) && !IsFloating(pDev)) - return; - - (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); - free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); - dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); -} - - -/** - * Warp the pointer to the given position on the given screen. May generate - * an event, depending on whether we're coming from miPointerSetPosition. - * - * Once signals are ignored, the WarpCursor function can call this - * - * @param pDev The device to warp - * @param pScreen Screen to warp on - * @param x The x coordinate in per-screen coordinates - * @param y The y coordinate in per-screen coordinates - */ - -void -miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - miPointerPtr pPointer; - BOOL changedScreen = FALSE; - - SetupScreen (pScreen); - pPointer = MIPOINTER(pDev); - - if (pPointer->pScreen != pScreen) - { - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); - changedScreen = TRUE; - } - - if (pPointer->generateEvent) - miPointerMove (pDev, pScreen, x, y); - else - miPointerMoveNoEvent(pDev, pScreen, x, y); - - /* Don't call USFS if we use Xinerama, otherwise the root window is - * updated to the second screen, and we never receive any events. - * (FDO bug #18668) */ - if (changedScreen -#ifdef PANORAMIX - && noPanoramiXExtension -#endif - ) - UpdateSpriteForScreen (pDev, pScreen) ; -} - -/** - * Syncronize the sprite with the cursor. - * - * @param pDev The device to sync - */ -void -miPointerUpdateSprite (DeviceIntPtr pDev) -{ - ScreenPtr pScreen; - miPointerScreenPtr pScreenPriv; - CursorPtr pCursor; - int x, y, devx, devy; - miPointerPtr pPointer; - - if (!pDev || !pDev->coreEvents) - return; - - pPointer = MIPOINTER(pDev); - - if (!pPointer) - return; - - pScreen = pPointer->pScreen; - if (!pScreen) - return; - - x = pPointer->x; - y = pPointer->y; - devx = pPointer->devx; - devy = pPointer->devy; - - pScreenPriv = GetScreenPrivate (pScreen); - /* - * if the cursor has switched screens, disable the sprite - * on the old screen - */ - if (pScreen != pPointer->pSpriteScreen) - { - if (pPointer->pSpriteScreen) - { - miPointerScreenPtr pOldPriv; - - pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); - if (pPointer->pCursor) - { - (*pOldPriv->spriteFuncs->SetCursor) - (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); - } - (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); - } - (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); - (*pScreenPriv->spriteFuncs->SetCursor) - (pDev, pScreen, pPointer->pCursor, x, y); - pPointer->devx = x; - pPointer->devy = y; - pPointer->pSpriteCursor = pPointer->pCursor; - pPointer->pSpriteScreen = pScreen; - } - /* - * if the cursor has changed, display the new one - */ - else if (pPointer->pCursor != pPointer->pSpriteCursor) - { - pCursor = pPointer->pCursor; - if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) - pCursor = NullCursor; - (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); - - pPointer->devx = x; - pPointer->devy = y; - pPointer->pSpriteCursor = pPointer->pCursor; - } - else if (x != devx || y != devy) - { - pPointer->devx = x; - pPointer->devy = y; - if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) - (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); - } -} - -/** - * Set the device to the coordinates on the given screen. - * - * @param pDev The device to move - * @param screen_no Index of the screen to move to - * @param x The x coordinate in per-screen coordinates - * @param y The y coordinate in per-screen coordinates - */ -void -miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) -{ - miPointerScreenPtr pScreenPriv; - ScreenPtr pScreen; - miPointerPtr pPointer; - - pPointer = MIPOINTER(pDev); - - pScreen = screenInfo.screens[screen_no]; - pScreenPriv = GetScreenPrivate (pScreen); - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); - NewCurrentScreen (pDev, pScreen, x, y); - - pPointer->limits.x2 = pScreen->width; - pPointer->limits.y2 = pScreen->height; -} - -/** - * @return The current screen of the VCP - */ -ScreenPtr -miPointerCurrentScreen (void) -{ - return miPointerGetScreen(inputInfo.pointer); -} - -/** - * @return The current screen of the given device or NULL. - */ -ScreenPtr -miPointerGetScreen(DeviceIntPtr pDev) -{ - miPointerPtr pPointer = MIPOINTER(pDev); - return (pPointer) ? pPointer->pScreen : NULL; -} - -/* Controls whether the cursor image should be updated immediately when - moved (FALSE) or if something else will be responsible for updating - it later (TRUE). Returns current setting. - Caller is responsible for calling OsBlockSignal first. -*/ -Bool -miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) -{ - SetupScreen(pScreen); - Bool prevWait = pScreenPriv->waitForUpdate; - - pScreenPriv->waitForUpdate = wait; - return prevWait; -} - - -/* Move the pointer on the current screen, and update the sprite. */ -static void -miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, - int x, int y) -{ - miPointerPtr pPointer; - SetupScreen(pScreen); - - pPointer = MIPOINTER(pDev); - - /* Hack: We mustn't call into ->MoveCursor for anything but the - * VCP, as this may cause a non-HW rendered cursor to be rendered during - * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. - */ - if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer - && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) - { - pPointer->devx = x; - pPointer->devy = y; - if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) - (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); - } - - pPointer->x = x; - pPointer->y = y; - pPointer->pScreen = pScreen; -} - -/** - * Set the devices' cursor position to the given x/y position. - * - * This function is called during the pointer update path in - * GetPointerEvents and friends (and the same in the xwin DDX). - * - * @param pDev The device to move - * @param[in,out] x The x coordiante in screen coordinates (in regards to total - * desktop size) - * @param[in,out] y The y coordiante in screen coordinates (in regards to total - * desktop size) - */ -void -miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) -{ - miPointerScreenPtr pScreenPriv; - ScreenPtr pScreen; - ScreenPtr newScreen; - - miPointerPtr pPointer; - - if (!pDev || !pDev->coreEvents) - return; - - pPointer = MIPOINTER(pDev); - pScreen = pPointer->pScreen; - if (!pScreen) - return; /* called before ready */ - - if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) - { - pScreenPriv = GetScreenPrivate (pScreen); - if (!pPointer->confined) - { - newScreen = pScreen; - (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); - if (newScreen != pScreen) - { - pScreen = newScreen; - (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, - FALSE); - pScreenPriv = GetScreenPrivate (pScreen); - /* Smash the confine to the new screen */ - pPointer->limits.x2 = pScreen->width; - pPointer->limits.y2 = pScreen->height; - } - } - } - /* Constrain the sprite to the current limits. */ - if (*x < pPointer->limits.x1) - *x = pPointer->limits.x1; - if (*x >= pPointer->limits.x2) - *x = pPointer->limits.x2 - 1; - if (*y < pPointer->limits.y1) - *y = pPointer->limits.y1; - if (*y >= pPointer->limits.y2) - *y = pPointer->limits.y2 - 1; - - if (pPointer->x == *x && pPointer->y == *y && - pPointer->pScreen == pScreen) - return; - - miPointerMoveNoEvent(pDev, pScreen, *x, *y); -} - -/** - * Get the current position of the device in desktop coordinates. - * - * @param x Return value for the current x coordinate in desktop coordiates. - * @param y Return value for the current y coordinate in desktop coordiates. - */ -void -miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) -{ - *x = MIPOINTER(pDev)->x; - *y = MIPOINTER(pDev)->y; -} - -#ifdef XQUARTZ -#include -void darwinEvents_lock(void); -void darwinEvents_unlock(void); -#endif - -/** - * Move the device's pointer to the x/y coordinates on the given screen. - * This function generates and enqueues pointer events. - * - * @param pDev The device to move - * @param pScreen The screen the device is on - * @param x The x coordinate in per-screen coordinates - * @param y The y coordinate in per-screen coordinates - */ -void -miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - int i, nevents; - int valuators[2]; - ValuatorMask mask; - - miPointerMoveNoEvent(pDev, pScreen, x, y); - - /* generate motion notify */ - valuators[0] = x; - valuators[1] = y; - - if (!events) - { - events = InitEventList(GetMaximumEventsNum()); - - if (!events) - { - FatalError("Could not allocate event store.\n"); - return; - } - } - - valuator_mask_set_range(&mask, 0, 2, valuators); - nevents = GetPointerEvents(events, pDev, MotionNotify, 0, - POINTER_SCREEN | POINTER_ABSOLUTE, &mask); - - OsBlockSignals(); -#ifdef XQUARTZ - darwinEvents_lock(); -#endif - for (i = 0; i < nevents; i++) - mieqEnqueue(pDev, (InternalEvent*)events[i].event); -#ifdef XQUARTZ - darwinEvents_unlock(); -#endif - OsReleaseSignals(); -} +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +/** + * @file + * This file contains functions to move the pointer on the screen and/or + * restrict its movement. These functions are divided into two sets: + * Screen-specific functions that are used as function pointers from other + * parts of the server (and end up heavily wrapped by e.g. animcur and + * xfixes): + * miPointerConstrainCursor + * miPointerCursorLimits + * miPointerDisplayCursor + * miPointerRealizeCursor + * miPointerUnrealizeCursor + * miPointerSetCursorPosition + * miRecolorCursor + * miPointerDeviceInitialize + * miPointerDeviceCleanup + * If wrapped, these are the last element in the wrapping chain. They may + * call into sprite-specific code through further function pointers though. + * + * The second type of functions are those that are directly called by the + * DIX, DDX and some drivers. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +# include +# include +# include +# include "misc.h" +# include "windowstr.h" +# include "pixmapstr.h" +# include "mi.h" +# include "scrnintstr.h" +# include "mipointrst.h" +# include "cursorstr.h" +# include "dixstruct.h" +# include "inputstr.h" +# include "inpututils.h" + +DevPrivateKeyRec miPointerScreenKeyRec; + +#define GetScreenPrivate(s) ((miPointerScreenPtr) \ + dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) +#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) + +DevPrivateKeyRec miPointerPrivKeyRec; + +#define MIPOINTER(dev) \ + (IsFloating(dev) ? \ + (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ + (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) + +static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + BoxPtr pBox); +static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, BoxPtr pHotBox, + BoxPtr pTopLeftBox); +static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, + Bool generateEvent); +static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); +static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); +static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); +static void miPointerDeviceCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); + +static EventList* events; /* for WarpPointer MotionNotifies */ + +Bool +miPointerInitialize (ScreenPtr pScreen, + miPointerSpriteFuncPtr spriteFuncs, + miPointerScreenFuncPtr screenFuncs, + Bool waitForUpdate) +{ + miPointerScreenPtr pScreenPriv; + + if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) + return FALSE; + + pScreenPriv = malloc(sizeof (miPointerScreenRec)); + if (!pScreenPriv) + return FALSE; + pScreenPriv->spriteFuncs = spriteFuncs; + pScreenPriv->screenFuncs = screenFuncs; + /* + * check for uninitialized methods + */ + if (!screenFuncs->EnqueueEvent) + screenFuncs->EnqueueEvent = mieqEnqueue; + if (!screenFuncs->NewEventScreen) + screenFuncs->NewEventScreen = mieqSwitchScreen; + pScreenPriv->waitForUpdate = waitForUpdate; + pScreenPriv->showTransparent = FALSE; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = miPointerCloseScreen; + dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); + /* + * set up screen cursor method table + */ + pScreen->ConstrainCursor = miPointerConstrainCursor; + pScreen->CursorLimits = miPointerCursorLimits; + pScreen->DisplayCursor = miPointerDisplayCursor; + pScreen->RealizeCursor = miPointerRealizeCursor; + pScreen->UnrealizeCursor = miPointerUnrealizeCursor; + pScreen->SetCursorPosition = miPointerSetCursorPosition; + pScreen->RecolorCursor = miRecolorCursor; + pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; + pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; + + events = NULL; + return TRUE; +} + +/** + * Destroy screen-specific information. + * + * @param index Screen index of the screen in screenInfo.screens[] + * @param pScreen The actual screen pointer + */ +static Bool +miPointerCloseScreen (int index, ScreenPtr pScreen) +{ + SetupScreen(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + free((pointer) pScreenPriv); + FreeEventList(events, GetMaximumEventsNum()); + events = NULL; + return (*pScreen->CloseScreen) (index, pScreen); +} + +/* + * DIX/DDX interface routines + */ + +static Bool +miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerUnrealizeCursor (DeviceIntPtr pDev, + ScreenPtr pScreen, + CursorPtr pCursor) +{ + SetupScreen(pScreen); + return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); +} + +static Bool +miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miPointerPtr pPointer; + + /* return for keyboards */ + if (!IsPointerDevice(pDev)) + return FALSE; + + pPointer = MIPOINTER(pDev); + + pPointer->pCursor = pCursor; + pPointer->pScreen = pScreen; + miPointerUpdateSprite(pDev); + return TRUE; +} + +/** + * Set up the constraints for the given device. This function does not + * actually constrain the cursor but merely copies the given box to the + * internal constraint storage. + * + * @param pDev The device to constrain to the box + * @param pBox The rectangle to constrain the cursor to + * @param pScreen Used for copying screen confinement + */ +static void +miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) +{ + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pPointer->limits = *pBox; + pPointer->confined = PointerConfinedToScreen(pDev); +} + +/** + * Should calculate the box for the given cursor, based on screen and the + * confinement given. But we assume that whatever box is passed in is valid + * anyway. + * + * @param pDev The device to calculate the cursor limits for + * @param pScreen The screen the confinement happens on + * @param pCursor The screen the confinement happens on + * @param pHotBox The confinement box for the cursor + * @param[out] pTopLeftBox The new confinement box, always *pHotBox. + */ +static void +miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox) +{ + *pTopLeftBox = *pHotBox; +} + +/** + * Set the device's cursor position to the x/y position on the given screen. + * Generates and event if required. + * + * This function is called from: + * - sprite init code to place onto initial position + * - the various WarpPointer implementations (core, XI, Xinerama, dmx,…) + * - during the cursor update path in CheckMotion + * - in the Xinerama part of NewCurrentScreen + * - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so + * it's set back to the original pos) + * + * @param pDev The device to move + * @param pScreen The screen the device is on + * @param x The x coordinate in per-screen coordinates + * @param y The y coordinate in per-screen coordinates + * @param generateEvent True if the pointer movement should generate an + * event. + * + * @return TRUE in all cases + */ +static Bool +miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y, Bool generateEvent) +{ + SetupScreen (pScreen); + miPointerPtr pPointer = MIPOINTER(pDev); + + pPointer->generateEvent = generateEvent; + + if (pScreen->ConstrainCursorHarder) + pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y); + + /* device dependent - must pend signal and call miPointerWarpCursor */ + (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); + if (!generateEvent) + miPointerUpdateSprite(pDev); + return TRUE; +} + +/** + * Set up sprite information for the device. + * This function will be called once for each device after it is initialized + * in the DIX. + * + * @param pDev The newly created device + * @param pScreen The initial sprite scree. + */ +static Bool +miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miPointerPtr pPointer; + SetupScreen (pScreen); + + pPointer = malloc(sizeof(miPointerRec)); + if (!pPointer) + return FALSE; + + pPointer->pScreen = NULL; + pPointer->pSpriteScreen = NULL; + pPointer->pCursor = NULL; + pPointer->pSpriteCursor = NULL; + pPointer->limits.x1 = 0; + pPointer->limits.x2 = 32767; + pPointer->limits.y1 = 0; + pPointer->limits.y2 = 32767; + pPointer->confined = FALSE; + pPointer->x = 0; + pPointer->y = 0; + pPointer->generateEvent = FALSE; + + if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) + { + free(pPointer); + return FALSE; + } + + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); + return TRUE; +} + +/** + * Clean up after device. + * This function will be called once before the device is freed in the DIX + * + * @param pDev The device to be removed from the server + * @param pScreen Current screen of the device + */ +static void +miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SetupScreen(pScreen); + + if (!IsMaster(pDev) && !IsFloating(pDev)) + return; + + (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); + free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); + dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); +} + + +/** + * Warp the pointer to the given position on the given screen. May generate + * an event, depending on whether we're coming from miPointerSetPosition. + * + * Once signals are ignored, the WarpCursor function can call this + * + * @param pDev The device to warp + * @param pScreen Screen to warp on + * @param x The x coordinate in per-screen coordinates + * @param y The y coordinate in per-screen coordinates + */ + +void +miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + miPointerPtr pPointer; + BOOL changedScreen = FALSE; + + SetupScreen (pScreen); + pPointer = MIPOINTER(pDev); + + if (pPointer->pScreen != pScreen) + { + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); + changedScreen = TRUE; + } + + if (pPointer->generateEvent) + miPointerMove (pDev, pScreen, x, y); + else + miPointerMoveNoEvent(pDev, pScreen, x, y); + + /* Don't call USFS if we use Xinerama, otherwise the root window is + * updated to the second screen, and we never receive any events. + * (FDO bug #18668) */ + if (changedScreen +#ifdef PANORAMIX + && noPanoramiXExtension +#endif + ) + UpdateSpriteForScreen (pDev, pScreen) ; +} + +/** + * Syncronize the sprite with the cursor. + * + * @param pDev The device to sync + */ +void +miPointerUpdateSprite (DeviceIntPtr pDev) +{ + ScreenPtr pScreen; + miPointerScreenPtr pScreenPriv; + CursorPtr pCursor; + int x, y, devx, devy; + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + + if (!pPointer) + return; + + pScreen = pPointer->pScreen; + if (!pScreen) + return; + + x = pPointer->x; + y = pPointer->y; + devx = pPointer->devx; + devy = pPointer->devy; + + pScreenPriv = GetScreenPrivate (pScreen); + /* + * if the cursor has switched screens, disable the sprite + * on the old screen + */ + if (pScreen != pPointer->pSpriteScreen) + { + if (pPointer->pSpriteScreen) + { + miPointerScreenPtr pOldPriv; + + pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); + if (pPointer->pCursor) + { + (*pOldPriv->spriteFuncs->SetCursor) + (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); + } + (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); + } + (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); + (*pScreenPriv->spriteFuncs->SetCursor) + (pDev, pScreen, pPointer->pCursor, x, y); + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + pPointer->pSpriteScreen = pScreen; + } + /* + * if the cursor has changed, display the new one + */ + else if (pPointer->pCursor != pPointer->pSpriteCursor) + { + pCursor = pPointer->pCursor; + if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) + pCursor = NullCursor; + (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); + + pPointer->devx = x; + pPointer->devy = y; + pPointer->pSpriteCursor = pPointer->pCursor; + } + else if (x != devx || y != devy) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } +} + +/** + * Set the device to the coordinates on the given screen. + * + * @param pDev The device to move + * @param screen_no Index of the screen to move to + * @param x The x coordinate in per-screen coordinates + * @param y The y coordinate in per-screen coordinates + */ +void +miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + miPointerPtr pPointer; + + pPointer = MIPOINTER(pDev); + + pScreen = screenInfo.screens[screen_no]; + pScreenPriv = GetScreenPrivate (pScreen); + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); + NewCurrentScreen (pDev, pScreen, x, y); + + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; +} + +/** + * @return The current screen of the VCP + */ +ScreenPtr +miPointerCurrentScreen (void) +{ + return miPointerGetScreen(inputInfo.pointer); +} + +/** + * @return The current screen of the given device or NULL. + */ +ScreenPtr +miPointerGetScreen(DeviceIntPtr pDev) +{ + miPointerPtr pPointer = MIPOINTER(pDev); + return (pPointer) ? pPointer->pScreen : NULL; +} + +/* Controls whether the cursor image should be updated immediately when + moved (FALSE) or if something else will be responsible for updating + it later (TRUE). Returns current setting. + Caller is responsible for calling OsBlockSignal first. +*/ +Bool +miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) +{ + SetupScreen(pScreen); + Bool prevWait = pScreenPriv->waitForUpdate; + + pScreenPriv->waitForUpdate = wait; + return prevWait; +} + + +/* Move the pointer on the current screen, and update the sprite. */ +static void +miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y) +{ + miPointerPtr pPointer; + SetupScreen(pScreen); + + pPointer = MIPOINTER(pDev); + + /* Hack: We mustn't call into ->MoveCursor for anything but the + * VCP, as this may cause a non-HW rendered cursor to be rendered during + * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. + */ + if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer + && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) + { + pPointer->devx = x; + pPointer->devy = y; + if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) + (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); + } + + pPointer->x = x; + pPointer->y = y; + pPointer->pScreen = pScreen; +} + +/** + * Set the devices' cursor position to the given x/y position. + * + * This function is called during the pointer update path in + * GetPointerEvents and friends (and the same in the xwin DDX). + * + * The coordinates provided are always absolute. The parameter mode whether + * it was relative or absolute movement that landed us at those coordinates. + * + * @param pDev The device to move + * @param mode Movement mode (Absolute or Relative) + * @param[in,out] x The x coordiante in screen coordinates (in regards to total + * desktop size) + * @param[in,out] y The y coordiante in screen coordinates (in regards to total + * desktop size) + */ +void +miPointerSetPosition(DeviceIntPtr pDev, int mode, int *x, int *y) +{ + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; + ScreenPtr newScreen; + + miPointerPtr pPointer; + + if (!pDev || !pDev->coreEvents) + return; + + pPointer = MIPOINTER(pDev); + pScreen = pPointer->pScreen; + if (!pScreen) + return; /* called before ready */ + + if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) + { + pScreenPriv = GetScreenPrivate (pScreen); + if (!pPointer->confined) + { + newScreen = pScreen; + (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); + if (newScreen != pScreen) + { + pScreen = newScreen; + (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, + FALSE); + pScreenPriv = GetScreenPrivate (pScreen); + /* Smash the confine to the new screen */ + pPointer->limits.x2 = pScreen->width; + pPointer->limits.y2 = pScreen->height; + } + } + } + /* Constrain the sprite to the current limits. */ + if (*x < pPointer->limits.x1) + *x = pPointer->limits.x1; + if (*x >= pPointer->limits.x2) + *x = pPointer->limits.x2 - 1; + if (*y < pPointer->limits.y1) + *y = pPointer->limits.y1; + if (*y >= pPointer->limits.y2) + *y = pPointer->limits.y2 - 1; + + if (pScreen->ConstrainCursorHarder) + pScreen->ConstrainCursorHarder(pDev, pScreen, mode, x, y); + + if (pPointer->x == *x && pPointer->y == *y && + pPointer->pScreen == pScreen) + return; + + miPointerMoveNoEvent(pDev, pScreen, *x, *y); +} + +/** + * Get the current position of the device in desktop coordinates. + * + * @param x Return value for the current x coordinate in desktop coordiates. + * @param y Return value for the current y coordinate in desktop coordiates. + */ +void +miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) +{ + *x = MIPOINTER(pDev)->x; + *y = MIPOINTER(pDev)->y; +} + +#ifdef XQUARTZ +#include +void darwinEvents_lock(void); +void darwinEvents_unlock(void); +#endif + +/** + * Move the device's pointer to the x/y coordinates on the given screen. + * This function generates and enqueues pointer events. + * + * @param pDev The device to move + * @param pScreen The screen the device is on + * @param x The x coordinate in per-screen coordinates + * @param y The y coordinate in per-screen coordinates + */ +void +miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + int i, nevents; + int valuators[2]; + ValuatorMask mask; + + miPointerMoveNoEvent(pDev, pScreen, x, y); + + /* generate motion notify */ + valuators[0] = x; + valuators[1] = y; + + if (!events) + { + events = InitEventList(GetMaximumEventsNum()); + + if (!events) + { + FatalError("Could not allocate event store.\n"); + return; + } + } + + valuator_mask_set_range(&mask, 0, 2, valuators); + nevents = GetPointerEvents(events, pDev, MotionNotify, 0, + POINTER_SCREEN | POINTER_ABSOLUTE, &mask); + + OsBlockSignals(); +#ifdef XQUARTZ + darwinEvents_lock(); +#endif + for (i = 0; i < nevents; i++) + mieqEnqueue(pDev, (InternalEvent*)events[i].event); +#ifdef XQUARTZ + darwinEvents_unlock(); +#endif + OsReleaseSignals(); +} -- cgit v1.2.3