1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

x11: coalesce resize and repaint events

The thesis is that some WM's might send a whole bunch of events
that cause us to over draw/over resize.

I'm not convinced that this is a righteous change, but it can't
hurt to try.

refs: #1051
This commit is contained in:
Wez Furlong 2021-08-20 08:41:40 -07:00
parent 3d227d27cc
commit 367797c1ae
2 changed files with 82 additions and 24 deletions

View File

@ -286,7 +286,11 @@ impl XConnection {
loop {
match self.conn.poll_for_queued_event() {
None => return Ok(()),
None => {
self.dispatch_pending_events()?;
self.conn.flush();
return Ok(());
}
Some(event) => self.process_xcb_event_ime(&event)?,
}
self.conn.flush();
@ -327,6 +331,15 @@ impl XConnection {
self.windows.borrow().get(&window_id).map(Arc::clone)
}
fn dispatch_pending_events(&self) -> anyhow::Result<()> {
for window in self.windows.borrow().values() {
let mut inner = window.lock().unwrap();
inner.dispatch_pending_events()?;
}
Ok(())
}
fn process_window_event(
&self,
window_id: xcb::xproto::Window,

View File

@ -69,6 +69,7 @@ pub(crate) struct XWindowInner {
last_cursor_position: Rect,
invalidated: bool,
paint_throttled: bool,
pending: Vec<WindowEvent>,
}
impl Drop for XWindowInner {
@ -129,7 +130,7 @@ impl XWindowInner {
/// it to encompass both. This avoids bloating the list with a series
/// of increasing rectangles when resizing larger or smaller.
fn expose(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
self.events.dispatch(WindowEvent::NeedRepaint);
self.queue_pending(WindowEvent::NeedRepaint);
}
fn do_mouse_event(&mut self, event: MouseEvent) -> anyhow::Result<()> {
@ -163,6 +164,69 @@ impl XWindowInner {
}
}
fn queue_pending(&mut self, event: WindowEvent) {
self.pending.push(event);
}
pub fn dispatch_pending_events(&mut self) -> anyhow::Result<()> {
if self.pending.is_empty() {
return Ok(());
}
let mut need_paint = false;
let mut resize = None;
for event in self.pending.drain(..) {
match event {
WindowEvent::NeedRepaint => {
if need_paint {
log::info!("coalesce a repaint");
}
need_paint = true;
}
e @ WindowEvent::Resized { .. } => {
if resize.is_some() {
log::info!("coalesce a resize");
}
resize.replace(e);
}
e => {
self.events.dispatch(e);
}
}
}
if let Some(resize) = resize.take() {
self.events.dispatch(resize);
}
if need_paint {
if self.paint_throttled {
self.invalidated = true;
} else {
self.invalidated = false;
self.events.dispatch(WindowEvent::NeedRepaint);
self.paint_throttled = true;
let window_id = self.window_id;
promise::spawn::spawn(async move {
// Don't try to paint more frequently than 30 fps
async_io::Timer::after(std::time::Duration::from_millis(1000 / 30)).await;
XConnection::with_window_inner(window_id, |inner| {
inner.paint_throttled = false;
if inner.invalidated {
inner.invalidate();
}
Ok(())
});
})
.detach();
}
}
Ok(())
}
pub fn dispatch_event(&mut self, event: &xcb::GenericEvent) -> anyhow::Result<()> {
let r = event.response_type() & 0x7f;
let conn = self.conn();
@ -195,7 +259,7 @@ impl XWindowInner {
dpi: self.dpi as usize,
};
self.events.dispatch(WindowEvent::Resized {
self.queue_pending(WindowEvent::Resized {
dimensions,
window_state: self.get_window_state().unwrap_or(WindowState::default()),
});
@ -786,6 +850,7 @@ impl XWindow {
last_cursor_position: Rect::default(),
paint_throttled: false,
invalidated: false,
pending: vec![],
}))
};
@ -835,27 +900,7 @@ impl XWindowInner {
}
fn invalidate(&mut self) {
if self.paint_throttled {
self.invalidated = true;
return;
}
self.invalidated = false;
self.events.dispatch(WindowEvent::NeedRepaint);
self.paint_throttled = true;
let window_id = self.window_id;
promise::spawn::spawn(async move {
// Don't try to paint more frequently than 30 fps
async_io::Timer::after(std::time::Duration::from_millis(1000 / 30)).await;
XConnection::with_window_inner(window_id, |inner| {
inner.paint_throttled = false;
if inner.invalidated {
inner.invalidate();
}
Ok(())
});
})
.detach();
self.queue_pending(WindowEvent::NeedRepaint);
}
fn toggle_fullscreen(&mut self) {