Browse Source

Merge branch 'v2_3338-Toplevel-Must-Be-Disposed' of tig:tig/Terminal.Gui into v2_3338-Toplevel-Must-Be-Disposed

Tig 1 năm trước cách đây
mục cha
commit
92cc648966
100 tập tin đã thay đổi với 1773 bổ sung1146 xóa
  1. 158 111
      Terminal.Gui/Application.cs
  2. 1 0
      Terminal.Gui/FileServices/DefaultFileOperations.cs
  3. 16 1
      Terminal.Gui/View/View.cs
  4. 36 0
      Terminal.Gui/Views/Dialog.cs
  5. 7 4
      Terminal.Gui/Views/FileDialog.cs
  6. 8 3
      Terminal.Gui/Views/ListView.cs
  7. 3 0
      Terminal.Gui/Views/Menu/ContextMenu.cs
  8. 1 0
      Terminal.Gui/Views/MessageBox.cs
  9. 1 1
      Terminal.Gui/Views/TableView/TableView.cs
  10. 1 1
      Terminal.Gui/Views/Toplevel.cs
  11. 1 0
      UICatalog/KeyBindingsDialog.cs
  12. 11 2
      UICatalog/Scenario.cs
  13. 5 4
      UICatalog/Scenarios/ASCIICustomButton.cs
  14. 4 3
      UICatalog/Scenarios/AdornmentExperiments.cs
  15. 5 2
      UICatalog/Scenarios/Adornments.cs
  16. 6 5
      UICatalog/Scenarios/AllViewsTester.cs
  17. 31 17
      UICatalog/Scenarios/BackgroundWorkerCollection.cs
  18. 1 1
      UICatalog/Scenarios/Buttons.cs
  19. 10 7
      UICatalog/Scenarios/CharacterMap.cs
  20. 5 2
      UICatalog/Scenarios/ChineseUI.cs
  21. 1 1
      UICatalog/Scenarios/ClassExplorer.cs
  22. 4 3
      UICatalog/Scenarios/Clipping.cs
  23. 8 7
      UICatalog/Scenarios/CollectionNavigatorTester.cs
  24. 3 2
      UICatalog/Scenarios/CombiningMarks.cs
  25. 36 35
      UICatalog/Scenarios/ComputedLayout.cs
  26. 6 5
      UICatalog/Scenarios/ConfigurationEditor.cs
  27. 1 1
      UICatalog/Scenarios/ContextMenus.cs
  28. 4 2
      UICatalog/Scenarios/CsvEditor.cs
  29. 2 1
      UICatalog/Scenarios/Dialogs.cs
  30. 13 10
      UICatalog/Scenarios/DynamicMenuBar.cs
  31. 13 10
      UICatalog/Scenarios/DynamicStatusBar.cs
  32. 16 9
      UICatalog/Scenarios/Editor.cs
  33. 10 3
      UICatalog/Scenarios/FileDialogExamples.cs
  34. 3 2
      UICatalog/Scenarios/Generic.cs
  35. 2 2
      UICatalog/Scenarios/GraphViewExample.cs
  36. 3 2
      UICatalog/Scenarios/HexEditor.cs
  37. 24 23
      UICatalog/Scenarios/HotKeys.cs
  38. 3 0
      UICatalog/Scenarios/Images.cs
  39. 3 2
      UICatalog/Scenarios/InteractiveTree.cs
  40. 7 3
      UICatalog/Scenarios/LineCanvasExperiment.cs
  41. 2 2
      UICatalog/Scenarios/LineViewExample.cs
  42. 3 2
      UICatalog/Scenarios/ListColumns.cs
  43. 3 1
      UICatalog/Scenarios/Localization.cs
  44. 17 16
      UICatalog/Scenarios/MenuBarScenario.cs
  45. 2 2
      UICatalog/Scenarios/MessageBoxes.cs
  46. 3 2
      UICatalog/Scenarios/MultiColouredTable.cs
  47. 15 7
      UICatalog/Scenarios/Notepad.cs
  48. 7 3
      UICatalog/Scenarios/ProgressBarStyles.cs
  49. 6 3
      UICatalog/Scenarios/RunTExample.cs
  50. 4 2
      UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  51. 4 4
      UICatalog/Scenarios/Scrolling.cs
  52. 33 11
      UICatalog/Scenarios/SingleBackgroundWorker.cs
  53. 1 1
      UICatalog/Scenarios/Sliders.cs
  54. 2 2
      UICatalog/Scenarios/SpinnerStyles.cs
  55. 2 2
      UICatalog/Scenarios/SyntaxHighlighting.cs
  56. 2 2
      UICatalog/Scenarios/TabViewExample.cs
  57. 4 2
      UICatalog/Scenarios/TableEditor.cs
  58. 1 1
      UICatalog/Scenarios/TextFormatterDemo.cs
  59. 2 2
      UICatalog/Scenarios/TextViewAutocompletePopup.cs
  60. 2 2
      UICatalog/Scenarios/Threading.cs
  61. 1 1
      UICatalog/Scenarios/TileViewNesting.cs
  62. 2 2
      UICatalog/Scenarios/TreeUseCases.cs
  63. 1 1
      UICatalog/Scenarios/TreeViewFileSystem.cs
  64. 2 2
      UICatalog/Scenarios/Unicode.cs
  65. 8 7
      UICatalog/Scenarios/ViewExperiments.cs
  66. 5 5
      UICatalog/Scenarios/WindowsAndFrameViews.cs
  67. 4 3
      UICatalog/Scenarios/WizardAsView.cs
  68. 3 2
      UICatalog/Scenarios/Wizards.cs
  69. 2 0
      UICatalog/UICatalog.cs
  70. 202 32
      UnitTests/Application/ApplicationTests.cs
  71. 29 24
      UnitTests/Application/KeyboardTests.cs
  72. 6 4
      UnitTests/Application/MainLoopTests.cs
  73. 15 12
      UnitTests/Application/MouseTests.cs
  74. 1 0
      UnitTests/Application/RunStateTests.cs
  75. 6 4
      UnitTests/ConsoleDrivers/ConsoleDriverTests.cs
  76. 206 60
      UnitTests/Dialogs/DialogTests.cs
  77. 15 30
      UnitTests/Dialogs/MessageBoxTests.cs
  78. 3 2
      UnitTests/Drawing/LineCanvasTests.cs
  79. 12 8
      UnitTests/Drawing/RulerTests.cs
  80. 3 2
      UnitTests/Drawing/ThicknessTests.cs
  81. 4 3
      UnitTests/Input/EscSeqUtilsTests.cs
  82. 1 0
      UnitTests/TestHelpers.cs
  83. 2 2
      UnitTests/Text/AutocompleteTests.cs
  84. 5 4
      UnitTests/UICatalog/ScenarioTests.cs
  85. 8 6
      UnitTests/View/Adornment/BorderTests.cs
  86. 13 9
      UnitTests/View/DrawTests.cs
  87. 9 8
      UnitTests/View/Layout/DimTests.cs
  88. 24 15
      UnitTests/View/Layout/LayoutTests.cs
  89. 27 20
      UnitTests/View/Layout/PosTests.cs
  90. 3 1
      UnitTests/View/MouseTests.cs
  91. 58 45
      UnitTests/View/NavigationTests.cs
  92. 2 0
      UnitTests/View/SubviewTests.cs
  93. 410 398
      UnitTests/View/Text/AutoSizeTrueTests.cs
  94. 12 8
      UnitTests/View/ViewKeyBindingTests.cs
  95. 24 20
      UnitTests/View/ViewTests.cs
  96. 4 1
      UnitTests/Views/AllViewsTests.cs
  97. 1 1
      UnitTests/Views/AppendAutocompleteTests.cs
  98. 27 31
      UnitTests/Views/ButtonTests.cs
  99. 22 15
      UnitTests/Views/CheckBoxTests.cs
  100. 3 2
      UnitTests/Views/ColorPickerTests.cs

+ 158 - 111
Terminal.Gui/Application.cs

@@ -75,6 +75,10 @@ public static partial class Application
                       .ToList ();
     }
 
+    // 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;
+
     // IMPORTANT: Ensure all property/fields are reset here. See Init_ResetState_Resets_Properties unit test.
     // Encapsulate all setting of initial state for Application; Having
     // this in a function like this ensures we don't make mistakes in
@@ -88,13 +92,29 @@ public static partial class Application
         foreach (Toplevel t in _topLevels)
         {
             t.Running = false;
-            t.Dispose ();
+#if DEBUG_IDISPOSABLE
+            // Don't dispose the tolevels. It's up to caller dispose them
+            Debug.Assert (t.WasDisposed);
+#endif
         }
 
         _topLevels.Clear ();
         Current = null;
-        Top?.Dispose ();
+#if DEBUG_IDISPOSABLE
+        // Don't dispose the Top. It's up to caller dispose it
+        if (Top is { })
+        {
+            Debug.Assert (Top.WasDisposed);
+            // If End wasn't called _latestClosedRunStateToplevel may be null
+            if (_cachedRunStateToplevel is { })
+            {
+                Debug.Assert (_cachedRunStateToplevel.WasDisposed);
+                Debug.Assert (_cachedRunStateToplevel == Top);
+            }
+        }
+#endif
         Top = null;
+        _cachedRunStateToplevel = null;
 
         // MainLoop stuff
         MainLoop?.Dispose ();
@@ -161,12 +181,12 @@ public static partial class Application
     /// </para>
     /// <para>
     ///     <see cref="Shutdown"/> must be called when the application is closing (typically after
-    ///     <see cref="Run(Func{Exception, bool})"/> has returned) to ensure resources are cleaned up and terminal settings
+    ///     <see cref="Run(Func{Exception, bool}, ConsoleDriver)"/> has returned) to ensure resources are cleaned up and terminal settings
     ///     restored.
     /// </para>
     /// <para>
     ///     The <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> function combines
-    ///     <see cref="Init(ConsoleDriver, string)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/> into a single
+    ///     <see cref="Init(ConsoleDriver, string)"/> and <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> into a single
     ///     call. An application cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> without explicitly calling
     ///     <see cref="Init(ConsoleDriver, string)"/>.
     /// </para>
@@ -179,7 +199,7 @@ public static partial class Application
     ///     <see cref="ConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are
     ///     specified the default driver for the platform will be used.
     /// </param>
-    public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (() => new Toplevel (), driver, driverName); }
+    public static void Init (ConsoleDriver driver = null, string driverName = null) { InternalInit (driver, driverName); }
 
     internal static bool _initialized;
     internal static int _mainThreadId = -1;
@@ -194,7 +214,6 @@ public static partial class Application
     // 
     // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
     internal static void InternalInit (
-        Func<Toplevel> topLevelFactory,
         ConsoleDriver driver = null,
         string driverName = null,
         bool calledViaRunT = false
@@ -292,12 +311,6 @@ public static partial class Application
 
         SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
 
-        Top = topLevelFactory ();
-        Current = Top;
-
-        // Ensure Top's layout is up to date.
-        Current.SetRelativeLayout (Driver.Bounds);
-
         SupportedCultures = GetSupportedCultures ();
         _mainThreadId = Thread.CurrentThread.ManagedThreadId;
         _initialized = true;
@@ -332,7 +345,7 @@ public static partial class Application
     /// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
     /// <remarks>
     ///     Shutdown must be called for every call to <see cref="Init"/> or
-    ///     <see cref="Application.Run(Toplevel, Func{Exception, bool})"/> to ensure all resources are cleaned up (Disposed)
+    ///     <see cref="Application.Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> to ensure all resources are cleaned up (Disposed)
     ///     and terminal settings are restored.
     /// </remarks>
     public static void Shutdown ()
@@ -369,25 +382,29 @@ public static partial class Application
     ///     The <see cref="RunState"/> handle that needs to be passed to the <see cref="End(RunState)"/> method upon
     ///     completion.
     /// </returns>
-    /// <param name="Toplevel">The <see cref="Toplevel"/> to prepare execution for.</param>
+    /// <param name="toplevel">The <see cref="Toplevel"/> to prepare execution for.</param>
     /// <remarks>
     ///     This method prepares the provided <see cref="Toplevel"/> for running with the focus, it adds this to the list
     ///     of <see cref="Toplevel"/>s, lays out the Subviews, focuses the first element, and draws the <see cref="Toplevel"/>
     ///     in the screen. This is usually followed by executing the <see cref="RunLoop"/> method, and then the
     ///     <see cref="End(RunState)"/> method upon termination which will undo these changes.
     /// </remarks>
-    public static RunState Begin (Toplevel Toplevel)
+    public static RunState Begin (Toplevel toplevel)
     {
-        if (Toplevel is null)
+        if (toplevel is null)
         {
-            throw new ArgumentNullException (nameof (Toplevel));
+            throw new ArgumentNullException (nameof (toplevel));
         }
 
 #if DEBUG_IDISPOSABLE
-        Debug.Assert (!Toplevel.WasDisposed);
+        Debug.Assert (!toplevel.WasDisposed);
+        if (_cachedRunStateToplevel is { } && _cachedRunStateToplevel != toplevel)
+        {
+            Debug.Assert (_cachedRunStateToplevel.WasDisposed);
+        }
 #endif
 
-        if (Toplevel.IsOverlappedContainer && OverlappedTop != Toplevel && OverlappedTop is { })
+        if (toplevel.IsOverlappedContainer && OverlappedTop != toplevel && OverlappedTop is { })
         {
             throw new InvalidOperationException ("Only one Overlapped Container is allowed.");
         }
@@ -395,33 +412,48 @@ public static partial class Application
         // Ensure the mouse is ungrabed.
         MouseGrabView = null;
 
-        var rs = new RunState (Toplevel);
+        var rs = new RunState (toplevel);
 
         // View implements ISupportInitializeNotification which is derived from ISupportInitialize
-        if (!Toplevel.IsInitialized)
+        if (!toplevel.IsInitialized)
+        {
+            toplevel.BeginInit ();
+            toplevel.EndInit ();
+        }
+
+#if DEBUG_IDISPOSABLE
+        if (Top is { } && toplevel != Top && !_topLevels.Contains (Top))
         {
-            Toplevel.BeginInit ();
-            Toplevel.EndInit ();
+            // This assertion confirm if the Top was already disposed
+            Debug.Assert (Top.WasDisposed);
+            Debug.Assert (Top == _cachedRunStateToplevel);
         }
+#endif
 
         lock (_topLevels)
         {
-            // If Top was already initialized with Init, and Begin has never been called
-            // Top was not added to the Toplevels Stack. It will thus never get disposed.
-            // Clean it up here:
-            if (Top is { } && Toplevel != Top && !_topLevels.Contains (Top))
+            if (Top is { } && toplevel != Top && !_topLevels.Contains (Top))
             {
-                Top.Dispose ();
-                Top = null;
+                // If Top was already disposed and isn't on the Toplevels Stack,
+                // clean it up here if is the same as _latestClosedRunStateToplevel
+                if (Top == _cachedRunStateToplevel)
+                {
+                    Top = null;
+                }
+                else
+                {
+                    // Probably this will never hit
+                    throw new ObjectDisposedException (Top.GetType ().FullName);
+                }
             }
-            else if (Top is { } && Toplevel != Top && _topLevels.Contains (Top))
+            else if (OverlappedTop is { } && toplevel != Top && _topLevels.Contains (Top))
             {
-                Top.OnLeave (Toplevel);
+                Top.OnLeave (toplevel);
             }
 
             // BUGBUG: We should not depend on `Id` internally. 
             // BUGBUG: It is super unclear what this code does anyway.
-            if (string.IsNullOrEmpty (Toplevel.Id))
+            if (string.IsNullOrEmpty (toplevel.Id))
             {
                 var count = 1;
                 var id = (_topLevels.Count + count).ToString ();
@@ -432,17 +464,17 @@ public static partial class Application
                     id = (_topLevels.Count + count).ToString ();
                 }
 
-                Toplevel.Id = (_topLevels.Count + count).ToString ();
+                toplevel.Id = (_topLevels.Count + count).ToString ();
 
-                _topLevels.Push (Toplevel);
+                _topLevels.Push (toplevel);
             }
             else
             {
-                Toplevel dup = _topLevels.FirstOrDefault (x => x.Id == Toplevel.Id);
+                Toplevel dup = _topLevels.FirstOrDefault (x => x.Id == toplevel.Id);
 
                 if (dup is null)
                 {
-                    _topLevels.Push (Toplevel);
+                    _topLevels.Push (toplevel);
                 }
             }
 
@@ -452,22 +484,26 @@ public static partial class Application
             }
         }
 
-        if (Top is null || Toplevel.IsOverlappedContainer)
+        if (Top is null || toplevel.IsOverlappedContainer)
         {
-            Top = Toplevel;
+            Top = toplevel;
         }
 
         var refreshDriver = true;
 
-        if (OverlappedTop == null
-            || Toplevel.IsOverlappedContainer
-            || (Current?.Modal == false && Toplevel.Modal)
-            || (Current?.Modal == false && !Toplevel.Modal)
-            || (Current?.Modal == true && Toplevel.Modal))
+        if (OverlappedTop is null
+            || toplevel.IsOverlappedContainer
+            || (Current?.Modal == false && toplevel.Modal)
+            || (Current?.Modal == false && !toplevel.Modal)
+            || (Current?.Modal == true && toplevel.Modal))
         {
-            if (Toplevel.Visible)
+            if (toplevel.Visible)
             {
-                Current = Toplevel;
+                Current?.OnDeactivate (toplevel);
+                var previousCurrent = Current;
+                Current = toplevel;
+                Current.OnActivate (previousCurrent);
+
                 SetCurrentOverlappedAsTop ();
             }
             else
@@ -476,13 +512,13 @@ public static partial class Application
             }
         }
         else if ((OverlappedTop != null
-                  && Toplevel != OverlappedTop
+                  && toplevel != OverlappedTop
                   && Current?.Modal == true
                   && !_topLevels.Peek ().Modal)
-                 || (OverlappedTop is { } && Toplevel != OverlappedTop && Current?.Running == false))
+                 || (OverlappedTop is { } && toplevel != OverlappedTop && Current?.Running == false))
         {
             refreshDriver = false;
-            MoveCurrent (Toplevel);
+            MoveCurrent (toplevel);
         }
         else
         {
@@ -491,39 +527,39 @@ public static partial class Application
         }
 
         //if (Toplevel.LayoutStyle == LayoutStyle.Computed) {
-        Toplevel.SetRelativeLayout (Driver.Bounds);
+        toplevel.SetRelativeLayout (Driver.Bounds);
 
         //}
 
         // BUGBUG: This call is likley not needed.
-        Toplevel.LayoutSubviews ();
-        Toplevel.PositionToplevels ();
-        Toplevel.FocusFirst ();
+        toplevel.LayoutSubviews ();
+        toplevel.PositionToplevels ();
+        toplevel.FocusFirst ();
 
         if (refreshDriver)
         {
-            OverlappedTop?.OnChildLoaded (Toplevel);
-            Toplevel.OnLoaded ();
-            Toplevel.SetNeedsDisplay ();
-            Toplevel.Draw ();
-            Toplevel.PositionCursor ();
+            OverlappedTop?.OnChildLoaded (toplevel);
+            toplevel.OnLoaded ();
+            toplevel.SetNeedsDisplay ();
+            toplevel.Draw ();
+            toplevel.PositionCursor ();
             Driver.Refresh ();
         }
 
-        NotifyNewRunState?.Invoke (Toplevel, new RunStateEventArgs (rs));
+        NotifyNewRunState?.Invoke (toplevel, new RunStateEventArgs (rs));
 
         return rs;
     }
 
     /// <summary>
-    ///     Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> with the value of
+    ///     Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> with the value of
     ///     <see cref="Top"/>.
     /// </summary>
-    /// <remarks>See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.</remarks>
-    public static void Run (Func<Exception, bool> errorHandler = null) { Run (Top, errorHandler); }
+    /// <remarks>See <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> for more details.</remarks>
+    public static void Run (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null) { Run<Toplevel> (errorHandler, driver);}
 
     /// <summary>
-    ///     Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> with a new instance of the
+    ///     Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> with a new instance of the
     ///     specified <see cref="Toplevel"/>-derived class.
     ///     <para>Calling <see cref="Init"/> first is not needed as this function will initialize the application.</para>
     ///     <para>
@@ -531,7 +567,7 @@ public static partial class Application
     ///         ensure resources are cleaned up and terminal settings restored.
     ///     </para>
     /// </summary>
-    /// <remarks>See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.</remarks>
+    /// <remarks>See <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> for more details.</remarks>
     /// <param name="errorHandler"></param>
     /// <param name="driver">
     ///     The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the platform will
@@ -541,48 +577,11 @@ public static partial class Application
     public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
         where T : Toplevel, new()
     {
-        if (_initialized)
-        {
-            // Init created Application.Top. If it hasn't been disposed...
-            if (Top is { })
-            {
-                Top.Dispose ();
-                Top = null;
-            }
-
-            if (Driver is { })
-            {
-                // Init() has been called and we have a driver, so just run the app.
-                // This Toplevel will get disposed in `Shutdown`
-                var top = new T ();
-                Type type = top.GetType ().BaseType;
-
-                while (type != typeof (Toplevel) && type != typeof (object))
-                {
-                    type = type.BaseType;
-                }
+        var top = new T () as Toplevel;
 
-                if (type != typeof (Toplevel))
-                {
-                    throw new ArgumentException ($"{top.GetType ().Name} must be derived from TopLevel");
-                }
+        EnsureValidInitialization (top, driver);
 
-                Run (top, errorHandler);
-            }
-            else
-            {
-                // This code path should be impossible because Init(null, null) will select the platform default driver
-                throw new InvalidOperationException (
-                                                     "Init() completed without a driver being set (this should be impossible); Run<T>() cannot be called."
-                                                    );
-            }
-        }
-        else
-        {
-            // Init() has NOT been called.
-            InternalInit (() => new T (), driver, null, true);
-            Run (Top, errorHandler);
-        }
+        RunApp (top, errorHandler);
     }
 
     /// <summary>Runs the main loop on the given <see cref="Toplevel"/> container.</summary>
@@ -592,11 +591,11 @@ public static partial class Application
     ///         modal <see cref="View"/>s such as <see cref="Dialog"/> boxes.
     ///     </para>
     ///     <para>
