Fix #5543: release raster graphics when their view stops being rendered#5547
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5543.
Problem
A modal
Dialog(or any overlapping view) hosting a rasterImageView(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
RasterImageCommandlives in the driver-level output buffer keyed by the owning view, but nothing removed it when the owning view stopped drawing — only explicitDispose/Image = nulldid. Closing a modal doesn't dispose its subviews, so the command (and the terminal-resident graphic) survived. This is general to any overlappingImageView, not specific toDialog/Runnable.Fix
Reconcile the buffer's raster images against the rendered view hierarchy on each draw:
IOutputBuffer/OutputBufferImpl: addRetainRasterImages(activeIds)— drops every raster command whose id is not active and marks its covered cells dirty.View: addinternal virtual CollectActiveRasterImageIds(skips invisible subtrees).ImageView/ProgressBar: override to report their active raster id while rendering.ApplicationImpl.LayoutAndDraw: afterView.Draw, collect the ids still owned by rendered views and callRetainRasterImagesto release the rest.Dropping a command marks its cells dirty, so the next
Refreshrepaints them (overwriting Sixel) and emits the Kitty delete for vanished placements. Callers no longer need theClearScreenNextIteration/ClearContentsworkaround from the issue.Tests
UnitTestsParallelizable:ImageViewraster released when removed from SuperView, hidden, its container removed, and when a modal runnable ends (the exact issue scenario).RetainRasterImagesbuffer 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