Jelajahi Sumber

Merge branch 'v2_develop' of tig:tig/Terminal.Gui into v2_develop

Tig 1 bulan lalu
induk
melakukan
55d1972bd5
100 mengubah file dengan 848 tambahan dan 2926 penghapusan
  1. 3 3
      .editorconfig
  2. 12 12
      Examples/UICatalog/Scenarios/Adornments.cs
  3. 1 1
      Examples/UICatalog/Scenarios/AllViewsTester.cs
  4. 1 1
      Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs
  5. 1 1
      Examples/UICatalog/Scenarios/Bars.cs
  6. 1 1
      Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
  7. 1 1
      Examples/UICatalog/Scenarios/Clipping.cs
  8. 1 1
      Examples/UICatalog/Scenarios/DimAutoDemo.cs
  9. 3 3
      Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs
  10. 5 5
      Examples/UICatalog/Scenarios/GraphViewExample.cs
  11. 3 3
      Examples/UICatalog/Scenarios/LineCanvasExperiment.cs
  12. 4 4
      Examples/UICatalog/Scenarios/PosAlignDemo.cs
  13. 1 1
      Examples/UICatalog/Scenarios/Shortcuts.cs
  14. 1 1
      Examples/UICatalog/Scenarios/TextInputControls.cs
  15. 2 2
      Examples/UICatalog/Scenarios/ViewportSettings.cs
  16. 1 1
      Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs
  17. 2 2
      Examples/UICatalog/UICatalog.cs
  18. 3 2
      Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs
  19. 4 111
      Terminal.Gui/App/Application.Lifecycle.cs
  20. 7 7
      Terminal.Gui/App/Application.Run.cs
  21. 8 20
      Terminal.Gui/App/Application.Screen.cs
  22. 8 0
      Terminal.Gui/App/Application.Toplevel.cs
  23. 5 5
      Terminal.Gui/App/Application.cs
  24. 21 34
      Terminal.Gui/App/ApplicationImpl.cs
  25. 5 0
      Terminal.Gui/App/IApplication.cs
  26. 6 6
      Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs
  27. 1 1
      Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs
  28. 1 1
      Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs
  29. 0 12
      Terminal.Gui/App/Timeout/ITimedEvents.cs
  30. 7 1
      Terminal.Gui/App/Timeout/TimedEvents.cs
  31. 8 5
      Terminal.Gui/Drawing/Ruler.cs
  32. 6 6
      Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs
  33. 32 29
      Terminal.Gui/Drawing/Thickness.cs
  34. 55 925
      Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs
  35. 1 1
      Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs
  36. 2 2
      Terminal.Gui/Drivers/ComponentFactory.cs
  37. 31 19
      Terminal.Gui/Drivers/ConsoleDriver.cs
  38. 37 25
      Terminal.Gui/Drivers/ConsoleDriverFacade.cs
  39. 1 1
      Terminal.Gui/Drivers/ConsoleKeyMapping.cs
  40. 35 0
      Terminal.Gui/Drivers/ConsoleSizeMonitor.cs
  41. 7 1
      Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs
  42. 59 0
      Terminal.Gui/Drivers/FakeDriver/FakeClipboard.cs
  43. 3 2
      Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs
  44. 3 3
      Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs
  45. 16 30
      Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs
  46. 33 177
      Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs
  47. 0 41
      Terminal.Gui/Drivers/FakeDriver/FakeWindowSizeMonitor.cs
  48. 3 3
      Terminal.Gui/Drivers/IComponentFactory.cs
  49. 14 8
      Terminal.Gui/Drivers/IConsoleDriver.cs
  50. 1 1
      Terminal.Gui/Drivers/IConsoleDriverFacade.cs
  51. 9 2
      Terminal.Gui/Drivers/IConsoleOutput.cs
  52. 3 3
      Terminal.Gui/Drivers/IConsoleSizeMonitor.cs
  53. 1 1
      Terminal.Gui/Drivers/IInputProcessor.cs
  54. 1 1
      Terminal.Gui/Drivers/IOutputBuffer.cs
  55. 2 2
      Terminal.Gui/Drivers/InputProcessor.cs
  56. 1 1
      Terminal.Gui/Drivers/MouseButtonStateEx.cs
  57. 1 1
      Terminal.Gui/Drivers/OutputBase.cs
  58. 3 3
      Terminal.Gui/Drivers/OutputBuffer.cs
  59. 7 1
      Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs
  60. 0 42
      Terminal.Gui/Drivers/WindowSizeMonitor.cs
  61. 31 908
      Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs
  62. 9 8
      Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs
  63. 7 1
      Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs
  64. 2 2
      Terminal.Gui/Resources/Strings.Designer.cs
  65. 4 4
      Terminal.Gui/Resources/Strings.resx
  66. 6 6
      Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs
  67. 1 1
      Terminal.Gui/ViewBase/Adornment/Border.cs
  68. 7 7
      Terminal.Gui/ViewBase/Adornment/Margin.cs
  69. 2 2
      Terminal.Gui/ViewBase/Adornment/ShadowView.cs
  70. 1 1
      Terminal.Gui/ViewBase/Layout/DimAuto.cs
  71. 5 4
      Terminal.Gui/ViewBase/View.Command.cs
  72. 8 8
      Terminal.Gui/ViewBase/View.Layout.cs
  73. 1 1
      Terminal.Gui/Views/CheckBox.cs
  74. 3 4
      Terminal.Gui/Views/FileDialogs/FileDialog.cs
  75. 1 1
      Terminal.Gui/Views/Label.cs
  76. 2 2
      Terminal.Gui/Views/Menu/MenuBarv2.cs
  77. 2 2
      Terminal.Gui/Views/Menuv1/MenuBar.cs
  78. 1 1
      Terminal.Gui/Views/RadioGroup.cs
  79. 9 9
      Terminal.Gui/Views/Shortcut.cs
  80. 1 1
      Terminal.Gui/Views/StatusBar.cs
  81. 1 1
      Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs
  82. 47 31
      Terminal.Gui/Views/TextInput/TextField.cs
  83. 0 1
      Terminal.Gui/Views/TreeView/Branch.cs
  84. 4 4
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs
  85. 0 58
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeConsoleDriver.cs
  86. 0 20
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeDriverFactory.cs
  87. 0 0
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeInput.cs
  88. 7 1
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeOutput.cs
  89. 6 6
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs
  90. 0 0
      Tests/TerminalGuiFluentTesting/FakeDriver/FakeWindowsInput.cs
  91. 0 8
      Tests/TerminalGuiFluentTesting/FakeDriver/IFakeConsoleDriver.cs
  92. 19 36
      Tests/TerminalGuiFluentTesting/GuiTestContext.cs
  93. 1 1
      Tests/UnitTests/Application/Application.NavigationTests.cs
  94. 2 2
      Tests/UnitTests/Application/ApplicationImplTests.cs
  95. 3 2
      Tests/UnitTests/Application/ApplicationPopoverTests.cs
  96. 2 2
      Tests/UnitTests/Application/ApplicationScreenTests.cs
  97. 31 44
      Tests/UnitTests/Application/ApplicationTests.cs
  98. 63 48
      Tests/UnitTests/Application/TimedEventsTests.cs
  99. 8 29
      Tests/UnitTests/AutoInitShutdownAttribute.cs
  100. 57 80
      Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs

+ 3 - 3
.editorconfig

@@ -82,8 +82,8 @@ dotnet_diagnostic.cs0464.severity = warning
 dotnet_diagnostic.cs0465.severity = warning
 dotnet_diagnostic.cs0469.severity = warning
 dotnet_diagnostic.cs0472.severity = warning
-dotnet_diagnostic.cs0612.severity = warning
-dotnet_diagnostic.cs0618.severity = warning
+dotnet_diagnostic.cs0612.severity = none
+dotnet_diagnostic.cs0618.severity = none
 dotnet_diagnostic.cs0628.severity = warning
 dotnet_diagnostic.cs0642.severity = warning
 dotnet_diagnostic.cs0649.severity = warning
@@ -94,7 +94,7 @@ dotnet_diagnostic.cs0659.severity = warning
 dotnet_diagnostic.cs0660.severity = warning
 dotnet_diagnostic.cs0661.severity = warning
 dotnet_diagnostic.cs0665.severity = warning
-dotnet_diagnostic.cs0672.severity = warning
+dotnet_diagnostic.cs0672.severity = none
 dotnet_diagnostic.cs0675.severity = warning
 dotnet_diagnostic.cs0693.severity = warning
 dotnet_diagnostic.cs0728.severity = warning

+ 12 - 12
Examples/UICatalog/Scenarios/Adornments.cs

@@ -26,7 +26,7 @@ public class Adornments : Scenario
             X = Pos.AnchorEnd ()
         };
 
-        editor.Border.Thickness = new (1, 2, 1, 1);
+        editor.Border!.Thickness = new (1, 2, 1, 1);
 
         app.Add (editor);
 
@@ -71,7 +71,7 @@ public class Adornments : Scenario
             Width = 40,
             Height = 6 // TODO: Use Dim.Auto
         };
-        label.Border.Thickness = new (1, 3, 1, 1);
+        label.Border!.Thickness = new (1, 3, 1, 1);
 
         var btnButtonInWindow = new Button { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" };
 
@@ -84,13 +84,13 @@ public class Adornments : Scenario
             SchemeName = "Dialog"
         };
 
-        window.Margin.Data = "Margin";
-        window.Margin.Text = "Margin Text";
-        window.Margin.Thickness = new (0);
+        window.Margin!.Data = "Margin";
+        window.Margin!.Text = "Margin Text";
+        window.Margin!.Thickness = new (0);
 
-        window.Border.Data = "Border";
-        window.Border.Text = "Border Text";
-        window.Border.Thickness = new (0);
+        window.Border!.Data = "Border";
+        window.Border!.Text = "Border Text";
+        window.Border!.Thickness = new (0);
 
         window.Padding.Data = "Padding";
         window.Padding.Text = "Padding Text line 1\nPadding Text line 3\nPadding Text line 3\nPadding Text line 4\nPadding Text line 5";
@@ -134,14 +134,14 @@ public class Adornments : Scenario
                                   };
                                   btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                   btnButtonInPadding.BorderStyle = LineStyle.Dashed;
-                                  btnButtonInPadding.Border.Thickness = new (1, 1, 1, 1);
+                                  btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1);
                                   window.Padding.Add (btnButtonInPadding);
 
 #if SUBVIEW_BASED_BORDER
-                                btnButtonInPadding.Border.CloseButton.Visible = true;
+                                btnButtonInPadding.Border!.CloseButton.Visible = true;
 
-                                view.Border.CloseButton.Visible = true;
-                                view.Border.CloseButton.Accept += (s, e) =>
+                                view.Border!.CloseButton.Visible = true;
+                                view.Border!.CloseButton.Accept += (s, e) =>
                                                                   {
                                                                       MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
                                                                       e.Handled = true;

+ 1 - 1
Examples/UICatalog/Scenarios/AllViewsTester.cs

@@ -38,7 +38,7 @@ public class AllViewsTester : Scenario
 
         // Set the BorderStyle we use for all subviews, but disable the app border thickness
         app.Border!.LineStyle = LineStyle.Heavy;
-        app.Border.Thickness = new (0);
+        app.Border!.Thickness = new (0);
 
 
         _viewClasses = GetAllViewClassesCollection ()

+ 1 - 1
Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs

@@ -112,7 +112,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
                                                       break;
                                                   case "CSI_ReportTerminalSizeInChars":
-                                                      selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportTerminalSizeInChars;
+                                                      selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportWindowSizeInChars;
 
                                                       break;
                                                   case "CSI_RequestCursorPositionReport":

+ 1 - 1
Examples/UICatalog/Scenarios/Bars.cs

@@ -40,7 +40,7 @@ public class Bars : Scenario
             SchemeName = "Toplevel",
             Source = new ListWrapper<string> (eventSource)
         };
-        eventLog.Border.Thickness = new (0, 1, 0, 0);
+        eventLog.Border!.Thickness = new (0, 1, 0, 0);
         Application.Top.Add (eventLog);
 
         FrameView menuBarLikeExamples = new ()

+ 1 - 1
Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs

@@ -85,7 +85,7 @@ public class CharacterMap : Scenario
             X = Pos.Right (jumpLabel) + 1,
             Y = Pos.Y (_charMap),
             Width = 17,
-            Caption = "e.g. 01BE3 or ✈"
+            Title = "e.g. 01BE3 or ✈"
 
             //SchemeName = "Dialog"
         };

+ 1 - 1
Examples/UICatalog/Scenarios/Clipping.cs

@@ -151,7 +151,7 @@ public class Clipping : Scenario
         //tiled.Padding.Thickness = new (1);
         //tiled.Padding.Diagnostics =  ViewDiagnosticFlags.Thickness;
 
-        //tiled.Margin.Thickness = new (1);
+        //tiled.Margin!.Thickness = new (1);
 
         FrameView fv = new ()
         {

+ 1 - 1
Examples/UICatalog/Scenarios/DimAutoDemo.cs

@@ -56,7 +56,7 @@ public class DimAutoDemo : Scenario
             Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: Dim.Percent (25)),
             Height = Dim.Auto (DimAutoStyle.Content, minimumContentDim: 10)
         };
-        dimAutoFrameView.Margin.Thickness = new Thickness (1);
+        dimAutoFrameView.Margin!.Thickness = new Thickness (1);
         dimAutoFrameView.ValidatePosDim = true;
 
         var textEdit = new TextView

+ 3 - 3
Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs

@@ -99,7 +99,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        MarginEditor.Border!.Thickness = MarginEditor.Border.Thickness with { Bottom = 0 };
+        MarginEditor.Border!.Thickness = MarginEditor.Border!.Thickness with { Bottom = 0 };
         Add (MarginEditor);
 
         BorderEditor = new ()
@@ -109,7 +109,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        BorderEditor.Border!.Thickness = BorderEditor.Border.Thickness with { Bottom = 0 };
+        BorderEditor.Border!.Thickness = BorderEditor.Border!.Thickness with { Bottom = 0 };
         Add (BorderEditor);
 
         PaddingEditor = new ()
@@ -119,7 +119,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        PaddingEditor.Border!.Thickness = PaddingEditor.Border.Thickness with { Bottom = 0 };
+        PaddingEditor.Border!.Thickness = PaddingEditor.Border!.Thickness with { Bottom = 0 };
         Add (PaddingEditor);
 
         Width = Dim.Auto (maximumContentDim: Dim.Func (_ => MarginEditor.Frame.Width - 2));

+ 5 - 5
Examples/UICatalog/Scenarios/GraphViewExample.cs

@@ -144,8 +144,8 @@ public class GraphViewExample : Scenario
             Height = Dim.Fill (1),
             BorderStyle = LineStyle.Single
         };
-        _graphView.Border.Thickness = _thickness;
-        _graphView.Margin.Thickness = _thickness;
+        _graphView.Border!.Thickness = _thickness;
+        _graphView.Margin!.Thickness = _thickness;
         _graphView.Padding.Thickness = _thickness;
 
         app.Add (_graphView);
@@ -955,14 +955,14 @@ public class GraphViewExample : Scenario
         if (_miShowBorder.Checked == true)
         {
             _graphView.BorderStyle = LineStyle.Single;
-            _graphView.Border.Thickness = _thickness;
-            _graphView.Margin.Thickness = _thickness;
+            _graphView.Border!.Thickness = _thickness;
+            _graphView.Margin!.Thickness = _thickness;
             _graphView.Padding.Thickness = _thickness;
         }
         else
         {
             _graphView.BorderStyle = LineStyle.None;
-            _graphView.Margin.Thickness = Thickness.Empty;
+            _graphView.Margin!.Thickness = Thickness.Empty;
             _graphView.Padding.Thickness = Thickness.Empty;
         }
     }

+ 3 - 3
Examples/UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -130,9 +130,9 @@ public class LineCanvasExperiment : Scenario
         //    //Scheme = Colors.Schemes ["Error"],
         //    SuperViewRendersLineCanvas = true
         //};
-        //marginWindow.Margin.Scheme = Colors.Schemes ["Error"];
-        //marginWindow.Margin.Thickness = new (1);
-        //marginWindow.Border.Thickness = new (1, 2, 1, 1);
+        //marginWindow.Margin!.Scheme = Colors.Schemes ["Error"];
+        //marginWindow.Margin!.Thickness = new (1);
+        //marginWindow.Border!.Thickness = new (1, 2, 1, 1);
 
         //frame1.Add (marginWindow);
 

+ 4 - 4
Examples/UICatalog/Scenarios/PosAlignDemo.cs

@@ -248,13 +248,13 @@ public sealed class PosAlignDemo : Scenario
         {
             addedViewsUpDown.X = Pos.Align (_horizAligner.Alignment);
             addedViewsUpDown.Y = Pos.Top (alignRadioGroup);
-            addedViewsUpDown.Border.Thickness = new (0, 1, 0, 0);
+            addedViewsUpDown.Border!.Thickness = new (0, 1, 0, 0);
         }
         else
         {
             addedViewsUpDown.X = Pos.Left (alignRadioGroup);
             addedViewsUpDown.Y = Pos.Align (_vertAligner.Alignment);
-            addedViewsUpDown.Border.Thickness = new (1, 0, 0, 0);
+            addedViewsUpDown.Border!.Thickness = new (1, 0, 0, 0);
         }
 
         addedViewsUpDown.ValueChanging += (s, e) =>
@@ -319,7 +319,7 @@ public sealed class PosAlignDemo : Scenario
                                         aligner.Alignment,
                                         aligner.AlignmentModes,
                                         posAlign!.GroupId);
-                    view.Margin.Thickness = new (_leftMargin, view.Margin.Thickness.Top, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom);
+                    view.Margin!.Thickness = new (_leftMargin, view.Margin!.Thickness.Top, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom);
                 }
                 else
                 {
@@ -330,7 +330,7 @@ public sealed class PosAlignDemo : Scenario
                                         aligner.AlignmentModes,
                                         posAlign!.GroupId);
 
-                    view.Margin.Thickness = new (view.Margin.Thickness.Left, _topMargin, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom);
+                    view.Margin!.Thickness = new (view.Margin!.Thickness.Left, _topMargin, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom);
                 }
             }
         }

+ 1 - 1
Examples/UICatalog/Scenarios/Shortcuts.cs

@@ -337,7 +337,7 @@ public class Shortcuts : Scenario
 
         if (framedShortcut.CommandView.Margin is { })
         {
-            framedShortcut.CommandView.Margin.SchemeName = framedShortcut.CommandView.SchemeName = "Error";
+            framedShortcut.CommandView.Margin!.SchemeName = framedShortcut.CommandView.SchemeName = "Error";
             framedShortcut.HelpView.Margin!.SchemeName = framedShortcut.HelpView.SchemeName = "Dialog";
             framedShortcut.KeyView.Margin!.SchemeName = framedShortcut.KeyView.SchemeName = "Menu";
         }

+ 1 - 1
Examples/UICatalog/Scenarios/TextInputControls.cs

@@ -68,7 +68,7 @@ public class TextInputControls : Scenario
             X = Pos.Right (label) + 1,
             Y = Pos.Bottom (textField),
             Width = Dim.Percent (50) - 1,
-            Caption = "TextField with caption"
+            Title = "TextField with caption"
         };
 
         win.Add (textField);

+ 2 - 2
Examples/UICatalog/Scenarios/ViewportSettings.cs

@@ -178,10 +178,10 @@ public class ViewportSettings : Scenario
         buttonAnchored.Accepting += (sender, args) => MessageBox.Query ("Hi", $"You pressed {((Button)sender)?.Text}", "_Ok");
 
         view.Margin!.Data = "Margin";
-        view.Margin.Thickness = new (0);
+        view.Margin!.Thickness = new (0);
 
         view.Border!.Data = "Border";
-        view.Border.Thickness = new (3);
+        view.Border!.Thickness = new (3);
 
         view.Padding.Data = "Padding";
 

+ 1 - 1
Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -43,7 +43,7 @@ public class WindowsAndFrameViews : Scenario
             Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable | ViewArrangement.Resizable
         };
         win.Padding.Thickness = new (padding);
-        win.Margin.Thickness = new (margin);
+        win.Margin!.Thickness = new (margin);
 
         var paddingButton = new Button
         {

+ 2 - 2
Examples/UICatalog/UICatalog.cs

@@ -451,7 +451,7 @@ public class UICatalog
             scenario.StartBenchmark ();
         }
 
-        Application.Init (driverName: _forceDriver);
+        Application.ForceDriver = _forceDriver!;
 
         scenario.Main ();
 
@@ -517,7 +517,7 @@ public class UICatalog
 
         if (benchmarkWindow.Border is { })
         {
-            benchmarkWindow.Border.Thickness = new (0, 0, 0, 0);
+            benchmarkWindow.Border!.Thickness = new (0, 0, 0, 0);
         }
 
         TableView resultsTableView = new ()

+ 3 - 2
Terminal.Gui.Analyzers.Tests/HandledEventArgsAnalyzerTests.cs

@@ -1,7 +1,8 @@
-using Terminal.Gui.Input;
+using Terminal.Gui.Analyzers;
+using Terminal.Gui.Input;
 using Terminal.Gui.Views;
 
-namespace Terminal.Gui.Analyzers.Tests;
+namespace Analyzers.Tests;
 
 public class HandledEventArgsAnalyzerTests
 {

+ 4 - 111
Terminal.Gui/App/Application.Lifecycle.cs

@@ -40,26 +40,6 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     [RequiresDynamicCode ("AOT")]
     public static void Init (IConsoleDriver? driver = null, string? driverName = null)
     {
-        // Check if this is a request for a legacy driver (like FakeDriver)
-        // that isn't supported by the modern application architecture
-        if (driver is null)
-        {
-            var driverNameToCheck = string.IsNullOrWhiteSpace (driverName) ? ForceDriver : driverName;
-            if (!string.IsNullOrEmpty (driverNameToCheck))
-            {
-                (List<Type?> drivers, List<string?> driverTypeNames) = GetDriverTypes ();
-                Type? driverType = drivers.FirstOrDefault (t => t!.Name.Equals (driverNameToCheck, StringComparison.InvariantCultureIgnoreCase));
-                
-                // If it's a legacy IConsoleDriver (not a Facade), use InternalInit which supports legacy drivers
-                if (driverType is { } && !typeof (IConsoleDriverFacade).IsAssignableFrom (driverType))
-                {
-                    InternalInit (driver, driverName);
-                    return;
-                }
-            }
-        }
-        
-        // Otherwise delegate to the ApplicationImpl instance (which uses the modern architecture)
         ApplicationImpl.Instance.Init (driver, driverName ?? ForceDriver);
     }
 
@@ -69,96 +49,6 @@ public static partial class Application // Lifecycle (Init/Shutdown)
         set => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId = value;
     }
 
