diff options
author | Aram Drevekenin <aram@poor.dev> | 2023-03-01 12:25:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-01 12:25:44 +0100 |
commit | a8b5bce9d9e6c080f3c57735ef689a74eb2124e5 (patch) | |
tree | 0157bf5faf052d8860ce9010b1ab6a80fd3adc2b | |
parent | d670c29649307ba575c71e267104f033f8600906 (diff) |
fix(sixel): report pixel size in winsize change ioctl (#2212)
* fix(sixel): report pixel size in winsize change ioctl
* style(fmt): rustfmt
-rw-r--r-- | zellij-server/src/os_input_output.rs | 50 | ||||
-rw-r--r-- | zellij-server/src/panes/floating_panes/mod.rs | 23 | ||||
-rw-r--r-- | zellij-server/src/panes/tiled_panes/mod.rs | 100 | ||||
-rw-r--r-- | zellij-server/src/tab/layout_applier.rs | 20 | ||||
-rw-r--r-- | zellij-server/src/tab/mod.rs | 77 | ||||
-rw-r--r-- | zellij-server/src/tab/unit/tab_integration_tests.rs | 9 | ||||
-rw-r--r-- | zellij-server/src/tab/unit/tab_tests.rs | 9 | ||||
-rw-r--r-- | zellij-server/src/unit/screen_tests.rs | 2 |
8 files changed, 246 insertions, 44 deletions
diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index e9caec061..873451dea 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -43,16 +43,24 @@ use std::{ pub use async_trait::async_trait; pub use nix::unistd::Pid; -fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) { +fn set_terminal_size_using_fd( + fd: RawFd, + columns: u16, + rows: u16, + width_in_pixels: Option<u16>, + height_in_pixels: Option<u16>, +) { // TODO: do this with the nix ioctl use libc::ioctl; use libc::TIOCSWINSZ; + let ws_xpixel = width_in_pixels.unwrap_or(0); + let ws_ypixel = height_in_pixels.unwrap_or(0); let winsize = Winsize { ws_col: columns, ws_row: rows, - ws_xpixel: 0, - ws_ypixel: 0, + ws_xpixel, + ws_ypixel, }; // TIOCGWINSZ is an u32, but the second argument to ioctl is u64 on // some platforms. When checked on Linux, clippy will complain about @@ -414,7 +422,7 @@ pub struct ServerOsInputOutput { // not connected to an fd (eg. // a command pane with a // non-existing command) - cached_resizes: Arc<Mutex<Option<BTreeMap<u32, (u16, u16)>>>>, // <terminal_id, (cols, rows)> + cached_resizes: Arc<Mutex<Option<BTreeMap<u32, (u16, u16, Option<u16>, Option<u16>)>>>>, // <terminal_id, (cols, rows, width_in_pixels, height_in_pixels)> } // async fn in traits is not supported by rust, so dtolnay's excellent async_trait macro is being @@ -448,7 +456,14 @@ impl AsyncReader for RawFdAsyncReader { /// The `ServerOsApi` trait represents an abstract interface to the features of an operating system that /// Zellij server requires. pub trait ServerOsApi: Send + Sync { - fn set_terminal_size_using_terminal_id(&self, id: u32, cols: u16, rows: u16) -> Result<()>; + fn set_terminal_size_using_terminal_id( + &self, + id: u32, + cols: u16, + rows: u16, + width_in_pixels: Option<u16>, + height_in_pixels: Option<u16>, + ) -> Result<()>; /// Spawn a new terminal, with a terminal action. The returned tuple contains the master file /// descriptor of the forked pseudo terminal and a [ChildId] struct containing process id's for /// the forked child process. @@ -501,7 +516,14 @@ pub trait ServerOsApi: Send + Sync { } impl ServerOsApi for ServerOsInputOutput { - fn set_terminal_size_using_terminal_id(&self, id: u32, cols: u16, rows: u16) -> Result<()> { + fn set_terminal_size_using_terminal_id( + &self, + id: u32, + cols: u16, + rows: u16, + width_in_pixels: Option<u16>, + height_in_pixels: Option<u16>, + ) -> Result<()> { let err_context = || { format!( "failed to set terminal id {} to size ({}, {})", @@ -509,7 +531,7 @@ impl ServerOsApi for ServerOsInputOutput { ) }; if let Some(cached_resizes) = self.cached_resizes.lock().unwrap().as_mut() { - cached_resizes.insert(id, (cols, rows)); + cached_resizes.insert(id, (cols, rows, width_in_pixels, height_in_pixels)); return Ok(()); } @@ -522,7 +544,7 @@ impl ServerOsApi for ServerOsInputOutput { { Some(Some(fd)) => { if cols > 0 && rows > 0 { - set_terminal_size_using_fd(*fd, cols, rows); + set_terminal_size_using_fd(*fd, cols, rows, width_in_pixels, height_in_pixels); } }, _ => { @@ -785,8 +807,16 @@ impl ServerOsApi for ServerOsInputOutput { fn apply_cached_resizes(&mut self) { let mut cached_resizes = self.cached_resizes.lock().unwrap().take(); if let Some(cached_resizes) = cached_resizes.as_mut() { - for (terminal_id, (cols, rows)) in cached_resizes.iter() { - let _ = self.set_terminal_size_using_terminal_id(*terminal_id, *cols, *rows); + for (terminal_id, (cols, rows, width_in_pixels, height_in_pixels)) in + cached_resizes.iter() + { + let _ = self.set_terminal_size_using_terminal_id( + *terminal_id, + *cols, + *rows, + width_in_pixels.clone(), + height_in_pixels.clone(), + ); } } } diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs index 399d16c98..765f0196d 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -26,7 +26,7 @@ use zellij_utils::{ errors::prelude::*, input::command::RunCommand, input::layout::FloatingPaneLayout, - pane_size::{Dimension, Offset, PaneGeom, Size, Viewport}, + pane_size::{Dimension, Offset, PaneGeom, Size, SizeInPixels, Viewport}, }; const RESIZE_INCREMENT_WIDTH: usize = 5; @@ -39,6 +39,7 @@ pub struct FloatingPanes { connected_clients: Rc<RefCell<HashSet<ClientId>>>, connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>, mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>, + character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, default_mode_info: ModeInfo, style: Style, session_is_mirrored: bool, @@ -59,6 +60,7 @@ impl FloatingPanes { connected_clients: Rc<RefCell<HashSet<ClientId>>>, connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>, mode_info: Rc<RefCell<HashMap<ClientId, ModeInfo>>>, + character_cell_size: Rc<RefCell<Option<SizeInPixels>>>, session_is_mirrored: bool, default_mode_info: ModeInfo, style: Style, @@ -72,6 +74,7 @@ impl FloatingPanes { connected_clients, connected_clients_in_app, mode_info, + character_cell_size, session_is_mirrored, default_mode_info, style, @@ -304,7 +307,8 @@ impl FloatingPanes { } else { pane.set_content_offset(Offset::default()); } - resize_pty!(pane, os_api, self.senders).with_context(|| err_context(&pane.pid()))?; + resize_pty!(pane, os_api, self.senders, self.character_cell_size) + .with_context(|| err_context(&pane.pid()))?; } Ok(()) } @@ -390,7 +394,7 @@ impl FloatingPanes { pub fn resize_pty_all_panes(&mut self, os_api: &mut Box<dyn ServerOsApi>) -> Result<()> { for pane in self.panes.values_mut() { - resize_pty!(pane, os_api, self.senders) + resize_pty!(pane, os_api, self.senders, self.character_cell_size) .with_context(|| format!("failed to resize PTY in pane {:?}", pane.pid()))?; } Ok(()) @@ -424,7 +428,8 @@ impl FloatingPanes { .with_context(err_context)?; for pane in self.panes.values_mut() { - resize_pty!(pane, os_api, self.senders).with_context(err_context)?; + resize_pty!(pane, os_api, self.senders, self.character_cell_size) + .with_context(err_context)?; } self.set_force_render(); return Ok(true); @@ -833,7 +838,7 @@ impl FloatingPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, os_api, self.senders).unwrap(); + resize_pty!(new_position, os_api, self.senders, self.character_cell_size).unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(&active_pane_id).unwrap(); @@ -841,7 +846,13 @@ impl FloatingPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, os_api, self.senders).unwrap(); + resize_pty!( + current_position, + os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.focus_pane_for_all_clients(active_pane_id); } diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 28941746e..ac0f8c635 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -300,7 +300,7 @@ impl TiledPanes { } } - resize_pty!(pane, self.os_api, self.senders).unwrap(); + resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap(); } self.reset_boundaries(); } @@ -781,7 +781,7 @@ impl TiledPanes { } for pane in self.panes.values_mut() { - resize_pty!(pane, self.os_api, self.senders).unwrap(); + resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap(); } self.reset_boundaries(); } @@ -1071,7 +1071,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(&active_pane_id).unwrap(); @@ -1079,7 +1085,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.focus_pane_for_all_clients(active_pane_id); self.set_pane_frames(self.draw_pane_frames); @@ -1123,7 +1135,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(&active_pane_id).unwrap(); @@ -1131,7 +1149,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.set_pane_frames(self.draw_pane_frames); } @@ -1159,7 +1183,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(active_pane_id).unwrap(); @@ -1167,7 +1197,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.set_pane_frames(self.draw_pane_frames); } @@ -1195,7 +1231,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(active_pane_id).unwrap(); @@ -1203,7 +1245,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.set_pane_frames(self.draw_pane_frames); } @@ -1231,7 +1279,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(active_pane_id).unwrap(); @@ -1239,7 +1293,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.set_pane_frames(self.draw_pane_frames); } @@ -1269,7 +1329,13 @@ impl TiledPanes { if let Some(geom) = prev_geom_override { new_position.set_geom_override(geom); } - resize_pty!(new_position, self.os_api, self.senders).unwrap(); + resize_pty!( + new_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); new_position.set_should_render(true); let current_position = self.panes.get_mut(active_pane_id).unwrap(); @@ -1277,7 +1343,13 @@ impl TiledPanes { if let Some(geom) = next_geom_override { current_position.set_geom_override(geom); } - resize_pty!(current_position, self.os_api, self.senders).unwrap(); + resize_pty!( + current_position, + self.os_api, + self.senders, + self.character_cell_size + ) + .unwrap(); current_position.set_should_render(true); self.set_pane_frames(self.draw_pane_frames); } diff --git a/zellij-server/src/tab/layout_applier.rs b/zellij-server/src/tab/layout_applier.rs index b2c3817bf..7964b6989 100644 --- a/zellij-server/src/tab/layout_applier.rs +++ b/zellij-server/src/tab/layout_applier.rs @@ -132,7 +132,7 @@ impl<'a> LayoutApplier<'a> { Some(position_and_size), ); pane_focuser.set_pane_id_in_focused_location(layout.focus, &pane); - resize_pty!(pane, self.os_api, self.senders)?; + resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)?; self.tiled_panes .add_pane_with_existing_geom(pane.pid(), pane); } @@ -305,7 +305,12 @@ impl<'a> LayoutApplier<'a> { ); new_pane.set_borderless(false); new_pane.set_content_offset(Offset::frame(1)); - resize_pty!(new_pane, self.os_api, self.senders)?; + resize_pty!( + new_pane, + self.os_api, + self.senders, + self.character_cell_size + )?; self.floating_panes .add_pane(PaneId::Plugin(pid), Box::new(new_pane)); if floating_pane_layout.focus.unwrap_or(false) { @@ -340,7 +345,12 @@ impl<'a> LayoutApplier<'a> { if let Some(held_command) = hold_for_command { new_pane.hold(None, true, held_command.clone()); } - resize_pty!(new_pane, self.os_api, self.senders)?; + resize_pty!( + new_pane, + self.os_api, + self.senders, + self.character_cell_size + )?; self.floating_panes .add_pane(PaneId::Terminal(*pid), Box::new(new_pane)); if floating_pane_layout.focus.unwrap_or(false) { @@ -398,7 +408,7 @@ impl<'a> LayoutApplier<'a> { .focus .or(Some(!layout_has_focused_pane)); pane_focuser.set_pane_id_in_focused_location(pane_is_focused, &pane); - resize_pty!(pane, self.os_api, self.senders)?; + resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)?; self.floating_panes.add_pane(pane.pid(), pane); } } @@ -415,7 +425,7 @@ impl<'a> LayoutApplier<'a> { ); pane_focuser .set_pane_id_in_focused_location(Some(!layout_has_focused_pane), &pane); - resize_pty!(pane, self.os_api, self.senders)?; + resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)?; self.floating_panes.add_pane(pane.pid(), pane); } }, diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index bcd549ccc..7cdef9619 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -63,6 +63,42 @@ macro_rules! resize_pty { *pid, $pane.get_content_columns() as u16, $pane.get_content_rows() as u16, + None, + None, + ), + PaneId::Plugin(ref pid) => { + let err_context = || format!("failed to resize plugin {pid}"); + $senders + .send_to_plugin(PluginInstruction::Resize( + *pid, + $pane.get_content_columns(), + $pane.get_content_rows(), + )) + .with_context(err_context) + }, + } + }}; + ($pane:expr, $os_input:expr, $senders:expr, $character_cell_size:expr) => {{ + let (width_in_pixels, height_in_pixels) = { + let character_cell_size = $character_cell_size.borrow(); + match *character_cell_size { + Some(size_in_pixels) => { + let width_in_pixels = + (size_in_pixels.width * $pane.get_content_columns()) as u16; + let height_in_pixels = + (size_in_pixels.height * $pane.get_content_rows()) as u16; + (Some(width_in_pixels), Some(height_in_pixels)) + }, + None => (None, None), + } + }; + match $pane.pid() { + PaneId::Terminal(ref pid) => $os_input.set_terminal_size_using_terminal_id( + *pid, + $pane.get_content_columns() as u16, + $pane.get_content_rows() as u16, + width_in_pixels, + height_in_pixels, ), PaneId::Plugin(ref pid) => { let err_context = || format!("failed to resize plugin {pid}"); @@ -490,6 +526,7 @@ impl Tab { connected_clients.clone(), connected_clients_in_app, mode_info.clone(), + character_cell_size.clone(), session_is_mirrored, default_mode_info.clone(), style, @@ -900,8 +937,13 @@ impl Tab { embedded_pane_to_float.set_content_offset(Offset::frame(1)); } embedded_pane_to_float.set_geom(new_pane_geom); - resize_pty!(embedded_pane_to_float, self.os_api, self.senders) - .with_context(err_context)?; + resize_pty!( + embedded_pane_to_float, + self.os_api, + self.senders, + self.character_cell_size + ) + .with_context(err_context)?; embedded_pane_to_float.set_active_at(Instant::now()); self.floating_panes .add_pane(focused_pane_id, embedded_pane_to_float); @@ -1001,7 +1043,13 @@ impl Tab { ); new_pane.set_active_at(Instant::now()); new_pane.set_content_offset(Offset::frame(1)); // floating panes always have a frame - resize_pty!(new_pane, self.os_api, self.senders).with_context(err_context)?; + resize_pty!( + new_pane, + self.os_api, + self.senders, + self.character_cell_size + ) + .with_context(err_context)?; self.floating_panes.add_pane(pid, Box::new(new_pane)); self.floating_panes.focus_pane_for_all_clients(pid); } @@ -1101,7 +1149,12 @@ impl Tab { self.get_active_pane(client_id) .with_context(|| format!("no active pane found for client {client_id}")) .and_then(|current_active_pane| { - resize_pty!(current_active_pane, self.os_api, self.senders) + resize_pty!( + current_active_pane, + self.os_api, + self.senders, + self.character_cell_size + ) }) .with_context(err_context)?; }, @@ -1375,8 +1428,13 @@ impl Tab { }) { if self.pids_waiting_resize.remove(&pid) { - resize_pty!(terminal_output, self.os_api, self.senders) - .with_context(err_context)?; + resize_pty!( + terminal_output, + self.os_api, + self.senders, + self.character_cell_size + ) + .with_context(err_context)?; } terminal_output.handle_pty_bytes(bytes); let messages_to_pty = terminal_output.drain_messages_to_pty(); @@ -2212,7 +2270,12 @@ impl Tab { // the pane there we replaced. Now, we need to update its pty about its new size. // We couldn't do that before, and we can't use the original moved item now - so we // need to refetch it - resize_pty!(suppressed_pane, self.os_api, self.senders)?; + resize_pty!( + suppressed_pane, + self.os_api, + self.senders, + self.character_cell_size + )?; } Ok(replaced_pane) }) diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 11de1c298..1652eb5ae 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -48,7 +48,14 @@ struct FakeInputOutput { } impl ServerOsApi for FakeInputOutput { - fn set_terminal_size_using_terminal_id(&self, _id: u32, _cols: u16, _rows: u16) -> Result<()> { + fn set_terminal_size_using_terminal_id( + &self, + _id: u32, + _cols: u16, + _rows: u16, + _width_in_pixels: Option<u16>, + _height_in_pixels: Option<u16>, + ) -> Result<()> { // noop Ok(()) } diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 8fbf66492..cb3d8f787 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -30,7 +30,14 @@ use zellij_utils::{ struct FakeInputOutput {} impl ServerOsApi for FakeInputOutput { - fn set_terminal_size_using_terminal_id(&self, _id: u32, _cols: u16, _rows: u16) -> Result<()> { + fn set_terminal_size_using_terminal_id( + &self, + _id: u32, + _cols: u16, + |