-    ///         To make a <see cref="Run(Toplevel, Func{Exception, bool})"/> stop execution, call
+    ///         To make a <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> stop execution, call
     ///         <see cref="Application.RequestStop"/>.
     ///     </para>
     ///     <para>
-    ///         Calling <see cref="Run(Toplevel, Func{Exception, bool})"/> is equivalent to calling
+    ///         Calling <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/> is equivalent to calling
     ///         <see cref="Begin(Toplevel)"/>, followed by <see cref="RunLoop(RunState)"/>, and then calling
     ///         <see cref="End(RunState)"/>.
     ///     </para>
@@ -619,7 +618,19 @@ public static partial class Application
     ///     RELEASE builds only: Handler for any unhandled exceptions (resumes when returns true,
     ///     rethrows when null).
     /// </param>
-    public static void Run (Toplevel view, Func<Exception, bool> errorHandler = null)
+    /// <param name="driver">
+    ///     The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the platform will
+    ///     be used ( <see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, or <see cref="NetDriver"/>). Must be
+    ///     <see langword="null"/> if <see cref="Init"/> has already been called.
+    /// </param>
+    public static void Run (Toplevel view, Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
+    {
+        EnsureValidInitialization (view, driver);
+
+        RunApp (view, errorHandler);
+    }
+
+    private static void RunApp (Toplevel view, Func<Exception, bool> errorHandler = null)
     {
         var resume = true;
 
@@ -655,6 +666,33 @@ public static partial class Application
         }
     }
 
+    private static void EnsureValidInitialization (Toplevel top, ConsoleDriver driver)
+    {
+        if (top is null)
+        {
+            throw new ArgumentException ($"{top.GetType ().Name} must be derived from TopLevel");
+        }
+
+        if (_initialized)
+        {
+            if (Driver is null)
+            {
+                // Ensure disposing the toplevel before throwing
+                top.Dispose ();
+
+                // This code path should be impossible because Init(null, null) will select the platform default driver
+                throw new InvalidOperationException (
+                                                     "Init() completed without a driver being set (this should be impossible); Run<T>() cannot be called."
+                                                    );
+            }
+        }
+        else
+        {
+            // Init() has NOT been called.
+            InternalInit (driver, null, true);
+        }
+    }
+
     /// <summary>Adds a timeout to the application.</summary>
     /// <remarks>
     ///     When time specified passes, the callback will be invoked. If the callback returns true, the timeout will be
@@ -845,7 +883,7 @@ public static partial class Application
     /// <summary>Stops running the most recent <see cref="Toplevel"/> or the <paramref name="top"/> if provided.</summary>
     /// <param name="top">The <see cref="Toplevel"/> to stop.</param>
     /// <remarks>
-    ///     <para>This will cause <see cref="Application.Run(Func{Exception, bool})"/> to return.</para>
+    ///     <para>This will cause <see cref="Application.Run(Func{Exception, bool}, ConsoleDriver)"/> to return.</para>
     ///     <para>
     ///         Calling <see cref="Application.RequestStop"/> is equivalent to setting the <see cref="Toplevel.Running"/>
     ///         property on the currently running <see cref="Toplevel"/> to false.
@@ -1040,8 +1078,17 @@ public static partial class Application
             Refresh ();
         }
 
-        // Do NOT dispose .Toplevel here. It was not created by
-        // Run, but Init or someone else.
+        // Don't dispose runState.Toplevel. It's up to caller dispose it
+        // If it's not the same as the current in the RunIteration,
+        // it will be fixed later in the next RunIteration.
+        if (OverlappedTop is { } && !_topLevels.Contains (OverlappedTop))
+        {
+            _cachedRunStateToplevel = OverlappedTop;
+        }
+        else
+        {
+            _cachedRunStateToplevel = runState.Toplevel;
+        }
         runState.Toplevel = null;
         runState.Dispose ();
     }
@@ -1062,7 +1109,7 @@ public static partial class Application
 
     /// <summary>
     ///     The current <see cref="Toplevel"/> object. This is updated when
-    ///     <see cref="Application.Run(Func{Exception, bool})"/> enters and leaves to point to the current
+    ///     <see cref="Application.Run(Func{Exception, bool}, ConsoleDriver)"/> enters and leaves to point to the current
     ///     <see cref="Toplevel"/> .
     /// </summary>
     /// <value>The current.</value>
@@ -1182,7 +1229,7 @@ public static partial class Application
             && top != OverlappedTop
             && top != Current
             && Current?.Running == false
-            && !top.Running)
+            && top?.Running == false)
         {
             lock (_topLevels)
             {

+ 1 - 0
Terminal.Gui/FileServices/DefaultFileOperations.cs

@@ -162,6 +162,7 @@ public class DefaultFileOperations : IFileOperations
         dlg.AddButton (btnCancel);
 
         Application.Run (dlg);
+        dlg.Dispose ();
 
         result = tf.Text;
 

+ 16 - 1
Terminal.Gui/View/View.cs

@@ -427,9 +427,24 @@ public partial class View : Responder, ISupportInitializeNotification
     /// <value>The title.</value>
     public string Title
     {
-        get => _title;
+        get
+        {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
+            return _title;
+        }
         set
         {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
             if (value == _title)
             {
                 return;

+ 36 - 0
Terminal.Gui/Views/Dialog.cs

@@ -68,9 +68,45 @@ public class Dialog : Window
         Modal = true;
         ButtonAlignment = DefaultButtonAlignment;
 
+        AddCommand (Command.QuitToplevel, () =>
+                                          {
+                                              Canceled = true;
+                                              RequestStop ();
+                                              return true;
+                                          });
         KeyBindings.Add (Key.Esc, Command.QuitToplevel);
     }
 
+
+    private bool _canceled;
+
+    /// <summary>Gets a value indicating whether the <see cref="Dialog"/> was canceled.</summary>
+    /// <remarks>The default value is <see langword="true"/>.</remarks>
+    public bool Canceled
+    {
+        get
+        {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
+            return _canceled;
+        }
+        set
+        {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
+            _canceled = value;
+            return;
+        }
+    }
+
     /// <summary>Determines how the <see cref="Dialog"/> <see cref="Button"/>s are aligned along the bottom of the dialog.</summary>
     public ButtonAlignments ButtonAlignment { get; set; }
 

+ 7 - 4
Terminal.Gui/Views/FileDialog.cs

@@ -60,6 +60,9 @@ public class FileDialog : Dialog
     /// <remarks>This overload is mainly useful for testing.</remarks>
     internal FileDialog (IFileSystem fileSystem)
     {
+        // Assume canceled
+        Canceled = true;
+
         _fileSystem = fileSystem;
         Style = new FileDialogStyle (fileSystem);
 
@@ -83,7 +86,10 @@ public class FileDialog : Dialog
                                   NavigateIf (k, KeyCode.CursorUp, _tableView);
                                   NavigateIf (k, KeyCode.CursorRight, _btnOk);
                               };
-        _btnCancel.Accept += (s, e) => { Application.RequestStop (); };
+        _btnCancel.Accept += (s, e) => {
+                                 Canceled = true;
+                                 Application.RequestStop ();
+                             };
 
         _btnUp = new Button { X = 0, Y = 1, NoPadding = true };
         _btnUp.Text = GetUpButtonText ();
@@ -314,9 +320,6 @@ public class FileDialog : Dialog
         set => _tableView.MultiSelect = value;
     }
 
-    /// <summary>Gets a value indicating whether the <see cref="FileDialog"/> was closed without confirming a selection.</summary>
-    public bool Canceled { get; private set; } = true;
-
     /// <summary>The UI selected <see cref="IAllowedType"/> from combo box. May be null.</summary>
     public IAllowedType CurrentFilter { get; private set; }
 

+ 8 - 3
Terminal.Gui/Views/ListView.cs

@@ -429,7 +429,7 @@ public class ListView : View
     /// <returns></returns>
     public virtual bool MoveDown ()
     {
-        if (_source.Count == 0)
+        if (_source is null || _source.Count == 0)
         {
             // Do we set lastSelectedItem to -1 here?
             return false; //Nothing for us to move to
@@ -479,7 +479,7 @@ public class ListView : View
     /// <returns></returns>
     public virtual bool MoveEnd ()
     {
-        if (_source.Count > 0 && _selected != _source.Count - 1)
+        if (_source is { Count: > 0 } && _selected != _source.Count - 1)
         {
             _selected = _source.Count - 1;
 
@@ -517,6 +517,11 @@ public class ListView : View
     /// <returns></returns>
     public virtual bool MovePageDown ()
     {
+        if (_source is null)
+        {
+            return true;
+        }
+
         int n = _selected + Bounds.Height;
 
         if (n >= _source.Count)
@@ -570,7 +575,7 @@ public class ListView : View
     /// <returns></returns>
     public virtual bool MoveUp ()
     {
-        if (_source.Count == 0)
+        if (_source is null || _source.Count == 0)
         {
             // Do we set lastSelectedItem to -1 here?
             return false; //Nothing for us to move to

+ 3 - 0
Terminal.Gui/Views/Menu/ContextMenu.cs

@@ -116,6 +116,7 @@ public sealed class ContextMenu : IDisposable
         if (_container is { })
         {
             _container.Closing -= Container_Closing;
+            _container.Deactivate -= Container_Deactivate;
         }
     }
 
@@ -142,6 +143,7 @@ public sealed class ContextMenu : IDisposable
 
         _container = Application.Current;
         _container.Closing += Container_Closing;
+        _container.Deactivate += Container_Deactivate;
         Rectangle frame = Application.Driver.Bounds;
         Point position = Position;
 
@@ -217,6 +219,7 @@ public sealed class ContextMenu : IDisposable
         _menuBar.OpenMenu ();
     }
 
+    private void Container_Deactivate (object sender, ToplevelEventArgs e) { Hide (); }
     private void Container_Closing (object sender, ToplevelClosingEventArgs obj) { Hide (); }
     private void MenuBar_MenuAllClosed (object sender, EventArgs e) { Dispose (); }
 }

+ 1 - 0
Terminal.Gui/Views/MessageBox.cs

@@ -468,6 +468,7 @@ public static class MessageBox
 
         // Run the modal; do not shutdown the mainloop driver when done
         Application.Run (d);
+        d.Dispose ();
 
         return Clicked;
     }

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

@@ -2119,7 +2119,7 @@ public class TableView : View
     )
     {
         // if the column index provided is out of bounds
-        if (columnIndex < 0 || columnIndex >= table.Columns)
+        if (table is null || columnIndex < 0 || columnIndex >= table.Columns)
         {
             idx = columnIndex;
 

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

@@ -803,7 +803,7 @@ public partial class Toplevel : View
     {
         if (Application.OverlappedTop is { })
         {
-            Application.OverlappedTop.RequestStop ();
+            RequestStop (this);
         }
         else
         {

+ 1 - 0
UICatalog/KeyBindingsDialog.cs

@@ -82,6 +82,7 @@ internal class KeyBindingsDialog : Dialog
                            Application.RequestStop ();
                        };
         Application.Run (dlg);
+        dlg.Dispose ();
 
         if (key.HasValue)
         {

+ 11 - 2
UICatalog/Scenario.cs

@@ -77,6 +77,11 @@ public class Scenario : IDisposable
     public string TopLevelColorScheme = "Base";
     private bool _disposedValue;
 
+    /// <summary>
+    ///     The Toplevel for the <see cref="Scenario"/>. This should be set to <see cref="Terminal.Gui.Application.Top"/>.
+    /// </summary>
+    public Toplevel Top { get; set; }
+
     /// <summary>
     ///     The Window for the <see cref="Scenario"/>. This should be set to <see cref="Terminal.Gui.Application.Top"/> in
     ///     most cases.
@@ -85,6 +90,8 @@ public class Scenario : IDisposable
 
     public void Dispose ()
     {
+        Top?.Dispose ();
+        Win?.Dispose ();
         // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
         Dispose (true);
         GC.SuppressFinalize (this);
@@ -151,6 +158,8 @@ public class Scenario : IDisposable
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
 
+        Top = new ();
+
         Win = new Window
         {
             Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
@@ -160,7 +169,7 @@ public class Scenario : IDisposable
             Height = Dim.Fill (),
             ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]
         };
-        Application.Top.Add (Win);
+        Top.Add (Win);
     }
 
     /// <summary>Stops the scenario. Override to change shutdown behavior for the <see cref="Scenario"/>.</summary>
@@ -177,7 +186,7 @@ public class Scenario : IDisposable
     public virtual void Run ()
     {
         // Must explicit call Application.Shutdown method to shutdown.
-        Application.Run (Application.Top);
+        Application.Run (Top);
     }
 
     /// <summary>Override this to implement the <see cref="Scenario"/> setup logic (create controls, etc...).</summary>

+ 5 - 4
UICatalog/Scenarios/ASCIICustomButton.cs

@@ -50,8 +50,9 @@ public class ASCIICustomButtonTest : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu, _scrollViewTestWindow);
-        Application.Run ();
+        Top = new ();
+        Top.Add (menu, _scrollViewTestWindow);
+        Application.Run (Top);
     }
 
     public override void Run () { }
@@ -60,9 +61,9 @@ public class ASCIICustomButtonTest : Scenario
     {
         _smallerWindow = (bool)(_miSmallerWindow.Checked = !_miSmallerWindow.Checked);
         _scrollViewTestWindow.Dispose ();
-        Application.Top.Remove (_scrollViewTestWindow);
+        Top.Remove (_scrollViewTestWindow);
         _scrollViewTestWindow = new ScrollViewTestWindow ();
-        Application.Top.Add (_scrollViewTestWindow);
+        Top.Add (_scrollViewTestWindow);
     }
 
     public class ASCIICustomButton : Button

+ 4 - 3
UICatalog/Scenarios/AdornmentExperiments.cs

@@ -13,7 +13,8 @@ public class AdornmentExperiments : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
 
         _diagnosticFlags = View.Diagnostics;
         //View.Diagnostics = ViewDiagnosticFlags.MouseEnter;
@@ -31,10 +32,10 @@ public class AdornmentExperiments : Scenario
             Height = Dim.Percent (90),
             CanFocus = true,
         };
-        Application.Top.Add (_frameView);
+        Top.Add (_frameView);
         _frameView.Initialized += FrameView_Initialized;
 
-        Application.Top.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
+        Top.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
     }
 
     private void FrameView_Initialized (object sender, System.EventArgs e)

+ 5 - 2
UICatalog/Scenarios/Adornments.cs

@@ -18,7 +18,8 @@ public class Adornments : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
 
         var view = new Window { Title = "The _Window" };
         var tf1 = new TextField { Width = 10, Text = "TextField" };
@@ -117,9 +118,11 @@ public class Adornments : Scenario
 #endif
                             };
 
-        Application.Top.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
+        Top.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
 
         Application.Run (editor);
+        editor.Dispose ();
+
         Application.Shutdown ();
     }
 

+ 6 - 5
UICatalog/Scenarios/AllViewsTester.cs

@@ -46,7 +46,8 @@ public class AllViewsTester : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public override void Setup ()
@@ -66,7 +67,7 @@ public class AllViewsTester : Scenario
                                                 {
                                                     View.Diagnostics ^=
                                                         ViewDiagnosticFlags.Ruler;
-                                                    Application.Top.SetNeedsDisplay ();
+                                                    Top.SetNeedsDisplay ();
                                                 }
                                                ),
                                            new (
@@ -76,12 +77,12 @@ public class AllViewsTester : Scenario
                                                 {
                                                     View.Diagnostics ^=
                                                         ViewDiagnosticFlags.Padding;
-                                                    Application.Top.SetNeedsDisplay ();
+                                                    Top.SetNeedsDisplay ();
                                                 }
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         _viewClasses = GetAllViewClassesCollection ()
                        .OrderBy (t => t.Name)
@@ -286,7 +287,7 @@ public class AllViewsTester : Scenario
             ColorScheme = Colors.ColorSchemes ["Dialog"]
         };
 
-        Application.Top.Add (_leftPane, _settingsPane, _hostPane);
+        Top.Add (_leftPane, _settingsPane, _hostPane);
 
         _curView = CreateClass (_viewClasses.First ().Value);
     }

+ 31 - 17
UICatalog/Scenarios/BackgroundWorkerCollection.cs

@@ -13,12 +13,19 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Controls")]
 public class BackgroundWorkerCollection : Scenario
 {
-    public override void Run () { Application.Run<OverlappedMain> (); }
+    public override void Init ()
+    {
+        Application.Run<OverlappedMain> ();
+
+        Application.Top.Dispose ();
+    }
+
+    public override void Run () { }
 
     private class OverlappedMain : Toplevel
     {
         private readonly MenuBar _menu;
-        private readonly WorkerApp _workerApp;
+        private WorkerApp _workerApp;
         private bool _canOpenWorkerApp;
 
         public OverlappedMain ()
@@ -28,6 +35,8 @@ public class BackgroundWorkerCollection : Scenario
             IsOverlappedContainer = true;
 
             _workerApp = new WorkerApp { Visible = false };
+            _workerApp.Border.Thickness = new (0, 1, 0, 0);
+            _workerApp.Border.LineStyle = LineStyle.Dashed;
 
             _menu = new MenuBar
             {
@@ -93,8 +102,6 @@ public class BackgroundWorkerCollection : Scenario
             Activate += OverlappedMain_Activate;
             Deactivate += OverlappedMain_Deactivate;
 
-            Closed += OverlappedMain_Closed;
-
             Application.Iteration += (s, a) =>
                                      {
                                          if (_canOpenWorkerApp && !_workerApp.Running && Application.OverlappedTop.Running)
@@ -165,15 +172,15 @@ public class BackgroundWorkerCollection : Scenario
             return new MenuBarItem ("_Window", new List<MenuItem []> { menuItems.ToArray () });
         }
 
-        private void OverlappedMain_Activate (object sender, ToplevelEventArgs top) { _workerApp.WriteLog ($"{top.Toplevel.Data} activate."); }
-
-        private void OverlappedMain_Closed (object sender, ToplevelEventArgs e)
+        private void OverlappedMain_Activate (object sender, ToplevelEventArgs top)
         {
-            _workerApp.Dispose ();
-            Dispose ();
+            _workerApp?.WriteLog ($"{top.Toplevel.Data} activate.");
         }
 
-        private void OverlappedMain_Deactivate (object sender, ToplevelEventArgs top) { _workerApp.WriteLog ($"{top.Toplevel.Data} deactivate."); }
+        private void OverlappedMain_Deactivate (object sender, ToplevelEventArgs top)
+        {
+            _workerApp?.WriteLog ($"{top.Toplevel.Data} deactivate.");
+        }
         private void Quit () { RequestStop (); }
 
         private MenuBarItem View ()
@@ -208,6 +215,15 @@ public class BackgroundWorkerCollection : Scenario
                                     new List<MenuItem []> { menuItems.Count == 0 ? new MenuItem [] { } : menuItems.ToArray () }
                                    );
         }
+
+        /// <inheritdoc />
+        protected override void Dispose (bool disposing)
+        {
+            _workerApp?.Dispose ();
+            _workerApp = null;
+
+            base.Dispose (disposing);
+        }
     }
 
     private class Staging
@@ -299,7 +315,6 @@ public class BackgroundWorkerCollection : Scenario
 
         public Staging Staging { get; private set; }
         public event Action<StagingUIController> ReportClosed;
-        public void Run () { Application.Run (this); }
 
         private void OnReportClosed (object sender, EventArgs e)
         {
@@ -322,19 +337,17 @@ public class BackgroundWorkerCollection : Scenario
         public WorkerApp ()
         {
             Data = "WorkerApp";
+            Title = "Worker collection Log";
 
             Width = Dim.Percent (80);
             Height = Dim.Percent (50);
 
             ColorScheme = Colors.ColorSchemes ["Base"];
 
-            var label = new Label { X = Pos.Center (), Y = 0, Text = "Worker collection Log" };
-            Add (label);
-
             _listLog = new ListView
             {
                 X = 0,
-                Y = Pos.Bottom (label),
+                Y = 0,
                 Width = Dim.Fill (),
                 Height = Dim.Fill (),
                 Source = new ListWrapper (_log)
@@ -447,7 +460,8 @@ public class BackgroundWorkerCollection : Scenario
                                                  _stagingsUi.Add (stagingUI);
                                                  _stagingWorkers.Remove (staging);
 
-                                                 stagingUI.Run ();
+                                                 Application.Run (stagingUI);
+                                                 stagingUI.Dispose ();
                                              }
                                          };
 
@@ -465,8 +479,8 @@ public class BackgroundWorkerCollection : Scenario
 
                 _stagingWorkers.Add (staging, worker);
                 worker.RunWorkerAsync ();
-                stagingUI.Dispose ();
             }
+            stagingUI.Dispose ();
         }
 
         public void WriteLog (string msg)

+ 1 - 1
UICatalog/Scenarios/Buttons.cs

@@ -329,6 +329,6 @@ public class Buttons : Scenario
                                               }
                                           };
 
-        Application.Top.Ready += (s, e) => radioGroup.Refresh ();
+        Top.Ready += (s, e) => radioGroup.Refresh ();
     }
 }

+ 10 - 7
UICatalog/Scenarios/CharacterMap.cs

@@ -36,13 +36,14 @@ public class CharacterMap : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 
     public override void Setup ()
     {
         _charMap = new() { X = 0, Y = 1, Height = Dim.Fill () };
-        Application.Top.Add (_charMap);
+        Top.Add (_charMap);
 
         var jumpLabel = new Label
         {
@@ -51,19 +52,19 @@ public class CharacterMap : Scenario
             HotKeySpecifier = (Rune)'_',
             Text = "_Jump To Code Point:"
         };
-        Application.Top.Add (jumpLabel);
+        Top.Add (jumpLabel);
 
         var jumpEdit = new TextField
         {
             X = Pos.Right (jumpLabel) + 1, Y = Pos.Y (_charMap), Width = 10, Caption = "e.g. 01BE3"
         };
-        Application.Top.Add (jumpEdit);
+        Top.Add (jumpEdit);
 
         _errorLabel = new()
         {
             X = Pos.Right (jumpEdit) + 1, Y = Pos.Y (_charMap), ColorScheme = Colors.ColorSchemes ["error"], Text = "err"
         };
-        Application.Top.Add (_errorLabel);
+        Top.Add (_errorLabel);
 
 #if TEXT_CHANGED_TO_JUMP
         jumpEdit.TextChanged += JumpEdit_TextChanged;
@@ -135,7 +136,7 @@ public class CharacterMap : Scenario
                                                  _charMap.StartCodePoint = table.Data.ToArray () [args.NewRow].Start;
                                              };
 
