Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Terminal.Gui/App/ApplicationImpl.Screen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,20 @@ public void LayoutAndDraw (bool forceRedraw = false)
// the whole tree.
View.Draw (views.ToArray ().Cast<View> (), forceRedraw);

// Release raster graphics (Sixel/Kitty) whose owning view is no longer rendered — hidden,
// removed from the hierarchy, or on a runnable that has ended. They are emitted out-of-band
// and persist on screen until explicitly deleted, so erasing their cells is not enough. See
// https://github.com/tui-cs/Terminal.Gui/issues/5543.
IOutputBuffer rasterBuffer = Driver.GetOutputBuffer ();
HashSet<string> activeRasterIds = [];

foreach (View? view in views)
{
view?.CollectActiveRasterImageIds (activeRasterIds);
}

rasterBuffer.RetainRasterImages (activeRasterIds);

Driver.Clip = new Region (clipRect);

// Cause the driver to flush any pending updates to the terminal
Expand Down
13 changes: 13 additions & 0 deletions Terminal.Gui/Drivers/Output/IOutputBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ public interface IOutputBuffer
/// <param name="id">The raster image command identifier.</param>
void RemoveRasterImage (string id);

/// <summary>
/// Removes every raster image command whose <see cref="RasterImageCommand.Id"/> is not in
/// <paramref name="activeIds"/>, marking the cells they covered dirty so they are repainted.
/// </summary>
/// <remarks>
/// Raster graphics (Sixel/Kitty) are emitted out-of-band and persist on screen until explicitly
/// deleted, so they linger after the view that transmitted them is no longer rendered (hidden,
/// removed, or on a runnable that has ended). The framework calls this after each draw with the ids
/// of the images still owned by rendered views, releasing the rest. See <see cref="RemoveRasterImage"/>.
/// </remarks>
/// <param name="activeIds">The ids of raster images still owned by a rendered view.</param>
void RetainRasterImages (IReadOnlyCollection<string> activeIds);

/// <summary>
/// Gets the raster image commands currently held by the output buffer.
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions Terminal.Gui/Drivers/Output/OutputBufferImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,26 @@ public void RemoveRasterImage (string id)
}
}

/// <inheritdoc/>
public void RetainRasterImages (IReadOnlyCollection<string> activeIds)
{
ArgumentNullException.ThrowIfNull (activeIds);

lock (_contentsLock)
{
for (int i = _rasterImages.Count - 1; i >= 0; i--)
{
if (_rasterImages [i].Id is { } id && activeIds.Contains (id))
{
continue;
}

MarkRasterImageCellsDirty (_rasterImages [i]);
_rasterImages.RemoveAt (i);
}
}
}

/// <inheritdoc/>
public IReadOnlyList<RasterImageCommand> GetRasterImages ()
{
Expand Down
25 changes: 25 additions & 0 deletions Terminal.Gui/ViewBase/View.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,31 @@
}
}

/// <summary>
/// Collects the ids of raster graphics (Sixel/Kitty) this view and its rendered SubViews currently keep
/// resident in the terminal. The framework calls this after drawing and passes the result to
/// <see cref="IOutputBuffer.RetainRasterImages"/> so raster graphics whose owning view is no longer
/// rendered (hidden, removed, or on a runnable that has ended) are released instead of lingering on screen.
/// </summary>
/// <remarks>
/// A view that transmits a raster image (e.g. <see cref="Views.ImageView"/>) overrides this to add its
/// id when it is currently rendering. Invisible views and their SubViews are skipped, so a view that was
/// hidden releases its raster graphics.
/// </remarks>
/// <param name="ids">The set to add active raster image ids to.</param>
internal virtual void CollectActiveRasterImageIds (HashSet<string> ids)
{
if (!Visible)
{
return;
}

foreach (View subView in InternalSubViews)
{
subView.CollectActiveRasterImageIds (ids);
}
}

