diff options
Diffstat (limited to 'alacritty/src/display.rs')
-rw-r--r-- | alacritty/src/display.rs | 794 |
1 files changed, 0 insertions, 794 deletions
diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs deleted file mode 100644 index 5e885b53..00000000 --- a/alacritty/src/display.rs +++ /dev/null @@ -1,794 +0,0 @@ -//! The display subsystem including window management, font rasterization, and -//! GPU drawing. - -use std::cmp::min; -use std::f64; -use std::fmt::{self, Formatter}; -#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] -use std::sync::atomic::Ordering; -use std::time::Instant; - -use glutin::dpi::{PhysicalPosition, PhysicalSize}; -use glutin::event::ModifiersState; -use glutin::event_loop::EventLoop; -#[cfg(not(any(target_os = "macos", windows)))] -use glutin::platform::unix::EventLoopWindowTargetExtUnix; -use glutin::window::CursorIcon; -use log::{debug, info}; -use parking_lot::MutexGuard; -use unicode_width::UnicodeWidthChar; -#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] -use wayland_client::{Display as WaylandDisplay, EventQueue}; - -use crossfont::{self, Rasterize, Rasterizer}; - -use alacritty_terminal::event::{EventListener, OnResize}; -use alacritty_terminal::grid::Dimensions as _; -use alacritty_terminal::index::{Column, Direction, Line, Point}; -use alacritty_terminal::selection::Selection; -use alacritty_terminal::term::{SizeInfo, Term, TermMode, MIN_COLS, MIN_SCREEN_LINES}; - -use crate::config::font::Font; -use crate::config::window::Dimensions; -#[cfg(not(windows))] -use crate::config::window::StartupMode; -use crate::config::Config; -use crate::cursor::IntoRects; -use crate::event::{Mouse, SearchState}; -use crate::message_bar::{MessageBuffer, MessageType}; -use crate::meter::Meter; -use crate::renderer::rects::{RenderLines, RenderRect}; -use crate::renderer::{self, GlyphCache, QuadRenderer}; -use crate::url::{Url, Urls}; -use crate::window::{self, Window}; - -const FORWARD_SEARCH_LABEL: &str = "Search: "; -const BACKWARD_SEARCH_LABEL: &str = "Backward Search: "; - -#[derive(Debug)] -pub enum Error { - /// Error with window management. - Window(window::Error), - - /// Error dealing with fonts. - Font(crossfont::Error), - - /// Error in renderer. - Render(renderer::Error), - - /// Error during buffer swap. - ContextError(glutin::ContextError), -} - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::Window(err) => err.source(), - Error::Font(err) => err.source(), - Error::Render(err) => err.source(), - Error::ContextError(err) => err.source(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Error::Window(err) => err.fmt(f), - Error::Font(err) => err.fmt(f), - Error::Render(err) => err.fmt(f), - Error::ContextError(err) => err.fmt(f), - } - } -} - -impl From<window::Error> for Error { - fn from(val: window::Error) -> Self { - Error::Window(val) - } -} - -impl From<crossfont::Error> for Error { - fn from(val: crossfont::Error) -> Self { - Error::Font(val) - } -} - -impl From<renderer::Error> for Error { - fn from(val: renderer::Error) -> Self { - Error::Render(val) - } -} - -impl From<glutin::ContextError> for Error { - fn from(val: glutin::ContextError) -> Self { - Error::ContextError(val) - } -} - -#[derive(Default, Clone, Debug, PartialEq)] -pub struct DisplayUpdate { - pub dirty: bool, - - dimensions: Option<PhysicalSize<u32>>, - cursor_dirty: bool, - font: Option<Font>, -} - -impl DisplayUpdate { - pub fn dimensions(&self) -> Option<PhysicalSize<u32>> { - self.dimensions - } - - pub fn font(&self) -> Option<&Font> { - self.font.as_ref() - } - - pub fn cursor_dirty(&self) -> bool { - self.cursor_dirty - } - - pub fn set_dimensions(&mut self, dimensions: PhysicalSize<u32>) { - self.dimensions = Some(dimensions); - self.dirty = true; - } - - pub fn set_font(&mut self, font: Font) { - self.font = Some(font); - self.dirty = true; - } - - pub fn set_cursor_dirty(&mut self) { - self.cursor_dirty = true; - self.dirty = true; - } -} - -/// The display wraps a window, font rasterizer, and GPU renderer. -pub struct Display { - pub size_info: SizeInfo, - pub window: Window, - pub urls: Urls, - - /// Currently highlighted URL. - pub highlighted_url: Option<Url>, - - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - pub wayland_event_queue: Option<EventQueue>, - - #[cfg(not(any(target_os = "macos", windows)))] - pub is_x11: bool, - - /// UI cursor visibility for blinking. - pub cursor_hidden: bool, - - renderer: QuadRenderer, - glyph_cache: GlyphCache, - meter: Meter, -} - -impl Display { - pub fn new<E>(config: &Config, event_loop: &EventLoop<E>) -> Result<Display, Error> { - // Guess DPR based on first monitor. - let estimated_dpr = - event_loop.available_monitors().next().map(|m| m.scale_factor()).unwrap_or(1.); - - // Guess the target window dimensions. - let metrics = GlyphCache::static_metrics(config.ui_config.font.clone(), estimated_dpr)?; - let (cell_width, cell_height) = compute_cell_size(config, &metrics); - - // Guess the target window size if the user has specified the number of lines/columns. - let dimensions = config.ui_config.window.dimensions(); - let estimated_size = dimensions.map(|dimensions| { - window_size(config, dimensions, cell_width, cell_height, estimated_dpr) - }); - - debug!("Estimated DPR: {}", estimated_dpr); - debug!("Estimated window size: {:?}", estimated_size); - debug!("Estimated cell size: {} x {}", cell_width, cell_height); - - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - let mut wayland_event_queue = None; - - // Initialize Wayland event queue, to handle Wayland callbacks. - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - if let Some(display) = event_loop.wayland_display() { - let display = unsafe { WaylandDisplay::from_external_display(display as _) }; - wayland_event_queue = Some(display.create_event_queue()); - } - - // Spawn the Alacritty window. - let mut window = Window::new( - event_loop, - &config, - estimated_size, - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - wayland_event_queue.as_ref(), - )?; - - info!("Device pixel ratio: {}", window.dpr); - - // Create renderer. - let mut renderer = QuadRenderer::new()?; - - let (glyph_cache, cell_width, cell_height) = - Self::new_glyph_cache(window.dpr, &mut renderer, config)?; - - if let Some(dimensions) = dimensions { - if (estimated_dpr - window.dpr).abs() < f64::EPSILON { - info!("Estimated DPR correctly, skipping resize"); - } else { - // Resize the window again if the DPR was not estimated correctly. - let size = window_size(config, dimensions, cell_width, cell_height, window.dpr); - window.set_inner_size(size); - } - } - - let padding = config.ui_config.window.padding(window.dpr); - let viewport_size = window.inner_size(); - - // Create new size with at least one column and row. - let size_info = SizeInfo::new( - viewport_size.width as f32, - viewport_size.height as f32, - cell_width, - cell_height, - padding.0, - padding.1, - config.ui_config.window.dynamic_padding && dimensions.is_none(), - ); - - info!("Cell size: {} x {}", cell_width, cell_height); - info!("Padding: {} x {}", size_info.padding_x(), size_info.padding_y()); - info!("Width: {}, Height: {}", size_info.width(), size_info.height()); - - // Update OpenGL projection. - renderer.resize(&size_info); - - // Clear screen. - let background_color = config.colors.primary.background; - renderer.with_api(&config.ui_config, &size_info, |api| { - api.clear(background_color); - }); - - // Set subpixel anti-aliasing. - #[cfg(target_os = "macos")] - crossfont::set_font_smoothing(config.ui_config.font.use_thin_strokes); - - // Disable shadows for transparent windows on macOS. - #[cfg(target_os = "macos")] - window.set_has_shadow(config.ui_config.background_opacity() >= 1.0); - - #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] - let is_x11 = event_loop.is_x11(); - #[cfg(not(any(feature = "x11", target_os = "macos", windows)))] - let is_x11 = false; - - // On Wayland we can safely ignore this call, since the window isn't visible until you - // actually draw something into it and commit those changes. - #[cfg(not(any(target_os = "macos", windows)))] - if is_x11 { - window.swap_buffers(); - renderer.with_api(&config.ui_config, &size_info, |api| { - api.finish(); - }); - } - - window.set_visible(true); - - // Set window position. - // - // TODO: replace `set_position` with `with_position` once available. - // Upstream issue: https://github.com/rust-windowing/winit/issues/806. - if let Some(position) = config.ui_config.window.position { - window.set_outer_position(PhysicalPosition::from((position.x, position.y))); - } - - #[allow(clippy::single_match)] - #[cfg(not(windows))] - match config.ui_config.window.startup_mode { - #[cfg(target_os = "macos")] - StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true), - #[cfg(not(target_os = "macos"))] - StartupMode::Maximized if is_x11 => window.set_maximized(true), - _ => (), - } - - Ok(Self { - window, - renderer, - glyph_cache, - meter: Meter::new(), - size_info, - urls: Urls::new(), - highlighted_url: None, - #[cfg(not(any(target_os = "macos", windows)))] - is_x11, - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - wayland_event_queue, - cursor_hidden: false, - }) - } - - fn new_glyph_cache( - dpr: f64, - renderer: &mut QuadRenderer, - config: &Config, - ) -> Result<(GlyphCache, f32, f32), Error> { - let font = config.ui_config.font.clone(); - let rasterizer = Rasterizer::new(dpr as f32, config.ui_config.font.use_thin_strokes)?; - - // Initialize glyph cache. - let glyph_cache = { - info!("Initializing glyph cache..."); - let init_start = Instant::now(); - - let cache = - renderer.with_loader(|mut api| GlyphCache::new(rasterizer, &font, &mut api))?; - - let stop = init_start.elapsed(); - let stop_f = stop.as_secs() as f64 + f64::from(stop.subsec_nanos()) / 1_000_000_000f64; - info!("... finished initializing glyph cache in {}s", stop_f); - - cache - }; - - // Need font metrics to resize the window properly. This suggests to me the - // font metrics should be computed before creating the window in the first - // place so that a resize is not needed. - let (cw, ch) = compute_cell_size(config, &glyph_cache.font_metrics()); - - Ok((glyph_cache, cw, ch)) - } - - /// Update font size and cell dimensions. - /// - /// This will return a tuple of the cell width and height. - fn update_glyph_cache(&mut self, config: &Config, font: &Font) -> (f32, f32) { - let cache = &mut self.glyph_cache; - let dpr = self.window.dpr; - - self.renderer.with_loader(|mut api| { - let _ = cache.update_font_size(font, dpr, &mut api); - }); - - // Compute new cell sizes. - compute_cell_size(config, &self.glyph_cache.font_metrics()) - } - - /// Clear glyph cache. - fn clear_glyph_cache(&mut self) { - let cache = &mut self.glyph_cache; - self.renderer.with_loader(|mut api| { - cache.clear_glyph_cache(&mut api); - }); - } - - /// Process update events. - pub fn handle_update<T>( - &mut self, - terminal: &mut Term<T>, - pty_resize_handle: &mut dyn OnResize, - message_buffer: &MessageBuffer, - search_active: bool, - config: &Config, - update_pending: DisplayUpdate, - ) where - T: EventListener, - { - let (mut cell_width, mut cell_height) = - (self.size_info.cell_width(), self.size_info.cell_height()); - - // Update font size and cell dimensions. - if let Some(font) = update_pending.font() { - let cell_dimensions = self.update_glyph_cache(config, font); - cell_width = cell_dimensions.0; - cell_height = cell_dimensions.1; - - info!("Cell size: {} x {}", cell_width, cell_height); - } else if update_pending.cursor_dirty() { - self.clear_glyph_cache(); - } - - let (mut width, mut height) = (self.size_info.width(), self.size_info.height()); - if let Some(dimensions) = update_pending.dimensions() { - width = dimensions.width as f32; - height = dimensions.height as f32; - } - - let padding = config.ui_config.window.padding(self.window.dpr); - - self.size_info = SizeInfo::new( - width, - height, - cell_width, - cell_height, - padding.0, - padding.1, - config.ui_config.window.dynamic_padding, - ); - - // Update number of column/lines in the viewport. - let message_bar_lines = - message_buffer.message().map(|m| m.text(&self.size_info).len()).unwrap_or(0); - let search_lines = if search_active { 1 } else { 0 }; - self.size_info.reserve_lines(message_bar_lines + search_lines); - - // Resize PTY. - pty_resize_handle.on_resize(&self.size_info); - - // Resize terminal. - terminal.resize(self.size_info); - - // Resize renderer. - let physical = - PhysicalSize::new(self.size_info.width() as u32, self.size_info.height() as u32); - self.window.resize(physical); - self.renderer.resize(&self.size_info); - - info!("Padding: {} x {}", self.size_info.padding_x(), self.size_info.padding_y()); - info!("Width: {}, Height: {}", self.size_info.width(), self.size_info.height()); - } - - /// Draw the screen. - /// - /// A reference to Term whose state is being drawn must be provided. - /// - /// This call may block if vsync is enabled. - pub fn draw<T>( - &mut self, - terminal: MutexGuard<'_, Term<T>>, - message_buffer: &MessageBuffer, - config: &Config, - mouse: &Mouse, - mods: ModifiersState, - search_state: &SearchState, - ) { - // Convert search match from viewport to absolute indexing. - let search_active = search_state.regex().is_some(); - let viewport_match = search_state - .focused_match() - .and_then(|focused_match| terminal.grid().clamp_buffer_range_to_visible(focused_match)); - let cursor_hidden = self.cursor_hidden || search_state.regex().is_some(); - - // Collect renderable content before the terminal is dropped. - let mut content = terminal.renderable_content(config, !cursor_hidden); - let mut grid_cells = Vec::new(); - while let Some(cell) = content.next() { - grid_cells.push(cell); - } - let cursor = content.cursor(); - - let visual_bell_intensity = terminal.visual_bell.intensity(); - let display_offset = terminal.grid().display_offset(); - let background_color = terminal.background_color(); - let cursor_point = terminal.grid().cursor.point; - let total_lines = terminal.grid().total_lines(); - let metrics = self.glyph_cache.font_metrics(); - let size_info = self.size_info; - - let selection = !terminal.selection.as_ref().map(Selection::is_empty).unwrap_or(true); - let mouse_mode = terminal.mode().intersects(TermMode::MOUSE_MODE) - && !terminal.mode().contains(TermMode::VI); - - let vi_mode = terminal.mode().contains(TermMode::VI); - let vi_mode_cursor = if vi_mode { Some(terminal.vi_mode_cursor) } else { None }; - - // Drop terminal as early as possible to free lock. - drop(terminal); - - self.renderer.with_api(&config.ui_config, &size_info, |api| { - api.clear(background_color); - }); - - let mut lines = RenderLines::new(); - let mut urls = Urls::new(); - - // Draw grid. - { - let _sampler = self.meter.sampler(); - - let glyph_cache = &mut self.glyph_cache; - self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - // Iterate over all non-empty cells in the grid. - for mut cell in grid_cells { - // Invert the active match during search. - if cell.is_match - && viewport_match - .as_ref() - .map_or(false, |viewport_match| viewport_match.contains(&cell.point())) - { - let colors = config.colors.search.focused_match; - let match_fg = colors.foreground.color(cell.fg, cell.bg); - cell.bg = colors.background.color(cell.fg, cell.bg); - cell.fg = match_fg; - cell.bg_alpha = 1.0; - } - - // Update URL underlines. - urls.update(size_info.cols(), &cell); - - // Update underline/strikeout. - lines.update(&cell); - - // Draw the cell. - api.render_cell(cell, glyph_cache); - } - }); - } - - let mut rects = lines.rects(&metrics, &size_info); - - // Update visible URLs. - self.urls = urls; - if let Some(url) = self.urls.highlighted(config, mouse, mods, mouse_mode, selection) { - rects.append(&mut url.rects(&metrics, &size_info)); - - self.window.set_mouse_cursor(CursorIcon::Hand); - - self.highlighted_url = Some(url); - } else if self.highlighted_url.is_some() { - self.highlighted_url = None; - - if mouse_mode { - self.window.set_mouse_cursor(CursorIcon::Default); - } else { - self.window.set_mouse_cursor(CursorIcon::Text); - } - } - - if let Some(vi_mode_cursor) = vi_mode_cursor { - // Highlight URLs at the vi mode cursor position. - let vi_mode_point = vi_mode_cursor.point; - if let Some(url) = self.urls.find_at(vi_mode_point) { - rects.append(&mut url.rects(&metrics, &size_info)); - } - - // Indicate vi mode by showing the cursor's position in the top right corner. - let line = size_info.screen_lines() + display_offset - vi_mode_point.line - 1; - self.draw_line_indicator(config, &size_info, total_lines, Some(vi_mode_point), line.0); - } else if search_active { - // Show current display offset in vi-less search to indicate match position. - self.draw_line_indicator(config, &size_info, total_lines, None, display_offset); - } - - // Push the cursor rects for rendering. - if let Some(cursor) = cursor { - for rect in cursor.rects(&size_info, config.cursor.thickness()) { - rects.push(rect); - } - } - - // Push visual bell after url/underline/strikeout rects. - if visual_bell_intensity != 0. { - let visual_bell_rect = RenderRect::new( - 0., - 0., - size_info.width(), - size_info.height(), - config.bell().color, - visual_bell_intensity as f32, - ); - rects.push(visual_bell_rect); - } - - if let Some(message) = message_buffer.message() { - let search_offset = if search_active { 1 } else { 0 }; - let text = message.text(&size_info); - - // Create a new rectangle for the background. - let start_line = size_info.screen_lines() + search_offset; - let y = size_info.cell_height().mul_add(start_line.0 as f32, size_info.padding_y()); - - let bg = match message.ty() { - MessageType::Error => config.colors.normal.red, - MessageType::Warning => config.colors.normal.yellow, - }; - - let message_bar_rect = - RenderRect::new(0., y, size_info.width(), size_info.height() - y, bg, 1.); - - // Push message_bar in the end, so it'll be above all other content. - rects.push(message_bar_rect); - - // Draw rectangles. - self.renderer.draw_rects(&size_info, rects); - - // Relay messages to the user. - let glyph_cache = &mut self.glyph_cache; - let fg = config.colors.primary.background; - for (i, message_text) in text.iter().enumerate() { - let point = Point::new(start_line + i, Column(0)); - self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, point, fg, bg, &message_text); - }); - } - } else { - // Draw rectangles. - self.renderer.draw_rects(&size_info, rects); - } - - self.draw_render_timer(config, &size_info); - - // Handle search and IME positioning. - let ime_position = match search_state.regex() { - Some(regex) => { - let search_label = match search_state.direction() { - Direction::Right => FORWARD_SEARCH_LABEL, - Direction::Left => BACKWARD_SEARCH_LABEL, - }; - - let search_text = Self::format_search(&size_info, regex, search_label); - - // Render the search bar. - self.draw_search(config, &size_info, &search_text); - - // Compute IME position. - Point::new(size_info.screen_lines() + 1, Column(search_text.chars().count() - 1)) - }, - None => cursor_point, - }; - - // Update IME position. - self.window.update_ime_position(ime_position, &self.size_info); - - // Frame event should be requested before swaping buffers, since it requires surface - // `commit`, which is done by swap buffers under the hood. - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - self.request_frame(&self.window); - - self.window.swap_buffers(); - - #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] - if self.is_x11 { - // On X11 `swap_buffers` does not block for vsync. However the next OpenGl command - // will block to synchronize (this is `glClear` in Alacritty), which causes a - // permanent one frame delay. - self.renderer.with_api(&config.ui_config, &size_info, |api| { - api.finish(); - }); - } - } - - /// Format search regex to account for the cursor and fullwidth characters. - fn format_search(size_info: &SizeInfo, search_regex: &str, search_label: &str) -> String { - // Add spacers for wide chars. - let mut formatted_regex = String::with_capacity(search_regex.len()); - for c in search_regex.chars() { - formatted_regex.push(c); - if c.width() == Some(2) { - formatted_regex.push(' '); - } - } - - // Add cursor to show whitespace. - formatted_regex.push('_'); - - // Truncate beginning of the search regex if it exceeds the viewport width. - let num_cols = size_info.cols().0; - let label_len = search_label.chars().count(); - let regex_len = formatted_regex.chars().count(); - let truncate_len = min((regex_len + label_len).saturating_sub(num_cols), regex_len); - let index = formatted_regex.char_indices().nth(truncate_len).map(|(i, _c)| i).unwrap_or(0); - let truncated_regex = &formatted_regex[index..]; - - // Add search label to the beginning of the search regex. - let mut bar_text = format!("{}{}", search_label, truncated_regex); - - // Make sure the label alone doesn't exceed the viewport width. - bar_text.truncate(num_cols); - - bar_text - } - - /// Draw current search regex. - fn draw_search(&mut self, config: &Config, size_info: &SizeInfo, text: &str) { - let glyph_cache = &mut self.glyph_cache; - let num_cols = size_info.cols().0; - - // Assure text length is at least num_cols. - let text = format!("{:<1$}", text, num_cols); - - let point = Point::new(size_info.screen_lines(), Column(0)); - let fg = config.colors.search_bar_foreground(); - let bg = config.colors.search_bar_background(); - - self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, point, fg, bg, &text); - }); - } - - /// Draw render timer. - fn draw_render_timer(&mut self, config: &Config, size_info: &SizeInfo) { - if !config.ui_config.debug.render_timer { - return; - } - - let glyph_cache = &mut self.glyph_cache; - - let timing = format!("{:.3} usec", self.meter.average()); - let point = Point::new(size_info.screen_lines() - 2, Column(0)); - let fg = config.colors.primary.background; - let bg = config.colors.normal.red; - - self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, point, fg, bg, &timing); - }); - } - - /// Draw an indicator for the position of a line in history. - fn draw_line_indicator( - &mut self, - config: &Config, - size_info: &SizeInfo, - total_lines: usize, - vi_mode_point: Option<Point>, - line: usize, - ) { - let text = format!("[{}/{}]", line, total_lines - 1); - let column = Column(size_info.cols().0.saturating_sub(text.len())); - let colors = &config.colors; - let fg = colors.line_indicator.foreground.unwrap_or(colors.primary.background); - let bg = colors.line_indicator.background.unwrap_or(colors.primary.foreground); - - // Do not render anything if it would obscure the vi mode cursor. - if vi_mode_point.map_or(true, |point| point.line.0 != 0 || point.col < column) { - let glyph_cache = &mut self.glyph_cache; - self.renderer.with_api(&config.ui_config, &size_info, |mut api| { - api.render_string(glyph_cache, Point::new(Line(0), column), fg, bg, &text); - }); - } - } - - /// Requst a new frame for a window on Wayland. - #[inline] - #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] - fn request_frame(&self, window: &Window) { - let surface = match window.wayland_surface() { - Some(surface) => surface, - None => return, - }; - - let should_draw = self.window.should_draw.clone(); - - // Mark that window was drawn. - should_draw.store(false, Ordering::Relaxed); - - // Request a new frame. - surface.frame().quick_assign(move |_, _, _| { - should_draw.store(true, Ordering::Relaxed); - }); - } -} - -/// Calculate the cell dimensions based on font metrics. -/// -/// This will return a tuple of the cell width and height. -#[inline] -fn compute_cell_size(config: &Config, metrics: &crossfont::Metrics) -> (f32, f32) { - let offset_x = f64::from(config.ui_config.font.offset.x); - let offset_y = f64::from(config.ui_config.font.offset.y); - ( - (metrics.average_advance + offset_x).floor().max(1.) as f32, - (metrics.line_height + offset_y).floor().max(1.) as f32, - ) -} - -/// Calculate the size of the window given padding, terminal dimensions and cell size. -fn window_size( - config: &Config, - dimensions: Dimensions, - cell_width: f32, - cell_height: f32, - dpr: f64, -) -> PhysicalSize<u32> { - let padding = config.ui_config.window.padding(dpr); - - let grid_width = cell_width * dimensions.columns.0.max(MIN_COLS) as f32; - let grid_height = cell_height * dimensions.lines.0.max(MIN_SCREEN_LINES) as f32; - - let width = (padding.0).mul_add(2., grid_width).floor(); - let height = (padding.1).mul_add(2., grid_height).floor(); - - PhysicalSize::new(width as u32, height as u32) -} |