-        Application.Top.Add (_categoryList);
+        Top.Add (_categoryList);
 
         _charMap.SelectedCodePoint = 0;
         _charMap.SetFocus ();
@@ -164,7 +165,7 @@ public class CharacterMap : Scenario
                     )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
     }
 
     private void _categoryList_Initialized (object sender, EventArgs e) { _charMap.Width = Dim.Fill () - _categoryList.Width; }
@@ -898,6 +899,7 @@ internal class CharMap : ScrollView
                                    (s as Dialog)?.RequestStop ();
                                };
         Application.Run (waitIndicator);
+        waitIndicator.Dispose ();
 
         if (!string.IsNullOrEmpty (decResponse))
         {
@@ -1011,6 +1013,7 @@ internal class CharMap : ScrollView
             dlg.Add (json);
 
             Application.Run (dlg);
+            dlg.Dispose ();
         }
         else
         {

+ 5 - 2
UICatalog/Scenarios/ChineseUI.cs

@@ -9,7 +9,8 @@ public class ChineseUI : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Toplevel top = Application.Top;
+
+        Toplevel top = new ();
 
         var win = new Window
         {
@@ -55,7 +56,9 @@ public class ChineseUI : Scenario
                          new Button { X = 22, Y = 1, Text = "呀" } // v1: C
                         );
 
-        Application.Run ();
+        Application.Run (top);
+
+        top.Dispose ();
     }
 
     public override void Run () { }

+ 1 - 1
UICatalog/Scenarios/ClassExplorer.cs

@@ -55,7 +55,7 @@ public class ClassExplorer : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _treeView = new TreeView<object> { X = 0, Y = 1, Width = Dim.Percent (50), Height = Dim.Fill () };
 

+ 4 - 3
UICatalog/Scenarios/Clipping.cs

@@ -9,7 +9,8 @@ public class Clipping : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 
     public override void Setup ()
@@ -22,7 +23,7 @@ public class Clipping : Scenario
         {
             X = 0, Y = 0, Text = "ScrollView (new Rectangle (3, 3, 50, 20)) with a 200, 100 ContentSize..."
         };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         var scrollView = new ScrollView { X = 3, Y = 3, Width = 50, Height = 20 };
         scrollView.ColorScheme = Colors.ColorSchemes ["Menu"];
@@ -79,6 +80,6 @@ public class Clipping : Scenario
 
         scrollView.Add (embedded1);
 
-        Application.Top.Add (scrollView);
+        Top.Add (scrollView);
     }
 }

+ 8 - 7
UICatalog/Scenarios/CollectionNavigatorTester.cs

@@ -80,7 +80,8 @@ public class CollectionNavigatorTester : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 
     public override void Setup ()
@@ -126,13 +127,13 @@ public class CollectionNavigatorTester : Scenario
             ]
         };
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _items.Sort (StringComparer.OrdinalIgnoreCase);
 
         CreateListView ();
         var vsep = new LineView (Orientation.Vertical) { X = Pos.Right (_listView), Y = 1, Height = Dim.Fill () };
-        Application.Top.Add (vsep);
+        Top.Add (vsep);
         CreateTreeView ();
     }
 
@@ -148,7 +149,7 @@ public class CollectionNavigatorTester : Scenario
             Width = Dim.Percent (50),
             Height = 1
         };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _listView = new ListView
         {
@@ -159,7 +160,7 @@ public class CollectionNavigatorTester : Scenario
             AllowsMarking = false,
             AllowsMultipleSelection = false
         };
-        Application.Top.Add (_listView);
+        Top.Add (_listView);
 
         _listView.SetSource (_items);
 
@@ -178,14 +179,14 @@ public class CollectionNavigatorTester : Scenario
             Width = Dim.Percent (50),
             Height = 1
         };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _treeView = new TreeView
         {
             X = Pos.Right (_listView) + 1, Y = Pos.Bottom (label), Width = Dim.Fill (), Height = Dim.Fill ()
         };
         _treeView.Style.HighlightModelTextOnly = true;
-        Application.Top.Add (_treeView);
+        Top.Add (_treeView);
 
         var root = new TreeNode ("IsLetterOrDigit examples");
 

+ 3 - 2
UICatalog/Scenarios/CombiningMarks.cs

@@ -11,12 +11,13 @@ public class CombiningMarks : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public override void Setup ()
     {
-        Application.Top.DrawContentComplete += (s, e) =>
+        Top.DrawContentComplete += (s, e) =>
                                                {
                                                    Application.Driver.Move (0, 0);
                                                    Application.Driver.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616.");

+ 36 - 35
UICatalog/Scenarios/ComputedLayout.cs

@@ -18,7 +18,8 @@ public class ComputedLayout : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public override void Setup ()
@@ -37,7 +38,7 @@ public class ComputedLayout : Scenario
             Text = rule
         };
 
-        Application.Top.Add (horizontalRuler);
+        Top.Add (horizontalRuler);
 
         // Demonstrate using Dim to create a vertical ruler that always measures the parent window's height
         const string vrule = "|\n1\n2\n3\n4\n5\n6\n7\n8\n9\n";
@@ -53,7 +54,7 @@ public class ComputedLayout : Scenario
             Text = vrule
         };
 
-        Application.Top.LayoutComplete += (s, a) =>
+        Top.LayoutComplete += (s, a) =>
                                           {
                                               horizontalRuler.Text =
                                                   rule.Repeat ((int)Math.Ceiling (horizontalRuler.Bounds.Width / (double)rule.Length)) [
@@ -64,15 +65,15 @@ public class ComputedLayout : Scenario
                                                       [..(verticalRuler.Bounds.Height * 2)];
                                           };
 
-        Application.Top.Add (verticalRuler);
+        Top.Add (verticalRuler);
 
         // Demonstrate At - Using Pos.At to locate a view in an absolute location
         var atButton = new Button { Text = "At(2,1)", X = Pos.At (2), Y = Pos.At (1) };
-        Application.Top.Add (atButton);
+        Top.Add (atButton);
 
         // Throw in a literal absolute - Should function identically to above
         var absoluteButton = new Button { Text = "X = 30, Y = 1", X = 30, Y = 1 };
-        Application.Top.Add (absoluteButton);
+        Top.Add (absoluteButton);
 
         // Demonstrate using Dim to create a window that fills the parent with a margin
         var margin = 10;
@@ -83,7 +84,7 @@ public class ComputedLayout : Scenario
                                   subWin.Title =
                                       $"{subWin.GetType ().Name} {{X={subWin.X},Y={subWin.Y},Width={subWin.Width},Height={subWin.Height}}}";
                               };
-        Application.Top.Add (subWin);
+        Top.Add (subWin);
 
         var i = 1;
         var txt = "Resize the terminal to see computed layout in action.";
@@ -208,7 +209,7 @@ public class ComputedLayout : Scenario
                        }
                       );
         frameView.Add (labelList.ToArray ());
-        Application.Top.Add (frameView);
+        Top.Add (frameView);
 
         frameView = new FrameView
         {
@@ -222,7 +223,7 @@ public class ComputedLayout : Scenario
                                      fv.Title =
                                          $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
                                  };
-        Application.Top.Add (frameView);
+        Top.Add (frameView);
 
         // Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide
         var textView = new TextView
@@ -236,7 +237,7 @@ public class ComputedLayout : Scenario
 
         textView.Text =
             "This TextView should horizontally & vertically centered and \n10% of the screeen height, and 80% of its width.";
-        Application.Top.Add (textView);
+        Top.Add (textView);
 
         var oddballButton = new Button
         {
@@ -244,7 +245,7 @@ public class ComputedLayout : Scenario
             X = Pos.Center (),
             Y = Pos.Bottom (textView) + 1
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         #region Issue2358
 
@@ -252,19 +253,19 @@ public class ComputedLayout : Scenario
         // Until https://github.com/gui-cs/Terminal.Gui/issues/2358 is fixed these won't work right
 
         oddballButton = new Button { Text = "Center + 0", X = Pos.Center () + 0, Y = Pos.Bottom (oddballButton) };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         oddballButton = new Button { Text = "Center + 1", X = Pos.Center () + 1, Y = Pos.Bottom (oddballButton) };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         oddballButton = new Button { Text = "0 + Center", X = 0 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         oddballButton = new Button { Text = "1 + Center", X = 1 + Pos.Center (), Y = Pos.Bottom (oddballButton) };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         oddballButton = new Button { Text = "Center - 1", X = Pos.Center () - 1, Y = Pos.Bottom (oddballButton) };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
         // The `- Pos.Percent(5)` is there so at least something is visible
@@ -274,7 +275,7 @@ public class ComputedLayout : Scenario
             X = Pos.Center () + Pos.Center () - Pos.Percent (50),
             Y = Pos.Bottom (oddballButton)
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
         // The `- Pos.Percent(5)` is there so at least something is visible
@@ -284,7 +285,7 @@ public class ComputedLayout : Scenario
             X = Pos.Percent (50) + Pos.Center () - Pos.Percent (50),
             Y = Pos.Bottom (oddballButton)
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         // This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
         // The `- Pos.Percent(5)` is there so at least something is visible
@@ -294,7 +295,7 @@ public class ComputedLayout : Scenario
             X = Pos.Center () + Pos.Percent (50) - Pos.Percent (50),
             Y = Pos.Bottom (oddballButton)
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         #endregion
 
@@ -305,14 +306,14 @@ public class ComputedLayout : Scenario
             X = Pos.Center () + Pos.Center () - Pos.Percent (50),
             Y = Pos.Bottom (oddballButton)
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         // This demonstrates combining Percents)
         oddballButton = new Button
         {
             Text = "Percent(40) + Percent(10)", X = Pos.Percent (40) + Pos.Percent (10), Y = Pos.Bottom (oddballButton)
         };
-        Application.Top.Add (oddballButton);
+        Top.Add (oddballButton);
 
         // Demonstrate AnchorEnd - Button is anchored to bottom/right
         var anchorButton = new Button { Text = "Button using AnchorEnd", Y = Pos.AnchorEnd () - 1 };
@@ -322,12 +323,12 @@ public class ComputedLayout : Scenario
                                 {
                                     // This demonstrates how to have a dynamically sized button
                                     // Each time the button is clicked the button's text gets longer
-                                    // The call to Application.Top.LayoutSubviews causes the Computed layout to
+                                    // The call to Top.LayoutSubviews causes the Computed layout to
                                     // get updated. 
                                     anchorButton.Text += "!";
-                                    Application.Top.LayoutSubviews ();
+                                    Top.LayoutSubviews ();
                                 };
-        Application.Top.Add (anchorButton);
+        Top.Add (anchorButton);
 
         // Demonstrate AnchorEnd(n) 
         // This is intentionally convoluted to illustrate potential bugs.
@@ -341,7 +342,7 @@ public class ComputedLayout : Scenario
             X = 5,
             Y = Pos.AnchorEnd (2)
         };
-        Application.Top.Add (anchorEndLabel1);
+        Top.Add (anchorEndLabel1);
 
         // Demonstrate DimCombine (via AnchorEnd(n) - 1)
         // This is intentionally convoluted to illustrate potential bugs.
@@ -356,7 +357,7 @@ public class ComputedLayout : Scenario
             X = 5,
             Y = Pos.AnchorEnd (2) - 1 // Pos.Combine
         };
-        Application.Top.Add (anchorEndLabel2);
+        Top.Add (anchorEndLabel2);
 
         // Show positioning vertically using Pos.AnchorEnd via Pos.Combine
         var leftButton = new Button
@@ -368,10 +369,10 @@ public class ComputedLayout : Scenario
                               {
                                   // This demonstrates how to have a dynamically sized button
                                   // Each time the button is clicked the button's text gets longer
-                                  // The call to Application.Top.LayoutSubviews causes the Computed layout to
+                                  // The call to Top.LayoutSubviews causes the Computed layout to
                                   // get updated. 
                                   leftButton.Text += "!";
-                                  Application.Top.LayoutSubviews ();
+                                  Top.LayoutSubviews ();
                               };
 
         // show positioning vertically using Pos.AnchorEnd
@@ -384,10 +385,10 @@ public class ComputedLayout : Scenario
                                 {
                                     // This demonstrates how to have a dynamically sized button
                                     // Each time the button is clicked the button's text gets longer
-                                    // The call to Application.Top.LayoutSubviews causes the Computed layout to
+                                    // The call to Top.LayoutSubviews causes the Computed layout to
                                     // get updated. 
                                     centerButton.Text += "!";
-                                    Application.Top.LayoutSubviews ();
+                                    Top.LayoutSubviews ();
                                 };
 
         // show positioning vertically using another window and Pos.Bottom
@@ -397,18 +398,18 @@ public class ComputedLayout : Scenario
                                {
                                    // This demonstrates how to have a dynamically sized button
                                    // Each time the button is clicked the button's text gets longer
-                                   // The call to Application.Top.LayoutSubviews causes the Computed layout to
+                                   // The call to Top.LayoutSubviews causes the Computed layout to
                                    // get updated. 
                                    rightButton.Text += "!";
-                                   Application.Top.LayoutSubviews ();
+                                   Top.LayoutSubviews ();
                                };
 
         // Center three buttons with 5 spaces between them
         leftButton.X = Pos.Left (centerButton) - (Pos.Right (leftButton) - Pos.Left (leftButton)) - 5;
         rightButton.X = Pos.Right (centerButton) + 5;
 
-        Application.Top.Add (leftButton);
-        Application.Top.Add (centerButton);
-        Application.Top.Add (rightButton);
+        Top.Add (leftButton);
+        Top.Add (centerButton);
+        Top.Add (rightButton);
     }
 }

+ 6 - 5
UICatalog/Scenarios/ConfigurationEditor.cs

@@ -42,7 +42,8 @@ public class ConfigurationEditor : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public void Save ()
@@ -60,7 +61,7 @@ public class ConfigurationEditor : Scenario
             Width = Dim.Fill (), Height = Dim.Fill (1), Orientation = Orientation.Vertical, LineStyle = LineStyle.Single
         };
 
-        Application.Top.Add (_tileView);
+        Top.Add (_tileView);
 
         _lenStatusItem = new StatusItem (KeyCode.CharMask, "Len: ", null);
 
@@ -78,9 +79,9 @@ public class ConfigurationEditor : Scenario
                                        }
                                       );
 
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
-        Application.Top.Loaded += (s, a) => Open ();
+        Top.Loaded += (s, a) => Open ();
 
         _editorColorSchemeChanged += () =>
                                      {
@@ -125,7 +126,7 @@ public class ConfigurationEditor : Scenario
             textView.Enter += (s, e) => { _lenStatusItem.Title = $"Len:{textView.Text.Length}"; };
         }
 
-        Application.Top.LayoutSubviews ();
+        Top.LayoutSubviews ();
     }
 
     private void Quit ()

+ 1 - 1
UICatalog/Scenarios/ContextMenus.cs

@@ -78,7 +78,7 @@ public class ContextMenus : Scenario
 
         Win.WantMousePositionReports = true;
 
-        Application.Top.Closed += (s, e) =>
+        Top.Closed += (s, e) =>
                                   {
                                       Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
                                       Application.MouseEvent -= ApplicationMouseEvent;

+ 4 - 2
UICatalog/Scenarios/CsvEditor.cs

@@ -101,7 +101,7 @@ public class CsvEditor : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -123,7 +123,7 @@ public class CsvEditor : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         Win.Add (_tableView);
 
@@ -316,6 +316,7 @@ public class CsvEditor : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         enteredText = okPressed ? tf.Text : null;
 
@@ -455,6 +456,7 @@ public class CsvEditor : Scenario
         {
             Open (ofd.Path);
         }
+        ofd.Dispose ();
     }
 
     private void Open (string filename)

+ 2 - 1
UICatalog/Scenarios/Dialogs.cs

@@ -155,7 +155,7 @@ public class Dialogs : Scenario
                 + frame.GetAdornmentsThickness ().Vertical;
         }
 
-        Application.Top.LayoutComplete += Top_LayoutComplete;
+        Top.LayoutComplete += Top_LayoutComplete;
 
         Win.Add (frame);
 
@@ -192,6 +192,7 @@ public class Dialogs : Scenario
                                                                        buttonPressedLabel
                                                                       );
                                         Application.Run (dlg);
+                                        dlg.Dispose ();
                                     };
 
         Win.Add (showDialogButton);

+ 13 - 10
UICatalog/Scenarios/DynamicMenuBar.cs

@@ -18,9 +18,11 @@ public class DynamicMenuBar : Scenario
     {
         Application.Init ();
 
-        Application.Top.Add (
-                             new DynamicMenuBarSample { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" }
-                            );
+        Top = new ();
+
+        Top.Add (
+                 new DynamicMenuBarSample { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" }
+                );
     }
 
     public class Binding
@@ -417,9 +419,9 @@ public class DynamicMenuBar : Scenario
                 EditMenuBarItem (_menuItem);
             }
 
-            var _btnOk = new Button { IsDefault = true, Text = "Ok" };
+            var btnOk = new Button { IsDefault = true, Text = "Ok" };
 
-            _btnOk.Accept += (s, e) =>
+            btnOk.Accept += (s, e) =>
                               {
                                   if (string.IsNullOrEmpty (TextTitle.Text))
                                   {
@@ -431,21 +433,22 @@ public class DynamicMenuBar : Scenario
                                       Application.RequestStop ();
                                   }
                               };
-            var _btnCancel = new Button { Text = "Cancel" };
+            var btnCancel = new Button { Text = "Cancel" };
 
-            _btnCancel.Accept += (s, e) =>
+            btnCancel.Accept += (s, e) =>
                                   {
                                       TextTitle.Text = string.Empty;
                                       Application.RequestStop ();
                                   };
-            var _dialog = new Dialog { Title = "Enter the menu details.", Buttons = [_btnOk, _btnCancel] };
+            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel] };
 
             Width = Dim.Fill ();
             Height = Dim.Fill () - 1;
-            _dialog.Add (this);
+            dialog.Add (this);
             TextTitle.SetFocus ();
             TextTitle.CursorPosition = TextTitle.Text.Length;
-            Application.Run (_dialog);
+            Application.Run (dialog);
+            dialog.Dispose ();
 
             if (valid)
             {

+ 13 - 10
UICatalog/Scenarios/DynamicStatusBar.cs

@@ -17,9 +17,11 @@ public class DynamicStatusBar : Scenario
     {
         Application.Init ();
 
-        Application.Top.Add (
-                             new DynamicStatusBarSample { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" }
-                            );
+        Top = new ();
+
+        Top.Add (
+                 new DynamicStatusBarSample { Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}" }
+                );
     }
 
     public class Binding
@@ -253,9 +255,9 @@ public class DynamicStatusBar : Scenario
                 EditStatusItem (_statusItem);
             }
 
-            var _btnOk = new Button { IsDefault = true, Text = "OK" };
+            var btnOk = new Button { IsDefault = true, Text = "OK" };
 
-            _btnOk.Accept += (s, e) =>
+            btnOk.Accept += (s, e) =>
                               {
                                   if (string.IsNullOrEmpty (TextTitle.Text))
                                   {
@@ -275,21 +277,22 @@ public class DynamicStatusBar : Scenario
                                       Application.RequestStop ();
                                   }
                               };
-            var _btnCancel = new Button { Text = "Cancel" };
+            var btnCancel = new Button { Text = "Cancel" };
 
-            _btnCancel.Accept += (s, e) =>
+            btnCancel.Accept += (s, e) =>
                                   {
                                       TextTitle.Text = string.Empty;
                                       Application.RequestStop ();
                                   };
-            var _dialog = new Dialog { Title = "Enter the menu details.", Buttons = [_btnOk, _btnCancel] };
+            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel] };
 
             Width = Dim.Fill ();
             Height = Dim.Fill () - 1;
-            _dialog.Add (this);
+            dialog.Add (this);
             TextTitle.SetFocus ();
             TextTitle.CursorPosition = TextTitle.Text.Length;
-            Application.Run (_dialog);
+            Application.Run (dialog);
+            dialog.Dispose ();
 
             return valid
                        ? new DynamicStatusItem

+ 16 - 9
UICatalog/Scenarios/Editor.cs

@@ -42,6 +42,8 @@ public class Editor : Scenario
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
 
+        Top = new ();
+
         Win = new Window
         {
             Title = _fileName ?? "Untitled",
@@ -51,7 +53,7 @@ public class Editor : Scenario
             Height = Dim.Fill (),
             ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]
         };
-        Application.Top.Add (Win);
+        Top.Add (Win);
 
         _textView = new TextView
         {
@@ -238,7 +240,7 @@ public class Editor : Scenario
             ]
         };
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var siCursorPosition = new StatusItem (KeyCode.Null, "", null);
 
@@ -268,7 +270,7 @@ public class Editor : Scenario
                                                  statusBar.SetNeedsDisplay ();
                                              };
 
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         _scrollBar = new ScrollBarView (_textView, true);
 
@@ -374,7 +376,7 @@ public class Editor : Scenario
                            }
                        };
 
-        Application.Top.Closed += (s, e) => Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
+        Top.Closed += (s, e) => Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
     }
 
     public override void Setup () { }
@@ -1061,6 +1063,7 @@ public class Editor : Scenario
             _fileName = d.FilePaths [0];
             LoadFile ();
         }
+        d.Dispose ();
     }
 
     private void Paste ()
@@ -1259,12 +1262,16 @@ public class Editor : Scenario
         };
         var sd = new SaveDialog { Title = "Save file", AllowedTypes = aTypes };
 
-        sd.Path = Path.Combine (sd.FileName, Win.Title);
+        sd.Path = Win.Title;
         Application.Run (sd);
+        bool canceled = sd.Canceled;
+        string path = sd.Path;
+        string fileName = sd.FileName;
+        sd.Dispose ();
 
