From 5361a4d72dfe8f286581896e9aa7feb232672493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=B1=B1=E9=A2=A8=E9=9C=B2?= Date: Tue, 26 Mar 2024 02:06:52 +0900 Subject: [PATCH] Windows: Better cursor (#9451) Moved `SetCursor` calls to `WM_SETCURSOR`, which occurs when OS is requires set cursor. Release Notes: - N/A --- crates/gpui/src/platform/windows/platform.rs | 32 +++-------------- crates/gpui/src/platform/windows/util.rs | 37 +++++++++++++++++++- crates/gpui/src/platform/windows/window.rs | 20 ++++++++++- 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index cdcfb56234305ea4b93c1951ce0d31f113758dbc..ef1140081ff6e1d72a0dad465c23d05eaea9a36b 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -62,6 +62,8 @@ pub(crate) struct WindowsPlatformInner { pub(crate) dispatch_event: OwnedHandle, pub(crate) settings: RefCell, pub icon: HICON, + // NOTE: standard cursor handles don't need to close. + pub(crate) current_cursor: Cell, } impl WindowsPlatformInner { @@ -157,6 +159,7 @@ impl WindowsPlatform { let raw_window_handles = RwLock::new(SmallVec::new()); let settings = RefCell::new(WindowsPlatformSystemSettings::new()); let icon = load_icon().unwrap_or_default(); + let current_cursor = Cell::new(load_cursor(CursorStyle::Arrow)); let inner = Rc::new(WindowsPlatformInner { background_executor, foreground_executor, @@ -167,6 +170,7 @@ impl WindowsPlatform { dispatch_event, settings, icon, + current_cursor, }); Self { inner } } @@ -646,29 +650,7 @@ impl Platform for WindowsPlatform { } fn set_cursor_style(&self, style: CursorStyle) { - let handle = match style { - CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => unsafe { - load_cursor(IDC_IBEAM) - }, - CursorStyle::Crosshair => unsafe { load_cursor(IDC_CROSS) }, - CursorStyle::PointingHand | CursorStyle::DragLink => unsafe { load_cursor(IDC_HAND) }, - CursorStyle::ResizeLeft | CursorStyle::ResizeRight | CursorStyle::ResizeLeftRight => unsafe { - load_cursor(IDC_SIZEWE) - }, - CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown => unsafe { - load_cursor(IDC_SIZENS) - }, - CursorStyle::OperationNotAllowed => unsafe { load_cursor(IDC_NO) }, - _ => unsafe { load_cursor(IDC_ARROW) }, - }; - if handle.is_err() { - log::error!( - "Error loading cursor image: {}", - std::io::Error::last_os_error() - ); - return; - } - let _ = unsafe { SetCursor(HCURSOR(handle.unwrap().0)) }; + self.inner.current_cursor.set(load_cursor(style)); } // todo(windows) @@ -773,10 +755,6 @@ impl Drop for WindowsPlatform { } } -unsafe fn load_cursor(name: PCWSTR) -> Result { - LoadImageW(None, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED).map_err(|e| anyhow!(e)) -} - fn open_target(target: &str) { unsafe { let ret = ShellExecuteW( diff --git a/crates/gpui/src/platform/windows/util.rs b/crates/gpui/src/platform/windows/util.rs index d534f4e3370b1c07baaf7db4d50638e20527fb8f..5cb5c6c64e21cbe7e212b82dad823ed46948791d 100644 --- a/crates/gpui/src/platform/windows/util.rs +++ b/crates/gpui/src/platform/windows/util.rs @@ -1,6 +1,10 @@ -use util::ResultExt; +use std::sync::OnceLock; + +use ::util::ResultExt; use windows::Win32::{Foundation::*, System::Threading::*, UI::WindowsAndMessaging::*}; +use crate::*; + pub(crate) trait HiLoWord { fn hiword(&self) -> u16; fn loword(&self) -> u16; @@ -100,3 +104,34 @@ pub(crate) fn create_event() -> windows::core::Result { pub(crate) fn windows_credentials_target_name(url: &str) -> String { format!("zed:url={}", url) } + +pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR { + static ARROW: OnceLock = OnceLock::new(); + static IBEAM: OnceLock = OnceLock::new(); + static CROSS: OnceLock = OnceLock::new(); + static HAND: OnceLock = OnceLock::new(); + static SIZEWE: OnceLock = OnceLock::new(); + static SIZENS: OnceLock = OnceLock::new(); + static NO: OnceLock = OnceLock::new(); + let (lock, name) = match style { + CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => (&IBEAM, IDC_IBEAM), + CursorStyle::Crosshair => (&CROSS, IDC_CROSS), + CursorStyle::PointingHand | CursorStyle::DragLink => (&HAND, IDC_HAND), + CursorStyle::ResizeLeft | CursorStyle::ResizeRight | CursorStyle::ResizeLeftRight => { + (&SIZEWE, IDC_SIZEWE) + } + CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown => { + (&SIZENS, IDC_SIZENS) + } + CursorStyle::OperationNotAllowed => (&NO, IDC_NO), + _ => (&ARROW, IDC_ARROW), + }; + *lock.get_or_init(|| { + HCURSOR( + unsafe { LoadImageW(None, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) } + .log_err() + .unwrap_or_default() + .0, + ) + }) +} diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index fdd000337ac57ac9c47069463e3cb26eca51443c..b2cb7c330c85a03ef292916aac03def9277268c6 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -228,6 +228,7 @@ impl WindowsWindowInner { WM_IME_STARTCOMPOSITION => self.handle_ime_position(), WM_IME_COMPOSITION => self.handle_ime_composition(lparam), WM_IME_CHAR => self.handle_ime_char(wparam), + WM_SETCURSOR => self.handle_set_cursor(lparam), _ => None, }; if let Some(n) = handled { @@ -1071,6 +1072,24 @@ impl WindowsWindowInner { None } + + fn handle_set_cursor(&self, lparam: LPARAM) -> Option { + if matches!( + lparam.loword() as u32, + HTLEFT + | HTRIGHT + | HTTOP + | HTTOPLEFT + | HTTOPRIGHT + | HTBOTTOM + | HTBOTTOMLEFT + | HTBOTTOMRIGHT + ) { + return None; + } + unsafe { SetCursor(self.platform_inner.current_cursor.get()) }; + Some(1) + } } #[derive(Default)] @@ -1572,7 +1591,6 @@ fn register_wnd_class(icon_handle: HICON) -> PCWSTR { let wc = WNDCLASSW { lpfnWndProc: Some(wnd_proc), hIcon: icon_handle, - hCursor: unsafe { LoadCursorW(None, IDC_ARROW).ok().unwrap() }, lpszClassName: PCWSTR(CLASS_NAME.as_ptr()), style: CS_HREDRAW | CS_VREDRAW, ..Default::default()