This is documentation about the cursor handling, not about the cursor rendering!
Generally, a _CursorRec_ gets allocated only once and used multiple times to save memory. Two functions are responsible for allocating cursors: _AllocCursorARGB()_ and _AllocGlyphCursor()_. The matching Xlib functions would be _XCreateCursor()_ and _XCreateGlyphCursor()_.
The CursorRec contains a number of things, we will focus on the _refcnt_ here. The _refcnt_ is used to track how many instances of the cursor are used and to avoid freeing memory too early. The _refcnt_ is increased when
1. a client gets a reference to a cursor
1. a window uses the cursor
1. a pointer uses the cursor
1. a pointer uses the cursor as part of a grab.
When you create a cursor, it will have a _refcnt_ of 1 (the client has a reference to it after all). Each time you use Xlib's _XDefineCursor()_ or _XChangeWindowAttributes()_, the window obtains a reference to the cursor and increases the _refcnt_. And each time the pointer passes into a window that has a cursor set, _ChangeToCursor()_ will change the pointer's cursor and increase the _refcnt_. Using the cursor for a sprite does NOT change the _refcnt_!
The _refcnt_ is decreased in _FreeCursor()_. When the _refcnt_ hits 0, the memory for the cursor is freed. Make sure that when you call _FreeCursor()_, nothing in your codepath references the address anymore. The usual way to do this is something like
[[!format txt """
CursorPtr pOldCursor = device->spriteInfo->sprite->current;
device->spriteInfo->sprite->current = NULL;
The value of _pOldCursor_ is undefined after _FreeCursor()_.
_FreeCursor()_ is called from several points. Each time the cursor leaves a window, _CheckMotion()_ call _PostNewCursor()_, which may call _ChangeToCursor()_. When the client issues a _FreeCursor_ request. Each time a window changes the cursor (_ChangeWindowAttributes()_). When a grab with a cursor is deactivated. And on _CloseDownClient()_, when all the resources are freed for the client. And quite a few more.
### Animated cursors
Animated cursors are part of the XRender extension. All they are is a list of standard cursors with a delay between them. The memory is a standard _CursorRec_, with an _AnimCursorRec_ and several _AnimCursElt_ attached to the end of the struct. The latter two contain the _CursorRec_ that make up the animated cursor's frames. Animated cursors are identified with a special pattern in the _CursorRec_s _bits_ field. See _AnimCursorCreate()_.
So for an animated cursor with 3 frames, the memory looks something like this.
[[!format txt """
[ CursorRec ][ AnimCursorRec ][AnimCursElt][AnimCursElt][AnimCursElt]
| | |
[ CursorRec ] <------------------- | |
[ CursorRec ] <--------------------------------- |
[ CursorRec ] <----------------------------------------------
Each cursor that is used in an animated cursor has the _refcnt_ increased, and likewise decreased via _FreeCursor()_ when the animated cursor is deleted. If a window or pointer uses a animated cursor, they use the animated cursor struct, never directly any of the cursors that make up the frames.
X uses a _BlockHandler_ to do stuff when nothing else needs to be done. Such as redrawing mouse cursors. The animated cursor code adds itself to the block handler and _AnimCurScreenBlockHandler()_ is called regularly.
Display of an animated cursor uses set of static variables in _animcur.c_. The currently displayed animated cursor is saved, and each time the block handler is called, it checks
* whether the current cursor is an animated cursor.
* if so, if the timeout for the next frame has passed already
* if so, display the next frame
* if so, save the timeout for the next frame in the static struct
* update wakeup handler to wake up for next timeout.