gpui: Implement hover for Windows (#20894)
This commit is contained in:
@@ -7,6 +7,7 @@ use windows::Win32::{
|
||||
Graphics::Gdi::*,
|
||||
System::SystemServices::*,
|
||||
UI::{
|
||||
Controls::*,
|
||||
HiDpi::*,
|
||||
Input::{Ime::*, KeyboardAndMouse::*},
|
||||
WindowsAndMessaging::*,
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
@@ -110,6 +112,7 @@ impl WindowsWindowState {
|
||||
callbacks,
|
||||
input_handler,
|
||||
system_key_handled,
|
||||
hovered,
|
||||
renderer,
|
||||
click_state,
|
||||
system_settings,
|
||||
@@ -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>>,
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user