/// <summary>
/// Draws the view if it needs to be drawn.
/// </summary>
Expand Down Expand Up @@ -782,7 +807,7 @@
/// <remarks>
/// <para>
/// The cull path skips <see cref="Draw(DrawContext?)"/>, hence <see cref="DoDrawComplete"/>, which
/// repopulates the <see cref="CachedDrawnRegion"/> that <see cref="GetViewsUnderLocation"/> consults

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Parallel Unit Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Validate Doc Snippets

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Validate Doc Snippets

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Build Validation (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (ubuntu-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Integration Tests (macos-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Performance Smoke Tests (Linux)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Performance Smoke Tests (Linux)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Performance Smoke Tests (Linux)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Performance Smoke Tests (Linux)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.

Check warning on line 810 in Terminal.Gui/ViewBase/View.Drawing.cs

View workflow job for this annotation

GitHub Actions / Non-Parallel Unit Tests (windows-latest)

Ambiguous reference in cref attribute: 'GetViewsUnderLocation'. Assuming 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)', but could have also matched other overloads including 'Terminal.Gui.ViewBase.View.GetViewsUnderLocation(Terminal.Gui.ViewBase.View, in System.Drawing.Point, Terminal.Gui.ViewBase.ViewportSettingsFlags)'.
/// for <see cref="ViewportSettingsFlags.TransparentMouse"/> layers. A view's own
/// <see cref="CachedDrawnRegion"/> is invalidated by <see cref="SetNeedsDraw()"/>, so a
/// <see cref="ViewportSettingsFlags.TransparentMouse"/> view that is culled would be left with a null
Expand Down
16 changes: 16 additions & 0 deletions Terminal.Gui/Views/ImageView/ImageView.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ protected override void OnFrameChanged (in Rectangle frame)
InvalidateScaledImage ();
}

/// <inheritdoc/>
internal override void CollectActiveRasterImageIds (HashSet<string> ids)
{
if (!Visible)
{
return;
}

base.CollectActiveRasterImageIds (ids);

if (IsUsingRasterGraphics && _image is { })
{
ids.Add (RasterImageId);
}
}

/// <summary>
/// Renders the image using cell-based rendering where each terminal cell
/// gets the background color of the corresponding pixel.
Expand Down
24 changes: 23 additions & 1 deletion Terminal.Gui/Views/ProgressBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public class ProgressBar : View, IDesignable
private int _fireEncoderMaxColors;
private int _fireFrame;
private readonly string _fireRasterImageId = $"{nameof (ProgressBar)}.{Guid.NewGuid ():N}.Fire";
private bool _fireRasterImageActive;
private float _fraction;
private bool _isActivity;
private bool _syncWithTerminal;
Expand Down Expand Up @@ -450,6 +451,7 @@ private bool DrawFireProgress (int filledCells)
};

driver.GetOutputBuffer ().AddRasterImage (command);
_fireRasterImageActive = true;

return true;
}
Expand Down Expand Up @@ -507,7 +509,27 @@ private sealed class FirePaletteBuilder : IStaticPaletteBuilder
public List<Color> BuildPalette (int maxColors) => [.. _firePalette.Take (maxColors)];
}

private void RemoveFireRasterImage () => Driver?.GetOutputBuffer ().RemoveRasterImage (_fireRasterImageId);
private void RemoveFireRasterImage ()
{
_fireRasterImageActive = false;
Driver?.GetOutputBuffer ().RemoveRasterImage (_fireRasterImageId);
}

/// <inheritdoc/>
internal override void CollectActiveRasterImageIds (HashSet<string> ids)
{
if (!Visible)
{
return;
}

base.CollectActiveRasterImageIds (ids);

if (_fireRasterImageActive)
{
ids.Add (_fireRasterImageId);
}
}

private void UpdateTerminalProgress ()
{
Expand Down
65 changes: 65 additions & 0 deletions Tests/UnitTestsParallelizable/Drivers/Output/OutputBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,71 @@ public void RemoveRasterImage_InvalidatesCoveredCells ()
Assert.True (buffer.DirtyLines [0]);
}

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
[Fact]
public void RetainRasterImages_RemovesUnlistedImages_AndInvalidatesTheirCells ()
{
// Arrange
AnsiOutput output = new ();
IOutputBuffer buffer = output.GetLastBuffer ()!;
buffer.SetSize (4, 4);
buffer.Clip = new Region (new Rectangle (0, 0, 4, 4));

RasterImageCommand keep = new ()
{
Id = "keep",
Pixels = CreateSolidImage (2, 2, new Color (255, 0, 0)),
DestinationCells = new Rectangle (0, 0, 2, 2)
};

RasterImageCommand drop = new ()
{
Id = "drop",
Pixels = CreateSolidImage (2, 2, new Color (0, 255, 0)),
DestinationCells = new Rectangle (2, 2, 2, 2)
};

buffer.AddRasterImage (keep);
buffer.AddRasterImage (drop);
buffer.DirtyLines [2] = false;
buffer.DirtyLines [3] = false;

// Act
buffer.RetainRasterImages (["keep"]);

// Assert
RasterImageCommand remaining = Assert.Single (buffer.GetRasterImages ());
Assert.Equal ("keep", remaining.Id);

// The dropped image's cells are invalidated so they get repainted.
Assert.True (buffer.Contents! [3, 3].IsDirty);
Assert.True (buffer.DirtyLines [3]);
}

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
[Fact]
public void RetainRasterImages_EmptyActiveIds_RemovesAll ()
{
// Arrange
AnsiOutput output = new ();
IOutputBuffer buffer = output.GetLastBuffer ()!;
buffer.SetSize (2, 2);
buffer.Clip = new Region (new Rectangle (0, 0, 2, 2));

buffer.AddRasterImage (new ()
{
Id = "image",
Pixels = CreateSolidImage (2, 2, new Color (255, 0, 0)),
DestinationCells = new Rectangle (0, 0, 2, 2)
});

// Act
buffer.RetainRasterImages ([]);

// Assert
Assert.Empty (buffer.GetRasterImages ());
}

// Copilot - GPT-5.5
[Fact]
public void GetRasterImages_ReturnsReadOnlySnapshot ()
Expand Down
133 changes: 133 additions & 0 deletions Tests/UnitTestsParallelizable/Views/ImageViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,139 @@ public void FitImageInViewportCells_WhenKittyOutputDisabled_UsesSixelResolution

