aboutsummaryrefslogtreecommitdiff
path: root/alacritty
diff options
context:
space:
mode:
authorii41 <23465321+ii41@users.noreply.github.com>2020-09-27 15:36:08 -0700
committerGitHub <noreply@github.com>2020-09-27 22:36:08 +0000
commita754d06b44139b85e8b34a71ece4477cb1caa85e (patch)
tree1733f8d17101947b6df5e1ad15b3fd64cf1db9a0 /alacritty
parente9c0034f4d3ee003149fe5454942bea7ff3d98be (diff)
downloadr-alacritty-a754d06b44139b85e8b34a71ece4477cb1caa85e.tar.gz
r-alacritty-a754d06b44139b85e8b34a71ece4477cb1caa85e.tar.bz2
r-alacritty-a754d06b44139b85e8b34a71ece4477cb1caa85e.zip
Add support for single line terminals
This changes the minimum terminal dimensions from 2 lines and 2 columns, to 1 line and 2 columns. This also reworks the `SizeInfo` to store the number of columns and lines and consistently has only the terminal lines/columns stored, instead of including the message bar and search in some places of the Alacritty renderer/input. These new changes also make it easy to properly start the selection scrolling as soon as the mouse is over the message bar, instead of waiting until it is beyond it. Fixes #4207. Co-authored-by: Christian Duerr <contact@christianduerr.com>
Diffstat (limited to 'alacritty')
-rw-r--r--alacritty/src/cli.rs13
-rw-r--r--alacritty/src/config/window.rs70
-rw-r--r--alacritty/src/display.rs230
-rw-r--r--alacritty/src/event.rs37
-rw-r--r--alacritty/src/input.rs103
-rw-r--r--alacritty/src/main.rs6
-rw-r--r--alacritty/src/message_bar.rs107
-rw-r--r--alacritty/src/renderer/mod.rs70
-rw-r--r--alacritty/src/renderer/rects.rs15
-rw-r--r--alacritty/src/window.rs18
10 files changed, 289 insertions, 380 deletions
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index 047c8d2e..6303d081 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -205,10 +205,10 @@ impl Options {
}
if let Some(mut dimensions) = matches.values_of("dimensions") {
- let width = dimensions.next().map(|w| w.parse().map(Column));
- let height = dimensions.next().map(|h| h.parse().map(Line));
- if let (Some(Ok(width)), Some(Ok(height))) = (width, height) {
- options.dimensions = Some(Dimensions::new(width, height));
+ let columns = dimensions.next().map(|columns| columns.parse().map(Column));
+ let lines = dimensions.next().map(|lines| lines.parse().map(Line));
+ if let (Some(Ok(columns)), Some(Ok(lines))) = (columns, lines) {
+ options.dimensions = Some(Dimensions { columns, lines });
}
}
@@ -309,7 +309,10 @@ impl Options {
let dynamic_title = config.ui_config.dynamic_title() && self.title.is_none();
config.ui_config.set_dynamic_title(dynamic_title);
- replace_if_some(&mut config.ui_config.window.dimensions, self.dimensions);
+ if let Some(dimensions) = self.dimensions {
+ config.ui_config.window.set_dimensions(dimensions);
+ }
+
replace_if_some(&mut config.ui_config.window.title, self.title.clone());
replace_if_some(&mut config.ui_config.window.class.instance, self.class_instance.clone());
replace_if_some(&mut config.ui_config.window.class.general, self.class_general.clone());
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
index f866e180..d2e5da68 100644
--- a/alacritty/src/config/window.rs
+++ b/alacritty/src/config/window.rs
@@ -15,26 +15,14 @@ pub const DEFAULT_NAME: &str = "Alacritty";
#[serde(default)]
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct WindowConfig {
- /// Initial dimensions.
- #[serde(deserialize_with = "failure_default")]
- pub dimensions: Dimensions,
-
/// Initial position.
#[serde(deserialize_with = "failure_default")]
pub position: Option<Delta<i32>>,
- /// Pixel padding.
- #[serde(deserialize_with = "failure_default")]
- pub padding: Delta<u8>,
-
/// Draw the window with title bar / borders.
#[serde(deserialize_with = "failure_default")]
pub decorations: Decorations,
- /// Spread out additional padding evenly.
- #[serde(deserialize_with = "failure_default")]
- pub dynamic_padding: bool,
-
/// Startup mode.
#[serde(deserialize_with = "failure_default")]
pub startup_mode: StartupMode,
@@ -55,9 +43,21 @@ pub struct WindowConfig {
#[serde(deserialize_with = "option_explicit_none")]
pub gtk_theme_variant: Option<String>,
+ /// Spread out additional padding evenly.
+ #[serde(deserialize_with = "failure_default")]
+ pub dynamic_padding: bool,
+
+ /// Pixel padding.
+ #[serde(deserialize_with = "failure_default")]
+ padding: Delta<u8>,
+
/// Use dynamic title.
#[serde(default, deserialize_with = "failure_default")]
dynamic_title: DefaultTrueBool,
+
+ /// Initial dimensions.
+ #[serde(deserialize_with = "failure_default")]
+ dimensions: Dimensions,
}
pub fn default_title() -> String {
@@ -74,6 +74,30 @@ impl WindowConfig {
pub fn set_dynamic_title(&mut self, dynamic_title: bool) {
self.dynamic_title.0 = dynamic_title;
}
+
+ #[inline]
+ pub fn set_dimensions(&mut self, dimensions: Dimensions) {
+ self.dimensions = dimensions;
+ }
+
+ #[inline]
+ pub fn dimensions(&self) -> Option<Dimensions> {
+ if self.dimensions.columns.0 != 0
+ && self.dimensions.lines.0 != 0
+ && self.startup_mode != StartupMode::Maximized
+ {
+ Some(self.dimensions)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn padding(&self, dpr: f64) -> (f32, f32) {
+ let padding_x = (f32::from(self.padding.x) * dpr as f32).floor();
+ let padding_y = (f32::from(self.padding.y) * dpr as f32).floor();
+ (padding_x, padding_y)
+ }
}
impl Default for WindowConfig {
@@ -137,29 +161,11 @@ impl Default for Decorations {
pub struct Dimensions {
/// Window width in character columns.
#[serde(deserialize_with = "failure_default")]
- columns: Column,
+ pub columns: Column,
/// Window Height in character lines.
#[serde(deserialize_with = "failure_default")]
- lines: Line,
-}
-
-impl Dimensions {
- pub fn new(columns: Column, lines: Line) -> Self {
- Dimensions { columns, lines }
- }
-
- /// Get lines.
- #[inline]
- pub fn lines_u32(&self) -> u32 {
- self.lines.0 as u32
- }
-
- /// Get columns.
- #[inline]
- pub fn columns_u32(&self) -> u32 {
- self.columns.0 as u32
- }
+ pub lines: Line,
}
/// Window class hint.
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)
+}
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index e81dc0f9..e45795dd 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -410,14 +410,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.goto_match(None);
}
- // Move vi cursor down if resize will pull content from history.
- if self.terminal.history_size() != 0 && self.terminal.grid().display_offset() == 0 {
- self.terminal.vi_mode_cursor.point.line += 1;
- }
-
- self.display_update_pending.dirty = true;
- self.search_state.regex = None;
- self.terminal.dirty = true;
+ self.exit_search();
}
#[inline]
@@ -429,14 +422,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.search_reset_state();
}
- // Move vi cursor down if resize will pull from history.
- if self.terminal.history_size() != 0 && self.terminal.grid().display_offset() == 0 {
- self.terminal.vi_mode_cursor.point.line += 1;
- }
-
- self.display_update_pending.dirty = true;
- self.search_state.regex = None;
- self.terminal.dirty = true;
+ self.exit_search();
}
#[inline]
@@ -628,6 +614,21 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
self.search_state.regex = Some(regex);
}
+ /// Close the search bar.
+ fn exit_search(&mut self) {
+ // Move vi cursor down if resize will pull content from history.
+ if self.terminal.history_size() != 0
+ && self.terminal.grid().display_offset() == 0
+ && self.terminal.screen_lines() > self.terminal.vi_mode_cursor.point.line + 1
+ {
+ self.terminal.vi_mode_cursor.point.line += 1;
+ }
+
+ self.display_update_pending.dirty = true;
+ self.search_state.regex = None;
+ self.terminal.dirty = true;
+ }
+
/// Get the absolute position of the search origin.
///
/// This takes the relative motion of the viewport since the start of the search into account.
@@ -914,7 +915,7 @@ impl<N: Notify + OnResize> Processor<N> {
// Resize to event's dimensions, since no resize event is emitted on Wayland.
display_update_pending.set_dimensions(PhysicalSize::new(width, height));
- processor.ctx.size_info.dpr = scale_factor;
+ processor.ctx.window.dpr = scale_factor;
processor.ctx.terminal.dirty = true;
},
Event::Message(message) => {
@@ -1098,7 +1099,7 @@ impl<N: Notify + OnResize> Processor<N> {
// Update display if padding options were changed.
let window_config = &processor.ctx.config.ui_config.window;
- if window_config.padding != config.ui_config.window.padding
+ if window_config.padding(1.) != config.ui_config.window.padding(1.)
|| window_config.dynamic_padding != config.ui_config.window.dynamic_padding
{
processor.ctx.display_update_pending.dirty = true;
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 351e164c..9c75753a 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -371,8 +371,8 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
self.update_selection_scrolling(y);
}
- let x = min(max(x, 0), size_info.width as i32 - 1) as usize;
- let y = min(max(y, 0), size_info.height as i32 - 1) as usize;
+ let x = min(max(x, 0), size_info.width() as i32 - 1) as usize;
+ let y = min(max(y, 0), size_info.height() as i32 - 1) as usize;
self.ctx.mouse_mut().x = x;
self.ctx.mouse_mut().y = y;
@@ -384,6 +384,11 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let cell_changed =
point.line != self.ctx.mouse().line || point.col != self.ctx.mouse().column;
+ // Update mouse state and check for URL change.
+ let mouse_state = self.mouse_state();
+ self.update_url_state(&mouse_state);
+ self.ctx.window_mut().set_mouse_cursor(mouse_state.into());
+
// If the mouse hasn't changed cells, do nothing.
if !cell_changed
&& self.ctx.mouse().cell_side == cell_side
@@ -400,11 +405,6 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
// Don't launch URLs if mouse has moved.
self.ctx.mouse_mut().block_url_launcher = true;
- // Update mouse state and check for URL change.
- let mouse_state = self.mouse_state();
- self.update_url_state(&mouse_state);
- self.ctx.window_mut().set_mouse_cursor(mouse_state.into());
-
if (lmb_pressed || rmb_pressed)
&& (self.ctx.modifiers().shift() || !self.ctx.mouse_mode())
&& !search_active
@@ -431,12 +431,13 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let size_info = self.ctx.size_info();
let x = self.ctx.mouse().x;
- let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize;
- let half_cell_width = (size_info.cell_width / 2.0) as usize;
+ let cell_x =
+ x.saturating_sub(size_info.padding_x() as usize) % size_info.cell_width() as usize;
+ let half_cell_width = (size_info.cell_width() / 2.0) as usize;
let additional_padding =
- (size_info.width - size_info.padding_x * 2.) % size_info.cell_width;
- let end_of_grid = size_info.width - size_info.padding_x - additional_padding;
+ (size_info.width() - size_info.padding_x() * 2.) % size_info.cell_width();
+ let end_of_grid = size_info.width() - size_info.padding_x() - additional_padding;
if cell_x > half_cell_width
// Edge case when mouse leaves the window.
@@ -661,7 +662,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
pub fn mouse_wheel_input(&mut self, delta: MouseScrollDelta, phase: TouchPhase) {
match delta {
MouseScrollDelta::LineDelta(_columns, lines) => {
- let new_scroll_px = lines * self.ctx.size_info().cell_height;
+ let new_scroll_px = lines * self.ctx.size_info().cell_height();
self.scroll_terminal(f64::from(new_scroll_px));
},
MouseScrollDelta::PixelDelta(lpos) => {
@@ -680,7 +681,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
}
fn scroll_terminal(&mut self, new_scroll_px: f64) {
- let height = f64::from(self.ctx.size_info().cell_height);
+ let height = f64::from(self.ctx.size_info().cell_height());
if self.ctx.mouse_mode() {
self.ctx.mouse_mut().scroll_px += new_scroll_px;
@@ -764,13 +765,17 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
}
// Skip normal mouse events if the message bar has been clicked.
- if self.message_close_at_cursor() && state == ElementState::Pressed {
+ if self.message_bar_mouse_state() == Some(MouseState::MessageBarButton)
+ && state == ElementState::Pressed
+ {
+ let size = self.ctx.size_info();
+
+ let current_lines = self.ctx.message().map(|m| m.text(&size).len()).unwrap_or(0);
+
self.ctx.clear_selection();
self.ctx.pop_message();
// Reset cursor when message bar height changed or all messages are gone.
- let size = self.ctx.size_info();
- let current_lines = (size.lines() - self.ctx.terminal().screen_lines()).0;
let new_lines = self.ctx.message().map(|m| m.text(&size).len()).unwrap_or(0);
let new_icon = match current_lines.cmp(&new_lines) {
@@ -976,21 +981,26 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
}
}
- /// Check if the cursor is hovering above the message bar.
- fn message_at_cursor(&mut self) -> bool {
- self.ctx.mouse().line >= self.ctx.terminal().screen_lines()
- }
-
- /// Whether the point is over the message bar's close button.
- fn message_close_at_cursor(&self) -> bool {
- let mouse = self.ctx.mouse();
-
+ /// Check mouse state in relation to the message bar.
+ fn message_bar_mouse_state(&self) -> Option<MouseState> {
// Since search is above the message bar, the button is offset by search's height.
let search_height = if self.ctx.search_active() { 1 } else { 0 };
- mouse.inside_text_area
- && mouse.column + message_bar::CLOSE_BUTTON_TEXT.len() >= self.ctx.size_info().cols()
- && mouse.line == self.ctx.terminal().screen_lines() + search_height
+ // Calculate Y position of the end of the last terminal line.
+ let size = self.ctx.size_info();
+ let terminal_end = size.padding_y() as usize
+ + size.cell_height() as usize * (size.screen_lines().0 + search_height);
+
+ let mouse = self.ctx.mouse();
+ if self.ctx.message().is_none() || (mouse.y <= terminal_end) {
+ None
+ } else if mouse.y <= terminal_end + size.cell_height() as usize
+ && mouse.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.cols()
+ {
+ Some(MouseState::MessageBarButton)
+ } else {
+ Some(MouseState::MessageBar)
+ }
}
/// Copy text selection.
@@ -1016,10 +1026,8 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
/// Location of the mouse cursor.
fn mouse_state(&mut self) -> MouseState {
// Check message bar before URL to ignore URLs in the message bar.
- if self.message_close_at_cursor() {
- return MouseState::MessageBarButton;
- } else if self.message_at_cursor() {
- return MouseState::MessageBar;
+ if let Some(mouse_state) = self.message_bar_mouse_state() {
+ return mouse_state;
}
let mouse_mode = self.ctx.mouse_mode();
@@ -1048,17 +1056,18 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
/// Handle automatic scrolling when selecting above/below the window.
fn update_selection_scrolling(&mut self, mouse_y: i32) {
- let size_info = self.ctx.size_info();
+ let dpr = self.ctx.window().dpr;
+ let size = self.ctx.size_info();
let scheduler = self.ctx.scheduler_mut();
// Scale constants by DPI.
- let min_height = (MIN_SELECTION_SCROLLING_HEIGHT * size_info.dpr) as i32;
- let step = (SELECTION_SCROLLING_STEP * size_info.dpr) as i32;
+ let min_height = (MIN_SELECTION_SCROLLING_HEIGHT * dpr) as i32;
+ let step = (SELECTION_SCROLLING_STEP * dpr) as i32;
// Compute the height of the scrolling areas.
- let end_top = max(min_height, size_info.padding_y as i32);
- let height_bottom = max(min_height, size_info.padding_bottom() as i32);
- let start_bottom = size_info.height as i32 - height_bottom;
+ let end_top = max(min_height, size.padding_y() as i32);
+ let text_area_bottom = size.padding_y() + size.screen_lines().0 as f32 * size.cell_height();
+ let start_bottom = min(size.height() as i32 - min_height, text_area_bottom as i32);
// Get distance from closest window boundary.
let delta = if mouse_y < end_top {
@@ -1283,15 +1292,15 @@ mod tests {
url: Default::default(),
};
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 1.0,
- };
+ let size = SizeInfo::new(
+ 21.0,
+ 51.0,
+ 3.0,
+ 3.0,
+ 0.,
+ 0.,
+ false,
+ );
let mut clipboard = Clipboard::new_nop();
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index efd3e947..09296f60 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -138,7 +138,11 @@ fn run(
// The display manages a window and can draw the terminal.
let display = Display::new(&config, &window_event_loop)?;
- info!("PTY dimensions: {:?} x {:?}", display.size_info.lines(), display.size_info.cols());
+ info!(
+ "PTY dimensions: {:?} x {:?}",
+ display.size_info.screen_lines(),
+ display.size_info.cols()
+ );
// Create the terminal.
//
diff --git a/alacritty/src/message_bar.rs b/alacritty/src/message_bar.rs
index 4c43c3d3..851cb6ee 100644
--- a/alacritty/src/message_bar.rs
+++ b/alacritty/src/message_bar.rs
@@ -34,7 +34,9 @@ impl Message {
/// Formatted message text lines.
pub fn text(&self, size_info: &SizeInfo) -> Vec<String> {
let num_cols = size_info.cols().0;
- let max_lines = size_info.lines().saturating_sub(MIN_FREE_LINES);
+ let total_lines =
+ (size_info.height() - 2. * size_info.padding_y()) / size_info.cell_height();
+ let max_lines = (total_lines as usize).saturating_sub(MIN_FREE_LINES);
let button_len = CLOSE_BUTTON_TEXT.len();
// Split line to fit the screen.
@@ -169,7 +171,8 @@ impl MessageBuffer {
#[cfg(test)]
mod tests {
- use super::{Message, MessageBuffer, MessageType, MIN_FREE_LINES};
+ use super::*;
+
use alacritty_terminal::term::SizeInfo;
#[test]
@@ -177,15 +180,7 @@ mod tests {
let input = "a";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 7.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(7., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -197,15 +192,7 @@ mod tests {
let input = "fo\nbar";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 6.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -217,15 +204,7 @@ mod tests {
let input = "a\nb";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 6.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -237,15 +216,7 @@ mod tests {
let input = "foobar1";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 6.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -257,15 +228,7 @@ mod tests {
let input = "foobar";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 6.,
- height: 0.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(6., 0., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -277,15 +240,7 @@ mod tests {
let input = "hahahahahahahahahahaha truncate this because it's too long for the term";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 22.,
- height: (MIN_FREE_LINES + 2) as f32,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(22., (MIN_FREE_LINES + 2) as f32, 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -300,15 +255,7 @@ mod tests {
let input = "ha";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 2.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(2., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -320,15 +267,7 @@ mod tests {
let input = "hahahahahahahahaha";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 2.,
- height: (MIN_FREE_LINES + 2) as f32,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(2., (MIN_FREE_LINES + 2) as f32, 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -340,15 +279,7 @@ mod tests {
let input = "test";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 5.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(5., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
@@ -398,15 +329,7 @@ mod tests {
let input = "a\nbc defg";
let mut message_buffer = MessageBuffer::new();
message_buffer.push(Message::new(input.into(), MessageType::Error));
- let size = SizeInfo {
- width: 5.,
- height: 10.,
- cell_width: 1.,
- cell_height: 1.,
- padding_x: 0.,
- padding_y: 0.,
- dpr: 0.,
- };
+ let size = SizeInfo::new(5., 10., 1., 1., 0., 0., false);
let lines = message_buffer.message().unwrap().text(&size);
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index da5f68a0..e97ac025 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -26,7 +26,6 @@ use alacritty_terminal::thread;
use crate::config::font::{Font, FontDescription};
use crate::config::ui_config::{Delta, UIConfig};
-use crate::config::window::{StartupMode, WindowConfig};
use crate::cursor;
use crate::gl;
use crate::gl::types::*;
@@ -231,7 +230,7 @@ impl GlyphCache {
if desc == regular_desc {
regular
} else {
- rasterizer.load_font(&desc, size).unwrap_or_else(|_| regular)
+ rasterizer.load_font(&desc, size).unwrap_or(regular)
}
};
@@ -358,34 +357,6 @@ impl GlyphCache {
rasterizer.metrics(regular, font.size)
}
-
- pub fn calculate_dimensions(
- window_config: &WindowConfig,
- dpr: f64,
- cell_width: f32,
- cell_height: f32,
- ) -> Option<(u32, u32)> {
- let dimensions = window_config.dimensions;
-
- if dimensions.columns_u32() == 0
- || dimensions.lines_u32() == 0
- || window_config.startup_mode != StartupMode::Windowed
- {
- return None;
- }
-
- let padding_x = f64::from(window_config.padding.x) * dpr;
- let padding_y = f64::from(window_config.padding.y) * dpr;
-
- // Calculate new size based on cols/lines specified in config.
- let grid_width = cell_width as u32 * dimensions.columns_u32();
- let grid_height = cell_height as u32 * dimensions.lines_u32();
-
- let width = padding_x.mul_add(2., f64::from(grid_width)).floor();
- let height = padding_y.mul_add(2., f64::from(grid_height)).floor();
-
- Some((width as u32, height as u32))
- }
}
#[derive(Debug)]
@@ -705,7 +676,7 @@ impl QuadRenderer {
gl::UseProgram(self.rect_program.id);
// Remove padding from viewport.
- gl::Viewport(0, 0, props.width as i32, props.height as i32);
+ gl::Viewport(0, 0, props.width() as i32, props.height() as i32);
// Change blending strategy.
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::SRC_ALPHA, gl::ONE);
@@ -740,10 +711,10 @@ impl QuadRenderer {
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindVertexArray(0);
- let padding_x = props.padding_x as i32;
- let padding_y = props.padding_y as i32;
- let width = props.width as i32;
- let height = props.height as i32;
+ let padding_x = props.padding_x() as i32;
+ let padding_y = props.padding_y() as i32;
+ let width = props.width() as i32;
+ let height = props.height() as i32;
gl::Viewport(padding_x, padding_y, width - 2 * padding_x, height - 2 * padding_y);
// Disable program.
@@ -821,10 +792,10 @@ impl QuadRenderer {
unsafe {
gl::UseProgram(program.id);
program.update_projection(
- props.width,
- props.height,
- props.padding_x,
- props.padding_y,
+ props.width(),
+ props.height(),
+ props.padding_x(),
+ props.padding_y(),
);
gl::UseProgram(0);
}
@@ -847,15 +818,20 @@ impl QuadRenderer {
// Viewport.
unsafe {
gl::Viewport(
- size.padding_x as i32,
- size.padding_y as i32,
- size.width as i32 - 2 * size.padding_x as i32,
- size.height as i32 - 2 * size.padding_y as i32,
+ size.padding_x() as i32,
+ size.padding_y() as i32,
+ size.width() as i32 - 2 * size.padding_x() as i32,
+ size.height() as i32 - 2 * size.padding_y() as i32,
);
// Update projection.
gl::UseProgram(self.program.id);
- self.program.update_projection(size.width, size.height, size.padding_x, size.padding_y);
+ self.program.update_projection(
+ size.width(),
+ size.height(),
+ size.padding_x(),
+ size.padding_y(),
+ );
gl::UseProgram(0);
}
}
@@ -870,8 +846,8 @@ impl QuadRenderer {
}
// Calculate rectangle position.
- let center_x = size.width / 2.;
- let center_y = size.height / 2.;
+ let center_x = size.width() / 2.;
+ let center_y = size.height() / 2.;
let x = (rect.x - center_x) / center_x;
let y = -(rect.y - center_y) / center_y;
let width = rect.width / center_x;
@@ -1226,7 +1202,7 @@ impl TextShaderProgram {
fn set_term_uniforms(&self, props: &SizeInfo) {
unsafe {
- gl::Uniform2f(self.u_cell_dim, props.cell_width, props.cell_height);
+ gl::Uniform2f(self.u_cell_dim, props.cell_width(), props.cell_height());
}
}
diff --git a/alacritty/src/renderer/rects.rs b/alacritty/src/renderer/rects.rs
index 83b59cb3..ca0bbd1c 100644
--- a/alacritty/src/renderer/rects.rs
+++ b/alacritty/src/renderer/rects.rs
@@ -99,14 +99,14 @@ impl RenderLine {
mut thickness: f32,
color: Rgb,
) -> RenderRect {
- let start_x = start.col.0 as f32 * size.cell_width;
- let end_x = (end.col.0 + 1) as f32 * size.cell_width;
+ let start_x = start.col.0 as f32 * size.cell_width();
+ let end_x = (end.col.0 + 1) as f32 * size.cell_width();
let width = end_x - start_x;
// Make sure lines are always visible.
thickness = thickness.max(1.);
- let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height;
+ let line_bottom = (start.line.0 as f32 + 1.) * size.cell_height();
let baseline = line_bottom + descent;
let mut y = (baseline - position - thickness / 2.).ceil();
@@ -115,7 +115,14 @@ impl RenderLine {
y = max_y;
}
- RenderRect::new(start_x + size.padding_x, y + size.padding_y, width, thickness, color, 1.)
+ RenderRect::new(
+ start_x + size.padding_x(),
+ y + size.padding_y(),
+ width,
+ thickness,
+ color,
+ 1.,
+ )
}
}
diff --git a/alacritty/src/window.rs b/alacritty/src/window.rs
index 3319dce8..92fedc86 100644
--- a/alacritty/src/window.rs
+++ b/alacritty/src/window.rs
@@ -137,6 +137,9 @@ pub struct Window {
#[cfg(not(any(target_os = "macos", windows)))]
pub wayland_surface: Option<Attached<WlSurface>>,
+ /// Cached DPR for quickly scaling pixel sizes.
+ pub dpr: f64,
+
windowed_context: WindowedContext<PossiblyCurrent>,
current_mouse_cursor: CursorIcon,
mouse_visible: bool,
@@ -192,6 +195,8 @@ impl Window {
wayland_surface = Some(proxy.attach(wayland_event_queue.as_ref().unwrap().token()));
}
+ let dpr = windowed_context.window().scale_factor();
+
Ok(Self {
current_mouse_cursor,
mouse_visible: true,
@@ -200,6 +205,7 @@ impl Window {
should_draw: Arc::new(AtomicBool::new(true)),
#[cfg(not(any(target_os = "macos", windows)))]
wayland_surface,
+ dpr,
})
}
@@ -211,10 +217,6 @@ impl Window {
self.window().inner_size()
}
- pub fn scale_factor(&self) -> f64 {
- self.window().scale_factor()
- }
-
#[inline]
pub fn set_visible(&self, visibility: bool) {
self.window().set_visible(visibility);
@@ -387,11 +389,9 @@ impl Window {
/// Adjust the IME editor position according to the new location of the cursor.
#[cfg(not(windows))]
- pub fn update_ime_position(&mut self, point: Point, size_info: &SizeInfo) {
- let SizeInfo { cell_width, cell_height, padding_x, padding_y, .. } = size_info;
-
- let nspot_x = f64::from(padding_x + point.col.0 as f32 * cell_width);
- let nspot_y = f64::from(padding_y + (point.line.0 + 1) as f32 * cell_height);
+ pub fn update_ime_position(&mut self, point: Point, size: &SizeInfo) {
+ let nspot_x = f64::from(size.padding_x() + point.col.0 as f32 * size.cell_width());
+ let nspot_y = f64::from(size.padding_y() + (point.line.0 + 1) as f32 * size.cell_height());
self.window().set_ime_position(PhysicalPosition::new(nspot_x, nspot_y));
}