-        if (!sd.Canceled)
+        if (!canceled)
         {
-            if (File.Exists (sd.Path))
+            if (File.Exists (path))
             {
                 if (MessageBox.Query (
                                       "Save File",
@@ -1274,7 +1281,7 @@ public class Editor : Scenario
                                      )
                     == 1)
                 {
-                    return SaveFile (sd.FileName, sd.Path);
+                    return SaveFile (fileName, path);
                 }
 
                 _saved = false;
@@ -1282,7 +1289,7 @@ public class Editor : Scenario
                 return _saved;
             }
 
-            return SaveFile (sd.FileName, sd.Path);
+            return SaveFile (fileName, path);
         }
 
         _saved = false;

+ 10 - 3
UICatalog/Scenarios/FileDialogExamples.cs

@@ -204,7 +204,14 @@ public class FileDialogExamples : Scenario
 
         Application.Run (fd);
 
-        if (fd.Canceled)
+        var canceled = fd.Canceled;
+        var multiSelected = fd.MultiSelected;
+        var path = fd.Path;
+
+        // This needs to be disposed before opening other toplevel
+        fd.Dispose ();
+
+        if (canceled)
         {
             MessageBox.Query (
                               "Canceled",
@@ -216,7 +223,7 @@ public class FileDialogExamples : Scenario
         {
             MessageBox.Query (
                               "Chosen!",
-                              "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, fd.MultiSelected.Select (m => m)),
+                              "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
                               "Ok"
                              );
         }
@@ -224,7 +231,7 @@ public class FileDialogExamples : Scenario
         {
             MessageBox.Query (
                               "Chosen!",
-                              "You chose:" + Environment.NewLine + fd.Path,
+                              "You chose:" + Environment.NewLine + path,
                               "Ok"
                              );
         }

+ 3 - 2
UICatalog/Scenarios/Generic.cs

@@ -23,7 +23,8 @@ public class MyScenario : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new Toplevel ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public override void Setup ()
@@ -34,6 +35,6 @@ public class MyScenario : Scenario
         // `Scenario.Run` which calls `Application.Run`. Example:
 
         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
-        Application.Top.Add (button);
+        Top.Add (button);
     }
 }

+ 2 - 2
UICatalog/Scenarios/GraphViewExample.cs

@@ -133,7 +133,7 @@ public class GraphViewExample : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _graphView = new GraphView
         {
@@ -179,7 +179,7 @@ public class GraphViewExample : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
     }
 
     private void EnableDiagnostics ()

+ 3 - 2
UICatalog/Scenarios/HexEditor.cs

@@ -74,7 +74,7 @@ public class HexEditor : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _statusBar = new StatusBar (
                                     new []
@@ -101,7 +101,7 @@ public class HexEditor : Scenario
                                                                             )
                                     }
                                    );
-        Application.Top.Add (_statusBar);
+        Top.Add (_statusBar);
     }
 
     private void _hexView_Edited (object sender, HexViewEditEventArgs e) { _saved = false; }
@@ -203,6 +203,7 @@ public class HexEditor : Scenario
             _hexView.Source = LoadFile ();
             _hexView.DisplayStart = 0;
         }
+        d.Dispose ();
     }
 
     private void Paste () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok"); }

+ 24 - 23
UICatalog/Scenarios/HotKeys.cs

@@ -12,21 +12,22 @@ public class HotKeys : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
-        Application.Top.BorderStyle = LineStyle.RoundedDotted;
-        Application.Top.Title = $"{Application.QuitKey} to _Quit - Scenario: {GetName ()}";
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top.BorderStyle = LineStyle.RoundedDotted;
+        Top.Title = $"{Application.QuitKey} to _Quit - Scenario: {GetName ()}";
     }
 
     public override void Run ()
     {
         var textViewLabel = new Label { Text = "_TextView:", X = 0, Y = 0 };
-        Application.Top.Add (textViewLabel);
+        Top.Add (textViewLabel);
         
         var textField = new TextField (){ X = Pos.Right (textViewLabel) + 1, Y = 0, Width = 10 };
-        Application.Top.Add (textField);
+        Top.Add (textField);
 
         var viewLabel = new Label { Text = "_View:", X = 0, Y = Pos.Bottom (textField) + 1 };
-        Application.Top.Add (viewLabel);
+        Top.Add (viewLabel);
 
         var view = new View () { 
             Title = "View (_focusable)", 
@@ -35,10 +36,10 @@ public class HotKeys : Scenario
             X = Pos.Right (viewLabel) + 1, Y = Pos.Top (viewLabel), Width = 30, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (view);
+        Top.Add (view);
 
         viewLabel = new Label { Text = "Vi_ew:", X = 0, Y = Pos.Bottom (view) + 1 };
-        Application.Top.Add (viewLabel);
+        Top.Add (viewLabel);
 
         view = new View ()
         {
@@ -47,10 +48,10 @@ public class HotKeys : Scenario
             X = Pos.Right (viewLabel) + 1, Y = Pos.Top (viewLabel), Width = 30, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (view);
+        Top.Add (view);
 
         var labelWithFrameLabel = new Label { Text = "_Label with Frame:", X = 0, Y = Pos.Bottom (view) + 1 };
-        Application.Top.Add (labelWithFrameLabel);
+        Top.Add (labelWithFrameLabel);
 
         var labelWithFrameFocusable = new Label ()
         {
@@ -60,10 +61,10 @@ public class HotKeys : Scenario
             X = Pos.Right (labelWithFrameLabel) + 1, Y = Pos.Top (labelWithFrameLabel), Width = 40, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (labelWithFrameFocusable);
+        Top.Add (labelWithFrameFocusable);
 
         labelWithFrameLabel = new Label { Text = "L_abel with Frame:", X = 0, Y = Pos.Bottom (labelWithFrameFocusable) + 1 };
-        Application.Top.Add (labelWithFrameLabel);
+        Top.Add (labelWithFrameLabel);
 
         var labelWithFrame = new Label ()
         {
@@ -72,11 +73,11 @@ public class HotKeys : Scenario
             X = Pos.Right (labelWithFrameLabel) + 1, Y = Pos.Top (labelWithFrameLabel), Width = 40, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (labelWithFrame);
+        Top.Add (labelWithFrame);
 
         
         var buttonWithFrameLabel = new Label { Text = "_Button with Frame:", X = 0, Y = Pos.Bottom (labelWithFrame) + 1 };
-        Application.Top.Add (buttonWithFrameLabel);
+        Top.Add (buttonWithFrameLabel);
 
         var buttonWithFrameFocusable = new Button ()
         {
@@ -86,10 +87,10 @@ public class HotKeys : Scenario
             X = Pos.Right (buttonWithFrameLabel) + 1, Y = Pos.Top (buttonWithFrameLabel), Width = 40, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (buttonWithFrameFocusable);
+        Top.Add (buttonWithFrameFocusable);
 
         buttonWithFrameLabel = new Label { Text = "Butt_on with Frame:", X = 0, Y = Pos.Bottom (buttonWithFrameFocusable) + 1 };
-        Application.Top.Add (buttonWithFrameLabel);
+        Top.Add (buttonWithFrameLabel);
 
         var buttonWithFrame = new Button ()
         {
@@ -99,12 +100,12 @@ public class HotKeys : Scenario
             CanFocus = false,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (buttonWithFrame);
+        Top.Add (buttonWithFrame);
 
 
 
         var checkboxWithFrameLabel = new Label { Text = "_Checkbox with Frame:", X = 0, Y = Pos.Bottom (buttonWithFrame) + 1 };
-        Application.Top.Add (checkboxWithFrameLabel);
+        Top.Add (checkboxWithFrameLabel);
 
         var checkboxWithFrameFocusable = new CheckBox
         {
@@ -114,10 +115,10 @@ public class HotKeys : Scenario
             X = Pos.Right (checkboxWithFrameLabel) + 1, Y = Pos.Top (checkboxWithFrameLabel), Width = 40, Height = 3,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (checkboxWithFrameFocusable);
+        Top.Add (checkboxWithFrameFocusable);
 
         checkboxWithFrameLabel = new Label { Text = "Checkb_ox with Frame:", X = 0, Y = Pos.Bottom (checkboxWithFrameFocusable) + 1 };
-        Application.Top.Add (checkboxWithFrameLabel);
+        Top.Add (checkboxWithFrameLabel);
 
         var checkboxWithFrame = new CheckBox
         {
@@ -127,12 +128,12 @@ public class HotKeys : Scenario
             CanFocus = false,
             BorderStyle = LineStyle.Dashed,
         };
-        Application.Top.Add (checkboxWithFrame);
+        Top.Add (checkboxWithFrame);
 
 
         var button = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (1), Text = "_Press me!" };
-        Application.Top.Add (button);
+        Top.Add (button);
 
-        Application.Run (Application.Top);
+        Application.Run (Top);
     }
 }

+ 3 - 0
UICatalog/Scenarios/Images.cs

@@ -66,11 +66,14 @@ public class Images : Scenario
 
                                     if (ofd.Canceled)
                                     {
+                                        ofd.Dispose ();
                                         return;
                                     }
 
                                     string path = ofd.FilePaths [0];
 
+                                    ofd.Dispose ();
+
                                     if (string.IsNullOrWhiteSpace (path))
                                     {
                                         return;

+ 3 - 2
UICatalog/Scenarios/InteractiveTree.cs

@@ -23,7 +23,7 @@ public class InteractiveTree : Scenario
                 new MenuBarItem ("_File", new MenuItem [] { new ("_Quit", "", Quit) })
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _treeView = new TreeView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill (1) };
         _treeView.KeyDown += TreeView_KeyPress;
@@ -55,7 +55,7 @@ public class InteractiveTree : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
     }
 
     private void AddChildNode ()
@@ -103,6 +103,7 @@ public class InteractiveTree : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         enteredText = okPressed ? tf.Text : null;
 

+ 7 - 3
UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -8,7 +8,11 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Proof of Concept")]
 public class LineCanvasExperiment : Scenario
 {
-    public override void Init () { Application.Init (); }
+    public override void Init ()
+    {
+        Application.Init ();
+        Top = new ();
+    }
 
     /// <summary>Setup the scenario.</summary>
     public override void Setup ()
@@ -18,7 +22,7 @@ public class LineCanvasExperiment : Scenario
         //	new MenuItem ("_Quit", "", () => Application.RequestStop()),
         //}) });
 
-        //Application.Top.Add (menu);
+        //Top.Add (menu);
 
         var frame1 = new FrameView
         {
@@ -33,7 +37,7 @@ public class LineCanvasExperiment : Scenario
 
         //View.Diagnostics ^= DiagnosticFlags.FrameRuler;
 
-        Application.Top.Add (frame1);
+        Top.Add (frame1);
 
         var win1 = new Window
         {

+ 2 - 2
UICatalog/Scenarios/LineViewExample.cs

@@ -22,7 +22,7 @@ public class LineViewExample : Scenario
                 new MenuBarItem ("_File", new MenuItem [] { new ("_Quit", "", () => Quit ()) })
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         Win.Add (new Label { Y = 0, Text = "Regular Line" });
 
@@ -82,7 +82,7 @@ public class LineViewExample : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
     }
 
     private void Quit () { Application.RequestStop (); }

+ 3 - 2
UICatalog/Scenarios/ListColumns.cs

@@ -208,7 +208,7 @@ public class ListColumns : Scenario
             ]
         };
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -235,7 +235,7 @@ public class ListColumns : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         Win.Add (_listColView);
 
@@ -294,6 +294,7 @@ public class ListColumns : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         if (accepted)
         {

+ 3 - 1
UICatalog/Scenarios/Localization.cs

@@ -93,7 +93,7 @@ public class Localization : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var selectLanguageLabel = new Label
         {
@@ -200,6 +200,7 @@ public class Localization : Scenario
         }
 
         Application.Run (dialog);
+        dialog.Dispose ();
     }
 
     public void ShowWizard ()
@@ -209,6 +210,7 @@ public class Localization : Scenario
         wizard.AddStep (new WizardStep { HelpText = "Wizard step 2", NextButtonText = ">>> (_N)" });
         wizard.AddStep (new WizardStep { HelpText = "Wizard last step" });
         Application.Run (wizard);
+        wizard.Dispose ();
     }
 
     private void LanguageComboBox_SelectChanged (object sender, ListViewItemEventArgs e)

+ 17 - 16
UICatalog/Scenarios/MenuBarScenario.cs

@@ -199,7 +199,8 @@ public class MenuBarScenario : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 
     public override void Setup ()
@@ -208,34 +209,34 @@ public class MenuBarScenario : Scenario
         MenuItem miCurrent = null;
 
         var label = new Label { X = 0, Y = 10, Text = "Last Key: " };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _lastKey = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
 
-        Application.Top.Add (_lastKey);
+        Top.Add (_lastKey);
         label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Current MenuBarItem: " };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _currentMenuBarItem = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        Application.Top.Add (_currentMenuBarItem);
+        Top.Add (_currentMenuBarItem);
 
         label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Current MenuItem: " };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _currentMenuItem = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        Application.Top.Add (_currentMenuItem);
+        Top.Add (_currentMenuItem);
 
         label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Last Action: " };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _lastAction = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        Application.Top.Add (_lastAction);
+        Top.Add (_lastAction);
 
         label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Focused View: " };
-        Application.Top.Add (label);
+        Top.Add (label);
 
         _focusedView = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        Application.Top.Add (_focusedView);
+        Top.Add (_focusedView);
 
         MenuBar menuBar = CreateTestMenu (
                                           s =>
@@ -276,21 +277,21 @@ public class MenuBarScenario : Scenario
                                };
 
         // There's no focus change event, so this is a bit of a hack.
-        menuBar.LayoutComplete += (s, e) => { _focusedView.Text = Application.Top.MostFocused?.ToString () ?? "None"; };
+        menuBar.LayoutComplete += (s, e) => { _focusedView.Text = Top.MostFocused?.ToString () ?? "None"; };
 
         var openBtn = new Button { X = Pos.Center (), Y = 4, Text = "_Open Menu", IsDefault = true };
         openBtn.Accept += (s, e) => { menuBar.OpenMenu (); };
-        Application.Top.Add (openBtn);
+        Top.Add (openBtn);
 
         var hideBtn = new Button { X = Pos.Center (), Y = Pos.Bottom (openBtn), Text = "Toggle Menu._Visible" };
         hideBtn.Accept += (s, e) => { menuBar.Visible = !menuBar.Visible; };
-        Application.Top.Add (hideBtn);
+        Top.Add (hideBtn);
 
         var enableBtn = new Button { X = Pos.Center (), Y = Pos.Bottom (hideBtn), Text = "_Toggle Menu.Enable" };
         enableBtn.Accept += (s, e) => { menuBar.Enabled = !menuBar.Enabled; };
-        Application.Top.Add (enableBtn);
+        Top.Add (enableBtn);
 
-        Application.Top.Add (menuBar);
+        Top.Add (menuBar);
     }
 
     private void SetCurrentMenuBarItem (MenuItem mbi) { _currentMenuBarItem.Text = mbi != null ? mbi.Title : "Closed"; }

+ 2 - 2
UICatalog/Scenarios/MessageBoxes.cs

@@ -188,10 +188,10 @@ public class MessageBoxes : Scenario
                 + styleRadioGroup.Frame.Height
                 + ckbWrapMessage.Frame.Height
                 + frame.GetAdornmentsThickness ().Vertical;
-            Application.Top.Loaded -= Top_LayoutComplete;
+            Top.Loaded -= Top_LayoutComplete;
         }
 
-        Application.Top.LayoutComplete += Top_LayoutComplete;
+        Top.LayoutComplete += Top_LayoutComplete;
 
         label = new Label
         {

+ 3 - 2
UICatalog/Scenarios/MultiColouredTable.cs

@@ -29,7 +29,7 @@ public class MultiColouredTable : Scenario
                 new MenuBarItem ("_File", new MenuItem [] { new ("_Quit", "", () => Quit ()) })
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -41,7 +41,7 @@ public class MultiColouredTable : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         Win.Add (_tableView);
 
@@ -117,6 +117,7 @@ public class MultiColouredTable : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         enteredText = okPressed ? tf.Text : null;
 

+ 15 - 7
UICatalog/Scenarios/Notepad.cs

@@ -19,7 +19,8 @@ public class Notepad : Scenario
     public override void Init ()
     {
         Application.Init ();
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 
     public void Save () { Save (_focusedTabView, _focusedTabView.SelectedTab); }
@@ -56,11 +57,13 @@ public class Notepad : Scenario
 
         if (string.IsNullOrWhiteSpace (fd.Path))
         {
+            fd.Dispose ();
             return false;
         }
 
         if (fd.Canceled)
         {
+            fd.Dispose ();
             return false;
         }
 
@@ -68,6 +71,7 @@ public class Notepad : Scenario
         tab.Text = fd.FileName;
         tab.Save ();
 
+        fd.Dispose ();
         return true;
     }
 
@@ -105,7 +109,7 @@ public class Notepad : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _tabView = CreateNewTabView ();
 
@@ -117,7 +121,7 @@ public class Notepad : Scenario
         split.Tiles.ElementAt (0).ContentView.Add (_tabView);
         split.LineStyle = LineStyle.None;
 
-        Application.Top.Add (split);
+        Top.Add (split);
 
         _lenStatusItem = new StatusItem (KeyCode.CharMask, "Len: ", null);
 
@@ -143,8 +147,8 @@ public class Notepad : Scenario
         _tabView.SelectedTabChanged += TabView_SelectedTabChanged;
         _tabView.Enter += (s, e) => _focusedTabView = _tabView;
 
-        Application.Top.Add (statusBar);
-        Application.Top.Ready += (s, e) => New ();
+        Top.Add (statusBar);
+        Top.Ready += (s, e) => New ();
     }
 
     private void Close () { Close (_focusedTabView, _focusedTabView.SelectedTab); }
@@ -248,19 +252,23 @@ public class Notepad : Scenario
 
         Application.Run (open);
 
-        if (!open.Canceled)
+        bool canceled = open.Canceled;
+
+        if (!canceled)
         {
             foreach (string path in open.FilePaths)
             {
                 if (string.IsNullOrEmpty (path) || !File.Exists (path))
                 {
-                    return;
+                    break;
                 }
 
                 // TODO should open in focused TabView
                 Open (new FileInfo (path), Path.GetFileName (path));
             }
         }
+
+        open.Dispose ();
     }
 
     /// <summary>Creates a new tab with initial text</summary>

+ 7 - 3
UICatalog/Scenarios/ProgressBarStyles.cs

@@ -27,6 +27,8 @@ public class ProgressBarStyles : Scenario
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
 
+        Top = new ();
+
         var editor = new AdornmentsEditor
         {
             Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}", BorderStyle = LineStyle.Single
@@ -72,12 +74,13 @@ public class ProgressBarStyles : Scenario
 
                                          dialog.Bounds = new Rectangle (0, 0, colorPicker.Frame.Width, colorPicker.Frame.Height);
 
-                                         Application.Top.LayoutSubviews ();
+                                         Top.LayoutSubviews ();
                                      };
 
             dialog.Add (colorPicker);
             colorPicker.ColorChanged += (s, e) => { dialog.RequestStop (); };
             Application.Run (dialog);
+            dialog.Dispose ();
 
             ColorName retColor = colorPicker.SelectedColor;
             colorPicker.Dispose ();
@@ -274,7 +277,7 @@ public class ProgressBarStyles : Scenario
                                  300
                                 );
 
-        Application.Top.Unloaded += Top_Unloaded;
+        Top.Unloaded += Top_Unloaded;
 
         void Top_Unloaded (object sender, EventArgs args)
         {
@@ -290,10 +293,11 @@ public class ProgressBarStyles : Scenario
                 _pulseTimer = null;
             }
 
-            Application.Top.Unloaded -= Top_Unloaded;
+            Top.Unloaded -= Top_Unloaded;
         }
 
         Application.Run (editor);
+        editor.Dispose ();
         Application.Shutdown ();
     }
 

+ 6 - 3
UICatalog/Scenarios/RunTExample.cs

@@ -6,13 +6,16 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Top Level Windows")]
 public class RunTExample : Scenario
 {
-    public override void Run () { Application.Run<ExampleWindow> (); }
-
-    public override void Setup ()
+    public override void Init ()
     {
         // No need to call Init if Application.Run<T> is used
+        Application.Run<ExampleWindow> ();
+
+        Application.Top.Dispose ();
     }
 
+    public override void Run () { }
+
     public class ExampleWindow : Window
     {
         private readonly TextField _usernameText;

+ 4 - 2
UICatalog/Scenarios/RuneWidthGreaterThanOne.cs

@@ -21,6 +21,8 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         Application.Init ();
 
+        Top = new ();
+
         var menu = new MenuBar
         {
             Menus =
@@ -85,13 +87,13 @@ public class RuneWidthGreaterThanOne : Scenario
         };
         _win = new Window { X = 5, Y = 5, Width = Dim.Fill (22), Height = Dim.Fill (5) };
         _win.Add (_label, _text, _button, _labelR, _labelV);
-        Application.Top.Add (menu, _win);
+        Top.Add (menu, _win);
 
         WideRunes ();
 
         //NarrowRunes ();
         //MixedRunes ();
-        Application.Run ();
+        Application.Run (Top);
     }
 
     public override void Run () { }

+ 4 - 4
UICatalog/Scenarios/Scrolling.cs

@@ -78,10 +78,10 @@ public class Scrolling : Scenario
             verticalRuler.Text =
                 vrule.Repeat ((int)Math.Ceiling (verticalRuler.Bounds.Height * 2 / (double)rule.Length))
                     [..(verticalRuler.Bounds.Height * 2)];
-            Application.Top.Loaded -= Top_Loaded;
+            Top.Loaded -= Top_Loaded;
         }
 
-        Application.Top.Loaded += Top_Loaded;
+        Top.Loaded += Top_Loaded;
 
         var pressMeButton = new Button { X = 3, Y = 3, Text = "Press me!" };
         pressMeButton.Accept += (s, e) => MessageBox.Query (20, 7, "MessageBox", "Neat?", "Yes", "No");
@@ -270,9 +270,9 @@ public class Scrolling : Scenario
         void Top_Unloaded (object sender, EventArgs args)
         {
             pulsing = false;
-            Application.Top.Unloaded -= Top_Unloaded;
+            Top.Unloaded -= Top_Unloaded;
         }
 
