Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | DevPrivateKeyRec miPointerScreenKeyRec; | |
69 | ||
70 | #define GetScreenPrivate(s) ((miPointerScreenPtr) \ | |
71 | dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) | |
72 | #define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) | |
73 | ||
74 | DevPrivateKeyRec miPointerPrivKeyRec; | |
75 | ||
76 | #define MIPOINTER(dev) \ | |
77 | (IsFloating(dev) ? \ | |
78 | (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ | |
79 | (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) | |
80 | ||
81 | static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
82 | CursorPtr pCursor); | |
83 | static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
84 | CursorPtr pCursor); | |
85 | static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
86 | CursorPtr pCursor); | |
87 | static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, | |
88 | BoxPtr pBox); | |
89 | static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, | |
90 | CursorPtr pCursor, BoxPtr pHotBox, | |
91 | BoxPtr pTopLeftBox); | |
92 | static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, | |
93 | int x, int y, Bool generateEvent); | |
94 | static Bool miPointerCloseScreen(ScreenPtr pScreen); | |
95 | static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); | |
96 | static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); | |
97 | static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); | |
98 | static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, | |
99 | int y); | |
100 | ||
101 | static InternalEvent *mipointermove_events; /* for WarpPointer MotionNotifies */ | |
102 | ||
103 | Bool | |
104 | miPointerInitialize(ScreenPtr pScreen, | |
105 | miPointerSpriteFuncPtr spriteFuncs, | |
106 | miPointerScreenFuncPtr screenFuncs, Bool waitForUpdate) | |
107 | { | |
108 | miPointerScreenPtr pScreenPriv; | |
109 | ||
110 | if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) | |
111 | return FALSE; | |
112 | ||
113 | if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) | |
114 | return FALSE; | |
115 | ||
116 | pScreenPriv = malloc(sizeof(miPointerScreenRec)); | |
117 | if (!pScreenPriv) | |
118 | return FALSE; | |
119 | pScreenPriv->spriteFuncs = spriteFuncs; | |
120 | pScreenPriv->screenFuncs = screenFuncs; | |
121 | pScreenPriv->waitForUpdate = waitForUpdate; | |
122 | pScreenPriv->showTransparent = FALSE; | |
123 | pScreenPriv->CloseScreen = pScreen->CloseScreen; | |
124 | pScreen->CloseScreen = miPointerCloseScreen; | |
125 | dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); | |
126 | /* | |
127 | * set up screen cursor method table | |
128 | */ | |
129 | pScreen->ConstrainCursor = miPointerConstrainCursor; | |
130 | pScreen->CursorLimits = miPointerCursorLimits; | |
131 | pScreen->DisplayCursor = miPointerDisplayCursor; | |
132 | pScreen->RealizeCursor = miPointerRealizeCursor; | |
133 | pScreen->UnrealizeCursor = miPointerUnrealizeCursor; | |
134 | pScreen->SetCursorPosition = miPointerSetCursorPosition; | |
135 | pScreen->RecolorCursor = miRecolorCursor; | |
136 | pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; | |
137 | pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; | |
138 | ||
139 | mipointermove_events = NULL; | |
140 | return TRUE; | |
141 | } | |
142 | ||
143 | /** | |
144 | * Destroy screen-specific information. | |
145 | * | |
146 | * @param index Screen index of the screen in screenInfo.screens[] | |
147 | * @param pScreen The actual screen pointer | |
148 | */ | |
149 | static Bool | |
150 | miPointerCloseScreen(ScreenPtr pScreen) | |
151 | { | |
152 | SetupScreen(pScreen); | |
153 | ||
154 | pScreen->CloseScreen = pScreenPriv->CloseScreen; | |
155 | free((pointer) pScreenPriv); | |
156 | FreeEventList(mipointermove_events, GetMaximumEventsNum()); | |
157 | mipointermove_events = NULL; | |
158 | return (*pScreen->CloseScreen) (pScreen); | |
159 | } | |
160 | ||
161 | /* | |
162 | * DIX/DDX interface routines | |
163 | */ | |
164 | ||
165 | static Bool | |
166 | miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
167 | { | |
168 | SetupScreen(pScreen); | |
169 | return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); | |
170 | } | |
171 | ||
172 | static Bool | |
173 | miPointerUnrealizeCursor(DeviceIntPtr pDev, | |
174 | ScreenPtr pScreen, CursorPtr pCursor) | |
175 | { | |
176 | SetupScreen(pScreen); | |
177 | return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, | |
178 | pCursor); | |
179 | } | |
180 | ||
181 | static Bool | |
182 | miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
183 | { | |
184 | miPointerPtr pPointer; | |
185 | ||
186 | /* return for keyboards */ | |
187 | if (!IsPointerDevice(pDev)) | |
188 | return FALSE; | |
189 | ||
190 | pPointer = MIPOINTER(pDev); | |
191 | ||
192 | pPointer->pCursor = pCursor; | |
193 | pPointer->pScreen = pScreen; | |
194 | miPointerUpdateSprite(pDev); | |
195 | return TRUE; | |
196 | } | |
197 | ||
198 | /** | |
199 | * Set up the constraints for the given device. This function does not | |
200 | * actually constrain the cursor but merely copies the given box to the | |
201 | * internal constraint storage. | |
202 | * | |
203 | * @param pDev The device to constrain to the box | |
204 | * @param pBox The rectangle to constrain the cursor to | |
205 | * @param pScreen Used for copying screen confinement | |
206 | */ | |
207 | static void | |
208 | miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) | |
209 | { | |
210 | miPointerPtr pPointer; | |
211 | ||
212 | pPointer = MIPOINTER(pDev); | |
213 | ||
214 | pPointer->limits = *pBox; | |
215 | pPointer->confined = PointerConfinedToScreen(pDev); | |
216 | } | |
217 | ||
218 | /** | |
219 | * Should calculate the box for the given cursor, based on screen and the | |
220 | * confinement given. But we assume that whatever box is passed in is valid | |
221 | * anyway. | |
222 | * | |
223 | * @param pDev The device to calculate the cursor limits for | |
224 | * @param pScreen The screen the confinement happens on | |
225 | * @param pCursor The screen the confinement happens on | |
226 | * @param pHotBox The confinement box for the cursor | |
227 | * @param[out] pTopLeftBox The new confinement box, always *pHotBox. | |
228 | */ | |
229 | static void | |
230 | miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, | |
231 | BoxPtr pHotBox, BoxPtr pTopLeftBox) | |
232 | { | |
233 | *pTopLeftBox = *pHotBox; | |
234 | } | |
235 | ||
236 | /** | |
237 | * Set the device's cursor position to the x/y position on the given screen. | |
238 | * Generates and event if required. | |
239 | * | |
240 | * This function is called from: | |
241 | * - sprite init code to place onto initial position | |
242 | * - the various WarpPointer implementations (core, XI, Xinerama, dmx,…) | |
243 | * - during the cursor update path in CheckMotion | |
244 | * - in the Xinerama part of NewCurrentScreen | |
245 | * - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so | |
246 | * it's set back to the original pos) | |
247 | * | |
248 | * @param pDev The device to move | |
249 | * @param pScreen The screen the device is on | |
250 | * @param x The x coordinate in per-screen coordinates | |
251 | * @param y The y coordinate in per-screen coordinates | |
252 | * @param generateEvent True if the pointer movement should generate an | |
253 | * event. | |
254 | * | |
255 | * @return TRUE in all cases | |
256 | */ | |
257 | static Bool | |
258 | miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, | |
259 | int x, int y, Bool generateEvent) | |
260 | { | |
261 | SetupScreen(pScreen); | |
262 | miPointerPtr pPointer = MIPOINTER(pDev); | |
263 | ||
264 | pPointer->generateEvent = generateEvent; | |
265 | ||
266 | if (pScreen->ConstrainCursorHarder) | |
267 | pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y); | |
268 | ||
269 | /* device dependent - must pend signal and call miPointerWarpCursor */ | |
270 | (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); | |
271 | if (!generateEvent) | |
272 | miPointerUpdateSprite(pDev); | |
273 | return TRUE; | |
274 | } | |
275 | ||
276 | /** | |
277 | * Set up sprite information for the device. | |
278 | * This function will be called once for each device after it is initialized | |
279 | * in the DIX. | |
280 | * | |
281 | * @param pDev The newly created device | |
282 | * @param pScreen The initial sprite scree. | |
283 | */ | |
284 | static Bool | |
285 | miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) | |
286 | { | |
287 | miPointerPtr pPointer; | |
288 | ||
289 | SetupScreen(pScreen); | |
290 | ||
291 | pPointer = malloc(sizeof(miPointerRec)); | |
292 | if (!pPointer) | |
293 | return FALSE; | |
294 | ||
295 | pPointer->pScreen = NULL; | |
296 | pPointer->pSpriteScreen = NULL; | |
297 | pPointer->pCursor = NULL; | |
298 | pPointer->pSpriteCursor = NULL; | |
299 | pPointer->limits.x1 = 0; | |
300 | pPointer->limits.x2 = 32767; | |
301 | pPointer->limits.y1 = 0; | |
302 | pPointer->limits.y2 = 32767; | |
303 | pPointer->confined = FALSE; | |
304 | pPointer->x = 0; | |
305 | pPointer->y = 0; | |
306 | pPointer->generateEvent = FALSE; | |
307 | ||
308 | if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen))) { | |
309 | free(pPointer); | |
310 | return FALSE; | |
311 | } | |
312 | ||
313 | dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); | |
314 | return TRUE; | |
315 | } | |
316 | ||
317 | /** | |
318 | * Clean up after device. | |
319 | * This function will be called once before the device is freed in the DIX | |
320 | * | |
321 | * @param pDev The device to be removed from the server | |
322 | * @param pScreen Current screen of the device | |
323 | */ | |
324 | static void | |
325 | miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) | |
326 | { | |
327 | SetupScreen(pScreen); | |
328 | ||
329 | if (!IsMaster(pDev) && !IsFloating(pDev)) | |
330 | return; | |
331 | ||
332 | (*pScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen); | |
333 | free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); | |
334 | dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); | |
335 | } | |
336 | ||
337 | /** | |
338 | * Warp the pointer to the given position on the given screen. May generate | |
339 | * an event, depending on whether we're coming from miPointerSetPosition. | |
340 | * | |
341 | * Once signals are ignored, the WarpCursor function can call this | |
342 | * | |
343 | * @param pDev The device to warp | |
344 | * @param pScreen Screen to warp on | |
345 | * @param x The x coordinate in per-screen coordinates | |
346 | * @param y The y coordinate in per-screen coordinates | |
347 | */ | |
348 | ||
349 | void | |
350 | miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) | |
351 | { | |
352 | miPointerPtr pPointer; | |
353 | BOOL changedScreen = FALSE; | |
354 | ||
355 | SetupScreen(pScreen); | |
356 | pPointer = MIPOINTER(pDev); | |
357 | ||
358 | if (pPointer->pScreen != pScreen) { | |
359 | mieqSwitchScreen(pDev, pScreen, TRUE); | |
360 | changedScreen = TRUE; | |
361 | } | |
362 | ||
363 | if (pPointer->generateEvent) | |
364 | miPointerMove(pDev, pScreen, x, y); | |
365 | else | |
366 | miPointerMoveNoEvent(pDev, pScreen, x, y); | |
367 | ||
368 | /* Don't call USFS if we use Xinerama, otherwise the root window is | |
369 | * updated to the second screen, and we never receive any events. | |
370 | * (FDO bug #18668) */ | |
371 | if (changedScreen | |
372 | #ifdef PANORAMIX | |
373 | && noPanoramiXExtension | |
374 | #endif | |
375 | ) | |
376 | UpdateSpriteForScreen(pDev, pScreen); | |
377 | } | |
378 | ||
379 | /** | |
380 | * Syncronize the sprite with the cursor. | |
381 | * | |
382 | * @param pDev The device to sync | |
383 | */ | |
384 | void | |
385 | miPointerUpdateSprite(DeviceIntPtr pDev) | |
386 | { | |
387 | ScreenPtr pScreen; | |
388 | miPointerScreenPtr pScreenPriv; | |
389 | CursorPtr pCursor; | |
390 | int x, y, devx, devy; | |
391 | miPointerPtr pPointer; | |
392 | ||
393 | if (!pDev || !pDev->coreEvents) | |
394 | return; | |
395 | ||
396 | pPointer = MIPOINTER(pDev); | |
397 | ||
398 | if (!pPointer) | |
399 | return; | |
400 | ||
401 | pScreen = pPointer->pScreen; | |
402 | if (!pScreen) | |
403 | return; | |
404 | ||
405 | x = pPointer->x; | |
406 | y = pPointer->y; | |
407 | devx = pPointer->devx; | |
408 | devy = pPointer->devy; | |
409 | ||
410 | pScreenPriv = GetScreenPrivate(pScreen); | |
411 | /* | |
412 | * if the cursor has switched screens, disable the sprite | |
413 | * on the old screen | |
414 | */ | |
415 | if (pScreen != pPointer->pSpriteScreen) { | |
416 | if (pPointer->pSpriteScreen) { | |
417 | miPointerScreenPtr pOldPriv; | |
418 | ||
419 | pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen); | |
420 | if (pPointer->pCursor) { | |
421 | (*pOldPriv->spriteFuncs->SetCursor) | |
422 | (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); | |
423 | } | |
424 | (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, | |
425 | FALSE); | |
426 | } | |
427 | (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); | |
428 | (*pScreenPriv->spriteFuncs->SetCursor) | |
429 | (pDev, pScreen, pPointer->pCursor, x, y); | |
430 | pPointer->devx = x; | |
431 | pPointer->devy = y; | |
432 | pPointer->pSpriteCursor = pPointer->pCursor; | |
433 | pPointer->pSpriteScreen = pScreen; | |
434 | } | |
435 | /* | |
436 | * if the cursor has changed, display the new one | |
437 | */ | |
438 | else if (pPointer->pCursor != pPointer->pSpriteCursor) { | |
439 | pCursor = pPointer->pCursor; | |
440 | if (!pCursor || | |
441 | (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) | |
442 | pCursor = NullCursor; | |
443 | (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); | |
444 | ||
445 | pPointer->devx = x; | |
446 | pPointer->devy = y; | |
447 | pPointer->pSpriteCursor = pPointer->pCursor; | |
448 | } | |
449 | else if (x != devx || y != devy) { | |
450 | pPointer->devx = x; | |
451 | pPointer->devy = y; | |
452 | if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) | |
453 | (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); | |
454 | } | |
455 | } | |
456 | ||
457 | /** | |
458 | * Set the device to the coordinates on the given screen. | |
459 | * | |
460 | * @param pDev The device to move | |
461 | * @param screen_no Index of the screen to move to | |
462 | * @param x The x coordinate in per-screen coordinates | |
463 | * @param y The y coordinate in per-screen coordinates | |
464 | */ | |
465 | void | |
466 | miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) | |
467 | { | |
468 | miPointerScreenPtr pScreenPriv; | |
469 | ScreenPtr pScreen; | |
470 | miPointerPtr pPointer; | |
471 | ||
472 | pPointer = MIPOINTER(pDev); | |
473 | ||
474 | pScreen = screenInfo.screens[screen_no]; | |
475 | pScreenPriv = GetScreenPrivate(pScreen); | |
476 | mieqSwitchScreen(pDev, pScreen, FALSE); | |
477 | NewCurrentScreen(pDev, pScreen, x, y); | |
478 | ||
479 | pPointer->limits.x2 = pScreen->width; | |
480 | pPointer->limits.y2 = pScreen->height; | |
481 | } | |
482 | ||
483 | /** | |
484 | * @return The current screen of the given device or NULL. | |
485 | */ | |
486 | ScreenPtr | |
487 | miPointerGetScreen(DeviceIntPtr pDev) | |
488 | { | |
489 | miPointerPtr pPointer = MIPOINTER(pDev); | |
490 | ||
491 | return (pPointer) ? pPointer->pScreen : NULL; | |
492 | } | |
493 | ||
494 | /* Controls whether the cursor image should be updated immediately when | |
495 | moved (FALSE) or if something else will be responsible for updating | |
496 | it later (TRUE). Returns current setting. | |
497 | Caller is responsible for calling OsBlockSignal first. | |
498 | */ | |
499 | Bool | |
500 | miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) | |
501 | { | |
502 | SetupScreen(pScreen); | |
503 | Bool prevWait = pScreenPriv->waitForUpdate; | |
504 | ||
505 | pScreenPriv->waitForUpdate = wait; | |
506 | return prevWait; | |
507 | } | |
508 | ||
509 | /* Move the pointer on the current screen, and update the sprite. */ | |
510 | static void | |
511 | miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) | |
512 | { | |
513 | miPointerPtr pPointer; | |
514 | ||
515 | SetupScreen(pScreen); | |
516 | ||
517 | pPointer = MIPOINTER(pDev); | |
518 | ||
519 | /* Hack: We mustn't call into ->MoveCursor for anything but the | |
520 | * VCP, as this may cause a non-HW rendered cursor to be rendered during | |
521 | * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. | |
522 | */ | |
523 | if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer | |
524 | &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) { | |
525 | pPointer->devx = x; | |
526 | pPointer->devy = y; | |
527 | if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) | |
528 | (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); | |
529 | } | |
530 | ||
531 | pPointer->x = x; | |
532 | pPointer->y = y; | |
533 | pPointer->pScreen = pScreen; | |
534 | } | |
535 | ||
536 | /** | |
537 | * Set the devices' cursor position to the given x/y position. | |
538 | * | |
539 | * This function is called during the pointer update path in | |
540 | * GetPointerEvents and friends (and the same in the xwin DDX). | |
541 | * | |
542 | * The coordinates provided are always absolute. The parameter mode whether | |
543 | * it was relative or absolute movement that landed us at those coordinates. | |
544 | * | |
545 | * @param pDev The device to move | |
546 | * @param mode Movement mode (Absolute or Relative) | |
547 | * @param[in,out] screenx The x coordinate in desktop coordinates | |
548 | * @param[in,out] screeny The y coordinate in desktop coordinates | |
549 | */ | |
550 | ScreenPtr | |
551 | miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, | |
552 | double *screeny, | |
553 | int *nevents, InternalEvent* events) | |
554 | { | |
555 | miPointerScreenPtr pScreenPriv; | |
556 | ScreenPtr pScreen; | |
557 | ScreenPtr newScreen; | |
558 | int x, y; | |
559 | Bool switch_screen = FALSE; | |
560 | Bool should_constrain_barriers = FALSE; | |
561 | int i; | |
562 | ||
563 | miPointerPtr pPointer; | |
564 | ||
565 | pPointer = MIPOINTER(pDev); | |
566 | pScreen = pPointer->pScreen; | |
567 | ||
568 | x = trunc(*screenx); | |
569 | y = trunc(*screeny); | |
570 | ||
571 | switch_screen = !point_on_screen(pScreen, x, y); | |
572 | ||
573 | /* Switch to per-screen coordinates for CursorOffScreen and | |
574 | * Pointer->limits */ | |
575 | x -= pScreen->x; | |
576 | y -= pScreen->y; | |
577 | ||
578 | should_constrain_barriers = (mode == Relative); | |
579 | ||
580 | if (should_constrain_barriers) { | |
581 | /* coordinates after clamped to a barrier */ | |
582 | int constrained_x, constrained_y; | |
583 | int current_x, current_y; /* current position in per-screen coord */ | |
584 | ||
585 | current_x = MIPOINTER(pDev)->x - pScreen->y; | |
586 | current_y = MIPOINTER(pDev)->y - pScreen->x; | |
587 | ||
588 | input_constrain_cursor(pDev, pScreen, | |
589 | current_x, current_y, x, y, | |
590 | &constrained_x, &constrained_y, | |
591 | nevents, events); | |
592 | ||
593 | x = constrained_x; | |
594 | y = constrained_y; | |
595 | } | |
596 | ||
597 | if (switch_screen) { | |
598 | pScreenPriv = GetScreenPrivate(pScreen); | |
599 | if (!pPointer->confined) { | |
600 | newScreen = pScreen; | |
601 | (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y); | |
602 | if (newScreen != pScreen) { | |
603 | pScreen = newScreen; | |
604 | mieqSwitchScreen(pDev, pScreen, FALSE); | |
605 | /* Smash the confine to the new screen */ | |
606 | pPointer->limits.x2 = pScreen->width; | |
607 | pPointer->limits.y2 = pScreen->height; | |
608 | } | |
609 | } | |
610 | } | |
611 | /* Constrain the sprite to the current limits. */ | |
612 | if (x < pPointer->limits.x1) | |
613 | x = pPointer->limits.x1; | |
614 | if (x >= pPointer->limits.x2) | |
615 | x = pPointer->limits.x2 - 1; | |
616 | if (y < pPointer->limits.y1) | |
617 | y = pPointer->limits.y1; | |
618 | if (y >= pPointer->limits.y2) | |
619 | y = pPointer->limits.y2 - 1; | |
620 | ||
621 | if (pScreen->ConstrainCursorHarder) | |
622 | pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y); | |
623 | ||
624 | if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen) | |
625 | miPointerMoveNoEvent(pDev, pScreen, x, y); | |
626 | ||
627 | /* check if we generated any barrier events and if so, update root x/y | |
628 | * to the fully constrained coords */ | |
629 | if (should_constrain_barriers) { | |
630 | for (i = 0; i < *nevents; i++) { | |
631 | if (events[i].any.type == ET_BarrierHit || | |
632 | events[i].any.type == ET_BarrierLeave) { | |
633 | events[i].barrier_event.root_x = x; | |
634 | events[i].barrier_event.root_y = y; | |
635 | } | |
636 | } | |
637 | } | |
638 | ||
639 | /* Convert to desktop coordinates again */ | |
640 | x += pScreen->x; | |
641 | y += pScreen->y; | |
642 | ||
643 | /* In the event we actually change screen or we get confined, we just | |
644 | * drop the float component on the floor | |
645 | * FIXME: only drop remainder for ConstrainCursorHarder, not for screen | |
646 | * crossings */ | |
647 | if (x != trunc(*screenx)) | |
648 | *screenx = x; | |
649 | if (y != trunc(*screeny)) | |
650 | *screeny = y; | |
651 | ||
652 | return pScreen; | |
653 | } | |
654 | ||
655 | /** | |
656 | * Get the current position of the device in desktop coordinates. | |
657 | * | |
658 | * @param x Return value for the current x coordinate in desktop coordiates. | |
659 | * @param y Return value for the current y coordinate in desktop coordiates. | |
660 | */ | |
661 | void | |
662 | miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) | |
663 | { | |
664 | *x = MIPOINTER(pDev)->x; | |
665 | *y = MIPOINTER(pDev)->y; | |
666 | } | |
667 | ||
668 | #ifdef XQUARTZ | |
669 | #include <pthread.h> | |
670 | void darwinEvents_lock(void); | |
671 | void darwinEvents_unlock(void); | |
672 | #endif | |
673 | ||
674 | /** | |
675 | * Move the device's pointer to the x/y coordinates on the given screen. | |
676 | * This function generates and enqueues pointer events. | |
677 | * | |
678 | * @param pDev The device to move | |
679 | * @param pScreen The screen the device is on | |
680 | * @param x The x coordinate in per-screen coordinates | |
681 | * @param y The y coordinate in per-screen coordinates | |
682 | */ | |
683 | void | |
684 | miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) | |
685 | { | |
686 | int i, nevents; | |
687 | int valuators[2]; | |
688 | ValuatorMask mask; | |
689 | ||
690 | miPointerMoveNoEvent(pDev, pScreen, x, y); | |
691 | ||
692 | /* generate motion notify */ | |
693 | valuators[0] = x; | |
694 | valuators[1] = y; | |
695 | ||
696 | if (!mipointermove_events) { | |
697 | mipointermove_events = InitEventList(GetMaximumEventsNum()); | |
698 | ||
699 | if (!mipointermove_events) { | |
700 | FatalError("Could not allocate event store.\n"); | |
701 | return; | |
702 | } | |
703 | } | |
704 | ||
705 | valuator_mask_set_range(&mask, 0, 2, valuators); | |
706 | nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0, | |
707 | POINTER_SCREEN | POINTER_ABSOLUTE | | |
708 | POINTER_NORAW, &mask); | |
709 | ||
710 | OsBlockSignals(); | |
711 | #ifdef XQUARTZ | |
712 | darwinEvents_lock(); | |
713 | #endif | |
714 | for (i = 0; i < nevents; i++) | |
715 | mieqEnqueue(pDev, &mipointermove_events[i]); | |
716 | #ifdef XQUARTZ | |
717 | darwinEvents_unlock(); | |
718 | #endif | |
719 | OsReleaseSignals(); | |
720 | } |