using System.Collections.Concurrent; namespace Terminal.Gui.App; /// /// Implementation of core methods using the modern /// main loop architecture with component factories for different platforms. /// public partial class ApplicationImpl : IApplication { /// /// INTERNAL: Creates a new instance of the Application backend. /// internal ApplicationImpl () { } /// /// INTERNAL: Creates a new instance of the Application backend. /// /// internal ApplicationImpl (IComponentFactory componentFactory) { _componentFactory = componentFactory; } #region Singleton /// /// Tracks which application model has been used in this process. /// private static ApplicationModelUsage _modelUsage = ApplicationModelUsage.None; /// /// Configures the singleton instance of to use the specified backend implementation. /// /// public static void SetInstance (IApplication? app) { _instance = app; } // Private static readonly Lazy instance of Application private static IApplication? _instance; /// /// Gets the currently configured backend implementation of gateway methods. /// public static IApplication Instance { get { // If an instance already exists, return it without fence checking // This allows for cleanup/reset operations if (_instance is { }) { return _instance; } // Only check the fence when creating a new instance if (_modelUsage == ApplicationModelUsage.InstanceBased) { throw new InvalidOperationException ( "Cannot use legacy static Application model (Application.Init/ApplicationImpl.Instance) after using modern instance-based model (Application.Create). " + "Use only one model per process."); } _modelUsage = ApplicationModelUsage.LegacyStatic; return _instance = new ApplicationImpl (); } } /// /// INTERNAL: Marks that the instance-based model has been used. Called by Application.Create(). /// internal static void MarkInstanceBasedModelUsed () { if (_modelUsage == ApplicationModelUsage.LegacyStatic) { throw new InvalidOperationException ( "Cannot use modern instance-based model (Application.Create) after using legacy static Application model (Application.Init/ApplicationImpl.Instance). " + "Use only one model per process."); } _modelUsage = ApplicationModelUsage.InstanceBased; } /// /// INTERNAL: Resets the model usage tracking. Only for testing purposes. /// internal static void ResetModelUsageTracking () { _modelUsage = ApplicationModelUsage.None; _instance = null; } #endregion Singleton /// /// Defines the different application usage models. /// private enum ApplicationModelUsage { /// No model has been used yet. None, /// Legacy static model (Application.Init/ApplicationImpl.Instance). LegacyStatic, /// Modern instance-based model (Application.Create). InstanceBased } private string? _driverName; #region Input private IMouse? _mouse; /// /// Handles mouse event state and processing. /// public IMouse Mouse { get { _mouse ??= new MouseImpl { App = this }; return _mouse; } set => _mouse = value ?? throw new ArgumentNullException (nameof (value)); } private IKeyboard? _keyboard; /// /// Handles keyboard input and key bindings at the Application level /// public IKeyboard Keyboard { get { _keyboard ??= new KeyboardImpl { App = this }; return _keyboard; } set => _keyboard = value ?? throw new ArgumentNullException (nameof (value)); } #endregion Input #region View Management private ApplicationPopover? _popover; /// public ApplicationPopover? Popover { get { _popover ??= new () { App = this }; return _popover; } set => _popover = value; } private ApplicationNavigation? _navigation; /// public ApplicationNavigation? Navigation { get { _navigation ??= new () { App = this }; return _navigation; } set => _navigation = value ?? throw new ArgumentNullException (nameof (value)); } private Toplevel? _topRunnable; /// public Toplevel? TopRunnable { get => _topRunnable; set { _topRunnable = value; if (_topRunnable is { }) { _topRunnable.App = this; } } } // BUGBUG: Technically, this is not the full lst of sessions. There be dragons here, e.g. see how Toplevel.Id is used. What /// public ConcurrentStack SessionStack { get; } = new (); /// public Toplevel? CachedSessionTokenToplevel { get; set; } /// public ConcurrentStack? RunnableSessionStack { get; } = new (); /// public IRunnable? FrameworkOwnedRunnable { get; set; } #endregion View Management /// public new string ToString () => Driver?.ToString () ?? string.Empty; }