Browse Source

Remove Top from the Init method.

BDisp 1 year ago
parent
commit
c68849a314
2 changed files with 73 additions and 50 deletions
  1. 13 46
      Terminal.Gui/Application.cs
  2. 60 4
      UnitTests/Application/ApplicationTests.cs

+ 13 - 46
Terminal.Gui/Application.cs

@@ -179,7 +179,7 @@ public static partial class Application
     ///     <see cref="ConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are
     ///     <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.
     ///     specified the default driver for the platform will be used.
     /// </param>
     /// </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 bool _initialized;
     internal static int _mainThreadId = -1;
     internal static int _mainThreadId = -1;
@@ -194,7 +194,6 @@ public static partial class Application
     // 
     // 
     // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
     // calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
     internal static void InternalInit (
     internal static void InternalInit (
-        Func<Toplevel> topLevelFactory,
         ConsoleDriver driver = null,
         ConsoleDriver driver = null,
         string driverName = null,
         string driverName = null,
         bool calledViaRunT = false
         bool calledViaRunT = false
@@ -292,13 +291,6 @@ public static partial class Application
 
 
         SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
         SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
 
 
-        Top = topLevelFactory ();
-        Current = Top;
-        _initialTop = Top;
-
-        // Ensure Top's layout is up to date.
-        Current.SetRelativeLayout (Driver.Bounds);
-
         SupportedCultures = GetSupportedCultures ();
         SupportedCultures = GetSupportedCultures ();
         _mainThreadId = Thread.CurrentThread.ManagedThreadId;
         _mainThreadId = Thread.CurrentThread.ManagedThreadId;
         _initialized = true;
         _initialized = true;
@@ -346,8 +338,6 @@ public static partial class Application
 
 
     #region Run (Begin, Run, End, Stop)
     #region Run (Begin, Run, End, Stop)
 
 
-    private static Toplevel _initialTop;
-
     /// <summary>
     /// <summary>
     ///     Notify that a new <see cref="RunState"/> was created (<see cref="Begin(Toplevel)"/> was called). The token is
     ///     Notify that a new <see cref="RunState"/> was created (<see cref="Begin(Toplevel)"/> was called). The token is
     ///     created in <see cref="Begin(Toplevel)"/> and this event will be fired before that function exits.
     ///     created in <see cref="Begin(Toplevel)"/> and this event will be fired before that function exits.
@@ -523,7 +513,7 @@ public static partial class Application
     ///     <see cref="Top"/>.
     ///     <see cref="Top"/>.
     /// </summary>
     /// </summary>
     /// <remarks>See <see cref="Run(Toplevel, Func{Exception, bool})"/> for more details.</remarks>
     /// <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); }
+    public static void Run (Func<Exception, bool> errorHandler = null) { Run<Toplevel> (errorHandler);}
 
 
     /// <summary>
     /// <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})"/> with a new instance of the
@@ -544,35 +534,16 @@ public static partial class Application
     public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
     public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null)
         where T : Toplevel, new()
         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");
-                }
+        if (top is null)
+        {
+            throw new ArgumentException ($"{top.GetType ().Name} must be derived from TopLevel");
+        }
 
 
-                Run (top, errorHandler);
-            }
-            else
+        if (_initialized)
+        {
+            if (Driver is null)
             {
             {
                 // This code path should be impossible because Init(null, null) will select the platform default driver
                 // This code path should be impossible because Init(null, null) will select the platform default driver
                 throw new InvalidOperationException (
                 throw new InvalidOperationException (
@@ -583,9 +554,10 @@ public static partial class Application
         else
         else
         {
         {
             // Init() has NOT been called.
             // Init() has NOT been called.
-            InternalInit (() => new T (), driver, null, true);
-            Run (Top, errorHandler);
+            InternalInit (driver, null, true);
         }
         }
+
+        Run (top, errorHandler);
     }
     }
 
 
     /// <summary>Runs the main loop on the given <see cref="Toplevel"/> container.</summary>
     /// <summary>Runs the main loop on the given <see cref="Toplevel"/> container.</summary>
@@ -1049,11 +1021,6 @@ public static partial class Application
         runState.Toplevel?.Dispose ();
         runState.Toplevel?.Dispose ();
         runState.Toplevel = null;
         runState.Toplevel = null;
         runState.Dispose ();
         runState.Dispose ();
-
-        if (_topLevels.Count == 0)
-        {
-            Top = _initialTop;
-        }
     }
     }
 
 
     #endregion Run (Begin, Run, End)
     #endregion Run (Begin, Run, End)

+ 60 - 4
UnitTests/Application/ApplicationTests.cs

@@ -265,7 +265,6 @@ public class ApplicationTests
         Assert.Throws<InvalidOperationException> (
         Assert.Throws<InvalidOperationException> (
                                                   () =>
                                                   () =>
                                                       Application.InternalInit (
                                                       Application.InternalInit (
-                                                                                () => topLevel = new TestToplevel (),
                                                                                 new FakeDriver ()
                                                                                 new FakeDriver ()
                                                                                )
                                                                                )
                                                  );
                                                  );
@@ -277,7 +276,7 @@ public class ApplicationTests
 
 
         // Now try the other way
         // Now try the other way
         topLevel = null;
         topLevel = null;
-        Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
+        Application.InternalInit (new FakeDriver ());
 
 
         Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver ()));
         Assert.Throws<InvalidOperationException> (() => Application.Init (new FakeDriver ()));
         Shutdown ();
         Shutdown ();