-    // INTERNAL function for initializing an app with a Toplevel factory object, driver, and mainloop.
-    //
-    // Called from:
-    //
-    // Init() - When the user wants to use the default Toplevel. calledViaRunT will be false, causing all state to be reset.
-    // Run<T>() - When the user wants to use a custom Toplevel. calledViaRunT will be true, enabling Run<T>() to be called without calling Init first.
-    // Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset.
-    //
-    // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
-    [RequiresUnreferencedCode ("AOT")]
-    [RequiresDynamicCode ("AOT")]
-    internal static void InternalInit (
-        IConsoleDriver? driver = null,
-        string? driverName = null,
-        bool calledViaRunT = false
-    )
-    {
-        if (Initialized && driver is null)
-        {
-            return;
-        }
-
-        if (Initialized)
-        {
-            throw new InvalidOperationException ("Init has already been called and must be bracketed by Shutdown.");
-        }
-
-        if (!calledViaRunT)
-        {
-            // Reset all class variables (Application is a singleton).
-            ResetState (ignoreDisposed: true);
-        }
-
-        // For UnitTests
-        if (driver is { })
-        {
-            Driver = driver;
-        }
-
-        // Ignore Configuration for ForceDriver if driverName is specified
-        if (!string.IsNullOrEmpty (driverName))
-        {
-            ForceDriver = driverName;
-        }
-
-        // Check if we need to use a legacy driver (like FakeDriver)
-        // or go through the modern application architecture
-        if (Driver is null)
-        {
-            ApplicationImpl.Instance.Init (driver, driverName);
-            Debug.Assert (Driver is { });
-            return;
-        }
-
-        Debug.Assert (Navigation is null);
-        Navigation = new ();
-
-        Debug.Assert (Popover is null);
-        Popover = new ();
-
-        try
-        {
-            Driver!.Init ();
-            SubscribeDriverEvents ();
-        }
-        catch (InvalidOperationException ex)
-        {
-            // This is a case where the driver is unable to initialize the console.
-            // This can happen if the console is already in use by another process or
-            // if running in unit tests.
-            // In this case, we want to throw a more specific exception.
-            throw new InvalidOperationException (
-                                                 "Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.",
-                                                 ex
-                                                );
-        }
-
-        SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
-
-        // TODO: This is probably not needed
-        if (Popover.GetActivePopover () is View popover)
-        {
-            popover.Visible = false;
-        }
-
-        MainThreadId = Thread.CurrentThread.ManagedThreadId;
-        bool init = Initialized = true;
-        InitializedChanged?.Invoke (null, new (init));
-    }
-
     internal static void SubscribeDriverEvents ()
     {
         ArgumentNullException.ThrowIfNull (Driver);
@@ -179,7 +69,10 @@ public static partial class Application // Lifecycle (Init/Shutdown)
         Driver.MouseEvent -= Driver_MouseEvent;
     }
 
-    private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { OnSizeChanging (e); }
+    private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e)
+    {
+        RaiseScreenChangedEvent (new Rectangle (new (0, 0), e.Size!.Value));
+    }
     private static void Driver_KeyDown (object? sender, Key e) { RaiseKeyDownEvent (e); }
     private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); }
     private static void Driver_MouseEvent (object? sender, MouseEventArgs e) { RaiseMouseEvent (e); }

+ 7 - 7
Terminal.Gui/App/Application.Run.cs

@@ -22,10 +22,6 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
         set => Keyboard.ArrangeKey = value;
     }
 
-    // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
-    // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
-    private static Toplevel? _cachedRunStateToplevel;
-
     /// <summary>
     ///     Notify that a new <see cref="RunState"/> was created (<see cref="Begin(Toplevel)"/> was called). The token is
     ///     created in <see cref="Begin(Toplevel)"/> and this event will be fired before that function exits.
@@ -43,7 +39,11 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
     ///     must also subscribe to <see cref="NotifyStopRunState"/> and manually dispose of the <see cref="RunState"/> token
     ///     when the application is done.
     /// </remarks>
+#pragma warning disable CS0067 // Event is never used
+#pragma warning disable CS0414 // Event is never used
     public static event EventHandler<ToplevelEventArgs>? NotifyStopRunState;
+#pragma warning restore CS0414 // Event is never used
+#pragma warning restore CS0067 // Event is never used
 
     /// <summary>Building block API: Prepares the provided <see cref="Toplevel"/> for execution.</summary>
     /// <returns>
@@ -74,7 +74,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
         {
             // This assertion confirm if the Top was already disposed
             Debug.Assert (Top.WasDisposed);
-            Debug.Assert (Top == _cachedRunStateToplevel);
+            Debug.Assert (Top == CachedRunStateToplevel);
         }
 #endif
 
@@ -84,7 +84,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
             {
                 // If Top was already disposed and isn't on the Toplevels Stack,
                 // clean it up here if is the same as _cachedRunStateToplevel
-                if (Top == _cachedRunStateToplevel)
+                if (Top == CachedRunStateToplevel)
                 {
                     Top = null;
                 }
@@ -493,7 +493,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
             Top.SetFocus ();
         }
 
-        _cachedRunStateToplevel = runState.Toplevel;
+        CachedRunStateToplevel = runState.Toplevel;
 
         runState.Toplevel = null;
         runState.Dispose ();

+ 8 - 20
Terminal.Gui/App/Application.Screen.cs

@@ -19,38 +19,26 @@ public static partial class Application // Screen related stuff; intended to hid
     }
 
     /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
-    /// <remarks>
-    ///     Event handlers can set <see cref="SizeChangedEventArgs.Cancel"/> to <see langword="true"/> to prevent
-    ///     <see cref="Application"/> from changing it's size to match the new terminal size.
-    /// </remarks>
-    public static event EventHandler<SizeChangedEventArgs>? SizeChanging;
+    public static event EventHandler<EventArgs<Rectangle>>? ScreenChanged;
 
     /// <summary>
-    ///     Called when the application's size changes. Sets the size of all <see cref="Toplevel"/>s and fires the
-    ///     <see cref="SizeChanging"/> event.
+    ///     Called when the application's size has changed. Sets the size of all <see cref="Toplevel"/>s and fires the
+    ///     <see cref="ScreenChanged"/> event.
     /// </summary>
-    /// <param name="args">The new size.</param>
-    /// <returns><see lanword="true"/>if the size was changed.</returns>
-    public static bool OnSizeChanging (SizeChangedEventArgs args)
+    /// <param name="screen">The new screen size and position.</param>
+    public static void RaiseScreenChangedEvent (Rectangle screen)
     {
-        SizeChanging?.Invoke (null, args);
-
-        if (args.Cancel || args.Size is null)
-        {
-            return false;
-        }
+        Screen = new (Point.Empty, screen.Size);
 
-        Screen = new (Point.Empty, args.Size.Value);
+        ScreenChanged?.Invoke (ApplicationImpl.Instance, new (screen));
 
         foreach (Toplevel t in TopLevels)
         {
-            t.OnSizeChanging (new (args.Size));
+            t.OnSizeChanging (new (screen.Size));
             t.SetNeedsLayout ();
         }
 
         LayoutAndDraw (true);
-
-        return true;
     }
 
     /// <summary>

+ 8 - 0
Terminal.Gui/App/Application.Toplevel.cs

@@ -17,4 +17,12 @@ public static partial class Application // Toplevel handling
         get => ApplicationImpl.Instance.Top;
         internal set => ApplicationImpl.Instance.Top = value;
     }
+
+    internal static Toplevel? CachedRunStateToplevel
+    {
+        get => ApplicationImpl.Instance.CachedRunStateToplevel;
+        private set => ApplicationImpl.Instance.CachedRunStateToplevel = value;
+    }
+
+
 }

+ 5 - 5
Terminal.Gui/App/Application.cs

@@ -206,15 +206,15 @@ public static partial class Application
             Debug.Assert (Top.WasDisposed, $"Title = {Top.Title}, Id = {Top.Id}");
 
             // If End wasn't called _cachedRunStateToplevel may be null
-            if (_cachedRunStateToplevel is { })
+            if (CachedRunStateToplevel is { })
             {
-                Debug.Assert (_cachedRunStateToplevel.WasDisposed);
-                Debug.Assert (_cachedRunStateToplevel == Top);
+                Debug.Assert (CachedRunStateToplevel.WasDisposed);
+                Debug.Assert (CachedRunStateToplevel == Top);
             }
         }
 #endif
         Top = null;
-        _cachedRunStateToplevel = null;
+        CachedRunStateToplevel = null;
 
         MainThreadId = -1;
         Iteration = null;
@@ -257,7 +257,7 @@ public static partial class Application
 
         // Keyboard events and bindings are now managed by the Keyboard instance
 
-        SizeChanging = null;
+        ScreenChanged = null;
 
         Navigation = null;
 

+ 21 - 34
Terminal.Gui/App/ApplicationImpl.cs

@@ -63,11 +63,6 @@ public class ApplicationImpl : IApplication
         set => _mouse = value ?? throw new ArgumentNullException (nameof (value));
     }
 
-    /// <summary>
-    /// Handles which <see cref="View"/> (if any) has captured the mouse
-    /// </summary>
-    public IMouseGrabHandler MouseGrabHandler { get; set; } = new MouseGrabHandler ();
-
     private IKeyboard? _keyboard;
 
     /// <summary>
@@ -134,7 +129,7 @@ public class ApplicationImpl : IApplication
         }
         set
         {
-            if (value is {} && (value.X != 0 || value.Y != 0))
+            if (value is { } && (value.X != 0 || value.Y != 0))
             {
                 throw new NotImplementedException ($"Screen locations other than 0, 0 are not yet supported");
             }
@@ -177,6 +172,11 @@ public class ApplicationImpl : IApplication
     /// <inheritdoc/>
     public ConcurrentStack<Toplevel> TopLevels => _topLevels;
 
+    // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
+    // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
+    /// <inheritdoc />
+    public Toplevel? CachedRunStateToplevel { get; set; }
+
     /// <summary>
     /// Gets or sets the main thread ID for the application.
     /// </summary>
@@ -231,10 +231,10 @@ public class ApplicationImpl : IApplication
 
         if (string.IsNullOrWhiteSpace (_driverName))
         {
-            _driverName = Application.ForceDriver;
+            _driverName = ForceDriver;
         }
 
-        Debug.Assert(_navigation is null);
+        Debug.Assert (_navigation is null);
         _navigation = new ();
 
         Debug.Assert (_popover is null);
@@ -264,7 +264,7 @@ public class ApplicationImpl : IApplication
         }
 
         CreateDriver (driverName ?? _driverName);
-
+        Screen = Driver!.Screen;
         _initialized = true;
 
         Application.OnInitializedChanged (this, new (true));
@@ -276,23 +276,6 @@ public class ApplicationImpl : IApplication
 
     private void CreateDriver (string? driverName)
     {
-        // When running unit tests, always use FakeDriver unless explicitly specified
-        if (ConsoleDriver.RunningUnitTests && 
-            string.IsNullOrEmpty (driverName) && 
-            _componentFactory is null)
-        {
-            Logging.Logger.LogDebug ("Unit test safeguard: forcing FakeDriver (RunningUnitTests=true, driverName=null, componentFactory=null)");
-            _coordinator = CreateSubcomponents (() => new FakeComponentFactory ());
-            _coordinator.StartAsync ().Wait ();
-
-            if (_driver == null)
-            {
-                throw new ("Driver was null even after booting MainLoopCoordinator");
-            }
-
-            return;
-        }
-
         PlatformID p = Environment.OSVersion.Platform;
 
         // Check component factory type first - this takes precedence over driverName
@@ -310,7 +293,10 @@ public class ApplicationImpl : IApplication
         // Decide which driver to use - component factory type takes priority
         if (factoryIsFake || (!factoryIsWindows && !factoryIsDotNet && !factoryIsUnix && nameIsFake))
         {
-            _coordinator = CreateSubcomponents (() => new FakeComponentFactory ());
+            FakeConsoleOutput fakeOutput = new ();
+            fakeOutput.SetConsoleSize (80, 25);
+
+            _coordinator = CreateSubcomponents (() => new FakeComponentFactory (null, fakeOutput));
         }
         else if (factoryIsWindows || (!factoryIsDotNet && !factoryIsUnix && nameIsWindows))
         {
@@ -410,7 +396,7 @@ public class ApplicationImpl : IApplication
 
         if (_driver == null)
         {
-            throw new  InvalidOperationException ("Driver was inexplicably null when trying to Run view");
+            throw new InvalidOperationException ("Driver was inexplicably null when trying to Run view");
         }
 
         _top = view;
@@ -437,17 +423,17 @@ public class ApplicationImpl : IApplication
     public void Shutdown ()
     {
         _coordinator?.Stop ();
-        
+
         bool wasInitialized = _initialized;
-        
+
         // Reset Screen before calling Application.ResetState to avoid circular reference
         ResetScreen ();
-        
+
         // Call ResetState FIRST so it can properly dispose Popover and other resources
         // that are accessed via Application.* static properties that now delegate to instance fields
         Application.ResetState ();
         ConfigurationManager.PrintJsonErrors ();
-        
+
         // Clear instance fields after ResetState has disposed everything
         _driver = null;
         _mouse = null;
@@ -455,6 +441,7 @@ public class ApplicationImpl : IApplication
         _initialized = false;
         _navigation = null;
         _popover = null;
+        CachedRunStateToplevel = null;
         _top = null;
         _topLevels.Clear ();
         _mainThreadId = -1;
@@ -475,7 +462,7 @@ public class ApplicationImpl : IApplication
     /// <inheritdoc />
     public void RequestStop (Toplevel? top)
     {
-        Logging.Logger.LogInformation ($"RequestStop '{(top is {} ? top : "null")}'");
+        Logging.Logger.LogInformation ($"RequestStop '{(top is { } ? top : "null")}'");
 
         top ??= _top;
 
@@ -499,7 +486,7 @@ public class ApplicationImpl : IApplication
     public void Invoke (Action action)
     {
         // If we are already on the main UI thread
-        if (Application.Top is { Running: true } && _mainThreadId == Thread.CurrentThread.ManagedThreadId)
+        if (Top is { Running: true } && _mainThreadId == Thread.CurrentThread.ManagedThreadId)
         {
             action ();
             return;

+ 5 - 0
Terminal.Gui/App/IApplication.cs

@@ -74,6 +74,11 @@ public interface IApplication
     /// <summary>Gets the stack of all Toplevels.</summary>
     System.Collections.Concurrent.ConcurrentStack<Toplevel> TopLevels { get; }
 
+    /// <summary>
+    /// Caches the Toplevel associated with the current RunState.
+    /// </summary>
+    Toplevel? CachedRunStateToplevel { get; set; }
+
     /// <summary>Requests that the application stop running.</summary>
     void RequestStop ();
 

+ 6 - 6
Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs

@@ -27,7 +27,7 @@ public class ApplicationMainLoop<T> : IApplicationMainLoop<T>
     private IInputProcessor? _inputProcessor;
     private IConsoleOutput? _out;
     private AnsiRequestScheduler? _ansiRequestScheduler;
-    private IWindowSizeMonitor? _windowSizeMonitor;
+    private IConsoleSizeMonitor? _consoleSizeMonitor;
 
     /// <inheritdoc/>
     public ITimedEvents TimedEvents
@@ -74,10 +74,10 @@ public class ApplicationMainLoop<T> : IApplicationMainLoop<T>
     }
 
     /// <inheritdoc/>
-    public IWindowSizeMonitor WindowSizeMonitor
+    public IConsoleSizeMonitor ConsoleSizeMonitor
     {
-        get => _windowSizeMonitor ?? throw new NotInitializedException (nameof (WindowSizeMonitor));
-        private set => _windowSizeMonitor = value;
+        get => _consoleSizeMonitor ?? throw new NotInitializedException (nameof (ConsoleSizeMonitor));
+        private set => _consoleSizeMonitor = value;
     }
 
     /// <summary>
@@ -114,7 +114,7 @@ public class ApplicationMainLoop<T> : IApplicationMainLoop<T>
         TimedEvents = timedEvents;
         AnsiRequestScheduler = new (InputProcessor.GetParser ());
 
-        WindowSizeMonitor = componentFactory.CreateWindowSizeMonitor (Out, OutputBuffer);
+        ConsoleSizeMonitor = componentFactory.CreateConsoleSizeMonitor (Out, OutputBuffer);
     }
 
     /// <inheritdoc/>
@@ -152,7 +152,7 @@ public class ApplicationMainLoop<T> : IApplicationMainLoop<T>
                                      || AnySubViewsNeedDrawn (Application.Top)
                                      || (Application.Mouse.MouseGrabView != null && AnySubViewsNeedDrawn (Application.Mouse.MouseGrabView));
 
-            bool sizeChanged = WindowSizeMonitor.Poll ();
+            bool sizeChanged = ConsoleSizeMonitor.Poll ();
 
             if (needsDrawOrLayout || sizeChanged)
             {

+ 1 - 1
Terminal.Gui/App/MainLoop/IApplicationMainLoop.cs

@@ -48,7 +48,7 @@ public interface IApplicationMainLoop<T> : IDisposable
     /// <summary>
     ///     Gets the class responsible for determining the current console size
     /// </summary>
-    public IWindowSizeMonitor WindowSizeMonitor { get; }
+    public IConsoleSizeMonitor ConsoleSizeMonitor { get; }
 
     /// <summary>
     ///     Initializes the loop with a buffer from which data can be read

+ 1 - 1
Terminal.Gui/App/MainLoop/MainLoopCoordinator.cs

@@ -149,7 +149,7 @@ internal class MainLoopCoordinator<T> : IMainLoopCoordinator
                            _loop.OutputBuffer,
                            _output,
                            _loop.AnsiRequestScheduler,
-                           _loop.WindowSizeMonitor);
+                           _loop.ConsoleSizeMonitor);
 
             Application.Driver = _facade;
 

+ 0 - 12
Terminal.Gui/App/Timeout/ITimedEvents.cs

@@ -27,18 +27,6 @@ public interface ITimedEvents
     /// </summary>
     event EventHandler<TimeoutEventArgs>? Added;
 
-    /// <summary>
-    ///     Called from <see cref="IMainLoopDriver.EventsPending"/> to check if there are any outstanding timer handlers.
-    /// </summary>
-    /// <param name="waitTimeout">
-    ///     Returns the number of milliseconds remaining in the current timer (if any). Will be -1 if
-    ///     there are no active timers.
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if there is a timer active; otherwise, <see langword="false"/>.
-    /// </returns>
-    bool CheckTimers (out int waitTimeout);
-
     /// <summary>
     ///     Removes a previously scheduled timeout.
     /// </summary>

+ 7 - 1
Terminal.Gui/App/Timeout/TimedEvents.cs

@@ -55,7 +55,13 @@ public class TimedEvents : ITimedEvents
     {
         // Convert Stopwatch ticks to TimeSpan ticks (100-nanosecond units)
         // Stopwatch.Frequency gives ticks per second, so we need to scale appropriately
-        return Stopwatch.GetTimestamp () * TimeSpan.TicksPerSecond / Stopwatch.Frequency;
+        // To avoid overflow, we perform the operation in double precision first and then cast to long.
+        var ticks = (long)((double)Stopwatch.GetTimestamp () * TimeSpan.TicksPerSecond / Stopwatch.Frequency);
+
+        // Ensure ticks is positive and not overflowed (very unlikely now)
+        Debug.Assert (ticks > 0);
+
+        return ticks;
     }
 
     /// <inheritdoc/>

+ 8 - 5
Terminal.Gui/Drawing/Ruler.cs

@@ -23,7 +23,8 @@ internal class Ruler
     /// <summary>Draws the <see cref="Ruler"/>.</summary>
     /// <param name="location">The location to start drawing the ruler, in screen-relative coordinates.</param>
     /// <param name="start">The start value of the ruler.</param>
-    public void Draw (Point location, int start = 0)
+    /// <param name="driver">Optional Driver. If not provided, driver will be used.</param>
+    public void Draw (Point location, int start = 0, IConsoleDriver? driver = null)
     {
         if (start < 0)
         {
@@ -35,14 +36,16 @@ internal class Ruler
             return;
         }
 
+        driver ??= driver;
+
         if (Orientation == Orientation.Horizontal)
         {
             string hrule =
                 _hTemplate.Repeat ((int)Math.Ceiling (Length + 2 / (double)_hTemplate.Length))! [start..(Length + start)];
 
             // Top
-            Application.Driver?.Move (location.X, location.Y);
-            Application.Driver?.AddStr (hrule);
+            driver?.Move (location.X, location.Y);
+            driver?.AddStr (hrule);
         }
         else
         {
@@ -52,8 +55,8 @@ internal class Ruler
 
             for (int r = location.Y; r < location.Y + Length; r++)
             {
-                Application.Driver?.Move (location.X, r);
-                Application.Driver?.AddRune ((Rune)vrule [r - location.Y]);
+                driver?.Move (location.X, r);
+                driver?.AddRune ((Rune)vrule [r - location.Y]);
             }
         }
     }

+ 6 - 6
Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs

@@ -53,21 +53,21 @@ public class SixelSupportDetector
 
     private void TryComputeResolution (SixelSupportResult result, Action<SixelSupportResult> resultCallback)
     {
-        string windowSize;
+        string consoleSize;
         string sizeInChars;
 
         QueueRequest (
                       EscSeqUtils.CSI_RequestWindowSizeInPixels,
                       r1 =>
                       {
-                          windowSize = r1;
+                          consoleSize = r1;
 
                           QueueRequest (
-                                        EscSeqUtils.CSI_ReportTerminalSizeInChars,
+                                        EscSeqUtils.CSI_ReportWindowSizeInChars,
                                         r2 =>
                                         {
                                             sizeInChars = r2;
-                                            ComputeResolution (result, windowSize, sizeInChars);
+                                            ComputeResolution (result, consoleSize, sizeInChars);
                                             resultCallback (result);
                                         },
                                         () => resultCallback (result));
@@ -75,11 +75,11 @@ public class SixelSupportDetector
                       () => resultCallback (result));
     }
 
-    private void ComputeResolution (SixelSupportResult result, string windowSize, string sizeInChars)
+    private void ComputeResolution (SixelSupportResult result, string consoleSize, string sizeInChars)
     {
         // Fallback to window size in pixels and characters
         // Example [4;600;1200t
-        Match pixelMatch = Regex.Match (windowSize, @"\[\d+;(\d+);(\d+)t$");
+        Match pixelMatch = Regex.Match (consoleSize, @"\[\d+;(\d+);(\d+)t$");
 
         // Example [8;30;120t
         Match charMatch = Regex.Match (sizeInChars, @"\[\d+;(\d+);(\d+)t$");

+ 32 - 29
Terminal.Gui/Drawing/Thickness.cs

@@ -88,14 +88,17 @@ public record struct Thickness
     /// <param name="rect">The location and size of the rectangle that bounds the thickness rectangle, in screen coordinates.</param>
     /// <param name="diagnosticFlags"></param>
     /// <param name="label">The diagnostics label to draw on the bottom of the <see cref="Bottom"/>.</param>
+    /// <param name="driver">Optional driver. If not specified, <see cref="Application.Driver"/> will be used.</param>
     /// <returns>The inner rectangle remaining to be drawn.</returns>
-    public Rectangle Draw (Rectangle rect, ViewDiagnosticFlags diagnosticFlags = ViewDiagnosticFlags.Off, string? label = null)
+    public Rectangle Draw (Rectangle rect, ViewDiagnosticFlags diagnosticFlags = ViewDiagnosticFlags.Off, string? label = null, IConsoleDriver? driver = null)
     {
         if (rect.Size.Width < 1 || rect.Size.Height < 1)
         {
             return Rectangle.Empty;
         }
 
+        driver ??= Application.Driver;
+
         var clearChar = (Rune)' ';
         Rune leftChar = clearChar;
         Rune rightChar = clearChar;
@@ -118,71 +121,71 @@ public record struct Thickness
         // Draw the Top side
         if (Top > 0)
         {
-            Application.Driver?.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar);
+            driver?.FillRect (rect with { Height = Math.Min (rect.Height, Top) }, topChar);
         }
 
         // Draw the Left side
         // Draw the Left side
         if (Left > 0)
         {
-            Application.Driver?.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar);
+            driver?.FillRect (rect with { Width = Math.Min (rect.Width, Left) }, leftChar);
         }
 
         // Draw the Right side
         if (Right > 0)
         {
-            Application.Driver?.FillRect (
-                                          rect with
-                                          {
-                                              X = Math.Max (0, rect.X + rect.Width - Right),
-                                              Width = Math.Min (rect.Width, Right)
-                                          },
-                                          rightChar
-                                         );
+            driver?.FillRect (
+                              rect with
+                              {
+                                  X = Math.Max (0, rect.X + rect.Width - Right),
+                                  Width = Math.Min (rect.Width, Right)
+                              },
+                              rightChar
+                             );
         }
 
         // Draw the Bottom side
         if (Bottom > 0)
         {
-            Application.Driver?.FillRect (
-                                          rect with
-                                          {
-                                              Y = rect.Y + Math.Max (0, rect.Height - Bottom),
-                                              Height = Bottom
-                                          },
-                                          bottomChar
-                                         );
+            driver?.FillRect (
+                              rect with
+                              {
+                                  Y = rect.Y + Math.Max (0, rect.Height - Bottom),
+                                  Height = Bottom
+                              },
+                              bottomChar
+                             );
         }
 
         if (diagnosticFlags.HasFlag (ViewDiagnosticFlags.Ruler))
         {
             // PERF: This can almost certainly be simplified down to a single point offset and fewer calls to Draw
             // Top
-            var hruler = new Ruler { Length = rect.Width, Orientation = Orientation.Horizontal };
+            Ruler hRuler = new () { Length = rect.Width, Orientation = Orientation.Horizontal };
 
             if (Top > 0)
             {
-                hruler.Draw (rect.Location);
+                hRuler.Draw (rect.Location, driver: driver);
             }
 
             //Left
-            var vruler = new Ruler { Length = rect.Height - 2, Orientation = Orientation.Vertical };
+            Ruler vRuler = new () { Length = rect.Height - 2, Orientation = Orientation.Vertical };
 
             if (Left > 0)
             {
-                vruler.Draw (rect.Location with { Y = rect.Y + 1 }, 1);
+                vRuler.Draw (rect.Location with { Y = rect.Y + 1 }, 1, driver);
             }
 
             // Bottom
             if (Bottom > 0)
             {
-                hruler.Draw (rect.Location with { Y = rect.Y + rect.Height - 1 });
+                hRuler.Draw (rect.Location with { Y = rect.Y + rect.Height - 1 }, driver: driver);
             }
 
             // Right
             if (Right > 0)
             {
-                vruler.Draw (new (rect.X + rect.Width - 1, rect.Y + 1), 1);
+                vRuler.Draw (new (rect.X + rect.Width - 1, rect.Y + 1), 1, driver);
             }
         }
 
@@ -191,7 +194,7 @@ public record struct Thickness
             // Draw the diagnostics label on the bottom
             string text = label is null ? string.Empty : $"{label} {this}";
 
-            var tf = new TextFormatter
+            TextFormatter tf = new ()
             {
                 Text = text,
                 Alignment = Alignment.Center,
@@ -200,9 +203,9 @@ public record struct Thickness
                 ConstrainToHeight = 1
             };
 
-            if (Application.Driver?.CurrentAttribute is { })
+            if (driver?.CurrentAttribute is { })
             {
-                tf.Draw (rect, Application.Driver!.CurrentAttribute, Application.Driver!.CurrentAttribute, rect);
+                tf.Draw (rect, driver!.CurrentAttribute, driver!.CurrentAttribute, rect, driver);
             }
         }
 
@@ -242,7 +245,7 @@ public record struct Thickness
     /// <returns></returns>
     public Region AsRegion (Rectangle rect)
     {
-        Region region = new Region (rect);
+        var region = new Region (rect);
         region.Exclude (GetInside (rect));
 
         return region;

File diff ditekan karena terlalu besar
+ 55 - 925
Terminal.Gui/Drivers/AnsiHandling/EscSeqUtils/EscSeqUtils.cs


+ 1 - 1
Terminal.Gui/Drivers/AnsiHandling/Osc8UrlLinker.cs

@@ -33,7 +33,7 @@ internal static class Osc8UrlLinker
 
     internal static StringBuilder WrapOsc8 (StringBuilder input, Options options)
     {
-        if (input is null || input.Length == 0)
+        if (input.Length == 0)
         {
             return input;
         }

+ 2 - 2
Terminal.Gui/Drivers/ComponentFactory.cs

@@ -16,9 +16,9 @@ public abstract class ComponentFactory<T> : IComponentFactory<T>
     public abstract IInputProcessor CreateInputProcessor (ConcurrentQueue<T> inputBuffer);
 
     /// <inheritdoc />
-    public virtual IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
+    public virtual IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
     {
-        return new WindowSizeMonitor (consoleOutput, outputBuffer);
+        return new ConsoleSizeMonitor (consoleOutput, outputBuffer);
     }
 
     /// <inheritdoc />

+ 31 - 19
Terminal.Gui/Drivers/ConsoleDriver.cs

@@ -60,6 +60,19 @@ public abstract class ConsoleDriver : IConsoleDriver
     /// <summary>Gets the location and size of the terminal screen.</summary>
     public Rectangle Screen => new (0, 0, Cols, Rows);
 
+    /// <summary>
+    /// Sets the screen size for testing purposes. Only supported by FakeDriver.
+    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    /// <see cref="Cols"/> and <see cref="Rows"/> are read-only and derived from <see cref="Screen"/>.
+    /// </summary>
+    /// <param name="width">The new width in columns.</param>
+    /// <param name="height">The new height in rows.</param>
+    /// <exception cref="NotSupportedException">Thrown when called on non-FakeDriver instances.</exception>
+    public virtual void SetScreenSize (int width, int height)
+    {
+        throw new NotSupportedException ("SetScreenSize is only supported by FakeDriver for test scenarios.");
+    }
+
     private Region? _clip;
 
     /// <summary>
@@ -508,9 +521,17 @@ public abstract class ConsoleDriver : IConsoleDriver
         }
     }
 
-    /// <summary>Called when the terminal size changes. Fires the <see cref="SizeChanged"/> event.</summary>
-    /// <param name="args"></param>
-    public void OnSizeChanged (SizeChangedEventArgs args) { SizeChanged?.Invoke (this, args); }
+    /// <summary>
+    /// Called when the terminal screen changes (size, position, etc.). Fires the <see cref="SizeChanged"/> event.
+    /// <see cref="Screen"/> reflects the source of truth for screen dimensions.
+    /// <see cref="Cols"/> and <see cref="Rows"/> are derived from <see cref="Screen"/> and are read-only.
+    /// </summary>
+    /// <param name="args">Event arguments containing the new screen size.</param>
+    public void OnSizeChanged (SizeChangedEventArgs args) 
+    { 
+        SizeChanged?.Invoke (this, args);
+    }
+
 
     /// <summary>Updates the screen to reflect all the changes that have been done to the display buffer</summary>
     public void Refresh ()
@@ -531,13 +552,17 @@ public abstract class ConsoleDriver : IConsoleDriver
     /// <returns><see langword="true"/> upon success</returns>
     public abstract bool SetCursorVisibility (CursorVisibility visibility);
 
-    /// <summary>The event fired when the terminal is resized.</summary>
+    /// <summary>
+    /// The event fired when the screen changes (size, position, etc.).
+    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    /// <see cref="Cols"/> and <see cref="Rows"/> are read-only and derived from <see cref="Screen"/>.
+    /// </summary>
     public event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     #endregion Cursor Handling
 
     /// <summary>Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.</summary>
-    /// <remarks>This is only implemented in <see cref="UnixDriver"/>.</remarks>
+    /// <remarks>This is only implemented in the Unix driver.</remarks>
     public abstract void Suspend ();
 
     /// <summary>Sets the position of the terminal cursor to <see cref="Col"/> and <see cref="Row"/>.</summary>
@@ -603,20 +628,7 @@ public abstract class ConsoleDriver : IConsoleDriver
     /// <summary>Gets the current <see cref="Attribute"/>.</summary>
     /// <returns>The current attribute.</returns>
     public Attribute GetAttribute () { return CurrentAttribute; }
-
-    /// <summary>Makes an <see cref="Attribute"/>.</summary>
-    /// <param name="foreground">The foreground color.</param>
-    /// <param name="background">The background color.</param>
-    /// <returns>The attribute for the foreground and background colors.</returns>
-    public virtual Attribute MakeColor (in Color foreground, in Color background)
-    {
-        // Encode the colors into the int value.
-        return new (
-                    foreground,
-                    background
-                   );
-    }
-
+    
     #endregion Color Handling
 
     #region Mouse Handling

+ 37 - 25
Terminal.Gui/Drivers/ConsoleDriverFacade.cs

@@ -10,13 +10,15 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
     private readonly AnsiRequestScheduler _ansiRequestScheduler;
     private CursorVisibility _lastCursor = CursorVisibility.Default;
 
-    /// <summary>The event fired when the terminal is resized.</summary>
+    /// <summary>
+    /// The event fired when the screen changes (size, position, etc.).
+    /// </summary>
     public event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     public IInputProcessor InputProcessor { get; }
     public IOutputBuffer OutputBuffer => _outputBuffer;
 
-    public IWindowSizeMonitor WindowSizeMonitor { get; }
+    public IConsoleSizeMonitor ConsoleSizeMonitor { get; }
 
 
     public ConsoleDriverFacade (
@@ -24,7 +26,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
         IOutputBuffer outputBuffer,
         IConsoleOutput output,
         AnsiRequestScheduler ansiRequestScheduler,
-        IWindowSizeMonitor windowSizeMonitor
+        IConsoleSizeMonitor sizeMonitor
     )
     {
         InputProcessor = inputProcessor;
@@ -40,8 +42,12 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
                                          MouseEvent?.Invoke (s, e);
                                      };
 
-        WindowSizeMonitor = windowSizeMonitor;
-        windowSizeMonitor.SizeChanging += (_,e) => SizeChanged?.Invoke (this, e);
+        ConsoleSizeMonitor = sizeMonitor;
+        sizeMonitor.SizeChanged += (_, e) =>
+        {
+            SetScreenSize(e.Size!.Value.Width, e.Size.Value.Height);
+            //SizeChanged?.Invoke (this, e);
+        };
 
         CreateClipboard ();
     }
@@ -50,7 +56,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
     {
         if (FakeDriver.FakeBehaviors.UseFakeClipboard)
         {
-            Clipboard = new FakeDriver.FakeClipboard (
+            Clipboard = new FakeClipboard (
                 FakeDriver.FakeBehaviors.FakeClipboardAlwaysThrowsNotSupportedException,
                 FakeDriver.FakeBehaviors.FakeClipboardIsSupportedAlwaysFalse);
 
@@ -73,7 +79,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
         }
         else
         {
-            Clipboard = new FakeDriver.FakeClipboard ();
+            Clipboard = new FakeClipboard ();
         }
     }
 
@@ -88,10 +94,23 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
                 return Rectangle.Empty;
             }
 
-            return new (new (0, 0), _output.GetWindowSize ());
+            return new (0, 0, _outputBuffer.Cols, _outputBuffer.Rows);
         }
     }
 
