mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-30 17:57:57 +01:00
Merge pull request #553 from BDisp/driver-shutdown
Fixes #515, #518 and #536.
This commit is contained in:
@@ -2125,23 +2125,25 @@ namespace Terminal.Gui {
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
var p = Environment.OSVersion.Platform;
|
||||
Mono.Terminal.IMainLoopDriver mainLoopDriver;
|
||||
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 ();
|
||||
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;
|
||||
@@ -2152,6 +2154,8 @@ namespace Terminal.Gui {
|
||||
/// 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;
|
||||
@@ -2168,7 +2172,7 @@ namespace Terminal.Gui {
|
||||
/// <see cref="Application.RunState"/> was occupying.</remarks>
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
Dispose (closeDriver);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
@@ -2180,7 +2184,7 @@ namespace Terminal.Gui {
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (Toplevel != null) {
|
||||
End (Toplevel);
|
||||
End (Toplevel, disposing);
|
||||
Toplevel = null;
|
||||
}
|
||||
}
|
||||
@@ -2373,14 +2377,14 @@ namespace Terminal.Gui {
|
||||
/// <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)
|
||||
@@ -2417,19 +2421,21 @@ namespace Terminal.Gui {
|
||||
/// 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.
|
||||
@@ -2443,10 +2449,12 @@ namespace Terminal.Gui {
|
||||
CurrentView = null;
|
||||
Top = null;
|
||||
|
||||
//
|
||||
MainLoop = null;
|
||||
// Closes the application if it's true.
|
||||
if (closeDriver) {
|
||||
MainLoop = null;
|
||||
Driver.End ();
|
||||
}
|
||||
|
||||
Driver.End ();
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
@@ -2480,13 +2488,13 @@ namespace Terminal.Gui {
|
||||
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 ();
|
||||
@@ -2545,7 +2553,7 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <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 ()
|
||||
{
|
||||
@@ -2553,7 +2561,7 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
@@ -2571,11 +2579,11 @@ namespace Terminal.Gui {
|
||||
/// 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
|
||||
@@ -2585,11 +2593,11 @@ namespace Terminal.Gui {
|
||||
/// 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>
|
||||
|
||||
@@ -195,11 +195,8 @@ namespace UICatalog {
|
||||
/// </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>
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace UICatalog {
|
||||
scenario.Run ();
|
||||
scenario = GetScenarioToRun ();
|
||||
}
|
||||
// Now closes the driver too.
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,7 +199,7 @@ namespace UICatalog {
|
||||
};
|
||||
#endif
|
||||
|
||||
Application.Run (_top);
|
||||
Application.Run (_top, false);
|
||||
return _runningScenario;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user