linux/x11: Restore differentiation of mouse/keyboard focus (#13995)

This restores https://github.com/zed-industries/zed/pull/13943 which was
reverted in #13974 because it was possible to get in a state where focus
could not be restored on a window.

In this PR there's an additional change: `FocusIn` and `FocusOut` events
are always handled, even if the `event.mode` is not "NORMAL". In my
testing, `alt-tabbing` between windows didn't produce `FocusIn` and
`FocusOut` events when we had that check. Now, with the check removed,
it's possible to switch focus between two windows again with `alt-tab`.


Release Notes:

- N/A

---------

Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Thorsten Ball 2024-07-10 19:54:26 +02:00 committed by GitHub
parent c732865fc5
commit ee623f77c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 127 additions and 17 deletions

View file

@ -211,6 +211,7 @@ pub struct Callbacks {
request_frame: Option<Box<dyn FnMut()>>,
input: Option<Box<dyn FnMut(PlatformInput) -> crate::DispatchEventResult>>,
active_status_change: Option<Box<dyn FnMut(bool)>>,
hovered_status_change: Option<Box<dyn FnMut(bool)>>,
resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
moved: Option<Box<dyn FnMut()>>,
should_close: Option<Box<dyn FnMut() -> bool>>,
@ -238,6 +239,7 @@ pub struct X11WindowState {
maximized_horizontal: bool,
hidden: bool,
active: bool,
hovered: bool,
fullscreen: bool,
client_side_decorations_supported: bool,
decorations: WindowDecorations,
@ -451,6 +453,7 @@ impl X11WindowState {
xinput::XIEventMask::MOTION
| xinput::XIEventMask::BUTTON_PRESS
| xinput::XIEventMask::BUTTON_RELEASE
| xinput::XIEventMask::ENTER
| xinput::XIEventMask::LEAVE,
],
}],
@ -507,6 +510,7 @@ impl X11WindowState {
atoms: *atoms,
input_handler: None,
active: false,
hovered: false,
fullscreen: false,
maximized_vertical: false,
maximized_horizontal: false,
@ -777,6 +781,15 @@ impl X11WindowStatePtr {
state.hidden = true;
}
}
let hovered_window = self
.xcb_connection
.query_pointer(state.x_root_window)
.unwrap()
.reply()
.unwrap()
.child;
self.set_hovered(hovered_window == self.x_window);
}
pub fn close(&self) {
@ -912,12 +925,18 @@ impl X11WindowStatePtr {
}
}
pub fn set_focused(&self, focus: bool) {
pub fn set_active(&self, focus: bool) {
if let Some(ref mut fun) = self.callbacks.borrow_mut().active_status_change {
fun(focus);
}
}
pub fn set_hovered(&self, focus: bool) {
if let Some(ref mut fun) = self.callbacks.borrow_mut().hovered_status_change {
fun(focus);
}
}
pub fn set_appearance(&mut self, appearance: WindowAppearance) {
let mut state = self.state.borrow_mut();
state.appearance = appearance;
@ -1046,6 +1065,10 @@ impl PlatformWindow for X11Window {
self.0.state.borrow().active
}
fn is_hovered(&self) -> bool {
self.0.state.borrow().hovered
}
fn set_title(&mut self, title: &str) {
self.0
.xcb_connection
@ -1162,6 +1185,10 @@ impl PlatformWindow for X11Window {
self.0.callbacks.borrow_mut().active_status_change = Some(callback);
}
fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
self.0.callbacks.borrow_mut().hovered_status_change = Some(callback);
}
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
self.0.callbacks.borrow_mut().resize = Some(callback);
}