-        Application.Top.Unloaded += Top_Unloaded;
+        Top.Unloaded += Top_Unloaded;
     }
 }

+ 33 - 11
UICatalog/Scenarios/SingleBackgroundWorker.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Threading;
 using Terminal.Gui;
 
@@ -11,15 +12,15 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Top Level Windows")]
 public class SingleBackgroundWorker : Scenario
 {
-    public override void Run ()
+    public override void Init ()
     {
-        Application.Top.Dispose ();
-
         Application.Run<MainApp> ();
 
         Application.Top.Dispose ();
     }
 
+    public override void Run () { }
+
     public class MainApp : Toplevel
     {
         private readonly ListView _listLog;
@@ -77,9 +78,9 @@ public class SingleBackgroundWorker : Scenario
                                           );
             Add (statusBar);
 
-            var top = new Toplevel ();
+            var workerLogTop = new Toplevel () { Title = "Worker Log Top"};
 
-            top.Add (
+            workerLogTop.Add (
                      new Label { X = Pos.Center (), Y = 0, Text = "Worker Log" }
                     );
 
@@ -91,8 +92,9 @@ public class SingleBackgroundWorker : Scenario
                 Height = Dim.Fill (),
                 Source = new ListWrapper (_log)
             };
-            top.Add (_listLog);
-            Add (top);
+            workerLogTop.Add (_listLog);
+            Add (workerLogTop);
+            Title = "MainApp";
         }
 
         private void RunWorker ()
@@ -193,24 +195,32 @@ public class SingleBackgroundWorker : Scenario
 
                                                   var builderUI =
                                                       new StagingUIController (_startStaging, e.Result as List<string>);
+                                                  var top = Application.Top;
+                                                  top.Visible = false;
+                                                  Application.Current.Visible = false;
                                                   builderUI.Load ();
+                                                  builderUI.Dispose ();
+                                                  top.Visible = true;
                                               }
 
                                               _worker = null;
                                           };
             _worker.RunWorkerAsync ();
             Application.Run (md);
+            md.Dispose ();
         }
     }
 
     public class StagingUIController : Window
     {
-        private readonly Toplevel _top;
+        private Toplevel _top;
 
         public StagingUIController (DateTime? start, List<string> list)
         {
-            Rectangle frame = Application.Top.Frame;
-            _top = new Toplevel { X = frame.X, Y = frame.Y, Width = frame.Width, Height = frame.Height };
+            _top = new Toplevel
+            {
+                Title = "_top", Width = Dim.Fill (), Height = Dim.Fill ()
+            };
 
             _top.KeyDown += (s, e) =>
                             {
@@ -299,6 +309,18 @@ public class SingleBackgroundWorker : Scenario
             _top.Add (this);
         }
 
-        public void Load () { Application.Run (_top); }
+        public void Load () {
+            Application.Run (_top);
+            _top.Dispose ();
+            _top = null;
+        }
+
+        ///// <inheritdoc />
+        //protected override void Dispose (bool disposing)
+        //{
+        //    _top?.Dispose ();
+        //    _top = null;
+        //    base.Dispose (disposing);
+        //}
     }
 }

+ 1 - 1
UICatalog/Scenarios/Sliders.cs

@@ -477,6 +477,6 @@ public class Sliders : Scenario
         #endregion Config Slider
 
         Win.FocusFirst ();
-        Application.Top.Initialized += (s, e) => Application.Top.LayoutSubviews ();
+        Top.Initialized += (s, e) => Top.LayoutSubviews ();
     }
 }

+ 2 - 2
UICatalog/Scenarios/SpinnerStyles.cs

@@ -159,7 +159,7 @@ public class SpinnerViewStyles : Scenario
 
         ckbBounce.Toggled += (s, e) => { spinner.SpinBounce = (bool)!e.OldValue; };
 
-        Application.Top.Unloaded += Top_Unloaded;
+        Top.Unloaded += Top_Unloaded;
 
         void SetCustom ()
         {
@@ -200,7 +200,7 @@ public class SpinnerViewStyles : Scenario
                 spinner = null;
             }
 
-            Application.Top.Unloaded -= Top_Unloaded;
+            Top.Unloaded -= Top_Unloaded;
         }
     }
 

+ 2 - 2
UICatalog/Scenarios/SyntaxHighlighting.cs

@@ -164,7 +164,7 @@ public class SyntaxHighlighting : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _textView = new TextView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
 
@@ -183,7 +183,7 @@ public class SyntaxHighlighting : Scenario
                                        }
                                       );
 
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
     }
 
     /// <summary>

+ 2 - 2
UICatalog/Scenarios/TabViewExample.cs

@@ -67,7 +67,7 @@ public class TabViewExample : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _tabView = new TabView
         {
@@ -181,7 +181,7 @@ public class TabViewExample : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
     }
 
     private void AddBlankTab () { _tabView.AddTab (new Tab (), false); }

+ 4 - 2
UICatalog/Scenarios/TableEditor.cs

@@ -669,7 +669,7 @@ public class TableEditor : Scenario
             ]
         };
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -696,7 +696,7 @@ public class TableEditor : Scenario
                                                )
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         Win.Add (_tableView);
 
@@ -886,6 +886,7 @@ public class TableEditor : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         if (okPressed)
         {
@@ -1085,6 +1086,7 @@ public class TableEditor : Scenario
         tf.SetFocus ();
 
         Application.Run (d);
+        d.Dispose ();
 
         if (accepted)
         {

+ 1 - 1
UICatalog/Scenarios/TextFormatterDemo.cs

@@ -57,7 +57,7 @@ public class TextFormatterDemo : Scenario
             X = 0,
             Y = Pos.Bottom (blockText) + 1,
             Text = "Unicode",
-            Checked = Application.Top.HotKeySpecifier == (Rune)' '
+            Checked = Top.HotKeySpecifier == (Rune)' '
         };
 
         Win.Add (unicodeCheckBox);

+ 2 - 2
UICatalog/Scenarios/TextViewAutocompletePopup.cs

@@ -51,7 +51,7 @@ public class TextViewAutocompletePopup : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _textViewTopLeft = new TextView { Width = width, Height = _height, Text = text };
         _textViewTopLeft.DrawContent += TextViewTopLeft_DrawContent;
@@ -105,7 +105,7 @@ public class TextViewAutocompletePopup : Scenario
                                            _siWrap = new StatusItem (KeyCode.Null, "", null)
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         Win.LayoutStarted += Win_LayoutStarted;
     }

+ 2 - 2
UICatalog/Scenarios/Threading.cs

@@ -118,10 +118,10 @@ public class Threading : Scenario
         void Top_Loaded (object sender, EventArgs args)
         {
             _btnActionCancel.SetFocus ();
-            Application.Top.Loaded -= Top_Loaded;
+            Top.Loaded -= Top_Loaded;
         }
 
-        Application.Top.Loaded += Top_Loaded;
+        Top.Loaded += Top_Loaded;
     }
 
     private async void CallLoadItemsAsync ()

+ 1 - 1
UICatalog/Scenarios/TileViewNesting.cs

@@ -62,7 +62,7 @@ public class TileViewNesting : Scenario
 
         SetupTileView ();
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         Win.Loaded += (s, e) => _loaded = true;
     }

+ 2 - 2
UICatalog/Scenarios/TreeUseCases.cs

@@ -47,7 +47,7 @@ public class TreeUseCases : Scenario
             ]
         };
 
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -60,7 +60,7 @@ public class TreeUseCases : Scenario
                                        }
                                       );
 
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         // Start with the most basic use case
         LoadSimpleNodes ();

+ 1 - 1
UICatalog/Scenarios/TreeViewFileSystem.cs

@@ -172,7 +172,7 @@ public class TreeViewFileSystem : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         _treeViewFiles = new TreeView<IFileSystemInfo> { X = 0, Y = 0, Width = Dim.Percent (50), Height = Dim.Fill () };
         _treeViewFiles.DrawLine += TreeViewFiles_DrawLine;

+ 2 - 2
UICatalog/Scenarios/Unicode.cs

@@ -60,7 +60,7 @@ public class UnicodeInMenu : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top.Add (menu);
 
         var statusBar = new StatusBar (
                                        new StatusItem []
@@ -74,7 +74,7 @@ public class UnicodeInMenu : Scenario
                                            new (KeyCode.Null, "~F3~ Со_хранить", null)
                                        }
                                       );
-        Application.Top.Add (statusBar);
+        Top.Add (statusBar);
 
         var label = new Label { X = 0, Y = 1, Text = "Label:" };
         Win.Add (label);

+ 8 - 7
UICatalog/Scenarios/ViewExperiments.cs

@@ -14,7 +14,8 @@ public class ViewExperiments : Scenario
         Application.Init ();
         ConfigurationManager.Themes.Theme = Theme;
         ConfigurationManager.Apply ();
-        Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+        Top = new ();
+        Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
     }
 
     public override void Setup ()
@@ -27,7 +28,7 @@ public class ViewExperiments : Scenario
             Width = Dim.Fill (),
             Height = 3
         };
-        Application.Top.Add (containerLabel);
+        Top.Add (containerLabel);
 
         var view = new View
         {
@@ -40,7 +41,7 @@ public class ViewExperiments : Scenario
             Id = "DaView"
         };
 
-        //Application.Top.Add (view);
+        //Top.Add (view);
 
         view.Margin.Thickness = new Thickness (2, 2, 2, 2);
         view.Margin.ColorScheme = Colors.ColorSchemes ["Toplevel"];
@@ -216,9 +217,9 @@ public class ViewExperiments : Scenario
                                {
                                    containerLabel.Text =
                                        $"Container.Frame: {
-                                           Application.Top.Frame
+                                           Top.Frame
                                        } .Bounds: {
-                                           Application.Top.Bounds
+                                           Top.Bounds
                                        }\nView.Frame: {
                                            view.Frame
                                        } .Bounds: {
@@ -243,11 +244,11 @@ public class ViewExperiments : Scenario
             ViewToEdit = view
         };
 
-        Application.Top.Add (editor);
+        Top.Add (editor);
         view.X = 36;
         view.Y = 4;
         view.Width = Dim.Fill ();
         view.Height = Dim.Fill ();
-        Application.Top.Add (view);
+        Top.Add (view);
     }
 }

+ 5 - 5
UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -27,7 +27,7 @@ public class WindowsAndFrameViews : Scenario
         List<View> listWin = new ();
 
         //Ignore the Win that UI Catalog created and create a new one
-        Application.Top.Remove (Win);
+        Top.Remove (Win);
         Win?.Dispose ();
 
         Win = new Window
@@ -61,7 +61,7 @@ public class WindowsAndFrameViews : Scenario
                      Text = "Press ME! (Y = Pos.AnchorEnd(1))"
                  }
                 );
-        Application.Top.Add (Win);
+        Top.Add (Win);
 
         // add it to our list
         listWin.Add (Win);
@@ -130,7 +130,7 @@ public class WindowsAndFrameViews : Scenario
                           );
             win.Add (frameView);
 
-            Application.Top.Add (win);
+            Top.Add (win);
             listWin.Add (win);
         }
 
@@ -212,9 +212,9 @@ public class WindowsAndFrameViews : Scenario
 
         frame.Add (subFrameViewofFV);
 
-        Application.Top.Add (frame);
+        Top.Add (frame);
         listWin.Add (frame);
 
-        Application.Top.ColorScheme = Colors.ColorSchemes ["Base"];
+        Top.ColorScheme = Colors.ColorSchemes ["Base"];
     }
 }

+ 4 - 3
UICatalog/Scenarios/WizardAsView.cs

@@ -52,7 +52,8 @@ public class WizardAsView : Scenario
                                 )
             ]
         };
-        Application.Top.Add (menu);
+        Top = new ();
+        Top.Add (menu);
 
         // No need for a Title because the border is disabled
         var wizard = new Wizard { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
@@ -138,8 +139,8 @@ public class WizardAsView : Scenario
         lastStep.HelpText =
             "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing Esc will cancel.";
 
-        Application.Top.Add (wizard);
-        Application.Run (Application.Top);
+        Top.Add (wizard);
+        Application.Run (Top);
     }
 
     public override void Run ()

+ 3 - 2
UICatalog/Scenarios/Wizards.cs

@@ -81,10 +81,10 @@ public class Wizards : Scenario
         void Top_Loaded (object sender, EventArgs args)
         {
             frame.Height = widthEdit.Frame.Height + heightEdit.Frame.Height + titleEdit.Frame.Height + 2;
-            Application.Top.Loaded -= Top_Loaded;
+            Top.Loaded -= Top_Loaded;
         }
 
-        Application.Top.Loaded += Top_Loaded;
+        Top.Loaded += Top_Loaded;
 
         label = new Label
         {
@@ -349,6 +349,7 @@ public class Wizards : Scenario
                                                                                     };
 
                                             Application.Run (wizard);
+                                            wizard.Dispose ();
                                         }
                                         catch (FormatException)
                                         {

+ 2 - 0
UICatalog/UICatalog.cs

@@ -992,6 +992,7 @@ internal class UICatalogApp
                            {
                                var dlg = new KeyBindingsDialog ();
                                Application.Run (dlg);
+                               dlg.Dispose ();
                            };
 
             menuItems.Add (null!);
@@ -1069,6 +1070,7 @@ internal class UICatalogApp
         {
             Applied -= ConfigAppliedHandler;
             Unloaded -= UnloadedHandler;
+            Dispose ();
         }
     }
 

+ 202 - 32
UnitTests/Application/ApplicationTests.cs

@@ -39,36 +39,39 @@ public class ApplicationTests
     [AutoInitShutdown]
     public void Begin_Sets_Application_Top_To_Console_Size ()
     {
-        Assert.Equal (new Rectangle (0, 0, 80, 25), Application.Top.Frame);
-        Application.Begin (Application.Top);
+        Assert.Null (Application.Top);
+        Application.Begin (new ());
         Assert.Equal (new Rectangle (0, 0, 80, 25), Application.Top.Frame);
         ((FakeDriver)Application.Driver).SetBufferSize (5, 5);
         Assert.Equal (new Rectangle (0, 0, 5, 5), Application.Top.Frame);
     }
 
     [Fact]
-    public void End_Should_Not_Dispose_ApplicationTop_Shutdown_Should ()
+    public void End_And_Shutdown_Should_Not_Dispose_ApplicationTop ()
     {
         Init ();
 
-        RunState rs = Application.Begin (Application.Top);
+        RunState rs = Application.Begin (new ());
+        Assert.Equal (rs.Toplevel, Application.Top);
         Application.End (rs);
 
 #if DEBUG_IDISPOSABLE
         Assert.True (rs.WasDisposed);
-        Assert.False (Application.Top.WasDisposed);
+        Assert.False (Application.Top.WasDisposed); // Is true because the rs.Toplevel is the same as Application.Top
 #endif
 
         Assert.Null (rs.Toplevel);
 
         var top = Application.Top;
 
-        Shutdown ();
-
 #if DEBUG_IDISPOSABLE
+        var exception = Record.Exception (() => Shutdown ());
+        Assert.NotNull (exception);
+        Assert.False (top.WasDisposed);
+        top.Dispose ();
         Assert.True (top.WasDisposed);
 #endif
-
+        Shutdown ();
         Assert.Null (Application.Top);
     }
 
@@ -107,6 +110,7 @@ public class ApplicationTests
         Assert.NotNull (Application.MainLoop);
         Assert.NotNull (Application.Driver);
 
+        topLevel.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -126,6 +130,7 @@ public class ApplicationTests
         var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
         Application.Init (driverName: driverType.Name);
         Assert.NotNull (Application.Driver);
+        Assert.NotEqual(driver, Application.Driver);
         Assert.Equal (driverType, Application.Driver.GetType ());
         Shutdown ();
     }
@@ -264,7 +269,6 @@ public class ApplicationTests
         Assert.Throws<InvalidOperationException> (
                                                   () =>
                                                       Application.InternalInit (
-                                                                                () => topLevel = new TestToplevel (),
                                                                                 new FakeDriver ()
                                                                                )
                                                  );
@@ -276,7 +280,7 @@ public class ApplicationTests
 
         // Now try the other way
         topLevel = null;
-        Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
+        Application.InternalInit (new FakeDriver ());
 
         Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver ()));
         Shutdown ();
@@ -287,7 +291,7 @@ public class ApplicationTests
     }
 
     [Fact]
-    public void InitWithTopLevelFactory_Begin_End_Cleans_Up ()
+    public void InitWithoutTopLevelFactory_Begin_End_Cleans_Up ()
     {
         // Begin will cause Run() to be called, which will call Begin(). Thus will block the tests
         // if we don't stop
@@ -295,8 +299,8 @@ 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 = null;
-        Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
+        Toplevel topLevel = new ();
+        Application.InternalInit (new FakeDriver ());
 
         RunState runstate = null;
 
@@ -323,6 +327,7 @@ public class ApplicationTests
         Assert.NotNull (Application.MainLoop);
         Assert.NotNull (Application.Driver);
 
+        topLevel.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -335,8 +340,8 @@ public class ApplicationTests
     public void Internal_Properties_Correct ()
     {
         Assert.True (Application._initialized);
-        Assert.NotNull (Application.Top);
-        RunState rs = Application.Begin (Application.Top);
+        Assert.Null (Application.Top);
+        RunState rs = Application.Begin (new ());
         Assert.Equal (Application.Top, rs.Toplevel);
         Assert.Null (Application.MouseGrabView); // public
         Assert.Null (Application.WantContinuousButtonPressedView); // public
@@ -358,6 +363,7 @@ public class ApplicationTests
         Application.MainLoop.Running = true;
         Application.RunIteration (ref rs, ref firstIteration);
         Assert.Equal (1, actionCalled);
+        top.Dispose ();
         Application.Shutdown ();
     }
 
@@ -365,6 +371,8 @@ public class ApplicationTests
     [AutoInitShutdown]
     public void SetCurrentAsTop_Run_A_Not_Modal_Toplevel_Make_It_The_Current_Application_Top ()
     {
+        var top = new Toplevel ();
+
         var t1 = new Toplevel ();
         var t2 = new Toplevel ();
         var t3 = new Toplevel ();
@@ -456,6 +464,13 @@ public class ApplicationTests
         Application.Run (t1);
 
         Assert.Equal (t1, Application.Top);
+        // top wasn't run and so never was added to toplevel's stack
+        Assert.NotEqual (top, Application.Top);
+#if DEBUG_IDISPOSABLE
+        Assert.False (Application.Top.WasDisposed);
+        t1.Dispose ();
+        Assert.True (Application.Top.WasDisposed);
+#endif
     }
 
     private void Init ()
@@ -497,14 +512,19 @@ public class ApplicationTests
 
     [Fact]
 
-    public void Run_T_After_InitWithDriver_with_TopLevel_Throws ()
+    public void Run_T_After_InitWithDriver_with_TopLevel_Does_Not_Throws ()
     {
         // Setup Mock driver
         Init ();
 
-        // Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not derived from TopLevel)
-        Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> ());
+        Application.Iteration += (s, e) => Application.RequestStop ();
+
+        // Run<Toplevel> when already initialized or not with a Driver will not throw (because Window is derived from Toplevel)
+        // Using another type not derived from Toplevel will throws at compile time
+        Application.Run<Window> ();
+        Assert.True (Application.Top is Window);
 
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -514,14 +534,24 @@ public class ApplicationTests
 
     [Fact]
 
-    public void Run_T_After_InitWithDriver_with_TopLevel_and_Driver_Throws ()
+    public void Run_T_After_InitWithDriver_with_TopLevel_and_Driver_Does_Not_Throws ()
     {
         // Setup Mock driver
         Init ();
 
-        // Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not derivied from TopLevel)
-        Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (null, new FakeDriver ()));
+        Application.Iteration += (s, e) => Application.RequestStop ();
 
+        // Run<Toplevel> when already initialized or not with a Driver will not throw (because Window is derived from Toplevel)
+        // Using another type not derived from Toplevel will throws at compile time
+        Application.Run<Window> (null, new FakeDriver ());
+        Assert.True (Application.Top is Window);
+
+        Application.Top.Dispose ();
+        // Run<Toplevel> when already initialized or not with a Driver will not throw (because Dialog is derived from Toplevel)
+        Application.Run<Dialog> (null, new FakeDriver ());
+        Assert.True (Application.Top is Dialog);
+
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -532,18 +562,19 @@ public class ApplicationTests
     [Fact]
     [TestRespondersDisposed]
 
-    public void Run_T_After_Init_Disposes_Application_Top ()
+    public void Run_T_After_Init_Does_Not_Disposes_Application_Top ()
     {
         Init ();
 
-        // Init created a Toplevel and assigned it to Application.Top
-        var initTop = Application.Top;
+        // Init doesn't create a Toplevel and assigned it to Application.Top
+        // but Begin does
+        var initTop = new Toplevel ();
 
         Application.Iteration += (s, a) =>
                                  {
                                      Assert.NotEqual(initTop, Application.Top);
 #if DEBUG_IDISPOSABLE
-                                     Assert.True (initTop.WasDisposed);
+                                     Assert.False (initTop.WasDisposed);
 #endif
                                      Application.RequestStop ();
                                  };
@@ -551,9 +582,11 @@ public class ApplicationTests
         Application.Run<TestToplevel> ();
 
 #if DEBUG_IDISPOSABLE
+        Assert.False (initTop.WasDisposed);
+        initTop.Dispose ();
         Assert.True (initTop.WasDisposed);
 #endif
-
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -574,6 +607,7 @@ public class ApplicationTests
         // Init has been called and we're passing no driver to Run<TestTopLevel>. This is ok.
         Application.Run<TestToplevel> ();
 
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -596,6 +630,7 @@ public class ApplicationTests
         // Init has been called, selecting FakeDriver; we're passing no driver to Run<TestTopLevel>. Should be fine.
         Application.Run<TestToplevel> ();
 
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -612,8 +647,6 @@ public class ApplicationTests
 
         Application.Driver = null;
 
-        Application.Iteration += (s, a) => { Application.RequestStop (); };
-
         // Init has been called, but Driver has been set to null. Bad.
         Assert.Throws<InvalidOperationException> (() => Application.Run<TestToplevel> ());
 
@@ -635,6 +668,7 @@ public class ApplicationTests
         Application.Run<TestToplevel> ();
         Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ());
 
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -652,6 +686,7 @@ public class ApplicationTests
         // Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
         Application.Run<TestToplevel> (null, new FakeDriver ());
 
+        Application.Top.Dispose ();
         Shutdown ();
 
         Assert.Null (Application.Top);
@@ -676,6 +711,7 @@ public class ApplicationTests
 
         Application.Run (top);
 
+        top.Dispose ();
         Application.Shutdown ();
         Assert.Null (Application.Current);
         Assert.Null (Application.Top);
@@ -700,6 +736,7 @@ public class ApplicationTests
 
         Application.Run (top);
 
+        top.Dispose ();
         Application.Shutdown ();
         Assert.Null (Application.Current);
         Assert.Null (Application.Top);
@@ -713,13 +750,14 @@ public class ApplicationTests
     public void Run_Loaded_Ready_Unlodaded_Events ()
     {
         Init ();
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var count = 0;
         top.Loaded += (s, e) => count++;
         top.Ready += (s, e) => count++;
         top.Unloaded += (s, e) => count++;
         Application.Iteration += (s, a) => Application.RequestStop ();
-        Application.Run ();
+        Application.Run (top);
+        top.Dispose ();
         Application.Shutdown ();
         Assert.Equal (3, count);
     }
@@ -733,7 +771,7 @@ public class ApplicationTests
 
         // Don't use Dialog here as it has more layout logic. Use Window instead.
         Dialog d = null;
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.DrawContent += (s, a) => count++;
         int iteration = -1;
 
@@ -768,7 +806,8 @@ public class ApplicationTests
                                          Application.RequestStop ();
                                      }
                                  };