#endregion Resolution Selection Consistency

#region Raster Cleanup (issue #5543)

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
// A raster ImageView removed from its SuperView (without being disposed) must not leave its
// out-of-band Sixel/Kitty graphic resident in the output buffer. See issue #5543.
[Fact]
public void RasterImage_Released_WhenRemovedFromSuperView ()
{
using IApplication app = Application.Create ();
app.Init (DriverRegistry.Names.ANSI);

DriverImpl driver = (DriverImpl)app.Driver!;
driver.SetSixelSupport (new () { IsSupported = true, Resolution = new (10, 10), MaxPaletteColors = 256 });

Runnable runnable = new () { Width = 10, Height = 10 };
app.Begin (runnable);

ImageView imageView = new () { Width = 4, Height = 4, Image = CreateCoordinateImage (4, 4) };
runnable.Add (imageView);
app.LayoutAndDraw ();

Assert.Single (driver.GetOutputBuffer ().GetRasterImages ());

runnable.Remove (imageView);
app.LayoutAndDraw ();

Assert.Empty (driver.GetOutputBuffer ().GetRasterImages ());

imageView.Dispose ();
runnable.Dispose ();
}

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
// A raster ImageView that becomes invisible must release its resident Sixel/Kitty graphic. See issue #5543.
[Fact]
public void RasterImage_Released_WhenHidden ()
{
using IApplication app = Application.Create ();
app.Init (DriverRegistry.Names.ANSI);

DriverImpl driver = (DriverImpl)app.Driver!;
driver.SetSixelSupport (new () { IsSupported = true, Resolution = new (10, 10), MaxPaletteColors = 256 });

Runnable runnable = new () { Width = 10, Height = 10 };
app.Begin (runnable);

ImageView imageView = new () { Width = 4, Height = 4, Image = CreateCoordinateImage (4, 4) };
runnable.Add (imageView);
app.LayoutAndDraw ();

Assert.Single (driver.GetOutputBuffer ().GetRasterImages ());

imageView.Visible = false;
app.LayoutAndDraw ();

Assert.Empty (driver.GetOutputBuffer ().GetRasterImages ());

runnable.Dispose ();
}

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
// A raster ImageView nested in a container that is removed (e.g. the container revealing the view
// beneath it) must release its resident Sixel/Kitty graphic. This generalizes the issue #5543 case
// beyond modal Dialogs to any overlapping container.
[Fact]
public void RasterImage_Released_WhenContainerRemoved ()
{
using IApplication app = Application.Create ();
app.Init (DriverRegistry.Names.ANSI);

DriverImpl driver = (DriverImpl)app.Driver!;
driver.SetSixelSupport (new () { IsSupported = true, Resolution = new (10, 10), MaxPaletteColors = 256 });

Runnable runnable = new () { Width = 10, Height = 10 };
app.Begin (runnable);

View container = new () { Width = 6, Height = 6 };
ImageView imageView = new () { Width = 4, Height = 4, Image = CreateCoordinateImage (4, 4) };
container.Add (imageView);
runnable.Add (container);
app.LayoutAndDraw ();

Assert.Single (driver.GetOutputBuffer ().GetRasterImages ());

runnable.Remove (container);
app.LayoutAndDraw ();

Assert.Empty (driver.GetOutputBuffer ().GetRasterImages ());

container.Dispose ();
runnable.Dispose ();
}

// Claude - Opus 4.8
Comment thread
tig marked this conversation as resolved.
// The issue #5543 scenario: a modal runnable hosting a raster ImageView leaves its Sixel/Kitty graphic
// on screen after it closes. When the modal session ends, its raster graphic must be released.
[Fact]
public void RasterImage_Released_WhenModalRunnableEnds ()
{
using IApplication app = Application.Create ();
app.Init (DriverRegistry.Names.ANSI);

DriverImpl driver = (DriverImpl)app.Driver!;
driver.SetSixelSupport (new () { IsSupported = true, Resolution = new (10, 10), MaxPaletteColors = 256 });
app.Driver!.SetScreenSize (10, 10);

Runnable main = new () { Width = 10, Height = 10 };
app.Begin (main);
app.LayoutAndDraw ();

Assert.Empty (driver.GetOutputBuffer ().GetRasterImages ());

// Run a modal runnable hosting a raster ImageView on top of the main view.
Runnable dialog = new () { Width = 6, Height = 6 };
ImageView imageView = new () { Width = 4, Height = 4, Image = CreateCoordinateImage (4, 4) };
dialog.Add (imageView);
SessionToken? dialogToken = app.Begin (dialog);
app.LayoutAndDraw ();

Assert.Single (driver.GetOutputBuffer ().GetRasterImages ());

// Close the modal — the main view is revealed and the dialog's graphic must not linger.
app.End (dialogToken!);
app.LayoutAndDraw ();

Assert.Empty (driver.GetOutputBuffer ().GetRasterImages ());

dialog.Dispose ();
main.Dispose ();
}

#endregion Raster Cleanup (issue #5543)

#region Helper Methods

/// <summary>Creates a solid-color image of the specified dimensions.</summary>
Expand Down
Loading