diff --git a/config/src/config.rs b/config/src/config.rs index 5a84f5431..8f52b91e5 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -1444,21 +1444,24 @@ impl Config { } } - pub fn initial_size(&self, dpi: u32) -> TerminalSize { + pub fn initial_size(&self, dpi: u32, cell_pixel_dims: Option<(usize, usize)>) -> TerminalSize { + // If we aren't passed the actual values, guess at a plausible + // default set of pixel dimensions. + // This is based on "typical" 10 point font at "normal" + // pixel density. + // This will get filled in by the gui layer, but there is + // an edge case where we emit an iTerm image escape in + // the software update banner through the mux layer before + // the GUI has had a chance to update the pixel dimensions + // when running under X11. + // This is a bit gross. + let (cell_pixel_width, cell_pixel_height) = cell_pixel_dims.unwrap_or((8, 16)); + TerminalSize { rows: self.initial_rows as usize, cols: self.initial_cols as usize, - // Guess at a plausible default set of pixel dimensions. - // This is based on "typical" 10 point font at "normal" - // pixel density. - // This will get filled in by the gui layer, but there is - // an edge case where we emit an iTerm image escape in - // the software update banner through the mux layer before - // the GUI has had a chance to update the pixel dimensions - // when running under X11. - // This is a bit gross. - pixel_width: 8 * self.initial_cols as usize, - pixel_height: 16 * self.initial_rows as usize, + pixel_width: cell_pixel_width * self.initial_cols as usize, + pixel_height: cell_pixel_height * self.initial_rows as usize, dpi, } } diff --git a/lua-api-crates/mux/src/lib.rs b/lua-api-crates/mux/src/lib.rs index 7ee755f68..b02db3a90 100644 --- a/lua-api-crates/mux/src/lib.rs +++ b/lua-api-crates/mux/src/lib.rs @@ -238,7 +238,7 @@ impl SpawnWindow { cols, ..Default::default() }, - _ => config::configuration().initial_size(0), + _ => config::configuration().initial_size(0, None), }; let (cmd_builder, cwd) = self.cmd_builder.to_command_builder(); @@ -284,7 +284,7 @@ impl SpawnTab { size = window .get_by_idx(0) .map(|tab| tab.get_size()) - .unwrap_or_else(|| config::configuration().initial_size(0)); + .unwrap_or_else(|| config::configuration().initial_size(0, None)); pane = window .get_active() diff --git a/wezterm-gui/src/frontend.rs b/wezterm-gui/src/frontend.rs index bfbe1a7c9..66c61e72a 100644 --- a/wezterm-gui/src/frontend.rs +++ b/wezterm-gui/src/frontend.rs @@ -279,8 +279,9 @@ impl GuiFrontEnd { fn spawn_command(spawn: &SpawnCommand, spawn_where: SpawnWhere) { let config = config::configuration(); - let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()) as u32; - let size = config.initial_size(dpi); + let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()); + let size = + config.initial_size(dpi as u32, crate::cell_pixel_dims(&config, dpi).ok()); let term_config = Arc::new(config::TermConfig::with_config(config)); crate::spawn::spawn_command_impl(spawn, spawn_where, size, None, term_config) diff --git a/wezterm-gui/src/main.rs b/wezterm-gui/src/main.rs index 0a28fafc6..a8a46afe7 100644 --- a/wezterm-gui/src/main.rs +++ b/wezterm-gui/src/main.rs @@ -3,6 +3,7 @@ use crate::customglyph::BlockKey; use crate::glyphcache::GlyphCache; +use crate::utilsprites::RenderMetrics; use ::window::*; use anyhow::{anyhow, Context}; use clap::builder::ValueParser; @@ -28,6 +29,7 @@ use unicode_normalization::UnicodeNormalization; use wezterm_bidi::Direction; use wezterm_client::domain::ClientDomain; use wezterm_font::shaper::PresentationWidth; +use wezterm_font::FontConfiguration; use wezterm_gui_subcommands::*; use wezterm_mux_server_impl::update_mux_domains; use wezterm_toast_notification::*; @@ -328,9 +330,14 @@ async fn spawn_tab_in_domain_if_mux_is_empty( true }); - let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()) as u32; + let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()); let _tab = domain - .spawn(config.initial_size(dpi), cmd, None, window_id) + .spawn( + config.initial_size(dpi as u32, Some(cell_pixel_dims(&config, dpi)?)), + cmd, + None, + window_id, + ) .await?; trigger_and_log_gui_attached(MuxDomain(domain.domain_id())).await; Ok(()) @@ -389,6 +396,15 @@ async fn trigger_and_log_gui_attached(domain: MuxDomain) { } } +fn cell_pixel_dims(config: &ConfigHandle, dpi: f64) -> anyhow::Result<(usize, usize)> { + let fontconfig = Rc::new(FontConfiguration::new(Some(config.clone()), dpi as usize)?); + let render_metrics = RenderMetrics::new(&fontconfig)?; + Ok(( + render_metrics.cell_size.width as usize, + render_metrics.cell_size.height as usize, + )) +} + async fn async_run_terminal_gui( cmd: Option, opts: StartCommand, @@ -456,9 +472,14 @@ async fn async_run_terminal_gui( domain.attach(Some(window_id)).await?; let config = config::configuration(); - let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()) as u32; + let dpi = config.dpi.unwrap_or_else(|| ::window::default_dpi()); let tab = domain - .spawn(config.initial_size(dpi), cmd.clone(), None, window_id) + .spawn( + config.initial_size(dpi as u32, Some(cell_pixel_dims(&config, dpi)?)), + cmd.clone(), + None, + window_id, + ) .await?; let mut window = mux .get_window_mut(window_id) @@ -585,7 +606,7 @@ impl Publish { window_id, command, command_dir: None, - size: config.initial_size(0), + size: config.initial_size(0, None), workspace: workspace.unwrap_or( config .default_workspace diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index 118d8fd2c..870422229 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -2949,7 +2949,15 @@ impl TermWindow { if !have_panes_in_domain { let config = config::configuration(); let _tab = domain - .spawn(config.initial_size(dpi), None, None, window) + .spawn( + config.initial_size( + dpi, + Some(crate::cell_pixel_dims(&config, dpi as f64)?), + ), + None, + None, + window, + ) .await?; } diff --git a/wezterm-gui/src/termwindow/resize.rs b/wezterm-gui/src/termwindow/resize.rs index 4e1aa64d7..a10d52094 100644 --- a/wezterm-gui/src/termwindow/resize.rs +++ b/wezterm-gui/src/termwindow/resize.rs @@ -533,7 +533,13 @@ impl super::TermWindow { } pub fn reset_font_and_window_size(&mut self, window: &Window) -> anyhow::Result<()> { - let size = self.config.initial_size(self.dimensions.dpi as u32); + let size = self.config.initial_size( + self.dimensions.dpi as u32, + Some(crate::cell_pixel_dims( + &self.config, + self.dimensions.dpi as f64, + )?), + ); self.set_window_size(size, window) } diff --git a/wezterm-gui/src/termwindow/spawn.rs b/wezterm-gui/src/termwindow/spawn.rs index 3404190c3..1395afc30 100644 --- a/wezterm-gui/src/termwindow/spawn.rs +++ b/wezterm-gui/src/termwindow/spawn.rs @@ -6,7 +6,10 @@ use std::sync::Arc; impl super::TermWindow { pub fn spawn_command(&self, spawn: &SpawnCommand, spawn_where: SpawnWhere) { let size = if spawn_where == SpawnWhere::NewWindow { - self.config.initial_size(self.dimensions.dpi as u32) + self.config.initial_size( + self.dimensions.dpi as u32, + crate::cell_pixel_dims(&self.config, self.dimensions.dpi as f64).ok(), + ) } else { self.terminal_size }; diff --git a/wezterm-mux-server/src/main.rs b/wezterm-mux-server/src/main.rs index 56dcfe9f2..3f9eac063 100644 --- a/wezterm-mux-server/src/main.rs +++ b/wezterm-mux-server/src/main.rs @@ -291,7 +291,7 @@ async fn async_run(cmd: Option) -> anyhow::Result<()> { let _tab = mux .default_domain() - .spawn(config.initial_size(0), cmd, None, *window_id) + .spawn(config.initial_size(0, None), cmd, None, *window_id) .await?; } Ok(()) diff --git a/wezterm/src/cli/spawn_command.rs b/wezterm/src/cli/spawn_command.rs index dbfb5fe65..0e6e490ca 100644 --- a/wezterm/src/cli/spawn_command.rs +++ b/wezterm/src/cli/spawn_command.rs @@ -94,7 +94,7 @@ impl SpawnCommand { ) .to_string(); - let size = config.initial_size(0); + let size = config.initial_size(0, None); let spawned = client .spawn_v2(codec::SpawnV2 { diff --git a/window/src/os/macos/connection.rs b/window/src/os/macos/connection.rs index 501f61ba4..b5a85d2e1 100644 --- a/window/src/os/macos/connection.rs +++ b/window/src/os/macos/connection.rs @@ -110,6 +110,14 @@ impl ConnectionOps for Connection { } } + fn default_dpi(&self) -> f64 { + if let Ok(screens) = self.screens() { + screens.active.effective_dpi.unwrap_or(crate::DEFAULT_DPI) + } else { + crate::DEFAULT_DPI + } + } + fn terminate_message_loop(&self) { unsafe { // bounce via an event callback to encourage stop to apply diff --git a/window/src/os/macos/window.rs b/window/src/os/macos/window.rs index dac38998b..07eae2f45 100644 --- a/window/src/os/macos/window.rs +++ b/window/src/os/macos/window.rs @@ -452,6 +452,13 @@ impl Window { x, y, } = conn.resolve_geometry(geometry); + + let scale_factor = (conn.default_dpi() / crate::DEFAULT_DPI) as usize; + let width = width / scale_factor; + let height = height / scale_factor; + let x = x.map(|x| x / scale_factor as i32); + let y = y.map(|y| y / scale_factor as i32); + let initial_pos = match (x, y) { (Some(x), Some(y)) => Some(ScreenPoint::new(x as isize, y as isize)), _ => None,