Skip to content

Commit

Permalink
fix(mouse): avoid forwarding click events on pane border (zellij-org#…
Browse files Browse the repository at this point in the history
…1584)

* if left click is on pane border do not forward to application

* properly handle frames

* fix comment

* fix another comment

* add tests, fix edge case
  • Loading branch information
tlinford authored and imsnif committed Jul 18, 2022
1 parent 7724ddb commit db83b8c
Show file tree
Hide file tree
Showing 2 changed files with 300 additions and 24 deletions.
255 changes: 254 additions & 1 deletion zellij-server/src/panes/unit/terminal_pane_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::collections::HashMap;
use std::rc::Rc;
use zellij_utils::{
data::{Palette, Style},
pane_size::{PaneGeom, SizeInPixels},
pane_size::{Offset, PaneGeom, SizeInPixels},
position::Position,
};

use std::fmt::Write;
Expand Down Expand Up @@ -391,3 +392,255 @@ pub fn keep_working_after_corrupted_sixel_image() {
terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
assert_snapshot!(format!("{:?}", terminal_pane.grid));
}

#[test]
pub fn pane_with_frame_position_is_on_frame() {
let mut fake_win_size = PaneGeom {
x: 10,
y: 10,
..PaneGeom::default()
};
fake_win_size.cols.set_inner(121);
fake_win_size.rows.set_inner(20);

let pid = 1;
let style = Style::default();
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
width: 8,
height: 21,
})));
let mut terminal_pane = TerminalPane::new(
pid,
fake_win_size,
style,
0,
String::new(),
Rc::new(RefCell::new(LinkHandler::new())),
character_cell_size,
sixel_image_store,
terminal_emulator_colors,
terminal_emulator_color_codes,
); // 0 is the pane index

terminal_pane.set_content_offset(Offset::frame(1));

// row above pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131)));

// first row: border for 10 <= col <= 130
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 10)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 11)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 129)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131)));

// second row: border only at col=10,130
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9)));
assert!(terminal_pane.position_is_on_frame(&Position::new(11, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(11, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131)));

// row in the middle: border only at col=10,130
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9)));
assert!(terminal_pane.position_is_on_frame(&Position::new(15, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(15, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131)));

// last row: border for 10 <= col <= 130
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 10)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 11)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131)));

// row below pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131)));
}

#[test]
pub fn pane_with_bottom_and_right_borders_position_is_on_frame() {
let mut fake_win_size = PaneGeom {
x: 10,
y: 10,
..PaneGeom::default()
};
fake_win_size.cols.set_inner(121);
fake_win_size.rows.set_inner(20);

let pid = 1;
let style = Style::default();
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
width: 8,
height: 21,
})));
let mut terminal_pane = TerminalPane::new(
pid,
fake_win_size,
style,
0,
String::new(),
Rc::new(RefCell::new(LinkHandler::new())),
character_cell_size,
sixel_image_store,
terminal_emulator_colors,
terminal_emulator_color_codes,
); // 0 is the pane index

terminal_pane.set_content_offset(Offset::shift(1, 1));

// row above pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131)));

// first row: border only at col=130
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 129)));
assert!(terminal_pane.position_is_on_frame(&Position::new(10, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131)));

// second row: border only at col=130
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(11, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131)));

// row in the middle: border only at col=130
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(15, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131)));

// last row: border for 10 <= col <= 130
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 10)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 11)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 70)));
assert!(terminal_pane.position_is_on_frame(&Position::new(29, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131)));

// row below pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131)));
}

#[test]
pub fn frameless_pane_position_is_on_frame() {
let mut fake_win_size = PaneGeom {
x: 10,
y: 10,
..PaneGeom::default()
};
fake_win_size.cols.set_inner(121);
fake_win_size.rows.set_inner(20);

let pid = 1;
let style = Style::default();
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
width: 8,
height: 21,
})));
let mut terminal_pane = TerminalPane::new(
pid,
fake_win_size,
style,
0,
String::new(),
Rc::new(RefCell::new(LinkHandler::new())),
character_cell_size,
sixel_image_store,
terminal_emulator_colors,
terminal_emulator_color_codes,
); // 0 is the pane index

