diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-14 03:02:14 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-14 03:02:14 +0300 |
| commit | 21c1f8cf856affb875b5ab4302225a63f4563bdd (patch) | |
| tree | fc3fa607c4af3d9233f3ba7d905a4744ad25c215 /src/client/shell/composition.rs | |
| parent | add3dd28f91db1a2b33e9582c60ac9c1809c1bf5 (diff) | |
fix: hide only kitty image placements overlapping overlays (#4081)
Diffstat (limited to 'src/client/shell/composition.rs')
| -rw-r--r-- | src/client/shell/composition.rs | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/src/client/shell/composition.rs b/src/client/shell/composition.rs index 8e99059b..cee57d96 100644 --- a/src/client/shell/composition.rs +++ b/src/client/shell/composition.rs @@ -314,6 +314,7 @@ impl ClientShellState { }); blit_pane_surface(&mut frame, &surface.frame, layout.pane_surface); restore_mode_bar(&mut frame, mode_bar, mode_bar_cells.as_deref()); + let mut occlusion = crate::kitty_graphics::surface::Occlusion::default(); let has_selection = self .selection .as_ref() @@ -335,6 +336,7 @@ impl ClientShellState { hit, &self.config.palette, false, + &mut occlusion, ); } let selection_is_stale_copy_projection = !copy_surface_coherent @@ -346,6 +348,13 @@ impl ClientShellState { .is_some_and(|selection| selection.pane_id == hit.pane_id) }); if !selection_is_stale_copy_projection { + if let Some(selection) = + self.selection.as_ref().filter(|s| s.pane_id == hit.pane_id) + { + for rect in selection.visible_rects(hit.inner_rect, hit.scroll) { + occlusion.cover(rect); + } + } crate::ui::render_selection_highlight( self.selection.as_ref(), &mut composed, @@ -366,12 +375,13 @@ impl ClientShellState { hit, &self.config.palette, true, + &mut occlusion, ); } } frame.replace_from_ratatui_buffer_preserving_effects(&composed, cursor); } - self.render_link_hover(&mut frame); + self.render_link_hover(&mut frame, &mut occlusion); if self.mode == ClientShellMode::Copy { frame.cursor = None; if let Some(copy_mode) = self.copy_mode.as_ref() { @@ -390,6 +400,7 @@ impl ClientShellState { let mut composed = frame.to_ratatui_buffer()?; let x = hit.inner_rect.x + copy_mode.cursor.col; let y = hit.inner_rect.y + viewport_row as u16; + occlusion.cover(Rect::new(x, y, 1, 1)); composed[(x, y)].set_style( Style::default() .fg(match self.config.palette.panel_bg { @@ -433,17 +444,18 @@ impl ClientShellState { diagnostic_area, diagnostic, &self.config.palette, + |rect| occlusion.cover(rect), ); } let lifecycle_offset = active_lifecycle.as_ref().map_or(0, |(label, status)| { - let _ = endpoint_notices::render_lifecycle_banner( + occlusion.cover(endpoint_notices::render_lifecycle_banner( &mut composed, Rect::new(0, 0, cols, rows), label, *status, u16::from(has_config_diagnostic) + layout.mobile_header.height, &self.config.palette, - ); + )); 1 }); if let Some(notice) = self.visible_endpoint_notice.as_ref() { @@ -484,6 +496,7 @@ impl ClientShellState { ) }; } + occlusion.cover(self.hits.notification_toast); frame.replace_from_ratatui_buffer_preserving_effects(&composed, cursor); } if let Some(feedback) = self.copy_feedback.as_ref() { @@ -502,14 +515,14 @@ impl ClientShellState { self.config.clipboard_toast_position, self.hits.notification_toast, ); - crate::ui::render_copy_feedback_buffer( + occlusion.cover(crate::ui::render_copy_feedback_buffer( &mut composed, feedback_area, feedback, offset, self.config.clipboard_toast_position, &self.config.palette, - ); + )); frame.replace_from_ratatui_buffer_preserving_effects(&composed, cursor); } self.hits.popup = None; @@ -519,6 +532,7 @@ impl ClientShellState { if let Some(geometry) = crate::popup_size::resolve_popup_geometry(width, height, layout.pane_surface) { + occlusion.start_popup(geometry.outer); let mut composed = frame.to_ratatui_buffer()?; let block = ratatui::widgets::Block::default() .borders(ratatui::widgets::Borders::ALL) @@ -552,6 +566,7 @@ impl ClientShellState { && self.overlay.is_none() { let mut composed = frame.to_ratatui_buffer()?; + occlusion.cover(composed.area); super::mobile::render_mobile_switcher( &mut composed, Rect::new(0, 0, cols, rows), @@ -591,20 +606,27 @@ impl ClientShellState { self.hits.popup = None; } restore_mode_bar(&mut frame, mode_bar, mode_bar_cells.as_deref()); + if let Some(bar) = mode_bar { + occlusion.cover(bar); + } if let Some(overlay) = self.overlay.as_ref() { let mut composed = frame.to_ratatui_buffer()?; let cursor = if let ClientShellOverlay::ContextMenu(menu) = overlay { - self.hits.context_menu_rows = + let rendered = render::render_context_menu(&mut composed, menu, &self.config.palette)?; + occlusion.cover(rendered.area); + self.hits.context_menu_rows = rendered.menu_rows; None } else if let ClientShellOverlay::GlobalMenu(menu) = overlay { - self.hits.global_menu_rows = render::render_global_menu( + let rendered = render::render_global_menu( &mut composed, self.hits.global_launcher, menu, snapshot, &self.config.palette, )?; + occlusion.cover(rendered.area); + self.hits.global_menu_rows = rendered.menu_rows; None } else { let rendered = render::render_client_overlay( @@ -616,6 +638,7 @@ impl ClientShellState { &self.config.keybinds, &self.config.palette, )?; + occlusion.cover(rendered.area); self.hits.overlay_primary = rendered.primary; self.hits.overlay_clear = rendered.clear; self.hits.overlay_cancel = rendered.cancel; @@ -662,7 +685,7 @@ impl ClientShellState { self.hits.pane_splits.clear(); self.hits.popup = None; } - self.compose_graphics(&mut frame, layout); + self.compose_graphics(&mut frame, layout, &occlusion); Some(frame) } } @@ -685,6 +708,7 @@ fn render_client_copy_search_highlights( hit: &PaneHit, palette: &Palette, current_only: bool, + occlusion: &mut crate::kitty_graphics::surface::Occlusion, ) { let Some(copy_mode) = copy_mode.filter(|copy_mode| copy_mode.pane_id == hit.pane_id) else { return; @@ -726,7 +750,14 @@ fn render_client_copy_search_highlights( } else { hit.inner_rect.width.saturating_sub(1) }; - for col in start_col..=end_col.min(hit.inner_rect.width.saturating_sub(1)) { + let end_col = end_col.min(hit.inner_rect.width.saturating_sub(1)); + occlusion.cover(Rect::new( + hit.inner_rect.x.saturating_add(start_col), + hit.inner_rect.y.saturating_add(viewport_row), + end_col.saturating_add(1).saturating_sub(start_col), + 1, + )); + for col in start_col..=end_col { buffer[( hit.inner_rect.x.saturating_add(col), hit.inner_rect.y.saturating_add(viewport_row), |
