Skip to content

Commit

Permalink
Merge pull request #553 from BDisp/driver-shutdown
Browse files Browse the repository at this point in the history
Fixes #515, #518 and #536.
  • Loading branch information
tig authored May 27, 2020
2 parents bfd62de + d629d5b commit 353baf7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 42 deletions.
80 changes: 44 additions & 36 deletions Terminal.Gui/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2125,23 +2125,25 @@ static void Init (Func<Toplevel> topLevelFactory)
{
if (_initialized) return;

var p = Environment.OSVersion.Platform;
Mono.Terminal.IMainLoopDriver mainLoopDriver;

if (UseSystemConsole) {
mainLoopDriver = new Mono.Terminal.NetMainLoop ();
Driver = new NetDriver ();
} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
var windowsDriver = new WindowsDriver ();
mainLoopDriver = windowsDriver;
Driver = windowsDriver;
} else {
mainLoopDriver = new Mono.Terminal.UnixMainLoop ();
Driver = new CursesDriver ();
if (Driver == null) {
var p = Environment.OSVersion.Platform;
Mono.Terminal.IMainLoopDriver mainLoopDriver;

if (UseSystemConsole) {
mainLoopDriver = new Mono.Terminal.NetMainLoop ();
Driver = new NetDriver ();
} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
var windowsDriver = new WindowsDriver ();
mainLoopDriver = windowsDriver;
Driver = windowsDriver;
} else {
mainLoopDriver = new Mono.Terminal.UnixMainLoop ();
Driver = new CursesDriver ();
}
Driver.Init (TerminalResized);
MainLoop = new Mono.Terminal.MainLoop (mainLoopDriver);
SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
}
Driver.Init (TerminalResized);
MainLoop = new Mono.Terminal.MainLoop (mainLoopDriver);
SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
Top = topLevelFactory ();
Current = Top;
CurrentView = Top;
Expand All @@ -2152,6 +2154,8 @@ static void Init (Func<Toplevel> topLevelFactory)
/// Captures the execution state for the provided <see cref="Toplevel"/> view.
/// </summary>
public class RunState : IDisposable {
internal bool closeDriver = true;

internal RunState (Toplevel view)
{
Toplevel = view;
Expand All @@ -2168,7 +2172,7 @@ internal RunState (Toplevel view)
/// <see cref="Application.RunState"/> was occupying.</remarks>
public void Dispose ()
{
Dispose (true);
Dispose (closeDriver);
GC.SuppressFinalize (this);
}

Expand All @@ -2180,7 +2184,7 @@ public void Dispose ()
protected virtual void Dispose (bool disposing)
{
if (Toplevel != null) {
End (Toplevel);
End (Toplevel, disposing);
Toplevel = null;
}
}
Expand Down Expand Up @@ -2373,14 +2377,14 @@ static bool OutsideFrame (Point p, Rect r)
/// <summary>
/// Building block API: Prepares the provided <see cref="Toplevel"/> for execution.
/// </summary>
/// <returns>The runstate handle that needs to be passed to the <see cref="End(RunState)"/> method upon completion.</returns>
/// <returns>The runstate handle that needs to be passed to the <see cref="End(RunState, bool)"/> method upon completion.</returns>
/// <param name="toplevel">Toplevel to prepare execution for.</param>
/// <remarks>
/// This method prepares the provided toplevel for running with the focus,
/// it adds this to the list of toplevels, sets up the mainloop to process the
/// event, lays out the subviews, focuses the first element, and draws the
/// 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
/// the <see cref="RunLoop"/> method, and then the <see cref="End(RunState, bool)"/> method upon termination which will
/// undo these changes.
/// </remarks>
public static RunState Begin (Toplevel toplevel)
Expand Down Expand Up @@ -2417,19 +2421,21 @@ public static RunState Begin (Toplevel toplevel)
/// Building block API: completes the execution of a <see cref="Toplevel"/> that was started with <see cref="Begin(Toplevel)"/> .
/// </summary>
/// <param name="runState">The runstate returned by the <see cref="Begin(Toplevel)"/> method.</param>
public static void End (RunState runState)
/// <param name="closeDriver"><c>true</c>Closes the application.<c>false</c>Closes the toplevels only.</param>
public static void End (RunState runState, bool closeDriver = true)
{
if (runState == null)
throw new ArgumentNullException (nameof (runState));

runState.closeDriver = closeDriver;
runState.Dispose ();
runState = null;
}

/// <summary>
/// Shutdown an application initalized with <see cref="Init()"/>
/// Shutdown an application initialized with <see cref="Init()"/>
/// </summary>
public static void Shutdown ()
/// /// <param name="closeDriver"><c>true</c>Closes the application.<c>false</c>Closes toplevels only.</param>
public static void Shutdown (bool closeDriver = true)
{
// Shutdown is the bookend for Init. As such it needs to clean up all resources
// Init created. Apps that do any threading will need to code defensively for this.
Expand All @@ -2443,10 +2449,12 @@ public static void Shutdown ()
CurrentView = null;
Top = null;

//
MainLoop = null;
// Closes the application if it's true.
if (closeDriver) {
MainLoop = null;
Driver.End ();
}

Driver.End ();
_initialized = false;
}

Expand Down Expand Up @@ -2480,13 +2488,13 @@ public static void Refresh ()
Driver.Refresh ();
}

internal static void End (View view)
internal static void End (View view, bool closeDriver = true)
{
if (toplevels.Peek () != view)
throw new ArgumentException ("The view that you end with must be balanced");
toplevels.Pop ();
if (toplevels.Count == 0)
Shutdown ();
Shutdown (closeDriver);
else {
Current = toplevels.Peek ();
Refresh ();
Expand Down Expand Up @@ -2545,15 +2553,15 @@ static void DrawBounds (View v)
}

/// <summary>
/// Runs the application by calling <see cref="Run(Toplevel)"/> with the value of <see cref="Top"/>
/// Runs the application by calling <see cref="Run(Toplevel, bool)"/> with the value of <see cref="Top"/>
/// </summary>
public static void Run ()
{
Run (Top);
}

/// <summary>
/// Runs the application by calling <see cref="Run(Toplevel)"/> with a new instance of the specified <see cref="Toplevel"/>-derived class
/// Runs the application by calling <see cref="Run(Toplevel, bool)"/> with a new instance of the specified <see cref="Toplevel"/>-derived class
/// </summary>
public static void Run<T> () where T : Toplevel, new()
{
Expand All @@ -2571,11 +2579,11 @@ public static void Run ()
/// run other modal <see cref="View"/>s such as <see cref="Dialog"/> boxes.
/// </para>
/// <para>
/// To make a <see cref="Run(Toplevel)"/> stop execution, call <see cref="Application.RequestStop"/>.
/// To make a <see cref="Run(Toplevel, bool)"/> stop execution, call <see cref="Application.RequestStop"/>.
/// </para>
/// <para>
/// Calling <see cref="Run(Toplevel)"/> is equivalent to calling <see cref="Begin(Toplevel)"/>, followed by <see cref="RunLoop(RunState, bool)"/>,
/// and then calling <see cref="End(RunState)"/>.
/// Calling <see cref="Run(Toplevel, bool)"/> is equivalent to calling <see cref="Begin(Toplevel)"/>, followed by <see cref="RunLoop(RunState, bool)"/>,
/// and then calling <see cref="End(RunState, bool)"/>.
/// </para>
/// <para>
/// Alternatively, to have a program control the main loop and
Expand All @@ -2585,11 +2593,11 @@ public static void Run ()
/// then return control immediately.
/// </para>
/// </remarks>
public static void Run (Toplevel view)
public static void Run (Toplevel view, bool closeDriver = true)
{
var runToken = Begin (view);
RunLoop (runToken);
End (runToken);
End (runToken, closeDriver);
}

/// <summary>
Expand Down
7 changes: 2 additions & 5 deletions UICatalog/Scenario.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,8 @@ public virtual void Setup ()
/// </remarks>
public virtual void Run ()
{
Application.Run (Top);

// Every call to Application.Init must be bound by a call to Shutdown
// or Init doesn't do anything
Application.Shutdown ();
// This method already performs a later automatic shutdown.
Application.Run (Top, false);
}

/// <summary>
Expand Down
4 changes: 3 additions & 1 deletion UICatalog/UICatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ static void Main (string [] args)
scenario.Run ();
scenario = GetScenarioToRun ();
}
// Now closes the driver too.
Application.Shutdown ();
}

/// <summary>
Expand Down Expand Up @@ -197,7 +199,7 @@ private static Scenario GetScenarioToRun ()
};
#endif

Application.Run (_top);
Application.Run (_top, false);
return _runningScenario;
}

Expand Down

0 comments on commit 353baf7

Please sign in to comment.