-        Application.Run ();
+        Application.Run (top);
+        top.Dispose ();
         Application.Shutdown ();
 
         // 1 - First top load, 1 - Dialog load, 1 - Dialog unload, Total - 3.
@@ -873,7 +912,138 @@ public class ApplicationTests
                                               );
 
         Application.End (rs);
+        w.Dispose ();
+        Application.Shutdown ();
+    }
+
+    [Fact]
+    public void End_Does_Not_Dispose ()
+    {
+        Init ();
+
+        var top = new Toplevel ();
+
+        Window w = new ();
+        w.Ready += (s, e) => Application.RequestStop (); // Causes `End` to be called
+        Application.Run(w);
+
+#if DEBUG_IDISPOSABLE
+        Assert.False (w.WasDisposed);
+#endif
+
+        Assert.NotNull (w);
+        Assert.Equal (string.Empty, w.Title); // Valid - w has not been disposed. The user may want to run it again
+        Assert.NotNull (Application.Top);
+        Assert.Equal(w, Application.Top);
+        Assert.NotEqual(top, Application.Top);
+        Assert.Null (Application.Current);
+
+        Application.Run(w); // Valid - w has not been disposed.
+
+#if DEBUG_IDISPOSABLE
+        Assert.False (w.WasDisposed);
+        var exception = Record.Exception (() => Application.Shutdown()); // Invalid - w has not been disposed.
+        Assert.NotNull (exception);
+
+        w.Dispose ();
+        Assert.True (w.WasDisposed);
+        exception = Record.Exception (() => Application.Run (w)); // Invalid - w has been disposed. Run it in debug mode will throw, otherwise the user may want to run it again
+        Assert.NotNull (exception);
+
+        exception = Record.Exception (() => Assert.Equal (string.Empty, w.Title)); // Invalid - w has been disposed and cannot be accessed
+        Assert.NotNull (exception);
+        exception = Record.Exception (() => w.Title = "NewTitle"); // Invalid - w has been disposed and cannot be accessed
+        Assert.NotNull (exception);
+#endif
+        Application.Shutdown ();
+        Assert.NotNull (w);
+        Assert.Null (Application.Current);
+        Assert.NotNull (top);
+        Assert.Null (Application.Top);
+    }
+
+    [Fact]
+    public void Run_Creates_Top_Without_Init ()
+    {
+        var driver = new FakeDriver ();
+
+        Assert.Null (Application.Top);
+
+        Application.Iteration += (s, e) =>
+                                 {
+                                     Assert.NotNull (Application.Top);
+                                     Application.RequestStop ();
+                                 };
+        Application.Run (null, driver);
+#if DEBUG_IDISPOSABLE
+        Assert.False (Application.Top.WasDisposed);
+        var exception = Record.Exception (() => Application.Shutdown ());
+        Assert.NotNull (exception);
+        Assert.False (Application.Top.WasDisposed);
+        // It's up to caller to dispose it
+        Application.Top.Dispose ();
+        Assert.True (Application.Top.WasDisposed);
+#endif
+        Assert.NotNull (Application.Top);
+
         Application.Shutdown ();
+        Assert.Null (Application.Top);
+    }
+
+    [Fact]
+    public void Run_T_Creates_Top_Without_Init ()
+    {
+        var driver = new FakeDriver ();
+
+        Assert.Null (Application.Top);
+
+        Application.Iteration += (s, e) =>
+                                 {
+                                     Assert.NotNull (Application.Top);
+                                     Application.RequestStop ();
+                                 };
+        Application.Run<Toplevel> (null, driver);
+#if DEBUG_IDISPOSABLE
+        Assert.False (Application.Top.WasDisposed);
+        var exception = Record.Exception (() => Application.Shutdown ());
+        Assert.NotNull (exception);
+        Assert.False (Application.Top.WasDisposed);
+        // It's up to caller to dispose it
+        Application.Top.Dispose ();
+        Assert.True (Application.Top.WasDisposed);
+#endif
+        Assert.NotNull (Application.Top);
+
+        Application.Shutdown ();
+        Assert.Null (Application.Top);
+    }
+
+    [Fact]
+    public void Run_t_Creates_Top_Without_Init ()
+    {
+        var driver = new FakeDriver ();
+
+        Assert.Null (Application.Top);
+
+        Application.Iteration += (s, e) =>
+                                 {
+                                     Assert.NotNull (Application.Top);
+                                     Application.RequestStop ();
+                                 };
+        Application.Run (new (), null, driver);
+#if DEBUG_IDISPOSABLE
+        Assert.False (Application.Top.WasDisposed);
+        var exception = Record.Exception (() => Application.Shutdown ());
+        Assert.NotNull (exception);
+        Assert.False (Application.Top.WasDisposed);
+        // It's up to caller to dispose it
+        Application.Top.Dispose ();
+        Assert.True (Application.Top.WasDisposed);
+#endif
+        Assert.NotNull (Application.Top);
+
+        Application.Shutdown ();
+        Assert.Null (Application.Top);
     }
 
     // TODO: Add tests for Run that test errorHandler

+ 29 - 24
UnitTests/Application/KeyboardTests.cs

@@ -20,7 +20,7 @@ public class KeyboardTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var w1 = new Window ();
         var v1 = new TextField ();
         var v2 = new TextView ();
@@ -110,6 +110,7 @@ public class KeyboardTests
         Assert.Equal (KeyCode.PageUp | KeyCode.CtrlMask, Application.AlternateBackwardKey.KeyCode);
         Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey.KeyCode);
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -118,7 +119,7 @@ public class KeyboardTests
     [AutoInitShutdown]
     public void EnsuresTopOnFront_CanFocus_False_By_Keyboard ()
     {
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var win = new Window
         {
@@ -149,35 +150,35 @@ public class KeyboardTests
         Assert.True (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.False (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
         win.CanFocus = false;
         Assert.False (win.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
         top.NewKeyDownEvent (Key.Tab.WithCtrl);
         Assert.True (win2.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
         top.NewKeyDownEvent (Key.Tab.WithCtrl);
         Assert.False (win.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
     }
 
     [Fact]
     [AutoInitShutdown]
     public void EnsuresTopOnFront_CanFocus_True_By_Keyboard_ ()
     {
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var win = new Window
         {
@@ -208,21 +209,21 @@ public class KeyboardTests
         Assert.True (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.False (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
         top.NewKeyDownEvent (Key.Tab.WithCtrl);
         Assert.True (win.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
-        Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
         top.NewKeyDownEvent (Key.Tab.WithCtrl);
         Assert.True (win.CanFocus);
         Assert.True (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.False (win2.HasFocus);
-        Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+        Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
     }
 
     [Fact]
@@ -281,18 +282,19 @@ public class KeyboardTests
 
         var keyUps = 0;
         var output = string.Empty;
+        var top = new Toplevel ();
 
-        Application.Top.KeyUp += (sender, args) =>
-                                 {
-                                     if (args.KeyCode != (KeyCode.CtrlMask | KeyCode.Q))
-                                     {
-                                         output += args.AsRune;
-                                     }
+        top.KeyUp += (sender, args) =>
+                     {
+                         if (args.KeyCode != (KeyCode.CtrlMask | KeyCode.Q))
+                         {
+                             output += args.AsRune;
+                         }
 
-                                     keyUps++;
-                                 };
+                         keyUps++;
+                     };
 
-        Application.Run (Application.Top);
+        Application.Run (top);
 
         // Input string should match output
         Assert.Equal (input, output);
@@ -306,6 +308,7 @@ public class KeyboardTests
         // # of key up events should match # of iterations
         Assert.Equal (stackSize, iterations);
 
+        top.Dispose ();
         Application.Shutdown ();
         Assert.Null (Application.Current);
         Assert.Null (Application.Top);
@@ -321,8 +324,9 @@ public class KeyboardTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnKeyDown (Key.A);
         Assert.True (invoked);
@@ -364,8 +368,9 @@ public class KeyboardTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnKeyDown (Key.A.WithCtrl);
         Assert.False (invoked);
@@ -386,7 +391,7 @@ public class KeyboardTests
     [AutoInitShutdown]
     public void QuitKey_Getter_Setter ()
     {
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var isQuiting = false;
 
         top.Closing += (s, e) =>

+ 6 - 4
UnitTests/Application/MainLoopTests.cs

@@ -625,7 +625,8 @@ public class MainLoopTests
     {
         Random r = new ();
         TextField tf = new ();
-        Application.Top.Add (tf);
+        var top = new Toplevel ();
+        top.Add (tf);
 
         const int numPasses = 5;
         const int numIncrements = 500;
@@ -634,7 +635,7 @@ public class MainLoopTests
         Task task = Task.Run (() => RunTest (r, tf, numPasses, numIncrements, pollMs));
 
         // blocks here until the RequestStop is processed at the end of the test
-        Application.Run ();
+        Application.Run (top);
 
         await task; // Propagate exception if any occurred
 
@@ -672,7 +673,8 @@ public class MainLoopTests
 
         btnLaunch.Accept += (s, e) => action ();
 
-        Application.Top.Add (btnLaunch);
+        var top = new Toplevel ();
+        top.Add (btnLaunch);
 
         int iterations = -1;
 
@@ -711,7 +713,7 @@ public class MainLoopTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.True (taskCompleted);
         Assert.Equal (clickMe, btn.Text);

+ 15 - 12
UnitTests/Application/MouseTests.cs

@@ -114,8 +114,6 @@ public class MouseTests
             Width = size.Width,
             Height = size.Height
         };
-        view.BeginInit();
-        view.EndInit();
 
         var mouseEvent = new MouseEvent { X = clickX, Y = clickY, Flags = MouseFlags.Button1Clicked };
         var mouseEventArgs = new MouseEventEventArgs (mouseEvent);
@@ -127,7 +125,10 @@ public class MouseTests
                                           clicked = true;
                                       };
 
-        Application.Top.Add (view);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
+
         Application.OnMouseEvent (mouseEventArgs);
         Assert.Equal (expectedClicked, clicked);
     }
@@ -198,11 +199,12 @@ public class MouseTests
 
         var clicked = false;
 
-        Application.Top.X = 0;
-        Application.Top.Y = 0;
-        Application.Top.Width = size.Width * 2;
-        Application.Top.Height = size.Height * 2;
-        Application.Top.BorderStyle = LineStyle.None;
+        var top = new Toplevel ();
+        top.X = 0;
+        top.Y = 0;
+        top.Width = size.Width * 2;
+        top.Height = size.Height * 2;
+        top.BorderStyle = LineStyle.None;
 
         var view = new View { X = pos.X, Y = pos.Y, Width = size.Width, Height = size.Height };
 
@@ -210,8 +212,8 @@ public class MouseTests
         view.BorderStyle = LineStyle.Single;
         view.CanFocus = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        top.Add (view);
+        Application.Begin (top);
         var mouseEvent = new MouseEvent { X = clickX, Y = clickY, Flags = MouseFlags.Button1Clicked };
         var mouseEventArgs = new MouseEventEventArgs (mouseEvent);
 
@@ -238,7 +240,8 @@ public class MouseTests
         var sv = new ScrollView { Width = Dim.Fill (), Height = Dim.Fill (), ContentSize = new (100, 100) };
 
         sv.Add (tf);
-        Application.Top.Add (sv);
+        var top = new Toplevel ();
+        top.Add (sv);
 
         int iterations = -1;
 
@@ -306,7 +309,7 @@ public class MouseTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]

+ 1 - 0
UnitTests/Application/RunStateTests.cs

@@ -33,6 +33,7 @@ public class RunStateTests
         Assert.NotNull (Application.MainLoop);
         Assert.NotNull (Application.Driver);
 
+        top.Dispose ();
         Shutdown ();
 
 #if DEBUG_IDISPOSABLE

+ 6 - 4
UnitTests/ConsoleDrivers/ConsoleDriverTests.cs

@@ -49,7 +49,7 @@ public class ConsoleDriverTests
 
         Console.MockKeyPresses = mKeys;
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var view = new View { CanFocus = true };
         var rText = "";
         var idx = 0;
@@ -72,10 +72,11 @@ public class ConsoleDriverTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.Equal ("MockKeyPresses", rText);
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -87,7 +88,7 @@ public class ConsoleDriverTests
         var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
         Application.Init (driver);
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var view = new View { CanFocus = true };
         var count = 0;
         var wasKeyPressed = false;
@@ -105,10 +106,11 @@ public class ConsoleDriverTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.False (wasKeyPressed);
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }

+ 206 - 60
UnitTests/Dialogs/DialogTests.cs

@@ -49,6 +49,7 @@ public class DialogTests
         RunIteration (ref runstate, ref first);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         dlg = new Dialog
@@ -73,6 +74,7 @@ public class DialogTests
         RunIteration (ref runstate, ref first);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         dlg = new Dialog
@@ -97,6 +99,7 @@ public class DialogTests
         RunIteration (ref runstate, ref first);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         dlg = new Dialog
@@ -121,6 +124,7 @@ public class DialogTests
         RunIteration (ref runstate, ref first);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -148,7 +152,7 @@ public class DialogTests
         d.SetBufferSize (buttonRow.Length, 3);
 
         // Default - Center
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -159,54 +163,58 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2}  {btn3}  {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
-                                                    title,
-                                                    width,
-                                                    Dialog.ButtonAlignments.Justify,
-                                                    new Button { Text = btn1Text },
-                                                    new Button { Text = btn2Text },
-                                                    new Button { Text = btn3Text },
-                                                    new Button { Text = btn4Text }
-                                                   );
+        (runstate, dlg) = RunButtonTestDialog (
+                                                      title,
+                                                      width,
+                                                      Dialog.ButtonAlignments.Justify,
+                                                      new Button { Text = btn1Text },
+                                                      new Button { Text = btn2Text },
+                                                      new Button { Text = btn3Text },
+                                                      new Button { Text = btn4Text }
+                                                     );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $"{CM.Glyphs.VLine}  {btn1} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
-                                                    title,
-                                                    width,
-                                                    Dialog.ButtonAlignments.Right,
-                                                    new Button { Text = btn1Text },
-                                                    new Button { Text = btn2Text },
-                                                    new Button { Text = btn3Text },
-                                                    new Button { Text = btn4Text }
-                                                   );
+        (runstate, dlg) = RunButtonTestDialog (
+                                                      title,
+                                                      width,
+                                                      Dialog.ButtonAlignments.Right,
+                                                      new Button { Text = btn1Text },
+                                                      new Button { Text = btn2Text },
+                                                      new Button { Text = btn3Text },
+                                                      new Button { Text = btn4Text }
+                                                     );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}  {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
-                                                    title,
-                                                    width,
-                                                    Dialog.ButtonAlignments.Left,
-                                                    new Button { Text = btn1Text },
-                                                    new Button { Text = btn2Text },
-                                                    new Button { Text = btn3Text },
-                                                    new Button { Text = btn4Text }
-                                                   );
+        (runstate, dlg) = RunButtonTestDialog (
+                                                      title,
+                                                      width,
+                                                      Dialog.ButtonAlignments.Left,
+                                                      new Button { Text = btn1Text },
+                                                      new Button { Text = btn2Text },
+                                                      new Button { Text = btn3Text },
+                                                      new Button { Text = btn4Text }
+                                                     );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -249,6 +257,7 @@ public class DialogTests
         Assert.Equal (new (width, 1), dlg.Frame.Size);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow =
@@ -268,7 +277,7 @@ public class DialogTests
                 CM.Glyphs.VLine
             }";
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -279,11 +288,12 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $"{CM.Glyphs.VLine}{CM.Glyphs.RightBracket} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}";
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -294,11 +304,12 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {CM.Glyphs.LeftBracket} n{CM.Glyphs.VLine}";
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -309,6 +320,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -338,7 +350,7 @@ public class DialogTests
         d.SetBufferSize (buttonRow.Length, 1);
 
         // Default - Center
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -349,12 +361,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow = $"{CM.Glyphs.VLine}{btn1}     {btn2}     {btn3}     {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -365,12 +378,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $"{CM.Glyphs.VLine}            {btn1} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -381,12 +395,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}            {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -397,6 +412,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -428,7 +444,7 @@ public class DialogTests
         d.SetBufferSize (width, 3);
 
         // Default - Center
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -439,12 +455,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow = $"{CM.Glyphs.VLine}{btn1}     {btn2}     {btn3}     {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.GetColumns ());
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -455,12 +472,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $"{CM.Glyphs.VLine}            {btn1} {btn2} {btn3} {btn4}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.GetColumns ());
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -471,12 +489,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $"{CM.Glyphs.VLine}{btn1} {btn2} {btn3} {btn4}            {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.GetColumns ());
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -487,6 +506,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -507,7 +527,7 @@ public class DialogTests
 
         d.SetBufferSize (width, 1);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -517,13 +537,14 @@ public class DialogTests
         // Center
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify 
         buttonRow =
             $"{CM.Glyphs.VLine}    {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -531,13 +552,14 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow =
             $"{CM.Glyphs.VLine}    {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -545,13 +567,14 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow =
             $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}    {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -559,6 +582,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Wider
         buttonRow =
@@ -567,7 +591,7 @@ public class DialogTests
 
         d.SetBufferSize (width, 1);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -575,13 +599,14 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow =
             $"{CM.Glyphs.VLine}      {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -589,13 +614,14 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow =
             $"{CM.Glyphs.VLine}      {CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -603,13 +629,14 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow =
             $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} {btnText} {CM.Glyphs.RightBracket}      {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -617,6 +644,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -642,7 +670,7 @@ public class DialogTests
 
         d.SetBufferSize (buttonRow.Length, 3);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -652,12 +680,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow = $@"{CM.Glyphs.VLine}{btn1}  {btn2}  {btn3}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -667,12 +696,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $@"{CM.Glyphs.VLine}  {btn1} {btn2} {btn3}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -682,12 +712,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $@"{CM.Glyphs.VLine}{btn1} {btn2} {btn3}  {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -697,6 +728,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -720,7 +752,7 @@ public class DialogTests
 
         d.SetBufferSize (buttonRow.Length, 3);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, Dialog dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Center,
@@ -729,12 +761,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         buttonRow = $@"{CM.Glyphs.VLine}{btn1}   {btn2}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Justify,
@@ -743,12 +776,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         buttonRow = $@"{CM.Glyphs.VLine}  {btn1} {btn2}{CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Right,
@@ -757,12 +791,13 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         buttonRow = $@"{CM.Glyphs.VLine}{btn1} {btn2}  {CM.Glyphs.VLine}";
         Assert.Equal (width, buttonRow.Length);
 
-        (runstate, Dialog _) = RunButtonTestDialog (
+        (runstate, dlg) = RunButtonTestDialog (
                                                     title,
                                                     width,
                                                     Dialog.ButtonAlignments.Left,
@@ -771,6 +806,7 @@ public class DialogTests
                                                    );
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -807,6 +843,7 @@ public class DialogTests
         buttonRow = $@"{CM.Glyphs.VLine}         {btn2} {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Justify
         Assert.Equal (width, buttonRow.Length);
@@ -818,6 +855,7 @@ public class DialogTests
         buttonRow = $@"{CM.Glyphs.VLine}          {btn2}{CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Right
         Assert.Equal (width, buttonRow.Length);
@@ -828,6 +866,7 @@ public class DialogTests
         RunIteration (ref runstate, ref firstIteration);
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
 
         // Left
         Assert.Equal (width, buttonRow.Length);
@@ -839,6 +878,7 @@ public class DialogTests
         buttonRow = $@"{CM.Glyphs.VLine}        {btn2}  {CM.Glyphs.VLine}";
         TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output);
         End (runstate);
+        dlg.Dispose ();
     }
 
     [Fact]
@@ -1087,6 +1127,7 @@ public class DialogTests
                      };
 
         Run ();
+        Top.Dispose ();
         Shutdown ();
 
         Assert.Equal (4, iterations);
@@ -1101,6 +1142,7 @@ public class DialogTests
             var fd = new FileDialog ();
             fd.Ready += (s, e) => RequestStop ();
             Run (fd);
+            fd.Dispose ();
         }
     }
 
@@ -1157,7 +1199,8 @@ public class DialogTests
     [AutoInitShutdown]
     public void Location_When_Not_Application_Top_Not_Default ()
     {
-        Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
 
         int iterations = -1;
 
@@ -1168,7 +1211,7 @@ public class DialogTests
                          if (iterations == 0)
                          {
                              var d = new Dialog { X = 5, Y = 5, Height = 3, Width = 5 };
-                             Begin (d);
+                             var rs = Begin (d);
 
                              Assert.Equal (new Point (5, 5), (Point)d.Frame.Location);
 
@@ -1186,9 +1229,11 @@ public class DialogTests
 ╚══════════════════╝",
                                                                            _output
                                                                           );
+                             End (rs);
+                             d.Dispose ();
 
                              d = new Dialog { X = 5, Y = 5 };
-                             Begin (d);
+                             rs = Begin (d);
 
                              // This is because of PostionTopLevels and EnsureVisibleBounds
                              Assert.Equal (new (3, 2), d.Frame.Location);
@@ -1224,6 +1269,8 @@ public class DialogTests
 ╚══════════════════╝",
                                                                            _output
                                                                           );
