Skip to content

Conversation

Kontrabant
Copy link
Contributor

@Kontrabant Kontrabant commented Oct 14, 2025

Add animated cursors to Cocoa, Wayland, Win32, and X11.

Animated cursors are composed of a series of images, with a duration specified for each.

Cursors are handled as close to the system level as possible:

  • On X11, XcursorImagesLoadCursor() is used.
  • On Wayland, custom cursors use the same code path as animated system cursors.
  • On Windows, there is no API to create an animated cursor, so a resource file is built in memory to create a cursor with the animation sequence.
  • On Mac, an NSTimer is used to fire when frame updates are required.

Currently, SDL_CreateAnimatedCursor() falls back to creating a static cursor from the first frame if the platform doesn't support animated cursors. Should it just fail instead?

TODO:

  • This can probably be implemented in KMSDRM.
  • There is probably a way to handle animated cursors on Emscripten, but someone more familiar with the platform could figure it out more easily.
  • Niche platforms and consoles?

Closes #14198
Closes #14248

Generalizes the animated cursor info, so it can be used for custom cursors as well.
@Kontrabant Kontrabant marked this pull request as draft October 14, 2025 15:11
@slouken
Copy link
Collaborator

slouken commented Oct 14, 2025

In general this looks good. Two questions:

  1. Do we need the flexibility of each frame having a different duration?
  2. Does it make sense to have a fallback (or even primary?) implementation that updates the cursor at the correct time in SDL_PumpEvents()?

@slouken
Copy link
Collaborator

slouken commented Oct 14, 2025

Can you update testcustomcursor to also test animated cursors?

@Kontrabant Kontrabant force-pushed the animated_cursors_work branch from 957feb1 to 1250636 Compare October 14, 2025 16:08
@Kontrabant
Copy link
Contributor Author

In general this looks good. Two questions:

  1. Do we need the flexibility of each frame having a different duration?

It's standard among the system level implementations, and adds flexibility without a lot of complexity. The old Windows hourglass wait cursor, for example, uses different durations to make the vertical frame hold longer than the turning frames. It also allows for easily creating one-shot animations by setting the last frame duration to 0 (infinite).

  1. Does it make sense to have a fallback (or even primary?) implementation that updates the cursor at the correct time in SDL_PumpEvents()?

The current implementations don't need this, and wouldn't benefit from it, as the cursors are handled as close to the system-level as possible. X and Windows pass the frames to the desktop and get a single Cursor/HCURSOR object that the system animates itself. Wayland does a single buffer pool allocation and commits suballocated wl_buffer objects in the cursor surface frame callback, just as it has to do with animated system cursors on compositors without the cursor shape protocol. Mac needs some manual handling, but that is still a simple matter of using an NSTimer and invalidating the cursor rect when it fires.

Unless some platform eventually needs this functionality generalized, it's not yet worth the time or effort imo.

@Kontrabant Kontrabant force-pushed the animated_cursors_work branch from 1250636 to b05a359 Compare October 14, 2025 17:10
@slouken
Copy link
Collaborator

slouken commented Oct 14, 2025

In general this looks good. Two questions:

  1. Do we need the flexibility of each frame having a different duration?

It's standard among the system level implementations, and adds flexibility without a lot of complexity. The old Windows hourglass wait cursor, for example, uses different durations to make the vertical frame hold longer than the turning frames. It also allows for easily creating one-shot animations by setting the last frame duration to 0 (infinite).

Okay, that makes sense, especially if it's supported in all the backends.

  1. Does it make sense to have a fallback (or even primary?) implementation that updates the cursor at the correct time in SDL_PumpEvents()?

Unless some platform eventually needs this functionality generalized, it's not yet worth the time or effort imo.

I agree that having the system do the animation is ideal. It might be worth implementing the fallback for the case that is currently a static one frame cursor, and then we can say it's supported everywhere?

@slouken
Copy link
Collaborator

slouken commented Oct 14, 2025

It might be worth implementing the fallback for the case that is currently a static one frame cursor, and then we can say it's supported everywhere?

This would be pretty trivial to do, and I'm happy to add that after this PR lands, if you want.

@Kontrabant Kontrabant force-pushed the animated_cursors_work branch 5 times, most recently from 2155711 to 0137762 Compare October 14, 2025 18:43
@Kontrabant
Copy link
Contributor Author

Kontrabant commented Oct 14, 2025

Can you update testcustomcursor to also test animated cursors?

There are two added cases that make the custom arrow cursor flash: a looping animated sample, and a one-shot that slows down and stops.

I'll add loading an image sequence from files a bit later.

@Kontrabant Kontrabant force-pushed the animated_cursors_work branch 2 times, most recently from f7b447d to f3db7b9 Compare October 15, 2025 00:00
@maia-s
Copy link
Contributor

maia-s commented Oct 15, 2025

Suggestion: For one shot animations, maybe it could get the fallback static cursor from the last frame instead of the first? Other animations can always be rearranged so they start on a suitable frame, but that's not possible for one shots.

@Kontrabant Kontrabant force-pushed the animated_cursors_work branch 2 times, most recently from 7d97a81 to c48d7f9 Compare October 15, 2025 15:46
@Kontrabant
Copy link
Contributor Author

Suggestion: For one shot animations, maybe it could get the fallback static cursor from the last frame instead of the first? Other animations can always be rearranged so they start on a suitable frame, but that's not possible for one shots.

The long term plan is to have a generic fallback that animated cursors at a higher level for backends without animation support, but for now, this is a good idea. Done.

@Kontrabant
Copy link
Contributor Author

I think this is ready to go. The only additional things to do are add support for more platforms.

Thanks @madebr and @sezero for the build fix.

@Kontrabant Kontrabant marked this pull request as ready for review October 15, 2025 16:25
@slouken
Copy link
Collaborator

slouken commented Oct 15, 2025

I added a couple of comments, but this generally looks good to me. Feel free to merge when ready!

Kontrabant and others added 2 commits October 15, 2025 14:33
Adds support for animated cursors on Cocoa, Wayland, Win32, and X11.

testcursor can take a semicolon separated list of filenames and load an animated cursor from them.
@Kontrabant Kontrabant force-pushed the animated_cursors_work branch from c48d7f9 to da49b41 Compare October 15, 2025 18:34
@Kontrabant Kontrabant merged commit aa57984 into libsdl-org:main Oct 15, 2025
42 of 43 checks passed
@Kontrabant
Copy link
Contributor Author

Merged!

@Kontrabant Kontrabant deleted the animated_cursors_work branch October 15, 2025 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SDL_strtok_r is broken on some platforms Add support for animated cursors

4 participants