mipointer.c revision 1b5d61b8
1/*
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24*/
25
26/**
27 * @file
28 * This file contains functions to move the pointer on the screen and/or
29 * restrict its movement. These functions are divided into two sets:
30 * Screen-specific functions that are used as function pointers from other
31 * parts of the server (and end up heavily wrapped by e.g. animcur and
32 * xfixes):
33 *      miPointerConstrainCursor
34 *      miPointerCursorLimits
35 *      miPointerDisplayCursor
36 *      miPointerRealizeCursor
37 *      miPointerUnrealizeCursor
38 *      miPointerSetCursorPosition
39 *      miRecolorCursor
40 *      miPointerDeviceInitialize
41 *      miPointerDeviceCleanup
42 * If wrapped, these are the last element in the wrapping chain. They may
43 * call into sprite-specific code through further function pointers though.
44 *
45 * The second type of functions are those that are directly called by the
46 * DIX, DDX and some drivers.
47 */
48
49#ifdef HAVE_DIX_CONFIG_H
50#include <dix-config.h>
51#endif
52
53#include   <X11/X.h>
54#include   <X11/Xmd.h>
55#include   <X11/Xproto.h>
56#include   "misc.h"
57#include   "windowstr.h"
58#include   "pixmapstr.h"
59#include   "mi.h"
60#include   "scrnintstr.h"
61#include   "mipointrst.h"
62#include   "cursorstr.h"
63#include   "dixstruct.h"
64#include   "inputstr.h"
65#include   "inpututils.h"
66#include   "eventstr.h"
67
68typedef struct {
69    ScreenPtr pScreen;          /* current screen */
70    ScreenPtr pSpriteScreen;    /* screen containing current sprite */
71    CursorPtr pCursor;          /* current cursor */
72    CursorPtr pSpriteCursor;    /* cursor on screen */
73    BoxRec limits;              /* current constraints */
74    Bool confined;              /* pointer can't change screens */
75    int x, y;                   /* hot spot location */
76    int devx, devy;             /* sprite position */
77    Bool generateEvent;         /* generate an event during warping? */
78} miPointerRec, *miPointerPtr;
79
80DevPrivateKeyRec miPointerScreenKeyRec;
81
82#define GetScreenPrivate(s) ((miPointerScreenPtr) \
83    dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey))
84#define SetupScreen(s)	miPointerScreenPtr  pScreenPriv = GetScreenPrivate(s)
85
86DevPrivateKeyRec miPointerPrivKeyRec;
87
88#define MIPOINTER(dev) \
89    (IsFloating(dev) ? \
90        (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \
91        (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey))
92
93static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
94                                   CursorPtr pCursor);
95static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
96                                     CursorPtr pCursor);
97static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
98                                   CursorPtr pCursor);
99static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
100                                     BoxPtr pBox);
101static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen,
102                                  CursorPtr pCursor, BoxPtr pHotBox,
103                                  BoxPtr pTopLeftBox);
104static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
105                                       int x, int y, Bool generateEvent);
106static Bool miPointerCloseScreen(ScreenPtr pScreen);
107static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
108static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen);
109static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
110static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x,
111                                 int y);
112
113static InternalEvent *mipointermove_events;   /* for WarpPointer MotionNotifies */
114
115Bool
116miPointerInitialize(ScreenPtr pScreen,
117                    miPointerSpriteFuncPtr spriteFuncs,
118                    miPointerScreenFuncPtr screenFuncs, Bool waitForUpdate)
119{
120    miPointerScreenPtr pScreenPriv;
121
122    if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0))
123        return FALSE;
124
125    if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0))
126        return FALSE;
127
128    pScreenPriv = malloc(sizeof(miPointerScreenRec));
129    if (!pScreenPriv)
130        return FALSE;
131    pScreenPriv->spriteFuncs = spriteFuncs;
132    pScreenPriv->screenFuncs = screenFuncs;
133    pScreenPriv->waitForUpdate = waitForUpdate;
134    pScreenPriv->showTransparent = FALSE;
135    pScreenPriv->CloseScreen = pScreen->CloseScreen;
136    pScreen->CloseScreen = miPointerCloseScreen;
137    dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv);
138    /*
139     * set up screen cursor method table
140     */
141    pScreen->ConstrainCursor = miPointerConstrainCursor;
142    pScreen->CursorLimits = miPointerCursorLimits;
143    pScreen->DisplayCursor = miPointerDisplayCursor;
144    pScreen->RealizeCursor = miPointerRealizeCursor;
145    pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
146    pScreen->SetCursorPosition = miPointerSetCursorPosition;
147    pScreen->RecolorCursor = miRecolorCursor;
148    pScreen->DeviceCursorInitialize = miPointerDeviceInitialize;
149    pScreen->DeviceCursorCleanup = miPointerDeviceCleanup;
150
151    mipointermove_events = NULL;
152    return TRUE;
153}
154
155/**
156 * Destroy screen-specific information.
157 *
158 * @param index Screen index of the screen in screenInfo.screens[]
159 * @param pScreen The actual screen pointer
160 */
161static Bool
162miPointerCloseScreen(ScreenPtr pScreen)
163{
164    SetupScreen(pScreen);
165
166    pScreen->CloseScreen = pScreenPriv->CloseScreen;
167    free((void *) pScreenPriv);
168    FreeEventList(mipointermove_events, GetMaximumEventsNum());
169    mipointermove_events = NULL;
170    return (*pScreen->CloseScreen) (pScreen);
171}
172
173/*
174 * DIX/DDX interface routines
175 */
176
177static Bool
178miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
179{
180    SetupScreen(pScreen);
181    return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor);
182}
183
184static Bool
185miPointerUnrealizeCursor(DeviceIntPtr pDev,
186                         ScreenPtr pScreen, CursorPtr pCursor)
187{
188    SetupScreen(pScreen);
189    return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen,
190                                                         pCursor);
191}
192
193static Bool
194miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
195{
196    miPointerPtr pPointer;
197
198    /* return for keyboards */
199    if (!IsPointerDevice(pDev))
200        return FALSE;
201
202    pPointer = MIPOINTER(pDev);
203
204    pPointer->pCursor = pCursor;
205    pPointer->pScreen = pScreen;
206    miPointerUpdateSprite(pDev);
207    return TRUE;
208}
209
210/**
211 * Set up the constraints for the given device. This function does not
212 * actually constrain the cursor but merely copies the given box to the
213 * internal constraint storage.
214 *
215 * @param pDev The device to constrain to the box
216 * @param pBox The rectangle to constrain the cursor to
217 * @param pScreen Used for copying screen confinement
218 */
219static void
220miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox)
221{
222    miPointerPtr pPointer;
223
224    pPointer = MIPOINTER(pDev);
225
226    pPointer->limits = *pBox;
227    pPointer->confined = PointerConfinedToScreen(pDev);
228}
229
230/**
231 * Should calculate the box for the given cursor, based on screen and the
232 * confinement given. But we assume that whatever box is passed in is valid
233 * anyway.
234 *
235 * @param pDev The device to calculate the cursor limits for
236 * @param pScreen The screen the confinement happens on
237 * @param pCursor The screen the confinement happens on
238 * @param pHotBox The confinement box for the cursor
239 * @param[out] pTopLeftBox The new confinement box, always *pHotBox.
240 */
241static void
242miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
243                      BoxPtr pHotBox, BoxPtr pTopLeftBox)
244{
245    *pTopLeftBox = *pHotBox;
246}
247
248/**
249 * Set the device's cursor position to the x/y position on the given screen.
250 * Generates and event if required.
251 *
252 * This function is called from:
253 *    - sprite init code to place onto initial position
254 *    - the various WarpPointer implementations (core, XI, Xinerama, dmx,…)
255 *    - during the cursor update path in CheckMotion
256 *    - in the Xinerama part of NewCurrentScreen
257 *    - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so
258 *      it's set back to the original pos)
259 *
260 * @param pDev The device to move
261 * @param pScreen The screen the device is on
262 * @param x The x coordinate in per-screen coordinates
263 * @param y The y coordinate in per-screen coordinates
264 * @param generateEvent True if the pointer movement should generate an
265 * event.
266 *
267 * @return TRUE in all cases
268 */
269static Bool
270miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
271                           int x, int y, Bool generateEvent)
272{
273    SetupScreen(pScreen);
274    miPointerPtr pPointer = MIPOINTER(pDev);
275
276    pPointer->generateEvent = generateEvent;
277
278    if (pScreen->ConstrainCursorHarder)
279        pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y);
280
281    /* device dependent - must pend signal and call miPointerWarpCursor */
282    (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
283    if (!generateEvent)
284        miPointerUpdateSprite(pDev);
285    return TRUE;
286}
287
288void
289miRecolorCursor(DeviceIntPtr pDev, ScreenPtr pScr,
290                CursorPtr pCurs, Bool displayed)
291{
292    /*
293     * This is guaranteed to correct any color-dependent state which may have
294     * been bound up in private state created by RealizeCursor
295     */
296    pScr->UnrealizeCursor(pDev, pScr, pCurs);
297    pScr->RealizeCursor(pDev, pScr, pCurs);
298    if (displayed)
299        pScr->DisplayCursor(pDev, pScr, pCurs);
300}
301
302/**
303 * Set up sprite information for the device.
304 * This function will be called once for each device after it is initialized
305 * in the DIX.
306 *
307 * @param pDev The newly created device
308 * @param pScreen The initial sprite scree.
309 */
310static Bool
311miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
312{
313    miPointerPtr pPointer;
314
315    SetupScreen(pScreen);
316
317    pPointer = malloc(sizeof(miPointerRec));
318    if (!pPointer)
319        return FALSE;
320
321    pPointer->pScreen = NULL;
322    pPointer->pSpriteScreen = NULL;
323    pPointer->pCursor = NULL;
324    pPointer->pSpriteCursor = NULL;
325    pPointer->limits.x1 = 0;
326    pPointer->limits.x2 = 32767;
327    pPointer->limits.y1 = 0;
328    pPointer->limits.y2 = 32767;
329    pPointer->confined = FALSE;
330    pPointer->x = 0;
331    pPointer->y = 0;
332    pPointer->generateEvent = FALSE;
333
334    if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen))) {
335        free(pPointer);
336        return FALSE;
337    }
338
339    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer);
340    return TRUE;
341}
342
343/**
344 * Clean up after device.
345 * This function will be called once before the device is freed in the DIX
346 *
347 * @param pDev The device to be removed from the server
348 * @param pScreen Current screen of the device
349 */
350static void
351miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
352{
353    SetupScreen(pScreen);
354
355    if (!IsMaster(pDev) && !IsFloating(pDev))
356        return;
357
358    (*pScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen);
359    free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey));
360    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL);
361}
362
363/**
364 * Warp the pointer to the given position on the given screen. May generate
365 * an event, depending on whether we're coming from miPointerSetPosition.
366 *
367 * Once signals are ignored, the WarpCursor function can call this
368 *
369 * @param pDev The device to warp
370 * @param pScreen Screen to warp on
371 * @param x The x coordinate in per-screen coordinates
372 * @param y The y coordinate in per-screen coordinates
373 */
374
375void
376miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
377{
378    miPointerPtr pPointer;
379    BOOL changedScreen = FALSE;
380
381    pPointer = MIPOINTER(pDev);
382
383    if (pPointer->pScreen != pScreen) {
384        mieqSwitchScreen(pDev, pScreen, TRUE);
385        changedScreen = TRUE;
386    }
387
388    if (pPointer->generateEvent)
389        miPointerMove(pDev, pScreen, x, y);
390    else
391        miPointerMoveNoEvent(pDev, pScreen, x, y);
392
393    /* Don't call USFS if we use Xinerama, otherwise the root window is
394     * updated to the second screen, and we never receive any events.
395     * (FDO bug #18668) */
396    if (changedScreen
397#ifdef PANORAMIX
398        && noPanoramiXExtension
399#endif
400        )
401        UpdateSpriteForScreen(pDev, pScreen);
402}
403
404/**
405 * Syncronize the sprite with the cursor.
406 *
407 * @param pDev The device to sync
408 */
409void
410miPointerUpdateSprite(DeviceIntPtr pDev)
411{
412    ScreenPtr pScreen;
413    miPointerScreenPtr pScreenPriv;
414    CursorPtr pCursor;
415    int x, y, devx, devy;
416    miPointerPtr pPointer;
417
418    if (!pDev || !pDev->coreEvents)
419        return;
420
421    pPointer = MIPOINTER(pDev);
422
423    if (!pPointer)
424        return;
425
426    pScreen = pPointer->pScreen;
427    if (!pScreen)
428        return;
429
430    x = pPointer->x;
431    y = pPointer->y;
432    devx = pPointer->devx;
433    devy = pPointer->devy;
434
435    pScreenPriv = GetScreenPrivate(pScreen);
436    /*
437     * if the cursor has switched screens, disable the sprite
438     * on the old screen
439     */
440    if (pScreen != pPointer->pSpriteScreen) {
441        if (pPointer->pSpriteScreen) {
442            miPointerScreenPtr pOldPriv;
443
444            pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen);
445            if (pPointer->pCursor) {
446                (*pOldPriv->spriteFuncs->SetCursor)
447                    (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
448            }
449            (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen,
450                                                   FALSE);
451        }
452        (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
453        (*pScreenPriv->spriteFuncs->SetCursor)
454            (pDev, pScreen, pPointer->pCursor, x, y);
455        pPointer->devx = x;
456        pPointer->devy = y;
457        pPointer->pSpriteCursor = pPointer->pCursor;
458        pPointer->pSpriteScreen = pScreen;
459    }
460    /*
461     * if the cursor has changed, display the new one
462     */
463    else if (pPointer->pCursor != pPointer->pSpriteCursor) {
464        pCursor = pPointer->pCursor;
465        if (!pCursor ||
466            (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
467            pCursor = NullCursor;
468        (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
469
470        pPointer->devx = x;
471        pPointer->devy = y;
472        pPointer->pSpriteCursor = pPointer->pCursor;
473    }
474    else if (x != devx || y != devy) {
475        pPointer->devx = x;
476        pPointer->devy = y;
477        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
478            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
479    }
480}
481
482/**
483 * Invalidate the current sprite and force it to be reloaded on next cursor setting
484 * operation
485 *
486 * @param pDev The device to invalidate the sprite fore
487 */
488void
489miPointerInvalidateSprite(DeviceIntPtr pDev)
490{
491    miPointerPtr pPointer;
492
493    pPointer = MIPOINTER(pDev);
494    pPointer->pSpriteCursor = (CursorPtr) 1;
495}
496
497/**
498 * Set the device to the coordinates on the given screen.
499 *
500 * @param pDev The device to move
501 * @param screen_no Index of the screen to move to
502 * @param x The x coordinate in per-screen coordinates
503 * @param y The y coordinate in per-screen coordinates
504 */
505void
506miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
507{
508    ScreenPtr pScreen;
509    miPointerPtr pPointer;
510
511    pPointer = MIPOINTER(pDev);
512
513    pScreen = screenInfo.screens[screen_no];
514    mieqSwitchScreen(pDev, pScreen, FALSE);
515    NewCurrentScreen(pDev, pScreen, x, y);
516
517    pPointer->limits.x2 = pScreen->width;
518    pPointer->limits.y2 = pScreen->height;
519}
520
521/**
522 * @return The current screen of the given device or NULL.
523 */
524ScreenPtr
525miPointerGetScreen(DeviceIntPtr pDev)
526{
527    miPointerPtr pPointer = MIPOINTER(pDev);
528
529    return (pPointer) ? pPointer->pScreen : NULL;
530}
531
532/* Controls whether the cursor image should be updated immediately when
533   moved (FALSE) or if something else will be responsible for updating
534   it later (TRUE).  Returns current setting.
535   Caller is responsible for calling OsBlockSignal first.
536*/
537Bool
538miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
539{
540    SetupScreen(pScreen);
541    Bool prevWait = pScreenPriv->waitForUpdate;
542
543    pScreenPriv->waitForUpdate = wait;
544    return prevWait;
545}
546
547/* Move the pointer on the current screen,  and update the sprite. */
548static void
549miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
550{
551    miPointerPtr pPointer;
552
553    SetupScreen(pScreen);
554
555    pPointer = MIPOINTER(pDev);
556
557    /* Hack: We mustn't call into ->MoveCursor for anything but the
558     * VCP, as this may cause a non-HW rendered cursor to be rendered while
559     * not holding the input lock. This would race with building the command
560     * buffer for other rendering.
561     */
562    if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer
563        &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) {
564        pPointer->devx = x;
565        pPointer->devy = y;
566        if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
567            (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
568    }
569
570    pPointer->x = x;
571    pPointer->y = y;
572    pPointer->pScreen = pScreen;
573}
574
575/**
576 * Set the devices' cursor position to the given x/y position.
577 *
578 * This function is called during the pointer update path in
579 * GetPointerEvents and friends (and the same in the xwin DDX).
580 *
581 * The coordinates provided are always absolute. The parameter mode whether
582 * it was relative or absolute movement that landed us at those coordinates.
583 *
584 * If the cursor was constrained by a barrier, ET_Barrier* events may be
585 * generated and appended to the InternalEvent list provided.
586 *
587 * @param pDev The device to move
588 * @param mode Movement mode (Absolute or Relative)
589 * @param[in,out] screenx The x coordinate in desktop coordinates
590 * @param[in,out] screeny The y coordinate in desktop coordinates
591 * @param[in,out] nevents The number of events in events (before/after)
592 * @param[in,out] events The list of events before/after being constrained
593 */
594ScreenPtr
595miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
596                     double *screeny,
597                     int *nevents, InternalEvent* events)
598{
599    miPointerScreenPtr pScreenPriv;
600    ScreenPtr pScreen;
601    ScreenPtr newScreen;
602    int x, y;
603    Bool switch_screen = FALSE;
604    Bool should_constrain_barriers = FALSE;
605    int i;
606
607    miPointerPtr pPointer;
608
609    pPointer = MIPOINTER(pDev);
610    pScreen = pPointer->pScreen;
611
612    x = trunc(*screenx);
613    y = trunc(*screeny);
614
615    switch_screen = !point_on_screen(pScreen, x, y);
616
617    /* Switch to per-screen coordinates for CursorOffScreen and
618     * Pointer->limits */
619    x -= pScreen->x;
620    y -= pScreen->y;
621
622    should_constrain_barriers = (mode == Relative);
623
624    if (should_constrain_barriers) {
625        /* coordinates after clamped to a barrier */
626        int constrained_x, constrained_y;
627        int current_x, current_y; /* current position in per-screen coord */
628
629        current_x = MIPOINTER(pDev)->x - pScreen->x;
630        current_y = MIPOINTER(pDev)->y - pScreen->y;
631
632        input_constrain_cursor(pDev, pScreen,
633                               current_x, current_y, x, y,
634                               &constrained_x, &constrained_y,
635                               nevents, events);
636
637        x = constrained_x;
638        y = constrained_y;
639    }
640
641    if (switch_screen) {
642        pScreenPriv = GetScreenPrivate(pScreen);
643        if (!pPointer->confined) {
644            newScreen = pScreen;
645            (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
646            if (newScreen != pScreen) {
647                pScreen = newScreen;
648                mieqSwitchScreen(pDev, pScreen, FALSE);
649                /* Smash the confine to the new screen */
650                pPointer->limits.x2 = pScreen->width;
651                pPointer->limits.y2 = pScreen->height;
652            }
653        }
654    }
655    /* Constrain the sprite to the current limits. */
656    if (x < pPointer->limits.x1)
657        x = pPointer->limits.x1;
658    if (x >= pPointer->limits.x2)
659        x = pPointer->limits.x2 - 1;
660    if (y < pPointer->limits.y1)
661        y = pPointer->limits.y1;
662    if (y >= pPointer->limits.y2)
663        y = pPointer->limits.y2 - 1;
664
665    if (pScreen->ConstrainCursorHarder)
666        pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y);
667
668    if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
669        miPointerMoveNoEvent(pDev, pScreen, x, y);
670
671    /* check if we generated any barrier events and if so, update root x/y
672     * to the fully constrained coords */
673    if (should_constrain_barriers) {
674        for (i = 0; i < *nevents; i++) {
675            if (events[i].any.type == ET_BarrierHit ||
676                events[i].any.type == ET_BarrierLeave) {
677                events[i].barrier_event.root_x = x;
678                events[i].barrier_event.root_y = y;
679            }
680        }
681    }
682
683    /* Convert to desktop coordinates again */
684    x += pScreen->x;
685    y += pScreen->y;
686
687    /* In the event we actually change screen or we get confined, we just
688     * drop the float component on the floor
689     * FIXME: only drop remainder for ConstrainCursorHarder, not for screen
690     * crossings */
691    if (x != trunc(*screenx))
692        *screenx = x;
693    if (y != trunc(*screeny))
694        *screeny = y;
695
696    return pScreen;
697}
698
699/**
700 * Get the current position of the device in desktop coordinates.
701 *
702 * @param x Return value for the current x coordinate in desktop coordiates.
703 * @param y Return value for the current y coordinate in desktop coordiates.
704 */
705void
706miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
707{
708    *x = MIPOINTER(pDev)->x;
709    *y = MIPOINTER(pDev)->y;
710}
711
712/**
713 * Move the device's pointer to the x/y coordinates on the given screen.
714 * This function generates and enqueues pointer events.
715 *
716 * @param pDev The device to move
717 * @param pScreen The screen the device is on
718 * @param x The x coordinate in per-screen coordinates
719 * @param y The y coordinate in per-screen coordinates
720 */
721void
722miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
723{
724    int i, nevents;
725    int valuators[2];
726    ValuatorMask mask;
727
728    miPointerMoveNoEvent(pDev, pScreen, x, y);
729
730    /* generate motion notify */
731    valuators[0] = x;
732    valuators[1] = y;
733
734    if (!mipointermove_events) {
735        mipointermove_events = InitEventList(GetMaximumEventsNum());
736
737        if (!mipointermove_events) {
738            FatalError("Could not allocate event store.\n");
739            return;
740        }
741    }
742
743    valuator_mask_set_range(&mask, 0, 2, valuators);
744    nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0,
745                               POINTER_SCREEN | POINTER_ABSOLUTE |
746                               POINTER_NORAW, &mask);
747
748    input_lock();
749    for (i = 0; i < nevents; i++)
750        mieqEnqueue(pDev, &mipointermove_events[i]);
751    input_unlock();
752}
753