+                             End (rs);
+                             d.Dispose ();
                          }
                          else if (iterations > 0)
                          {
@@ -1231,9 +1278,8 @@ public class DialogTests
                          }
                      };
 
-        Begin (Top);
         ((FakeDriver)Driver).SetBufferSize (20, 10);
-        Run ();
+        Run (top);
     }
 
     [Fact]
@@ -1331,4 +1377,104 @@ public class DialogTests
 
         return (Begin (dlg), dlg);
     }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void Run_Does_Not_Dispose_Dialog ()
+    {
+        var top = new Toplevel ();
+
+        Dialog dlg = new ();
+
+        dlg.Ready += Dlg_Ready;
+
+        Run (dlg);
+
+#if DEBUG_IDISPOSABLE
+        Assert.False (dlg.WasDisposed);
+        Assert.False (Top.WasDisposed);
+        Assert.NotEqual (top, Top);
+        Assert.Equal (dlg, Top);
+#endif
+
+        // dlg wasn't disposed yet and it's possible to access to his properties
+        Assert.False (dlg.Canceled);
+        Assert.NotNull (dlg);
+
+        dlg.Canceled = true;
+        Assert.True (dlg.Canceled);
+
+        dlg.Dispose ();
+        top.Dispose ();
+#if DEBUG_IDISPOSABLE
+        Assert.True (dlg.WasDisposed);
+        Assert.True (Top.WasDisposed);
+        Assert.NotNull (Top);
+#endif
+        Shutdown();
+        Assert.Null (Top);
+
+        return;
+
+        void Dlg_Ready (object sender, EventArgs e)
+        {
+            RequestStop ();
+        }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void Can_Access_Cancel_Property_After_Run ()
+    {
+        Dialog dlg = new ();
+
+        dlg.Ready += Dlg_Ready;
+
+        Run (dlg);
+
+#if DEBUG_IDISPOSABLE
+        Assert.False (dlg.WasDisposed);
+        Assert.False (Top.WasDisposed);
+        Assert.Equal (dlg, Top);
+#endif
+
+        Assert.True (dlg.Canceled);
+
+        // Run it again is possible because it isn't disposed yet
+        Run (dlg);
+
+        // Run another view without dispose the prior will throw an assertion
+#if DEBUG_IDISPOSABLE
+        Dialog dlg2 = new ();
+        dlg2.Ready += Dlg_Ready;
+        var exception = Record.Exception (() => Run (dlg2));
+        Assert.NotNull (exception);
+
+        dlg.Dispose();
+        // Now it's possible to tun dlg2 without throw
+        Run (dlg2);
+
+        Assert.True (dlg.WasDisposed);
+        Assert.False (Top.WasDisposed);
+        Assert.Equal (dlg2, Top);
+        Assert.False (dlg2.WasDisposed);
+
+        dlg2.Dispose ();
+        // Now an assertion will throw accessing the Canceled property
+        exception = Record.Exception (() => Assert.True (dlg.Canceled));
+        Assert.NotNull (exception);
+        Assert.True (Top.WasDisposed);
+        Shutdown ();
+        Assert.True (dlg2.WasDisposed);
+        Assert.Null (Top);
+#endif
+
+        return;
+
+        void Dlg_Ready (object sender, EventArgs e)
+        {
+            ((Dialog)sender).Canceled = true;
+            RequestStop ();
+        }
+    }
 }

+ 15 - 30
UnitTests/Dialogs/MessageBoxTests.cs

@@ -12,8 +12,6 @@ public class MessageBoxTests
     [AutoInitShutdown]
     public void KeyBindings_Enter_Causes_Focused_Button_Click ()
     {
-        Application.Begin (Application.Top);
-
         int result = -1;
 
         var iteration = 0;
@@ -52,8 +50,6 @@ public class MessageBoxTests
     [AutoInitShutdown]
     public void KeyBindings_Esc_Closes ()
     {
-        Application.Begin (Application.Top);
-
         var result = 999;
 
         var iteration = 0;
@@ -90,8 +86,6 @@ public class MessageBoxTests
     [AutoInitShutdown]
     public void KeyBindings_Space_Causes_Focused_Button_Click ()
     {
-        Application.Begin (Application.Top);
-
         int result = -1;
 
         var iteration = 0;
@@ -131,7 +125,6 @@ public class MessageBoxTests
     public void Location_Default ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
         ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
 
         Application.Iteration += (s, a) =>
@@ -179,7 +172,6 @@ public class MessageBoxTests
     )
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
 
         Application.Iteration += (s, a) =>
                                  {
@@ -249,8 +241,8 @@ public class MessageBoxTests
     public void Message_Long_Without_Spaces_WrapMessage_True ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var btn =
@@ -325,7 +317,7 @@ public class MessageBoxTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]
@@ -333,8 +325,8 @@ public class MessageBoxTests
     public void Message_With_Spaces_WrapMessage_False ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var btn =
@@ -410,7 +402,7 @@ ffffffffffffffffffff
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]
@@ -418,8 +410,8 @@ ffffffffffffffffffff
     public void Message_With_Spaces_WrapMessage_True ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel();
+        top.BorderStyle = LineStyle.Double;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var btn =
@@ -499,7 +491,7 @@ ffffffffffffffffffff
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]
@@ -507,8 +499,8 @@ ffffffffffffffffffff
     public void Message_Without_Spaces_WrapMessage_False ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel();
+        top.BorderStyle = LineStyle.Double;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var btn =
@@ -579,7 +571,7 @@ ffffffffffffffffffff
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]
@@ -587,7 +579,6 @@ ffffffffffffffffffff
     public void Size_Default ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
         ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
 
         Application.Iteration += (s, a) =>
@@ -621,7 +612,6 @@ ffffffffffffffffffff
     public void Size_JustBigEnough_Fixed_Size ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
 
         var btn =
             $"{
@@ -672,9 +662,9 @@ ffffffffffffffffffff
     [AutoInitShutdown]
     public void Size_No_With_Button ()
     {
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
         int iterations = -1;
-        Application.Begin (Application.Top);
 
         var aboutMessage = new StringBuilder ();
         aboutMessage.AppendLine (@"0123456789012345678901234567890123456789");
@@ -728,7 +718,7 @@ ffffffffffffffffffff
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
     }
 
     [Fact]
