From 28941256598e0a67392c1584f75e60f212666794 Mon Sep 17 00:00:00 2001 From: Olli Asikainen Date: Wed, 15 Apr 2026 00:32:06 +0300 Subject: [PATCH 1/4] fix island gap persisting after shell exit with hide-if-single MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shell-exit branch of CloseTerminal called resize_top_or_bottom_line but never re-applied the taffy layout, so sugarloaf.set_position kept using the old scaled_margin. With hide_if_single, the surviving tab left a tab-bar-sized gap at the top, and Renderer::run's per-panel is_dirty / force_full_damage gate also dropped the queued redraw, so the closed tab's last frame stayed on screen until the next user input. Re-apply the layout via update_dimensions and mark the screen dirty. The PTY performer follows up with a RioEvent::Render, so the existing event-driven redraw paints the surviving tab once the dirty flag clears the panel gate — no need to force a synchronous render from inside the event handler. --- frontends/rioterm/src/application.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/frontends/rioterm/src/application.rs b/frontends/rioterm/src/application.rs index a6f9096e76..eb030a0f57 100644 --- a/frontends/rioterm/src/application.rs +++ b/frontends/rioterm/src/application.rs @@ -499,6 +499,21 @@ impl ApplicationHandler for Application<'_> { } else { let size = route.window.screen.context_manager.len(); route.window.screen.resize_top_or_bottom_line(size); + // Re-apply taffy layout so sugarloaf.set_position reflects the + // updated scaled_margin (e.g. when hide_if_single transitions + // from 2 tabs to 1 tab via shell exit rather than close-tab action). + route + .window + .screen + .context_manager + .current_grid_mut() + .update_dimensions(&mut route.window.screen.sugarloaf); + // Mark the surviving tab dirty so Renderer::run's + // is_dirty / force_full_damage gate lets it through. + // The PTY performer follows up with a RioEvent::Render, + // so the queued redraw paints the new layout — no need + // to force a synchronous render from this handler. + route.window.screen.mark_dirty(); } } } From 7e33e04657748d4939440de0f6735a1bb4c1fe87 Mon Sep 17 00:00:00 2001 From: KOGA Mitsuhiro Date: Sun, 26 Apr 2026 23:58:45 +0900 Subject: [PATCH 2/4] fix: keep tab-bar margin transitions in sync with hide-if-single resize_top_or_bottom_line compared the new padding against dimension.margin, but apply_taffy_layout zeroes dimension.margin on every run. Once that has happened the "previous" margin reads as zero; when num_tabs drops to 1 and hide_if_single makes padding_y_top zero too, the comparison short-circuits and update_scaled_margin is never called. Compare against the grid's scaled_margin (divided by scale) instead, since that holds the authoritative current margin. Without this, closing the second tab with hide-if-single enabled left the tab-bar strip reserved at the top and terminal content drew below it instead of filling the freed area. --- frontends/rioterm/src/screen/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontends/rioterm/src/screen/mod.rs b/frontends/rioterm/src/screen/mod.rs index 070bf03c47..5f770ae6fd 100644 --- a/frontends/rioterm/src/screen/mod.rs +++ b/frontends/rioterm/src/screen/mod.rs @@ -1553,8 +1553,6 @@ impl Screen<'_> { } pub fn resize_top_or_bottom_line(&mut self, num_tabs: usize) { - let layout = self.context_manager.current().dimension; - let previous_margin = layout.margin; let padding_y_top = padding_top_from_config( &self.renderer.navigation, self.renderer.margin.top, @@ -1563,8 +1561,16 @@ impl Screen<'_> { ); let padding_y_bottom = self.renderer.margin.bottom; - if previous_margin.top != padding_y_top - || previous_margin.bottom != padding_y_bottom + // Compare against the grid's scaled_margin (the actual current margin) + // rather than dimension.margin, which apply_taffy_layout zeroes out and + // therefore cannot tell us whether the top-bar margin changed. + let scale = self.sugarloaf.scale_factor(); + let current_scaled_margin = self.context_manager.current_grid().scaled_margin; + let previous_margin_top = current_scaled_margin.top / scale; + let previous_margin_bottom = current_scaled_margin.bottom / scale; + + if previous_margin_top != padding_y_top + || previous_margin_bottom != padding_y_bottom { let current_dim = self.context_manager.current().dimension; if current_dim.font_size > 0.0 { @@ -1572,7 +1578,6 @@ impl Screen<'_> { s.font_size = current_dim.font_size; s.line_height = current_dim.line_height; - let scale = self.sugarloaf.scale_factor(); let d = self.context_manager.current_grid_mut(); d.update_scaled_margin(Margin::new( padding_y_top * scale, From ed73ff38ab735653e333a0bcbdb56e70e9407250 Mon Sep 17 00:00:00 2001 From: 0x0aa <38528110+0x0aa@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:01:29 +0900 Subject: [PATCH 3/4] skip island click handling when hidden --- frontends/rioterm/src/screen/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontends/rioterm/src/screen/mod.rs b/frontends/rioterm/src/screen/mod.rs index 5f770ae6fd..80a413bc86 100644 --- a/frontends/rioterm/src/screen/mod.rs +++ b/frontends/rioterm/src/screen/mod.rs @@ -2599,6 +2599,11 @@ impl Screen<'_> { let window_width = self.sugarloaf.window_size().width; let num_tabs = self.context_manager.len(); + // Island is hidden when hide_if_single is set with a single tab. + if self.renderer.navigation.hide_if_single && num_tabs <= 1 { + return false; + } + // Check if the color picker is open and the click hits a swatch if let Some(ref mut island) = self.renderer.island { if island.is_color_picker_open() { From fbe9dd367883a11838b940111656be4e008edb2e Mon Sep 17 00:00:00 2001 From: 0x0aa <38528110+0x0aa@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:01:32 +0900 Subject: [PATCH 4/4] skip island cursor override when hidden --- frontends/rioterm/src/application.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontends/rioterm/src/application.rs b/frontends/rioterm/src/application.rs index eb030a0f57..d31dfa4757 100644 --- a/frontends/rioterm/src/application.rs +++ b/frontends/rioterm/src/application.rs @@ -1362,13 +1362,16 @@ impl ApplicationHandler for Application<'_> { } } - // Check if mouse is over island and set cursor to default + // Check if mouse is over island and set cursor to default. + // Skip guard when island is hidden (hide_if_single + single tab). use crate::renderer::island::ISLAND_HEIGHT; let scale_factor = route.window.screen.sugarloaf.scale_factor(); let island_height_px = (ISLAND_HEIGHT * scale_factor) as f64; - if route.window.screen.renderer.navigation.is_enabled() - && y <= island_height_px - { + let num_tabs = route.window.screen.ctx().len(); + let nav = &route.window.screen.renderer.navigation; + let island_is_visible = + nav.is_enabled() && !(nav.hide_if_single && num_tabs <= 1); + if island_is_visible && y <= island_height_px { route.window.winit_window.set_cursor(CursorIcon::Default); return; }