+    /// <summary>
+    /// Sets the screen size for testing purposes. Only supported by FakeDriver.
+    /// </summary>
+    /// <param name="width">The new width in columns.</param>
+    /// <param name="height">The new height in rows.</param>
+    /// <exception cref="NotSupportedException">Thrown when called on non-FakeDriver instances.</exception>
+    public virtual void SetScreenSize (int width, int height)
+    {
+        _outputBuffer.SetSize (width, height);
+        _output.SetSize (width, height);
+        SizeChanged?.Invoke(this, new (new (width, height)));
+    }
+
     /// <summary>
     ///     Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
     ///     to.
@@ -104,7 +123,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
     }
 
     /// <summary>Get the operating system clipboard.</summary>
-    public IClipboard Clipboard { get; private set; } = new FakeDriver.FakeClipboard ();
+    public IClipboard Clipboard { get; private set; } = new FakeClipboard ();
 
     /// <summary>
     ///     Gets the column last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/> are used by
@@ -364,7 +383,6 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
     public void UpdateCursor () { _output.SetCursorPosition (Col, Row); }
 
     /// <summary>Initializes the driver</summary>
-    /// <returns>Returns an instance of <see cref="MainLoop"/> using the <see cref="IMainLoopDriver"/> for the driver.</returns>
     public void Init () { throw new NotSupportedException (); }
 
     /// <summary>Ends the execution of the console driver.</summary>
@@ -375,26 +393,20 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
 
     /// <summary>Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.</summary>
     /// <remarks>Implementations should call <c>base.SetAttribute(c)</c>.</remarks>
-    /// <param name="c">C.</param>
-    public Attribute SetAttribute (Attribute c) { return _outputBuffer.CurrentAttribute = c; }
+    /// <param name="newAttribute">C.</param>
+    /// <returns>The previously set Attribute.</returns>
+    public Attribute SetAttribute (Attribute newAttribute)
+    {
+        Attribute currentAttribute = _outputBuffer.CurrentAttribute;
+        _outputBuffer.CurrentAttribute = newAttribute;
+
+        return currentAttribute;
+    }
 
     /// <summary>Gets the current <see cref="Attribute"/>.</summary>
     /// <returns>The current attribute.</returns>
     public Attribute GetAttribute () { return _outputBuffer.CurrentAttribute; }
 
-    /// <summary>Makes an <see cref="Attribute"/>.</summary>
-    /// <param name="foreground">The foreground color.</param>
-    /// <param name="background">The background color.</param>
-    /// <returns>The attribute for the foreground and background colors.</returns>
-    public Attribute MakeColor (in Color foreground, in Color background)
-    {
-        // TODO: what even is this? why Attribute constructor wants to call Driver method which must return an instance of Attribute? ?!?!?!
-        return new (
-                    foreground,
-                    background
-                   );
-    }
-
     /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary>
     public event EventHandler<Key>? KeyDown;
 

+ 1 - 1
Terminal.Gui/Drivers/ConsoleKeyMapping.cs

@@ -533,7 +533,7 @@ public static class ConsoleKeyMapping
 
     /// <summary>
     ///     Get the output character from the <see cref="GetConsoleKeyInfoFromKeyCode"/>, with the correct
-    ///     <see cref="ConsoleKey"/> and the scan code used on <see cref="WindowsDriver"/>.
+    ///     <see cref="ConsoleKey"/> and the scan code used on Windows.
     /// </summary>
     /// <param name="unicodeChar">The unicode character.</param>
     /// <param name="modifiers">The modifiers keys.</param>

+ 35 - 0
Terminal.Gui/Drivers/ConsoleSizeMonitor.cs

@@ -0,0 +1,35 @@
+#nullable enable
+using Microsoft.Extensions.Logging;
+
+namespace Terminal.Gui.Drivers;
+
+/// <inheritdoc />
+internal class ConsoleSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer _) : IConsoleSizeMonitor
+{
+    private Size _lastSize = Size.Empty;
+
+    /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
+    public event EventHandler<SizeChangedEventArgs>? SizeChanged;
+
+    /// <inheritdoc/>
+    public bool Poll ()
+    {
+        if (ConsoleDriver.RunningUnitTests)
+        {
+            return false;
+        }
+
+        Size size = consoleOut.GetSize ();
+
+        if (size != _lastSize)
+        {
+            Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}");
+            _lastSize = size;
+            SizeChanged?.Invoke (this, new (size));
+
+            return true;
+        }
+
+        return false;
+    }
+}

+ 7 - 1
Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs

@@ -35,7 +35,7 @@ public class NetOutput : OutputBase, IConsoleOutput
 
 
     /// <inheritdoc/>
-    public Size GetWindowSize ()
+    public Size GetSize ()
     {
         if (ConsoleDriver.RunningUnitTests)
         {
@@ -49,6 +49,12 @@ public class NetOutput : OutputBase, IConsoleOutput
     /// <inheritdoc/>
     public void SetCursorPosition (int col, int row) { SetCursorPositionImpl (col, row); }
 
+    /// <inheritdoc />
+    public void SetSize (int width, int height)
+    {
+        // Do Nothing.
+    }
+
     private Point? _lastCursorPosition;
 
     /// <inheritdoc/>

+ 59 - 0
Terminal.Gui/Drivers/FakeDriver/FakeClipboard.cs

@@ -0,0 +1,59 @@
+#nullable enable
+namespace Terminal.Gui.Drivers;
+
+/// <summary>
+///     Implements a fake clipboard for testing purposes.
+/// </summary>
+public class FakeClipboard : ClipboardBase
+{
+    /// <summary>
+    ///     Gets or sets an exception to be thrown by clipboard operations.
+    /// </summary>
+    public Exception? FakeException { get; set; }
+
+    private readonly bool _isSupportedAlwaysFalse;
+    private string _contents = string.Empty;
+
+    /// <summary>
+    ///     Constructs a new instance of <see cref="FakeClipboard"/>.
+    /// </summary>
+    /// <param name="fakeClipboardThrowsNotSupportedException"></param>
+    /// <param name="isSupportedAlwaysFalse"></param>
+    public FakeClipboard (
+        bool fakeClipboardThrowsNotSupportedException = false,
+        bool isSupportedAlwaysFalse = false
+    )
+    {
+        _isSupportedAlwaysFalse = isSupportedAlwaysFalse;
+
+        if (fakeClipboardThrowsNotSupportedException)
+        {
+            FakeException = new NotSupportedException ("Fake clipboard exception");
+        }
+    }
+
+    /// <inheritdoc />
+    public override bool IsSupported => !_isSupportedAlwaysFalse;
+
+    /// <inheritdoc />
+    protected override string GetClipboardDataImpl ()
+    {
+        if (FakeException is { })
+        {
+            throw FakeException;
+        }
+
+        return _contents;
+    }
+
+    /// <inheritdoc />
+    protected override void SetClipboardDataImpl (string? text)
+    {
+        if (FakeException is { })
+        {
+            throw FakeException;
+        }
+
+        _contents = text ?? throw new ArgumentNullException (nameof (text));
+    }
+}

+ 3 - 2
Terminal.Gui/Drivers/FakeDriver/FakeComponentFactory.cs

@@ -42,8 +42,9 @@ public class FakeComponentFactory : ComponentFactory<ConsoleKeyInfo>
     }
 
     /// <inheritdoc />
-    public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
+    public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
     {
-        return new FakeWindowSizeMonitor(consoleOutput, outputBuffer);
+        outputBuffer.SetSize(consoleOutput.GetSize().Width, consoleOutput.GetSize().Height);
+        return new ConsoleSizeMonitor (consoleOutput, outputBuffer);
     }
 }

+ 3 - 3
Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs

@@ -32,10 +32,10 @@ public static class FakeConsole
 #pragma warning disable RCS1138 // Add summary to documentation comment.
 
     /// <summary>Specifies the initial console width.</summary>
-    public const int WIDTH = 80;
+    public const int WIDTH = 0;
 
     /// <summary>Specifies the initial console height.</summary>
-    public const int HEIGHT = 25;
+    public const int HEIGHT = 0;
 
     /// <summary></summary>
     public static int WindowWidth { get; set; } = WIDTH;
@@ -971,7 +971,7 @@ public static class FakeConsole
     /// <summary></summary>
     /// <param name="width"></param>
     /// <param name="height"></param>
-    public static void SetWindowSize (int width, int height)
+    public static void SetConsoleSize (int width, int height)
     {
         WindowWidth = width;
         WindowHeight = height;

+ 16 - 30
Terminal.Gui/Drivers/FakeDriver/FakeConsoleOutput.cs

@@ -1,33 +1,28 @@
 #nullable enable
-using System;
-using System.Text;
-
 namespace Terminal.Gui.Drivers;
 
 /// <summary>
-/// Fake console output for testing that captures what would be written to the console.
+///     Fake console output for testing that captures what would be written to the console.
 /// </summary>
 public class FakeConsoleOutput : OutputBase, IConsoleOutput
 {
     private readonly StringBuilder _output = new ();
     private int _cursorLeft;
     private int _cursorTop;
-    private Size _windowSize = new (80, 25);
+    private Size _consoleSize = new (80, 25);
 
     /// <summary>
-    /// Gets the captured output as a string.
+    ///     Gets the captured output as a string.
     /// </summary>
     public string Output => _output.ToString ();
 
-    /// <summary>
-    /// Clears the captured output.
-    /// </summary>
-    public void ClearOutput () => _output.Clear ();
-
     /// <inheritdoc/>
-    public void SetCursorPosition (int col, int row)
+    public void SetCursorPosition (int col, int row) { SetCursorPositionImpl (col, row); }
+
+    /// <inheritdoc />
+    public void SetSize (int width, int height)
     {
-        SetCursorPositionImpl (col, row);
+        _consoleSize = new (width, height);
     }
 
     /// <inheritdoc/>
@@ -35,30 +30,25 @@ public class FakeConsoleOutput : OutputBase, IConsoleOutput
     {
         _cursorLeft = col;
         _cursorTop = row;
+
         return true;
     }
 
     /// <summary>
-    /// Sets the fake window size.
+    ///     Sets the fake window size.
     /// </summary>
-    public void SetWindowSize (int width, int height)
-    {
-        _windowSize = new Size (width, height);
-    }
+    public void SetConsoleSize (int width, int height) { _consoleSize = new (width, height); }
 
     /// <summary>
-    /// Gets the current cursor position.
+    ///     Gets the current cursor position.
     /// </summary>
-    public (int left, int top) GetCursorPosition () => (_cursorLeft, _cursorTop);
+    public (int left, int top) GetCursorPosition () { return (_cursorLeft, _cursorTop); }
 
     /// <inheritdoc/>
-    public Size GetWindowSize () => _windowSize;
+    public Size GetSize () { return _consoleSize; }
 
     /// <inheritdoc/>
-    public void Write (ReadOnlySpan<char> text)
-    {
-        _output.Append (text);
-    }
+    public void Write (ReadOnlySpan<char> text) { _output.Append (text); }
 
     /// <inheritdoc/>
     public override void SetCursorVisibility (CursorVisibility visibility)
@@ -80,9 +70,5 @@ public class FakeConsoleOutput : OutputBase, IConsoleOutput
     }
 
     /// <inheritdoc/>
-    protected override void Write (StringBuilder output)
-    {
-        _output.Append (output);
-    }
-
+    protected override void Write (StringBuilder output) { _output.Append (output); }
 }

