From 92aae1cec1b5195beb39413fe73c5fd69477cf8c Mon Sep 17 00:00:00 2001 From: apricotbucket28 <71973804+apricotbucket28@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:59:30 -0300 Subject: [PATCH] x11: Differentiate between mouse and keyboard focus (#13943) Fixes https://github.com/zed-industries/zed/issues/13897 Release Notes: - N/A --- crates/gpui/src/platform/linux/x11/client.rs | 39 ++++++++++++++------ crates/gpui/src/platform/linux/x11/window.rs | 1 + 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 8590defea922c53b60f4754101f9e5f4c6ddec98..83f31a1de93c434d098f3c67a79052fe77ddf9cf 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -115,7 +115,8 @@ pub struct X11ClientState { pub(crate) _resource_database: Database, pub(crate) atoms: XcbAtoms, pub(crate) windows: HashMap, - pub(crate) focused_window: Option, + pub(crate) mouse_focused_window: Option, + pub(crate) keyboard_focused_window: Option, pub(crate) xkb: xkbc::State, pub(crate) ximc: Option>>, pub(crate) xim_handler: Option, @@ -151,7 +152,12 @@ impl X11ClientStatePtr { x_window ); } - + if state.mouse_focused_window == Some(x_window) { + state.mouse_focused_window = None; + } + if state.keyboard_focused_window == Some(x_window) { + state.keyboard_focused_window = None; + } state.cursor_styles.remove(&x_window); if state.windows.is_empty() { @@ -320,7 +326,8 @@ impl X11Client { _resource_database: resource_database, atoms, windows: HashMap::default(), - focused_window: None, + mouse_focused_window: None, + keyboard_focused_window: None, xkb: xkb_state, ximc, xim_handler, @@ -361,7 +368,7 @@ impl X11Client { .push(AttributeName::ClientWindow, xim_handler.window) .push(AttributeName::FocusWindow, xim_handler.window); - let window_id = state.focused_window; + let window_id = state.keyboard_focused_window; drop(state); if let Some(window_id) = window_id { let window = self.get_window(window_id).unwrap(); @@ -558,19 +565,19 @@ impl X11Client { let window = self.get_window(event.window)?; window.refresh(); } - Event::FocusIn(event) => { + Event::FocusIn(event) if event.mode == xproto::NotifyMode::NORMAL => { let window = self.get_window(event.event)?; window.set_focused(true); let mut state = self.0.borrow_mut(); - state.focused_window = Some(event.event); + state.keyboard_focused_window = Some(event.event); drop(state); self.enable_ime(); } - Event::FocusOut(event) => { + Event::FocusOut(event) if event.mode == xproto::NotifyMode::NORMAL => { let window = self.get_window(event.event)?; window.set_focused(false); let mut state = self.0.borrow_mut(); - state.focused_window = None; + state.keyboard_focused_window = None; if let Some(compose_state) = state.compose_state.as_mut() { compose_state.reset(); } @@ -594,7 +601,7 @@ impl X11Client { if state.modifiers == modifiers { drop(state); } else { - let focused_window_id = state.focused_window?; + let focused_window_id = state.keyboard_focused_window?; state.modifiers = modifiers; drop(state); @@ -844,12 +851,18 @@ impl X11Client { valuator_idx += 1; } } + Event::XinputEnter(event) if event.mode == xinput::NotifyMode::NORMAL => { + let window = self.get_window(event.event)?; + window.set_focused(true); + let mut state = self.0.borrow_mut(); + state.mouse_focused_window = Some(event.event); + } Event::XinputLeave(event) if event.mode == xinput::NotifyMode::NORMAL => { self.0.borrow_mut().scroll_x = None; // Set last scroll to `None` so that a large delta isn't created if scrolling is done outside the window (the valuator is global) self.0.borrow_mut().scroll_y = None; - let window = self.get_window(event.event)?; let mut state = self.0.borrow_mut(); + state.mouse_focused_window = None; let pressed_button = pressed_button_from_mask(event.buttons[0]); let position = point( px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor), @@ -859,11 +872,13 @@ impl X11Client { state.modifiers = modifiers; drop(state); + let window = self.get_window(event.event)?; window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent { pressed_button, position, modifiers, })); + window.set_focused(false); } _ => {} }; @@ -1046,7 +1061,7 @@ impl LinuxClient for X11Client { fn set_cursor_style(&self, style: CursorStyle) { let mut state = self.0.borrow_mut(); - let Some(focused_window) = state.focused_window else { + let Some(focused_window) = state.mouse_focused_window else { return; }; let current_style = state @@ -1294,7 +1309,7 @@ impl LinuxClient for X11Client { fn active_window(&self) -> Option { let state = self.0.borrow(); - state.focused_window.and_then(|focused_window| { + state.keyboard_focused_window.and_then(|focused_window| { state .windows .get(&focused_window) diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index d81de2a48e4c48f15a7b0cf280b1b0409155c191..0f97071155bee56dc4c75ef7dbfb8f254690a270 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -450,6 +450,7 @@ impl X11WindowState { xinput::XIEventMask::MOTION | xinput::XIEventMask::BUTTON_PRESS | xinput::XIEventMask::BUTTON_RELEASE + | xinput::XIEventMask::ENTER | xinput::XIEventMask::LEAVE, ], }],