summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2021-04-15 22:16:31 +0000
committerGitHub <noreply@github.com>2021-04-15 22:16:31 +0000
commit9cb55621f77a8eeca3738013ef9b1274b7a97e96 (patch)
tree4ccd2f192ee230af1c0e52dcd6614f9ac80d4f37
parent1f46bb7b925e5a6ce2dc4e5eeb88449d4cb8ebc5 (diff)
downloadalacritty-9cb55621f77a8eeca3738013ef9b1274b7a97e96.tar.gz
alacritty-9cb55621f77a8eeca3738013ef9b1274b7a97e96.zip
Fix mouse point crash on resize
This resolves an issue with Alacritty crashing after a resize, due to the last cached mouse point being out of bounds. Instead of caching the mouse point, it is now computed on demand to make sure it can never be invalid. Fixes #4977.
-rw-r--r--alacritty/src/display/mod.rs2
-rw-r--r--alacritty/src/event.rs27
-rw-r--r--alacritty/src/input.rs119
3 files changed, 76 insertions, 72 deletions
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index 6e40e35c..810d20f3 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -680,7 +680,7 @@ impl Display {
}
// Find highlighted hint at mouse position.
- let point = viewport_to_point(term.grid().display_offset(), mouse.point);
+ let point = mouse.point(&self.size_info, term.grid().display_offset());
let highlighted_hint = hint::highlighted_at(&term, config, point, modifiers);
// Update cursor shape.
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 3b24de0f..e61354b8 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -209,12 +209,12 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
&& self.terminal.selection.as_ref().map(|s| s.is_empty()) != Some(true)
{
self.update_selection(self.terminal.vi_mode_cursor.point, Side::Right);
- } else if self.mouse().left_button_state == ElementState::Pressed
- || self.mouse().right_button_state == ElementState::Pressed
+ } else if self.mouse.left_button_state == ElementState::Pressed
+ || self.mouse.right_button_state == ElementState::Pressed
{
let display_offset = self.terminal.grid().display_offset();
- let point = display::viewport_to_point(display_offset, self.mouse().point);
- self.update_selection(point, self.mouse().cell_side);
+ let point = self.mouse.point(&self.size_info(), display_offset);
+ self.update_selection(point, self.mouse.cell_side);
}
*self.dirty = true;
@@ -891,7 +891,6 @@ pub struct Mouse {
pub block_hint_launcher: bool,
pub hint_highlight_dirty: bool,
pub inside_text_area: bool,
- pub point: Point<usize>,
pub x: usize,
pub y: usize,
}
@@ -911,13 +910,29 @@ impl Default for Mouse {
inside_text_area: Default::default(),
lines_scrolled: Default::default(),
scroll_px: Default::default(),
- point: Default::default(),
x: Default::default(),
y: Default::default(),
}
}
}
+impl Mouse {
+ /// Convert mouse pixel coordinates to viewport point.
+ ///
+ /// If the coordinates are outside of the terminal grid, like positions inside the padding, the
+ /// coordinates will be clamped to the closest grid coordinates.
+ #[inline]
+ pub fn point(&self, size: &SizeInfo, display_offset: usize) -> Point {
+ let col = self.x.saturating_sub(size.padding_x() as usize) / (size.cell_width() as usize);
+ let col = min(Column(col), size.last_column());
+
+ let line = self.y.saturating_sub(size.padding_y() as usize) / (size.cell_height() as usize);
+ let line = min(line, size.bottommost_line().0 as usize);
+
+ display::viewport_to_point(display_offset, Point::new(line, col))
+ }
+}
+
/// The event processor.
///
/// Stores some state from received events and dispatches actions when they are
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 7dd47803..0fd2b224 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -33,7 +33,7 @@ use crate::config::{Action, BindingMode, Config, Key, SearchAction, ViAction};
use crate::daemon::start_daemon;
use crate::display::hint::HintMatch;
use crate::display::window::Window;
-use crate::display::{self, Display};
+use crate::display::Display;
use crate::event::{ClickState, Event, Mouse, TYPING_SEARCH_DELAY};
use crate::message_bar::{self, Message};
use crate::scheduler::{Scheduler, TimerId};
@@ -341,17 +341,19 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.update_selection_scrolling(y);
}
+ let display_offset = self.ctx.terminal().grid().display_offset();
+ let old_point = self.ctx.mouse().point(&size_info, display_offset);
+
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;
let inside_text_area = size_info.contains_point(x, y);
- let point = self.coords_to_point(x, y);
let cell_side = self.cell_side(x);
- let cell_changed = point != self.ctx.mouse().point;
+ let point = self.ctx.mouse().point(&size_info, display_offset);
+ let cell_changed = old_point != point;
// If the mouse hasn't changed cells, do nothing.
if !cell_changed
@@ -363,7 +365,6 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.ctx.mouse_mut().inside_text_area = inside_text_area;
self.ctx.mouse_mut().cell_side = cell_side;
- self.ctx.mouse_mut().point = point;
// Update mouse state and check for URL change.
let mouse_state = self.cursor_state();
@@ -377,11 +378,8 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
if (lmb_pressed || rmb_pressed) && (self.ctx.modifiers().shift() || !self.ctx.mouse_mode())
{
- let display_offset = self.ctx.terminal().grid().display_offset();
- let point = display::viewport_to_point(display_offset, point);
self.ctx.update_selection(point, cell_side);
} else if cell_changed
- && point.line < self.ctx.terminal().screen_lines()
&& self.ctx.terminal().mode().intersects(TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG)
{
if lmb_pressed {
@@ -396,23 +394,6 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
}
}
- /// Convert window space pixels to terminal grid coordinates.
- ///
- /// If the coordinates are outside of the terminal grid, like positions inside the padding, the
- /// coordinates will be clamped to the closest grid coordinates.
- #[inline]
- fn coords_to_point(&self, x: usize, y: usize) -> Point<usize> {
- let size = self.ctx.size_info();
-
- let column = x.saturating_sub(size.padding_x() as usize) / (size.cell_width() as usize);
- let column = min(Column(column), size.last_column());
-
- let line = y.saturating_sub(size.padding_y() as usize) / (size.cell_height() as usize);
- let line = min(line, size.bottommost_line().0 as usize);
-
- Point::new(line, column)
- }
-
/// Check which side of a cell an X coordinate lies on.
fn cell_side(&self, x: usize) -> Side {
let size_info = self.ctx.size_info();
@@ -435,13 +416,45 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
}
}
- fn normal_mouse_report(&mut self, button: u8) {
- let Point { line, column } = self.ctx.mouse().point;
+ fn mouse_report(&mut self, button: u8, state: ElementState) {
+ let display_offset = self.ctx.terminal().grid().display_offset();
+ let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset);
+
+ // Assure the mouse point is not in the scrollback.
+ if point.line >= 0 {
+ return;
+ }
+
+ // Calculate modifiers value.
+ let mut mods = 0;
+ let modifiers = self.ctx.modifiers();
+ if modifiers.shift() {
+ mods += 4;
+ }
+ if modifiers.alt() {
+ mods += 8;
+ }
+ if modifiers.ctrl() {
+ mods += 16;
+ }
+
+ // Report mouse events.
+ if self.ctx.terminal().mode().contains(TermMode::SGR_MOUSE) {
+ self.sgr_mouse_report(point, button + mods, state);
+ } else if let ElementState::Released = state {
+ self.normal_mouse_report(point, 3 + mods);
+ } else {
+ self.normal_mouse_report(point, button + mods);
+ }
+ }
+
+ fn normal_mouse_report(&mut self, point: Point, button: u8) {
+ let Point { line, column } = point;
let utf8 = self.ctx.terminal().mode().contains(TermMode::UTF8_MOUSE);
let max_point = if utf8 { 2015 } else { 223 };
- if line >= max_point || column >= Column(max_point) {
+ if line >= max_point || column >= max_point {
return;
}
@@ -461,49 +474,24 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
}
if utf8 && line >= 95 {
- msg.append(&mut mouse_pos_encode(line));
+ msg.append(&mut mouse_pos_encode(line.0 as usize));
} else {
- msg.push(32 + 1 + line as u8);
+ msg.push(32 + 1 + line.0 as u8);
}
self.ctx.write_to_pty(msg);
}
- fn sgr_mouse_report(&mut self, button: u8, state: ElementState) {
- let Point { line, column } = self.ctx.mouse().point;
+ fn sgr_mouse_report(&mut self, point: Point, button: u8, state: ElementState) {
let c = match state {
ElementState::Pressed => 'M',
ElementState::Released => 'm',
};
- let msg = format!("\x1b[<{};{};{}{}", button, column + 1, line + 1, c);
+ let msg = format!("\x1b[<{};{};{}{}", button, point.column + 1, point.line + 1, c);
self.ctx.write_to_pty(msg.into_bytes());
}
- fn mouse_report(&mut self, button: u8, state: ElementState) {
- // Calculate modifiers value.
- let mut mods = 0;
- let modifiers = self.ctx.modifiers();
- if modifiers.shift() {
- mods += 4;
- }
- if modifiers.alt() {
- mods += 8;
- }
- if modifiers.ctrl() {
- mods += 16;
- }
-
- // Report mouse events.
- if self.ctx.terminal().mode().contains(TermMode::SGR_MOUSE) {
- self.sgr_mouse_report(button + mods, state);
- } else if let ElementState::Released = state {
- self.normal_mouse_report(3 + mods);
- } else {
- self.normal_mouse_report(button + mods);
- }
- }
-
fn on_mouse_press(&mut self, button: MouseButton) {
// Handle mouse mode.
if !self.ctx.modifiers().shift() && self.ctx.mouse_mode() {
@@ -543,7 +531,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// Load mouse point, treating message bar and padding as the closest cell.
let display_offset = self.ctx.terminal().grid().display_offset();
- let point = display::viewport_to_point(display_offset, self.ctx.mouse().point);
+ let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset);
match button {
MouseButton::Left => self.on_left_click(point),
@@ -921,10 +909,13 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
+ size.cell_height() as usize * (size.screen_lines() + search_height);
let mouse = self.ctx.mouse();
+ let display_offset = self.ctx.terminal().grid().display_offset();
+ let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset);
+
if self.ctx.message().is_none() || (mouse.y <= terminal_end) {
None
} else if mouse.y <= terminal_end + size.cell_height() as usize
- && mouse.point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns()
+ && point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns()
{
Some(CursorIcon::Hand)
} else {
@@ -934,13 +925,11 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
/// Icon state of the cursor.
fn cursor_state(&mut self) -> CursorIcon {
- // Define function to check if mouse is on top of a hint.
let display_offset = self.ctx.terminal().grid().display_offset();
- let mouse_point = self.ctx.mouse().point;
- let hint_highlighted = |hint: &HintMatch| {
- let point = display::viewport_to_point(display_offset, mouse_point);
- hint.bounds.contains(&point)
- };
+ let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset);
+
+ // Function to check if mouse is on top of a hint.
+ let hint_highlighted = |hint: &HintMatch| hint.bounds.contains(&point);
if let Some(mouse_state) = self.message_bar_cursor_state() {
mouse_state