+ 33 - 177
Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs

@@ -1,4 +1,5 @@
 #nullable enable
+
 //
 // FakeDriver.cs: A fake IConsoleDriver for unit tests. 
 //
@@ -6,8 +7,6 @@
 using System.Diagnostics;
 using System.Runtime.InteropServices;
 
-// Alias Console to MockConsole so we don't accidentally use Console
-
 namespace Terminal.Gui.Drivers;
 
 /// <summary>Implements a mock IConsoleDriver for unit testing</summary>
@@ -28,8 +27,8 @@ public class FakeDriver : ConsoleDriver
             FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue;
 
             // double check usage is correct
-            Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false);
-            Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false);
+            Debug.Assert (!useFakeClipboard && !fakeClipboardAlwaysThrowsNotSupportedException);
+            Debug.Assert (!useFakeClipboard && !fakeClipboardIsSupportedAlwaysTrue);
         }
 
         public bool FakeClipboardAlwaysThrowsNotSupportedException { get; internal set; }
@@ -40,19 +39,16 @@ public class FakeDriver : ConsoleDriver
     public static Behaviors FakeBehaviors { get; } = new ();
     public override bool SupportsTrueColor => false;
 
-    /// <inheritdoc />
-    public override void WriteRaw (string ansi)
-    {
-
-    }
+    /// <inheritdoc/>
+    public override void WriteRaw (string ansi) { }
 
     public FakeDriver ()
     {
         // FakeDriver implies UnitTests
         RunningUnitTests = true;
 
-        base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
-        base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
+        //base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
+        //base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
 
         if (FakeBehaviors.UseFakeClipboard)
         {
@@ -95,16 +91,19 @@ public class FakeDriver : ConsoleDriver
     {
         FakeConsole.MockKeyPresses.Clear ();
 
-        Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
-        Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
+        //Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
+        //Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
         FakeConsole.Clear ();
+
+        SetScreenSize (80,25);
         ResizeScreen ();
-        CurrentAttribute = new Attribute (Color.White, Color.Black);
+        ClearContents ();
+        CurrentAttribute = new (Color.White, Color.Black);
     }
 
     public override bool UpdateScreen ()
     {
-        bool updated = false;
+        var updated = false;
 
         int savedRow = FakeConsole.CursorTop;
         int savedCol = FakeConsole.CursorLeft;
@@ -223,117 +222,8 @@ public class FakeDriver : ConsoleDriver
         FakeConsole.CursorTop = savedRow;
         FakeConsole.CursorLeft = savedCol;
         FakeConsole.CursorVisible = savedCursorVisible;
-        return updated;
-    }
-
-
-    #region Color Handling
-
-    ///// <remarks>
-    ///// In the FakeDriver, colors are encoded as an int; same as DotNetDriver
-    ///// However, the foreground color is stored in the most significant 16 bits, 
-    ///// and the background color is stored in the least significant 16 bits.
-    ///// </remarks>
-    //public override Attribute MakeColor (Color foreground, Color background)
-    //{
-    //	// Encode the colors into the int value.
-    //	return new Attribute (
-    //		foreground: foreground,
-    //		background: background
-    //	);
-    //}
-
-    #endregion
-
-    private KeyCode MapKey (ConsoleKeyInfo keyInfo)
-    {
-        switch (keyInfo.Key)
-        {
-            case ConsoleKey.Escape:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Esc);
-            case ConsoleKey.Tab:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Tab);
-            case ConsoleKey.Clear:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Clear);
-            case ConsoleKey.Home:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Home);
-            case ConsoleKey.End:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.End);
-            case ConsoleKey.LeftArrow:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorLeft);
-            case ConsoleKey.RightArrow:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorRight);
-            case ConsoleKey.UpArrow:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorUp);
-            case ConsoleKey.DownArrow:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.CursorDown);
-            case ConsoleKey.PageUp:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageUp);
-            case ConsoleKey.PageDown:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PageDown);
-            case ConsoleKey.Enter:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Enter);
-            case ConsoleKey.Spacebar:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (
-                                                                keyInfo.Modifiers,
-                                                                keyInfo.KeyChar == 0
-                                                                    ? KeyCode.Space
-                                                                    : (KeyCode)keyInfo.KeyChar
-                                                               );
-            case ConsoleKey.Backspace:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Backspace);
-            case ConsoleKey.Delete:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Delete);
-            case ConsoleKey.Insert:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.Insert);
-            case ConsoleKey.PrintScreen:
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, KeyCode.PrintScreen);
-
-            case ConsoleKey.Oem1:
-            case ConsoleKey.Oem2:
-            case ConsoleKey.Oem3:
-            case ConsoleKey.Oem4:
-            case ConsoleKey.Oem5:
-            case ConsoleKey.Oem6:
-            case ConsoleKey.Oem7:
-            case ConsoleKey.Oem8:
-            case ConsoleKey.Oem102:
-            case ConsoleKey.OemPeriod:
-            case ConsoleKey.OemComma:
-            case ConsoleKey.OemPlus:
-            case ConsoleKey.OemMinus:
-                if (keyInfo.KeyChar == 0)
-                {
-                    return KeyCode.Null;
-                }
-
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar);
-        }
-
-        ConsoleKey key = keyInfo.Key;
-
-        if (key >= ConsoleKey.A && key <= ConsoleKey.Z)
-        {
-            int delta = key - ConsoleKey.A;
-
-            if (keyInfo.KeyChar != (uint)key)
-            {
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.Key);
-            }
-
-            if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Control)
-                || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Alt)
-                || keyInfo.Modifiers.HasFlag (ConsoleModifiers.Shift))
-            {
-                return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)KeyCode.A + delta));
-            }
 
-            char alphaBase = keyInfo.Modifiers != ConsoleModifiers.Shift ? 'A' : 'a';
-
-            return (KeyCode)((uint)alphaBase + delta);
-        }
-
-        return ConsoleKeyMapping.MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)keyInfo.KeyChar);
+        return updated;
     }
 
     private CursorVisibility _savedCursorVisibility;
@@ -356,7 +246,6 @@ public class FakeDriver : ConsoleDriver
         return FakeConsole.CursorVisible = visibility == CursorVisibility.Default;
     }
 
-    /// <inheritdoc/>
     private bool EnsureCursorVisibility ()
     {
         if (!(Col >= 0 && Row >= 0 && Col < Cols && Row < Rows))
@@ -373,23 +262,32 @@ public class FakeDriver : ConsoleDriver
         return FakeConsole.CursorVisible;
     }
 
-    private AnsiResponseParser _parser = new ();
+    private readonly AnsiResponseParser _parser = new ();
+
+    /// <inheritdoc/>
+    internal override IAnsiResponseParser GetParser () { return _parser; }
 
-    /// <inheritdoc />
-    internal override IAnsiResponseParser GetParser () => _parser;
+    /// <summary>
+    ///     Sets the screen size for testing purposes. Only available in FakeDriver.
+    ///     This method updates the driver's dimensions and triggers the ScreenChanged event.
+    /// </summary>
+    /// <param name="width">The new width in columns.</param>
+    /// <param name="height">The new height in rows.</param>
+    public override void SetScreenSize (int width, int height) { SetBufferSize (width, height); }
 
     public void SetBufferSize (int width, int height)
     {
         FakeConsole.SetBufferSize (width, height);
         Cols = width;
         Rows = height;
-        SetWindowSize (width, height);
+        SetConsoleSize (width, height);
         ProcessResize ();
     }
 
-    public void SetWindowSize (int width, int height)
+    public void SetConsoleSize (int width, int height)
     {
-        FakeConsole.SetWindowSize (width, height);
+        FakeConsole.SetConsoleSize (width, height);
+        FakeConsole.SetBufferSize (width, height);
 
         if (width != Cols || height != Rows)
         {
@@ -416,7 +314,7 @@ public class FakeDriver : ConsoleDriver
     {
         ResizeScreen ();
         ClearContents ();
-        OnSizeChanged (new SizeChangedEventArgs (new (Cols, Rows)));
+        OnSizeChanged (new (new (Cols, Rows)));
     }
 
     public virtual void ResizeScreen ()
@@ -452,7 +350,7 @@ public class FakeDriver : ConsoleDriver
             return;
         }
 
-        // Prevents the exception of size changing during resizing.
+        // Prevents the exception to size changing during resizing.
         try
         {
             // BUGBUG: Why is this using BufferWidth/Height and now Cols/Rows?
@@ -476,48 +374,6 @@ public class FakeDriver : ConsoleDriver
 
     #endregion
 
-    public class FakeClipboard : ClipboardBase
-    {
-        public Exception? FakeException { get; set; }
-
-        private readonly bool _isSupportedAlwaysFalse;
-        private string _contents = string.Empty;
-
-        public FakeClipboard (
-            bool fakeClipboardThrowsNotSupportedException = false,
-            bool isSupportedAlwaysFalse = false
-        )
-        {
-            _isSupportedAlwaysFalse = isSupportedAlwaysFalse;
-
-            if (fakeClipboardThrowsNotSupportedException)
-            {
-                FakeException = new NotSupportedException ("Fake clipboard exception");
-            }
-        }
-
-        public override bool IsSupported => !_isSupportedAlwaysFalse;
-
-        protected override string GetClipboardDataImpl ()
-        {
-            if (FakeException is { })
-            {
-                throw FakeException;
-            }
-
-            return _contents;
-        }
-
-        protected override void SetClipboardDataImpl (string? text)
-        {
-            if (FakeException is { })
-            {
-                throw FakeException;
-            }
-
-            _contents = text ?? throw new ArgumentNullException (nameof (text));
-        }
-    }
 
 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
-}
+}

+ 0 - 41
Terminal.Gui/Drivers/FakeDriver/FakeWindowSizeMonitor.cs

@@ -1,41 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace Terminal.Gui.Drivers;
-
-internal class FakeWindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer) : IWindowSizeMonitor
-{
-    private Size _lastSize = new (0, 0);
-
-    /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
-    public event EventHandler<SizeChangedEventArgs> SizeChanging;
-
-    /// <summary>Raises the <see cref="SizeChanging"/> event with the specified size. Used for testing.</summary>
-    /// <param name="newSize">The new size to report.</param>
-    public void RaiseSizeChanging (Size newSize)
-    {
-        SizeChanging?.Invoke (this, new (newSize));
-    }
-
-    /// <inheritdoc/>
-    public bool Poll ()
-    {
-        if (ConsoleDriver.RunningUnitTests)
-        {
-            return false;
-        }
-
-        Size size = consoleOut.GetWindowSize ();
-
-        if (size != _lastSize)
-        {
-            Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}");
-            outputBuffer.SetWindowSize (size.Width, size.Height);
-            _lastSize = size;
-            SizeChanging?.Invoke (this, new (size));
-
-            return true;
-        }
-
-        return false;
-    }
-}

+ 3 - 3
Terminal.Gui/Drivers/IComponentFactory.cs

@@ -41,11 +41,11 @@ public interface IComponentFactory<T> : IComponentFactory
     IInputProcessor CreateInputProcessor (ConcurrentQueue<T> inputBuffer);
 
     /// <summary>
-    /// Creates <see cref="IWindowSizeMonitor"/> class for the current driver implementation i.e. the class responsible for
-    /// reporting the current size of the terminal window.
+    /// Creates <see cref="IConsoleSizeMonitor"/> class for the current driver implementation i.e. the class responsible for
+    /// reporting the current size of the terminal.
     /// </summary>
     /// <param name="consoleOutput"></param>
     /// <param name="outputBuffer"></param>
     /// <returns></returns>
-    IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer);
+    IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer);
 }

+ 14 - 8
Terminal.Gui/Drivers/IConsoleDriver.cs

@@ -14,6 +14,15 @@ public interface IConsoleDriver
     /// <summary>Gets the location and size of the terminal screen.</summary>
     Rectangle Screen { get; }
 
+    /// <summary>
+    /// Sets the screen size for testing purposes. Only supported by FakeDriver.
+    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    /// </summary>
+    /// <param name="width">The new width in columns.</param>
+    /// <param name="height">The new height in rows.</param>
+    /// <exception cref="NotSupportedException">Thrown when called on non-FakeDriver instances.</exception>
+    void SetScreenSize (int width, int height);
+
     /// <summary>
     ///     Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
     ///     to.
@@ -200,11 +209,14 @@ public interface IConsoleDriver
     /// <returns><see langword="true"/> upon success</returns>
     bool SetCursorVisibility (CursorVisibility visibility);
 
-    /// <summary>The event fired when the terminal is resized.</summary>
+    /// <summary>
+    /// The event fired when the screen changes (size, position, etc.).
+    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    /// </summary>
     event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     /// <summary>Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.</summary>
-    /// <remarks>This is only implemented in <see cref="UnixDriver"/>.</remarks>
+    /// <remarks>This is only implemented in UnixDriver.</remarks>
     void Suspend ();
 
     /// <summary>
@@ -228,12 +240,6 @@ public interface IConsoleDriver
     /// <returns>The current attribute.</returns>
     Attribute GetAttribute ();
 
-    /// <summary>Makes an <see cref="Attribute"/>.</summary>
-    /// <param name="foreground">The foreground color.</param>
-    /// <param name="background">The background color.</param>
-    /// <returns>The attribute for the foreground and background colors.</returns>
-    Attribute MakeColor (in Color foreground, in Color background);
-
     /// <summary>Event fired when a mouse event occurs.</summary>
     event EventHandler<MouseEventArgs>? MouseEvent;
 

+ 1 - 1
Terminal.Gui/Drivers/IConsoleDriverFacade.cs

@@ -22,5 +22,5 @@ public interface IConsoleDriverFacade
     ///     Interface for classes responsible for reporting the current
     ///     size of the terminal window.
     /// </summary>
-    IWindowSizeMonitor WindowSizeMonitor { get; }
+    IConsoleSizeMonitor ConsoleSizeMonitor { get; }
 }

+ 9 - 2
Terminal.Gui/Drivers/IConsoleOutput.cs

@@ -20,11 +20,11 @@ public interface IConsoleOutput : IDisposable
     void Write (IOutputBuffer buffer);
 
     /// <summary>
-    ///     Returns the current size of the console window in rows/columns (i.e.
+    ///     Returns the current size of the console in rows/columns (i.e.
     ///     of characters not pixels).
     /// </summary>
     /// <returns></returns>
-    public Size GetWindowSize ();
+    public Size GetSize ();
 
     /// <summary>
     ///     Updates the console cursor (the blinking underscore) to be hidden,
@@ -39,4 +39,11 @@ public interface IConsoleOutput : IDisposable
     /// <param name="col"></param>
     /// <param name="row"></param>
     void SetCursorPosition (int col, int row);
+
+    /// <summary>
+    ///     Sets the size of the console..
+    /// </summary>
+    /// <param name="width"></param>
+    /// <param name="height"></param>
+    void SetSize (int width, int height);
 }

+ 3 - 3
Terminal.Gui/Drivers/IWindowSizeMonitor.cs → Terminal.Gui/Drivers/IConsoleSizeMonitor.cs

@@ -6,13 +6,13 @@ namespace Terminal.Gui.Drivers;
 ///     Interface for classes responsible for reporting the current
 ///     size of the terminal window.
 /// </summary>
