#nullable enable
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
namespace Terminal.Gui;
/// A static, singleton class representing the application. This class is the entry point for the application.
///
///
/// Application.Init();
/// var win = new Window()
/// {
/// Title = $"Example App ({Application.QuitKey} to quit)"
/// };
/// Application.Run(win);
/// win.Dispose();
/// Application.Shutdown();
///
///
///
public static partial class Application
{
/// Gets all cultures supported by the application without the invariant language.
public static List? SupportedCultures { get; private set; }
internal static List GetSupportedCultures ()
{
CultureInfo [] culture = CultureInfo.GetCultures (CultureTypes.AllCultures);
// Get the assembly
var assembly = Assembly.GetExecutingAssembly ();
//Find the location of the assembly
string assemblyLocation = AppDomain.CurrentDomain.BaseDirectory;
// Find the resource file name of the assembly
var resourceFilename = $"{Path.GetFileNameWithoutExtension (AppContext.BaseDirectory)}.resources.dll";
// Return all culture for which satellite folder found with culture code.
return culture.Where (
cultureInfo =>
Directory.Exists (Path.Combine (assemblyLocation, cultureInfo.Name))
&& File.Exists (Path.Combine (assemblyLocation, cultureInfo.Name, resourceFilename))
)
.ToList ();
}
// 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
// guaranteeing that the state of this singleton is deterministic when Init
// starts running and after Shutdown returns.
internal static void ResetState (bool ignoreDisposed = false)
{
// 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.
// e.g. see Issue #537
foreach (Toplevel? t in TopLevels)
{
t!.Running = false;
}
TopLevels.Clear ();
Current = null;
#if DEBUG_IDISPOSABLE
// Don't dispose the Top. It's up to caller dispose it
if (!ignoreDisposed && Top is { })
{
Debug.Assert (Top.WasDisposed);
// If End wasn't called _cachedRunStateToplevel may be null
if (_cachedRunStateToplevel is { })
{
Debug.Assert (_cachedRunStateToplevel.WasDisposed);
Debug.Assert (_cachedRunStateToplevel == Top);
}
}
#endif
Top = null;
_cachedRunStateToplevel = null;
// MainLoop stuff
MainLoop?.Dispose ();
MainLoop = null;
MainThreadId = -1;
Iteration = null;
EndAfterFirstIteration = false;
// Driver stuff
if (Driver is { })
{
Driver.SizeChanged -= Driver_SizeChanged;
Driver.KeyDown -= Driver_KeyDown;
Driver.KeyUp -= Driver_KeyUp;
Driver.MouseEvent -= Driver_MouseEvent;
Driver?.End ();
Driver = null;
}
// Don't reset ForceDriver; it needs to be set before Init is called.
//ForceDriver = string.Empty;
//Force16Colors = false;
_forceFakeConsole = false;
// Run State stuff
NotifyNewRunState = null;
NotifyStopRunState = null;
MouseGrabView = null;
IsInitialized = false;
// Mouse
MouseEnteredView = null;
WantContinuousButtonPressedView = null;
MouseEvent = null;
GrabbedMouse = null;
UnGrabbingMouse = null;
GrabbedMouse = null;
UnGrabbedMouse = null;
// Keyboard
AlternateBackwardKey = Key.Empty;
AlternateForwardKey = Key.Empty;
QuitKey = Key.Empty;
KeyDown = null;
KeyUp = null;
SizeChanging = null;
AddApplicationKeyBindings ();
Colors.Reset ();
// Reset synchronization context to allow the user to run async/await,
// as the main loop has been ended, the synchronization context from
// gui.cs does no longer process any callbacks. See #1084 for more details:
// (https://github.com/gui-cs/Terminal.Gui/issues/1084).
SynchronizationContext.SetSynchronizationContext (null);
}
#nullable enable
#nullable restore
#nullable enable
// Only return true if the Current has changed.
#nullable restore
///
/// Gets a string representation of the Application as rendered by .
///
/// A string representation of the Application
public new static string ToString ()
{
ConsoleDriver driver = Driver;
if (driver is null)
{
return string.Empty;
}
return ToString (driver);
}
///
/// Gets a string representation of the Application rendered by the provided .
///
/// The driver to use to render the contents.
/// A string representation of the Application
public static string ToString (ConsoleDriver driver)
{
var sb = new StringBuilder ();
Cell [,] contents = driver.Contents;
for (var r = 0; r < driver.Rows; r++)
{
for (var c = 0; c < driver.Cols; c++)
{
Rune rune = contents [r, c].Rune;
if (rune.DecodeSurrogatePair (out char [] sp))
{
sb.Append (sp);
}
else
{
sb.Append ((char)rune.Value);
}
if (rune.GetColumns () > 1)
{
c++;
}
// See Issue #2616
//foreach (var combMark in contents [r, c].CombiningMarks) {
// sb.Append ((char)combMark.Value);
//}
}
sb.AppendLine ();
}
return sb.ToString ();
}
}