diff --git a/Examples/UICatalog/Scenarios/CombiningMarks.cs b/Examples/UICatalog/Scenarios/CombiningMarks.cs index 6e0467ce0..7d8437a23 100644 --- a/Examples/UICatalog/Scenarios/CombiningMarks.cs +++ b/Examples/UICatalog/Scenarios/CombiningMarks.cs @@ -13,7 +13,7 @@ public class CombiningMarks : Scenario top.DrawComplete += (s, e) => { // Forces reset _lineColsOffset because we're dealing with direct draw - Application.ClearScreenNextIteration = true; + Application.Top!.SetNeedsDraw (); var i = -1; top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616."); diff --git a/Examples/UICatalog/Scenarios/Shortcuts.cs b/Examples/UICatalog/Scenarios/Shortcuts.cs index 73ec7a5dd..c96dccd7c 100644 --- a/Examples/UICatalog/Scenarios/Shortcuts.cs +++ b/Examples/UICatalog/Scenarios/Shortcuts.cs @@ -12,6 +12,7 @@ public class Shortcuts : Scenario public override void Main () { Application.Init (); + var quitKey = Application.QuitKey; Window app = new (); app.Loaded += App_Loaded; @@ -19,6 +20,7 @@ public class Shortcuts : Scenario Application.Run (app); app.Dispose (); Application.Shutdown (); + Application.QuitKey = quitKey; } // Setting everything up in Loaded handler because we change the diff --git a/Terminal.Gui/App/Application.Screen.cs b/Terminal.Gui/App/Application.Screen.cs index cc9dcb0b6..1ceed1d7c 100644 --- a/Terminal.Gui/App/Application.Screen.cs +++ b/Terminal.Gui/App/Application.Screen.cs @@ -82,8 +82,8 @@ public static partial class Application // Screen related stuff /// Gets or sets whether the screen will be cleared, and all Views redrawn, during the next Application iteration. /// /// - /// This is typicall set to true when a View's changes and that view has no + /// This is typical set to true when a View's changes and that view has no /// SuperView (e.g. when is moved or resized. /// - public static bool ClearScreenNextIteration { get; set; } + internal static bool ClearScreenNextIteration { get; set; } } diff --git a/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs b/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs index 4c14cd6ed..6c5f806c7 100644 --- a/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs +++ b/Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs @@ -100,6 +100,8 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput private readonly nint _outputHandle; private nint _screenBuffer; private readonly bool _isVirtualTerminal; + private readonly ConsoleColor _foreground; + private readonly ConsoleColor _background; public WindowsOutput () { @@ -117,8 +119,16 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput if (_isVirtualTerminal) { - //Enable alternative screen buffer. - Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll); + if (Environment.GetEnvironmentVariable ("VSAPPIDNAME") is null) + { + //Enable alternative screen buffer. + Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll); + } + else + { + _foreground = Console.ForegroundColor; + _background = Console.BackgroundColor; + } } else { @@ -502,8 +512,18 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput if (_isVirtualTerminal) { - //Disable alternative screen buffer. - Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndRestoreAltBufferWithBackscroll); + if (Environment.GetEnvironmentVariable ("VSAPPIDNAME") is null) + { + //Disable alternative screen buffer. + Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndRestoreAltBufferWithBackscroll); + } + else + { + // Simulate restoring the color and clearing the screen. + Console.ForegroundColor = _foreground; + Console.BackgroundColor = _background; + Console.Clear (); + } } else { diff --git a/Terminal.Gui/ViewBase/View.Layout.cs b/Terminal.Gui/ViewBase/View.Layout.cs index 8f28cdba2..72bb409b3 100644 --- a/Terminal.Gui/ViewBase/View.Layout.cs +++ b/Terminal.Gui/ViewBase/View.Layout.cs @@ -239,6 +239,8 @@ public partial class View // Layout APIs _x = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (X)} cannot be null"); PosDimSet (); + + NeedsClearScreenNextIteration (); } } @@ -281,6 +283,8 @@ public partial class View // Layout APIs _y = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Y)} cannot be null"); PosDimSet (); + + NeedsClearScreenNextIteration (); } } @@ -339,6 +343,8 @@ public partial class View // Layout APIs OnHeightChanged, HeightChanged, out Dim _); + + NeedsClearScreenNextIteration (); } } @@ -425,6 +431,17 @@ public partial class View // Layout APIs OnWidthChanged, WidthChanged, out Dim _); + + NeedsClearScreenNextIteration (); + } + } + + private void NeedsClearScreenNextIteration () + { + if (Application.Top is { } && Application.Top == this && Application.TopLevels.Count == 1) + { + // If this is the only TopLevel, we need to redraw the screen + Application.ClearScreenNextIteration = true; } } @@ -653,10 +670,9 @@ public partial class View // Layout APIs { SuperView?.SetNeedsDraw (); } - else if (Application.TopLevels.Count == 1) + else { - // If this is the only TopLevel, we need to redraw the screen - Application.ClearScreenNextIteration = true; + NeedsClearScreenNextIteration (); } } diff --git a/Terminal.Gui/ViewBase/View.cs b/Terminal.Gui/ViewBase/View.cs index 3edf1e768..27c0780f7 100644 --- a/Terminal.Gui/ViewBase/View.cs +++ b/Terminal.Gui/ViewBase/View.cs @@ -378,7 +378,7 @@ public partial class View : IDisposable, ISupportInitializeNotification } else { - Application.ClearScreenNextIteration = true; + NeedsClearScreenNextIteration (); } } } diff --git a/Tests/IntegrationTests/UICatalog/ScenarioTests.cs b/Tests/IntegrationTests/UICatalog/ScenarioTests.cs index 7fa654e9e..12517df84 100644 --- a/Tests/IntegrationTests/UICatalog/ScenarioTests.cs +++ b/Tests/IntegrationTests/UICatalog/ScenarioTests.cs @@ -41,8 +41,9 @@ public class ScenarioTests : TestsAllViews _output.WriteLine ($"Running Scenario '{scenarioType}'"); var scenario = Activator.CreateInstance (scenarioType) as Scenario; + var scenarioName = scenario!.GetName (); - uint abortTime = 2000; + uint abortTime = 2200; object? timeout = null; var initialized = false; var shutdownGracefully = false; @@ -70,7 +71,7 @@ public class ScenarioTests : TestsAllViews Assert.True (initialized); - Assert.True (shutdownGracefully, $"Scenario Failed to Quit with {quitKey} after {abortTime}ms and {iterationCount} iterations. Force quit."); + Assert.True (shutdownGracefully, $"Scenario '{scenarioName}' Failed to Quit with {quitKey} after {abortTime}ms and {iterationCount} iterations. Force quit."); #if DEBUG_IDISPOSABLE Assert.Empty (View.Instances); @@ -91,11 +92,6 @@ public class ScenarioTests : TestsAllViews { Application.Iteration += OnApplicationOnIteration; initialized = true; - - lock (_timeoutLock) - { - timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback); - } } else { @@ -126,6 +122,15 @@ public class ScenarioTests : TestsAllViews void OnApplicationOnIteration (object? s, IterationEventArgs a) { + if (iterationCount == 0) + { + // Start the timeout countdown on the first iteration + lock (_timeoutLock) + { + timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback); + } + } + iterationCount++; if (Application.Initialized) diff --git a/Tests/UnitTests/Application/ApplicationScreenTests.cs b/Tests/UnitTests/Application/ApplicationScreenTests.cs index 0086cb01b..675b683ad 100644 --- a/Tests/UnitTests/Application/ApplicationScreenTests.cs +++ b/Tests/UnitTests/Application/ApplicationScreenTests.cs @@ -47,7 +47,7 @@ public class ApplicationScreenTests Assert.Equal (0, clearedContentsRaised); // Act - Application.Top.SetNeedsLayout (); + Application.Top!.SetNeedsLayout (); Application.LayoutAndDraw (); // Assert @@ -67,6 +67,20 @@ public class ApplicationScreenTests // Assert Assert.Equal (2, clearedContentsRaised); + // Act + Application.Top.Y = 1; + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (3, clearedContentsRaised); + + // Act + Application.Top.Height = 10; + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (4, clearedContentsRaised); + Application.End (rs); return; diff --git a/Tests/UnitTests/Application/SynchronizatonContextTests.cs b/Tests/UnitTests/Application/SynchronizatonContextTests.cs index 6546692df..e049dcb03 100644 --- a/Tests/UnitTests/Application/SynchronizatonContextTests.cs +++ b/Tests/UnitTests/Application/SynchronizatonContextTests.cs @@ -10,7 +10,7 @@ public class SyncrhonizationContextTests public void SynchronizationContext_CreateCopy () { ConsoleDriver.RunningUnitTests = true; - Application.Init (); + Application.Init (null, "fake"); SynchronizationContext context = SynchronizationContext.Current; Assert.NotNull (context); diff --git a/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs b/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs index 4e0774f1f..77ac743c0 100644 --- a/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs +++ b/Tests/UnitTests/Configuration/ConfigurationMangerTests.cs @@ -1010,8 +1010,6 @@ public class ConfigurationManagerTests (ITestOutputHelper output) finally { Disable (resetToHardCodedDefaults: true); - } } - } diff --git a/Tests/UnitTests/Views/ComboBoxTests.cs b/Tests/UnitTests/Views/ComboBoxTests.cs index 9466b47fb..a8caab2c7 100644 --- a/Tests/UnitTests/Views/ComboBoxTests.cs +++ b/Tests/UnitTests/Views/ComboBoxTests.cs @@ -525,7 +525,9 @@ public class ComboBoxTests (ITestOutputHelper output) Assert.True (cb.IsShow); Assert.Equal (-1, cb.SelectedItem); Assert.Equal ("", cb.Text); - + Assert.False (Application.ClearScreenNextIteration); + Assert.True (cb.NeedsLayout); + Assert.True (cb.NeedsDraw); cb.Layout (); cb.Draw ();