From 71a0eb3b13fa6085022e87c73a4ac0ce5c117a23 Mon Sep 17 00:00:00 2001 From: tims <0xtimsb@gmail.com> Date: Sat, 4 Jan 2025 05:31:29 +0530 Subject: [PATCH] windows: Fix cursor style not changing when hovering over items in the title bar (#22580) Closes #22578 Currently, the `hovered` boolean in the window state is only updated by the `WM_MOUSELEAVE` event, which fires when the mouse cursor leaves the window's working area. This means that when the user moves the cursor from the window to the title bar, `hovered` is set to `false`. Later in the code, this flag is used to determine the cursor style and check if the cursor is over the correct window. The `hovered` boolean should remain active even when the mouse is over non-client items, such as the title bar or window borders. This PR fixes that by using `WM_NCMOUSELEAVE` event, which is triggered when the mouse leaves non-client items. This event is used to update the `hovered` boolean accordingly. Now, `hovered` is `true` when the mouse is over the window's working area, as well as non-client areas like the title bar. More context: - Existing: `dwFlags: TME_LEAVE` tracks window area mouse leaves, which is used in `handle_mouse_move_msg` func. - New: `dwFlags: TME_LEAVE | TME_NONCLIENT` tracks non-client mouse leaves, which is used in `handle_nc_mouse_move_msg` func. Preview: https://github.com/user-attachments/assets/b319303f-81b9-45cb-bf0c-535a59b96561 Release Notes: - Fix cursor style not changing on hover over items in the title bar on Windows --- crates/gpui/src/platform/windows/events.rs | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index f5313a39b0..efaf7a148a 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -47,6 +47,7 @@ pub(crate) fn handle_msg( WM_MOUSEMOVE => handle_mouse_move_msg(handle, lparam, wparam, state_ptr), WM_MOUSELEAVE => handle_mouse_leave_msg(state_ptr), WM_NCMOUSEMOVE => handle_nc_mouse_move_msg(handle, lparam, state_ptr), + WM_NCMOUSELEAVE => handle_nc_mouse_leave_msg(state_ptr), WM_NCLBUTTONDOWN => { handle_nc_mouse_down_msg(handle, MouseButton::Left, wparam, lparam, state_ptr) } @@ -314,6 +315,18 @@ fn handle_mouse_move_msg( Some(1) } +fn handle_nc_mouse_leave_msg(state_ptr: Rc) -> Option { + let mut lock = state_ptr.state.borrow_mut(); + lock.hovered = false; + if let Some(mut callback) = lock.callbacks.hovered_status_change.take() { + drop(lock); + callback(false); + state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback); + } + + Some(0) +} + fn handle_mouse_leave_msg(state_ptr: Rc) -> Option { let mut lock = state_ptr.state.borrow_mut(); lock.hovered = false; @@ -971,6 +984,27 @@ fn handle_nc_mouse_move_msg( return None; } + let mut lock = state_ptr.state.borrow_mut(); + if !lock.hovered { + lock.hovered = true; + unsafe { + TrackMouseEvent(&mut TRACKMOUSEEVENT { + cbSize: std::mem::size_of::() as u32, + dwFlags: TME_LEAVE | TME_NONCLIENT, + hwndTrack: handle, + dwHoverTime: HOVER_DEFAULT, + }) + .log_err() + }; + if let Some(mut callback) = lock.callbacks.hovered_status_change.take() { + drop(lock); + callback(true); + state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback); + } + } else { + drop(lock); + } + let mut lock = state_ptr.state.borrow_mut(); if let Some(mut callback) = lock.callbacks.input.take() { let scale_factor = lock.scale_factor;