animcur.c revision 05b261ec
105b261ecSmrg/*
205b261ecSmrg *
305b261ecSmrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
405b261ecSmrg *
505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
705b261ecSmrg * the above copyright notice appear in all copies and that both that
805b261ecSmrg * copyright notice and this permission notice appear in supporting
905b261ecSmrg * documentation, and that the name of Keith Packard not be used in
1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1105b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1205b261ecSmrg * representations about the suitability of this software for any purpose.  It
1305b261ecSmrg * is provided "as is" without express or implied warranty.
1405b261ecSmrg *
1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2205b261ecSmrg */
2305b261ecSmrg
2405b261ecSmrg/*
2505b261ecSmrg * Animated cursors for X.  Not specific to Render in any way, but
2605b261ecSmrg * stuck there because Render has the other cool cursor extension.
2705b261ecSmrg * Besides, everyone has Render.
2805b261ecSmrg *
2905b261ecSmrg * Implemented as a simple layer over the core cursor code; it
3005b261ecSmrg * creates composite cursors out of a set of static cursors and
3105b261ecSmrg * delta times between each image.
3205b261ecSmrg */
3305b261ecSmrg
3405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3505b261ecSmrg#include <dix-config.h>
3605b261ecSmrg#endif
3705b261ecSmrg
3805b261ecSmrg#include <X11/X.h>
3905b261ecSmrg#include <X11/Xmd.h>
4005b261ecSmrg#include "servermd.h"
4105b261ecSmrg#include "scrnintstr.h"
4205b261ecSmrg#include "dixstruct.h"
4305b261ecSmrg#include "cursorstr.h"
4405b261ecSmrg#include "dixfontstr.h"
4505b261ecSmrg#include "opaque.h"
4605b261ecSmrg#include "picturestr.h"
4705b261ecSmrg
4805b261ecSmrgtypedef struct _AnimCurElt {
4905b261ecSmrg    CursorPtr	pCursor;    /* cursor to show */
5005b261ecSmrg    CARD32	delay;	    /* in ms */
5105b261ecSmrg} AnimCurElt;
5205b261ecSmrg
5305b261ecSmrgtypedef struct _AnimCur {
5405b261ecSmrg    int		nelt;	    /* number of elements in the elts array */
5505b261ecSmrg    AnimCurElt	*elts;	    /* actually allocated right after the structure */
5605b261ecSmrg} AnimCurRec, *AnimCurPtr;
5705b261ecSmrg
5805b261ecSmrgtypedef struct _AnimScrPriv {
5905b261ecSmrg    CursorPtr			pCursor;
6005b261ecSmrg    int				elt;
6105b261ecSmrg    CARD32			time;
6205b261ecSmrg
6305b261ecSmrg    CloseScreenProcPtr		CloseScreen;
6405b261ecSmrg
6505b261ecSmrg    ScreenBlockHandlerProcPtr	BlockHandler;
6605b261ecSmrg
6705b261ecSmrg    CursorLimitsProcPtr		CursorLimits;
6805b261ecSmrg    DisplayCursorProcPtr	DisplayCursor;
6905b261ecSmrg    SetCursorPositionProcPtr	SetCursorPosition;
7005b261ecSmrg    RealizeCursorProcPtr	RealizeCursor;
7105b261ecSmrg    UnrealizeCursorProcPtr	UnrealizeCursor;
7205b261ecSmrg    RecolorCursorProcPtr	RecolorCursor;
7305b261ecSmrg} AnimCurScreenRec, *AnimCurScreenPtr;
7405b261ecSmrg
7505b261ecSmrgtypedef struct _AnimCurState {
7605b261ecSmrg    CursorPtr			pCursor;
7705b261ecSmrg    ScreenPtr			pScreen;
7805b261ecSmrg    int				elt;
7905b261ecSmrg    CARD32			time;
8005b261ecSmrg} AnimCurStateRec, *AnimCurStatePtr;
8105b261ecSmrg
8205b261ecSmrgstatic AnimCurStateRec  animCurState;
8305b261ecSmrg
8405b261ecSmrgstatic unsigned char empty[4];
8505b261ecSmrg
8605b261ecSmrgstatic CursorBits   animCursorBits = {
8705b261ecSmrg    empty, empty, 2, 1, 1, 0, 0, 1
8805b261ecSmrg};
8905b261ecSmrg
9005b261ecSmrgstatic int AnimCurScreenPrivateIndex = -1;
9105b261ecSmrgstatic int AnimCurGeneration;
9205b261ecSmrg
9305b261ecSmrg#define IsAnimCur(c)	    ((c)->bits == &animCursorBits)
9405b261ecSmrg#define GetAnimCur(c)	    ((AnimCurPtr) ((c) + 1))
9505b261ecSmrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr))
9605b261ecSmrg#define GetAnimCurScreenIfSet(s) ((AnimCurScreenPrivateIndex != -1) ? GetAnimCurScreen(s) : NULL)
9705b261ecSmrg#define SetAnimCurScreen(s,p) ((s)->devPrivates[AnimCurScreenPrivateIndex].ptr = (pointer) (p))
9805b261ecSmrg
9905b261ecSmrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
10005b261ecSmrg#define Unwrap(as,s,elt)    ((s)->elt = (as)->elt)
10105b261ecSmrg
10205b261ecSmrgstatic Bool
10305b261ecSmrgAnimCurDisplayCursor (ScreenPtr pScreen,
10405b261ecSmrg		      CursorPtr pCursor);
10505b261ecSmrg
10605b261ecSmrgstatic Bool
10705b261ecSmrgAnimCurSetCursorPosition (ScreenPtr pScreen,
10805b261ecSmrg			  int x,
10905b261ecSmrg			  int y,
11005b261ecSmrg			  Bool generateEvent);
11105b261ecSmrg
11205b261ecSmrgstatic Bool
11305b261ecSmrgAnimCurCloseScreen (int index, ScreenPtr pScreen)
11405b261ecSmrg{
11505b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
11605b261ecSmrg    Bool                ret;
11705b261ecSmrg
11805b261ecSmrg    Unwrap(as, pScreen, CloseScreen);
11905b261ecSmrg
12005b261ecSmrg    Unwrap(as, pScreen, BlockHandler);
12105b261ecSmrg
12205b261ecSmrg    Unwrap(as, pScreen, CursorLimits);
12305b261ecSmrg    Unwrap(as, pScreen, DisplayCursor);
12405b261ecSmrg    Unwrap(as, pScreen, SetCursorPosition);
12505b261ecSmrg    Unwrap(as, pScreen, RealizeCursor);
12605b261ecSmrg    Unwrap(as, pScreen, UnrealizeCursor);
12705b261ecSmrg    Unwrap(as, pScreen, RecolorCursor);
12805b261ecSmrg    SetAnimCurScreen(pScreen,0);
12905b261ecSmrg    ret = (*pScreen->CloseScreen) (index, pScreen);
13005b261ecSmrg    xfree (as);
13105b261ecSmrg    if (index == 0)
13205b261ecSmrg	AnimCurScreenPrivateIndex = -1;
13305b261ecSmrg    return ret;
13405b261ecSmrg}
13505b261ecSmrg
13605b261ecSmrgstatic void
13705b261ecSmrgAnimCurCursorLimits (ScreenPtr pScreen,
13805b261ecSmrg		     CursorPtr pCursor,
13905b261ecSmrg		     BoxPtr pHotBox,
14005b261ecSmrg		     BoxPtr pTopLeftBox)
14105b261ecSmrg{
14205b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
14305b261ecSmrg
14405b261ecSmrg    Unwrap (as, pScreen, CursorLimits);
14505b261ecSmrg    if (IsAnimCur(pCursor))
14605b261ecSmrg    {
14705b261ecSmrg	AnimCurPtr	ac = GetAnimCur(pCursor);
14805b261ecSmrg
14905b261ecSmrg	(*pScreen->CursorLimits) (pScreen, ac->elts[0].pCursor, pHotBox, pTopLeftBox);
15005b261ecSmrg    }
15105b261ecSmrg    else
15205b261ecSmrg    {
15305b261ecSmrg	(*pScreen->CursorLimits) (pScreen, pCursor, pHotBox, pTopLeftBox);
15405b261ecSmrg    }
15505b261ecSmrg    Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits);
15605b261ecSmrg}
15705b261ecSmrg
15805b261ecSmrg/*
15905b261ecSmrg * This has to be a screen block handler instead of a generic
16005b261ecSmrg * block handler so that it is well ordered with respect to the DRI
16105b261ecSmrg * block handler responsible for releasing the hardware to DRI clients
16205b261ecSmrg */
16305b261ecSmrg
16405b261ecSmrgstatic void
16505b261ecSmrgAnimCurScreenBlockHandler (int screenNum,
16605b261ecSmrg			   pointer blockData,
16705b261ecSmrg			   pointer pTimeout,
16805b261ecSmrg			   pointer pReadmask)
16905b261ecSmrg{
17005b261ecSmrg    ScreenPtr		pScreen = screenInfo.screens[screenNum];
17105b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
17205b261ecSmrg
17305b261ecSmrg    if (pScreen == animCurState.pScreen)
17405b261ecSmrg    {
17505b261ecSmrg	CARD32		now = GetTimeInMillis ();
17605b261ecSmrg
17705b261ecSmrg	if ((INT32) (now - animCurState.time) >= 0)
17805b261ecSmrg	{
17905b261ecSmrg	    AnimCurPtr		    ac = GetAnimCur(animCurState.pCursor);
18005b261ecSmrg	    int			    elt = (animCurState.elt + 1) % ac->nelt;
18105b261ecSmrg	    DisplayCursorProcPtr    DisplayCursor;
18205b261ecSmrg
18305b261ecSmrg	    /*
18405b261ecSmrg	     * Not a simple Unwrap/Wrap as this
18505b261ecSmrg	     * isn't called along the DisplayCursor
18605b261ecSmrg	     * wrapper chain.
18705b261ecSmrg	     */
18805b261ecSmrg	    DisplayCursor = pScreen->DisplayCursor;
18905b261ecSmrg	    pScreen->DisplayCursor = as->DisplayCursor;
19005b261ecSmrg	    (void) (*pScreen->DisplayCursor) (pScreen, ac->elts[elt].pCursor);
19105b261ecSmrg	    as->DisplayCursor = pScreen->DisplayCursor;
19205b261ecSmrg	    pScreen->DisplayCursor = DisplayCursor;
19305b261ecSmrg
19405b261ecSmrg	    animCurState.elt = elt;
19505b261ecSmrg	    animCurState.time = now + ac->elts[elt].delay;
19605b261ecSmrg	}
19705b261ecSmrg	AdjustWaitForDelay (pTimeout, animCurState.time - now);
19805b261ecSmrg    }
19905b261ecSmrg    Unwrap (as, pScreen, BlockHandler);
20005b261ecSmrg    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
20105b261ecSmrg    Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
20205b261ecSmrg}
20305b261ecSmrg
20405b261ecSmrgstatic Bool
20505b261ecSmrgAnimCurDisplayCursor (ScreenPtr pScreen,
20605b261ecSmrg		      CursorPtr pCursor)
20705b261ecSmrg{
20805b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
20905b261ecSmrg    Bool		ret;
21005b261ecSmrg
21105b261ecSmrg    Unwrap (as, pScreen, DisplayCursor);
21205b261ecSmrg    if (IsAnimCur(pCursor))
21305b261ecSmrg    {
21405b261ecSmrg	if (pCursor != animCurState.pCursor)
21505b261ecSmrg	{
21605b261ecSmrg	    AnimCurPtr		ac = GetAnimCur(pCursor);
21705b261ecSmrg
21805b261ecSmrg	    ret = (*pScreen->DisplayCursor) (pScreen, ac->elts[0].pCursor);
21905b261ecSmrg	    if (ret)
22005b261ecSmrg	    {
22105b261ecSmrg		animCurState.elt = 0;
22205b261ecSmrg		animCurState.time = GetTimeInMillis () + ac->elts[0].delay;
22305b261ecSmrg		animCurState.pCursor = pCursor;
22405b261ecSmrg		animCurState.pScreen = pScreen;
22505b261ecSmrg	    }
22605b261ecSmrg	}
22705b261ecSmrg	else
22805b261ecSmrg	    ret = TRUE;
22905b261ecSmrg    }
23005b261ecSmrg    else
23105b261ecSmrg    {
23205b261ecSmrg        animCurState.pCursor = 0;
23305b261ecSmrg	animCurState.pScreen = 0;
23405b261ecSmrg	ret = (*pScreen->DisplayCursor) (pScreen, pCursor);
23505b261ecSmrg    }
23605b261ecSmrg    Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor);
23705b261ecSmrg    return ret;
23805b261ecSmrg}
23905b261ecSmrg
24005b261ecSmrgstatic Bool
24105b261ecSmrgAnimCurSetCursorPosition (ScreenPtr pScreen,
24205b261ecSmrg			  int x,
24305b261ecSmrg			  int y,
24405b261ecSmrg			  Bool generateEvent)
24505b261ecSmrg{
24605b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
24705b261ecSmrg    Bool		ret;
24805b261ecSmrg
24905b261ecSmrg    Unwrap (as, pScreen, SetCursorPosition);
25005b261ecSmrg    if (animCurState.pCursor)
25105b261ecSmrg	animCurState.pScreen = pScreen;
25205b261ecSmrg    ret = (*pScreen->SetCursorPosition) (pScreen, x, y, generateEvent);
25305b261ecSmrg    Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
25405b261ecSmrg    return ret;
25505b261ecSmrg}
25605b261ecSmrg
25705b261ecSmrgstatic Bool
25805b261ecSmrgAnimCurRealizeCursor (ScreenPtr pScreen,
25905b261ecSmrg		      CursorPtr pCursor)
26005b261ecSmrg{
26105b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
26205b261ecSmrg    Bool		ret;
26305b261ecSmrg
26405b261ecSmrg    Unwrap (as, pScreen, RealizeCursor);
26505b261ecSmrg    if (IsAnimCur(pCursor))
26605b261ecSmrg	ret = TRUE;
26705b261ecSmrg    else
26805b261ecSmrg	ret = (*pScreen->RealizeCursor) (pScreen, pCursor);
26905b261ecSmrg    Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor);
27005b261ecSmrg    return ret;
27105b261ecSmrg}
27205b261ecSmrg
27305b261ecSmrgstatic Bool
27405b261ecSmrgAnimCurUnrealizeCursor (ScreenPtr pScreen,
27505b261ecSmrg			CursorPtr pCursor)
27605b261ecSmrg{
27705b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
27805b261ecSmrg    Bool		ret;
27905b261ecSmrg
28005b261ecSmrg    Unwrap (as, pScreen, UnrealizeCursor);
28105b261ecSmrg    if (IsAnimCur(pCursor))
28205b261ecSmrg    {
28305b261ecSmrg        AnimCurPtr  ac = GetAnimCur(pCursor);
28405b261ecSmrg	int	    i;
28505b261ecSmrg
28605b261ecSmrg	if (pScreen->myNum == 0)
28705b261ecSmrg	    for (i = 0; i < ac->nelt; i++)
28805b261ecSmrg		FreeCursor (ac->elts[i].pCursor, 0);
28905b261ecSmrg	ret = TRUE;
29005b261ecSmrg    }
29105b261ecSmrg    else
29205b261ecSmrg	ret = (*pScreen->UnrealizeCursor) (pScreen, pCursor);
29305b261ecSmrg    Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
29405b261ecSmrg    return ret;
29505b261ecSmrg}
29605b261ecSmrg
29705b261ecSmrgstatic void
29805b261ecSmrgAnimCurRecolorCursor (ScreenPtr pScreen,
29905b261ecSmrg		      CursorPtr pCursor,
30005b261ecSmrg		      Bool displayed)
30105b261ecSmrg{
30205b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
30305b261ecSmrg
30405b261ecSmrg    Unwrap (as, pScreen, RecolorCursor);
30505b261ecSmrg    if (IsAnimCur(pCursor))
30605b261ecSmrg    {
30705b261ecSmrg        AnimCurPtr  ac = GetAnimCur(pCursor);
30805b261ecSmrg	int	    i;
30905b261ecSmrg
31005b261ecSmrg        for (i = 0; i < ac->nelt; i++)
31105b261ecSmrg	    (*pScreen->RecolorCursor) (pScreen, ac->elts[i].pCursor,
31205b261ecSmrg				       displayed &&
31305b261ecSmrg				       animCurState.elt == i);
31405b261ecSmrg    }
31505b261ecSmrg    else
31605b261ecSmrg	(*pScreen->RecolorCursor) (pScreen, pCursor, displayed);
31705b261ecSmrg    Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor);
31805b261ecSmrg}
31905b261ecSmrg
32005b261ecSmrgBool
32105b261ecSmrgAnimCurInit (ScreenPtr pScreen)
32205b261ecSmrg{
32305b261ecSmrg    AnimCurScreenPtr    as;
32405b261ecSmrg
32505b261ecSmrg    if (AnimCurGeneration != serverGeneration)
32605b261ecSmrg    {
32705b261ecSmrg	AnimCurScreenPrivateIndex = AllocateScreenPrivateIndex ();
32805b261ecSmrg	if (AnimCurScreenPrivateIndex < 0)
32905b261ecSmrg	    return FALSE;
33005b261ecSmrg	AnimCurGeneration = serverGeneration;
33105b261ecSmrg	animCurState.pCursor = 0;
33205b261ecSmrg	animCurState.pScreen = 0;
33305b261ecSmrg	animCurState.elt = 0;
33405b261ecSmrg	animCurState.time = 0;
33505b261ecSmrg    }
33605b261ecSmrg    as = (AnimCurScreenPtr) xalloc (sizeof (AnimCurScreenRec));
33705b261ecSmrg    if (!as)
33805b261ecSmrg	return FALSE;
33905b261ecSmrg    Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
34005b261ecSmrg
34105b261ecSmrg    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
34205b261ecSmrg
34305b261ecSmrg    Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
34405b261ecSmrg    Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
34505b261ecSmrg    Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
34605b261ecSmrg    Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
34705b261ecSmrg    Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
34805b261ecSmrg    Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
34905b261ecSmrg    SetAnimCurScreen(pScreen,as);
35005b261ecSmrg    return TRUE;
35105b261ecSmrg}
35205b261ecSmrg
35305b261ecSmrgint
35405b261ecSmrgAnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor)
35505b261ecSmrg{
35605b261ecSmrg    CursorPtr	pCursor;
35705b261ecSmrg    int		i;
35805b261ecSmrg    AnimCurPtr	ac;
35905b261ecSmrg
36005b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
36105b261ecSmrg	if (!GetAnimCurScreenIfSet (screenInfo.screens[i]))
36205b261ecSmrg	    return BadImplementation;
36305b261ecSmrg
36405b261ecSmrg    for (i = 0; i < ncursor; i++)
36505b261ecSmrg	if (IsAnimCur (cursors[i]))
36605b261ecSmrg	    return BadMatch;
36705b261ecSmrg
36805b261ecSmrg    pCursor = (CursorPtr) xalloc (sizeof (CursorRec) +
36905b261ecSmrg				  sizeof (AnimCurRec) +
37005b261ecSmrg				  ncursor * sizeof (AnimCurElt));
37105b261ecSmrg    if (!pCursor)
37205b261ecSmrg	return BadAlloc;
37305b261ecSmrg    pCursor->bits = &animCursorBits;
37405b261ecSmrg    animCursorBits.refcnt++;
37505b261ecSmrg    pCursor->refcnt = 1;
37605b261ecSmrg
37705b261ecSmrg    pCursor->foreRed = cursors[0]->foreRed;
37805b261ecSmrg    pCursor->foreGreen = cursors[0]->foreGreen;
37905b261ecSmrg    pCursor->foreBlue = cursors[0]->foreBlue;
38005b261ecSmrg
38105b261ecSmrg    pCursor->backRed = cursors[0]->backRed;
38205b261ecSmrg    pCursor->backGreen = cursors[0]->backGreen;
38305b261ecSmrg    pCursor->backBlue = cursors[0]->backBlue;
38405b261ecSmrg
38505b261ecSmrg    /*
38605b261ecSmrg     * Fill in the AnimCurRec
38705b261ecSmrg     */
38805b261ecSmrg    ac = GetAnimCur (pCursor);
38905b261ecSmrg    ac->nelt = ncursor;
39005b261ecSmrg    ac->elts = (AnimCurElt *) (ac + 1);
39105b261ecSmrg
39205b261ecSmrg    for (i = 0; i < ncursor; i++)
39305b261ecSmrg    {
39405b261ecSmrg	cursors[i]->refcnt++;
39505b261ecSmrg	ac->elts[i].pCursor = cursors[i];
39605b261ecSmrg	ac->elts[i].delay = deltas[i];
39705b261ecSmrg    }
39805b261ecSmrg
39905b261ecSmrg    *ppCursor = pCursor;
40005b261ecSmrg    return Success;
40105b261ecSmrg}
402