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