@@ -297,7 +296,7 @@ public class ApplicationTests
         // NOTE: Run<T>, when called after Init has been called behaves differently than
         // NOTE: Run<T>, when called after Init has been called behaves differently than
         // when called if Init has not been called.
         // when called if Init has not been called.
         Toplevel topLevel = null;
         Toplevel topLevel = null;
-        Application.InternalInit (() => topLevel = new TestToplevel (), new FakeDriver ());
+        Application.InternalInit (new FakeDriver ());
 
 
         RunState runstate = null;
         RunState runstate = null;
 
 
@@ -911,9 +910,66 @@ public class ApplicationTests
         Application.Shutdown ();
         Application.Shutdown ();
         Assert.NotNull (w);
         Assert.NotNull (w);
         Assert.Equal (string.Empty, w.Title); // Invalid - w has been disposed -> Valid - w isn't Application.Top but the original created by Init
         Assert.Equal (string.Empty, w.Title); // Invalid - w has been disposed -> Valid - w isn't Application.Top but the original created by Init
-        Assert.Null (Application.Top);
         Assert.Null (Application.Current);
         Assert.Null (Application.Current);
         Assert.NotNull (top);
         Assert.NotNull (top);
+        Assert.Null (Application.Top);
+    }
+
+    [Fact]
+    public void Run_Creates_Top_With_Init ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Assert.Null (Application.Top);
+
+        Application.Iteration += (s, e) =>
+                                 {
+                                     Assert.NotNull (Application.Top);
+                                     Application.RequestStop ();
+                                 };
+        Application.Run ();
+        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);
+        Assert.NotNull (Application.Top);
+
+        Application.Shutdown ();
+        Assert.Null (Application.Top);
+    }
+
+    [Fact]
+    public void Run_t_Creates_Top_With_Init ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Assert.Null (Application.Top);
+
+        Application.Iteration += (s, e) =>
+                                 {
+                                     Assert.NotNull (Application.Top);
+                                     Application.RequestStop ();
+                                 };
+        Application.Run (new Toplevel ());
+        Assert.NotNull (Application.Top);
+
+        Application.Shutdown ();
+        Assert.Null (Application.Top);
     }
     }
 
 
     // TODO: Add tests for Run that test errorHandler
     // TODO: Add tests for Run that test errorHandler