-public interface IWindowSizeMonitor
+public interface IConsoleSizeMonitor
 {
     /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
-    event EventHandler<SizeChangedEventArgs>? SizeChanging;
+    event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     /// <summary>
-    ///     Examines the current size of the terminal and raises <see cref="SizeChanging"/> if it is different
+    ///     Examines the current size of the terminal and raises <see cref="SizeChanged"/> if it is different
     ///     from last inspection.
     /// </summary>
     /// <returns></returns>

+ 1 - 1
Terminal.Gui/Drivers/IInputProcessor.cs

@@ -28,7 +28,7 @@ public interface IInputProcessor
     /// <summary>
     /// Gets the name of the driver associated with this input processor.
     /// </summary>
-    string DriverName { get; init; }
+    string? DriverName { get; init; }
 
     /// <summary>
     ///     Called when a key is pressed down. Fires the <see cref="KeyDown"/> event. This is a precursor to

+ 1 - 1
Terminal.Gui/Drivers/IOutputBuffer.cs

@@ -97,7 +97,7 @@ public interface IOutputBuffer
     /// </summary>
     /// <param name="cols"></param>
     /// <param name="rows"></param>
-    void SetWindowSize (int cols, int rows);
+    void SetSize (int cols, int rows);
 
     /// <summary>
     ///     Fills the given <paramref name="rect"/> with the given

+ 2 - 2
Terminal.Gui/Drivers/InputProcessor.cs

@@ -31,7 +31,7 @@ public abstract class InputProcessor<T> : IInputProcessor
     public ConcurrentQueue<T> InputBuffer { get; }
 
     /// <inheritdoc />
-    public string DriverName { get; init; }
+    public string? DriverName { get; init; }
 
     /// <inheritdoc/>
     public IAnsiResponseParser GetParser () { return Parser; }
@@ -166,7 +166,7 @@ public abstract class InputProcessor<T> : IInputProcessor
     /// <param name="input"></param>
     protected abstract void ProcessAfterParsing (T input);
 
-    internal char _highSurrogate = '\0';
+    private char _highSurrogate = '\0';
 
     /// <inheritdoc />
     public bool IsValidInput (Key key, out Key result)

+ 1 - 1
Terminal.Gui/Drivers/MouseButtonStateEx.cs

@@ -3,7 +3,7 @@
 namespace Terminal.Gui.Drivers;
 
 /// <summary>
-///     Not to be confused with <see cref="NetEvents.MouseButtonState"/>
+///     Not to be confused with NetEvents.MouseButtonState
 /// </summary>
 internal class MouseButtonStateEx
 {

+ 1 - 1
Terminal.Gui/Drivers/OutputBase.cs

@@ -56,7 +56,7 @@ public abstract class OutputBase
 
                 for (; col < cols; col++)
                 {
-                    if (!buffer.Contents [row, col].IsDirty)
+                    if (!buffer.Contents! [row, col].IsDirty)
                     {
                         if (output.Length > 0)
                         {

+ 3 - 3
Terminal.Gui/Drivers/OutputBuffer.cs

@@ -5,7 +5,7 @@ namespace Terminal.Gui.Drivers;
 
 /// <summary>
 ///     Stores the desired output state for the whole application. This is updated during
-///     draw operations before being flushed to the console as part of <see cref="MainLoop{T}"/>
+///     draw operations before being flushed to the console as part of the main loop.
 ///     operation
 /// </summary>
 public class OutputBuffer : IOutputBuffer
@@ -15,7 +15,7 @@ public class OutputBuffer : IOutputBuffer
     ///     UpdateScreen is called.
     ///     <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
     /// </summary>
-    public Cell [,] Contents { get; set; } = new Cell[0, 0];
+    public Cell [,]? Contents { get; set; } = new Cell[0, 0];
 
     private int _cols;
     private int _rows;
@@ -365,7 +365,7 @@ public class OutputBuffer : IOutputBuffer
     }
 
     /// <inheritdoc/>
-    public void SetWindowSize (int cols, int rows)
+    public void SetSize (int cols, int rows)
     {
         Cols = cols;
         Rows = rows;

+ 7 - 1
Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs

@@ -121,7 +121,7 @@ internal class UnixOutput : OutputBase, IConsoleOutput
     }
 
     /// <inheritdoc />
-    public Size GetWindowSize ()
+    public Size GetSize ()
     {
         if (ConsoleDriver.RunningUnitTests)
         {
@@ -168,6 +168,12 @@ internal class UnixOutput : OutputBase, IConsoleOutput
         SetCursorPositionImpl (col, row);
     }
 
+    /// <inheritdoc />
+    public void SetSize (int width, int height)
+    {
+        // Do nothing
+    }
+
     /// <inheritdoc />
     public void Dispose ()
     {

+ 0 - 42
Terminal.Gui/Drivers/WindowSizeMonitor.cs

@@ -1,42 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace Terminal.Gui.Drivers;
-
-internal class WindowSizeMonitor : IWindowSizeMonitor
-{
-    private readonly IConsoleOutput _consoleOut;
-    private readonly IOutputBuffer _outputBuffer;
-    private Size _lastSize = new (0, 0);
-
-    /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
-    public event EventHandler<SizeChangedEventArgs> SizeChanging;
-
-    public WindowSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer outputBuffer)
-    {
-        _consoleOut = consoleOut;
-        _outputBuffer = outputBuffer;
-    }
-
-    /// <inheritdoc/>
-    public bool Poll ()
-    {
-        if (ConsoleDriver.RunningUnitTests)
-        {
-            return false;
-        }
-
-        Size size = _consoleOut.GetWindowSize ();
-
-        if (size != _lastSize)
-        {
-            Logging.Logger.LogInformation ($"Console size changes from '{_lastSize}' to {size}");
-            _outputBuffer.SetWindowSize (size.Width, size.Height);
-            _lastSize = size;
-            SizeChanging?.Invoke (this, new (size));
-
-            return true;
-        }
-
-        return false;
-    }
-}

+ 31 - 908
Terminal.Gui/Drivers/WindowsDriver/WindowsConsole.cs

@@ -1,719 +1,25 @@
 #nullable enable
-using System.Collections.Concurrent;
-using System.ComponentModel;
 using System.Runtime.InteropServices;
-#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
-#pragma warning disable IDE1006// Naming rule violation: Prefix '_' is not expected
+
+// ReSharper disable InconsistentNaming
 
 namespace Terminal.Gui.Drivers;
 
-public partial class WindowsConsole
-{
-    private CancellationTokenSource? _inputReadyCancellationTokenSource;
-    private readonly BlockingCollection<InputRecord> _inputQueue = new (new ConcurrentQueue<InputRecord> ());
+#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
 
-    public const int STD_OUTPUT_HANDLE = -11;
+/// <summary>
+///     Definitions for Windows Console API structures and constants.
+/// </summary>
+public class WindowsConsole
+{
+    /// <summary>
+    ///     Standard input handle constant.
+    /// </summary>
     public const int STD_INPUT_HANDLE = -10;
 
-    private readonly nint _inputHandle;
-    private nint _outputHandle;
-    private nint _screenBuffer;
-    private readonly uint _originalConsoleMode;
-    private CursorVisibility? _initialCursorVisibility;
-    private CursorVisibility? _currentCursorVisibility;
-    private CursorVisibility? _pendingCursorVisibility;
-    private readonly StringBuilder _stringBuilder = new (256 * 1024);
-    private string _lastWrite = string.Empty;
-
-    public WindowsConsole ()
-    {
-        _inputHandle = GetStdHandle (STD_INPUT_HANDLE);
-        _outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
-        _originalConsoleMode = ConsoleMode;
-        uint newConsoleMode = _originalConsoleMode;
-        newConsoleMode |= (uint)(ConsoleModes.EnableMouseInput | ConsoleModes.EnableExtendedFlags);
-        newConsoleMode &= ~(uint)ConsoleModes.EnableQuickEditMode;
-        newConsoleMode &= ~(uint)ConsoleModes.EnableProcessedInput;
-        ConsoleMode = newConsoleMode;
-
-        IsVirtualTerminal = GetConsoleMode (_outputHandle, out uint mode) && (mode & (uint)ConsoleModes.EnableVirtualTerminalProcessing) != 0;
-
-        if (!IsVirtualTerminal)
-        {
-            CreateConsoleScreenBuffer ();
-            Size bufferSize = GetConsoleBufferWindow (out _);
-            SmallRect window = new ()
-            {
-                Top = 0,
-                Left = 0,
-                Bottom = (short)bufferSize.Height,
-                Right = (short)bufferSize.Width
-            };
-
-            ReadFromConsoleOutput (bufferSize, new ((short)bufferSize.Width, (short)bufferSize.Height), ref window);
-
-            if (!GetConsoleMode (_screenBuffer, out mode))
-            {
-                throw new ApplicationException ($"Failed to get screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}.");
-            }
-
-            const uint ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002;
-
-            mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; // Disable wrap
-
-            if (!SetConsoleMode (_screenBuffer, mode))
-            {
-                throw new ApplicationException ($"Failed to set screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}.");
-            }
-        }
-
-        SetInitialCursorVisibility ();
-
-        _inputReadyCancellationTokenSource = new ();
-        Task.Run (ProcessInputQueue, _inputReadyCancellationTokenSource.Token);
-    }
-
-    private void CreateConsoleScreenBuffer ()
-    {
-        _screenBuffer = CreateConsoleScreenBuffer (
-                                                   DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
-                                                   ShareMode.FileShareRead | ShareMode.FileShareWrite,
-                                                   nint.Zero,
-                                                   1,
-                                                   nint.Zero
-                                                  );
-
-        if (_screenBuffer == INVALID_HANDLE_VALUE)
-        {
-            int err = Marshal.GetLastWin32Error ();
-
-            if (err != 0)
-            {
-                throw new Win32Exception (err);
-            }
-        }
-
-        if (!SetConsoleActiveScreenBuffer (_screenBuffer))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-    }
-
-    public InputRecord? DequeueInput ()
-    {
-        while (_inputReadyCancellationTokenSource is { })
-        {
-            try
-            {
-                return _inputQueue.Take (_inputReadyCancellationTokenSource.Token);
-            }
-            catch (OperationCanceledException)
-            {
-                return null;
-            }
-        }
-
-        return null;
-    }
-
-    public InputRecord? ReadConsoleInput ()
-    {
-        const int BUFFER_SIZE = 1;
-        InputRecord inputRecord = default;
-        uint numberEventsRead = 0;
-
-        while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
-        {
-            try
-            {
-                // Peek to check if there is any input available
-                if (PeekConsoleInput (_inputHandle, out _, BUFFER_SIZE, out uint eventsRead) && eventsRead > 0)
-                {
-                    // Read the input since it is available
-                    ReadConsoleInput (
-                                      _inputHandle,
-                                      out inputRecord,
-                                      BUFFER_SIZE,
-                                      out numberEventsRead);
-                }
-
-                if (numberEventsRead > 0)
-                {
-                    return inputRecord;
-                }
-
-                try
-                {
-                    Task.Delay (100, _inputReadyCancellationTokenSource.Token).Wait (_inputReadyCancellationTokenSource.Token);
-                }
-                catch (OperationCanceledException)
-                {
-                    return null;
-                }
-            }
-            catch (Exception ex)
-            {
-                if (ex is OperationCanceledException or ObjectDisposedException)
-                {
-                    return null;
-                }
-
-                throw;
-            }
-        }
-
-        return null;
-    }
-
-    private void ProcessInputQueue ()
-    {
-        while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
-        {
-            try
-            {
-                if (_inputQueue.Count == 0)
-                {
-                    while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
-                    {
-                        try
-                        {
-                            InputRecord? inpRec = ReadConsoleInput ();
-
-                            if (inpRec is { })
-                            {
-                                _inputQueue.Add (inpRec.Value);
-
-                                break;
-                            }
-                        }
-                        catch (OperationCanceledException)
-                        {
-                            return;
-                        }
-                    }
-                }
-            }
-            catch (OperationCanceledException)
-            {
-                return;
-            }
-        }
-    }
-
-
-    // Last text style used, for updating style with EscSeqUtils.CSI_AppendTextStyleChange().
-    private TextStyle _redrawTextStyle = TextStyle.None;
-
-    private CharInfo []? _originalStdOutChars;
-
-    private struct Run
-    {
-        public ushort attr;
-        public string text;
-
-        public Run (ushort attr, string text)
-        {
-            this.attr = attr;
-            this.text = text;
-        }
-    }
-
-    public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord bufferSize, SmallRect window, bool force16Colors)
-    {
-        //Debug.WriteLine ("WriteToConsole");
-
-        Attribute? prev = null;
-        var result = false;
-
-        if (force16Colors)
-        {
-            _stringBuilder.Clear ();
-
-            var i = 0;
-            List<Run> runs = [];
-            Run? current = null;
-            SetCursorPosition (new Coord (0, 0));
-
-            foreach (ExtendedCharInfo info in charInfoBuffer)
-            {
-                if (IsVirtualTerminal)
-                {
-                    Attribute attr = info.Attribute;
-                    AnsiColorCode fgColor = info.Attribute.Foreground.GetAnsiColorCode ();
-                    AnsiColorCode bgColor = info.Attribute.Background.GetAnsiColorCode ();
-
-                    if (attr != prev)
-                    {
-                        prev = attr;
-                        _stringBuilder.Append (EscSeqUtils.CSI_SetForegroundColor (fgColor));
-                        _stringBuilder.Append (EscSeqUtils.CSI_SetBackgroundColor (bgColor));
-
-                        EscSeqUtils.CSI_AppendTextStyleChange (_stringBuilder, _redrawTextStyle, attr.Style);
-                        _redrawTextStyle = attr.Style;
-                    }
-
-                    if (info.Char [0] != '\x1b')
-                    {
-                        if (!info.Empty)
-                        {
-                            _stringBuilder.Append (info.Char);
-                        }
-                    }
-                    else
-                    {
-                        _stringBuilder.Append (' ');
-                    }
-                }
-                else
-                {
-                    if (info.Empty)
-                    {
-                        i++;
-                        continue;
-                    }
-
-                    if (!info.Empty)
-                    {
-                        var attr = (ushort)((int)info.Attribute.Foreground.GetClosestNamedColor16 ()
-                                            | ((int)info.Attribute.Background.GetClosestNamedColor16 () << 4));
-
-                        // Start new run if needed
-                        if (current == null || attr != current.Value.attr)
-                        {
-                            if (current != null)
-                            {
-                                runs.Add (new (current.Value.attr, _stringBuilder.ToString ()));
-                            }
-
-                            _stringBuilder.Clear ();
-                            current = new Run (attr, "");
-                        }
-
-                        _stringBuilder!.Append (info.Char);
-                    }
-
-                    i++;
-
-                    if (i > 0 && i <= charInfoBuffer.Length && i % bufferSize.X == 0)
-                    {
-                        if (i < charInfoBuffer.Length)
-                        {
-                            _stringBuilder.AppendLine ();
-                        }
-
-                        runs.Add (new (current!.Value.attr, _stringBuilder.ToString ()));
-                        _stringBuilder.Clear ();
-                    }
-                }
-            }
-
-            if (IsVirtualTerminal)
-            {
-                _stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
-                _stringBuilder.Append (EscSeqUtils.CSI_HideCursor);
-
-                var s = _stringBuilder.ToString ();
-
-                // TODO: requires extensive testing if we go down this route
-                // If console output has changed
-                if (s != _lastWrite)
-                {
-                    // supply console with the new content
-                    result = WriteConsole (_outputHandle, s, (uint)s.Length, out uint _, nint.Zero);
-                }
-
-                _lastWrite = s;
-
-                foreach (var sixel in Application.Sixel)
-                {
-                    SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y));
-                    WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
-                }
-            }
-            else
-            {
-                foreach (var run in runs)
-                {
-                    SetConsoleTextAttribute (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.attr);
-                    result = WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, run.text, (uint)run.text.Length, out _, nint.Zero);
-                }
-            }
-        }
-        else
-        {
-            _stringBuilder.Clear ();
-
-            _stringBuilder.Append (EscSeqUtils.CSI_SaveCursorPosition);
-            EscSeqUtils.CSI_AppendCursorPosition (_stringBuilder, 0, 0);
-
-            foreach (ExtendedCharInfo info in charInfoBuffer)
-            {
-                Attribute attr = info.Attribute;
-
-                if (attr != prev)
-                {
-                    prev = attr;
-                    EscSeqUtils.CSI_AppendForegroundColorRGB (_stringBuilder, attr.Foreground.R, attr.Foreground.G, attr.Foreground.B);
-                    EscSeqUtils.CSI_AppendBackgroundColorRGB (_stringBuilder, attr.Background.R, attr.Background.G, attr.Background.B);
-                    EscSeqUtils.CSI_AppendTextStyleChange (_stringBuilder, _redrawTextStyle, attr.Style);
-                    _redrawTextStyle = attr.Style;
-                }
-
-                if (info.Char [0] != '\x1b')
-                {
-                    if (!info.Empty)
-                    {
-                        _stringBuilder.Append (info.Char);
-                    }
-                }
-                else
-                {
-                    _stringBuilder.Append (' ');
-                }
-            }
-
-            _stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
-            _stringBuilder.Append (EscSeqUtils.CSI_HideCursor);
-
-            var s = _stringBuilder.ToString ();
-
-            // TODO: requires extensive testing if we go down this route
-            // If console output has changed
-            if (s != _lastWrite)
-            {
-                // supply console with the new content
-                result = WriteConsole (_outputHandle, s, (uint)s.Length, out uint _, nint.Zero);
-            }
-
-            _lastWrite = s;
-
-            foreach (var sixel in Application.Sixel)
-            {
-                SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y));
-                WriteConsole (IsVirtualTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
-            }
-        }
-
-        if (!result)
-        {
-            int err = Marshal.GetLastWin32Error ();
-
-            if (err != 0)
-            {
-                throw new Win32Exception (err);
-            }
-        }
-
-        return result;
-    }
-
-    internal bool WriteANSI (string ansi)
-    {
-        if (WriteConsole (_outputHandle, ansi, (uint)ansi.Length, out uint _, nint.Zero))
-        {
-            // Flush the output to make sure it's sent immediately
-            return FlushFileBuffers (_outputHandle);
-        }
-
-        return false;
-    }
-
-    public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window)
-    {
-        _originalStdOutChars = new CharInfo [size.Height * size.Width];
-
-        if (!ReadConsoleOutput (_screenBuffer, _originalStdOutChars, coords, new Coord { X = 0, Y = 0 }, ref window))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-    }
-
-    public bool SetCursorPosition (Coord position)
-    {
-        return SetConsoleCursorPosition (IsVirtualTerminal ? _outputHandle : _screenBuffer, position);
-    }
-
-    public void SetInitialCursorVisibility ()
-    {
-        if (_initialCursorVisibility.HasValue == false && GetCursorVisibility (out CursorVisibility visibility))
-        {
-            _initialCursorVisibility = visibility;
-        }
-    }
-
-    public bool GetCursorVisibility (out CursorVisibility visibility)
-    {
-        if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
-        {
-            visibility = CursorVisibility.Invisible;
-
-            return false;
-        }
-
-        if (!GetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, out ConsoleCursorInfo info))
-        {
-            int err = Marshal.GetLastWin32Error ();
-
-            if (err != 0)
-            {
-                throw new Win32Exception (err);
-            }
-
-            visibility = CursorVisibility.Default;
-
-            return false;
-        }
-
-        if (!info.bVisible)
-        {
-            visibility = CursorVisibility.Invisible;
-        }
-        else if (info.dwSize > 50)
-        {
-            visibility = CursorVisibility.Default;
-        }
-        else
-        {
-            visibility = CursorVisibility.Default;
-        }
-
-        return visibility != CursorVisibility.Invisible;
-    }
-
-    public bool EnsureCursorVisibility ()
-    {
-        if (_initialCursorVisibility.HasValue && _pendingCursorVisibility.HasValue && SetCursorVisibility (_pendingCursorVisibility.Value))
-        {
-            _pendingCursorVisibility = null;
-
-            return true;
-        }
-
-        return false;
-    }
-
-    public void ForceRefreshCursorVisibility ()
-    {
-        if (_currentCursorVisibility.HasValue)
-        {
-            _pendingCursorVisibility = _currentCursorVisibility;
-            _currentCursorVisibility = null;
-        }
-    }
-
-    public bool SetCursorVisibility (CursorVisibility visibility)
-    {
-        if (_initialCursorVisibility.HasValue == false)
-        {
-            _pendingCursorVisibility = visibility;
-
-            return false;
-        }
-
-        if (_currentCursorVisibility.HasValue == false || _currentCursorVisibility.Value != visibility)
-        {
-            var info = new ConsoleCursorInfo
-            {
-                dwSize = (uint)visibility & 0x00FF,
-                bVisible = ((uint)visibility & 0xFF00) != 0
-            };
-
-            if (!SetConsoleCursorInfo (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref info))
-            {
-                return false;
-            }
-
-            _currentCursorVisibility = visibility;
-        }
-
-        return true;
-    }
-
-    public void Cleanup ()
-    {
-        if (_initialCursorVisibility.HasValue)
-        {
-            SetCursorVisibility (_initialCursorVisibility.Value);
-        }
-
-        //SetConsoleOutputWindow (out _);
-
-        ConsoleMode = _originalConsoleMode;
-
-        _outputHandle = CreateConsoleScreenBuffer (
-                                                   DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
-                                                   ShareMode.FileShareRead | ShareMode.FileShareWrite,
-                                                   nint.Zero,
-                                                   1,
-                                                   nint.Zero
-                                                  );
-
-        if (!SetConsoleActiveScreenBuffer (_outputHandle))
-        {
-            int err = Marshal.GetLastWin32Error ();
-            Console.WriteLine ("Error: {0}", err);
-        }
-
-        if (_screenBuffer != nint.Zero)
-        {
-            CloseHandle (_screenBuffer);
-        }
-
-        _screenBuffer = nint.Zero;
-
-        _inputReadyCancellationTokenSource?.Cancel ();
-        _inputReadyCancellationTokenSource?.Dispose ();
-        _inputReadyCancellationTokenSource = null;
-    }
-
-    internal Size GetConsoleBufferWindow (out Point position)
-    {
-        if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
-        {
-            position = Point.Empty;
-
-            return Size.Empty;
-        }
-
-        var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
-        csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
-        if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
-        {
-            //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
-            position = Point.Empty;
-
-            return Size.Empty;
-        }
-
-        Size sz = new (
-                       csbi.srWindow.Right - csbi.srWindow.Left + 1,
-                       csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
-        position = new (csbi.srWindow.Left, csbi.srWindow.Top);
-
-        return sz;
-    }
-
-    internal Size GetConsoleOutputWindow (out Point position)
-    {
-        var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
-        csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
-        if (!GetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        Size sz = new (
-                       csbi.srWindow.Right - csbi.srWindow.Left + 1,
-                       csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
-        position = new (csbi.srWindow.Left, csbi.srWindow.Top);
-
-        return sz;
-    }
-
-    internal Size SetConsoleWindow (short cols, short rows)
-    {
-        var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
-        csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
-        if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer);
-        short newCols = Math.Min (cols, maxWinSize.X);
-        short newRows = Math.Min (rows, maxWinSize.Y);
-        csbi.dwSize = new Coord (newCols, Math.Max (newRows, (short)1));
-        csbi.srWindow = new SmallRect (0, 0, newCols, newRows);
-        csbi.dwMaximumWindowSize = new Coord (newCols, newRows);
-
-        if (!SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0));
-
-        if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect))
-        {
-            //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
-            return new (cols, rows);
-        }
-
-        SetConsoleOutputWindow (csbi);
-
-        return new (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1);
-    }
-
-    internal Size GetLargestConsoleWindowSize ()
-    {
-        Coord maxWinSize = GetLargestConsoleWindowSize (IsVirtualTerminal ? _outputHandle : _screenBuffer);
-
-        return new (maxWinSize.X, maxWinSize.Y);
-    }
-
-    private void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
-    {
-        if ((IsVirtualTerminal
-                ? _outputHandle
-                : _screenBuffer) != nint.Zero && !SetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-    }
-
-    internal Size SetConsoleOutputWindow (out Point position)
-    {
-        if ((IsVirtualTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
-        {
-            position = Point.Empty;
-
-            return Size.Empty;
-        }
-
-        var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
-        csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
-        if (!GetConsoleScreenBufferInfoEx (IsVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        Size sz = new (
-                           csbi.srWindow.Right - csbi.srWindow.Left + 1,
-                           Math.Max (csbi.srWindow.Bottom - csbi.srWindow.Top + 1, 0));
-        position = new (csbi.srWindow.Left, csbi.srWindow.Top);
-        SetConsoleOutputWindow (csbi);
-        var winRect = new SmallRect (0, 0, (short)(sz.Width - 1), (short)Math.Max (sz.Height - 1, 0));
-
-        if (!SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect))
-        {
-            throw new Win32Exception (Marshal.GetLastWin32Error ());
-        }
-
-        return sz;
-    }
-
-    internal bool IsVirtualTerminal { get; init; }
-
-    private uint ConsoleMode
-    {
-        get
-        {
-            GetConsoleMode (_inputHandle, out uint v);
-
-            return v;
-        }
-        set => SetConsoleMode (_inputHandle, value);
-    }
-
+    /// <summary>
+    ///     Windows Console mode flags.
+    /// </summary>
     [Flags]
     public enum ConsoleModes : uint
     {
@@ -724,6 +30,9 @@ public partial class WindowsConsole
         EnableExtendedFlags = 128
     }
 
+    /// <summary>
+    ///     Key event record structure.
+    /// </summary>
     [StructLayout (LayoutKind.Explicit, CharSet = CharSet.Unicode)]
     public struct KeyEventRecord
     {
@@ -811,11 +120,9 @@ public partial class WindowsConsole
         public readonly override string ToString () { return $"[Mouse{MousePosition},{ButtonState},{ControlKeyState},{EventFlags}]"; }
     }
 
-    public struct WindowBufferSizeRecord
+    public struct WindowBufferSizeRecord (short x, short y)
     {
-        public Coord _size;
-
-        public WindowBufferSizeRecord (short x, short y) { _size = new Coord (x, y); }
+        public Coord _size = new (x, y);
 
         public readonly override string ToString () { return $"[WindowBufferSize{_size}"; }
     }
@@ -865,41 +172,17 @@ public partial class WindowsConsole
         public readonly override string ToString ()
         {
             return (EventType switch
-            {
-                EventType.Focus => FocusEvent.ToString (),
-                EventType.Key => KeyEvent.ToString (),
-                EventType.Menu => MenuEvent.ToString (),
-                EventType.Mouse => MouseEvent.ToString (),
-                EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
-                _ => "Unknown event type: " + EventType
-            })!;
+                    {
+                        EventType.Focus => FocusEvent.ToString (),
+                        EventType.Key => KeyEvent.ToString (),
+                        EventType.Menu => MenuEvent.ToString (),
+                        EventType.Mouse => MouseEvent.ToString (),
+                        EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
+                        _ => "Unknown event type: " + EventType
+                    })!;
         }
     }
 
-    [Flags]
-    private enum ShareMode : uint
-    {
-        FileShareRead = 1,
-        FileShareWrite = 2
-    }
-
-    [Flags]
-    private enum DesiredAccess : uint
-    {
-        GenericRead = 2147483648,
-        GenericWrite = 1073741824
-    }
-
-    [StructLayout (LayoutKind.Sequential)]
-    public struct ConsoleScreenBufferInfo
-    {
-        public Coord dwSize;
-        public Coord dwCursorPosition;
-        public ushort wAttributes;
-        public SmallRect srWindow;
-        public Coord dwMaximumWindowSize;
-    }
-
     [StructLayout (LayoutKind.Sequential)]
     public struct Coord
     {
@@ -935,20 +218,6 @@ public partial class WindowsConsole
         public ushort Attributes;
     }
 
-    public struct ExtendedCharInfo
-    {
-        public char [] Char { get; set; }
-        public Attribute Attribute { get; set; }
-        public bool Empty { get; set; } // TODO: Temp hack until virtual terminal sequences
-
-        public ExtendedCharInfo (char [] character, Attribute attribute)
-        {
-            Char = character;
-            Attribute = attribute;
-            Empty = false;
-        }
-    }
-
     [StructLayout (LayoutKind.Sequential)]
     public struct SmallRect
     {
@@ -1045,147 +314,19 @@ public partial class WindowsConsole
         }
     }
 
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern nint GetStdHandle (int nStdHandle);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool CloseHandle (nint handle);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    public static extern bool PeekConsoleInput (nint hConsoleInput, out InputRecord lpBuffer, uint nLength, out uint lpNumberOfEventsRead);
-
-    [DllImport ("kernel32.dll", EntryPoint = "ReadConsoleInputW", CharSet = CharSet.Unicode)]
-    public static extern bool ReadConsoleInput (
-        nint hConsoleInput,
-        out InputRecord lpBuffer,
-        uint nLength,
-        out uint lpNumberOfEventsRead
-    );
-
-    [DllImport ("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
-    private static extern bool ReadConsoleOutput (
-        nint hConsoleOutput,
-        [Out] CharInfo [] lpBuffer,
-        Coord dwBufferSize,
-        Coord dwBufferCoord,
-        ref SmallRect lpReadRegion
-    );
-
-    // TODO: This API is obsolete. See https://learn.microsoft.com/en-us/windows/console/writeconsoleoutput
-    [DllImport ("kernel32.dll", EntryPoint = "WriteConsoleOutputW", SetLastError = true, CharSet = CharSet.Unicode)]
-    public static extern bool WriteConsoleOutput (
-        nint hConsoleOutput,
-        CharInfo [] lpBuffer,
-        Coord dwBufferSize,
-        Coord dwBufferCoord,
-        ref SmallRect lpWriteRegion
-    );
-
-    [LibraryImport ("kernel32.dll", EntryPoint = "WriteConsoleW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
-    [return: MarshalAs (UnmanagedType.Bool)]
-    private static partial bool WriteConsole (
-        nint hConsoleOutput,
-        ReadOnlySpan<char> lpbufer,
-        uint NumberOfCharsToWriten,
-        out uint lpNumberOfCharsWritten,
-        nint lpReserved
-    );
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool SetConsoleTextAttribute (
-        nint hConsoleOutput,
-        ushort wAttributes
-    );
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool FlushFileBuffers (nint hFile);
-
-    [DllImport ("kernel32.dll")]
-    private static extern bool SetConsoleCursorPosition (nint hConsoleOutput, Coord dwCursorPosition);
-
     [StructLayout (LayoutKind.Sequential)]
     public struct ConsoleCursorInfo
     {
         /// <summary>
-        /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
-        /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
-        /// line at the bottom of the cell.
+        ///     The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
+        ///     The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
+        ///     line at the bottom of the cell.
         /// </summary>
         public uint dwSize;
-        public bool bVisible;
-    }
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool SetConsoleCursorInfo (nint hConsoleOutput, [In] ref ConsoleCursorInfo lpConsoleCursorInfo);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool GetConsoleCursorInfo (nint hConsoleOutput, out ConsoleCursorInfo lpConsoleCursorInfo);
-
-    [DllImport ("kernel32.dll")]
-    private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode);
-
-    [DllImport ("kernel32.dll")]
-    private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern nint CreateConsoleScreenBuffer (
-        DesiredAccess dwDesiredAccess,
-        ShareMode dwShareMode,
-        nint secutiryAttributes,
-        uint flags,
-        nint screenBufferData
-    );
-
-    internal static nint INVALID_HANDLE_VALUE = new (-1);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool SetConsoleActiveScreenBuffer (nint handle);
 
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool GetNumberOfConsoleInputEvents (nint handle, out uint lpcNumberOfEvents);
-
-    internal uint GetNumberOfConsoleInputEvents ()
-    {
-        if (!GetNumberOfConsoleInputEvents (_inputHandle, out uint numOfEvents))
-        {
-            Console.WriteLine ($"Error: {Marshal.GetLastWin32Error ()}");
-
-            return 0;
-        }
-
-        return numOfEvents;
-    }
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool FlushConsoleInputBuffer (nint handle);
-
-    internal void FlushConsoleInputBuffer ()
-    {
-        if (!FlushConsoleInputBuffer (_inputHandle))
-        {
-            Console.WriteLine ($"Error: {Marshal.GetLastWin32Error ()}");
-        }
+        public bool bVisible;
     }
 
-#if false // Not needed on the constructor. Perhaps could be used on resizing. To study.
-		[DllImport ("kernel32.dll", ExactSpelling = true)]
-		static extern IntPtr GetConsoleWindow ();
-
-		[DllImport ("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
-		static extern bool ShowWindow (IntPtr hWnd, int nCmdShow);
-
-		public const int HIDE = 0;
-		public const int MAXIMIZE = 3;
-		public const int MINIMIZE = 6;
-		public const int RESTORE = 9;
-
-		internal void ShowWindow (int state)
-		{
-			IntPtr thisConsole = GetConsoleWindow ();
-			ShowWindow (thisConsole, state);
-		}
-#endif
-
     // See: https://github.com/gui-cs/Terminal.Gui/issues/357
 
     [StructLayout (LayoutKind.Sequential)]
@@ -1235,22 +376,4 @@ public partial class WindowsConsole
         [FieldOffset (0)]
         public uint Value;
     }
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool GetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX csbi);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool SetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX consoleScreenBufferInfo);
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern bool SetConsoleWindowInfo (
-        nint hConsoleOutput,
-        bool bAbsolute,
-        [In] ref SmallRect lpConsoleWindow
-    );
-
-    [DllImport ("kernel32.dll", SetLastError = true)]
-    private static extern Coord GetLargestConsoleWindowSize (
-        nint hConsoleOutput
-    );
 }

+ 9 - 8
Terminal.Gui/Drivers/WindowsDriver/WindowsInput.cs

@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+#nullable enable
+using System.Runtime.InteropServices;
 using Microsoft.Extensions.Logging;
 using static Terminal.Gui.Drivers.WindowsConsole;
 
@@ -66,13 +67,13 @@ internal class WindowsInput : ConsoleInput<InputRecord>, IWindowsInput
             return false;
         }
 
-        const int bufferSize = 1; // We only need to check if there's at least one event
-        nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf<InputRecord> () * bufferSize);
+        const int BUFFER_SIZE = 1; // We only need to check if there's at least one event
+        nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf<InputRecord> () * BUFFER_SIZE);
 
         try
         {
             // Use PeekConsoleInput to inspect the input buffer without removing events
-            if (PeekConsoleInput (_inputHandle, pRecord, bufferSize, out uint numberOfEventsRead))
+            if (PeekConsoleInput (_inputHandle, pRecord, BUFFER_SIZE, out uint numberOfEventsRead))
             {
                 // Return true if there's at least one event in the buffer
                 return numberOfEventsRead > 0;
@@ -86,7 +87,7 @@ internal class WindowsInput : ConsoleInput<InputRecord>, IWindowsInput
         catch (Exception ex)
         {
             // Optionally log the exception
-            Console.WriteLine ($"Error in Peek: {ex.Message}");
+            Console.WriteLine (@$"Error in Peek: {ex.Message}");
 
             return false;
         }
@@ -99,15 +100,15 @@ internal class WindowsInput : ConsoleInput<InputRecord>, IWindowsInput
 
     protected override IEnumerable<InputRecord> Read ()
     {
-        const int bufferSize = 1;
-        nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf<InputRecord> () * bufferSize);
+        const int BUFFER_SIZE = 1;
+        nint pRecord = Marshal.AllocHGlobal (Marshal.SizeOf<InputRecord> () * BUFFER_SIZE);
 
         try
         {
             ReadConsoleInput (
                               _inputHandle,
                               pRecord,
-                              bufferSize,
+                              BUFFER_SIZE,
                               out uint numberEventsRead);
 
             return numberEventsRead == 0

+ 7 - 1
Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs

@@ -356,7 +356,7 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput
     private Size? _lastWindowSizeBeforeMaximized;
     private bool _lockResize;
 
-    public Size GetWindowSize ()
+    public Size GetSize ()
     {
         if (_lockResize)
         {
@@ -497,6 +497,12 @@ internal partial class WindowsOutput : OutputBase, IConsoleOutput
         }
     }
 
+    /// <inheritdoc />
+    public void SetSize (int width, int height)
+    {
+        // Do Nothing.
+    }
+
     private bool _isDisposed;
     private bool _force16Colors;
     private nint _consoleBuffer;

+ 2 - 2
Terminal.Gui/Resources/Strings.Designer.cs

@@ -628,7 +628,7 @@ namespace Terminal.Gui.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Enter Path.
+        ///   Looks up a localized string similar to _Enter Path.
         /// </summary>
         internal static string fdPathCaption {
             get {
@@ -682,7 +682,7 @@ namespace Terminal.Gui.Resources {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Find.
+        ///   Looks up a localized string similar to _Find.
         /// </summary>
         internal static string fdSearchCaption {
             get {

+ 4 - 4
Terminal.Gui/Resources/Strings.resx

@@ -192,10 +192,7 @@
     <value>Modified</value>
   </data>
   <data name="fdPathCaption" xml:space="preserve">
-    <value>Enter Path</value>
-  </data>
-  <data name="fdSearchCaption" xml:space="preserve">
-    <value>Find</value>
+    <value>_Enter Path</value>
   </data>
   <data name="fdSize" xml:space="preserve">
     <value>Size</value>
@@ -359,4 +356,7 @@
     <value>_Tree</value>
     <comment>Show/Hide Tree View</comment>
   </data>
+  <data name="fdSearchCaption" xml:space="preserve">
+    <value>_Find</value>
+  </data>
 </root>

+ 6 - 6
Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs

@@ -688,7 +688,7 @@ public partial class Border
                 break;
 
             case ViewArrangement.BottomResizable:
-                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1);
+                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1);
                 break;
 
             case ViewArrangement.LeftResizable:
@@ -705,12 +705,12 @@ public partial class Border
                 break;
 
             case ViewArrangement.RightResizable:
-                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1);
+                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1);
                 break;
 
             case ViewArrangement.BottomResizable | ViewArrangement.RightResizable:
-                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1);
-                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1);
+                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1);
+                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1);
                 break;
 
             case ViewArrangement.BottomResizable | ViewArrangement.LeftResizable:
