animcur.c revision 6747b715
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, BlockHandler);
100
101    Unwrap(as, pScreen, CursorLimits);
102    Unwrap(as, pScreen, DisplayCursor);
103    Unwrap(as, pScreen, SetCursorPosition);
104    Unwrap(as, pScreen, RealizeCursor);
105    Unwrap(as, pScreen, UnrealizeCursor);
106    Unwrap(as, pScreen, RecolorCursor);
107    SetAnimCurScreen(pScreen,0);
108    ret = (*pScreen->CloseScreen) (index, pScreen);
109    free(as);
110    return ret;
111}
112
113static void
114AnimCurCursorLimits (DeviceIntPtr pDev,
115                     ScreenPtr pScreen,
116		     CursorPtr pCursor,
117		     BoxPtr pHotBox,
118		     BoxPtr pTopLeftBox)
119{
120    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
121
122    Unwrap (as, pScreen, CursorLimits);
123    if (IsAnimCur(pCursor))
124    {
125	AnimCurPtr	ac = GetAnimCur(pCursor);
126
127        (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor,
128                                  pHotBox, pTopLeftBox);
129    }
130    else
131    {
132        (*pScreen->CursorLimits) (pDev, pScreen, pCursor,
133                                  pHotBox, pTopLeftBox);
134    }
135    Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits);
136}
137
138/*
139 * This has to be a screen block handler instead of a generic
140 * block handler so that it is well ordered with respect to the DRI
141 * block handler responsible for releasing the hardware to DRI clients
142 */
143
144static void
145AnimCurScreenBlockHandler (int screenNum,
146			   pointer blockData,
147			   pointer pTimeout,
148			   pointer pReadmask)
149{
150    ScreenPtr		pScreen = screenInfo.screens[screenNum];
151    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
152    DeviceIntPtr        dev;
153    CARD32              now = 0,
154                        soonest = ~0; /* earliest time to wakeup again */
155
156    for (dev = inputInfo.devices; dev; dev = dev->next)
157    {
158	if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen)
159	{
160	    if (!now) now = GetTimeInMillis ();
161
162	    if ((INT32) (now - dev->spriteInfo->anim.time) >= 0)
163	    {
164		AnimCurPtr ac  = GetAnimCur(dev->spriteInfo->anim.pCursor);
165		int        elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt;
166		DisplayCursorProcPtr DisplayCursor;
167
168		/*
169		 * Not a simple Unwrap/Wrap as this
170		 * isn't called along the DisplayCursor
171		 * wrapper chain.
172		 */
173		DisplayCursor = pScreen->DisplayCursor;
174		pScreen->DisplayCursor = as->DisplayCursor;
175		(void) (*pScreen->DisplayCursor) (dev,
176						  pScreen,
177						  ac->elts[elt].pCursor);
178		as->DisplayCursor = pScreen->DisplayCursor;
179		pScreen->DisplayCursor = DisplayCursor;
180
181		dev->spriteInfo->anim.elt = elt;
182		dev->spriteInfo->anim.time = now + ac->elts[elt].delay;
183	    }
184
185	    if (soonest > dev->spriteInfo->anim.time)
186		soonest = dev->spriteInfo->anim.time;
187	}
188    }
189
190    if (now)
191        AdjustWaitForDelay (pTimeout, soonest - now);
192
193    Unwrap (as, pScreen, BlockHandler);
194    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
195    Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
196}
197
198static Bool
199AnimCurDisplayCursor (DeviceIntPtr pDev,
200                      ScreenPtr pScreen,
201		      CursorPtr pCursor)
202{
203    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
204    Bool		ret;
205
206    Unwrap (as, pScreen, DisplayCursor);
207    if (IsAnimCur(pCursor))
208    {
209	if (pCursor != pDev->spriteInfo->anim.pCursor)
210	{
211	    AnimCurPtr		ac = GetAnimCur(pCursor);
212
213	    ret = (*pScreen->DisplayCursor)
214                (pDev, pScreen, ac->elts[0].pCursor);
215	    if (ret)
216	    {
217		pDev->spriteInfo->anim.elt = 0;
218		pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay;
219		pDev->spriteInfo->anim.pCursor = pCursor;
220		pDev->spriteInfo->anim.pScreen = pScreen;
221	    }
222	}
223	else
224	    ret = TRUE;
225    }
226    else
227    {
228	pDev->spriteInfo->anim.pCursor = 0;
229	pDev->spriteInfo->anim.pScreen = 0;
230	ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
231    }
232    Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor);
233    return ret;
234}
235
236static Bool
237AnimCurSetCursorPosition (DeviceIntPtr pDev,
238                          ScreenPtr pScreen,
239			  int x,
240			  int y,
241			  Bool generateEvent)
242{
243    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
244    Bool		ret;
245
246    Unwrap (as, pScreen, SetCursorPosition);
247    if (pDev->spriteInfo->anim.pCursor)
248	pDev->spriteInfo->anim.pScreen = pScreen;
249    ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
250    Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
251    return ret;
252}
253
254static Bool
255AnimCurRealizeCursor (DeviceIntPtr pDev,
256                      ScreenPtr pScreen,
257		      CursorPtr pCursor)
258{
259    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
260    Bool		ret;
261
262    Unwrap (as, pScreen, RealizeCursor);
263    if (IsAnimCur(pCursor))
264	ret = TRUE;
265    else
266	ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor);
267    Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor);
268    return ret;
269}
270
271static Bool
272AnimCurUnrealizeCursor (DeviceIntPtr pDev,
273                        ScreenPtr pScreen,
274			CursorPtr pCursor)
275{
276    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
277    Bool		ret;
278
279    Unwrap (as, pScreen, UnrealizeCursor);
280    if (IsAnimCur(pCursor))
281    {
282        AnimCurPtr  ac = GetAnimCur(pCursor);
283	int	    i;
284
285	if (pScreen->myNum == 0)
286	    for (i = 0; i < ac->nelt; i++)
287		FreeCursor (ac->elts[i].pCursor, 0);
288	ret = TRUE;
289    }
290    else
291	ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor);
292    Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
293    return ret;
294}
295
296static void
297AnimCurRecolorCursor (DeviceIntPtr pDev,
298                      ScreenPtr pScreen,
299		      CursorPtr pCursor,
300		      Bool displayed)
301{
302    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
303
304    Unwrap (as, pScreen, RecolorCursor);
305    if (IsAnimCur(pCursor))
306    {
307        AnimCurPtr  ac = GetAnimCur(pCursor);
308	int	    i;
309
310        for (i = 0; i < ac->nelt; i++)
311	    (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor,
312				       displayed &&
313				       pDev->spriteInfo->anim.elt == i);
314    }
315    else
316	(*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed);
317    Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor);
318}
319
320Bool
321AnimCurInit (ScreenPtr pScreen)
322{
323    AnimCurScreenPtr    as;
324
325    if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
326	return FALSE;
327
328    as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec));
329    if (!as)
330	return FALSE;
331    Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
332
333    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
334
335    Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
336    Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
337    Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
338    Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
339    Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
340    Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
341    SetAnimCurScreen(pScreen,as);
342    return TRUE;
343}
344
345int
346AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid)
347{
348    CursorPtr	pCursor;
349    int		rc, i;
350    AnimCurPtr	ac;
351
352    for (i = 0; i < screenInfo.numScreens; i++)
353	if (!GetAnimCurScreen (screenInfo.screens[i]))
354	    return BadImplementation;
355
356    for (i = 0; i < ncursor; i++)
357	if (IsAnimCur (cursors[i]))
358	    return BadMatch;
359
360    pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE +
361				 sizeof (AnimCurRec) +
362				 ncursor * sizeof (AnimCurElt), 1);
363    if (!pCursor)
364	return BadAlloc;
365    dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR);
366    pCursor->bits = &animCursorBits;
367    pCursor->refcnt = 1;
368
369    pCursor->foreRed = cursors[0]->foreRed;
370    pCursor->foreGreen = cursors[0]->foreGreen;
371    pCursor->foreBlue = cursors[0]->foreBlue;
372
373    pCursor->backRed = cursors[0]->backRed;
374    pCursor->backGreen = cursors[0]->backGreen;
375    pCursor->backBlue = cursors[0]->backBlue;
376
377    pCursor->id = cid;
378
379    /* security creation/labeling check */
380    rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor,
381		  RT_NONE, NULL, DixCreateAccess);
382    if (rc != Success) {
383	dixFiniPrivates(pCursor, PRIVATE_CURSOR);
384	free(pCursor);
385	return rc;
386    }
387
388    /*
389     * Fill in the AnimCurRec
390     */
391    animCursorBits.refcnt++;
392    ac = GetAnimCur (pCursor);
393    ac->nelt = ncursor;
394    ac->elts = (AnimCurElt *) (ac + 1);
395
396    for (i = 0; i < ncursor; i++)
397    {
398	cursors[i]->refcnt++;
399	ac->elts[i].pCursor = cursors[i];
400	ac->elts[i].delay = deltas[i];
401    }
402
403    *ppCursor = pCursor;
404    return Success;
405}
406