aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/display.rs')
-rw-r--r--alacritty/src/display.rs230
1 files changed, 105 insertions, 125 deletions
diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs
index ca5bfe34..0b493936 100644
--- a/alacritty/src/display.rs
+++ b/alacritty/src/display.rs
@@ -25,12 +25,13 @@ use crossfont::set_font_smoothing;
use crossfont::{self, Rasterize, Rasterizer};
use alacritty_terminal::event::{EventListener, OnResize};
-use alacritty_terminal::index::{Column, Direction, Line, Point};
+use alacritty_terminal::index::{Column, Direction, Point};
use alacritty_terminal::selection::Selection;
use alacritty_terminal::term::{RenderableCell, SizeInfo, Term, TermMode};
+use alacritty_terminal::term::{MIN_COLS, MIN_SCREEN_LINES};
use crate::config::font::Font;
-use crate::config::window::StartupMode;
+use crate::config::window::{Dimensions, StartupMode};
use crate::config::Config;
use crate::event::{Mouse, SearchState};
use crate::message_bar::{MessageBuffer, MessageType};
@@ -109,8 +110,8 @@ pub struct DisplayUpdate {
pub dirty: bool,
dimensions: Option<PhysicalSize<u32>>,
- font: Option<Font>,
cursor_dirty: bool,
+ font: Option<Font>,
}
impl DisplayUpdate {
@@ -171,16 +172,15 @@ impl Display {
let metrics = GlyphCache::static_metrics(config.ui_config.font.clone(), estimated_dpr)?;
let (cell_width, cell_height) = compute_cell_size(config, &metrics);
- let dimensions = GlyphCache::calculate_dimensions(
- &config.ui_config.window,
- estimated_dpr,
- cell_width,
- cell_height,
- );
+ // 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 Cell Size: {} x {}", cell_width, cell_height);
- debug!("Estimated Dimensions: {:?}", dimensions);
+ debug!("Estimated window size: {:?}", estimated_size);
+ debug!("Estimated cell size: {} x {}", cell_width, cell_height);
#[cfg(not(any(target_os = "macos", windows)))]
let mut wayland_event_queue = None;
@@ -192,20 +192,16 @@ impl Display {
wayland_event_queue = Some(display.create_event_queue());
}
- // Create the window where Alacritty will be displayed.
- let size = dimensions.map(|(width, height)| PhysicalSize::new(width, height));
-
- // Spawn window.
+ // Spawn the Alacritty window.
let mut window = Window::new(
event_loop,
&config,
- size,
+ estimated_size,
#[cfg(not(any(target_os = "macos", windows)))]
wayland_event_queue.as_ref(),
)?;
- let dpr = window.scale_factor();
- info!("Device pixel ratio: {}", dpr);
+ info!("Device pixel ratio: {}", window.dpr);
// get window properties for initializing the other subsystems.
let viewport_size = window.inner_size();
@@ -214,43 +210,33 @@ impl Display {
let mut renderer = QuadRenderer::new()?;
let (glyph_cache, cell_width, cell_height) =
- Self::new_glyph_cache(dpr, &mut renderer, config)?;
-
- let padding = config.ui_config.window.padding;
- let mut padding_x = f32::from(padding.x) * dpr as f32;
- let mut padding_y = f32::from(padding.y) * dpr as f32;
+ Self::new_glyph_cache(window.dpr, &mut renderer, config)?;
- if let Some((width, height)) =
- GlyphCache::calculate_dimensions(&config.ui_config.window, dpr, cell_width, cell_height)
- {
- let PhysicalSize { width: w, height: h } = window.inner_size();
- if w == width && h == height {
+ if let Some(dimensions) = dimensions {
+ if (estimated_dpr - window.dpr).abs() < f64::EPSILON {
info!("Estimated DPR correctly, skipping resize");
} else {
- window.set_inner_size(PhysicalSize::new(width, height));
+ // 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);
}
- } else if config.ui_config.window.dynamic_padding {
- // Make sure additional padding is spread evenly.
- padding_x = dynamic_padding(padding_x, viewport_size.width as f32, cell_width);
- padding_y = dynamic_padding(padding_y, viewport_size.height as f32, cell_height);
}
- padding_x = padding_x.floor();
- padding_y = padding_y.floor();
-
- info!("Cell Size: {} x {}", cell_width, cell_height);
- info!("Padding: {} x {}", padding_x, padding_y);
+ let padding = config.ui_config.window.padding(window.dpr);
// Create new size with at least one column and row.
- let size_info = SizeInfo {
- dpr,
- width: (viewport_size.width as f32).max(cell_width + 2. * padding_x),
- height: (viewport_size.height as f32).max(cell_height + 2. * padding_y),
+ let size_info = SizeInfo::new(
+ viewport_size.width as f32,
+ viewport_size.height as f32,
cell_width,
cell_height,
- padding_x,
- padding_y,
- };
+ 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());
// Update OpenGL projection.
renderer.resize(&size_info);
@@ -345,20 +331,18 @@ impl Display {
}
/// Update font size and cell dimensions.
- fn update_glyph_cache(&mut self, config: &Config, font: &Font) {
- let size_info = &mut self.size_info;
+ ///
+ /// 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, size_info.dpr, &mut api);
+ let _ = cache.update_font_size(font, dpr, &mut api);
});
- // Update cell size.
- let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
- size_info.cell_width = cell_width;
- size_info.cell_height = cell_height;
-
- info!("Cell Size: {} x {}", cell_width, cell_height);
+ // Compute new cell sizes.
+ compute_cell_size(config, &self.glyph_cache.font_metrics())
}
/// Clear glyph cache.
@@ -381,63 +365,58 @@ impl Display {
) 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() {
- self.update_glyph_cache(config, 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 cell_width = self.size_info.cell_width;
- let cell_height = self.size_info.cell_height;
-
- // Recalculate padding.
- let padding = config.ui_config.window.padding;
- let mut padding_x = f32::from(padding.x) * self.size_info.dpr as f32;
- let mut padding_y = f32::from(padding.y) * self.size_info.dpr as f32;
-
- // Update the window dimensions.
- if let Some(size) = update_pending.dimensions() {
- // Ensure we have at least one column and row.
- self.size_info.width = (size.width as f32).max(cell_width + 2. * padding_x);
- self.size_info.height = (size.height as f32).max(cell_height + 2. * padding_y);
+ 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;
}
- // Distribute excess padding equally on all sides.
- if config.ui_config.window.dynamic_padding {
- padding_x = dynamic_padding(padding_x, self.size_info.width, cell_width);
- padding_y = dynamic_padding(padding_y, self.size_info.height, cell_height);
- }
+ let padding = config.ui_config.window.padding(self.window.dpr);
- self.size_info.padding_x = padding_x.floor() as f32;
- self.size_info.padding_y = padding_y.floor() as f32;
-
- let mut pty_size = self.size_info;
-
- // Subtract message bar lines from pty size.
- if let Some(message) = message_buffer.message() {
- let lines = message.text(&self.size_info).len();
- pty_size.height -= pty_size.cell_height * lines as f32;
- }
+ self.size_info = SizeInfo::new(
+ width,
+ height,
+ cell_width,
+ cell_height,
+ padding.0,
+ padding.1,
+ config.ui_config.window.dynamic_padding,
+ );
- // Add an extra line for the current search regex.
- if search_active {
- pty_size.height -= pty_size.cell_height;
- }
+ // 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(&pty_size);
+ pty_resize_handle.on_resize(&self.size_info);
// Resize terminal.
- terminal.resize(pty_size);
+ terminal.resize(self.size_info);
// Resize renderer.
- let physical = PhysicalSize::new(self.size_info.width as u32, self.size_info.height as u32);
+ 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);
+ 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.
@@ -533,22 +512,21 @@ impl Display {
let visual_bell_rect = RenderRect::new(
0.,
0.,
- size_info.width,
- size_info.height,
+ size_info.width(),
+ size_info.height(),
config.bell().color,
visual_bell_intensity as f32,
);
rects.push(visual_bell_rect);
}
- let mut message_bar_lines = 0;
if let Some(message) = message_buffer.message() {
+ let search_offset = if search_state.regex().is_some() { 1 } else { 0 };
let text = message.text(&size_info);
- message_bar_lines = text.len();
// Create a new rectangle for the background.
- let start_line = size_info.lines().0 - message_bar_lines;
- let y = size_info.cell_height.mul_add(start_line as f32, size_info.padding_y);
+ 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 color = match message.ty() {
MessageType::Error => config.colors.normal().red,
@@ -556,7 +534,7 @@ impl Display {
};
let message_bar_rect =
- RenderRect::new(0., y, size_info.width, size_info.height - y, color, 1.);
+ RenderRect::new(0., y, size_info.width(), size_info.height() - y, color, 1.);
// Push message_bar in the end, so it'll be above all other content.
rects.push(message_bar_rect);
@@ -566,15 +544,9 @@ impl Display {
// Relay messages to the user.
let fg = config.colors.primary.background;
- for (i, message_text) in text.iter().rev().enumerate() {
+ for (i, message_text) in text.iter().enumerate() {
self.renderer.with_api(&config.ui_config, config.cursor, &size_info, |mut api| {
- api.render_string(
- glyph_cache,
- Line(size_info.lines().saturating_sub(i + 1)),
- &message_text,
- fg,
- None,
- );
+ api.render_string(glyph_cache, start_line + i, &message_text, fg, None);
});
}
} else {
@@ -595,10 +567,10 @@ impl Display {
let search_text = Self::format_search(&size_info, regex, search_label);
// Render the search bar.
- self.draw_search(config, &size_info, message_bar_lines, &search_text);
+ self.draw_search(config, &size_info, &search_text);
// Compute IME position.
- Point::new(size_info.lines() - 1, Column(search_text.chars().count() - 1))
+ Point::new(size_info.screen_lines() + 1, Column(search_text.chars().count() - 1))
},
None => cursor_point,
};
@@ -656,13 +628,7 @@ impl Display {
}
/// Draw current search regex.
- fn draw_search(
- &mut self,
- config: &Config,
- size_info: &SizeInfo,
- message_bar_lines: usize,
- text: &str,
- ) {
+ 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;
@@ -671,9 +637,8 @@ impl Display {
let fg = config.colors.search_bar_foreground();
let bg = config.colors.search_bar_background();
- let line = size_info.lines() - message_bar_lines - 1;
self.renderer.with_api(&config.ui_config, config.cursor, &size_info, |mut api| {
- api.render_string(glyph_cache, line, &text, fg, Some(bg));
+ api.render_string(glyph_cache, size_info.screen_lines(), &text, fg, Some(bg));
});
}
@@ -689,7 +654,7 @@ impl Display {
let bg = config.colors.normal().red;
self.renderer.with_api(&config.ui_config, config.cursor, &size_info, |mut api| {
- api.render_string(glyph_cache, size_info.lines() - 2, &timing[..], fg, Some(bg));
+ api.render_string(glyph_cache, size_info.screen_lines() - 2, &timing[..], fg, Some(bg));
});
}
@@ -714,13 +679,9 @@ impl Display {
}
}
-/// Calculate padding to spread it evenly around the terminal content.
-#[inline]
-fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
- padding + ((dimension - 2. * padding) % cell_dimension) / 2.
-}
-
/// 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);
@@ -730,3 +691,22 @@ fn compute_cell_size(config: &Config, metrics: &crossfont::Metrics) -> (f32, f32
((metrics.line_height + offset_y) as f32).floor().max(1.),
)
}
+
+/// 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)
+}