summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Linford <tlinford@users.noreply.github.com>2022-03-10 13:14:02 +0100
committerGitHub <noreply@github.com>2022-03-10 13:14:02 +0100
commit9961a28cb5b5e4a029e237d4e72157a0c1f1b23e (patch)
tree77a16ea7dc2a4d298aa075b8231d379e55421bc2
parentc38981c655dae4fc94e1a001b169d3ab1eda6c5e (diff)
feature(mouse): forward mouse events (#1191)
* handle sgr mouse mode enable by applications * forward mouse events * fix scroll events not forwarded to floating panes * improve mouse hold/release with floating panes
-rw-r--r--zellij-server/src/panes/grid.rs8
-rw-r--r--zellij-server/src/panes/plugin_pane.rs3
-rw-r--r--zellij-server/src/panes/terminal_pane.rs4
-rw-r--r--zellij-server/src/tab/mod.rs145
4 files changed, 132 insertions, 28 deletions
diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs
index dedf93412..fe1a81ea0 100644
--- a/zellij-server/src/panes/grid.rs
+++ b/zellij-server/src/panes/grid.rs
@@ -306,6 +306,7 @@ pub struct Grid {
pub link_handler: Rc<RefCell<LinkHandler>>,
pub ring_bell: bool,
scrollback_buffer_lines: usize,
+ pub mouse_mode: bool,
}
impl Debug for Grid {
@@ -363,6 +364,7 @@ impl Grid {
link_handler,
ring_bell: false,
scrollback_buffer_lines: 0,
+ mouse_mode: false,
}
}
pub fn render_full_viewport(&mut self) {
@@ -1773,6 +1775,9 @@ impl Perform for Grid {
Some(7) => {
self.disable_linewrap = true;
}
+ Some(1006) => {
+ self.mouse_mode = false;
+ }
_ => {}
};
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
@@ -1826,6 +1831,9 @@ impl Perform for Grid {
Some(7) => {
self.disable_linewrap = false;
}
+ Some(1006) => {
+ self.mouse_mode = true;
+ }
_ => {}
};
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index f5a11c845..8b21c8333 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -401,4 +401,7 @@ impl Pane for PluginPane {
))
.unwrap();
}
+ fn mouse_mode(&self) -> bool {
+ false
+ }
}
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index eca769869..5ac94c4f3 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -472,6 +472,10 @@ impl Pane for TerminalPane {
fn borderless(&self) -> bool {
self.borderless
}
+
+ fn mouse_mode(&self) -> bool {
+ self.grid.mouse_mode
+ }
}
impl TerminalPane {
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index d304aa61c..e33141f61 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -289,6 +289,7 @@ pub trait Pane {
fn set_borderless(&mut self, borderless: bool);
fn borderless(&self) -> bool;
fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {}
+ fn mouse_mode(&self) -> bool;
}
impl Tab {
@@ -975,6 +976,20 @@ impl Tab {
};
self.write_to_pane_id(input_bytes, pane_id);
}
+ pub fn write_to_terminal_at(&mut self, input_bytes: Vec<u8>, position: &Position) {
+ if self.floating_panes.panes_are_visible() {
+ let pane_id = self.floating_panes.get_pane_id_at(position, false);
+ if let Some(pane_id) = pane_id {
+ self.write_to_pane_id(input_bytes, pane_id);
+ return;
+ }
+ }
+
+ let pane_id = self.get_pane_id_at(position, false);
+ if let Some(pane_id) = pane_id {
+ self.write_to_pane_id(input_bytes, pane_id);
+ }
+ }
pub fn write_to_pane_id(&mut self, input_bytes: Vec<u8>, pane_id: PaneId) {
match pane_id {
PaneId::Terminal(active_terminal_id) => {
@@ -2288,15 +2303,35 @@ impl Tab {
}
pub fn scroll_terminal_up(&mut self, point: &Position, lines: usize, client_id: ClientId) {
if let Some(pane) = self.get_pane_at(point, false) {
- pane.scroll_up(lines, client_id);
+ if pane.mouse_mode() {
+ let relative_position = pane.relative_position(point);
+ let mouse_event = format!(
+ "\u{1b}[<64;{:?};{:?}M",
+ relative_position.column.0 + 1,
+ relative_position.line.0 + 1
+ );
+ self.write_to_terminal_at(mouse_event.into_bytes(), point);
+ } else {
+ pane.scroll_up(lines, client_id);
+ }
}
}
pub fn scroll_terminal_down(&mut self, point: &Position, lines: usize, client_id: ClientId) {
if let Some(pane) = self.get_pane_at(point, false) {
- pane.scroll_down(lines, client_id);
- if !pane.is_scrolled() {
- if let PaneId::Terminal(pid) = pane.pid() {
- self.process_pending_vte_events(pid);
+ if pane.mouse_mode() {
+ let relative_position = pane.relative_position(point);
+ let mouse_event = format!(
+ "\u{1b}[<65;{:?};{:?}M",
+ relative_position.column.0 + 1,
+ relative_position.line.0 + 1
+ );
+ self.write_to_terminal_at(mouse_event.into_bytes(), point);
+ } else {
+ pane.scroll_down(lines, client_id);
+ if !pane.is_scrolled() {
+ if let PaneId::Terminal(pid) = pane.pid() {
+ self.process_pending_vte_events(pid);
+ }
}
}
}
@@ -2348,8 +2383,18 @@ impl Tab {
if let Some(pane) = self.get_pane_at(position, false) {
let relative_position = pane.relative_position(position);
- pane.start_selection(&relative_position, client_id);
- self.selecting_with_mouse = true;
+
+ 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);
+ } else {
+ pane.start_selection(&relative_position, client_id);
+ self.selecting_with_mouse = true;
+ }
};
}
pub fn handle_right_click(&mut self, position: &Position, client_id: ClientId) {
@@ -2357,7 +2402,16 @@ impl Tab {
if let Some(pane) = self.get_pane_at(position, false) {
let relative_position = pane.relative_position(position);
- pane.handle_right_click(&relative_position, client_id);
+ 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);
+ } else {
+ pane.handle_right_click(&relative_position, client_id);
+ }
};
}
fn focus_pane_at(&mut self, point: &Position, client_id: ClientId) {
@@ -2392,38 +2446,73 @@ impl Tab {
}
}
pub fn handle_mouse_release(&mut self, position: &Position, client_id: ClientId) {
- if self.selecting_with_mouse {
- let mut selected_text = None;
- let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
- if let Some(active_pane) = active_pane {
- let relative_position = active_pane.relative_position(position);
+ if self.floating_panes.panes_are_visible()
+ && self.floating_panes.pane_is_being_moved_with_mouse()
+ {
+ self.floating_panes.stop_moving_pane_with_mouse(*position);
+ return;
+ }
+
+ let selecting = self.selecting_with_mouse;
+ let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
+
+ if let Some(active_pane) = active_pane {
+ 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)
+ .max(1)
+ .min(active_pane.get_content_columns());
+
+ let line = (relative_position.line.0 + 1)
+ .max(1)
+ .min(active_pane.get_content_rows() as isize);
+ let mouse_event = format!("\u{1b}[<0;{:?};{:?}m", col, line);
+ self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
+ } else if selecting {
active_pane.end_selection(&relative_position, client_id);
- selected_text = active_pane.get_selected_text();
+ let selected_text = active_pane.get_selected_text();
active_pane.reset_selection();
+ if let Some(selected_text) = selected_text {
+ self.write_selection_to_clipboard(&selected_text);
+ }
+ self.selecting_with_mouse = false;
}
-
- if let Some(selected_text) = selected_text {
- self.write_selection_to_clipboard(&selected_text);
- }
- self.selecting_with_mouse = false;
- } else if self.floating_panes.panes_are_visible() {
- self.floating_panes.stop_moving_pane_with_mouse(*position);
}
}
pub fn handle_mouse_hold(&mut self, position_on_screen: &Position, client_id: ClientId) {
let search_selectable = true;
- if self.selecting_with_mouse {
- let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
- if let Some(active_pane) = active_pane {
- let relative_position = active_pane.relative_position(position_on_screen);
- active_pane.update_selection(&relative_position, client_id);
- }
- } else if self.floating_panes.panes_are_visible()
+
+ if self.floating_panes.panes_are_visible()
+ && self.floating_panes.pane_is_being_moved_with_mouse()
&& self
.floating_panes
.move_pane_with_mouse(*position_on_screen, search_selectable)
{
self.set_force_render();
+ return;
+ }
+
+ let selecting = self.selecting_with_mouse;
+ let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
+
+ if let Some(active_pane) = active_pane {
+ let relative_position = active_pane.relative_position(position_on_screen);
+ if active_pane.mouse_mode() {
+ // ensure that coordinates are valid
+ let col = (relative_position.column.0 + 1)
+ .max(1)
+ .min(active_pane.get_content_columns());
+
+ let line = (relative_position.line.0 + 1)
+ .max(1)
+ .min(active_pane.get_content_rows() as isize);
+
+ let mouse_event = format!("\u{1b}[<32;{:?};{:?}M", col, line);
+ self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
+ } else if selecting {
+ active_pane.update_selection(&relative_position, client_id);
+ }
}
}