mirror of
https://github.com/wez/wezterm.git
synced 2024-12-26 14:54:16 +03:00
Implement SetInnerSizeCompleted events
These are used to signal, after a set_inner_size() call, at what point we can expect any and all of its related Resized events to have already been dispatched. SetInnerSizeCompleted events are currently used to fix a race condition in rescaling the terminal in which the number of cells of the terminal (e.g., 80x24) can change when quickly rescaling the terminal.
This commit is contained in:
parent
2c5fa35986
commit
a0974a2537
@ -56,7 +56,8 @@ impl UserData for GuiWin {
|
||||
methods.add_method(
|
||||
"set_inner_size",
|
||||
|_, this, (width, height): (usize, usize)| {
|
||||
this.window.set_inner_size(width, height);
|
||||
this.window
|
||||
.notify(TermWindowNotif::SetInnerSize { width, height });
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
@ -54,7 +54,7 @@ use mux_lua::MuxPane;
|
||||
use smol::channel::Sender;
|
||||
use smol::Timer;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, LinkedList};
|
||||
use std::ops::Add;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@ -145,6 +145,10 @@ pub enum TermWindowNotif {
|
||||
EmitStatusUpdate,
|
||||
Apply(Box<dyn FnOnce(&mut TermWindow) + Send + Sync>),
|
||||
SwitchToMuxWindow(MuxWindowId),
|
||||
SetInnerSize {
|
||||
width: usize,
|
||||
height: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -365,6 +369,8 @@ pub struct TermWindow {
|
||||
/// Window dimensions and dpi
|
||||
pub dimensions: Dimensions,
|
||||
pub window_state: WindowState,
|
||||
pub resizes_pending: usize,
|
||||
pending_scale_changes: LinkedList<resize::ScaleChange>,
|
||||
/// Terminal dimensions
|
||||
terminal_size: TerminalSize,
|
||||
pub mux_window_id: MuxWindowId,
|
||||
@ -689,6 +695,8 @@ impl TermWindow {
|
||||
render_metrics,
|
||||
dimensions,
|
||||
window_state: WindowState::default(),
|
||||
resizes_pending: 0,
|
||||
pending_scale_changes: LinkedList::new(),
|
||||
terminal_size,
|
||||
render_state,
|
||||
input_map: InputMap::new(&config),
|
||||
@ -944,6 +952,11 @@ impl TermWindow {
|
||||
self.resize(dimensions, window_state, window, live_resizing);
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::SetInnerSizeCompleted => {
|
||||
self.resizes_pending -= 1;
|
||||
self.apply_pending_scale_changes();
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::AdviseModifiersLedStatus(modifiers, leds) => {
|
||||
self.current_modifier_and_leds = (modifiers, leds);
|
||||
self.update_title();
|
||||
@ -1287,11 +1300,21 @@ impl TermWindow {
|
||||
self.update_title();
|
||||
window.invalidate();
|
||||
}
|
||||
TermWindowNotif::SetInnerSize { width, height } => {
|
||||
self.set_inner_size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_inner_size(&mut self, width: usize, height: usize) {
|
||||
if let Some(window) = &self.window {
|
||||
self.resizes_pending += 1;
|
||||
window.set_inner_size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// Take care to remove our panes from the mux, otherwise
|
||||
/// we can leave the mux with no windows but some panes
|
||||
/// and it won't believe that we are empty.
|
||||
@ -2579,21 +2602,9 @@ impl TermWindow {
|
||||
self.activate_tab_relative(*n, false)?;
|
||||
}
|
||||
ActivateLastTab => self.activate_last_tab()?,
|
||||
DecreaseFontSize => {
|
||||
if let Some(w) = window.as_ref() {
|
||||
self.decrease_font_size(w)
|
||||
}
|
||||
}
|
||||
IncreaseFontSize => {
|
||||
if let Some(w) = window.as_ref() {
|
||||
self.increase_font_size(w)
|
||||
}
|
||||
}
|
||||
ResetFontSize => {
|
||||
if let Some(w) = window.as_ref() {
|
||||
self.reset_font_size(w)
|
||||
}
|
||||
}
|
||||
DecreaseFontSize => self.decrease_font_size(),
|
||||
IncreaseFontSize => self.increase_font_size(),
|
||||
ResetFontSize => self.reset_font_size(),
|
||||
ResetFontAndWindowSize => {
|
||||
if let Some(w) = window.as_ref() {
|
||||
self.reset_font_and_window_size(&w)?
|
||||
|
@ -13,6 +13,12 @@ pub struct RowsAndCols {
|
||||
pub cols: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ScaleChange {
|
||||
Absolute(f64),
|
||||
Relative(f64),
|
||||
}
|
||||
|
||||
impl super::TermWindow {
|
||||
pub fn resize(
|
||||
&mut self,
|
||||
@ -64,6 +70,24 @@ impl super::TermWindow {
|
||||
self.emit_window_event("window-resized", None);
|
||||
}
|
||||
|
||||
pub fn apply_pending_scale_changes(&mut self) {
|
||||
while self.resizes_pending == 0 {
|
||||
match self.pending_scale_changes.pop_front() {
|
||||
Some(ScaleChange::Relative(change)) => {
|
||||
if let Some(window) = self.window.as_ref().map(|w| w.clone()) {
|
||||
self.adjust_font_scale(self.fonts.get_font_scale() * change, &window);
|
||||
}
|
||||
}
|
||||
Some(ScaleChange::Absolute(change)) => {
|
||||
if let Some(window) = self.window.as_ref().map(|w| w.clone()) {
|
||||
self.adjust_font_scale(change, &window);
|
||||
}
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_scale_change(&mut self, dimensions: &Dimensions, font_scale: f64) {
|
||||
let config = &self.config;
|
||||
let font_size = config.font_size * font_scale;
|
||||
@ -313,7 +337,7 @@ impl super::TermWindow {
|
||||
// pixel geometry which is considered to be a user-driven resize.
|
||||
// Stashing the dimensions here avoids that misconception.
|
||||
self.dimensions = dims;
|
||||
window.set_inner_size(dims.pixel_width, dims.pixel_height);
|
||||
self.set_inner_size(dims.pixel_width, dims.pixel_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -430,16 +454,22 @@ impl super::TermWindow {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrease_font_size(&mut self, window: &Window) {
|
||||
self.adjust_font_scale(self.fonts.get_font_scale() / 1.1, window);
|
||||
pub fn decrease_font_size(&mut self) {
|
||||
self.pending_scale_changes
|
||||
.push_back(ScaleChange::Relative(1.0 / 1.1));
|
||||
self.apply_pending_scale_changes();
|
||||
}
|
||||
|
||||
pub fn increase_font_size(&mut self, window: &Window) {
|
||||
self.adjust_font_scale(self.fonts.get_font_scale() * 1.1, window);
|
||||
pub fn increase_font_size(&mut self) {
|
||||
self.pending_scale_changes
|
||||
.push_back(ScaleChange::Relative(1.1));
|
||||
self.apply_pending_scale_changes();
|
||||
}
|
||||
|
||||
pub fn reset_font_size(&mut self, window: &Window) {
|
||||
self.adjust_font_scale(1.0, window);
|
||||
pub fn reset_font_size(&mut self) {
|
||||
self.pending_scale_changes
|
||||
.push_back(ScaleChange::Absolute(1.0));
|
||||
self.apply_pending_scale_changes();
|
||||
}
|
||||
|
||||
pub fn set_window_size(&mut self, size: TerminalSize, window: &Window) -> anyhow::Result<()> {
|
||||
|
@ -86,7 +86,8 @@ impl MyWindow {
|
||||
| WindowEvent::DraggedFile(_)
|
||||
| WindowEvent::DroppedFile(_)
|
||||
| WindowEvent::PerformKeyAssignment(_)
|
||||
| WindowEvent::MouseLeave => {}
|
||||
| WindowEvent::MouseLeave
|
||||
| WindowEvent::SetInnerSizeCompleted => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +171,9 @@ pub enum WindowEvent {
|
||||
live_resizing: bool,
|
||||
},
|
||||
|
||||
/// Called when a program-requested set_inner_size() has finished
|
||||
SetInnerSizeCompleted,
|
||||
|
||||
/// Called when the window has been invalidated and needs to
|
||||
/// be repainted
|
||||
NeedRepaint,
|
||||
|
@ -776,6 +776,13 @@ impl WindowOps for Window {
|
||||
fn set_inner_size(&self, width: usize, height: usize) {
|
||||
Connection::with_window_inner(self.id, move |inner| {
|
||||
inner.set_inner_size(width, height);
|
||||
if let Some(window_view) = WindowView::get_this(unsafe { &**inner.view }) {
|
||||
window_view
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.events
|
||||
.dispatch(WindowEvent::SetInnerSizeCompleted);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
@ -976,7 +976,7 @@ impl WaylandWindowInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_inner_size(&mut self, width: usize, height: usize) -> Dimensions {
|
||||
fn set_inner_size(&mut self, width: usize, height: usize) {
|
||||
let pixel_width = width as i32;
|
||||
let pixel_height = height as i32;
|
||||
let surface_width = self.pixels_to_surface(pixel_width) as u32;
|
||||
@ -993,7 +993,7 @@ impl WaylandWindowInner {
|
||||
// apply the synthetic configure event to the inner surfaces
|
||||
self.dispatch_pending_event();
|
||||
|
||||
self.dimensions.clone()
|
||||
self.events.dispatch(WindowEvent::SetInnerSizeCompleted);
|
||||
}
|
||||
|
||||
fn do_paint(&mut self) -> anyhow::Result<()> {
|
||||
|
@ -898,6 +898,10 @@ impl WindowOps for Window {
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER,
|
||||
);
|
||||
wm_paint(hwnd.0, 0, 0, 0);
|
||||
if let Some(inner) = rc_from_hwnd(hwnd.0) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
inner.events.dispatch(WindowEvent::SetInnerSizeCompleted);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::trace!(
|
||||
|
@ -80,6 +80,8 @@ pub(crate) struct XWindowInner {
|
||||
current_mouse_event: Option<MouseEvent>,
|
||||
window_drag_position: Option<ScreenPoint>,
|
||||
dragging: bool,
|
||||
outstanding_configure_requests: usize,
|
||||
pending_finished_resizes: usize,
|
||||
}
|
||||
|
||||
/// <https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm46409506331616>
|
||||
@ -267,6 +269,13 @@ impl XWindowInner {
|
||||
self.events.dispatch(resize);
|
||||
}
|
||||
|
||||
// These SetInnerSizeCompleted events need to be dispatched after the
|
||||
// above Resized events because a resize cannot finish before it occurs.
|
||||
while self.pending_finished_resizes > 0 {
|
||||
self.events.dispatch(WindowEvent::SetInnerSizeCompleted);
|
||||
self.pending_finished_resizes -= 1;
|
||||
}
|
||||
|
||||
if need_paint {
|
||||
if self.paint_throttled {
|
||||
self.invalidated = true;
|
||||
@ -524,6 +533,10 @@ impl XWindowInner {
|
||||
}
|
||||
Event::X(xcb::x::Event::ConfigureNotify(cfg)) => {
|
||||
self.configure_notify("X::ConfigureNotify", cfg.width(), cfg.height())?;
|
||||
if self.outstanding_configure_requests > 0 {
|
||||
self.outstanding_configure_requests -= 1;
|
||||
self.pending_finished_resizes += 1;
|
||||
}
|
||||
}
|
||||
Event::X(xcb::x::Event::KeyPress(key_press)) => {
|
||||
self.copy_and_paste.time = key_press.time();
|
||||
@ -1204,6 +1217,8 @@ impl XWindow {
|
||||
current_mouse_event: None,
|
||||
window_drag_position: None,
|
||||
dragging: false,
|
||||
outstanding_configure_requests: 0,
|
||||
pending_finished_resizes: 0,
|
||||
}))
|
||||
};
|
||||
|
||||
@ -1748,6 +1763,7 @@ impl WindowOps for XWindow {
|
||||
xcb::x::ConfigWindow::Height(height as u32),
|
||||
],
|
||||
});
|
||||
inner.outstanding_configure_requests += 1;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user