Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom cursor icon support on Windows #1617

Closed
wants to merge 31 commits into from

Conversation

Osspial
Copy link
Contributor

@Osspial Osspial commented Jul 4, 2020

  • Tested on all platforms changed
  • Compilation warnings were addressed
  • cargo fmt has been run on this branch
  • cargo doc builds successfully
  • Added an entry to CHANGELOG.md if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality

@Osspial Osspial changed the title Set cursor custom icon Add custom cursor icon support on Windows Jul 4, 2020
@kchibisov
Copy link
Member

kchibisov commented Jul 4, 2020

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.

@Osspial
Copy link
Contributor Author

Osspial commented Jul 4, 2020

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.

@kchibisov
Copy link
Member

kchibisov commented Jul 9, 2020

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.

@Osspial Osspial force-pushed the set_cursor_custom_icon branch from 1923108 to 54646ae Compare July 10, 2020 00:41
@Osspial
Copy link
Contributor Author

Osspial commented Jul 10, 2020

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 ICO files and icon resources include multiple icon sizes in a single file, and if an Icon struct 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.

@kchibisov
Copy link
Member

kchibisov commented Jul 10, 2020

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?

@Osspial
Copy link
Contributor Author

Osspial commented Jul 13, 2020

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.

src/icon.rs Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
src/icon.rs Outdated Show resolved Hide resolved
src/icon.rs Outdated
pub struct RgbaIcon<I: Deref<Target = [u8]>> {
pub(crate) rgba: I,
pub(crate) size: PhysicalSize<u32>,
pub(crate) hot_spot: PhysicalPosition<u32>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like that we have a cursor and normal icons under the same RgbaIcon, in general, we can name it like RgbaBuffer, since the intent to have RgbaBuffer and have Icon and a new type for cursor icons, which will use that RgbaBuffer under the hood?

It's just strange that we have a field that shouldn't be used in any ways in certain scenarios, but in other cases it's fine to use them. Such issues should be solved on type system level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a decent point. I've updated the API to split the custom window type and custom cursor type into two parts, though it's not documented yet. Could you take a look at it?

src/icon.rs Outdated Show resolved Hide resolved
src/icon.rs Outdated Show resolved Hide resolved
src/icon.rs Outdated Show resolved Hide resolved
src/platform_impl/linux/x11/util/cursor.rs Outdated Show resolved Hide resolved
Co-authored-by: Kirill Chibisov <[email protected]>
@anlumo
Copy link

anlumo commented Aug 20, 2020

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`

@Osspial
Copy link
Contributor Author

Osspial commented Sep 16, 2020

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?

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.

@daxpedda
Copy link
Member

Closing due to inactivity.

Tracked in #3005.

@daxpedda daxpedda closed this Aug 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

5 participants