Add custom cursor icon support on Windows
- [ ] Tested on all platforms changed
- [x] Compilation warnings were addressed
- [ ]
cargo fmthas been run on this branch - [x]
cargo docbuilds successfully - [x] Added an entry to
CHANGELOG.mdif knowledge of this change could be valuable to users - [x] Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
- [x] Created or updated an example program if it would help users understand this functionality
The PR mentions windows, however you're touching other backends and exposing a new API to some sort. So what's the buffer pixel on Windows(RGBA/ARGB)? On Wayland for example the buffer is in ARGB(the most used one), so it could mean that for custom cursor loading I should change it a bit(convert ARGB to RGBA). Also, maybe we should check what cursor buffer format is on majority platforms and just use it? I'd be interested myself in ARGB, but I guess the most used should be picked?
I also can add wayland implementation for such thing, I guess, but it's a bit obscure. And has some edges like scale factor and what user should provide. I'd assume that all HiDPI handling is up to user here, and it should just ensure that buffer is scaled properly.
I needed to touch the other platforms because this PR makes CursorIcon non-Copy and non-Hash, and adds a new variant that the other platforms weren't handling. Right now, I'm having the other platforms treat custom cursors as the default cursor, which seems like the least intrusive way of ignoring the Custom variant.
The public API surface area for this is fairly small - we're just adding a Custom(Icon) variant to CursorIcon, and adding a new_with_hot_spot method to Icon. Icon's pixel buffer was already publicly formatted as RGBA, and this PR doesn't change that. Each individual backend is expected to convert that to the pixel format it needs, and on Windows, that's BGRA.
I also can add wayland implementation for such thing, I guess, but it's a bit obscure. And has some edges like scale factor and what user should provide. I'd assume that all HiDPI handling is up to user here, and it should just ensure that buffer is scaled properly.
@kchibisov That'd be great, thanks! On Windows, the OS doesn't do any automatic DPI scaling for the custom cursor, so the user would have to manually upload an appropriately-scaled version of the cursor when the scale factor changes. I'm personally okay with that approach, but it should definitely be documented.
note, I'll send Wayland impl later(as separate PR), since it'll actually require some rework of Wayland backend before doing so. Just saying so won't end up waiting on something.
I've thought some more about how icon scaling works, and I've changed my mind somewhat. I still don't think that Winit should do any implicit icon scaling beyond what the OS does, but it should provide an API for attaching multiple images at different scales for a single logical Icon. This is for a couple of reasons:
- Windows
ICOfiles and icon resources include multiple icon sizes in a single file, and if anIconstruct only contains an icon at a single scale (as it does today), users have to manually reload those icons when the scale changes. That's super counterintuitive. - The OS can use multiple window icon sizes at the same time. The current model doesn't support that usecase.
- Windows changes the cursor size when the cursor changes monitor, not when the underlying window changes the scale factor. Expecting users to monitor the exact position of the cursor in a multiple-monitor setup to determine the cursor size is unreasonable, especially since not all backends give access to that information.
I'll update this PR to expose that API and implement it on Windows.
I'll just add that on Wayland client draws the cursor itself with the size and scale it wants. winit shouldn't care about size part on it, since sctk does that already for it, so only scale. Since scaling is done by clients, they should just set buffer scale and attach the proper buffer size (just physical size thing).
So multiple icons is softly required thing on Wayland (you can in theory draw with some big scale, and rely on compositor downscaling).
Windows changes the cursor size when the cursor changes monitor, not when the underlying window changes the scale factor. Expecting users to monitor the exact position of the cursor in a multiple-monitor setup to determine the cursor size is unreasonable, especially since not all backends give access to that information.
Same for Wayland, but since cursor is managed by users, and it's just a normal surface, you get scale changes events for it separately, and so can react and pick proper cursor for that scale, so not a big issue. So if winit wants some consistency across the platforms the cursor DPI scaling should be entirely done by winit, and user should just provide some set of images to pick from.
The OS can use multiple window icon sizes at the same time. The current model doesn't support that usecase.
Not sure how it's related to cursor related things?
Not sure how it's related to cursor related things?
The current API uses the same type for custom window icons and custom cursor icons, so adding support in the public API for this helps improve both the cursor implementation and the window icon implementation.
This change removes the Send trait from winit::window::CursorIcon for Windows, which is kinda a big deal. Is there a way to get it back?
= help: within `winit::platform_impl::platform::icon::RaiiIcon`, the trait `std::marker::Send` is not implemented for `*mut winapi::shared::windef::HICON__`
= note: required because it appears within the type `winit::platform_impl::platform::icon::RaiiIcon`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::Arc<winit::platform_impl::platform::icon::RaiiIcon>`
= note: required because it appears within the type `winit::platform_impl::platform::icon::CustomCursorIcon`
= note: required because it appears within the type `winit::icon::CustomCursorIcon`
= note: required because it appears within the type `winit::window::CursorIcon`
This change removes the
Sendtrait fromwinit::window::CursorIconfor Windows, which is kinda a big deal. Is there a way to get it back?
Yep! That was just an oversight - the implementation was written with Send and Sync in mind, but I forgot to mark the relevant types with those traits. That's fixed now.
Closing due to inactivity.
Tracked in #3005.