x11: Differentiate between mouse and keyboard focus (#13943)

Fixes https://github.com/zed-industries/zed/issues/13897

Release Notes:

- N/A
This commit is contained in:
apricotbucket28 2024-07-08 16:59:30 -03:00 committed by GitHub
parent 032b203519
commit 75377bbe0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 12 deletions

View file

@ -115,7 +115,8 @@ pub struct X11ClientState {
pub(crate) _resource_database: Database, pub(crate) _resource_database: Database,
pub(crate) atoms: XcbAtoms, pub(crate) atoms: XcbAtoms,
pub(crate) windows: HashMap<xproto::Window, WindowRef>, pub(crate) windows: HashMap<xproto::Window, WindowRef>,
pub(crate) focused_window: Option<xproto::Window>, pub(crate) mouse_focused_window: Option<xproto::Window>,
pub(crate) keyboard_focused_window: Option<xproto::Window>,
pub(crate) xkb: xkbc::State, pub(crate) xkb: xkbc::State,
pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>, pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>,
pub(crate) xim_handler: Option<XimHandler>, pub(crate) xim_handler: Option<XimHandler>,
@ -151,7 +152,12 @@ impl X11ClientStatePtr {
x_window 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); state.cursor_styles.remove(&x_window);
if state.windows.is_empty() { if state.windows.is_empty() {
@ -320,7 +326,8 @@ impl X11Client {
_resource_database: resource_database, _resource_database: resource_database,
atoms, atoms,
windows: HashMap::default(), windows: HashMap::default(),
focused_window: None, mouse_focused_window: None,
keyboard_focused_window: None,
xkb: xkb_state, xkb: xkb_state,
ximc, ximc,
xim_handler, xim_handler,
@ -361,7 +368,7 @@ impl X11Client {
.push(AttributeName::ClientWindow, xim_handler.window) .push(AttributeName::ClientWindow, xim_handler.window)
.push(AttributeName::FocusWindow, xim_handler.window); .push(AttributeName::FocusWindow, xim_handler.window);
let window_id = state.focused_window; let window_id = state.keyboard_focused_window;
drop(state); drop(state);
if let Some(window_id) = window_id { if let Some(window_id) = window_id {
let window = self.get_window(window_id).unwrap(); let window = self.get_window(window_id).unwrap();
@ -558,19 +565,19 @@ impl X11Client {
let window = self.get_window(event.window)?; let window = self.get_window(event.window)?;
window.refresh(); window.refresh();
} }
Event::FocusIn(event) => { Event::FocusIn(event) if event.mode == xproto::NotifyMode::NORMAL => {
let window = self.get_window(event.event)?; let window = self.get_window(event.event)?;
window.set_focused(true); window.set_focused(true);
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.focused_window = Some(event.event); state.keyboard_focused_window = Some(event.event);
drop(state); drop(state);
self.enable_ime(); self.enable_ime();
} }
Event::FocusOut(event) => { Event::FocusOut(event) if event.mode == xproto::NotifyMode::NORMAL => {
let window = self.get_window(event.event)?; let window = self.get_window(event.event)?;
window.set_focused(false); window.set_focused(false);
let mut state = self.0.borrow_mut(); 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() { if let Some(compose_state) = state.compose_state.as_mut() {
compose_state.reset(); compose_state.reset();
} }
@ -594,7 +601,7 @@ impl X11Client {
if state.modifiers == modifiers { if state.modifiers == modifiers {
drop(state); drop(state);
} else { } else {
let focused_window_id = state.focused_window?; let focused_window_id = state.keyboard_focused_window?;
state.modifiers = modifiers; state.modifiers = modifiers;
drop(state); drop(state);
@ -844,12 +851,18 @@ impl X11Client {
valuator_idx += 1; 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 => { 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_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; self.0.borrow_mut().scroll_y = None;
let window = self.get_window(event.event)?;
let mut state = self.0.borrow_mut(); let mut state = self.0.borrow_mut();
state.mouse_focused_window = None;
let pressed_button = pressed_button_from_mask(event.buttons[0]); let pressed_button = pressed_button_from_mask(event.buttons[0]);
let position = point( let position = point(
px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor), px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
@ -859,11 +872,13 @@ impl X11Client {
state.modifiers = modifiers; state.modifiers = modifiers;
drop(state); drop(state);
let window = self.get_window(event.event)?;
window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent { window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent {
pressed_button, pressed_button,
position, position,
modifiers, modifiers,
})); }));
window.set_focused(false);
} }
_ => {} _ => {}
}; };
@ -1046,7 +1061,7 @@ impl LinuxClient for X11Client {
fn set_cursor_style(&self, style: CursorStyle) { fn set_cursor_style(&self, style: CursorStyle) {
let mut state = self.0.borrow_mut(); 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; return;
}; };
let current_style = state let current_style = state
@ -1294,7 +1309,7 @@ impl LinuxClient for X11Client {
fn active_window(&self) -> Option<AnyWindowHandle> { fn active_window(&self) -> Option<AnyWindowHandle> {
let state = self.0.borrow(); let state = self.0.borrow();
state.focused_window.and_then(|focused_window| { state.keyboard_focused_window.and_then(|focused_window| {
state state
.windows .windows
.get(&focused_window) .get(&focused_window)

View file

@ -450,6 +450,7 @@ impl X11WindowState {
xinput::XIEventMask::MOTION xinput::XIEventMask::MOTION
| xinput::XIEventMask::BUTTON_PRESS | xinput::XIEventMask::BUTTON_PRESS
| xinput::XIEventMask::BUTTON_RELEASE | xinput::XIEventMask::BUTTON_RELEASE
| xinput::XIEventMask::ENTER
| xinput::XIEventMask::LEAVE, | xinput::XIEventMask::LEAVE,
], ],
}], }],