terminal_pane.set_content_offset(Offset::default());

// row above pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131)));

// first row: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 129)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131)));

// second row: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131)));

// random row in the middle: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131)));

// last row: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131)));

// row below pane: no border
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130)));
assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131)));
}
69 changes: 46 additions & 23 deletions zellij-server/src/tab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,32 @@ pub trait Pane {
fn relative_position(&self, position_on_screen: &Position) -> Position {
position_on_screen.relative_to(self.get_content_y(), self.get_content_x())
}
fn position_is_on_frame(&self, position_on_screen: &Position) -> bool {
// TODO: handle cases where we have no frame
position_on_screen.line() == self.y() as isize
|| position_on_screen.line()
== (self.y() as isize + self.rows() as isize).saturating_sub(1)
|| position_on_screen.column() == self.x()
|| position_on_screen.column() == (self.x() + self.cols()).saturating_sub(1)
fn position_is_on_frame(&self, position: &Position) -> bool {
if !self.contains(position) {
return false;
}
if (self.x()..self.get_content_x()).contains(&position.column()) {
// position is on left border
return true;
}
if (self.get_content_x() + self.get_content_columns()..(self.x() + self.cols()))
.contains(&position.column())
{
// position is on right border
return true;
}
if (self.y() as isize..self.get_content_y() as isize).contains(&position.line()) {
// position is on top border
return true;
}
if ((self.get_content_y() + self.get_content_rows()) as isize
..(self.y() + self.rows()) as isize)
.contains(&position.line())
{
// position is on bottom border
return true;
}
false
}
fn store_pane_name(&mut self);
fn load_pane_name(&mut self);
Expand Down Expand Up @@ -1730,12 +1749,14 @@ impl Tab {
let relative_position = pane.relative_position(position);

if pane.mouse_mode() {
let mouse_event = format!(
"\u{1b}[<0;{:?};{:?}M",
relative_position.column.0 + 1,
relative_position.line.0 + 1
);
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
if !pane.position_is_on_frame(position) {
let mouse_event = format!(
"\u{1b}[<0;{:?};{:?}M",
relative_position.column() + 1,
relative_position.line() + 1
);
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
}
} else {
// TODO: rename this method, it is used to forward click events to plugin panes
pane.start_selection(&relative_position, client_id);
Expand All @@ -1751,12 +1772,14 @@ impl Tab {
if let Some(pane) = self.get_pane_at(position, false) {
let relative_position = pane.relative_position(position);
if pane.mouse_mode() {
let mouse_event = format!(
"\u{1b}[<2;{:?};{:?}M",
relative_position.column.0 + 1,
relative_position.line.0 + 1
);
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
if !pane.position_is_on_frame(position) {
let mouse_event = format!(
"\u{1b}[<2;{:?};{:?}M",
relative_position.column() + 1,
relative_position.line() + 1
);
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
}
} else {
pane.handle_right_click(&relative_position, client_id);
}
Expand Down Expand Up @@ -1798,11 +1821,11 @@ impl Tab {
let relative_position = active_pane.relative_position(position);
if active_pane.mouse_mode() {
// ensure that coordinates are valid
let col = (relative_position.column.0 + 1)
let col = (relative_position.column() + 1)
.max(1)
.min(active_pane.get_content_columns());

let line = (relative_position.line.0 + 1)
let line = (relative_position.line() + 1)
.max(1)
.min(active_pane.get_content_rows() as isize);
let mouse_event = format!("\u{1b}[<0;{:?};{:?}m", col, line);
Expand Down Expand Up @@ -1861,11 +1884,11 @@ impl Tab {
let relative_position = active_pane.relative_position(position_on_screen);
if active_pane.mouse_mode() && !is_repeated {
// ensure that coordinates are valid
let col = (relative_position.column.0 + 1)
let col = (relative_position.column() + 1)
.max(1)
.min(active_pane.get_content_columns());

let line = (relative_position.line.0 + 1)
let line = (relative_position.line() + 1)
.max(1)
.min(active_pane.get_content_rows() as isize);

Expand Down

0 comments on commit db83b8c

Please sign in to comment.