Application.Lifecycle.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #nullable enable
  2. using System.Diagnostics;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Reflection;
  5. namespace Terminal.Gui.App;
  6. public static partial class Application // Lifecycle (Init/Shutdown)
  7. {
  8. /// <summary>Initializes a new instance of a Terminal.Gui Application. <see cref="Shutdown"/> must be called when the application is closing.</summary>
  9. /// <para>Call this method once per instance (or after <see cref="Shutdown"/> has been called).</para>
  10. /// <para>
  11. /// This function loads the right <see cref="IConsoleDriver"/> for the platform, Creates a <see cref="Toplevel"/>. and
  12. /// assigns it to <see cref="Top"/>
  13. /// </para>
  14. /// <para>
  15. /// <see cref="Shutdown"/> must be called when the application is closing (typically after
  16. /// <see cref="Run{T}"/> has returned) to ensure resources are cleaned up and
  17. /// terminal settings
  18. /// restored.
  19. /// </para>
  20. /// <para>
  21. /// The <see cref="Run{T}"/> function combines
  22. /// <see cref="Init(IConsoleDriver,string)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
  23. /// into a single
  24. /// call. An application can use <see cref="Run{T}"/> without explicitly calling
  25. /// <see cref="Init(IConsoleDriver,string)"/>.
  26. /// </para>
  27. /// <param name="driver">
  28. /// The <see cref="IConsoleDriver"/> to use. If neither <paramref name="driver"/> or
  29. /// <paramref name="driverName"/> are specified the default driver for the platform will be used.
  30. /// </param>
  31. /// <param name="driverName">
  32. /// The short name (e.g. "dotnet", "windows", "unix", or "fake") of the
  33. /// <see cref="IConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are
  34. /// specified the default driver for the platform will be used.
  35. /// </param>
  36. [RequiresUnreferencedCode ("AOT")]
  37. [RequiresDynamicCode ("AOT")]
  38. public static void Init (IConsoleDriver? driver = null, string? driverName = null)
  39. {
  40. ApplicationImpl.Instance.Init (driver, driverName ?? ForceDriver);
  41. }
  42. internal static int MainThreadId
  43. {
  44. get => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId;
  45. set => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId = value;
  46. }
  47. internal static void SubscribeDriverEvents ()
  48. {
  49. ArgumentNullException.ThrowIfNull (Driver);
  50. Driver.SizeChanged += Driver_SizeChanged;
  51. Driver.KeyDown += Driver_KeyDown;
  52. Driver.KeyUp += Driver_KeyUp;
  53. Driver.MouseEvent += Driver_MouseEvent;
  54. }
  55. internal static void UnsubscribeDriverEvents ()
  56. {
  57. ArgumentNullException.ThrowIfNull (Driver);
  58. Driver.SizeChanged -= Driver_SizeChanged;
  59. Driver.KeyDown -= Driver_KeyDown;
  60. Driver.KeyUp -= Driver_KeyUp;
  61. Driver.MouseEvent -= Driver_MouseEvent;
  62. }
  63. private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e)
  64. {
  65. RaiseScreenChangedEvent (new Rectangle (new (0, 0), e.Size!.Value));
  66. }
  67. private static void Driver_KeyDown (object? sender, Key e) { RaiseKeyDownEvent (e); }
  68. private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); }
  69. private static void Driver_MouseEvent (object? sender, MouseEventArgs e) { RaiseMouseEvent (e); }
  70. /// <summary>Gets a list of <see cref="IConsoleDriver"/> types and type names that are available.</summary>
  71. /// <returns></returns>
  72. [RequiresUnreferencedCode ("AOT")]
  73. public static (List<Type?>, List<string?>) GetDriverTypes ()
  74. {
  75. // use reflection to get the list of drivers
  76. List<Type?> driverTypes = new ();
  77. // Only inspect the IConsoleDriver assembly
  78. var asm = typeof (IConsoleDriver).Assembly;
  79. foreach (Type? type in asm.GetTypes ())
  80. {
  81. if (typeof (IConsoleDriver).IsAssignableFrom (type) &&
  82. type is { IsAbstract: false, IsClass: true })
  83. {
  84. driverTypes.Add (type);
  85. }
  86. }
  87. List<string?> driverTypeNames = driverTypes
  88. .Where (d => !typeof (IConsoleDriverFacade).IsAssignableFrom (d))
  89. .Select (d => d!.Name)
  90. .Union (["dotnet", "windows", "unix", "fake"])
  91. .ToList ()!;
  92. return (driverTypes, driverTypeNames);
  93. }
  94. /// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
  95. /// <remarks>
  96. /// Shutdown must be called for every call to <see cref="Init"/> or
  97. /// <see cref="Application.Run(Toplevel, Func{Exception, bool})"/> to ensure all resources are cleaned
  98. /// up (Disposed)
  99. /// and terminal settings are restored.
  100. /// </remarks>
  101. public static void Shutdown () => ApplicationImpl.Instance.Shutdown ();
  102. /// <summary>
  103. /// Gets whether the application has been initialized with <see cref="Init"/> and not yet shutdown with <see cref="Shutdown"/>.
  104. /// </summary>
  105. /// <remarks>
  106. /// <para>
  107. /// The <see cref="InitializedChanged"/> event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
  108. /// </para>
  109. /// </remarks>
  110. public static bool Initialized
  111. {
  112. get => ApplicationImpl.Instance.Initialized;
  113. internal set => ApplicationImpl.Instance.Initialized = value;
  114. }
  115. /// <summary>
  116. /// This event is raised after the <see cref="Init"/> and <see cref="Shutdown"/> methods have been called.
  117. /// </summary>
  118. /// <remarks>
  119. /// Intended to support unit tests that need to know when the application has been initialized.
  120. /// </remarks>
  121. public static event EventHandler<EventArgs<bool>>? InitializedChanged;
  122. /// <summary>
  123. /// Raises the <see cref="InitializedChanged"/> event.
  124. /// </summary>
  125. internal static void OnInitializedChanged (object sender, EventArgs<bool> e)
  126. {
  127. Application.InitializedChanged?.Invoke (sender, e);
  128. }
  129. }