animcur.c revision 9ace9065
1/*
2 *
3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24/*
25 * Animated cursors for X.  Not specific to Render in any way, but
26 * stuck there because Render has the other cool cursor extension.
27 * Besides, everyone has Render.
28 *
29 * Implemented as a simple layer over the core cursor code; it
30 * creates composite cursors out of a set of static cursors and
31 * delta times between each image.
32 */
33
34#ifdef HAVE_DIX_CONFIG_H
35#include <dix-config.h>
36#endif
37
38#include <X11/X.h>
39#include <X11/Xmd.h>
40#include "servermd.h"
41#include "scrnintstr.h"
42#include "dixstruct.h"
43#include "cursorstr.h"
44#include "dixfontstr.h"
45#include "opaque.h"
46#include "picturestr.h"
47#include "inputstr.h"
48#include "xace.h"
49
50typedef struct _AnimCurElt {
51    CursorPtr	pCursor;    /* cursor to show */
52    CARD32	delay;	    /* in ms */
53} AnimCurElt;
54
55typedef struct _AnimCur {
56    int		nelt;	    /* number of elements in the elts array */
57    AnimCurElt	*elts;	    /* actually allocated right after the structure */
58} AnimCurRec, *AnimCurPtr;
59
60typedef struct _AnimScrPriv {
61    CloseScreenProcPtr		CloseScreen;
62
63    ScreenBlockHandlerProcPtr	BlockHandler;
64
65    CursorLimitsProcPtr		CursorLimits;
66    DisplayCursorProcPtr	DisplayCursor;
67    SetCursorPositionProcPtr	SetCursorPosition;
68    RealizeCursorProcPtr	RealizeCursor;
69    UnrealizeCursorProcPtr	UnrealizeCursor;
70    RecolorCursorProcPtr	RecolorCursor;
71} AnimCurScreenRec, *AnimCurScreenPtr;
72
73static unsigned char empty[4];
74
75static CursorBits   animCursorBits = {
76    empty, empty, 2, 1, 1, 0, 0, 1
77};
78
79static DevPrivateKeyRec AnimCurScreenPrivateKeyRec;
80#define AnimCurScreenPrivateKey (&AnimCurScreenPrivateKeyRec)
81
82#define IsAnimCur(c)	    ((c) && ((c)->bits == &animCursorBits))
83#define GetAnimCur(c)	    ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE))))
84#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey))
85#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p)
86
87#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
88#define Unwrap(as,s,elt)    ((s)->elt = (as)->elt)
89
90
91static Bool
92AnimCurCloseScreen (int index, ScreenPtr pScreen)
93{
94    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
95    Bool                ret;
96
97    Unwrap(as, pScreen, CloseScreen);
98
99    Unwrap(as, pScreen, CursorLimits);
100    Unwrap(as, pScreen, DisplayCursor);
101    Unwrap(as, pScreen, SetCursorPosition);
102    Unwrap(as, pScreen, RealizeCursor);
103    Unwrap(as, pScreen, UnrealizeCursor);
104    Unwrap(as, pScreen, RecolorCursor);
105    SetAnimCurScreen(pScreen,0);
106    ret = (*pScreen->CloseScreen) (index, pScreen);
107    free(as);
108    return ret;
109}
110
111static void
112AnimCurCursorLimits (DeviceIntPtr pDev,
113                     ScreenPtr pScreen,
114		     CursorPtr pCursor,
115		     BoxPtr pHotBox,
116		     BoxPtr pTopLeftBox)
117{
118    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
119
120    Unwrap (as, pScreen, CursorLimits);
121    if (IsAnimCur(pCursor))
122    {
123	AnimCurPtr	ac = GetAnimCur(pCursor);
124
125        (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor,
126                                  pHotBox, pTopLeftBox);
127    }
128    else
129    {
130        (*pScreen->CursorLimits) (pDev, pScreen, pCursor,
131                                  pHotBox, pTopLeftBox);
132    }
133    Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits);
134}
135
136/*
137 * This has to be a screen block handler instead of a generic
138 * block handler so that it is well ordered with respect to the DRI
139 * block handler responsible for releasing the hardware to DRI clients
140 */
141
142static void
143AnimCurScreenBlockHandler (int screenNum,
144			   pointer blockData,
145			   pointer pTimeout,
146			   pointer pReadmask)
147{
148    ScreenPtr		pScreen = screenInfo.screens[screenNum];
149    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
150    DeviceIntPtr        dev;
151    Bool                activeDevice = FALSE;
152    CARD32              now = 0,
153                        soonest = ~0; /* earliest time to wakeup again */
154
155    for (dev = inputInfo.devices; dev; dev = dev->next)
156    {
157	if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen)
158	{
159	    if (!activeDevice) {
160                now = GetTimeInMillis ();
161                activeDevice = TRUE;
162            }
163
164	    if ((INT32) (now - dev->spriteInfo->anim.time) >= 0)
165	    {
166		AnimCurPtr ac  = GetAnimCur(dev->spriteInfo->anim.pCursor);
167		int        elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt;
168		DisplayCursorProcPtr DisplayCursor;
169
170		/*
171		 * Not a simple Unwrap/Wrap as this
172		 * isn't called along the DisplayCursor
173		 * wrapper chain.
174		 */
175		DisplayCursor = pScreen->DisplayCursor;
176		pScreen->DisplayCursor = as->DisplayCursor;
177		(void) (*pScreen->DisplayCursor) (dev,
178						  pScreen,
179						  ac->elts[elt].pCursor);
180		as->DisplayCursor = pScreen->DisplayCursor;
181		pScreen->DisplayCursor = DisplayCursor;
182
183		dev->spriteInfo->anim.elt = elt;
184		dev->spriteInfo->anim.time = now + ac->elts[elt].delay;
185	    }
186
187	    if (soonest > dev->spriteInfo->anim.time)
188		soonest = dev->spriteInfo->anim.time;
189	}
190    }
191
192    if (activeDevice)
193        AdjustWaitForDelay (pTimeout, soonest - now);
194
195    Unwrap (as, pScreen, BlockHandler);
196    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
197    if (activeDevice)
198        Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
199    else
200        as->BlockHandler = NULL;
201}
202
203static Bool
204AnimCurDisplayCursor (DeviceIntPtr pDev,
205                      ScreenPtr pScreen,
206		      CursorPtr pCursor)
207{
208    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
209    Bool		ret;
210
211    Unwrap (as, pScreen, DisplayCursor);
212    if (IsAnimCur(pCursor))
213    {
214	if (pCursor != pDev->spriteInfo->anim.pCursor)
215	{
216	    AnimCurPtr		ac = GetAnimCur(pCursor);
217
218	    ret = (*pScreen->DisplayCursor)
219                (pDev, pScreen, ac->elts[0].pCursor);
220	    if (ret)
221	    {
222		pDev->spriteInfo->anim.elt = 0;
223		pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay;
224		pDev->spriteInfo->anim.pCursor = pCursor;
225		pDev->spriteInfo->anim.pScreen = pScreen;
226
227		if (!as->BlockHandler)
228		    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
229	    }
230	}
231	else
232	    ret = TRUE;
233    }
234    else
235    {
236	pDev->spriteInfo->anim.pCursor = 0;
237	pDev->spriteInfo->anim.pScreen = 0;
238	ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
239    }
240    Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor);
241    return ret;
242}
243
244static Bool
245AnimCurSetCursorPosition (DeviceIntPtr pDev,
246                          ScreenPtr pScreen,
247			  int x,
248			  int y,
249			  Bool generateEvent)
250{
251    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
252    Bool		ret;
253
254    Unwrap (as, pScreen, SetCursorPosition);
255    if (pDev->spriteInfo->anim.pCursor) {
256	pDev->spriteInfo->anim.pScreen = pScreen;
257
258	if (!as->BlockHandler)
259	    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
260    }
261    ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
262    Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
263    return ret;
264}
265
266static Bool
267AnimCurRealizeCursor (DeviceIntPtr pDev,
268                      ScreenPtr pScreen,
269		      CursorPtr pCursor)
270{
271    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
272    Bool		ret;
273
274    Unwrap (as, pScreen, RealizeCursor);
275    if (IsAnimCur(pCursor))
276	ret = TRUE;
277    else
278	ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor);
279    Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor);
280    return ret;
281}
282
283static Bool
284AnimCurUnrealizeCursor (DeviceIntPtr pDev,
285                        ScreenPtr pScreen,
286			CursorPtr pCursor)
287{
288    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
289    Bool		ret;
290
291    Unwrap (as, pScreen, UnrealizeCursor);
292    if (IsAnimCur(pCursor))
293    {
294        AnimCurPtr  ac = GetAnimCur(pCursor);
295	int	    i;
296
297	if (pScreen->myNum == 0)
298	    for (i = 0; i < ac->nelt; i++)
299		FreeCursor (ac->elts[i].pCursor, 0);
300	ret = TRUE;
301    }
302    else
303	ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor);
304    Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
305    return ret;
306}
307
308static void
309AnimCurRecolorCursor (DeviceIntPtr pDev,
310                      ScreenPtr pScreen,
311		      CursorPtr pCursor,
312		      Bool displayed)
313{
314    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
315
316    Unwrap (as, pScreen, RecolorCursor);
317    if (IsAnimCur(pCursor))
318    {
319        AnimCurPtr  ac = GetAnimCur(pCursor);
320	int	    i;
321
322        for (i = 0; i < ac->nelt; i++)
323	    (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor,
324				       displayed &&
325				       pDev->spriteInfo->anim.elt == i);
326    }
327    else
328	(*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed);
329    Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor);
330}
331
332Bool
333AnimCurInit (ScreenPtr pScreen)
334{
335    AnimCurScreenPtr    as;
336
337    if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
338	return FALSE;
339
340    as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec));
341    if (!as)
342	return FALSE;
343    Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
344
345    as->BlockHandler = NULL;
346
347    Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
348    Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
349    Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
350    Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
351    Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
352    Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
353    SetAnimCurScreen(pScreen,as);
354    return TRUE;
355}
356
357int
358AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid)
359{
360    CursorPtr	pCursor;
361    int		rc, i;
362    AnimCurPtr	ac;
363
364    for (i = 0; i < screenInfo.numScreens; i++)
365	if (!GetAnimCurScreen (screenInfo.screens[i]))
366	    return BadImplementation;
367
368    for (i = 0; i < ncursor; i++)
369	if (IsAnimCur (cursors[i]))
370	    return BadMatch;
371
372    pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE +
373				 sizeof (AnimCurRec) +
374				 ncursor * sizeof (AnimCurElt), 1);
375    if (!pCursor)
376	return BadAlloc;
377    dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR);
378    pCursor->bits = &animCursorBits;
379    pCursor->refcnt = 1;
380
381    pCursor->foreRed = cursors[0]->foreRed;
382    pCursor->foreGreen = cursors[0]->foreGreen;
383    pCursor->foreBlue = cursors[0]->foreBlue;
384
385    pCursor->backRed = cursors[0]->backRed;
386    pCursor->backGreen = cursors[0]->backGreen;
387    pCursor->backBlue = cursors[0]->backBlue;
388
389    pCursor->id = cid;
390
391    /* security creation/labeling check */
392    rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor,
393		  RT_NONE, NULL, DixCreateAccess);
394    if (rc != Success) {
395	dixFiniPrivates(pCursor, PRIVATE_CURSOR);
396	free(pCursor);
397	return rc;
398    }
399
400    /*
401     * Fill in the AnimCurRec
402     */
403    animCursorBits.refcnt++;
404    ac = GetAnimCur (pCursor);
405    ac->nelt = ncursor;
406    ac->elts = (AnimCurElt *) (ac + 1);
407
408    for (i = 0; i < ncursor; i++)
409    {
410	cursors[i]->refcnt++;
411	ac->elts[i].pCursor = cursors[i];
412	ac->elts[i].delay = deltas[i];
413    }
414
415    *ppCursor = pCursor;
416    return Success;
417}
418