1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

x11: try harder to detect missing resize/focus events

This commit:

* Logs atom names in property change events (makes it easier to
  understand user's logs)
* Sets flags in cases where property changes might imply that a
  configure or focus event should have or should be sent
* Adjusts the "unsure about state" logic so that it doesn't just
  trigger on the initial paint, but also on those flags being set

refs: https://github.com/wez/wezterm/issues/1992
This commit is contained in:
Wez Furlong 2022-05-27 08:56:29 -07:00
parent 8f222d9559
commit 03e07ece56
2 changed files with 66 additions and 47 deletions

View File

@ -54,6 +54,7 @@ pub struct XConnection {
pub(crate) ime: RefCell<std::pin::Pin<Box<xcb_imdkit::ImeClient>>>,
pub(crate) ime_process_event_result: RefCell<anyhow::Result<()>>,
pub(crate) has_randr: bool,
pub(crate) atom_names: RefCell<HashMap<Atom, String>>,
}
impl std::ops::Deref for XConnection {
@ -470,6 +471,7 @@ impl XConnection {
ime: RefCell::new(ime),
ime_process_event_result: RefCell::new(Ok(())),
has_randr,
atom_names: RefCell::new(HashMap::new()),
});
{
@ -528,6 +530,21 @@ impl XConnection {
Ok(conn)
}
pub fn atom_name(&self, atom: Atom) -> String {
if let Some(name) = self.atom_names.borrow().get(&atom) {
return name.to_string();
}
let cookie = self.conn.send_request(&xcb::x::GetAtomName { atom });
let name = if let Ok(reply) = self.conn.wait_for_reply(cookie) {
reply.name().to_string()
} else {
format!("{:?}", atom)
};
self.atom_names.borrow_mut().insert(atom, name.to_string());
name
}
pub fn conn(&self) -> &xcb::Connection {
&self.conn
}

View File

@ -68,6 +68,7 @@ pub(crate) struct XWindowInner {
appearance: Appearance,
title: String,
has_focus: Option<bool>,
verify_focus: bool,
last_cursor_position: Rect,
invalidated: bool,
paint_throttled: bool,
@ -215,29 +216,26 @@ impl XWindowInner {
} else {
self.invalidated = false;
if self.has_focus.is_none() {
log::trace!(
"About to paint, but we've never received a FOCUS_IN/FOCUS_OUT \
event; querying WM to determine focus state"
);
if self.verify_focus || self.has_focus.is_none() {
log::trace!("About to paint, but we're unsure about focus; querying!");
let focus = self
.conn()
.wait_for_reply(self.conn().send_request(&xcb::x::GetInputFocus {}))?;
let focused = focus.focus() == self.window_id;
log::trace!("Do I have focus? {}", focused);
self.has_focus.replace(focused);
self.events.dispatch(WindowEvent::FocusChanged(focused));
if Some(focused) != self.has_focus {
self.has_focus.replace(focused);
self.events.dispatch(WindowEvent::FocusChanged(focused));
}
self.verify_focus = false;
}
if !self.dispatched_any_resize {
self.dispatched_any_resize = true;
log::trace!(
"About to paint, but we've never dispatched a Resized \
event, and thus never received a CONFIGURE_NOTIFY; \
querying WM for geometry"
);
log::trace!("About to paint, but we've unsure about geometry; querying!");
let geom = self.conn().wait_for_reply(self.conn().send_request(
&xcb::x::GetGeometry {
drawable: xcb::x::Drawable::Window(self.window_id),
@ -251,18 +249,20 @@ impl XWindowInner {
self.height
);
self.width = geom.width();
self.height = geom.height();
if self.width != geom.width() || self.height != geom.height() {
self.width = geom.width();
self.height = geom.height();
self.events.dispatch(WindowEvent::Resized {
dimensions: Dimensions {
pixel_width: self.width as usize,
pixel_height: self.height as usize,
dpi: self.dpi as usize,
},
window_state: self.get_window_state().unwrap_or(WindowState::default()),
live_resizing: false,
});
self.events.dispatch(WindowEvent::Resized {
dimensions: Dimensions {
pixel_width: self.width as usize,
pixel_height: self.height as usize,
dpi: self.dpi as usize,
},
window_state: self.get_window_state().unwrap_or(WindowState::default()),
live_resizing: false,
});
}
}
self.events.dispatch(WindowEvent::NeedRepaint);
@ -363,7 +363,10 @@ impl XWindowInner {
if width == self.width && height == self.height && dpi == self.dpi {
// Effectively unchanged; perhaps it was simply moved?
// Do nothing!
log::trace!("Ignoring CONFIGURE_NOTIFY because width,height,dpi are unchanged");
log::trace!(
"Ignoring CONFIGURE_NOTIFY ({width}x{height} dpi={dpi}) \
because width,height,dpi are unchanged"
);
return Ok(());
}
@ -470,22 +473,8 @@ impl XWindowInner {
self.selection_notify(e)?;
}
Event::X(xcb::x::Event::PropertyNotify(msg)) => {
/*
if let Ok(reply) = xcb::x::get_atom_name(&conn, msg.atom()).get_reply() {
log::info!(
"PropertyNotifyEvent atom={} {} xsel={}",
msg.atom(),
reply.name(),
conn.atom_xsel_data
);
}
*/
log::trace!(
"PropertyNotifyEvent atom={:?} xsel={:?}",
msg.atom(),
conn.atom_xsel_data
);
let atom_name = conn.atom_name(msg.atom());
log::trace!("PropertyNotifyEvent {atom_name}");
if msg.atom() == conn.atom_gtk_edge_constraints {
// "_GTK_EDGE_CONSTRAINTS" property is changed when the
@ -501,17 +490,29 @@ impl XWindowInner {
.dispatch(WindowEvent::AppearanceChanged(appearance));
}
}
if msg.atom() == conn.atom_net_wm_state {
// Change in window state should be accompanied by
// a Configure Notify but not all WMs send these
// events consistently/at all/in the same order.
self.dispatched_any_resize = false;
self.verify_focus = true;
}
}
Event::X(xcb::x::Event::FocusIn(_)) => {
self.has_focus.replace(true);
self.update_ime_position();
log::trace!("Calling focus_change(true)");
self.events.dispatch(WindowEvent::FocusChanged(true));
if self.has_focus != Some(true) {
self.has_focus.replace(true);
self.update_ime_position();
log::trace!("Calling focus_change(true)");
self.events.dispatch(WindowEvent::FocusChanged(true));
}
}
Event::X(xcb::x::Event::FocusOut(_)) => {
self.has_focus.replace(false);
log::trace!("Calling focus_change(false)");
self.events.dispatch(WindowEvent::FocusChanged(false));
if self.has_focus != Some(false) {
self.has_focus.replace(false);
log::trace!("Calling focus_change(false)");
self.events.dispatch(WindowEvent::FocusChanged(false));
}
}
Event::X(xcb::x::Event::LeaveNotify(_)) => {
self.events.dispatch(WindowEvent::MouseLeave);
@ -969,6 +970,7 @@ impl XWindow {
cursors: CursorInfo::new(&config, &conn),
config: config.clone(),
has_focus: None,
verify_focus: true,
last_cursor_position: Rect::default(),
paint_throttled: false,
invalidated: false,