@@ -723,7 +723,7 @@ public partial class Border
                     Parent.X = parentLoc.X - _startGrabPoint.X;
                 }
 
-                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1);
+                Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin!.Thickness.Bottom + 1);
                 break;
 
             case ViewArrangement.TopResizable | ViewArrangement.RightResizable:
@@ -736,7 +736,7 @@ public partial class Border
                     Parent.Y = parentLoc.Y - _startGrabPoint.Y;
                 }
 
-                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1);
+                Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin!.Thickness.Right + 1);
                 break;
 
             case ViewArrangement.TopResizable | ViewArrangement.LeftResizable:

+ 1 - 1
Terminal.Gui/ViewBase/Adornment/Border.cs

@@ -152,7 +152,7 @@ public partial class Border : Adornment
 #if SUBVIEW_BASED_BORDER
     private void OnLayoutStarted (object sender, LayoutEventArgs e)
     {
-        _left.Border.LineStyle = LineStyle;
+        _left.Border!.LineStyle = LineStyle;
 
         _left.X = Thickness.Left - 1;
         _left.Y = Thickness.Top - 1;

+ 7 - 7
Terminal.Gui/ViewBase/Adornment/Margin.cs

@@ -79,12 +79,12 @@ public class Margin : Adornment
 
             if (view.Margin?.GetCachedClip () != null)
             {
-                view.Margin.NeedsDraw = true;
+                view.Margin!.NeedsDraw = true;
                 Region? saved = GetClip ();
-                View.SetClip (view.Margin.GetCachedClip ());
-                view.Margin.Draw ();
+                View.SetClip (view.Margin!.GetCachedClip ());
+                view.Margin!.Draw ();
                 View.SetClip (saved);
-                view.Margin.ClearCachedClip ();
+                view.Margin!.ClearCachedClip ();
             }
 
             view.NeedsDraw = false;
@@ -292,14 +292,14 @@ public class Margin : Adornment
             {
                 case ShadowStyle.Transparent:
                     // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner.
-                    _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0;
+                    _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).Y + 1 : 0;
 
                     break;
 
                 case ShadowStyle.Opaque:
                     // BUGBUG: This doesn't work right for all Border.Top sizes - Need an API on Border that gives top-right location of line corner.
-                    _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).Y + 1 : 0;
-                    _bottomShadow.X = Parent.Border.Thickness.Left > 0 ? ScreenToViewport (Parent.Border.GetBorderRectangle ().Location).X + 1 : 0;
+                    _rightShadow.Y = Parent!.Border!.Thickness.Top > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).Y + 1 : 0;
+                    _bottomShadow.X = Parent.Border!.Thickness.Left > 0 ? ScreenToViewport (Parent.Border!.GetBorderRectangle ().Location).X + 1 : 0;
 
                     break;
 

+ 2 - 2
Terminal.Gui/ViewBase/Adornment/ShadowView.cs

