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 * Syncronize 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 coordiates.
703 * @param y Return value for the current y coordinate in desktop coordiates.
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