Skip to content

Commit

Permalink
gpui: Implement hover for Windows (#20894)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatinAniss authored Nov 28, 2024
1 parent 301a890 commit 4a96db0
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
38 changes: 37 additions & 1 deletion crates/gpui/src/platform/windows/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use windows::Win32::{
Graphics::Gdi::*,
System::SystemServices::*,
UI::{
Controls::*,
HiDpi::*,
Input::{Ime::*, KeyboardAndMouse::*},
WindowsAndMessaging::*,
Expand Down Expand Up @@ -43,7 +44,8 @@ pub(crate) fn handle_msg(
WM_PAINT => handle_paint_msg(handle, state_ptr),
WM_CLOSE => handle_close_msg(state_ptr),
WM_DESTROY => handle_destroy_msg(handle, state_ptr),
WM_MOUSEMOVE => handle_mouse_move_msg(lparam, wparam, state_ptr),
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_NCLBUTTONDOWN => {
handle_nc_mouse_down_msg(handle, MouseButton::Left, wparam, lparam, state_ptr)
Expand Down Expand Up @@ -234,10 +236,32 @@ fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Opt
}

fn handle_mouse_move_msg(
handle: HWND,
lparam: LPARAM,
wparam: WPARAM,
state_ptr: Rc<WindowsWindowStatePtr>,
) -> Option<isize> {
let mut lock = state_ptr.state.borrow_mut();
if !lock.hovered {
lock.hovered = true;
unsafe {
TrackMouseEvent(&mut TRACKMOUSEEVENT {
cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
dwFlags: TME_LEAVE,
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;
Expand Down Expand Up @@ -272,6 +296,18 @@ fn handle_mouse_move_msg(
Some(1)
}

fn handle_mouse_leave_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
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_syskeydown_msg(
wparam: WPARAM,
lparam: LPARAM,
Expand Down
11 changes: 8 additions & 3 deletions crates/gpui/src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct WindowsWindowState {
pub callbacks: Callbacks,
pub input_handler: Option<PlatformInputHandler>,
pub system_key_handled: bool,
pub hovered: bool,

pub renderer: BladeRenderer,

Expand Down Expand Up @@ -95,6 +96,7 @@ impl WindowsWindowState {
let callbacks = Callbacks::default();
let input_handler = None;
let system_key_handled = false;
let hovered = false;
let click_state = ClickState::new();
let system_settings = WindowsSystemSettings::new(display);
let nc_button_pressed = None;
Expand All @@ -110,6 +112,7 @@ impl WindowsWindowState {
callbacks,
input_handler,
system_key_handled,
hovered,
renderer,
click_state,
system_settings,
Expand Down Expand Up @@ -326,6 +329,7 @@ pub(crate) struct Callbacks {
pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>,
pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
pub(crate) moved: Option<Box<dyn FnMut()>>,
pub(crate) should_close: Option<Box<dyn FnMut() -> bool>>,
Expand Down Expand Up @@ -635,9 +639,8 @@ impl PlatformWindow for WindowsWindow {
self.0.hwnd == unsafe { GetActiveWindow() }
}

// is_hovered is unused on Windows. See WindowContext::is_window_hovered.
fn is_hovered(&self) -> bool {
false
self.0.state.borrow().hovered
}

fn set_title(&mut self, title: &str) {
Expand Down Expand Up @@ -728,7 +731,9 @@ impl PlatformWindow for WindowsWindow {
self.0.state.borrow_mut().callbacks.active_status_change = Some(callback);
}

fn on_hover_status_change(&self, _: Box<dyn FnMut(bool)>) {}
fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
self.0.state.borrow_mut().callbacks.hovered_status_change = Some(callback);
}

fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
self.0.state.borrow_mut().callbacks.resize = Some(callback);
Expand Down
6 changes: 5 additions & 1 deletion crates/gpui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,11 @@ impl<'a> WindowContext<'a> {
/// that currently owns the mouse cursor.
/// On mac, this is equivalent to `is_window_active`.
pub fn is_window_hovered(&self) -> bool {
if cfg!(any(target_os = "linux", target_os = "freebsd")) {
if cfg!(any(
target_os = "windows",
target_os = "linux",
target_os = "freebsd"
)) {
self.window.hovered.get()
} else {
self.is_window_active()
Expand Down

0 comments on commit 4a96db0

Please sign in to comment.