@@ -95,7 +95,7 @@ internal class ShadowView : View
         {
             for (int c = Math.Max (0, screen.X + 1); c < screen.X + screen.Width; c++)
             {
-                Driver.Move (c, r);
+                Driver?.Move (c, r);
                 SetAttribute (GetAttributeUnderLocation (new (c, r)));
 
                 if (c < ScreenContents?.GetLength (1) && r < ScreenContents?.GetLength (0))
@@ -129,7 +129,7 @@ internal class ShadowView : View
         {
             for (int r = Math.Max (0, screen.Y); r < screen.Y + viewport.Height; r++)
             {
-                Driver.Move (c, r);
+                Driver?.Move (c, r);
                 SetAttribute (GetAttributeUnderLocation (new (c, r)));
 
                 if (ScreenContents is { } && screen.X < ScreenContents.GetLength (1) && r < ScreenContents.GetLength (0))

+ 1 - 1
Terminal.Gui/ViewBase/Layout/DimAuto.cs

@@ -35,7 +35,7 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
         int screenX4 = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4;
         int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screenX4;
 
-        Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim.");
+        //Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim.");
 
         if (Style.FastHasFlags (DimAutoStyle.Text))
         {

+ 5 - 4
Terminal.Gui/ViewBase/View.Command.cs

@@ -22,9 +22,9 @@ public partial class View // Command APIs
         // HotKey - SetFocus and raise HandlingHotKey
         AddCommand (
                     Command.HotKey,
-                    () =>
+                    (ctx) =>
                     {
-                        if (RaiseHandlingHotKey () is true)
+                        if (RaiseHandlingHotKey (ctx) is true)
                         {
                             return true;
                         }
@@ -257,15 +257,16 @@ public partial class View // Command APIs
     ///     <see cref="OnHandlingHotKey"/> which can be cancelled; if not cancelled raises <see cref="Accepting"/>.
     ///     event. The default <see cref="Command.HotKey"/> handler calls this method.
     /// </summary>
+    /// <param name="ctx">The context to pass with the command.</param>
     /// <returns>
     ///     <see langword="null"/> if no event was raised; input processing should continue.
     ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input processing should
     ///     continue.
     ///     <see langword="true"/> if the event was raised and handled (or cancelled); input processing should stop.
     /// </returns>
-    protected bool? RaiseHandlingHotKey ()
+    protected bool? RaiseHandlingHotKey (ICommandContext? ctx)
     {
-        CommandEventArgs args = new () { Context = new CommandContext<KeyBinding> { Command = Command.HotKey } };
+        CommandEventArgs args = new () { Context = ctx };
         //Logging.Debug ($"{Title} ({args.Context?.Source?.Title})");
 
         // Best practice is to invoke the virtual method first.

+ 8 - 8
Terminal.Gui/ViewBase/View.Layout.cs

@@ -37,7 +37,7 @@ public partial class View // Layout APIs
     ///     <para>
     ///         Changing this property will result in <see cref="NeedsLayout"/> and <see cref="NeedsDraw"/> to be set,
     ///         resulting in the
-    ///         view being laid out and redrawn as appropriate in the next iteration of the <see cref="MainLoop"/>.
+    ///         view being laid out and redrawn as appropriate in the next iteration.
     ///     </para>
     /// </remarks>
     public Rectangle Frame
@@ -219,7 +219,7 @@ public partial class View // Layout APIs
     ///     <para>
     ///         Changing this property will result in <see cref="NeedsLayout"/> and <see cref="NeedsDraw"/> to be set,
     ///         resulting in the
-    ///         view being laid out and redrawn as appropriate in the next iteration of the <see cref="MainLoop"/>.
+    ///         view being laid out and redrawn as appropriate in the next iteration.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -264,7 +264,7 @@ public partial class View // Layout APIs
     ///     <para>
     ///         Changing this property will result in <see cref="NeedsLayout"/> and <see cref="NeedsDraw"/> to be set,
     ///         resulting in the
-    ///         view being laid out and redrawn as appropriate in the next iteration of the <see cref="MainLoop"/>.
+    ///         view being laid out and redrawn as appropriate in the next iteration.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -308,7 +308,7 @@ public partial class View // Layout APIs
     ///     <para>
     ///         Changing this property will result in <see cref="NeedsLayout"/> and <see cref="NeedsDraw"/> to be set,
     ///         resulting in the
-    ///         view being laid out and redrawn as appropriate in the next iteration of the <see cref="MainLoop"/>.
+    ///         view being laid out and redrawn as appropriate in the next iteration.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -396,7 +396,7 @@ public partial class View // Layout APIs
     ///     <para>
     ///         Changing this property will result in <see cref="NeedsLayout"/> and <see cref="NeedsDraw"/> to be set,
     ///         resulting in the
-    ///         view being laid out and redrawn as appropriate in the next iteration of the <see cref="MainLoop"/>.
+    ///         view being laid out and redrawn as appropriate in the next iteration.
     ///     </para>
     ///     <para>
     ///         Changing this property will cause <see cref="Frame"/> to be updated.
@@ -843,7 +843,7 @@ public partial class View // Layout APIs
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         The <see cref="MainLoop"/> will cause <see cref="Layout()"/> to be called on the next
+    ///         The next iteration will cause <see cref="Layout()"/> to be called on the next
     ///         <see cref="Application.Iteration"/> so there is normally no reason to call see <see cref="Layout()"/>.
     ///     </para>
     /// </remarks>
@@ -882,12 +882,12 @@ public partial class View // Layout APIs
 
                 if (current.Margin is { SubViews.Count: > 0 })
                 {
-                    current.Margin.SetNeedsLayout ();
+                    current.Margin!.SetNeedsLayout ();
                 }
 
                 if (current.Border is { SubViews.Count: > 0 })
                 {
-                    current.Border.SetNeedsLayout ();
+                    current.Border!.SetNeedsLayout ();
                 }
 
                 if (current.Padding is { SubViews.Count: > 0 })

+ 1 - 1
Terminal.Gui/Views/CheckBox.cs

@@ -32,7 +32,7 @@ public class CheckBox : View
         // Hotkey - Advance state and raise Select event - DO NOT raise Accept
         AddCommand (Command.HotKey, ctx =>
                                     {
-                                        if (RaiseHandlingHotKey () is true)
+                                        if (RaiseHandlingHotKey (ctx) is true)
                                         {
                                             return true;
                                         }

+ 3 - 4
Terminal.Gui/Views/FileDialogs/FileDialog.cs

@@ -148,7 +148,7 @@ public class FileDialog : Dialog, IDesignable
                                      e.Handled = true;
                                  };
 
-        _tbPath = new () { Width = Dim.Fill (),/* CaptionColor = new (Color.Black)*/ };
+        _tbPath = new () { Width = Dim.Fill () };
 
         _tbPath.KeyDown += (s, k) =>
                            {
@@ -248,7 +248,6 @@ public class FileDialog : Dialog, IDesignable
             X = 0,
             Width = Dim.Fill (),
             Y = Pos.AnchorEnd (),
-            HotKey = Key.F.WithAlt,
             Id = "_tbFind",
         };
 
@@ -456,8 +455,8 @@ public class FileDialog : Dialog, IDesignable
         _btnBack.Text = GetBackButtonText ();
         _btnForward.Text = GetForwardButtonText ();
 
-        _tbPath.Caption = Style.PathCaption;
-        _tbFind.Caption = Style.SearchCaption;
+        _tbPath.Title = Style.PathCaption;
+        _tbFind.Title = Style.SearchCaption;
 
         _tbPath.Autocomplete.Scheme = new (_tbPath.GetScheme ())
         {

+ 1 - 1
Terminal.Gui/Views/Label.cs

@@ -60,7 +60,7 @@ public class Label : View, IDesignable
 
     private bool? InvokeHotKeyOnNextPeer (ICommandContext commandContext)
     {
-        if (RaiseHandlingHotKey () == true)
+        if (RaiseHandlingHotKey (commandContext) == true)
         {
             return true;
         }

+ 2 - 2
Terminal.Gui/Views/Menu/MenuBarv2.cs

@@ -31,11 +31,11 @@ public class MenuBarv2 : Menuv2, IDesignable
 
         AddCommand (
                     Command.HotKey,
-                    () =>
+                    (ctx) =>
                     {
                         // Logging.Debug ($"{Title} - Command.HotKey");
 
-                        if (RaiseHandlingHotKey () is true)
+                        if (RaiseHandlingHotKey (ctx) is true)
                         {
                             return true;
                         }

+ 2 - 2
Terminal.Gui/Views/Menuv1/MenuBar.cs

@@ -1441,8 +1441,8 @@ public class MenuBar : View, IDesignable
 
             if (SuperView is { })
             {
-                locationOffset.X += SuperView.Border.Thickness.Left;
-                locationOffset.Y += SuperView.Border.Thickness.Top;
+                locationOffset.X += SuperView.Border!.Thickness.Left;
+                locationOffset.Y += SuperView.Border!.Thickness.Top;
             }
 
             int cx = me.Position.X - locationOffset.X;

+ 1 - 1
Terminal.Gui/Views/RadioGroup.cs

@@ -94,7 +94,7 @@ public class RadioGroup : View, IDesignable, IOrientation
             return false;
         }
 
-        if (RaiseHandlingHotKey () == true)
+        if (RaiseHandlingHotKey (ctx) == true)
         {
             return true;
         }

+ 9 - 9
Terminal.Gui/Views/Shortcut.cs

@@ -210,14 +210,14 @@ public class Shortcut : View, IOrientation, IDesignable
                 case 0:
                 case 1:
                     // Scrunch it by removing both margins
-                    HelpView.Margin.Thickness = new (t.Right - 1, t.Top, t.Left - 1, t.Bottom);
+                    HelpView.Margin!.Thickness = new (t.Right - 1, t.Top, t.Left - 1, t.Bottom);
 
                     break;
 
                 case 2:
 
                     // Scrunch just the right margin
-                    HelpView.Margin.Thickness = new (t.Right, t.Top, t.Left - 1, t.Bottom);
+                    HelpView.Margin!.Thickness = new (t.Right, t.Top, t.Left - 1, t.Bottom);
 
                     break;
             }
@@ -225,7 +225,7 @@ public class Shortcut : View, IOrientation, IDesignable
         else
         {
             // Reset to default
-            HelpView.Margin.Thickness = GetMarginThickness ();
+            HelpView.Margin!.Thickness = GetMarginThickness ();
         }
     }
 
@@ -471,9 +471,9 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         if (CommandView.Margin is { })
         {
-            CommandView.Margin.Thickness = GetMarginThickness ();
+            CommandView.Margin!.Thickness = GetMarginThickness ();
             // strip off ViewportSettings.TransparentMouse
-            CommandView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
+            CommandView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
         }
 
         CommandView.X = Pos.Align (Alignment.End, AlignmentModes);
@@ -533,9 +533,9 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         if (HelpView.Margin is { })
         {
-            HelpView.Margin.Thickness = GetMarginThickness ();
+            HelpView.Margin!.Thickness = GetMarginThickness ();
             // strip off ViewportSettings.TransparentMouse
-            HelpView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
+            HelpView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
         }
 
         HelpView.X = Pos.Align (Alignment.End, AlignmentModes);
@@ -666,9 +666,9 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         if (KeyView.Margin is { })
         {
-            KeyView.Margin.Thickness = GetMarginThickness ();
+            KeyView.Margin!.Thickness = GetMarginThickness ();
             // strip off ViewportSettings.TransparentMouse
-            KeyView.Margin.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
+            KeyView.Margin!.ViewportSettings &= ~ViewportSettingsFlags.TransparentMouse;
         }
 
         KeyView.X = Pos.Align (Alignment.End, AlignmentModes);

+ 1 - 1
Terminal.Gui/Views/StatusBar.cs

@@ -71,7 +71,7 @@ public class StatusBar : Bar, IDesignable
 
             if (barItem.Border is { })
             {
-                barItem.Border.Thickness = index == SubViews.Count - 1 ? new Thickness (0, 0, 0, 0) : new Thickness (0, 0, 1, 0);
+                barItem.Border!.Thickness = index == SubViews.Count - 1 ? new Thickness (0, 0, 0, 0) : new Thickness (0, 0, 1, 0);
             }
 
             if (barItem is Shortcut shortcut)

+ 1 - 1
Terminal.Gui/Views/TextInput/NetMaskedTextProvider.cs

@@ -61,7 +61,7 @@ public class NetMaskedTextProvider : ITextValidateProvider
     public bool Fixed => true;
 
     /// <inheritdoc/>
-    public string DisplayText => _provider.ToDisplayString ();
+    public string DisplayText => _provider!.ToDisplayString ();
 
     /// <inheritdoc/>
     public int Cursor (int pos)

+ 47 - 31
Terminal.Gui/Views/TextInput/TextField.cs

@@ -28,9 +28,6 @@ public class TextField : View, IDesignable
         _selectedStart = -1;
         _text = new ();
 
-        // TODO: Determine if this is a good choice. Previously this was hard coded to 
-        // TODO: DarkGray which was NOT a good choice.
-        CaptionColor = GetAttributeForRole (VisualRole.Normal).Foreground.GetBrighterColor();
         ReadOnly = false;
         Autocomplete = new TextFieldAutocomplete ();
         Height = Dim.Auto (DimAutoStyle.Text, 1);
@@ -40,9 +37,6 @@ public class TextField : View, IDesignable
         Used = true;
         WantMousePositionReports = true;
 
-        // By default, disable hotkeys (in case someome sets Title)
-        HotKeySpecifier = new ('\xffff');
-
         _historyText.ChangeText += HistoryText_ChangeText;
 
         Initialized += TextField_Initialized;
@@ -324,6 +318,30 @@ public class TextField : View, IDesignable
                     }
                    );
 
+        AddCommand (
+                    Command.HotKey,
+                    ctx =>
+                    {
+                        if (RaiseHandlingHotKey (ctx) is true)
+                        {
+                            return true;
+                        }
+
+                        // If we have focus, then ignore the hotkey because the user
+                        // means to enter it
+                        if (HasFocus)
+                        {
+                            return false;
+                        }
+
+                        // This is what the default HotKey handler does:
+                        SetFocus ();
+
+                        // Always return true on hotkey, even if SetFocus fails because 
+                        // hotkeys are always handled by the View (unless RaiseHandlingHotKey cancels).
+                        return true;
+                    });
+
         // Default keybindings for this view
         // We follow this as closely as possible: https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts
         KeyBindings.Add (Key.Delete, Command.DeleteCharRight);
@@ -411,15 +429,6 @@ public class TextField : View, IDesignable
     /// </summary>
     public IAutocomplete Autocomplete { get; set; }
 
-    /// <summary>
-    ///     Gets or sets the text to render in control when no value has been entered yet and the <see cref="View"/> does
-    ///     not yet have input focus.
-    /// </summary>
-    public string Caption { get; set; }
-
-    /// <summary>Gets or sets the foreground <see cref="Color"/> to use when rendering <see cref="Caption"/>.</summary>
-    public Color CaptionColor { get; set; }
-
     /// <summary>Get the Context Menu for this view.</summary>
     [CanBeNull]
     public PopoverMenu ContextMenu { get; private set; }
@@ -920,7 +929,7 @@ public class TextField : View, IDesignable
         _isDrawing = true;
 
         // Cache attributes as GetAttributeForRole might raise events
-        Attribute selectedAttribute = new Attribute (GetAttributeForRole (VisualRole.Active));
+        var selectedAttribute = new Attribute (GetAttributeForRole (VisualRole.Active));
         Attribute readonlyAttribute = GetAttributeForRole (VisualRole.ReadOnly);
         Attribute normalAttribute = GetAttributeForRole (VisualRole.Editable);
 
@@ -943,7 +952,7 @@ public class TextField : View, IDesignable
             {
                 // Disabled
                 SetAttributeForRole (VisualRole.Disabled);
-            } 
+            }
             else if (idx == _cursorPosition && HasFocus && !Used && SelectedLength == 0 && !ReadOnly)
             {
                 // Selected text
@@ -1157,7 +1166,6 @@ public class TextField : View, IDesignable
     ///// </summary>
     //public event EventHandler<StateEventArgs<string>> TextChanged;
 
-
     /// <summary>Undoes the latest changes.</summary>
     public void Undo ()
     {
@@ -1699,25 +1707,33 @@ public class TextField : View, IDesignable
     private void RenderCaption ()
     {
         if (HasFocus
-            || Caption == null
-            || Caption.Length == 0
+            || string.IsNullOrEmpty (Title)
             || Text?.Length > 0)
         {
             return;
         }
 
-        var color = new Attribute (CaptionColor, GetAttributeForRole (VisualRole.Editable).Background, GetAttributeForRole (VisualRole.Editable).Style);
-        SetAttribute (color);
-
-        Move (0, 0);
-        string render = Caption;
-
-        if (render.GetColumns () > Viewport.Width)
+        // Ensure TitleTextFormatter has the current Title text
+        // (should already be set by the Title property setter, but being defensive)
+        if (TitleTextFormatter.Text != Title)
         {
-            render = render [..Viewport.Width];
+            TitleTextFormatter.Text = Title;
         }
 
-        AddStr (render);
+        var captionAttribute = new Attribute (
+                                              GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
+                                              GetAttributeForRole (VisualRole.Editable).Background);
+
+        var hotKeyAttribute = new Attribute (
+                                             GetAttributeForRole (VisualRole.Editable).Foreground.GetDimColor (),
+                                             GetAttributeForRole (VisualRole.Editable).Background,
+                                             GetAttributeForRole (VisualRole.Editable).Style | TextStyle.Underline);
+
+        // Use TitleTextFormatter to render the caption with hotkey support
+        TitleTextFormatter.Draw (
+                                 ViewportToScreen (new Rectangle (0, 0, Viewport.Width, 1)),
+                                 captionAttribute,
+                                 hotKeyAttribute);
     }
 
     private void SetClipboard (IEnumerable<Rune> text)
@@ -1814,11 +1830,11 @@ public class TextField : View, IDesignable
         }
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     public bool EnableForDesign ()
     {
         Text = "This is a test.";
-        Caption = "Caption";
+        Title = "Caption";
 
         return true;
     }

+ 0 - 1
Terminal.Gui/Views/TreeView/Branch.cs

@@ -451,7 +451,6 @@ internal class Branch<T> where T : class
     ///     Returns true if the given x offset on the branch line is the +/- symbol.  Returns false if not showing
     ///     expansion symbols or leaf node etc.
     /// </summary>
-    /// <param name="driver"></param>
     /// <param name="x"></param>
     /// <returns></returns>
     internal bool IsHitOnExpandableSymbol (int x)

+ 4 - 4
Tests/TerminalGuiFluentTesting/FakeDriver/FakeApplicationFactory.cs

@@ -16,11 +16,11 @@ public class FakeApplicationFactory
         var cts = new CancellationTokenSource ();
         var fakeInput = new FakeNetInput (cts.Token);
         FakeOutput output = new ();
-        output.Size = new (25, 25);
+        output.Size = new (80, 25);
 
         IApplication origApp = ApplicationImpl.Instance;
 
-        var sizeMonitor = new FakeSizeMonitor ();
+        var sizeMonitor = new FakeSizeMonitor (output, output.LastBuffer!);
 
         var impl = new ApplicationImpl (new FakeNetComponentFactory (fakeInput, output, sizeMonitor));
 
@@ -32,13 +32,13 @@ public class FakeApplicationFactory
         // Handle different facade types - cast to common interface instead
         var d = (IConsoleDriverFacade)Application.Driver!;
 
-        sizeMonitor.SizeChanging += (_, e) =>
+        sizeMonitor.SizeChanged += (_, e) =>
                                     {
                                         if (e.Size != null)
                                         {
                                             Size s = e.Size.Value;
                                             output.Size = s;
-                                            d.OutputBuffer.SetWindowSize (s.Width, s.Height);
+                                            d.OutputBuffer.SetSize (s.Width, s.Height);
                                         }
                                     };
 

+ 0 - 58
Tests/TerminalGuiFluentTesting/FakeDriver/FakeConsoleDriver.cs

@@ -1,58 +0,0 @@
-#nullable enable
-using System.Collections.Concurrent;
-using System.Drawing;
-using TerminalGuiFluentTesting;
-
-#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
-
-namespace Terminal.Gui.Drivers;
-
-/// <summary>
-///     Implementation of <see cref="IConsoleDriver"/> that uses fake input/output.
-///     This is a lightweight alternative to <see cref="GuiTestContext"/> (if you don't
-///     need the entire application main loop running).
-/// </summary>
-internal class FakeConsoleDriver : ConsoleDriverFacade<ConsoleKeyInfo>, IFakeConsoleDriver
-{
-    internal FakeConsoleDriver (
-        ConcurrentQueue<ConsoleKeyInfo> inputBuffer,
-        OutputBuffer outputBuffer,
-        FakeOutput fakeOutput,
-        Func<DateTime> datetimeFunc,
-        FakeSizeMonitor sizeMonitor
-    ) :
-        base (
-              new NetInputProcessor (inputBuffer),
-              outputBuffer,
-              fakeOutput,
-              new (new AnsiResponseParser (), datetimeFunc),
-              sizeMonitor)
-    {
-        FakeOutput fakeOutput1;
-        InputBuffer = inputBuffer;
-        SizeMonitor = sizeMonitor;
-        OutputBuffer = outputBuffer;
-        ConsoleOutput = fakeOutput1 = fakeOutput;
-
-        SizeChanged += (_, e) =>
-                       {
-                           if (e.Size != null)
-                           {
-                               Size s = e.Size.Value;
-                               fakeOutput1.Size = s;
-                               OutputBuffer.SetWindowSize (s.Width, s.Height);
-                           }
-                       };
-    }
-
-    public void SetBufferSize (int width, int height)
-    {
-        SizeMonitor.RaiseSizeChanging (new (width, height));
-        OutputBuffer.SetWindowSize (width, height);
-    }
-
-    public IConsoleOutput ConsoleOutput { get; }
-    public ConcurrentQueue<ConsoleKeyInfo> InputBuffer { get; }
-    public new OutputBuffer OutputBuffer { get; }
-    public FakeSizeMonitor SizeMonitor { get; }
-}

+ 0 - 20
Tests/TerminalGuiFluentTesting/FakeDriver/FakeDriverFactory.cs

@@ -1,20 +0,0 @@
-#nullable enable
-namespace Terminal.Gui.Drivers;
-
-#pragma warning disable CS1591
-public class FakeDriverFactory
-{
-    /// <summary>
-    ///     Creates a new instance of <see cref="FakeConsoleDriver"/> using default options
-    /// </summary>
-    /// <returns></returns>
-    public IFakeConsoleDriver Create ()
-    {
-        return new FakeConsoleDriver (
-                                 new (),
-                                 new (),
-                                 new (),
-                                 () => DateTime.Now,
-                                 new ());
-    }
-}

+ 0 - 0
Tests/TerminalGuiFluentTesting/FakeInput.cs → Tests/TerminalGuiFluentTesting/FakeDriver/FakeInput.cs


+ 7 - 1
Tests/TerminalGuiFluentTesting/FakeOutput.cs → Tests/TerminalGuiFluentTesting/FakeDriver/FakeOutput.cs

@@ -17,7 +17,7 @@ internal class FakeOutput : IConsoleOutput
     public void Write (IOutputBuffer buffer) { LastBuffer = buffer; }
 
     /// <inheritdoc/>
-    public Size GetWindowSize () { return Size; }
+    public Size GetSize () { return Size; }
 
     /// <inheritdoc/>
     public void SetCursorVisibility (CursorVisibility visibility) { }
@@ -25,6 +25,12 @@ internal class FakeOutput : IConsoleOutput
     /// <inheritdoc/>
     public void SetCursorPosition (int col, int row) { CursorPosition = new Point (col, row); }
 
+    /// <inheritdoc />
+    public void SetSize (int width, int height)
+    {
+        Size = new (width, height);
+    }
+
     /// <summary>
     /// The last value set by calling <see cref="SetCursorPosition"/>
     /// </summary>

+ 6 - 6
Tests/TerminalGuiFluentTesting/FakeDriver/FakeSizeMonitor.cs

@@ -4,17 +4,17 @@ using System.Drawing;
 namespace Terminal.Gui.Drivers;
 
 #pragma warning disable CS1591
-public class FakeSizeMonitor : IWindowSizeMonitor
+public class FakeSizeMonitor (IConsoleOutput consoleOut, IOutputBuffer _) : IConsoleSizeMonitor
 {
-    /// <inheritdoc/>
-    public event EventHandler<SizeChangedEventArgs>? SizeChanging;
+    /// <inheritdoc />
+    public event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     /// <inheritdoc/>
     public bool Poll () { return false; }
 
     /// <summary>
-    ///     Raises the <see cref="SizeChanging"/> event.
+    ///     Raises the <see cref="SizeChanged"/> event.
     /// </summary>
     /// <param name="newSize"></param>
-    public void RaiseSizeChanging (Size newSize) { SizeChanging?.Invoke (this, new (newSize)); }
-}
+    public void RaiseSizeChanged (Size newSize) { SizeChanged?.Invoke (this, new (newSize)); }
+}

+ 0 - 0
Tests/TerminalGuiFluentTesting/FakeWindowsInput.cs → Tests/TerminalGuiFluentTesting/FakeDriver/FakeWindowsInput.cs


+ 0 - 8
Tests/TerminalGuiFluentTesting/FakeDriver/IFakeConsoleDriver.cs

@@ -1,8 +0,0 @@
-#nullable enable
-namespace Terminal.Gui.Drivers;
-
-#pragma warning disable CS1591
-public interface IFakeConsoleDriver : IConsoleDriver, IConsoleDriverFacade
-{
-    void SetBufferSize (int width, int height);
-}

+ 19 - 36
Tests/TerminalGuiFluentTesting/GuiTestContext.cs

@@ -43,7 +43,7 @@ public class GuiTestContext : IDisposable
         _winInput = new (_cts.Token);
 
         _output.Size = new (width, height);
-        _fakeSizeMonitor = new ();
+        _fakeSizeMonitor = new (_output, _output.LastBuffer!);
 
         IComponentFactory cf = driver == TestDriver.DotNet
                                    ? new FakeNetComponentFactory (_netInput, _output, _fakeSizeMonitor)
@@ -238,11 +238,7 @@ public class GuiTestContext : IDisposable
         return WaitIteration (
                               () =>
                               {
-                                  _output.Size = new (width, height);
-                                  _fakeSizeMonitor.RaiseSizeChanging (_output.Size);
-
-                                  var d = (IConsoleDriverFacade)Application.Driver!;
-                                  d.OutputBuffer.SetWindowSize (width, height);
+                                  Application.Driver!.SetScreenSize(width, height);
                               });
     }
 
@@ -938,48 +934,35 @@ public class GuiTestContext : IDisposable
     public Point GetCursorPosition () { return _output.CursorPosition; }
 }
 
-internal class FakeWindowsComponentFactory : WindowsComponentFactory
+internal class FakeWindowsComponentFactory (FakeWindowsInput winInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor)
+    : WindowsComponentFactory
 {
-    private readonly FakeWindowsInput _winInput;
-    private readonly FakeOutput _output;
-    private readonly FakeSizeMonitor _fakeSizeMonitor;
-
-    public FakeWindowsComponentFactory (FakeWindowsInput winInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor)
-    {
-        _winInput = winInput;
-        _output = output;
-        _fakeSizeMonitor = fakeSizeMonitor;
-    }
-
     /// <inheritdoc/>
-    public override IConsoleInput<WindowsConsole.InputRecord> CreateInput () { return _winInput; }
+    public override IConsoleInput<WindowsConsole.InputRecord> CreateInput () { return winInput; }
 
     /// <inheritdoc/>
-    public override IConsoleOutput CreateOutput () { return _output; }
+    public override IConsoleOutput CreateOutput () { return output; }
 
     /// <inheritdoc/>
-    public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { return _fakeSizeMonitor; }
-}
-
-internal class FakeNetComponentFactory : NetComponentFactory
-{
-    private readonly FakeNetInput _netInput;
-    private readonly FakeOutput _output;
-    private readonly FakeSizeMonitor _fakeSizeMonitor;
-
-    public FakeNetComponentFactory (FakeNetInput netInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor)
+    public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
     {
-        _netInput = netInput;
-        _output = output;
-        _fakeSizeMonitor = fakeSizeMonitor;
+        outputBuffer.SetSize (consoleOutput.GetSize ().Width, consoleOutput.GetSize ().Height);
+        return fakeSizeMonitor;
     }
+}
 
+internal class FakeNetComponentFactory (FakeNetInput netInput, FakeOutput output, FakeSizeMonitor fakeSizeMonitor) : NetComponentFactory
+{
     /// <inheritdoc/>
-    public override IConsoleInput<ConsoleKeyInfo> CreateInput () { return _netInput; }
+    public override IConsoleInput<ConsoleKeyInfo> CreateInput () { return netInput; }
 
     /// <inheritdoc/>
-    public override IConsoleOutput CreateOutput () { return _output; }
+    public override IConsoleOutput CreateOutput () { return output; }
 
     /// <inheritdoc/>
-    public override IWindowSizeMonitor CreateWindowSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer) { return _fakeSizeMonitor; }
+    public override IConsoleSizeMonitor CreateConsoleSizeMonitor (IConsoleOutput consoleOutput, IOutputBuffer outputBuffer)
+    {
+        outputBuffer.SetSize (consoleOutput.GetSize ().Width, consoleOutput.GetSize ().Height);
+        return fakeSizeMonitor;
+    }
 }

+ 1 - 1
Tests/UnitTests/Application/Application.NavigationTests.cs

@@ -1,7 +1,7 @@
 using UnitTests;
 using Xunit.Abstractions;
 
-namespace UnitTests.ApplicationTests.NavigationTests;
+namespace UnitTests.ApplicationTests;
 
 public class ApplicationNavigationTests (ITestOutputHelper output)
 {

+ 2 - 2
Tests/UnitTests/Application/ApplicationImplTests.cs

@@ -25,7 +25,7 @@ public class ApplicationImplTests
             m.Setup (f => f.CreateInput ()).Returns (netInput.Object);
             m.Setup (f => f.CreateInputProcessor (It.IsAny<ConcurrentQueue<ConsoleKeyInfo>> ())).Returns (Mock.Of <IInputProcessor> ());
             m.Setup (f => f.CreateOutput ()).Returns (Mock.Of<IConsoleOutput> ());
-            m.Setup (f => f.CreateWindowSizeMonitor (It.IsAny<IConsoleOutput> (),It.IsAny<IOutputBuffer> ())).Returns (Mock.Of<IWindowSizeMonitor> ());
+            m.Setup (f => f.CreateConsoleSizeMonitor (It.IsAny<IConsoleOutput> (),It.IsAny<IOutputBuffer> ())).Returns (Mock.Of<IConsoleSizeMonitor> ());
 
             return new (m.Object);
         }
@@ -38,7 +38,7 @@ public class ApplicationImplTests
             m.Setup (f => f.CreateInput ()).Returns (winInput.Object);
             m.Setup (f => f.CreateInputProcessor (It.IsAny<ConcurrentQueue<WindowsConsole.InputRecord>> ())).Returns (Mock.Of<IInputProcessor> ());
             m.Setup (f => f.CreateOutput ()).Returns (Mock.Of<IConsoleOutput> ());
-            m.Setup (f => f.CreateWindowSizeMonitor (It.IsAny<IConsoleOutput> (), It.IsAny<IOutputBuffer> ())).Returns (Mock.Of<IWindowSizeMonitor> ());
+            m.Setup (f => f.CreateConsoleSizeMonitor (It.IsAny<IConsoleOutput> (), It.IsAny<IOutputBuffer> ())).Returns (Mock.Of<IConsoleSizeMonitor> ());
             return new (m.Object);
         }
     }

+ 3 - 2
Tests/UnitTests/Application/ApplicationPopoverTests.cs

@@ -1,4 +1,5 @@
-namespace UnitTests.ApplicationTests;
+#nullable enable
+namespace UnitTests.ApplicationTests;
 
 public class ApplicationPopoverTests
 {
@@ -276,7 +277,7 @@ public class ApplicationPopoverTests
         public PopoverTestClass ()
         {
             CanFocus = true;
-            AddCommand (Command.New, NewCommandHandler);
+            AddCommand (Command.New, NewCommandHandler!);
             HotKeyBindings.Add (Key.N.WithCtrl, Command.New);
 
             return;

+ 2 - 2
Tests/UnitTests/Application/ApplicationScreenTests.cs

@@ -89,7 +89,7 @@ public class ApplicationScreenTests
     }
 
     [Fact]
-    public void Screen_Changes_OnSizeChanged_Without_Call_Application_Init ()
+    public void Screen_Changes_OnScreenChanged_Without_Call_Application_Init ()
     {
         // Arrange
         Application.ResetState (true);
@@ -99,7 +99,7 @@ public class ApplicationScreenTests
         Assert.Equal (new (0, 0, 25, 25), Application.Screen);
 
         // Act
-        ((FakeDriver)Application.Driver)!.SetBufferSize (120, 30);
+        Application.Driver.SetScreenSize(120,30);
 
         // Assert
         Assert.Equal (new (0, 0, 120, 30), Application.Screen);

+ 31 - 44
Tests/UnitTests/Application/ApplicationTests.cs

@@ -1,8 +1,4 @@
 using System.Diagnostics;
-using System.Reflection;
-using JetBrains.Annotations;
-using Terminal.Gui.Drivers;
-using UnitTests;
 using Xunit.Abstractions;
 using static Terminal.Gui.Configuration.ConfigurationManager;
 
@@ -81,8 +77,8 @@ public class ApplicationTests
             _timeoutLock = null;
         }
 
-
         a.After (null);
+
         return;
 
         void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
@@ -167,11 +163,11 @@ public class ApplicationTests
     public void Begin_Sets_Application_Top_To_Console_Size ()
     {
         Assert.Null (Application.Top);
-        AutoInitShutdownAttribute.FakeResize (new Size (80, 25));
+        Application.Driver!.SetScreenSize (80, 25);
         Toplevel top = new ();
         Application.Begin (top);
         Assert.Equal (new (0, 0, 80, 25), Application.Top!.Frame);
-        AutoInitShutdownAttribute.FakeResize (new Size (5, 5));
+        Application.Driver!.SetScreenSize (5, 5);
         Assert.Equal (new (0, 0, 5, 5), Application.Top!.Frame);
         top.Dispose ();
     }
@@ -212,7 +208,7 @@ public class ApplicationTests
     public void Init_Begin_End_Cleans_Up ()
     {
         // Start stopwatch
-        Stopwatch stopwatch = new Stopwatch ();
+        var stopwatch = new Stopwatch ();
         stopwatch.Start ();
 
         // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
@@ -252,7 +248,6 @@ public class ApplicationTests
         stopwatch.Stop ();
 
         _output.WriteLine ($"Load took {stopwatch.ElapsedMilliseconds} ms");
-
     }
 
     // Legacy driver test - all InlineData commented out
@@ -284,6 +279,7 @@ public class ApplicationTests
 
     [Theory]
     [InlineData (typeof (FakeDriver))]
+
     //[InlineData (typeof (DotNetDriver))]
     //[InlineData (typeof (WindowsDriver))]
     //[InlineData (typeof (UnixDriver))]
@@ -422,6 +418,7 @@ public class ApplicationTests
 
     [Theory]
     [InlineData (typeof (FakeDriver))]
+
     //[InlineData (typeof (DotNetDriver))]
     //[InlineData (typeof (WindowsDriver))]
     //[InlineData (typeof (UnixDriver))]
@@ -461,11 +458,8 @@ public class ApplicationTests
     [AutoInitShutdown]
     public void Init_Unbalanced_Throws ()
     {
-        Assert.Throws<InvalidOperationException> (
-                                                  () =>
-                                                      Application.InternalInit (
-                                                                                new FakeDriver ()
-                                                                               )
+        Assert.Throws<InvalidOperationException> (() =>
+                                                      Application.Init (null, "fake")
                                                  );
         Application.Shutdown ();
 
@@ -473,7 +467,6 @@ public class ApplicationTests
         Assert.Null (Application.Driver);
     }
 
-
     [Fact]
     [AutoInitShutdown]
     public void Init_Unbalanced_Throws2 ()
@@ -496,7 +489,7 @@ public class ApplicationTests
         // NOTE: Run<T>, when called after Init has been called behaves differently than
         // when called if Init has not been called.
         Toplevel topLevel = new ();
-        Application.InternalInit (new FakeDriver ());
+        Application.Init (null, "fake");
 
         RunState runstate = null;
 
@@ -532,6 +525,7 @@ public class ApplicationTests
     {
         Application.ForceDriver = "Fake";
         Application.Init ();
+
         //Assert.IsType<FakeConsoleInput>(Application.Drive);
         //Assert.IsType<FakeDriver> (Application.Driver);
         Application.ResetState ();
@@ -556,7 +550,7 @@ public class ApplicationTests
         }
         finally
         {
-            Application.ResetState (false);
+            Application.ResetState ();
         }
     }
 
@@ -594,7 +588,7 @@ public class ApplicationTests
     {
         var iteration = 0;
 
-        Application.Init (null, driverName: "fake");
+        Application.Init (null, "fake");
 
         Application.Iteration += Application_Iteration;
         Application.Run<Toplevel> ().Dispose ();
@@ -620,9 +614,9 @@ public class ApplicationTests
     [AutoInitShutdown]
     public void Screen_Size_Changes ()
     {
-        var driver = Application.Driver;
+        IConsoleDriver driver = Application.Driver;
 
-        AutoInitShutdownAttribute.FakeResize (new Size (80,25));
+        Application.Driver!.SetScreenSize (80, 25);
 
         Assert.Equal (new (0, 0, 80, 25), driver.Screen);
         Assert.Equal (new (0, 0, 80, 25), Application.Screen);
@@ -630,13 +624,14 @@ public class ApplicationTests
         // TODO: Should not be possible to manually change these at whim!
         driver.Cols = 100;
         driver.Rows = 30;
+
         // IConsoleDriver.Screen isn't assignable
         //driver.Screen = new (0, 0, driver.Cols, Rows);
 
-        AutoInitShutdownAttribute.FakeResize (new Size (100, 30));
+        Application.Driver!.SetScreenSize (100, 30);
 
         Assert.Equal (new (0, 0, 100, 30), driver.Screen);
-        
+
         // Assert does not make sense
         // Assert.NotEqual (new (0, 0, 100, 30), Application.Screen);
         // Assert.Equal (new (0, 0, 80, 25), Application.Screen);
@@ -647,11 +642,7 @@ public class ApplicationTests
     }
 
     [Fact]
-    public void InitState_Throws_If_Driver_Is_Null ()
-    {
-        Assert.Throws<ArgumentNullException> (static () => Application.SubscribeDriverEvents ());
-    }
-
+    public void InitState_Throws_If_Driver_Is_Null () { Assert.Throws<ArgumentNullException> (static () => Application.SubscribeDriverEvents ()); }
 
     #region RunTests
 
@@ -701,7 +692,6 @@ public class ApplicationTests
     [TestRespondersDisposed]
     public void Run_T_After_Init_Does_Not_Disposes_Application_Top ()
     {
-
         // Init doesn't create a Toplevel and assigned it to Application.Top
         // but Begin does
         var initTop = new Toplevel ();
@@ -785,7 +775,7 @@ public class ApplicationTests
         Assert.Null (Application.Driver);
     }
 
-    [Fact(Skip = "FakeDriver is not allowed, use AutoInitShutdown attribute instead")]
+    [Fact (Skip = "FakeDriver is not allowed, use AutoInitShutdown attribute instead")]
     [TestRespondersDisposed]
     public void Run_T_NoInit_DoesNotThrow ()
     {
@@ -907,7 +897,7 @@ public class ApplicationTests
             Width = 5, Height = 5,
             Arrangement = ViewArrangement.Movable
         };
-        AutoInitShutdownAttribute.FakeResize (new Size (10, 10));
+        Application.Driver!.SetScreenSize (10, 10);
         RunState rs = Application.Begin (w);
 
         // Don't use visuals to test as style of border can change over time.
@@ -1075,7 +1065,8 @@ public class ApplicationTests
         Assert.Null (Application.Top);
     }
 
-    private class TestToplevel : Toplevel { }
+    private class TestToplevel : Toplevel
+    { }
 
     private readonly object _forceDriverLock = new ();
 
@@ -1155,19 +1146,15 @@ public class ApplicationTests
         Assert.False (Application.Initialized);
         Application.Init (null, "v2net");
         Assert.True (Application.Initialized);
-        Task.Run (() =>
-                  {
-                      Task.Delay (300).Wait ();
-                  }).ContinueWith (
-                                   (t, _) =>
-                                   {
-                                       // no longer loading
-                                       Application.Invoke (() =>
-                                                           {
-                                                               Application.RequestStop ();
-                                                           });
-                                   },
-                                   TaskScheduler.FromCurrentSynchronizationContext ());
+
+        Task.Run (() => { Task.Delay (300).Wait (); })
+            .ContinueWith (
+                           (t, _) =>
+                           {
+                               // no longer loading
+                               Application.Invoke (() => { Application.RequestStop (); });
+                           },
+                           TaskScheduler.FromCurrentSynchronizationContext ());
         Application.Run<TestToplevel> ();
         Assert.NotNull (Application.Driver);
         Assert.NotNull (Application.Top);

+ 63 - 48
Tests/UnitTests/Application/TimedEventsTests.cs

@@ -1,42 +1,50 @@
-using System.Diagnostics;
-
+#nullable enable
 namespace UnitTests.ApplicationTests;
 
 /// <summary>
-/// Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch.
+///     Tests for TimedEvents class, focusing on high-resolution timing with Stopwatch.
 /// </summary>
 public class TimedEventsTests
 {
     [Fact]
     public void HighFrequency_Concurrent_Invocations_No_Lost_Timeouts ()
     {
-        var timedEvents = new Terminal.Gui.App.TimedEvents ();
+        var timedEvents = new TimedEvents ();
         var counter = 0;
         var expected = 1000;
         var completed = new ManualResetEventSlim (false);
 
         // Add many timeouts with TimeSpan.Zero concurrently
-        Parallel.For (0, expected, i =>
-        {
-            timedEvents.Add (TimeSpan.Zero, () =>
-            {
-                var current = Interlocked.Increment (ref counter);
-                if (current == expected)
-                {
-                    completed.Set ();
-                }
-                return false; // One-shot
-            });
-        });
+        Parallel.For (
+                      0,
+                      expected,
+                      i =>
+                      {
+                          timedEvents.Add (
+                                           TimeSpan.Zero,
+                                           () =>
+                                           {
+                                               int current = Interlocked.Increment (ref counter);
+
+                                               if (current == expected)
+                                               {
+                                                   completed.Set ();
+                                               }
+
+                                               return false; // One-shot
+                                           });
+                      });
 
         // Run timers multiple times to ensure all are processed
-        for (int i = 0; i < 10; i++)
+        for (var i = 0; i < 10; i++)
         {
             timedEvents.RunTimers ();
+
             if (completed.IsSet)
             {
                 break;
             }
+
             Thread.Sleep (10);
         }
 
@@ -46,72 +54,79 @@ public class TimedEventsTests
     [Fact]
     public void GetTimestampTicks_Provides_High_Resolution ()
     {
-        var timedEvents = new Terminal.Gui.App.TimedEvents ();
-        
+        var timedEvents = new TimedEvents ();
+
         // Add multiple timeouts with TimeSpan.Zero rapidly
-        var timestamps = new List<long> ();
-        
+        List<long> timestamps = new ();
+
         // Single event handler to capture all timestamps
-        EventHandler<Terminal.Gui.App.TimeoutEventArgs>? handler = null;
-        handler = (s, e) =>
-        {
-            timestamps.Add (e.Ticks);
-        };
-        
+        EventHandler<TimeoutEventArgs>? handler = null;
+        handler = (s, e) => { timestamps.Add (e.Ticks); };
+
         timedEvents.Added += handler;
-        
-        for (int i = 0; i < 100; i++)
+
+        for (var i = 0; i < 100; i++)
         {
             timedEvents.Add (TimeSpan.Zero, () => false);
         }
-        
+
         timedEvents.Added -= handler;
 
         // Verify that we got timestamps
         Assert.True (timestamps.Count > 0, $"Should have captured timestamps. Got {timestamps.Count}");
-        
+
         // Verify that we got unique timestamps (or very close)
         // With Stopwatch, we should have much better resolution than DateTime.UtcNow
-        var uniqueTimestamps = timestamps.Distinct ().Count ();
-        
+        int uniqueTimestamps = timestamps.Distinct ().Count ();
+
         // We should have mostly unique timestamps
         // Allow some duplicates due to extreme speed, but should be > 50% unique
-        Assert.True (uniqueTimestamps > timestamps.Count / 2, 
-            $"Expected more unique timestamps. Got {uniqueTimestamps} unique out of {timestamps.Count} total");
+        Assert.True (
+                     uniqueTimestamps > timestamps.Count / 2,
+                     $"Expected more unique timestamps. Got {uniqueTimestamps} unique out of {timestamps.Count} total");
     }
 
     [Fact]
     public void TimeSpan_Zero_Executes_Immediately ()
     {
-        var timedEvents = new Terminal.Gui.App.TimedEvents ();
+        var timedEvents = new TimedEvents ();
         var executed = false;
 
-        timedEvents.Add (TimeSpan.Zero, () =>
-        {
-            executed = true;
-            return false;
-        });
+        timedEvents.Add (
+                         TimeSpan.Zero,
+                         () =>
+                         {
+                             executed = true;
+
+                             return false;
+                         });
+
+        Assert.True (timedEvents.Timeouts.Keys [0] > 0);
 
         // Should execute on first RunTimers call
         timedEvents.RunTimers ();
 
+        Assert.Empty (timedEvents.Timeouts);
         Assert.True (executed);
     }
 
     [Fact]
     public void Multiple_TimeSpan_Zero_Timeouts_All_Execute ()
     {
-        var timedEvents = new Terminal.Gui.App.TimedEvents ();
+        var timedEvents = new TimedEvents ();
         var executeCount = 0;
         var expected = 100;
 
-        for (int i = 0; i < expected; i++)
+        for (var i = 0; i < expected; i++)
         {
-            timedEvents.Add (TimeSpan.Zero, () =>
-            {
-                Interlocked.Increment (ref executeCount);
-                return false;
-            });
+            timedEvents.Add (
+                             TimeSpan.Zero,
+                             () =>
+                             {
+                                 Interlocked.Increment (ref executeCount);
+
+                                 return false;
+                             });
         }
 
         // Run timers once

+ 8 - 29
Tests/UnitTests/AutoInitShutdownAttribute.cs

@@ -26,7 +26,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
     ///     <paramref name="autoInit"/> is true.
     /// </param>
     /// <param name="useFakeClipboard">
-    ///     If true, will force the use of <see cref="FakeDriver.FakeClipboard"/>. Only valid if
+    ///     If true, will force the use of <see cref="FakeClipboard"/>. Only valid if
     ///     <see cref="IConsoleDriver"/> == <see cref="FakeDriver"/> and <paramref name="autoInit"/> is true.
     /// </param>
     /// <param name="fakeClipboardAlwaysThrowsNotSupportedException">
@@ -107,7 +107,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
         Debug.Assert (!CM.IsEnabled, "This test left ConfigurationManager enabled!");
 
         // Force the ConfigurationManager to reset to its hardcoded defaults
-        CM.Disable(true);
+        CM.Disable (true);
     }
 
     public override void Before (MethodInfo methodUnderTest)
@@ -138,12 +138,14 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
 #endif
             if (_driverType == null)
             {
-                Application.Top = null;
-                Application.TopLevels.Clear ();
+                //Application.Init (null, "fake");
+                //Application.Driver!.SetScreenSize (80, 25);
+                //Application.Top = null;
+                //Application.TopLevels.Clear ();
 
                 var fa = new FakeApplicationFactory ();
                 _v2Cleanup = fa.SetupFakeApplication ();
-                AutoInitShutdownAttribute.FakeResize (new Size (80,25));
+                //Application.Driver!.SetScreenSize (80,25));
             }
             else
             {
@@ -154,35 +156,12 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
 
     private bool AutoInit { get; }
 
-    /// <summary>
-    /// 'Resizes' the application and forces layout. Only works if your test uses <see cref="AutoInitShutdownAttribute"/>
-    /// </summary>
-    /// <param name="size"></param>
-    public static void FakeResize (Size size)
-    {
-        var d = (IConsoleDriverFacade)Application.Driver!;
-        d.OutputBuffer.SetWindowSize (size.Width, size.Height);
-        
-        // Handle both FakeSizeMonitor (from test project) and FakeWindowSizeMonitor (from main library)
-        if (d.WindowSizeMonitor is FakeSizeMonitor fakeSizeMonitor)
-        {
-            fakeSizeMonitor.RaiseSizeChanging (size);
-        }
-        else if (d.WindowSizeMonitor is FakeWindowSizeMonitor fakeWindowSizeMonitor)
-        {
-            // For FakeWindowSizeMonitor, use the RaiseSizeChanging method
-            fakeWindowSizeMonitor.RaiseSizeChanging (size);
-        }
-
-        Application.LayoutAndDraw (true);
-    }
-
     /// <summary>
     /// Runs a single iteration of the main loop (layout, draw, run timed events etc.)
     /// </summary>
     public static void RunIteration ()
     {
-        var a = (ApplicationImpl)ApplicationImpl.Instance;
+        ApplicationImpl a = (ApplicationImpl)ApplicationImpl.Instance;
         a.Coordinator?.RunIteration ();
     }
 }

+ 57 - 80
Tests/UnitTests/ConsoleDrivers/ClipRegionTests.cs

@@ -15,119 +15,96 @@ public class ClipRegionTests
         this._output = output;
     }
 
-    [Theory]
-    [InlineData (typeof (FakeDriver))]
-    //[InlineData (typeof (DotNetDriver))]
-
-    //[InlineData (typeof (ANSIDriver))]
-    //[InlineData (typeof (WindowsDriver))]
-    //[InlineData (typeof (UnixDriver))]
-    public void AddRune_Is_Clipped (Type driverType)
+    [Fact]
+    public void AddRune_Is_Clipped ()
     {
-        var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
-        Application.Init (driver);
-        Application.Driver!.Rows = 25;
-        Application.Driver!.Cols = 80;
+        Application.Init (null, "fake");
 
-        driver.Move (0, 0);
-        driver.AddRune ('x');
-        Assert.Equal ((Rune)'x', driver.Contents [0, 0].Rune);
+        Application.Driver!.Move (0, 0);
+        Application.Driver!.AddRune ('x');
+        Assert.Equal ((Rune)'x', Application.Driver!.Contents! [0, 0].Rune);
 
-        driver.Move (5, 5);
-        driver.AddRune ('x');
-        Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
+        Application.Driver?.Move (5, 5);
+        Application.Driver?.AddRune ('x');
+        Assert.Equal ((Rune)'x', Application.Driver!.Contents [5, 5].Rune);
 
         // Clear the contents
-        driver.FillRect (new Rectangle (0, 0, driver.Rows, driver.Cols), ' ');
-        Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
+        Application.Driver?.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), ' ');
+        Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune);
 
         // Setup the region with a single rectangle, fill screen with 'x'
-        driver.Clip = new (new Rectangle (5, 5, 5, 5));
-        driver.FillRect (new Rectangle (0, 0, driver.Rows, driver.Cols), 'x');
-        Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
-        Assert.Equal ((Rune)' ', driver.Contents [4, 9].Rune);
-        Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
-        Assert.Equal ((Rune)'x', driver.Contents [9, 9].Rune);
-        Assert.Equal ((Rune)' ', driver.Contents [10, 10].Rune);
+        Application.Driver!.Clip = new (new Rectangle (5, 5, 5, 5));
+        Application.Driver.FillRect (new Rectangle (0, 0, Application.Driver.Rows, Application.Driver.Cols), 'x');
+        Assert.Equal ((Rune)' ', Application.Driver?.Contents [0, 0].Rune);
+        Assert.Equal ((Rune)' ', Application.Driver?.Contents [4, 9].Rune);
+        Assert.Equal ((Rune)'x', Application.Driver?.Contents [5, 5].Rune);
+        Assert.Equal ((Rune)'x', Application.Driver?.Contents [9, 9].Rune);
+        Assert.Equal ((Rune)' ', Application.Driver?.Contents [10, 10].Rune);
 
         Application.Shutdown ();
     }
 
-    [Theory]
-    [InlineData (typeof (FakeDriver))]
-    //[InlineData (typeof (DotNetDriver))]
-
-    //[InlineData (typeof (ANSIDriver))]
-    //[InlineData (typeof (WindowsDriver))]
-    //[InlineData (typeof (UnixDriver))]
-    public void Clip_Set_To_Empty_AllInvalid (Type driverType)
+    [Fact]
+    public void Clip_Set_To_Empty_AllInvalid ()
     {
-        var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
-        Application.Init (driver);
+        Application.Init (null, "fake");
 
         // Define a clip rectangle
-        driver.Clip = new (Rectangle.Empty);
+        Application.Driver!.Clip = new (Rectangle.Empty);
 
         // negative
-        Assert.False (driver.IsValidLocation (default, 4, 5));
-        Assert.False (driver.IsValidLocation (default, 5, 4));
-        Assert.False (driver.IsValidLocation (default, 10, 9));
-        Assert.False (driver.IsValidLocation (default, 9, 10));
-        Assert.False (driver.IsValidLocation (default, -1, 0));
-        Assert.False (driver.IsValidLocation (default, 0, -1));
-        Assert.False (driver.IsValidLocation (default, -1, -1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows));
+        Assert.False (Application.Driver.IsValidLocation (default, 4, 5));
+        Assert.False (Application.Driver.IsValidLocation (default, 5, 4));
+        Assert.False (Application.Driver.IsValidLocation (default, 10, 9));
+        Assert.False (Application.Driver.IsValidLocation (default, 9, 10));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, 0));
+        Assert.False (Application.Driver.IsValidLocation (default, 0, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows));
 
         Application.Shutdown ();
     }
 