@@ -736,7 +726,6 @@ ffffffffffffffffffff
     public void Size_None_No_Buttons ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
 
         Application.Iteration += (s, a) =>
                                  {
@@ -783,7 +772,6 @@ ffffffffffffffffffff
     public void Size_Not_Default_Message (int height, int width, string message)
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
         ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
 
         Application.Iteration += (s, a) =>
@@ -821,7 +809,6 @@ ffffffffffffffffffff
     public void Size_Not_Default_Message_Button (int height, int width, string message)
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
         ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
 
         Application.Iteration += (s, a) =>
@@ -855,7 +842,6 @@ ffffffffffffffffffff
     public void Size_Not_Default_No_Message (int height, int width)
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
         ((FakeDriver)Application.Driver).SetBufferSize (100, 100);
 
         Application.Iteration += (s, a) =>
@@ -885,7 +871,6 @@ ffffffffffffffffffff
     public void Size_Tiny_Fixed_Size ()
     {
         int iterations = -1;
-        Application.Begin (Application.Top);
 
         Application.Iteration += (s, a) =>
                                  {

+ 3 - 2
UnitTests/Drawing/LineCanvasTests.cs

@@ -1305,8 +1305,9 @@ public class LineCanvasTests
     private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0)
     {
         var v = new View { Width = 10, Height = 5, Bounds = new Rectangle (0, 0, 10, 5) };
-        Application.Top.Add (v);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (v);
+        Application.Begin (top);
 
         LineCanvas canvasCopy = canvas = new LineCanvas ();
 

+ 12 - 8
UnitTests/Drawing/RulerTests.cs

@@ -48,8 +48,9 @@ public class RulerTests
 
         // Add a frame so we can see the ruler
         var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
-        Application.Top.Add (f);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (f);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (len + 5, 5);
         Assert.Equal (new Rectangle (0, 0, len + 5, 5), f.Frame);
 
@@ -120,8 +121,9 @@ public class RulerTests
 
         // Add a frame so we can see the ruler
         var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
-        Application.Top.Add (f);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (f);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (len + 5, 5);
         Assert.Equal (new Rectangle (0, 0, len + 5, 5), f.Frame);
 
@@ -165,8 +167,9 @@ public class RulerTests
         // Add a frame so we can see the ruler
         var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
 
-        Application.Top.Add (f);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (f);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (5, len + 5);
         Assert.Equal (new Rectangle (0, 0, 5, len + 5), f.Frame);
 
@@ -297,8 +300,9 @@ public class RulerTests
         // Add a frame so we can see the ruler
         var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
 
-        Application.Top.Add (f);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (f);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (5, len + 5);
         Assert.Equal (new Rectangle (0, 0, 5, len + 5), f.Frame);
 

+ 3 - 2
UnitTests/Drawing/ThicknessTests.cs

@@ -177,8 +177,9 @@ public class ThicknessTests
         // Add a frame so we can see the ruler
         var f = new FrameView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
 
-        Application.Top.Add (f);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (f);
+        Application.Begin (top);
 
         ((FakeDriver)Application.Driver).SetBufferSize (45, 20);
         var t = new Thickness (0, 0, 0, 0);

+ 4 - 3
UnitTests/Input/EscSeqUtilsTests.cs

@@ -695,8 +695,9 @@ public class EscSeqUtilsTests
         Assert.False (_isReq);
 
         var view = new View { Width = Dim.Fill (), Height = Dim.Fill (), WantContinuousButtonPressed = true };
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnMouseEvent (
                                   new MouseEventEventArgs (
@@ -769,7 +770,7 @@ public class EscSeqUtilsTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.Null (Application.WantContinuousButtonPressedView);
 

+ 1 - 0
UnitTests/TestHelpers.cs

@@ -74,6 +74,7 @@ public class AutoInitShutdownAttribute : BeforeAfterTestAttribute
 
         if (AutoInit)
         {
+            Application.Top?.Dispose ();
             Application.Shutdown ();
 #if DEBUG_IDISPOSABLE
             if (Responder.Instances.Count == 0)

+ 2 - 2
UnitTests/Text/AutocompleteTests.cs

@@ -20,7 +20,7 @@ public class AutocompleteTests
                                 .Select (s => s.Value)
                                 .Distinct ()
                                 .ToList ();
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (tv);
         Application.Begin (top);
 
@@ -152,7 +152,7 @@ This an long line and against TextView.",
     public void KeyBindings_Command ()
     {
         var tv = new TextView { Width = 10, Height = 2, Text = " Fortunately super feature." };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (tv);
         Application.Begin (top);
 

+ 5 - 4
UnitTests/UICatalog/ScenarioTests.cs

@@ -40,7 +40,7 @@ public class ScenarioTests
             FakeConsole.PushMockKeyPress ((KeyCode)Application.QuitKey);
 
             // The only key we care about is the QuitKey
-            Application.Top.KeyDown += (sender, args) =>
+            Application.KeyDown += (sender, args) =>
                                        {
                                            _output.WriteLine ($"  Keypress: {args.KeyCode}");
 
@@ -135,7 +135,7 @@ public class ScenarioTests
 
         Application.Init (new FakeDriver ());
 
-        Toplevel Top = Application.Top;
+        Toplevel Top = new Toplevel ();
 
         _viewClasses = GetAllViewClassesCollection ()
                        .OrderBy (t => t.Name)
@@ -348,10 +348,11 @@ public class ScenarioTests
                                      }
                                  };
 
-        Application.Run ();
+        Application.Run (Top);
 
         Assert.Equal (_viewClasses.Count, iterations);
 
+        Top.Dispose ();
         Application.Shutdown ();
 
         void DimPosChanged (View view)
@@ -624,7 +625,7 @@ public class ScenarioTests
                                      }
                                  };
 
-        Application.Top.KeyDown += (sender, args) =>
+        Application.KeyDown += (sender, args) =>
                                    {
                                        // See #2474 for why this is commented out
                                        Assert.Equal (KeyCode.CtrlMask | KeyCode.Q, args.KeyCode);

+ 8 - 6
UnitTests/View/Adornment/BorderTests.cs

@@ -711,12 +711,13 @@ public class BorderTests
     [AutoInitShutdown]
     public void HasSuperView ()
     {
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
 
         var frame = new FrameView { Width = Dim.Fill (), Height = Dim.Fill () };
 
-        Application.Top.Add (frame);
-        RunState rs = Application.Begin (Application.Top);
+        top.Add (frame);
+        RunState rs = Application.Begin (top);
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver).SetBufferSize (5, 5);
@@ -737,12 +738,13 @@ public class BorderTests
     [AutoInitShutdown]
     public void HasSuperView_Title ()
     {
-        Application.Top.BorderStyle = LineStyle.Double;
+        var top = new Toplevel ();
+        top.BorderStyle = LineStyle.Double;
 
         var frame = new FrameView { Title = "1234", Width = Dim.Fill (), Height = Dim.Fill () };
 
-        Application.Top.Add (frame);
-        RunState rs = Application.Begin (Application.Top);
+        top.Add (frame);
+        RunState rs = Application.Begin (top);
         var firstIteration = false;
 
         ((FakeDriver)Application.Driver).SetBufferSize (10, 4);

+ 13 - 9
UnitTests/View/DrawTests.cs

@@ -70,7 +70,7 @@ public class DrawTests
         var view = new View { Text = r.ToString (), Height = Dim.Fill (), Width = Dim.Fill () };
         var tf = new TextField { Text = us, Y = 1, Width = 3 };
         win.Add (view, tf);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
 
         Application.Begin (top);
@@ -135,7 +135,8 @@ public class DrawTests
         };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (tv);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
         // Don't use Label. It sets AutoSize = true which is not what we're testing here.
         var view = new View { Text = "ワイドルーン。", Height = Dim.Fill (), Width = Dim.Fill () };
@@ -143,8 +144,8 @@ public class DrawTests
         // Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
         var dg = new Window { X = 2, Y = 2, Width = 14, Height = 3 };
         dg.Add (view);
-        Application.Begin (Application.Top);
-        Application.Begin (dg);
+        RunState rsTop = Application.Begin (top);
+        RunState rsDiag = Application.Begin (dg);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 10);
 
         const string expectedOutput = """
@@ -163,6 +164,9 @@ public class DrawTests
 
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expectedOutput, _output);
         Assert.Equal (new Rectangle (0, 0, 30, 10), pos);
+
+        Application.End (rsDiag);
+        Application.End (rsTop);
     }
 
     [Fact]
@@ -189,7 +193,7 @@ public class DrawTests
             VerticalTextAlignment = VerticalTextAlignment.Bottom,
             ColorScheme = Colors.ColorSchemes ["Base"]
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (viewRight, viewBottom);
 
         Application.Begin (top);
@@ -402,7 +406,7 @@ public class DrawTests
             Height = 5
         };
         container.Add (content);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (container);
         Application.Driver.Clip = container.Frame;
         Application.Begin (top);
@@ -517,7 +521,7 @@ public class DrawTests
             Height = 5
         };
         container.Add (content);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (container);
 
         // BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
@@ -604,7 +608,7 @@ public class DrawTests
             Height = 5
         };
         container.Add (content);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (container);
         Application.Driver.Clip = container.Frame;
         Application.Begin (top);
@@ -723,7 +727,7 @@ public class DrawTests
         var view = new Label { Text = r.ToString () };
         var tf = new TextField { Text = us, Y = 1, Width = 3 };
         win.Add (view, tf);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
 
         Application.Begin (top);

+ 9 - 8
UnitTests/View/Layout/DimTests.cs

@@ -28,7 +28,7 @@ public class DimTests
     [AutoInitShutdown]
     public void Dim_Add_Operator ()
     {
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { X = 0, Y = 0, Width = 20, Height = 0 };
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
@@ -102,7 +102,7 @@ public class DimTests
     [AutoInitShutdown]
     public void Dim_Subtract_Operator ()
     {
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { X = 0, Y = 0, Width = 20, Height = 0 };
         var field = new TextField { X = 0, Y = Pos.Bottom (view), Width = 20 };
@@ -386,10 +386,11 @@ public class DimTests
         };
 
         container.Add (label);
-        Application.Top.Add (container);
-        Application.Top.BeginInit ();
-        Application.Top.EndInit ();
-        Application.Top.LayoutSubviews ();
+        var top = new Toplevel ();
+        top.Add (container);
+        top.BeginInit ();
+        top.EndInit ();
+        top.LayoutSubviews ();
 
         Assert.Equal (100, container.Frame.Width);
         Assert.Equal (100, container.Frame.Height);
@@ -528,7 +529,7 @@ public class DimTests
     public void Only_DimAbsolute_And_DimFactor_As_A_Different_Procedure_For_Assigning_Value_To_Width_Or_Height ()
     {
         // Testing with the Button because it properly handles the Dim class.
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window { Width = 100, Height = 100 };
 
@@ -765,7 +766,7 @@ public class DimTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
     }
 
     [Fact]

+ 24 - 15
UnitTests/View/Layout/LayoutTests.cs

@@ -331,12 +331,13 @@ public class LayoutTests
     public void DimFill_SizedCorrectly ()
     {
         var view = new View { Width = Dim.Fill (), Height = Dim.Fill (), BorderStyle = LineStyle.Single };
-        Application.Top.Add (view);
-        RunState rs = Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        RunState rs = Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (32, 5);
 
         //view.SetNeedsLayout ();
-        Application.Top.LayoutSubviews ();
+        top.LayoutSubviews ();
 
         //view.SetRelativeLayout (new (0, 0, 32, 5));
         Assert.Equal (32, view.Frame.Width);
@@ -349,7 +350,7 @@ public class LayoutTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { X = -2, Text = "view" };
         top.Add (view);
@@ -363,7 +364,7 @@ public class LayoutTests
 
         try
         {
-            Application.Run ();
+            Application.Run (top);
         }
         catch (IndexOutOfRangeException ex)
         {
@@ -371,6 +372,7 @@ public class LayoutTests
             Assert.IsType<IndexOutOfRangeException> (ex);
         }
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -381,7 +383,7 @@ public class LayoutTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { Y = -2, Height = 10, TextDirection = TextDirection.TopBottom_LeftRight, Text = "view" };
         top.Add (view);
@@ -395,7 +397,7 @@ public class LayoutTests
 
         try
         {
-            Application.Run ();
+            Application.Run (top);
         }
         catch (IndexOutOfRangeException ex)
         {
@@ -403,6 +405,7 @@ public class LayoutTests
             Assert.IsType<IndexOutOfRangeException> (ex);
         }
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -488,7 +491,7 @@ public class LayoutTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window { X = Pos.Left (t) + 2, Y = Pos.At (2) };
 
@@ -506,7 +509,8 @@ public class LayoutTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -545,14 +549,16 @@ public class LayoutTests
     {
         Application.Init (new FakeDriver ());
 
-        var w = new Window { X = Pos.Left (Application.Top) + 2, Y = Pos.Top (Application.Top) + 2 };
+        var top = new Toplevel ();
+        var w = new Window { X = Pos.Left (top) + 2, Y = Pos.Top (top) + 2 };
         var f = new FrameView ();
         var v1 = new View { X = Pos.Left (w) + 2, Y = Pos.Top (w) + 2 };
         var v2 = new View { X = Pos.Left (v1) + 2, Y = Pos.Top (v1) + 2 };
 
         f.Add (v1, v2);
         w.Add (f);
-        Application.Top.Add (w);
+        top.Add (w);
+        Application.Begin (top);
 
         f.X = Pos.X (Application.Top) + Pos.X (v2) - Pos.X (v1);
         f.Y = Pos.Y (Application.Top) + Pos.Y (v2) - Pos.Y (v1);
@@ -574,6 +580,7 @@ public class LayoutTests
         Application.Iteration += (s, a) => Application.RequestStop ();
 
         Assert.Throws<InvalidOperationException> (() => Application.Run ());
+        top.Dispose ();
         Application.Shutdown ();
     }
 
@@ -634,8 +641,9 @@ public class LayoutTests
         Assert.Equal (10, rHeight);
         Assert.False (v.IsInitialized);
 
-        Application.Top.Add (top);
-        Application.Begin (Application.Top);
+        var toplevel = new Toplevel ();
+        toplevel.Add (top);
+        Application.Begin (toplevel);
 
         Assert.True (v.IsInitialized);
 
@@ -665,8 +673,9 @@ public class LayoutTests
         Assert.Equal (70, rWidth);
         Assert.False (v.IsInitialized);
 
-        Application.Top.Add (top);
-        Application.Begin (Application.Top);
+        var toplevel = new Toplevel ();
+        toplevel.Add (top);
+        Application.Begin (toplevel);
 
         Assert.True (v.IsInitialized);
         v.Width = 75;

+ 27 - 20
UnitTests/View/Layout/PosTests.cs

@@ -43,7 +43,7 @@ public class PosTests
 
         win.Add (tv);
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
         RunState rs = Application.Begin (top);
 
@@ -73,7 +73,7 @@ public class PosTests
 
         var menu = new MenuBar ();
         var status = new StatusBar ();
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win, menu, status);
         RunState rs = Application.Begin (top);
 
@@ -317,17 +317,18 @@ public class PosTests
     public void LeftTopBottomRight_Win_ShouldNotThrow ()
     {
         // Setup Fake driver
-        (Window win, Button button) setup ()
+        (Toplevel top, Window win, Button button) setup ()
         {
             Application.Init (new FakeDriver ());
             Application.Iteration += (s, a) => { Application.RequestStop (); };
             var win = new Window { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
-            Application.Top.Add (win);
+            var top = new Toplevel ();
+            top.Add (win);
 
             var button = new Button { X = Pos.Center (), Text = "button" };
             win.Add (button);
 
-            return (win, button);
+            return (top, win, button);
         }
 
         RunState rs;
@@ -337,14 +338,15 @@ public class PosTests
             // Cleanup
             Application.End (rs);
 
+            Application.Top.Dispose ();
             // Shutdown must be called to safely clean up Application if Init has been called
             Application.Shutdown ();
         }
 
         // Test cases:
-        (Window win, Button button) app = setup ();
+        (Toplevel top, Window win, Button button) app = setup ();
         app.button.Y = Pos.Left (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -352,7 +354,7 @@ public class PosTests
 
         app = setup ();
         app.button.Y = Pos.X (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -360,7 +362,7 @@ public class PosTests
 
         app = setup ();
         app.button.Y = Pos.Top (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -368,7 +370,7 @@ public class PosTests
 
         app = setup ();
         app.button.Y = Pos.Y (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -376,7 +378,7 @@ public class PosTests
 
         app = setup ();
         app.button.Y = Pos.Bottom (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -384,7 +386,7 @@ public class PosTests
 
         app = setup ();
         app.button.Y = Pos.Right (app.win);
-        rs = Application.Begin (Application.Top);
+        rs = Application.Begin (app.top);
 
         // If Application.RunState is used then we must use Application.RunLoop with the rs parameter
         Application.RunLoop (rs);
@@ -467,7 +469,7 @@ public class PosTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
         var field = new TextField { X = 0, Y = 0, Width = 20 };
@@ -510,6 +512,7 @@ public class PosTests
 
         Assert.Equal (20, count);
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -522,7 +525,7 @@ public class PosTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         var view = new View { X = 0, Y = 0, Width = 20, Height = 20 };
         var field = new TextField { X = 0, Y = 0, Width = 20 };
@@ -578,6 +581,7 @@ public class PosTests
 
         Assert.Equal (0, count);
 
+        top.Dispose ();
         // Shutdown must be called to safely clean up Application if Init has been called
         Application.Shutdown ();
     }
@@ -589,7 +593,7 @@ public class PosTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window { X = 1, Y = 2, Width = 3, Height = 5 };
         t.Add (w);
@@ -602,7 +606,8 @@ public class PosTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -637,7 +642,7 @@ public class PosTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window { X = Pos.Left (t) + 2, Y = Pos.Top (t) + 2 };
         var f = new FrameView ();
@@ -651,7 +656,8 @@ public class PosTests
         f.X = Pos.X (v2) - Pos.X (v1);
         f.Y = Pos.Y (v2) - Pos.Y (v1);
 
-        Assert.Throws<InvalidOperationException> (() => Application.Run ());
+        Assert.Throws<InvalidOperationException> (() => Application.Run (t));
+        t.Dispose ();
         Application.Shutdown ();
 
         v2.Dispose ();
@@ -676,8 +682,9 @@ public class PosTests
         };
 
         container.Add (view);
-        Application.Top.Add (container);
-        Application.Top.LayoutSubviews ();
+        var top = new Toplevel ();
+        top.Add (container);
+        top.LayoutSubviews ();
 
         Assert.Equal (100, container.Frame.Width);
         Assert.Equal (100, container.Frame.Height);

+ 3 - 1
UnitTests/View/MouseTests.cs

@@ -68,7 +68,9 @@ public class MouseTests (ITestOutputHelper output)
         testView.Border.Thickness = new (borderThickness);
         testView.Padding.Thickness = new (paddingThickness);
 
-        Application.Top.Add (testView);
+        var top = new Toplevel ();
+        top.Add (testView);
+        Application.Begin (top);
 
         Assert.Equal (new Point (4, 4), testView.Frame.Location);
         Application.OnMouseEvent (new (new () { X = xy, Y = xy, Flags = MouseFlags.Button1Pressed }));

+ 58 - 45
UnitTests/View/NavigationTests.cs

@@ -57,7 +57,7 @@ public class NavigationTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window ();
         var f = new FrameView ();
@@ -84,7 +84,8 @@ public class NavigationTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -93,7 +94,7 @@ public class NavigationTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window ();
         var f = new FrameView ();
@@ -126,7 +127,8 @@ public class NavigationTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -166,7 +168,7 @@ public class NavigationTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window ();
         var f = new FrameView ();
@@ -201,7 +203,8 @@ public class NavigationTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -210,7 +213,7 @@ public class NavigationTests
     {
         Application.Init (new FakeDriver ());
 
-        Toplevel t = Application.Top;
+        Toplevel t = new ();
 
         var w = new Window ();
         var f = new FrameView ();
@@ -238,7 +241,8 @@ public class NavigationTests
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
     }
 
@@ -292,8 +296,9 @@ public class NavigationTests
         var view = new View { CanFocus = true };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (view);
-        Application.Top.Add (win);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (win);
+        Application.Begin (top);
 
         Assert.True (view.CanFocus);
         Assert.True (view.HasFocus);
@@ -315,21 +320,22 @@ public class NavigationTests
         var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
         var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
         win2.Add (view2);
-        Application.Top.Add (win1, win2);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
 
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
         Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab));
+        Assert.True (top.NewKeyDownEvent (Key.Tab));
         Assert.True (view1.CanFocus);
         Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
         Assert.True (view2.CanFocus);
         Assert.True (view2.HasFocus);
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab));
+        Assert.True (top.NewKeyDownEvent (Key.Tab));
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
@@ -354,21 +360,22 @@ public class NavigationTests
         var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
         var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
         win2.Add (view2);
-        Application.Top.Add (win1, win2);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
 
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
         Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab.WithCtrl));
+        Assert.True (top.NewKeyDownEvent (Key.Tab.WithCtrl));
         Assert.True (view1.CanFocus);
         Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
         Assert.True (view2.CanFocus);
         Assert.True (view2.HasFocus);
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab.WithCtrl));
+        Assert.True (top.NewKeyDownEvent (Key.Tab.WithCtrl));
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
@@ -404,22 +411,23 @@ public class NavigationTests
         var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
         var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
         win2.Add (view2);
-        Application.Top.Add (win1, win2);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
 
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
         Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab.WithCtrl));
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab.WithCtrl));
+        Assert.True (top.NewKeyDownEvent (Key.Tab.WithCtrl));
+        Assert.True (top.NewKeyDownEvent (Key.Tab.WithCtrl));
         Assert.True (view1.CanFocus);
         Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
         Assert.True (view2.CanFocus);
         Assert.True (view2.HasFocus);
 
-        Assert.True (Application.Top.NewKeyDownEvent (Key.Tab.WithCtrl));
+        Assert.True (top.NewKeyDownEvent (Key.Tab.WithCtrl));
         Assert.True (view1.CanFocus);
         Assert.True (view1.HasFocus);
         Assert.True (view2.CanFocus);
@@ -441,7 +449,6 @@ public class NavigationTests
         var wasClicked = false;
         var view = new Button { Text = "Click Me" };
         view.Accept += (s, e) => wasClicked = !wasClicked;
-        Application.Top.Add (view);
 
         view.NewKeyDownEvent (Key.Space);
         Assert.True (wasClicked);
@@ -473,7 +480,8 @@ public class NavigationTests
         button.Accept += (s, e) => wasClicked = !wasClicked;
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (button);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
         var iterations = 0;
 
@@ -518,7 +526,7 @@ public class NavigationTests
                                      Application.RequestStop ();
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.Equal (1, iterations);
     }
@@ -556,7 +564,7 @@ public class NavigationTests
     [AutoInitShutdown]
     public void FocusNext_Does_Not_Throws_If_A_View_Was_Removed_From_The_Collection ()
     {
-        Toplevel top1 = Application.Top;
+        Toplevel top1 = new ();
         var view1 = new View { Id = "view1", Width = 10, Height = 5, CanFocus = true };
         var top2 = new Toplevel { Id = "top2", Y = 1, Width = 10, Height = 5 };
 
@@ -644,7 +652,7 @@ public class NavigationTests
 
         var win = new Window ();
         win.Add (sb, tf);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.KeyDown += Top_KeyPress;
 
         void Top_KeyPress (object sender, Key obj)
@@ -718,7 +726,7 @@ public class NavigationTests
 
         var win = new Window ();
         win.Add (sb, tf);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
         Application.Begin (top);
 
@@ -746,14 +754,16 @@ public class NavigationTests
 
         Application.Init (new FakeDriver ());
 
-        Application.Top.Ready += (s, e) => { Assert.Null (Application.Top.Focused); };
+        var top = new Toplevel ();
+        top.Ready += (s, e) => { Assert.Null (top.Focused); };
 
         // Keyboard navigation with tab
         Console.MockKeyPresses.Push (new ConsoleKeyInfo ('\t', ConsoleKey.Tab, false, false, false));
 
         Application.Iteration += (s, a) => Application.RequestStop ();
 
-        Application.Run ();
+        Application.Run (top);
+        top.Dispose ();
         Application.Shutdown ();
     }
 
@@ -761,8 +771,9 @@ public class NavigationTests
     [AutoInitShutdown]
     public void Remove_Does_Not_Change_Focus ()
     {
-        Assert.True (Application.Top.CanFocus);
-        Assert.False (Application.Top.HasFocus);
+        var top = new Toplevel ();
+        Assert.True (top.CanFocus);
+        Assert.False (top.HasFocus);
 
         var container = new View { Width = 10, Height = 10 };
         var leave = false;
@@ -776,11 +787,11 @@ public class NavigationTests
         Assert.True (child.CanFocus);
         Assert.False (child.HasFocus);
 
-        Application.Top.Add (container);
-        Application.Begin (Application.Top);
+        top.Add (container);
+        Application.Begin (top);
 
-        Assert.True (Application.Top.CanFocus);
-        Assert.True (Application.Top.HasFocus);
+        Assert.True (top.CanFocus);
+        Assert.True (top.HasFocus);
         Assert.True (container.CanFocus);
         Assert.True (container.HasFocus);
         Assert.True (child.CanFocus);
@@ -789,7 +800,7 @@ public class NavigationTests
         container.Remove (child);
         child.Dispose ();
         child = null;
-        Assert.True (Application.Top.HasFocus);
+        Assert.True (top.HasFocus);
         Assert.True (container.CanFocus);
         Assert.True (container.HasFocus);
         Assert.Null (child);
@@ -800,7 +811,7 @@ public class NavigationTests
     [AutoInitShutdown]
     public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top ()
     {
-        Toplevel top = Application.Current;
+        Toplevel top = new ();
         top.BorderStyle = LineStyle.Single;
 
         var view = new View
@@ -1120,13 +1131,14 @@ public class NavigationTests
     [AutoInitShutdown]
     public void SetFocus_View_With_Null_Superview_Does_Not_Throw_Exception ()
     {
-        Assert.True (Application.Top.CanFocus);
-        Assert.False (Application.Top.HasFocus);
+        var top = new Toplevel ();
+        Assert.True (top.CanFocus);
+        Assert.False (top.HasFocus);
 
-        Exception exception = Record.Exception (Application.Top.SetFocus);
+        Exception exception = Record.Exception (top.SetFocus);
         Assert.Null (exception);
-        Assert.True (Application.Top.CanFocus);
-        Assert.True (Application.Top.HasFocus);
+        Assert.True (top.CanFocus);
+        Assert.True (top.HasFocus);
     }
 
     [Fact]
@@ -1136,7 +1148,7 @@ public class NavigationTests
         var view1Leave = false;
         var subView1Leave = false;
         var subView1subView1Leave = false;
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         var view1 = new View { CanFocus = true };
         var subView1 = new View { CanFocus = true };
         var subView1subView1 = new View { CanFocus = true };
@@ -1459,6 +1471,7 @@ public class NavigationTests
         // Act
         RunState rs = Application.Begin (top);
         Application.End (rs);
+        top.Dispose ();
         Application.Shutdown ();
 
         // Assert does Not throw NullReferenceException

+ 2 - 0
UnitTests/View/SubviewTests.cs

@@ -206,6 +206,7 @@ public class SubviewTests
                                  };
 
         Application.Run (top);
+        top.Dispose ();
         Application.Shutdown ();
 
         Assert.Equal (1, tc);
@@ -301,6 +302,7 @@ public class SubviewTests
                                  };
 
         Application.Run (t);
+        t.Dispose ();
         Application.Shutdown ();
 
         Assert.Equal (1, tc);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 410 - 398
UnitTests/View/Text/AutoSizeTrueTests.cs


+ 12 - 8
UnitTests/View/ViewKeyBindingTests.cs

@@ -15,8 +15,9 @@ public class ViewKeyBindingTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnKeyDown (Key.A);
         Assert.True (invoked);
@@ -51,8 +52,9 @@ public class ViewKeyBindingTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnKeyDown (Key.Z);
         Assert.False (invoked);
@@ -77,8 +79,9 @@ public class ViewKeyBindingTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         invoked = false;
         Application.OnKeyDown (Key.H);
@@ -105,8 +108,9 @@ public class ViewKeyBindingTests
         var invoked = false;
         view.InvokingKeyBindings += (s, e) => invoked = true;
 
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
 
         Application.OnKeyDown (Key.Z);
         Assert.False (invoked);

+ 24 - 20
UnitTests/View/ViewTests.cs

@@ -33,8 +33,9 @@ public class ViewTests
                                 Application.Driver.Clip = savedClip;
                                 e.Cancel = true;
                             };
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var expected = @"
@@ -95,8 +96,9 @@ public class ViewTests
                                 Application.Driver.Clip = savedClip;
                                 e.Cancel = true;
                             };
-        Application.Top.Add (view);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (view);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
         var expected = @"
@@ -147,8 +149,9 @@ public class ViewTests
 
         root.Add (v);
 
-        Application.Top.Add (root);
-        RunState runState = Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (root);
+        RunState runState = Application.Begin (top);
 
         if (label)
         {
@@ -232,7 +235,7 @@ cccccccccccccccccccc",
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -277,7 +280,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -326,7 +329,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -371,7 +374,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -435,8 +438,9 @@ At 0,0
         var tv = new TextView { Y = 11, Width = 10, Height = 10 };
         tv.DrawContentComplete += (s, e) => tvCalled = true;
 
-        Application.Top.Add (view, tv);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+       top.Add (view, tv);
+        Application.Begin (top);
 
         Assert.True (viewCalled);
         Assert.True (tvCalled);
@@ -467,7 +471,7 @@ At 0,0
         frame.Width = 40;
         frame.Height = 8;
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
 
         top.Add (frame);
 
@@ -539,7 +543,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -584,7 +588,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -633,7 +637,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -680,7 +684,7 @@ At 0,0
             Height = 2,
             Text = "A text with some long width\n and also with two lines."
         };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (label, view);
         RunState runState = Application.Begin (top);
 
@@ -999,7 +1003,7 @@ At 0,0
         Assert.Equal (0, view.Height);
         var win = new Window ();
         win.Add (view);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
         RunState rs = Application.Begin (top);
 
@@ -1044,7 +1048,7 @@ At 0,0
         var button = new Button { Text = "Click Me" };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (button);
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (win);
 
         var iterations = 0;
@@ -1087,7 +1091,7 @@ At 0,0
                                      Application.RequestStop ();
                                  };
 
-        Application.Run ();
+        Application.Run (top);
 
         Assert.Equal (1, iterations);
 

+ 4 - 1
UnitTests/Views/AllViewsTests.cs

@@ -64,12 +64,13 @@ public class AllViewsTests (ITestOutputHelper output)
 
             Application.Init (new FakeDriver ());
 
-            Toplevel top = Application.Top;
+            Toplevel top = new ();
             View vType = CreateViewFromType (type, type.GetConstructor (Array.Empty<Type> ()));
 
             if (vType == null)
             {
                 output.WriteLine ($"Ignoring {type} - It's a Generic");
+                top.Dispose ();
                 Application.Shutdown ();
 
                 continue;
@@ -104,6 +105,7 @@ public class AllViewsTests (ITestOutputHelper output)
 
             if (!vType.CanFocus || (vType is Toplevel && ((Toplevel)vType).Modal))
             {
+                top.Dispose ();
                 Application.Shutdown ();
 
                 continue;
@@ -132,6 +134,7 @@ public class AllViewsTests (ITestOutputHelper output)
             Assert.Equal (1, viewEnter);
             Assert.Equal (1, viewLeave);
 
+            top.Dispose ();
             Application.Shutdown ();
         }
     }

+ 1 - 1
UnitTests/Views/AppendAutocompleteTests.cs

@@ -227,7 +227,7 @@ public class AppendAutocompleteTests
         var tf = new TextField { Width = 10 };
         var tf2 = new TextField { Y = 1, Width = 10 };
 
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (tf);
         top.Add (tf2);
 

+ 27 - 31
UnitTests/Views/ButtonTests.cs

@@ -113,9 +113,10 @@ public class ButtonTests
         tab.Height = btnFindNext.Height + btnFindPrevious.Height + btnCancel.Height + 4;
 
         win.Add (tabView);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (54, 11);
 
         Assert.Equal (new Rectangle (0, 0, 54, 11), win.Frame);
@@ -185,12 +186,12 @@ public class ButtonTests
 
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (btn);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Assert.True (btn.AutoSize);
         Assert.True (btn.AutoSize);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         var expected = @$"
@@ -232,12 +233,12 @@ public class ButtonTests
 
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (btn);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Assert.True (btn.AutoSize);
         Assert.True (btn.AutoSize);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         var expected = @$"
@@ -282,18 +283,16 @@ public class ButtonTests
 
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (btn);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+       top.Add (win);
 
-        Assert.True (btn.AutoSize);
         Assert.True (btn.AutoSize);
 
-        btn.Text = "Say Hello 你";
         btn.Text = "Say Hello 你";
 
-        Assert.True (btn.AutoSize);
         Assert.True (btn.AutoSize);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         var expected = @$"
@@ -532,8 +531,9 @@ public class ButtonTests
         var clicked = false;
         var btn = new Button { Text = "_Test" };
         btn.Accept += (s, e) => clicked = true;
-        Application.Top.Add (btn);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (btn);
+        Application.Begin (top);
 
         Assert.Equal (KeyCode.T, btn.HotKey);
         Assert.True (btn.NewKeyDownEvent (Key.T));
@@ -566,10 +566,9 @@ public class ButtonTests
         Assert.Contains (Command.HotKey, btn.GetSupportedCommands ());
         Assert.Contains (Command.Accept, btn.GetSupportedCommands ());
 
-        Application.Top.Add (btn);
-        Application.Begin (Application.Top);
-        Application.Top.Add (btn);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (btn);
+        Application.Begin (top);
 
         // default keybinding is Space which results in keypress
         Application.OnKeyDown (new Key ((KeyCode)' '));
@@ -611,8 +610,9 @@ public class ButtonTests
         var clicked = false;
         var btn = new Button { Text = "_Test" };
         btn.Accept += (s, e) => clicked = true;
-        Application.Top.Add (btn);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (btn);
+        Application.Begin (top);
 
         // Hot key. Both alone and with alt
         Assert.Equal (KeyCode.T, btn.HotKey);
@@ -749,14 +749,12 @@ public class ButtonTests
         var btn = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Say Hello 你" };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (btn);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Assert.False (btn.IsInitialized);
         Assert.False (btn.IsInitialized);
 
-        Application.Begin (Application.Top);
-        ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.True (btn.IsInitialized);
@@ -786,14 +784,12 @@ public class ButtonTests
         var btn = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Say Hello 你" };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
         win.Add (btn);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Assert.False (btn.IsInitialized);
         Assert.False (btn.IsInitialized);
 
-        Application.Begin (Application.Top);
-        ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.True (btn.IsInitialized);

+ 22 - 15
UnitTests/Views/CheckBoxTests.cs

@@ -40,7 +40,7 @@ public class CheckBoxTests
     public void AllowNullChecked_Get_Set ()
     {
         var checkBox = new CheckBox { Text = "Check this out 你" };
-        Toplevel top = Application.Top;
+        Toplevel top = new ();
         top.Add (checkBox);
         Application.Begin (top);
 
@@ -81,11 +81,12 @@ public class CheckBoxTests
 
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
         Assert.True (checkBox.AutoSize);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         var expected = @$"
@@ -124,11 +125,12 @@ public class CheckBoxTests
 
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
         Assert.True (checkBox.AutoSize);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         var expected = @$"
@@ -164,11 +166,12 @@ public class CheckBoxTests
         var checkBox = new CheckBox { X = 1, Y = Pos.Center (), Text = "Check this out 你" };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
         Assert.False (checkBox.IsInitialized);
 
-        RunState runstate = Application.Begin (Application.Top);
+        RunState runstate = Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.True (checkBox.IsInitialized);
@@ -355,9 +358,10 @@ public class CheckBoxTests
         };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.Equal (TextAlignment.Centered, checkBox.TextAlignment);
@@ -416,9 +420,10 @@ public class CheckBoxTests
         };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox1, checkBox2);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 6);
 
         Assert.Equal (TextAlignment.Justified, checkBox1.TextAlignment);
@@ -475,9 +480,10 @@ public class CheckBoxTests
         };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.Equal (TextAlignment.Left, checkBox.TextAlignment);
@@ -525,9 +531,10 @@ public class CheckBoxTests
         };
         var win = new Window { Width = Dim.Fill (), Height = Dim.Fill (), Title = "Test Demo 你" };
         win.Add (checkBox);
-        Application.Top.Add (win);
+        var top = new Toplevel ();
+        top.Add (win);
 
-        Application.Begin (Application.Top);
+        Application.Begin (top);
         ((FakeDriver)Application.Driver).SetBufferSize (30, 5);
 
         Assert.Equal (TextAlignment.Right, checkBox.TextAlignment);

+ 3 - 2
UnitTests/Views/ColorPickerTests.cs

@@ -48,8 +48,9 @@ public class ColorPickerTests
     {
         var colorPicker = new ColorPicker { X = 0, Y = 0, Height = 4, Width = 32 };
         Assert.Equal (ColorName.Black, colorPicker.SelectedColor);
-        Application.Top.Add (colorPicker);
-        Application.Begin (Application.Top);
+        var top = new Toplevel ();
+        top.Add (colorPicker);
+        Application.Begin (top);
 
         Assert.False (colorPicker.OnMouseEvent (new MouseEvent ()));
 

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác