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

Adding the ability to change the mouse cursor for MacOS and Windows #128

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

discordance
Copy link
Contributor

The feature was already there for X11, but wasn't available in MacOS and Windows.

The code is based on winit code mostly.
I've tested locally with a modified version of iced_baseview that I am working on for a project.
Not sure if adding a set_mouse_cursor to the window is the way to go but it works for me.

This is related to the #123 issue.

Copy link
Member

@robbert-vdh robbert-vdh left a comment

Choose a reason for hiding this comment

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

Rebased here, tested on Windows/Wine and Linux (can also boot up a Mac if noone's tested that). Mostly LGTM functionality wise, though I have some comments on how this changes the current behavior on WIndows.

I would suggest using the same list of cursors and the same cursor assignments as winit though. And thus also dropping MouseCursor::Pointer again. The existing cursor enum was already based on this, so bringing everything back in line with winit's current definitions shouldn't be too difficult. The enum can be found here, and I linked the platform-specific cursor assignments in the comments below. This way it becomes easier to switch between winit and baseview backends for GUI frameworks that support both, as the cursors will look the same on both platforms.

@@ -62,6 +62,7 @@ pub(super) fn get_xcursor(display: *mut x11::xlib::Display, cursor: MouseCursor)

MouseCursor::Hand => loadn(&[b"hand2\0", b"hand1\0"]),
MouseCursor::HandGrabbing => loadn(&[b"closedhand\0", b"grabbing\0"]),
MouseCursor::Pointer => loadn(&[b"hand2\0"]),
Copy link
Member

Choose a reason for hiding this comment

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

This can be load() since there's only a single cursor name here. Won't make any difference in practice, but then it's consistent with the other calls here. And as mentioned above, there probably shouldn't be another MouseCursor::Pointer so the list can stay identical to winit's.

These are winit's x11 cursor assignments:

https://github.com/rust-windowing/winit/blob/bdcbd7d1f99464fe945596b43a922a9632456e44/src/platform_impl/linux/x11/util/cursor.rs#L78

match cursor {
MouseCursor::Default => Cursor::Native("arrowCursor"),
MouseCursor::Pointer => Cursor::Native("pointingHandCursor"),
MouseCursor::Hand => Cursor::Native("openHandCursor"),
Copy link
Member

Choose a reason for hiding this comment

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

Is MouseCursor::Pointer needed? It might be a good idea to use the exact same cursor assignments as winit, since this list is based on winit's: https://github.com/rust-windowing/winit/blob/bdcbd7d1f99464fe945596b43a922a9632456e44/src/platform_impl/macos/appkit/cursor.rs#L196

That way GUI frameworks that support both winit and baseview will look the same. Now they'd use different cursors for baseview and winit.

use crate::MouseCursor;

impl MouseCursor {
pub(crate) fn to_windows_cursor(self) -> PCWSTR {
Copy link
Member

Choose a reason for hiding this comment

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

@@ -350,7 +341,7 @@ unsafe fn register_wnd_class() -> ATOM {
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: LoadCursorW(null_mut(), IDC_ARROW),
hCursor: null_mut(), // If the class cursor is not NULL, the system restores the class cursor each time the mouse is moved.
Copy link
Member

Choose a reason for hiding this comment

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

The downside to defaulting this to null_mut() is that this now breaks every application that doesn't set a custom mouse cursor on startup by hiding the cursor by default. This behavior is then also different between Windows, Linux, and macOS.

I'm not quite sure what the best way to tackle this is. One option is to store the last cursor set through Window::set_mouse_cursor() in WindowState, default this value to IDC_ARROW, and set the cursor to that value whenever the user enters the window. Another less hacky approach is to also change the window class's cursor using SetClassLong(hwnd, GCL_HCURSOR, cursor as i32);. Neither is particularly pretty, but the latter approach is at least pretty foolproof. If you want, you can use this patch for this: (for some reason GitHub doesn't let you upload .patch files, so I gzipped it)

0001-Revert-to-IDC_ARROW-as-default-window-class-cursor.patch.gz

@BillyDM BillyDM mentioned this pull request Mar 18, 2024
27 tasks
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.

2 participants