animcur.c revision 05b261ec
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
48typedef struct _AnimCurElt {
49    CursorPtr	pCursor;    /* cursor to show */
50    CARD32	delay;	    /* in ms */
51} AnimCurElt;
52
53typedef struct _AnimCur {
54    int		nelt;	    /* number of elements in the elts array */
55    AnimCurElt	*elts;	    /* actually allocated right after the structure */
56} AnimCurRec, *AnimCurPtr;
57
58typedef struct _AnimScrPriv {
59    CursorPtr			pCursor;
60    int				elt;
61    CARD32			time;
62
63    CloseScreenProcPtr		CloseScreen;
64
65    ScreenBlockHandlerProcPtr	BlockHandler;
66
67    CursorLimitsProcPtr		CursorLimits;
68    DisplayCursorProcPtr	DisplayCursor;
69    SetCursorPositionProcPtr	SetCursorPosition;
70    RealizeCursorProcPtr	RealizeCursor;
71    UnrealizeCursorProcPtr	UnrealizeCursor;
72    RecolorCursorProcPtr	RecolorCursor;
73} AnimCurScreenRec, *AnimCurScreenPtr;
74
75typedef struct _AnimCurState {
76    CursorPtr			pCursor;
77    ScreenPtr			pScreen;
78    int				elt;
79    CARD32			time;
80} AnimCurStateRec, *AnimCurStatePtr;
81
82static AnimCurStateRec  animCurState;
83
84static unsigned char empty[4];
85
86static CursorBits   animCursorBits = {
87    empty, empty, 2, 1, 1, 0, 0, 1
88};
89
90static int AnimCurScreenPrivateIndex = -1;
91static int AnimCurGeneration;
92
93#define IsAnimCur(c)	    ((c)->bits == &animCursorBits)
94#define GetAnimCur(c)	    ((AnimCurPtr) ((c) + 1))
95#define GetAnimCurScreen(s) ((AnimCurScreenPtr) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr))
96#define GetAnimCurScreenIfSet(s) ((AnimCurScreenPrivateIndex != -1) ? GetAnimCurScreen(s) : NULL)
97#define SetAnimCurScreen(s,p) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr = (pointer) (p))
98
99#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
100#define Unwrap(as,s,elt)    ((s)->elt = (as)->elt)
101
102static Bool
103AnimCurDisplayCursor (ScreenPtr pScreen,
104		      CursorPtr pCursor);
105
106static Bool
107AnimCurSetCursorPosition (ScreenPtr pScreen,
108			  int x,
109			  int y,
110			  Bool generateEvent);
111
112static Bool
113AnimCurCloseScreen (int index, ScreenPtr pScreen)
114{
115    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
116    Bool                ret;
117
118    Unwrap(as, pScreen, CloseScreen);
119
120    Unwrap(as, pScreen, BlockHandler);
121
122    Unwrap(as, pScreen, CursorLimits);
123    Unwrap(as, pScreen, DisplayCursor);
124    Unwrap(as, pScreen, SetCursorPosition);
125    Unwrap(as, pScreen, RealizeCursor);
126    Unwrap(as, pScreen, UnrealizeCursor);
127    Unwrap(as, pScreen, RecolorCursor);
128    SetAnimCurScreen(pScreen,0);
129    ret = (*pScreen->CloseScreen) (index, pScreen);
130    xfree (as);
131    if (index == 0)
132	AnimCurScreenPrivateIndex = -1;
133    return ret;
134}
135
136static void
137AnimCurCursorLimits (ScreenPtr pScreen,
138		     CursorPtr pCursor,
139		     BoxPtr pHotBox,
140		     BoxPtr pTopLeftBox)
141{
142    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
143
144    Unwrap (as, pScreen, CursorLimits);
145    if (IsAnimCur(pCursor))
146    {
147	AnimCurPtr	ac = GetAnimCur(pCursor);
148
149	(*pScreen->CursorLimits) (pScreen, ac->elts[0].pCursor, pHotBox, pTopLeftBox);
150    }
151    else
152    {
153	(*pScreen->CursorLimits) (pScreen, pCursor, pHotBox, pTopLeftBox);
154    }
155    Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits);
156}
157
158/*
159 * This has to be a screen block handler instead of a generic
160 * block handler so that it is well ordered with respect to the DRI
161 * block handler responsible for releasing the hardware to DRI clients
162 */
163
164static void
165AnimCurScreenBlockHandler (int screenNum,
166			   pointer blockData,
167			   pointer pTimeout,
168			   pointer pReadmask)
169{
170    ScreenPtr		pScreen = screenInfo.screens[screenNum];
171    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
172
173    if (pScreen == animCurState.pScreen)
174    {
175	CARD32		now = GetTimeInMillis ();
176
177	if ((INT32) (now - animCurState.time) >= 0)
178	{
179	    AnimCurPtr		    ac = GetAnimCur(animCurState.pCursor);
180	    int			    elt = (animCurState.elt + 1) % ac->nelt;
181	    DisplayCursorProcPtr    DisplayCursor;
182
183	    /*
184	     * Not a simple Unwrap/Wrap as this
185	     * isn't called along the DisplayCursor
186	     * wrapper chain.
187	     */
188	    DisplayCursor = pScreen->DisplayCursor;
189	    pScreen->DisplayCursor = as->DisplayCursor;
190	    (void) (*pScreen->DisplayCursor) (pScreen, ac->elts[elt].pCursor);
191	    as->DisplayCursor = pScreen->DisplayCursor;
192	    pScreen->DisplayCursor = DisplayCursor;
193
194	    animCurState.elt = elt;
195	    animCurState.time = now + ac->elts[elt].delay;
196	}
197	AdjustWaitForDelay (pTimeout, animCurState.time - now);
198    }
199    Unwrap (as, pScreen, BlockHandler);
200    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
201    Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
202}
203
204static Bool
205AnimCurDisplayCursor (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 != animCurState.pCursor)
215	{
216	    AnimCurPtr		ac = GetAnimCur(pCursor);
217
218	    ret = (*pScreen->DisplayCursor) (pScreen, ac->elts[0].pCursor);
219	    if (ret)
220	    {
221		animCurState.elt = 0;
222		animCurState.time = GetTimeInMillis () + ac->elts[0].delay;
223		animCurState.pCursor = pCursor;
224		animCurState.pScreen = pScreen;
225	    }
226	}
227	else
228	    ret = TRUE;
229    }
230    else
231    {
232        animCurState.pCursor = 0;
233	animCurState.pScreen = 0;
234	ret = (*pScreen->DisplayCursor) (pScreen, pCursor);
235    }
236    Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor);
237    return ret;
238}
239
240static Bool
241AnimCurSetCursorPosition (ScreenPtr pScreen,
242			  int x,
243			  int y,
244			  Bool generateEvent)
245{
246    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
247    Bool		ret;
248
249    Unwrap (as, pScreen, SetCursorPosition);
250    if (animCurState.pCursor)
251	animCurState.pScreen = pScreen;
252    ret = (*pScreen->SetCursorPosition) (pScreen, x, y, generateEvent);
253    Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
254    return ret;
255}
256
257static Bool
258AnimCurRealizeCursor (ScreenPtr pScreen,
259		      CursorPtr pCursor)
260{
261    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
262    Bool		ret;
263
264    Unwrap (as, pScreen, RealizeCursor);
265    if (IsAnimCur(pCursor))
266	ret = TRUE;
267    else
268	ret = (*pScreen->RealizeCursor) (pScreen, pCursor);
269    Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor);
270    return ret;
271}
272
273static Bool
274AnimCurUnrealizeCursor (ScreenPtr pScreen,
275			CursorPtr pCursor)
276{
277    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
278    Bool		ret;
279
280    Unwrap (as, pScreen, UnrealizeCursor);
281    if (IsAnimCur(pCursor))
282    {
283        AnimCurPtr  ac = GetAnimCur(pCursor);
284	int	    i;
285
286	if (pScreen->myNum == 0)
287	    for (i = 0; i < ac->nelt; i++)
288		FreeCursor (ac->elts[i].pCursor, 0);
289	ret = TRUE;
290    }
291    else
292	ret = (*pScreen->UnrealizeCursor) (pScreen, pCursor);
293    Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
294    return ret;
295}
296
297static void
298AnimCurRecolorCursor (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) (pScreen, ac->elts[i].pCursor,
312				       displayed &&
313				       animCurState.elt == i);
314    }
315    else
316	(*pScreen->RecolorCursor) (pScreen, pCursor, displayed);
317    Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor);
318}
319
320Bool
321AnimCurInit (ScreenPtr pScreen)
322{
323    AnimCurScreenPtr    as;
324
325    if (AnimCurGeneration != serverGeneration)
326    {
327	AnimCurScreenPrivateIndex = AllocateScreenPrivateIndex ();
328	if (AnimCurScreenPrivateIndex < 0)
329	    return FALSE;
330	AnimCurGeneration = serverGeneration;
331	animCurState.pCursor = 0;
332	animCurState.pScreen = 0;
333	animCurState.elt = 0;
334	animCurState.time = 0;
335    }
336    as = (AnimCurScreenPtr) xalloc (sizeof (AnimCurScreenRec));
337    if (!as)
338	return FALSE;
339    Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
340
341    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
342
343    Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
344    Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
345    Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
346    Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
347    Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
348    Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
349    SetAnimCurScreen(pScreen,as);
350    return TRUE;
351}
352
353int
354AnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor)
355{
356    CursorPtr	pCursor;
357    int		i;
358    AnimCurPtr	ac;
359
360    for (i = 0; i < screenInfo.numScreens; i++)
361	if (!GetAnimCurScreenIfSet (screenInfo.screens[i]))
362	    return BadImplementation;
363
364    for (i = 0; i < ncursor; i++)
365	if (IsAnimCur (cursors[i]))
366	    return BadMatch;
367
368    pCursor = (CursorPtr) xalloc (sizeof (CursorRec) +
369				  sizeof (AnimCurRec) +
370				  ncursor * sizeof (AnimCurElt));
371    if (!pCursor)
372	return BadAlloc;
373    pCursor->bits = &animCursorBits;
374    animCursorBits.refcnt++;
375    pCursor->refcnt = 1;
376
377    pCursor->foreRed = cursors[0]->foreRed;
378    pCursor->foreGreen = cursors[0]->foreGreen;
379    pCursor->foreBlue = cursors[0]->foreBlue;
380
381    pCursor->backRed = cursors[0]->backRed;
382    pCursor->backGreen = cursors[0]->backGreen;
383    pCursor->backBlue = cursors[0]->backBlue;
384
385    /*
386     * Fill in the AnimCurRec
387     */
388    ac = GetAnimCur (pCursor);
389    ac->nelt = ncursor;
390    ac->elts = (AnimCurElt *) (ac + 1);
391
392    for (i = 0; i < ncursor; i++)
393    {
394	cursors[i]->refcnt++;
395	ac->elts[i].pCursor = cursors[i];
396	ac->elts[i].delay = deltas[i];
397    }
398
399    *ppCursor = pCursor;
400    return Success;
401}
402