1 /*
2 
3 Copyright 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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 
68 typedef 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 
80 DevPrivateKeyRec miPointerScreenKeyRec;
81 
82 #define GetScreenPrivate(s) ((miPointerScreenPtr) \
83     dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey))
84 #define SetupScreen(s)	miPointerScreenPtr  pScreenPriv = GetScreenPrivate(s)
85 
86 DevPrivateKeyRec 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 
93 static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
94                                    CursorPtr pCursor);
95 static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
96                                      CursorPtr pCursor);
97 static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
98                                    CursorPtr pCursor);
99 static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
100                                      BoxPtr pBox);
101 static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen,
102                                   CursorPtr pCursor, BoxPtr pHotBox,
103                                   BoxPtr pTopLeftBox);
104 static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
105                                        int x, int y, Bool generateEvent);
106 static Bool miPointerCloseScreen(ScreenPtr pScreen);
107 static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
108 static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen);
109 static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
110 static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x,
111                                  int y);
112 
113 static InternalEvent *mipointermove_events;   /* for WarpPointer MotionNotifies */
114 
115 Bool
miPointerInitialize(ScreenPtr pScreen,miPointerSpriteFuncPtr spriteFuncs,miPointerScreenFuncPtr screenFuncs,Bool waitForUpdate)116 miPointerInitialize(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  */
161 static Bool
miPointerCloseScreen(ScreenPtr pScreen)162 miPointerCloseScreen(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 
177 static Bool
miPointerRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)178 miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
179 {
180     SetupScreen(pScreen);
181     return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor);
182 }
183 
184 static Bool
miPointerUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)185 miPointerUnrealizeCursor(DeviceIntPtr pDev,
186                          ScreenPtr pScreen, CursorPtr pCursor)
187 {
188     SetupScreen(pScreen);
189     return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen,
190                                                          pCursor);
191 }
192 
193 static Bool
miPointerDisplayCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)194 miPointerDisplayCursor(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  */
219 static void
miPointerConstrainCursor(DeviceIntPtr pDev,ScreenPtr pScreen,BoxPtr pBox)220 miPointerConstrainCursor(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  */
241 static void
miPointerCursorLimits(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,BoxPtr pHotBox,BoxPtr pTopLeftBox)242 miPointerCursorLimits(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  */
269 static Bool
miPointerSetCursorPosition(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y,Bool generateEvent)270 miPointerSetCursorPosition(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 
288 void
miRecolorCursor(DeviceIntPtr pDev,ScreenPtr pScr,CursorPtr pCurs,Bool displayed)289 miRecolorCursor(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  */
310 static Bool
miPointerDeviceInitialize(DeviceIntPtr pDev,ScreenPtr pScreen)311 miPointerDeviceInitialize(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  */
350 static void
miPointerDeviceCleanup(DeviceIntPtr pDev,ScreenPtr pScreen)351 miPointerDeviceCleanup(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 
375 void
miPointerWarpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)376 miPointerWarpCursor(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  * Synchronize the sprite with the cursor.
406  *
407  * @param pDev The device to sync
408  */
409 void
miPointerUpdateSprite(DeviceIntPtr pDev)410 miPointerUpdateSprite(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  */
488 void
miPointerInvalidateSprite(DeviceIntPtr pDev)489 miPointerInvalidateSprite(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  */
505 void
miPointerSetScreen(DeviceIntPtr pDev,int screen_no,int x,int y)506 miPointerSetScreen(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  */
524 ScreenPtr
miPointerGetScreen(DeviceIntPtr pDev)525 miPointerGetScreen(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 */
537 Bool
miPointerSetWaitForUpdate(ScreenPtr pScreen,Bool wait)538 miPointerSetWaitForUpdate(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. */
548 static void
miPointerMoveNoEvent(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)549 miPointerMoveNoEvent(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  */
594 ScreenPtr
miPointerSetPosition(DeviceIntPtr pDev,int mode,double * screenx,double * screeny,int * nevents,InternalEvent * events)595 miPointerSetPosition(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 coordinates.
703  * @param y Return value for the current y coordinate in desktop coordinates.
704  */
705 void
miPointerGetPosition(DeviceIntPtr pDev,int * x,int * y)706 miPointerGetPosition(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  */
721 void
miPointerMove(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)722 miPointerMove(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