1706f2543Smrg/*
2706f2543Smrg
3706f2543SmrgCopyright 1989, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg*/
25706f2543Smrg
26706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
27706f2543Smrg#include <dix-config.h>
28706f2543Smrg#endif
29706f2543Smrg
30706f2543Smrg# include   <X11/X.h>
31706f2543Smrg# include   <X11/Xmd.h>
32706f2543Smrg# include   <X11/Xproto.h>
33706f2543Smrg# include   "misc.h"
34706f2543Smrg# include   "windowstr.h"
35706f2543Smrg# include   "pixmapstr.h"
36706f2543Smrg# include   "mi.h"
37706f2543Smrg# include   "scrnintstr.h"
38706f2543Smrg# include   "mipointrst.h"
39706f2543Smrg# include   "cursorstr.h"
40706f2543Smrg# include   "dixstruct.h"
41706f2543Smrg# include   "inputstr.h"
42706f2543Smrg# include   "inpututils.h"
43706f2543Smrg
44bc1411c9Smrg# include   "eventstr.h"
45bc1411c9Smrg
46706f2543SmrgDevPrivateKeyRec miPointerScreenKeyRec;
47706f2543Smrg
48706f2543Smrg#define GetScreenPrivate(s) ((miPointerScreenPtr) \
49706f2543Smrg    dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey))
50706f2543Smrg#define SetupScreen(s)	miPointerScreenPtr  pScreenPriv = GetScreenPrivate(s)
51706f2543Smrg
52706f2543SmrgDevPrivateKeyRec miPointerPrivKeyRec;
53706f2543Smrg
54706f2543Smrg#define MIPOINTER(dev) \
55706f2543Smrg    ((!IsMaster(dev) && !dev->u.master) ? \
56706f2543Smrg        (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \
57706f2543Smrg        (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey))
58706f2543Smrg
59706f2543Smrgstatic Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
60706f2543Smrg                                   CursorPtr pCursor);
61706f2543Smrgstatic Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
62706f2543Smrg                                     CursorPtr pCursor);
63706f2543Smrgstatic Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
64706f2543Smrg                                   CursorPtr pCursor);
65706f2543Smrgstatic void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
66706f2543Smrg                                     BoxPtr pBox);
67706f2543Smrgstatic void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen,
68706f2543Smrg                                  CursorPtr pCursor, BoxPtr pHotBox,
69706f2543Smrg                                  BoxPtr pTopLeftBox);
70706f2543Smrgstatic Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
71706f2543Smrg                                       int x, int y,
72706f2543Smrg				       Bool generateEvent);
73706f2543Smrgstatic Bool miPointerCloseScreen(int index, ScreenPtr pScreen);
74706f2543Smrgstatic void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen,
75706f2543Smrg                          int x, int y);
76706f2543Smrgstatic Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen);
77706f2543Smrgstatic void miPointerDeviceCleanup(DeviceIntPtr pDev,
78706f2543Smrg                                   ScreenPtr pScreen);
79706f2543Smrgstatic void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
80706f2543Smrg
81706f2543Smrgstatic EventList* events; /* for WarpPointer MotionNotifies */
82706f2543Smrg
83706f2543SmrgBool
84706f2543SmrgmiPointerInitialize (ScreenPtr                  pScreen,
85706f2543Smrg                     miPointerSpriteFuncPtr     spriteFuncs,
86706f2543Smrg                     miPointerScreenFuncPtr     screenFuncs,
87706f2543Smrg                     Bool                       waitForUpdate)
88706f2543Smrg{
89706f2543Smrg    miPointerScreenPtr	pScreenPriv;
90706f2543Smrg
91706f2543Smrg    if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0))
92706f2543Smrg	return FALSE;
93706f2543Smrg
94706f2543Smrg    if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0))
95706f2543Smrg	return FALSE;
96706f2543Smrg
97706f2543Smrg    pScreenPriv = malloc(sizeof (miPointerScreenRec));
98706f2543Smrg    if (!pScreenPriv)
99706f2543Smrg	return FALSE;
100706f2543Smrg    pScreenPriv->spriteFuncs = spriteFuncs;
101706f2543Smrg    pScreenPriv->screenFuncs = screenFuncs;
102706f2543Smrg    /*
103706f2543Smrg     * check for uninitialized methods
104706f2543Smrg     */
105706f2543Smrg    if (!screenFuncs->EnqueueEvent)
106706f2543Smrg	screenFuncs->EnqueueEvent = mieqEnqueue;
107706f2543Smrg    if (!screenFuncs->NewEventScreen)
108706f2543Smrg	screenFuncs->NewEventScreen = mieqSwitchScreen;
109706f2543Smrg    pScreenPriv->waitForUpdate = waitForUpdate;
110706f2543Smrg    pScreenPriv->showTransparent = FALSE;
111706f2543Smrg    pScreenPriv->CloseScreen = pScreen->CloseScreen;
112706f2543Smrg    pScreen->CloseScreen = miPointerCloseScreen;
113706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv);
114706f2543Smrg    /*
115706f2543Smrg     * set up screen cursor method table
116706f2543Smrg     */
117706f2543Smrg    pScreen->ConstrainCursor = miPointerConstrainCursor;
118706f2543Smrg    pScreen->CursorLimits = miPointerCursorLimits;
119706f2543Smrg    pScreen->DisplayCursor = miPointerDisplayCursor;
120706f2543Smrg    pScreen->RealizeCursor = miPointerRealizeCursor;
121706f2543Smrg    pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
122706f2543Smrg    pScreen->SetCursorPosition = miPointerSetCursorPosition;
123706f2543Smrg    pScreen->RecolorCursor = miRecolorCursor;
124706f2543Smrg    pScreen->DeviceCursorInitialize = miPointerDeviceInitialize;
125706f2543Smrg    pScreen->DeviceCursorCleanup = miPointerDeviceCleanup;
126706f2543Smrg
127706f2543Smrg    events = NULL;
128706f2543Smrg    return TRUE;
129706f2543Smrg}
130706f2543Smrg
131706f2543Smrgstatic Bool
132706f2543SmrgmiPointerCloseScreen (int index, ScreenPtr pScreen)
133706f2543Smrg{
134706f2543Smrg#if 0
135706f2543Smrg    miPointerPtr pPointer;
136706f2543Smrg    DeviceIntPtr pDev;
137706f2543Smrg#endif
138706f2543Smrg
139706f2543Smrg    SetupScreen(pScreen);
140706f2543Smrg
141706f2543Smrg#if 0
142706f2543Smrg    for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
143706f2543Smrg    {
144706f2543Smrg        if (DevHasCursor(pDev))
145706f2543Smrg        {
146706f2543Smrg            pPointer = MIPOINTER(pDev);
147706f2543Smrg
148706f2543Smrg            if (pScreen == pPointer->pScreen)
149706f2543Smrg                pPointer->pScreen = 0;
150706f2543Smrg            if (pScreen == pPointer->pSpriteScreen)
151706f2543Smrg                pPointer->pSpriteScreen = 0;
152706f2543Smrg        }
153706f2543Smrg    }
154706f2543Smrg
155706f2543Smrg    if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen)
156706f2543Smrg        MIPOINTER(inputInfo.pointer)->pScreen = 0;
157706f2543Smrg    if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen)
158706f2543Smrg        MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0;
159706f2543Smrg#endif
160706f2543Smrg
161706f2543Smrg    pScreen->CloseScreen = pScreenPriv->CloseScreen;
162706f2543Smrg    free((pointer) pScreenPriv);
163706f2543Smrg    FreeEventList(events, GetMaximumEventsNum());
164706f2543Smrg    events = NULL;
165706f2543Smrg    return (*pScreen->CloseScreen) (index, pScreen);
166706f2543Smrg}
167706f2543Smrg
168706f2543Smrg/*
169706f2543Smrg * DIX/DDX interface routines
170706f2543Smrg */
171706f2543Smrg
172706f2543Smrgstatic Bool
173706f2543SmrgmiPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
174706f2543Smrg{
175706f2543Smrg    SetupScreen(pScreen);
176706f2543Smrg    return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor);
177706f2543Smrg}
178706f2543Smrg
179706f2543Smrgstatic Bool
180706f2543SmrgmiPointerUnrealizeCursor (DeviceIntPtr  pDev,
181706f2543Smrg                          ScreenPtr     pScreen,
182706f2543Smrg                          CursorPtr     pCursor)
183706f2543Smrg{
184706f2543Smrg    SetupScreen(pScreen);
185706f2543Smrg    return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor);
186706f2543Smrg}
187706f2543Smrg
188706f2543Smrgstatic Bool
189706f2543SmrgmiPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
190706f2543Smrg{
191706f2543Smrg    miPointerPtr pPointer;
192706f2543Smrg
193706f2543Smrg    /* return for keyboards */
194706f2543Smrg    if ((IsMaster(pDev) && !DevHasCursor(pDev)) ||
195706f2543Smrg        (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master)))
196706f2543Smrg            return FALSE;
197706f2543Smrg
198706f2543Smrg    pPointer = MIPOINTER(pDev);
199706f2543Smrg
200706f2543Smrg    pPointer->pCursor = pCursor;
201706f2543Smrg    pPointer->pScreen = pScreen;
202706f2543Smrg    miPointerUpdateSprite(pDev);
203706f2543Smrg    return TRUE;
204706f2543Smrg}
205706f2543Smrg
206706f2543Smrgstatic void
207706f2543SmrgmiPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox)
208706f2543Smrg{
209706f2543Smrg    miPointerPtr pPointer;
210706f2543Smrg
211706f2543Smrg    pPointer = MIPOINTER(pDev);
212706f2543Smrg
213706f2543Smrg    pPointer->limits = *pBox;
214706f2543Smrg    pPointer->confined = PointerConfinedToScreen(pDev);
215706f2543Smrg}
216706f2543Smrg
217706f2543Smrg/*ARGSUSED*/
218706f2543Smrgstatic void
219706f2543SmrgmiPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
220706f2543Smrg                      BoxPtr pHotBox, BoxPtr pTopLeftBox)
221706f2543Smrg{
222706f2543Smrg    *pTopLeftBox = *pHotBox;
223706f2543Smrg}
224706f2543Smrg
225706f2543Smrgstatic Bool GenerateEvent;
226706f2543Smrg
227706f2543Smrgstatic Bool
228706f2543SmrgmiPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
229706f2543Smrg                           int x, int y, Bool generateEvent)
230706f2543Smrg{
231706f2543Smrg    SetupScreen (pScreen);
232706f2543Smrg
233706f2543Smrg    GenerateEvent = generateEvent;
234706f2543Smrg    /* device dependent - must pend signal and call miPointerWarpCursor */
235706f2543Smrg    (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
236706f2543Smrg    if (!generateEvent)
237706f2543Smrg	miPointerUpdateSprite(pDev);
238706f2543Smrg    return TRUE;
239706f2543Smrg}
240706f2543Smrg
241706f2543Smrg/* Set up sprite information for the device.
242706f2543Smrg   This function will be called once for each device after it is initialized
243706f2543Smrg   in the DIX.
244706f2543Smrg */
245706f2543Smrgstatic Bool
246706f2543SmrgmiPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
247706f2543Smrg{
248706f2543Smrg    miPointerPtr pPointer;
249706f2543Smrg    SetupScreen (pScreen);
250706f2543Smrg
251706f2543Smrg    pPointer = malloc(sizeof(miPointerRec));
252706f2543Smrg    if (!pPointer)
253706f2543Smrg        return FALSE;
254706f2543Smrg
255706f2543Smrg    pPointer->pScreen = NULL;
256706f2543Smrg    pPointer->pSpriteScreen = NULL;
257706f2543Smrg    pPointer->pCursor = NULL;
258706f2543Smrg    pPointer->pSpriteCursor = NULL;
259706f2543Smrg    pPointer->limits.x1 = 0;
260706f2543Smrg    pPointer->limits.x2 = 32767;
261706f2543Smrg    pPointer->limits.y1 = 0;
262706f2543Smrg    pPointer->limits.y2 = 32767;
263706f2543Smrg    pPointer->confined = FALSE;
264706f2543Smrg    pPointer->x = 0;
265706f2543Smrg    pPointer->y = 0;
266706f2543Smrg
267706f2543Smrg    if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen)))
268706f2543Smrg    {
269706f2543Smrg        free(pPointer);
270706f2543Smrg        return FALSE;
271706f2543Smrg    }
272706f2543Smrg
273706f2543Smrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer);
274706f2543Smrg    return TRUE;
275706f2543Smrg}
276706f2543Smrg
277706f2543Smrg/* Clean up after device.
278706f2543Smrg   This function will be called once before the device is freed in the DIX
279706f2543Smrg */
280706f2543Smrgstatic void
281706f2543SmrgmiPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
282706f2543Smrg{
283706f2543Smrg    SetupScreen(pScreen);
284706f2543Smrg
285706f2543Smrg    if (!IsMaster(pDev) && pDev->u.master)
286706f2543Smrg        return;
287706f2543Smrg
288706f2543Smrg    (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen);
289706f2543Smrg    free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey));
290706f2543Smrg    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL);
291706f2543Smrg}
292706f2543Smrg
293706f2543Smrg
294706f2543Smrg/* Once signals are ignored, the WarpCursor function can call this */
295706f2543Smrg
296706f2543Smrgvoid
297706f2543SmrgmiPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
298706f2543Smrg{
299706f2543Smrg    miPointerPtr pPointer;
300706f2543Smrg    BOOL changedScreen = FALSE;
301706f2543Smrg
302706f2543Smrg    SetupScreen (pScreen);
303706f2543Smrg    pPointer = MIPOINTER(pDev);
304706f2543Smrg
305706f2543Smrg    if (pPointer->pScreen != pScreen)
306706f2543Smrg    {
307706f2543Smrg	(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE);
308706f2543Smrg        changedScreen = TRUE;
309706f2543Smrg    }
310706f2543Smrg
311706f2543Smrg    if (GenerateEvent)
312706f2543Smrg	miPointerMove (pDev, pScreen, x, y);
313706f2543Smrg    else
314706f2543Smrg        miPointerMoveNoEvent(pDev, pScreen, x, y);
315706f2543Smrg
316706f2543Smrg    /* Don't call USFS if we use Xinerama, otherwise the root window is
317706f2543Smrg     * updated to the second screen, and we never receive any events.
318706f2543Smrg     * (FDO bug #18668) */
319706f2543Smrg    if (changedScreen
320706f2543Smrg#ifdef PANORAMIX
321706f2543Smrg            && noPanoramiXExtension
322706f2543Smrg#endif
323bc1411c9Smrg       ) {
324bc1411c9Smrg            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
325bc1411c9Smrg            /* Hack for CVE-2023-5380: if we're moving
326bc1411c9Smrg             * screens PointerWindows[] keeps referring to the
327bc1411c9Smrg             * old window. If that gets destroyed we have a UAF
328bc1411c9Smrg             * bug later. Only happens when jumping from a window
329bc1411c9Smrg             * to the root window on the other screen.
330bc1411c9Smrg             * Enter/Leave events are incorrect for that case but
331bc1411c9Smrg             * too niche to fix.
332bc1411c9Smrg             */
333bc1411c9Smrg            LeaveWindow(pDev);
334bc1411c9Smrg            if (master)
335bc1411c9Smrg                LeaveWindow(master);
336bc1411c9Smrg            UpdateSpriteForScreen(pDev, pScreen);
337bc1411c9Smrg    }
338706f2543Smrg}
339706f2543Smrg
340706f2543Smrg/*
341706f2543Smrg * Pointer/CursorDisplay interface routines
342706f2543Smrg */
343706f2543Smrg
344706f2543Smrg/*
345706f2543Smrg * miPointerUpdateSprite
346706f2543Smrg *
347706f2543Smrg * Syncronize the sprite with the cursor - called from ProcessInputEvents
348706f2543Smrg */
349706f2543Smrg
350706f2543Smrgvoid
351706f2543SmrgmiPointerUpdateSprite (DeviceIntPtr pDev)
352706f2543Smrg{
353706f2543Smrg    ScreenPtr		pScreen;
354706f2543Smrg    miPointerScreenPtr	pScreenPriv;
355706f2543Smrg    CursorPtr		pCursor;
356706f2543Smrg    int			x, y, devx, devy;
357706f2543Smrg    miPointerPtr        pPointer;
358706f2543Smrg
359706f2543Smrg    if (!pDev || !pDev->coreEvents)
360706f2543Smrg        return;
361706f2543Smrg
362706f2543Smrg    pPointer = MIPOINTER(pDev);
363706f2543Smrg
364706f2543Smrg    if (!pPointer)
365706f2543Smrg        return;
366706f2543Smrg
367706f2543Smrg    pScreen = pPointer->pScreen;
368706f2543Smrg    if (!pScreen)
369706f2543Smrg	return;
370706f2543Smrg
371706f2543Smrg    x = pPointer->x;
372706f2543Smrg    y = pPointer->y;
373706f2543Smrg    devx = pPointer->devx;
374706f2543Smrg    devy = pPointer->devy;
375706f2543Smrg
376706f2543Smrg    pScreenPriv = GetScreenPrivate (pScreen);
377706f2543Smrg    /*
378706f2543Smrg     * if the cursor has switched screens, disable the sprite
379706f2543Smrg     * on the old screen
380706f2543Smrg     */
381706f2543Smrg    if (pScreen != pPointer->pSpriteScreen)
382706f2543Smrg    {
383706f2543Smrg	if (pPointer->pSpriteScreen)
384706f2543Smrg	{
385706f2543Smrg	    miPointerScreenPtr  pOldPriv;
386706f2543Smrg
387706f2543Smrg	    pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen);
388706f2543Smrg	    if (pPointer->pCursor)
389706f2543Smrg	    {
390706f2543Smrg	    	(*pOldPriv->spriteFuncs->SetCursor)
391706f2543Smrg			    	(pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
392706f2543Smrg	    }
393706f2543Smrg	    (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE);
394706f2543Smrg	}
395706f2543Smrg	(*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
396706f2543Smrg	(*pScreenPriv->spriteFuncs->SetCursor)
397706f2543Smrg				(pDev, pScreen, pPointer->pCursor, x, y);
398706f2543Smrg	pPointer->devx = x;
399706f2543Smrg	pPointer->devy = y;
400706f2543Smrg	pPointer->pSpriteCursor = pPointer->pCursor;
401706f2543Smrg	pPointer->pSpriteScreen = pScreen;
402706f2543Smrg    }
403706f2543Smrg    /*
404706f2543Smrg     * if the cursor has changed, display the new one
405706f2543Smrg     */
406706f2543Smrg    else if (pPointer->pCursor != pPointer->pSpriteCursor)
407706f2543Smrg    {
408706f2543Smrg	pCursor = pPointer->pCursor;
409706f2543Smrg	if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
410706f2543Smrg	    pCursor = NullCursor;
411706f2543Smrg	(*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
412706f2543Smrg
413706f2543Smrg	pPointer->devx = x;
414706f2543Smrg	pPointer->devy = y;
415706f2543Smrg	pPointer->pSpriteCursor = pPointer->pCursor;
416706f2543Smrg    }
417706f2543Smrg    else if (x != devx || y != devy)
418706f2543Smrg    {
419706f2543Smrg	pPointer->devx = x;
420706f2543Smrg	pPointer->devy = y;
421706f2543Smrg	if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
422706f2543Smrg	    (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
423706f2543Smrg    }
424706f2543Smrg}
425706f2543Smrg
426706f2543Smrgvoid
427706f2543SmrgmiPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
428706f2543Smrg{
429706f2543Smrg	miPointerScreenPtr pScreenPriv;
430706f2543Smrg	ScreenPtr pScreen;
431706f2543Smrg        miPointerPtr pPointer;
432706f2543Smrg
433706f2543Smrg        pPointer = MIPOINTER(pDev);
434706f2543Smrg
435706f2543Smrg	pScreen = screenInfo.screens[screen_no];
436706f2543Smrg	pScreenPriv = GetScreenPrivate (pScreen);
437706f2543Smrg	(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE);
438706f2543Smrg	NewCurrentScreen (pDev, pScreen, x, y);
439706f2543Smrg
440706f2543Smrg        pPointer->limits.x2 = pScreen->width;
441706f2543Smrg        pPointer->limits.y2 = pScreen->height;
442706f2543Smrg}
443706f2543Smrg
444706f2543SmrgScreenPtr
445706f2543SmrgmiPointerCurrentScreen (void)
446706f2543Smrg{
447706f2543Smrg    return miPointerGetScreen(inputInfo.pointer);
448706f2543Smrg}
449706f2543Smrg
450706f2543SmrgScreenPtr
451706f2543SmrgmiPointerGetScreen(DeviceIntPtr pDev)
452706f2543Smrg{
453706f2543Smrg    miPointerPtr pPointer = MIPOINTER(pDev);
454706f2543Smrg    return (pPointer) ? pPointer->pScreen : NULL;
455706f2543Smrg}
456706f2543Smrg
457706f2543Smrg/* Controls whether the cursor image should be updated immediately when
458706f2543Smrg   moved (FALSE) or if something else will be responsible for updating
459706f2543Smrg   it later (TRUE).  Returns current setting.
460706f2543Smrg   Caller is responsible for calling OsBlockSignal first.
461706f2543Smrg*/
462706f2543SmrgBool
463706f2543SmrgmiPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
464706f2543Smrg{
465706f2543Smrg    SetupScreen(pScreen);
466706f2543Smrg    Bool prevWait = pScreenPriv->waitForUpdate;
467706f2543Smrg
468706f2543Smrg    pScreenPriv->waitForUpdate = wait;
469706f2543Smrg    return prevWait;
470706f2543Smrg}
471706f2543Smrg
472706f2543Smrg
473706f2543Smrg/* Move the pointer on the current screen,  and update the sprite. */
474706f2543Smrgstatic void
475706f2543SmrgmiPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen,
476706f2543Smrg                int x, int y)
477706f2543Smrg{
478706f2543Smrg    miPointerPtr pPointer;
479706f2543Smrg    SetupScreen(pScreen);
480706f2543Smrg
481706f2543Smrg    pPointer = MIPOINTER(pDev);
482706f2543Smrg
483706f2543Smrg    /* Hack: We mustn't call into ->MoveCursor for anything but the
484706f2543Smrg     * VCP, as this may cause a non-HW rendered cursor to be rendered during
485706f2543Smrg     * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT.
486706f2543Smrg     */
487706f2543Smrg    if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer))
488706f2543Smrg        && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen)
489706f2543Smrg    {
490706f2543Smrg	pPointer->devx = x;
491706f2543Smrg	pPointer->devy = y;
492706f2543Smrg	if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
493706f2543Smrg	    (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
494706f2543Smrg    }
495706f2543Smrg
496706f2543Smrg    pPointer->x = x;
497706f2543Smrg    pPointer->y = y;
498706f2543Smrg    pPointer->pScreen = pScreen;
499706f2543Smrg}
500706f2543Smrg
501706f2543Smrgvoid
502706f2543SmrgmiPointerSetPosition(DeviceIntPtr pDev, int *x, int *y)
503706f2543Smrg{
504706f2543Smrg    miPointerScreenPtr	pScreenPriv;
505706f2543Smrg    ScreenPtr		pScreen;
506706f2543Smrg    ScreenPtr		newScreen;
507706f2543Smrg
508706f2543Smrg    miPointerPtr        pPointer;
509706f2543Smrg
510706f2543Smrg    if (!pDev || !pDev->coreEvents)
511706f2543Smrg        return;
512706f2543Smrg
513706f2543Smrg    pPointer = MIPOINTER(pDev);
514706f2543Smrg    pScreen = pPointer->pScreen;
515706f2543Smrg    if (!pScreen)
516706f2543Smrg	return;	    /* called before ready */
517706f2543Smrg
518706f2543Smrg    if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height)
519706f2543Smrg    {
520706f2543Smrg	pScreenPriv = GetScreenPrivate (pScreen);
521706f2543Smrg	if (!pPointer->confined)
522706f2543Smrg	{
523706f2543Smrg	    newScreen = pScreen;
524706f2543Smrg	    (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y);
525706f2543Smrg	    if (newScreen != pScreen)
526706f2543Smrg	    {
527706f2543Smrg		pScreen = newScreen;
528706f2543Smrg		(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen,
529706f2543Smrg							     FALSE);
530706f2543Smrg	    	/* Smash the confine to the new screen */
531706f2543Smrg                pPointer->limits.x2 = pScreen->width;
532706f2543Smrg                pPointer->limits.y2 = pScreen->height;
533706f2543Smrg	    }
534706f2543Smrg	}
535706f2543Smrg    }
536706f2543Smrg    /* Constrain the sprite to the current limits. */
537706f2543Smrg    if (*x < pPointer->limits.x1)
538706f2543Smrg	*x = pPointer->limits.x1;
539706f2543Smrg    if (*x >= pPointer->limits.x2)
540706f2543Smrg	*x = pPointer->limits.x2 - 1;
541706f2543Smrg    if (*y < pPointer->limits.y1)
542706f2543Smrg	*y = pPointer->limits.y1;
543706f2543Smrg    if (*y >= pPointer->limits.y2)
544706f2543Smrg	*y = pPointer->limits.y2 - 1;
545706f2543Smrg
546706f2543Smrg    if (pPointer->x == *x && pPointer->y == *y &&
547706f2543Smrg            pPointer->pScreen == pScreen)
548706f2543Smrg        return;
549706f2543Smrg
550706f2543Smrg    miPointerMoveNoEvent(pDev, pScreen, *x, *y);
551706f2543Smrg}
552706f2543Smrg
553706f2543Smrgvoid
554706f2543SmrgmiPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
555706f2543Smrg{
556706f2543Smrg    *x = MIPOINTER(pDev)->x;
557706f2543Smrg    *y = MIPOINTER(pDev)->y;
558706f2543Smrg}
559706f2543Smrg
560706f2543Smrg#ifdef XQUARTZ
561706f2543Smrg#include <pthread.h>
562706f2543Smrgvoid darwinEvents_lock(void);
563706f2543Smrgvoid darwinEvents_unlock(void);
564706f2543Smrg#endif
565706f2543Smrg
566706f2543Smrgvoid
567706f2543SmrgmiPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
568706f2543Smrg{
569706f2543Smrg    int i, nevents;
570706f2543Smrg    int valuators[2];
571706f2543Smrg    ValuatorMask mask;
572706f2543Smrg
573706f2543Smrg    miPointerMoveNoEvent(pDev, pScreen, x, y);
574706f2543Smrg
575706f2543Smrg    /* generate motion notify */
576706f2543Smrg    valuators[0] = x;
577706f2543Smrg    valuators[1] = y;
578706f2543Smrg
579706f2543Smrg    if (!events)
580706f2543Smrg    {
581706f2543Smrg        events = InitEventList(GetMaximumEventsNum());
582706f2543Smrg
583706f2543Smrg        if (!events)
584706f2543Smrg        {
585706f2543Smrg            FatalError("Could not allocate event store.\n");
586706f2543Smrg            return;
587706f2543Smrg        }
588706f2543Smrg    }
589706f2543Smrg
590706f2543Smrg    valuator_mask_set_range(&mask, 0, 2, valuators);
591706f2543Smrg    nevents = GetPointerEvents(events, pDev, MotionNotify, 0,
592706f2543Smrg                               POINTER_SCREEN | POINTER_ABSOLUTE | POINTER_NORAW, &mask);
593706f2543Smrg
594706f2543Smrg    OsBlockSignals();
595706f2543Smrg#ifdef XQUARTZ
596706f2543Smrg    darwinEvents_lock();
597706f2543Smrg#endif
598706f2543Smrg    for (i = 0; i < nevents; i++)
599706f2543Smrg        mieqEnqueue(pDev, (InternalEvent*)events[i].event);
600706f2543Smrg#ifdef XQUARTZ
601706f2543Smrg    darwinEvents_unlock();
602706f2543Smrg#endif
603706f2543Smrg    OsReleaseSignals();
604706f2543Smrg}
605