From bd9cc2a9da7de62bf2cdd5d220f8c3635c3d82cc Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Tue, 9 May 2023 20:19:35 +0300 Subject: [PATCH] Use `cursor-icon` crate for `CursorIcon` This crate is aimed to simplify handling of cursor icon across various crates and be used in the public API. --- CHANGELOG.md | 3 + Cargo.toml | 2 + examples/cursor.rs | 3 +- .../linux/wayland/window/state.rs | 63 +++------------- src/platform_impl/linux/x11/util/cursor.rs | 71 ++----------------- src/platform_impl/macos/appkit/cursor.rs | 4 +- src/platform_impl/web/window.rs | 43 +---------- src/platform_impl/windows/event_loop.rs | 2 +- src/platform_impl/windows/util.rs | 48 ++++++------- src/platform_impl/windows/window.rs | 2 +- src/window.rs | 63 +--------------- 11 files changed, 54 insertions(+), 250 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d55171ef..dfcd18d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- **Breaking:** `CursorIcon` is now used from the `cursor-icon` crate. +- **Breaking:** `CursorIcon::Hand` is now named `CursorIcon::Pointer`. +- **Breaking:** `CursorIcon::Arrow` was removed. - On macOS, fixed memory leak when getting monitor handle. - On Wayland, fix maximized startup not taking full size on GNOME. - On Wayland, fix initial window size not restored for maximized/fullscreened on startup window. diff --git a/Cargo.toml b/Cargo.toml index a067c117..8772306d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,12 +44,14 @@ wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"] wayland-csd-adwaita-notitle = ["sctk-adwaita"] android-native-activity = ["android-activity/native-activity"] android-game-activity = ["android-activity/game-activity"] +serde = ["dep:serde", "cursor-icon/serde"] [build-dependencies] cfg_aliases = "0.1.1" [dependencies] bitflags = "1" +cursor-icon = "1.0.0" instant = { version = "0.1", features = ["wasm-bindgen"] } log = "0.4" mint = { version = "0.5.6", optional = true } diff --git a/examples/cursor.rs b/examples/cursor.rs index fdef7ef9..93b69d77 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -54,8 +54,7 @@ fn main() { const CURSORS: &[CursorIcon] = &[ CursorIcon::Default, CursorIcon::Crosshair, - CursorIcon::Hand, - CursorIcon::Arrow, + CursorIcon::Pointer, CursorIcon::Move, CursorIcon::Text, CursorIcon::Wait, diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index f968866b..47f6c7fc 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -547,63 +547,22 @@ impl WindowState { return; } - let cursors: &[&str] = match cursor_icon { - CursorIcon::Alias => &["link"], - CursorIcon::Arrow => &["arrow"], - CursorIcon::Cell => &["plus"], - CursorIcon::Copy => &["copy"], - CursorIcon::Crosshair => &["crosshair"], - CursorIcon::Default => &["left_ptr"], - CursorIcon::Hand => &["hand2", "hand1"], - CursorIcon::Help => &["question_arrow"], - CursorIcon::Move => &["move"], - CursorIcon::Grab => &["openhand", "grab"], - CursorIcon::Grabbing => &["closedhand", "grabbing"], - CursorIcon::Progress => &["progress"], - CursorIcon::AllScroll => &["all-scroll"], - CursorIcon::ContextMenu => &["context-menu"], - - CursorIcon::NoDrop => &["no-drop", "circle"], - CursorIcon::NotAllowed => &["crossed_circle"], - - // Resize cursors - CursorIcon::EResize => &["right_side"], - CursorIcon::NResize => &["top_side"], - CursorIcon::NeResize => &["top_right_corner"], - CursorIcon::NwResize => &["top_left_corner"], - CursorIcon::SResize => &["bottom_side"], - CursorIcon::SeResize => &["bottom_right_corner"], - CursorIcon::SwResize => &["bottom_left_corner"], - CursorIcon::WResize => &["left_side"], - CursorIcon::EwResize => &["h_double_arrow"], - CursorIcon::NsResize => &["v_double_arrow"], - CursorIcon::NwseResize => &["bd_double_arrow", "size_fdiag"], - CursorIcon::NeswResize => &["fd_double_arrow", "size_bdiag"], - CursorIcon::ColResize => &["split_h", "h_double_arrow"], - CursorIcon::RowResize => &["split_v", "v_double_arrow"], - CursorIcon::Text => &["text", "xterm"], - CursorIcon::VerticalText => &["vertical-text"], - - CursorIcon::Wait => &["watch"], - - CursorIcon::ZoomIn => &["zoom-in"], - CursorIcon::ZoomOut => &["zoom-out"], - }; - self.apply_on_poiner(|pointer, data| { let surface = data.cursor_surface(); let scale_factor = surface.data::().unwrap().scale_factor(); - for cursor in cursors { - if pointer - .set_cursor(&self.connection, cursor, &self.shm, surface, scale_factor) - .is_ok() - { - return; - } + if pointer + .set_cursor( + &self.connection, + cursor_icon.name(), + &self.shm, + surface, + scale_factor, + ) + .is_err() + { + warn!("Failed to set cursor to {:?}", cursor_icon); } - - warn!("Failed to set cursor to {:?}", cursor_icon); }) } diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index 99b25635..1e70b864 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -1,3 +1,5 @@ +use std::ffi::CString; + use crate::window::CursorIcon; use super::*; @@ -45,78 +47,15 @@ impl XConnection { } } - fn load_cursor(&self, name: &[u8]) -> ffi::Cursor { - unsafe { - (self.xcursor.XcursorLibraryLoadCursor)(self.display, name.as_ptr() as *const c_char) - } - } - - fn load_first_existing_cursor(&self, names: &[&[u8]]) -> ffi::Cursor { - for name in names.iter() { - let xcursor = self.load_cursor(name); - if xcursor != 0 { - return xcursor; - } - } - 0 - } - fn get_cursor(&self, cursor: Option) -> ffi::Cursor { let cursor = match cursor { Some(cursor) => cursor, None => return self.create_empty_cursor(), }; - let load = |name: &[u8]| self.load_cursor(name); - - let loadn = |names: &[&[u8]]| self.load_first_existing_cursor(names); - - // Try multiple names in some cases where the name - // differs on the desktop environments or themes. - // - // Try the better looking (or more suiting) names first. - match cursor { - CursorIcon::Alias => load(b"link\0"), - CursorIcon::Arrow => load(b"arrow\0"), - CursorIcon::Cell => load(b"plus\0"), - CursorIcon::Copy => load(b"copy\0"), - CursorIcon::Crosshair => load(b"crosshair\0"), - CursorIcon::Default => load(b"left_ptr\0"), - CursorIcon::Hand => loadn(&[b"hand2\0", b"hand1\0"]), - CursorIcon::Help => load(b"question_arrow\0"), - CursorIcon::Move => load(b"move\0"), - CursorIcon::Grab => loadn(&[b"openhand\0", b"grab\0"]), - CursorIcon::Grabbing => loadn(&[b"closedhand\0", b"grabbing\0"]), - CursorIcon::Progress => load(b"left_ptr_watch\0"), - CursorIcon::AllScroll => load(b"all-scroll\0"), - CursorIcon::ContextMenu => load(b"context-menu\0"), - - CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]), - CursorIcon::NotAllowed => load(b"crossed_circle\0"), - - // Resize cursors - CursorIcon::EResize => load(b"right_side\0"), - CursorIcon::NResize => load(b"top_side\0"), - CursorIcon::NeResize => load(b"top_right_corner\0"), - CursorIcon::NwResize => load(b"top_left_corner\0"), - CursorIcon::SResize => load(b"bottom_side\0"), - CursorIcon::SeResize => load(b"bottom_right_corner\0"), - CursorIcon::SwResize => load(b"bottom_left_corner\0"), - CursorIcon::WResize => load(b"left_side\0"), - CursorIcon::EwResize => load(b"h_double_arrow\0"), - CursorIcon::NsResize => load(b"v_double_arrow\0"), - CursorIcon::NwseResize => loadn(&[b"bd_double_arrow\0", b"size_fdiag\0"]), - CursorIcon::NeswResize => loadn(&[b"fd_double_arrow\0", b"size_bdiag\0"]), - CursorIcon::ColResize => loadn(&[b"split_h\0", b"h_double_arrow\0"]), - CursorIcon::RowResize => loadn(&[b"split_v\0", b"v_double_arrow\0"]), - - CursorIcon::Text => loadn(&[b"text\0", b"xterm\0"]), - CursorIcon::VerticalText => load(b"vertical-text\0"), - - CursorIcon::Wait => load(b"watch\0"), - - CursorIcon::ZoomIn => load(b"zoom-in\0"), - CursorIcon::ZoomOut => load(b"zoom-out\0"), + let name = CString::new(cursor.name()).unwrap(); + unsafe { + (self.xcursor.XcursorLibraryLoadCursor)(self.display, name.as_ptr() as *const c_char) } } diff --git a/src/platform_impl/macos/appkit/cursor.rs b/src/platform_impl/macos/appkit/cursor.rs index 0461b3ac..dd86026c 100644 --- a/src/platform_impl/macos/appkit/cursor.rs +++ b/src/platform_impl/macos/appkit/cursor.rs @@ -197,8 +197,7 @@ impl NSCursor { pub fn from_icon(icon: CursorIcon) -> Id { match icon { CursorIcon::Default => Default::default(), - CursorIcon::Arrow => Self::arrowCursor(), - CursorIcon::Hand => Self::pointingHandCursor(), + CursorIcon::Pointer => Self::pointingHandCursor(), CursorIcon::Grab => Self::openHandCursor(), CursorIcon::Grabbing => Self::closedHandCursor(), CursorIcon::Text => Self::IBeamCursor(), @@ -228,6 +227,7 @@ impl NSCursor { CursorIcon::Wait | CursorIcon::Progress => Self::busyButClickableCursor(), CursorIcon::Move | CursorIcon::AllScroll => Self::moveCursor(), CursorIcon::Cell => Self::cellCursor(), + _ => Default::default(), } } } diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index a46a0b80..55ddf9dc 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -192,47 +192,8 @@ impl Window { #[inline] pub fn set_cursor_icon(&self, cursor: CursorIcon) { - let text = match cursor { - CursorIcon::Default => "auto", - CursorIcon::Crosshair => "crosshair", - CursorIcon::Hand => "pointer", - CursorIcon::Arrow => "default", - CursorIcon::Move => "move", - CursorIcon::Text => "text", - CursorIcon::Wait => "wait", - CursorIcon::Help => "help", - CursorIcon::Progress => "progress", - - CursorIcon::NotAllowed => "not-allowed", - CursorIcon::ContextMenu => "context-menu", - CursorIcon::Cell => "cell", - CursorIcon::VerticalText => "vertical-text", - CursorIcon::Alias => "alias", - CursorIcon::Copy => "copy", - CursorIcon::NoDrop => "no-drop", - CursorIcon::Grab => "grab", - CursorIcon::Grabbing => "grabbing", - CursorIcon::AllScroll => "all-scroll", - CursorIcon::ZoomIn => "zoom-in", - CursorIcon::ZoomOut => "zoom-out", - - CursorIcon::EResize => "e-resize", - CursorIcon::NResize => "n-resize", - CursorIcon::NeResize => "ne-resize", - CursorIcon::NwResize => "nw-resize", - CursorIcon::SResize => "s-resize", - CursorIcon::SeResize => "se-resize", - CursorIcon::SwResize => "sw-resize", - CursorIcon::WResize => "w-resize", - CursorIcon::EwResize => "ew-resize", - CursorIcon::NsResize => "ns-resize", - CursorIcon::NeswResize => "nesw-resize", - CursorIcon::NwseResize => "nwse-resize", - CursorIcon::ColResize => "col-resize", - CursorIcon::RowResize => "row-resize", - }; - *self.previous_pointer.borrow_mut() = text; - backend::set_canvas_style_property(self.canvas.borrow().raw(), "cursor", text); + *self.previous_pointer.borrow_mut() = cursor.name(); + backend::set_canvas_style_property(self.canvas.borrow().raw(), "cursor", cursor.name()); } #[inline] diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 6d5f9d44..55341e2b 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -2026,7 +2026,7 @@ unsafe fn public_window_callback_inner( match set_cursor_to { Some(cursor) => { - let cursor = LoadCursorW(0, cursor.to_windows_cursor()); + let cursor = LoadCursorW(0, util::to_windows_cursor(cursor)); SetCursor(cursor); 0 } diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 35009764..06d2728f 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -164,32 +164,30 @@ pub fn get_instance_handle() -> HINSTANCE { unsafe { &__ImageBase as *const _ as _ } } -impl CursorIcon { - pub(crate) fn to_windows_cursor(self) -> PCWSTR { - match self { - CursorIcon::Arrow | CursorIcon::Default => IDC_ARROW, - CursorIcon::Hand => IDC_HAND, - CursorIcon::Crosshair => IDC_CROSS, - CursorIcon::Text | CursorIcon::VerticalText => IDC_IBEAM, - CursorIcon::NotAllowed | CursorIcon::NoDrop => IDC_NO, - CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => { - IDC_SIZEALL - } - CursorIcon::EResize - | CursorIcon::WResize - | CursorIcon::EwResize - | CursorIcon::ColResize => IDC_SIZEWE, - CursorIcon::NResize - | CursorIcon::SResize - | CursorIcon::NsResize - | CursorIcon::RowResize => IDC_SIZENS, - CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => IDC_SIZENESW, - CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => IDC_SIZENWSE, - CursorIcon::Wait => IDC_WAIT, - CursorIcon::Progress => IDC_APPSTARTING, - CursorIcon::Help => IDC_HELP, - _ => IDC_ARROW, // use arrow for the missing cases. +pub(crate) fn to_windows_cursor(cursor: CursorIcon) -> PCWSTR { + match cursor { + CursorIcon::Default => IDC_ARROW, + CursorIcon::Pointer => IDC_HAND, + CursorIcon::Crosshair => IDC_CROSS, + CursorIcon::Text | CursorIcon::VerticalText => IDC_IBEAM, + CursorIcon::NotAllowed | CursorIcon::NoDrop => IDC_NO, + CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => { + IDC_SIZEALL } + CursorIcon::EResize + | CursorIcon::WResize + | CursorIcon::EwResize + | CursorIcon::ColResize => IDC_SIZEWE, + CursorIcon::NResize + | CursorIcon::SResize + | CursorIcon::NsResize + | CursorIcon::RowResize => IDC_SIZENS, + CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => IDC_SIZENESW, + CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => IDC_SIZENWSE, + CursorIcon::Wait => IDC_WAIT, + CursorIcon::Progress => IDC_APPSTARTING, + CursorIcon::Help => IDC_HELP, + _ => IDC_ARROW, // use arrow for the missing cases. } } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 21fa458e..162b9299 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -333,7 +333,7 @@ impl Window { pub fn set_cursor_icon(&self, cursor: CursorIcon) { self.window_state_lock().mouse.cursor = cursor; self.thread_executor.execute_in_thread(move || unsafe { - let cursor = LoadCursorW(0, cursor.to_windows_cursor()); + let cursor = LoadCursorW(0, util::to_windows_cursor(cursor)); SetCursor(cursor); }); } diff --git a/src/window.rs b/src/window.rs index 50d8cd24..f34d6264 100644 --- a/src/window.rs +++ b/src/window.rs @@ -15,6 +15,9 @@ use crate::{ pub use crate::icon::{BadIcon, Icon}; +#[doc(inline)] +pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError}; + /// Represents a window. /// /// # Example @@ -1388,66 +1391,6 @@ pub enum CursorGrabMode { Locked, } -/// Describes the appearance of the mouse cursor. -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum CursorIcon { - /// The platform-dependent default cursor. - #[default] - Default, - /// A simple crosshair. - Crosshair, - /// A hand (often used to indicate links in web browsers). - Hand, - /// Self explanatory. - Arrow, - /// Indicates something is to be moved. - Move, - /// Indicates text that may be selected or edited. - Text, - /// Program busy indicator. - Wait, - /// Help indicator (often rendered as a "?") - Help, - /// Progress indicator. Shows that processing is being done. But in contrast - /// with "Wait" the user may still interact with the program. Often rendered - /// as a spinning beach ball, or an arrow with a watch or hourglass. - Progress, - - /// Cursor showing that something cannot be done. - NotAllowed, - ContextMenu, - Cell, - VerticalText, - Alias, - Copy, - NoDrop, - /// Indicates something can be grabbed. - Grab, - /// Indicates something is grabbed. - Grabbing, - AllScroll, - ZoomIn, - ZoomOut, - - /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor - /// is used when the movement starts from the south-east corner of the box. - EResize, - NResize, - NeResize, - NwResize, - SResize, - SeResize, - SwResize, - WResize, - EwResize, - NsResize, - NeswResize, - NwseResize, - ColResize, - RowResize, -} - /// Defines the orientation that a window resize will be performed. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ResizeDirection {