animcur.c revision 9ace9065
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"
474642e01fSmrg#include "inputstr.h"
484642e01fSmrg#include "xace.h"
4905b261ecSmrg
5005b261ecSmrgtypedef struct _AnimCurElt {
5105b261ecSmrg    CursorPtr	pCursor;    /* cursor to show */
5205b261ecSmrg    CARD32	delay;	    /* in ms */
5305b261ecSmrg} AnimCurElt;
5405b261ecSmrg
5505b261ecSmrgtypedef struct _AnimCur {
5605b261ecSmrg    int		nelt;	    /* number of elements in the elts array */
5705b261ecSmrg    AnimCurElt	*elts;	    /* actually allocated right after the structure */
5805b261ecSmrg} AnimCurRec, *AnimCurPtr;
5905b261ecSmrg
6005b261ecSmrgtypedef struct _AnimScrPriv {
6105b261ecSmrg    CloseScreenProcPtr		CloseScreen;
6205b261ecSmrg
6305b261ecSmrg    ScreenBlockHandlerProcPtr	BlockHandler;
6405b261ecSmrg
6505b261ecSmrg    CursorLimitsProcPtr		CursorLimits;
6605b261ecSmrg    DisplayCursorProcPtr	DisplayCursor;
6705b261ecSmrg    SetCursorPositionProcPtr	SetCursorPosition;
6805b261ecSmrg    RealizeCursorProcPtr	RealizeCursor;
6905b261ecSmrg    UnrealizeCursorProcPtr	UnrealizeCursor;
7005b261ecSmrg    RecolorCursorProcPtr	RecolorCursor;
7105b261ecSmrg} AnimCurScreenRec, *AnimCurScreenPtr;
7205b261ecSmrg
7305b261ecSmrgstatic unsigned char empty[4];
7405b261ecSmrg
7505b261ecSmrgstatic CursorBits   animCursorBits = {
7605b261ecSmrg    empty, empty, 2, 1, 1, 0, 0, 1
7705b261ecSmrg};
7805b261ecSmrg
796747b715Smrgstatic DevPrivateKeyRec AnimCurScreenPrivateKeyRec;
806747b715Smrg#define AnimCurScreenPrivateKey (&AnimCurScreenPrivateKeyRec)
814642e01fSmrg
824642e01fSmrg#define IsAnimCur(c)	    ((c) && ((c)->bits == &animCursorBits))
836747b715Smrg#define GetAnimCur(c)	    ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE))))
844642e01fSmrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey))
854642e01fSmrg#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p)
8605b261ecSmrg
8705b261ecSmrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
8805b261ecSmrg#define Unwrap(as,s,elt)    ((s)->elt = (as)->elt)
8905b261ecSmrg
9005b261ecSmrg
9105b261ecSmrgstatic Bool
9205b261ecSmrgAnimCurCloseScreen (int index, ScreenPtr pScreen)
9305b261ecSmrg{
9405b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
9505b261ecSmrg    Bool                ret;
9605b261ecSmrg
9705b261ecSmrg    Unwrap(as, pScreen, CloseScreen);
9805b261ecSmrg
9905b261ecSmrg    Unwrap(as, pScreen, CursorLimits);
10005b261ecSmrg    Unwrap(as, pScreen, DisplayCursor);
10105b261ecSmrg    Unwrap(as, pScreen, SetCursorPosition);
10205b261ecSmrg    Unwrap(as, pScreen, RealizeCursor);
10305b261ecSmrg    Unwrap(as, pScreen, UnrealizeCursor);
10405b261ecSmrg    Unwrap(as, pScreen, RecolorCursor);
10505b261ecSmrg    SetAnimCurScreen(pScreen,0);
10605b261ecSmrg    ret = (*pScreen->CloseScreen) (index, pScreen);
1076747b715Smrg    free(as);
10805b261ecSmrg    return ret;
10905b261ecSmrg}
11005b261ecSmrg
11105b261ecSmrgstatic void
1124642e01fSmrgAnimCurCursorLimits (DeviceIntPtr pDev,
1134642e01fSmrg                     ScreenPtr pScreen,
11405b261ecSmrg		     CursorPtr pCursor,
11505b261ecSmrg		     BoxPtr pHotBox,
11605b261ecSmrg		     BoxPtr pTopLeftBox)
11705b261ecSmrg{
11805b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
11905b261ecSmrg
12005b261ecSmrg    Unwrap (as, pScreen, CursorLimits);
12105b261ecSmrg    if (IsAnimCur(pCursor))
12205b261ecSmrg    {
12305b261ecSmrg	AnimCurPtr	ac = GetAnimCur(pCursor);
12405b261ecSmrg
1254642e01fSmrg        (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor,
1264642e01fSmrg                                  pHotBox, pTopLeftBox);
12705b261ecSmrg    }
12805b261ecSmrg    else
12905b261ecSmrg    {
1306747b715Smrg        (*pScreen->CursorLimits) (pDev, pScreen, pCursor,
1314642e01fSmrg                                  pHotBox, pTopLeftBox);
13205b261ecSmrg    }
13305b261ecSmrg    Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits);
13405b261ecSmrg}
13505b261ecSmrg
13605b261ecSmrg/*
13705b261ecSmrg * This has to be a screen block handler instead of a generic
13805b261ecSmrg * block handler so that it is well ordered with respect to the DRI
13905b261ecSmrg * block handler responsible for releasing the hardware to DRI clients
14005b261ecSmrg */
14105b261ecSmrg
14205b261ecSmrgstatic void
14305b261ecSmrgAnimCurScreenBlockHandler (int screenNum,
14405b261ecSmrg			   pointer blockData,
14505b261ecSmrg			   pointer pTimeout,
14605b261ecSmrg			   pointer pReadmask)
14705b261ecSmrg{
14805b261ecSmrg    ScreenPtr		pScreen = screenInfo.screens[screenNum];
14905b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
1504642e01fSmrg    DeviceIntPtr        dev;
1518223e2f2Smrg    Bool                activeDevice = FALSE;
1524642e01fSmrg    CARD32              now = 0,
1534642e01fSmrg                        soonest = ~0; /* earliest time to wakeup again */
15405b261ecSmrg
1554642e01fSmrg    for (dev = inputInfo.devices; dev; dev = dev->next)
15605b261ecSmrg    {
1576747b715Smrg	if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen)
15805b261ecSmrg	{
1598223e2f2Smrg	    if (!activeDevice) {
1608223e2f2Smrg                now = GetTimeInMillis ();
1618223e2f2Smrg                activeDevice = TRUE;
1628223e2f2Smrg            }
1634642e01fSmrg
1646747b715Smrg	    if ((INT32) (now - dev->spriteInfo->anim.time) >= 0)
1654642e01fSmrg	    {
1666747b715Smrg		AnimCurPtr ac  = GetAnimCur(dev->spriteInfo->anim.pCursor);
1676747b715Smrg		int        elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt;
1684642e01fSmrg		DisplayCursorProcPtr DisplayCursor;
1694642e01fSmrg
1704642e01fSmrg		/*
1714642e01fSmrg		 * Not a simple Unwrap/Wrap as this
1724642e01fSmrg		 * isn't called along the DisplayCursor
1734642e01fSmrg		 * wrapper chain.
1744642e01fSmrg		 */
1754642e01fSmrg		DisplayCursor = pScreen->DisplayCursor;
1764642e01fSmrg		pScreen->DisplayCursor = as->DisplayCursor;
1774642e01fSmrg		(void) (*pScreen->DisplayCursor) (dev,
1784642e01fSmrg						  pScreen,
1794642e01fSmrg						  ac->elts[elt].pCursor);
1804642e01fSmrg		as->DisplayCursor = pScreen->DisplayCursor;
1814642e01fSmrg		pScreen->DisplayCursor = DisplayCursor;
1824642e01fSmrg
1836747b715Smrg		dev->spriteInfo->anim.elt = elt;
1846747b715Smrg		dev->spriteInfo->anim.time = now + ac->elts[elt].delay;
1854642e01fSmrg	    }
1864642e01fSmrg
1876747b715Smrg	    if (soonest > dev->spriteInfo->anim.time)
1886747b715Smrg		soonest = dev->spriteInfo->anim.time;
18905b261ecSmrg	}
19005b261ecSmrg    }
1914642e01fSmrg
1928223e2f2Smrg    if (activeDevice)
1934642e01fSmrg        AdjustWaitForDelay (pTimeout, soonest - now);
1944642e01fSmrg
19505b261ecSmrg    Unwrap (as, pScreen, BlockHandler);
19605b261ecSmrg    (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask);
1979ace9065Smrg    if (activeDevice)
1989ace9065Smrg        Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
1999ace9065Smrg    else
2009ace9065Smrg        as->BlockHandler = NULL;
20105b261ecSmrg}
20205b261ecSmrg
20305b261ecSmrgstatic Bool
2044642e01fSmrgAnimCurDisplayCursor (DeviceIntPtr pDev,
2054642e01fSmrg                      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    {
2146747b715Smrg	if (pCursor != pDev->spriteInfo->anim.pCursor)
21505b261ecSmrg	{
21605b261ecSmrg	    AnimCurPtr		ac = GetAnimCur(pCursor);
21705b261ecSmrg
2184642e01fSmrg	    ret = (*pScreen->DisplayCursor)
2194642e01fSmrg                (pDev, pScreen, ac->elts[0].pCursor);
22005b261ecSmrg	    if (ret)
22105b261ecSmrg	    {
2226747b715Smrg		pDev->spriteInfo->anim.elt = 0;
2236747b715Smrg		pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay;
2246747b715Smrg		pDev->spriteInfo->anim.pCursor = pCursor;
2256747b715Smrg		pDev->spriteInfo->anim.pScreen = pScreen;
2269ace9065Smrg
2279ace9065Smrg		if (!as->BlockHandler)
2289ace9065Smrg		    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
22905b261ecSmrg	    }
23005b261ecSmrg	}
23105b261ecSmrg	else
23205b261ecSmrg	    ret = TRUE;
23305b261ecSmrg    }
23405b261ecSmrg    else
23505b261ecSmrg    {
2366747b715Smrg	pDev->spriteInfo->anim.pCursor = 0;
2376747b715Smrg	pDev->spriteInfo->anim.pScreen = 0;
2384642e01fSmrg	ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor);
23905b261ecSmrg    }
24005b261ecSmrg    Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor);
24105b261ecSmrg    return ret;
24205b261ecSmrg}
24305b261ecSmrg
24405b261ecSmrgstatic Bool
2454642e01fSmrgAnimCurSetCursorPosition (DeviceIntPtr pDev,
2464642e01fSmrg                          ScreenPtr pScreen,
24705b261ecSmrg			  int x,
24805b261ecSmrg			  int y,
24905b261ecSmrg			  Bool generateEvent)
25005b261ecSmrg{
25105b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
25205b261ecSmrg    Bool		ret;
25305b261ecSmrg
25405b261ecSmrg    Unwrap (as, pScreen, SetCursorPosition);
2559ace9065Smrg    if (pDev->spriteInfo->anim.pCursor) {
2566747b715Smrg	pDev->spriteInfo->anim.pScreen = pScreen;
2579ace9065Smrg
2589ace9065Smrg	if (!as->BlockHandler)
2599ace9065Smrg	    Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler);
2609ace9065Smrg    }
2614642e01fSmrg    ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
26205b261ecSmrg    Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
26305b261ecSmrg    return ret;
26405b261ecSmrg}
26505b261ecSmrg
26605b261ecSmrgstatic Bool
2674642e01fSmrgAnimCurRealizeCursor (DeviceIntPtr pDev,
2684642e01fSmrg                      ScreenPtr pScreen,
26905b261ecSmrg		      CursorPtr pCursor)
27005b261ecSmrg{
27105b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
27205b261ecSmrg    Bool		ret;
27305b261ecSmrg
27405b261ecSmrg    Unwrap (as, pScreen, RealizeCursor);
27505b261ecSmrg    if (IsAnimCur(pCursor))
27605b261ecSmrg	ret = TRUE;
27705b261ecSmrg    else
2784642e01fSmrg	ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor);
27905b261ecSmrg    Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor);
28005b261ecSmrg    return ret;
28105b261ecSmrg}
28205b261ecSmrg
28305b261ecSmrgstatic Bool
2844642e01fSmrgAnimCurUnrealizeCursor (DeviceIntPtr pDev,
2854642e01fSmrg                        ScreenPtr pScreen,
28605b261ecSmrg			CursorPtr pCursor)
28705b261ecSmrg{
28805b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
28905b261ecSmrg    Bool		ret;
29005b261ecSmrg
29105b261ecSmrg    Unwrap (as, pScreen, UnrealizeCursor);
29205b261ecSmrg    if (IsAnimCur(pCursor))
29305b261ecSmrg    {
29405b261ecSmrg        AnimCurPtr  ac = GetAnimCur(pCursor);
29505b261ecSmrg	int	    i;
29605b261ecSmrg
29705b261ecSmrg	if (pScreen->myNum == 0)
29805b261ecSmrg	    for (i = 0; i < ac->nelt; i++)
29905b261ecSmrg		FreeCursor (ac->elts[i].pCursor, 0);
30005b261ecSmrg	ret = TRUE;
30105b261ecSmrg    }
30205b261ecSmrg    else
3034642e01fSmrg	ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor);
30405b261ecSmrg    Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
30505b261ecSmrg    return ret;
30605b261ecSmrg}
30705b261ecSmrg
30805b261ecSmrgstatic void
3094642e01fSmrgAnimCurRecolorCursor (DeviceIntPtr pDev,
3104642e01fSmrg                      ScreenPtr pScreen,
31105b261ecSmrg		      CursorPtr pCursor,
31205b261ecSmrg		      Bool displayed)
31305b261ecSmrg{
31405b261ecSmrg    AnimCurScreenPtr    as = GetAnimCurScreen(pScreen);
31505b261ecSmrg
31605b261ecSmrg    Unwrap (as, pScreen, RecolorCursor);
31705b261ecSmrg    if (IsAnimCur(pCursor))
31805b261ecSmrg    {
31905b261ecSmrg        AnimCurPtr  ac = GetAnimCur(pCursor);
32005b261ecSmrg	int	    i;
32105b261ecSmrg
32205b261ecSmrg        for (i = 0; i < ac->nelt; i++)
3234642e01fSmrg	    (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor,
32405b261ecSmrg				       displayed &&
3256747b715Smrg				       pDev->spriteInfo->anim.elt == i);
32605b261ecSmrg    }
32705b261ecSmrg    else
3284642e01fSmrg	(*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed);
32905b261ecSmrg    Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor);
33005b261ecSmrg}
33105b261ecSmrg
33205b261ecSmrgBool
33305b261ecSmrgAnimCurInit (ScreenPtr pScreen)
33405b261ecSmrg{
33505b261ecSmrg    AnimCurScreenPtr    as;
33605b261ecSmrg
3376747b715Smrg    if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
3386747b715Smrg	return FALSE;
3396747b715Smrg
3406747b715Smrg    as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec));
34105b261ecSmrg    if (!as)
34205b261ecSmrg	return FALSE;
34305b261ecSmrg    Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen);
34405b261ecSmrg
3459ace9065Smrg    as->BlockHandler = NULL;
34605b261ecSmrg
34705b261ecSmrg    Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits);
34805b261ecSmrg    Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor);
34905b261ecSmrg    Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition);
35005b261ecSmrg    Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor);
35105b261ecSmrg    Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
35205b261ecSmrg    Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor);
35305b261ecSmrg    SetAnimCurScreen(pScreen,as);
35405b261ecSmrg    return TRUE;
35505b261ecSmrg}
35605b261ecSmrg
35705b261ecSmrgint
3584642e01fSmrgAnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid)
35905b261ecSmrg{
36005b261ecSmrg    CursorPtr	pCursor;
3614642e01fSmrg    int		rc, i;
36205b261ecSmrg    AnimCurPtr	ac;
36305b261ecSmrg
36405b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++)
3656747b715Smrg	if (!GetAnimCurScreen (screenInfo.screens[i]))
36605b261ecSmrg	    return BadImplementation;
36705b261ecSmrg
36805b261ecSmrg    for (i = 0; i < ncursor; i++)
36905b261ecSmrg	if (IsAnimCur (cursors[i]))
37005b261ecSmrg	    return BadMatch;
37105b261ecSmrg
3726747b715Smrg    pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE +
3736747b715Smrg				 sizeof (AnimCurRec) +
3746747b715Smrg				 ncursor * sizeof (AnimCurElt), 1);
37505b261ecSmrg    if (!pCursor)
37605b261ecSmrg	return BadAlloc;
3776747b715Smrg    dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR);
37805b261ecSmrg    pCursor->bits = &animCursorBits;
37905b261ecSmrg    pCursor->refcnt = 1;
38005b261ecSmrg
38105b261ecSmrg    pCursor->foreRed = cursors[0]->foreRed;
38205b261ecSmrg    pCursor->foreGreen = cursors[0]->foreGreen;
38305b261ecSmrg    pCursor->foreBlue = cursors[0]->foreBlue;
38405b261ecSmrg
38505b261ecSmrg    pCursor->backRed = cursors[0]->backRed;
38605b261ecSmrg    pCursor->backGreen = cursors[0]->backGreen;
38705b261ecSmrg    pCursor->backBlue = cursors[0]->backBlue;
38805b261ecSmrg
3894642e01fSmrg    pCursor->id = cid;
3904642e01fSmrg
3914642e01fSmrg    /* security creation/labeling check */
3924642e01fSmrg    rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor,
3934642e01fSmrg		  RT_NONE, NULL, DixCreateAccess);
3944642e01fSmrg    if (rc != Success) {
3956747b715Smrg	dixFiniPrivates(pCursor, PRIVATE_CURSOR);
3966747b715Smrg	free(pCursor);
3974642e01fSmrg	return rc;
3984642e01fSmrg    }
3994642e01fSmrg
40005b261ecSmrg    /*
40105b261ecSmrg     * Fill in the AnimCurRec
40205b261ecSmrg     */
4034642e01fSmrg    animCursorBits.refcnt++;
40405b261ecSmrg    ac = GetAnimCur (pCursor);
40505b261ecSmrg    ac->nelt = ncursor;
40605b261ecSmrg    ac->elts = (AnimCurElt *) (ac + 1);
40705b261ecSmrg
40805b261ecSmrg    for (i = 0; i < ncursor; i++)
40905b261ecSmrg    {
41005b261ecSmrg	cursors[i]->refcnt++;
41105b261ecSmrg	ac->elts[i].pCursor = cursors[i];
41205b261ecSmrg	ac->elts[i].delay = deltas[i];
41305b261ecSmrg    }
41405b261ecSmrg
41505b261ecSmrg    *ppCursor = pCursor;
41605b261ecSmrg    return Success;
41705b261ecSmrg}
418