Skip to content

Fix #5543: release raster graphics when their view stops being rendered#5547

Merged
tig merged 2 commits into
developfrom
fix/5543-raster-graphics-linger
Jun 27, 2026
Merged

Fix #5543: release raster graphics when their view stops being rendered#5547
tig merged 2 commits into
developfrom
fix/5543-raster-graphics-linger

Conversation

@tig

@tig tig commented Jun 27, 2026

Copy link
Copy Markdown
Member

Fixes #5543.

Problem

A modal Dialog (or any overlapping view) hosting a raster ImageView (UseRasterGraphics = true, rendering via Sixel or the Kitty graphics protocol) left its graphics on screen after it stopped being rendered. Closing the dialog erased the cell grid, but the out-of-band Sixel DCS / Kitty placement lingered over the restored view until the next full-screen clear.

Root cause

A RasterImageCommand lives in the driver-level output buffer keyed by the owning view, but nothing removed it when the owning view stopped drawing — only explicit Dispose / Image = null did. Closing a modal doesn't dispose its subviews, so the command (and the terminal-resident graphic) survived. This is general to any overlapping ImageView, not specific to Dialog/Runnable.

Fix

Reconcile the buffer's raster images against the rendered view hierarchy on each draw:

  • IOutputBuffer / OutputBufferImpl: add RetainRasterImages(activeIds) — drops every raster command whose id is not active and marks its covered cells dirty.
  • View: add internal virtual CollectActiveRasterImageIds (skips invisible subtrees).
  • ImageView / ProgressBar: override to report their active raster id while rendering.
  • ApplicationImpl.LayoutAndDraw: after View.Draw, collect the ids still owned by rendered views and call RetainRasterImages to release the rest.

Dropping a command marks its cells dirty, so the next Refresh repaints them (overwriting Sixel) and emits the Kitty delete for vanished placements. Callers no longer need the ClearScreenNextIteration / ClearContents workaround from the issue.

Tests

UnitTestsParallelizable:

  • ImageView raster released when removed from SuperView, hidden, its container removed, and when a modal runnable ends (the exact issue scenario).
  • Direct RetainRasterImages buffer tests (unlisted images removed + cells invalidated; empty active set removes all).

Full parallelizable suite: 17,442 passed, 0 failed, 17 skipped. No new build warnings.

🤖 Generated with Claude Code

tig and others added 2 commits June 25, 2026 12:05
A view hosting a raster ImageView (UseRasterGraphics, Sixel/Kitty) left its
out-of-band graphic on screen after it stopped being rendered — closing a modal
Dialog, hiding the ImageView, or removing it (or its container) from the
hierarchy. The cells were repainted, but the Sixel DCS / Kitty placement is not
part of the cell grid, so it lingered until the next full-screen clear.

Root cause: a RasterImageCommand lives in the driver-level output buffer keyed by
the owning view, but nothing removed it when the owning view stopped drawing
(only explicit Dispose / Image=null did). This is general to any overlapping
ImageView, not specific to Dialog/Runnable.

Fix: reconcile the buffer's raster images against the rendered view hierarchy on
each draw. After View.Draw, the application collects the ids of raster images
owned by views that are still rendered (CollectActiveRasterImageIds, overridden
by ImageView and ProgressBar) and calls IOutputBuffer.RetainRasterImages to drop
the rest. Dropping a command marks its covered cells dirty, so the next Refresh
repaints them and emits the Kitty delete for vanished placements.

- IOutputBuffer/OutputBufferImpl: add RetainRasterImages(activeIds)
- View: add internal virtual CollectActiveRasterImageIds (skips invisible subtrees)
- ImageView/ProgressBar: override to report their active raster id
- ApplicationImpl.LayoutAndDraw: reconcile after drawing

Tests (UnitTestsParallelizable): ImageView raster released when removed, hidden,
its container removed, and when a modal runnable ends; plus direct
RetainRasterImages buffer tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tig tig requested a review from Copilot June 27, 2026 22:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Comment thread Tests/UnitTestsParallelizable/Views/ImageViewTests.cs
Comment thread Tests/UnitTestsParallelizable/Views/ImageViewTests.cs
Comment thread Tests/UnitTestsParallelizable/Views/ImageViewTests.cs
Comment thread Tests/UnitTestsParallelizable/Views/ImageViewTests.cs
Comment thread Tests/UnitTestsParallelizable/Drivers/Output/OutputBaseTests.cs
Comment thread Tests/UnitTestsParallelizable/Drivers/Output/OutputBaseTests.cs
@tig tig merged commit 5fd918d into develop Jun 27, 2026
15 checks passed
@tig tig deleted the fix/5543-raster-graphics-linger branch June 27, 2026 23:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dialog hosting a raster ImageView leaves its Sixel/Kitty graphics on screen after it closes

2 participants