-    [Theory]
-    [InlineData (typeof (FakeDriver))]
-    //[InlineData (typeof (DotNetDriver))]
-
-    //[InlineData (typeof (ANSIDriver))]
-    //[InlineData (typeof (WindowsDriver))]
-    //[InlineData (typeof (UnixDriver))]
-    public void IsValidLocation (Type driverType)
+    [Fact]
+    public void IsValidLocation ()
     {
-        var driver = (IConsoleDriver)Activator.CreateInstance (driverType);
-        Application.Init (driver);
+        Application.Init (null, "fake");
         Application.Driver!.Rows = 10;
         Application.Driver!.Cols = 10;
 
         // positive
-        Assert.True (driver.IsValidLocation (default, 0, 0));
-        Assert.True (driver.IsValidLocation (default, 1, 1));
-        Assert.True (driver.IsValidLocation (default, driver.Cols - 1, driver.Rows - 1));
+        Assert.True (Application.Driver.IsValidLocation (default, 0, 0));
+        Assert.True (Application.Driver.IsValidLocation (default, 1, 1));
+        Assert.True (Application.Driver.IsValidLocation (default, Application.Driver.Cols - 1, Application.Driver.Rows - 1));
 
         // negative
-        Assert.False (driver.IsValidLocation (default, -1, 0));
-        Assert.False (driver.IsValidLocation (default, 0, -1));
-        Assert.False (driver.IsValidLocation (default, -1, -1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, 0));
+        Assert.False (Application.Driver.IsValidLocation (default, 0, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows));
 
         // Define a clip rectangle
-        driver.Clip = new(new Rectangle(5, 5, 5, 5));
+        Application.Driver.Clip = new (new Rectangle (5, 5, 5, 5));
 
         // positive
-        Assert.True (driver.IsValidLocation (default, 5, 5));
-        Assert.True (driver.IsValidLocation (default, 9, 9));
+        Assert.True (Application.Driver.IsValidLocation (default, 5, 5));
+        Assert.True (Application.Driver.IsValidLocation (default, 9, 9));
 
         // negative
-        Assert.False (driver.IsValidLocation (default, 4, 5));
-        Assert.False (driver.IsValidLocation (default, 5, 4));
-        Assert.False (driver.IsValidLocation (default, 10, 9));
-        Assert.False (driver.IsValidLocation (default, 9, 10));
-        Assert.False (driver.IsValidLocation (default, -1, 0));
-        Assert.False (driver.IsValidLocation (default, 0, -1));
-        Assert.False (driver.IsValidLocation (default, -1, -1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows - 1));
-        Assert.False (driver.IsValidLocation (default, driver.Cols, driver.Rows));
+        Assert.False (Application.Driver.IsValidLocation (default, 4, 5));
+        Assert.False (Application.Driver.IsValidLocation (default, 5, 4));
+        Assert.False (Application.Driver.IsValidLocation (default, 10, 9));
+        Assert.False (Application.Driver.IsValidLocation (default, 9, 10));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, 0));
+        Assert.False (Application.Driver.IsValidLocation (default, 0, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, -1, -1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows - 1));
+        Assert.False (Application.Driver.IsValidLocation (default, Application.Driver.Cols, Application.Driver.Rows));
 
         Application.Shutdown ();
     }

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini