mipointer.c revision bc1411c9
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#ifdef HAVE_DIX_CONFIG_H
27#include <dix-config.h>
28#endif
29
30# include   <X11/X.h>
31# include   <X11/Xmd.h>
32# include   <X11/Xproto.h>
33# include   "misc.h"
34# include   "windowstr.h"
35# include   "pixmapstr.h"
36# include   "mi.h"
37# include   "scrnintstr.h"
38# include   "mipointrst.h"
39# include   "cursorstr.h"
40# include   "dixstruct.h"
41# include   "inputstr.h"
42# include   "inpututils.h"
43
44# include   "eventstr.h"
45
46DevPrivateKeyRec miPointerScreenKeyRec;
47
48#define GetScreenPrivate(s) ((miPointerScreenPtr) \
49    dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey))
50#define SetupScreen(s)	miPointerScreenPtr  pScreenPriv = GetScreenPrivate(s)
51
52DevPrivateKeyRec miPointerPrivKeyRec;
53
54#define MIPOINTER(dev) \
55    ((!IsMaster(dev) && !dev->u.master) ? \
56        (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \
57        (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey))
58
59static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
60                                   CursorPtr pCursor);
61static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
62                                     CursorPtr pCursor);
63static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
64                                   CursorPtr pCursor);
65static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
66                                     BoxPtr pBox);
67static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen,
68                                  CursorPtr pCursor, BoxPtr pHotBox,
69                                  BoxPtr pTopLeftBox);
70static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
71                                       int x, int y,
72				       Bool generateEvent);
73static Bool miPointerCloseScreen(int index, ScreenPtr pScreen);
74static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen,
75                          int x, int y);
76static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen);
77static void miPointerDeviceCleanup(DeviceIntPtr pDev,
78                                   ScreenPtr pScreen);
79static void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y);
80
81static EventList* events; /* for WarpPointer MotionNotifies */
82
83Bool
84miPointerInitialize (ScreenPtr                  pScreen,
85                     miPointerSpriteFuncPtr     spriteFuncs,
86                     miPointerScreenFuncPtr     screenFuncs,
87                     Bool                       waitForUpdate)
88{
89    miPointerScreenPtr	pScreenPriv;
90
91    if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0))
92	return FALSE;
93
94    if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0))
95	return FALSE;
96
97    pScreenPriv = malloc(sizeof (miPointerScreenRec));
98    if (!pScreenPriv)
99	return FALSE;
100    pScreenPriv->spriteFuncs = spriteFuncs;
101    pScreenPriv->screenFuncs = screenFuncs;
102    /*
103     * check for uninitialized methods
104     */
105    if (!screenFuncs->EnqueueEvent)
106	screenFuncs->EnqueueEvent = mieqEnqueue;
107    if (!screenFuncs->NewEventScreen)
108	screenFuncs->NewEventScreen = mieqSwitchScreen;
109    pScreenPriv->waitForUpdate = waitForUpdate;
110    pScreenPriv->showTransparent = FALSE;
111    pScreenPriv->CloseScreen = pScreen->CloseScreen;
112    pScreen->CloseScreen = miPointerCloseScreen;
113    dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv);
114    /*
115     * set up screen cursor method table
116     */
117    pScreen->ConstrainCursor = miPointerConstrainCursor;
118    pScreen->CursorLimits = miPointerCursorLimits;
119    pScreen->DisplayCursor = miPointerDisplayCursor;
120    pScreen->RealizeCursor = miPointerRealizeCursor;
121    pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
122    pScreen->SetCursorPosition = miPointerSetCursorPosition;
123    pScreen->RecolorCursor = miRecolorCursor;
124    pScreen->DeviceCursorInitialize = miPointerDeviceInitialize;
125    pScreen->DeviceCursorCleanup = miPointerDeviceCleanup;
126
127    events = NULL;
128    return TRUE;
129}
130
131static Bool
132miPointerCloseScreen (int index, ScreenPtr pScreen)
133{
134#if 0
135    miPointerPtr pPointer;
136    DeviceIntPtr pDev;
137#endif
138
139    SetupScreen(pScreen);
140
141#if 0
142    for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
143    {
144        if (DevHasCursor(pDev))
145        {
146            pPointer = MIPOINTER(pDev);
147
148            if (pScreen == pPointer->pScreen)
149                pPointer->pScreen = 0;
150            if (pScreen == pPointer->pSpriteScreen)
151                pPointer->pSpriteScreen = 0;
152        }
153    }
154
155    if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen)
156        MIPOINTER(inputInfo.pointer)->pScreen = 0;
157    if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen)
158        MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0;
159#endif
160
161    pScreen->CloseScreen = pScreenPriv->CloseScreen;
162    free((pointer) pScreenPriv);
163    FreeEventList(events, GetMaximumEventsNum());
164    events = NULL;
165    return (*pScreen->CloseScreen) (index, pScreen);
166}
167
168/*
169 * DIX/DDX interface routines
170 */
171
172static Bool
173miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
174{
175    SetupScreen(pScreen);
176    return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor);
177}
178
179static Bool
180miPointerUnrealizeCursor (DeviceIntPtr  pDev,
181                          ScreenPtr     pScreen,
182                          CursorPtr     pCursor)
183{
184    SetupScreen(pScreen);
185    return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor);
186}
187
188static Bool
189miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
190{
191    miPointerPtr pPointer;
192
193    /* return for keyboards */
194    if ((IsMaster(pDev) && !DevHasCursor(pDev)) ||
195        (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master)))
196            return FALSE;
197
198    pPointer = MIPOINTER(pDev);
199
200    pPointer->pCursor = pCursor;
201    pPointer->pScreen = pScreen;
202    miPointerUpdateSprite(pDev);
203    return TRUE;
204}
205
206static void
207miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox)
208{
209    miPointerPtr pPointer;
210
211    pPointer = MIPOINTER(pDev);
212
213    pPointer->limits = *pBox;
214    pPointer->confined = PointerConfinedToScreen(pDev);
215}
216
217/*ARGSUSED*/
218static void
219miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor,
220                      BoxPtr pHotBox, BoxPtr pTopLeftBox)
221{
222    *pTopLeftBox = *pHotBox;
223}
224
225static Bool GenerateEvent;
226
227static Bool
228miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
229                           int x, int y, Bool generateEvent)
230{
231    SetupScreen (pScreen);
232
233    GenerateEvent = generateEvent;
234    /* device dependent - must pend signal and call miPointerWarpCursor */
235    (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
236    if (!generateEvent)
237	miPointerUpdateSprite(pDev);
238    return TRUE;
239}
240
241/* Set up sprite information for the device.
242   This function will be called once for each device after it is initialized
243   in the DIX.
244 */
245static Bool
246miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
247{
248    miPointerPtr pPointer;
249    SetupScreen (pScreen);
250
251    pPointer = malloc(sizeof(miPointerRec));
252    if (!pPointer)
253        return FALSE;
254
255    pPointer->pScreen = NULL;
256    pPointer->pSpriteScreen = NULL;
257    pPointer->pCursor = NULL;
258    pPointer->pSpriteCursor = NULL;
259    pPointer->limits.x1 = 0;
260    pPointer->limits.x2 = 32767;
261    pPointer->limits.y1 = 0;
262    pPointer->limits.y2 = 32767;
263    pPointer->confined = FALSE;
264    pPointer->x = 0;
265    pPointer->y = 0;
266
267    if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen)))
268    {
269        free(pPointer);
270        return FALSE;
271    }
272
273    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer);
274    return TRUE;
275}
276
277/* Clean up after device.
278   This function will be called once before the device is freed in the DIX
279 */
280static void
281miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
282{
283    SetupScreen(pScreen);
284
285    if (!IsMaster(pDev) && pDev->u.master)
286        return;
287
288    (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen);
289    free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey));
290    dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL);
291}
292
293
294/* Once signals are ignored, the WarpCursor function can call this */
295
296void
297miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
298{
299    miPointerPtr pPointer;
300    BOOL changedScreen = FALSE;
301
302    SetupScreen (pScreen);
303    pPointer = MIPOINTER(pDev);
304
305    if (pPointer->pScreen != pScreen)
306    {
307	(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE);
308        changedScreen = TRUE;
309    }
310
311    if (GenerateEvent)
312	miPointerMove (pDev, pScreen, x, y);
313    else
314        miPointerMoveNoEvent(pDev, pScreen, x, y);
315
316    /* Don't call USFS if we use Xinerama, otherwise the root window is
317     * updated to the second screen, and we never receive any events.
318     * (FDO bug #18668) */
319    if (changedScreen
320#ifdef PANORAMIX
321            && noPanoramiXExtension
322#endif
323       ) {
324            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
325            /* Hack for CVE-2023-5380: if we're moving
326             * screens PointerWindows[] keeps referring to the
327             * old window. If that gets destroyed we have a UAF
328             * bug later. Only happens when jumping from a window
329             * to the root window on the other screen.
330             * Enter/Leave events are incorrect for that case but
331             * too niche to fix.
332             */
333            LeaveWindow(pDev);
334            if (master)
335                LeaveWindow(master);
336            UpdateSpriteForScreen(pDev, pScreen);
337    }
338}
339
340/*
341 * Pointer/CursorDisplay interface routines
342 */
343
344/*
345 * miPointerUpdateSprite
346 *
347 * Syncronize the sprite with the cursor - called from ProcessInputEvents
348 */
349
350void
351miPointerUpdateSprite (DeviceIntPtr pDev)
352{
353    ScreenPtr		pScreen;
354    miPointerScreenPtr	pScreenPriv;
355    CursorPtr		pCursor;
356    int			x, y, devx, devy;
357    miPointerPtr        pPointer;
358
359    if (!pDev || !pDev->coreEvents)
360        return;
361
362    pPointer = MIPOINTER(pDev);
363
364    if (!pPointer)
365        return;
366
367    pScreen = pPointer->pScreen;
368    if (!pScreen)
369	return;
370
371    x = pPointer->x;
372    y = pPointer->y;
373    devx = pPointer->devx;
374    devy = pPointer->devy;
375
376    pScreenPriv = GetScreenPrivate (pScreen);
377    /*
378     * if the cursor has switched screens, disable the sprite
379     * on the old screen
380     */
381    if (pScreen != pPointer->pSpriteScreen)
382    {
383	if (pPointer->pSpriteScreen)
384	{
385	    miPointerScreenPtr  pOldPriv;
386
387	    pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen);
388	    if (pPointer->pCursor)
389	    {
390	    	(*pOldPriv->spriteFuncs->SetCursor)
391			    	(pDev, pPointer->pSpriteScreen, NullCursor, 0, 0);
392	    }
393	    (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE);
394	}
395	(*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
396	(*pScreenPriv->spriteFuncs->SetCursor)
397				(pDev, pScreen, pPointer->pCursor, x, y);
398	pPointer->devx = x;
399	pPointer->devy = y;
400	pPointer->pSpriteCursor = pPointer->pCursor;
401	pPointer->pSpriteScreen = pScreen;
402    }
403    /*
404     * if the cursor has changed, display the new one
405     */
406    else if (pPointer->pCursor != pPointer->pSpriteCursor)
407    {
408	pCursor = pPointer->pCursor;
409	if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
410	    pCursor = NullCursor;
411	(*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y);
412
413	pPointer->devx = x;
414	pPointer->devy = y;
415	pPointer->pSpriteCursor = pPointer->pCursor;
416    }
417    else if (x != devx || y != devy)
418    {
419	pPointer->devx = x;
420	pPointer->devy = y;
421	if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
422	    (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
423    }
424}
425
426void
427miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
428{
429	miPointerScreenPtr pScreenPriv;
430	ScreenPtr pScreen;
431        miPointerPtr pPointer;
432
433        pPointer = MIPOINTER(pDev);
434
435	pScreen = screenInfo.screens[screen_no];
436	pScreenPriv = GetScreenPrivate (pScreen);
437	(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE);
438	NewCurrentScreen (pDev, pScreen, x, y);
439
440        pPointer->limits.x2 = pScreen->width;
441        pPointer->limits.y2 = pScreen->height;
442}
443
444ScreenPtr
445miPointerCurrentScreen (void)
446{
447    return miPointerGetScreen(inputInfo.pointer);
448}
449
450ScreenPtr
451miPointerGetScreen(DeviceIntPtr pDev)
452{
453    miPointerPtr pPointer = MIPOINTER(pDev);
454    return (pPointer) ? pPointer->pScreen : NULL;
455}
456
457/* Controls whether the cursor image should be updated immediately when
458   moved (FALSE) or if something else will be responsible for updating
459   it later (TRUE).  Returns current setting.
460   Caller is responsible for calling OsBlockSignal first.
461*/
462Bool
463miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait)
464{
465    SetupScreen(pScreen);
466    Bool prevWait = pScreenPriv->waitForUpdate;
467
468    pScreenPriv->waitForUpdate = wait;
469    return prevWait;
470}
471
472
473/* Move the pointer on the current screen,  and update the sprite. */
474static void
475miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen,
476                int x, int y)
477{
478    miPointerPtr pPointer;
479    SetupScreen(pScreen);
480
481    pPointer = MIPOINTER(pDev);
482
483    /* Hack: We mustn't call into ->MoveCursor for anything but the
484     * VCP, as this may cause a non-HW rendered cursor to be rendered during
485     * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT.
486     */
487    if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer))
488        && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen)
489    {
490	pPointer->devx = x;
491	pPointer->devy = y;
492	if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
493	    (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
494    }
495
496    pPointer->x = x;
497    pPointer->y = y;
498    pPointer->pScreen = pScreen;
499}
500
501void
502miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y)
503{
504    miPointerScreenPtr	pScreenPriv;
505    ScreenPtr		pScreen;
506    ScreenPtr		newScreen;
507
508    miPointerPtr        pPointer;
509
510    if (!pDev || !pDev->coreEvents)
511        return;
512
513    pPointer = MIPOINTER(pDev);
514    pScreen = pPointer->pScreen;
515    if (!pScreen)
516	return;	    /* called before ready */
517
518    if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height)
519    {
520	pScreenPriv = GetScreenPrivate (pScreen);
521	if (!pPointer->confined)
522	{
523	    newScreen = pScreen;
524	    (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y);
525	    if (newScreen != pScreen)
526	    {
527		pScreen = newScreen;
528		(*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen,
529							     FALSE);
530	    	/* Smash the confine to the new screen */
531                pPointer->limits.x2 = pScreen->width;
532                pPointer->limits.y2 = pScreen->height;
533	    }
534	}
535    }
536    /* Constrain the sprite to the current limits. */
537    if (*x < pPointer->limits.x1)
538	*x = pPointer->limits.x1;
539    if (*x >= pPointer->limits.x2)
540	*x = pPointer->limits.x2 - 1;
541    if (*y < pPointer->limits.y1)
542	*y = pPointer->limits.y1;
543    if (*y >= pPointer->limits.y2)
544	*y = pPointer->limits.y2 - 1;
545
546    if (pPointer->x == *x && pPointer->y == *y &&
547            pPointer->pScreen == pScreen)
548        return;
549
550    miPointerMoveNoEvent(pDev, pScreen, *x, *y);
551}
552
553void
554miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
555{
556    *x = MIPOINTER(pDev)->x;
557    *y = MIPOINTER(pDev)->y;
558}
559
560#ifdef XQUARTZ
561#include <pthread.h>
562void darwinEvents_lock(void);
563void darwinEvents_unlock(void);
564#endif
565
566void
567miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
568{
569    int i, nevents;
570    int valuators[2];
571    ValuatorMask mask;
572
573    miPointerMoveNoEvent(pDev, pScreen, x, y);
574
575    /* generate motion notify */
576    valuators[0] = x;
577    valuators[1] = y;
578
579    if (!events)
580    {
581        events = InitEventList(GetMaximumEventsNum());
582
583        if (!events)
584        {
585            FatalError("Could not allocate event store.\n");
586            return;
587        }
588    }
589
590    valuator_mask_set_range(&mask, 0, 2, valuators);
591    nevents = GetPointerEvents(events, pDev, MotionNotify, 0,
592                               POINTER_SCREEN | POINTER_ABSOLUTE | POINTER_NORAW, &mask);
593
594    OsBlockSignals();
595#ifdef XQUARTZ
596    darwinEvents_lock();
597#endif
598    for (i = 0; i < nevents; i++)
599        mieqEnqueue(pDev, (InternalEvent*)events[i].event);
600#ifdef XQUARTZ
601    darwinEvents_unlock();
602#endif
603    OsReleaseSignals();
604}
605