using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
namespace Terminal.Gui.App;
///
/// Interface for instances that provide backing functionality to static
/// gateway class .
///
///
///
/// Implements to support automatic resource cleanup via using statements.
/// Call or use a using statement to properly clean up resources.
///
///
public interface IApplication : IDisposable
{
#region Lifecycle - App Initialization and Shutdown
///
/// Gets or sets the managed thread ID of the application's main UI thread, which is set during
/// and used to determine if code is executing on the main thread.
///
///
/// The managed thread ID of the main UI thread, or if the application is not initialized.
///
public int? MainThreadId { get; internal set; }
/// Initializes a new instance of Application.
///
/// The short name (e.g. "dotnet", "windows", "unix", or "fake") of the
/// to use. If not specified the default driver for the platform will be used.
///
/// This instance for fluent API chaining.
///
/// Call this method once per instance (or after has been called).
///
/// This function loads the right for the platform, creates a main loop coordinator,
/// initializes keyboard and mouse handlers, and subscribes to driver events.
///
///
/// must be called when the application is closing (typically after
/// has returned) to ensure all resources are cleaned up (disposed) and
/// terminal settings are restored.
///
///
/// Supports fluent API with automatic resource management:
///
///
/// Recommended pattern (using statement):
///
/// using (var app = Application.Create().Init())
/// {
/// app.Run<MyDialog>();
/// var result = app.GetResult<MyResultType>();
/// } // app.Dispose() called automatically
///
///
///
/// Alternative pattern (manual disposal):
///
/// var app = Application.Create().Init();
/// app.Run<MyDialog>();
/// var result = app.GetResult<MyResultType>();
/// app.Dispose(); // Must call explicitly
///
///
///
/// Note: Runnables created by are automatically disposed when
/// that method returns. Runnables passed to
/// must be disposed by the caller.
///
///
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public IApplication Init (string? driverName = null);
///
/// This event is raised after the and methods have been called.
///
///
/// Intended to support unit tests that need to know when the application has been initialized.
///
public event EventHandler>? InitializedChanged;
/// Gets or sets whether the application has been initialized.
bool Initialized { get; set; }
///
/// INTERNAL: Resets the state of this instance. Called by Dispose.
///
/// If true, ignores disposed state checks during reset.
///
///
/// Encapsulates 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
/// starts running and after returns.
///
///
/// IMPORTANT: Ensure all property/fields are reset here. See Init_ResetState_Resets_Properties unit test.
///
///
internal void ResetState (bool ignoreDisposed = false);
#endregion App Initialization and Shutdown
#region Session Management - Begin->Run->Iteration->Stop->End
///
/// Gets the stack of all active runnable session tokens.
/// Sessions execute serially - the top of stack is the currently modal session.
///
///
///
/// Session tokens are pushed onto the stack when is called and
/// popped when
/// completes. The stack grows during nested modal calls and
/// shrinks as they complete.
///
///
/// Only the top session () has exclusive keyboard/mouse input (
/// = true).
/// All other sessions on the stack continue to be laid out, drawn, and receive iteration events (
/// = true),
/// but they don't receive user input.
///
///
/// Stack during nested modals:
///
/// RunnableSessionStack (top to bottom):
/// - MessageBox (TopRunnable, IsModal=true, IsRunning=true, has input)
/// - FileDialog (IsModal=false, IsRunning=true, continues to update/draw)
/// - MainWindow (IsModal=false, IsRunning=true, continues to update/draw)
///
///
///
ConcurrentStack? SessionStack { get; }
///
/// Raised when has been called and has created a new .
///
///
/// If is , callers to
/// must also subscribe to and manually dispose of the token
/// when the application is done.
///
public event EventHandler? SessionBegun;
#region TopRunnable Properties
/// Gets the Runnable that is on the top of the .
///
///
/// The top runnable in the session stack captures all mouse and keyboard input.
/// This is set by and cleared by .
///
///
IRunnable? TopRunnable { get; }
/// Gets the View that is on the top of the .
///
///
/// This is a convenience property that casts to a .
///
///
View? TopRunnableView { get; }
#endregion TopRunnable Properties
///
/// Building block API: Creates a and prepares the provided
/// for
/// execution. Not usually called directly by applications. Use
/// instead.
///
/// The to prepare execution for.
///
/// The that needs to be passed to the
/// method upon
/// completion.
///
///
///
/// This method prepares the provided for running. It adds this to the
/// , lays out the SubViews, focuses the first element, and draws the
/// runnable on the screen. This is usually followed by starting the main loop, and then the
/// method upon termination which will undo these changes.
///
///
/// Raises the , ,
/// and events.
///
///
/// The session token. if the operation was cancelled.
SessionToken? Begin (IRunnable runnable);
///
/// Runs a new Session with the provided runnable view.
///
/// The runnable to execute.
/// Optional handler for unhandled exceptions (resumes when returns true, rethrows when null).
///
///
/// This method is used to start processing events for the main application, but it is also used to run other
/// modal views such as dialogs.
///
///
/// To make stop execution, call
/// or .
///
///
/// Calling is equivalent to calling
/// , followed by starting the main loop, and then calling
/// .
///
///
/// In RELEASE builds: When is any exceptions will be
/// rethrown. Otherwise, will be called. If
/// returns the main loop will resume; otherwise this method will exit.
///
///
object? Run (IRunnable runnable, Func? errorHandler = null);
///
/// Runs a new Session creating a -derived object of type
/// and calling . When the session is stopped,
/// will be called.
///
///
/// Handler for any unhandled exceptions (resumes when returns true, rethrows when null).
///
/// The driver name. If not specified the default driver for the platform will be used. Must be
/// if has already been called.
///
///
/// The created object. The caller is responsible for calling
/// on this
/// object.
///
///
///
/// This method is used to start processing events for the main application, but it is also used to run other
/// modal s such as boxes.
///
///
/// To make stop execution, call
/// or .
///
///
/// In RELEASE builds: When is any exceptions will be
/// rethrown. Otherwise, will be called. If
/// returns the main loop will resume; otherwise this method will exit.
///
///
/// must be called when the application is closing (typically after Run has
/// returned) to
/// ensure resources are cleaned up and terminal settings restored.
///
///
/// In RELEASE builds: When is any exceptions will be
/// rethrown. Otherwise, will be called. If
/// returns the main loop will resume; otherwise this method will exit.
///
///
/// The caller is responsible for disposing the object returned by this method.
///
///
[RequiresUnreferencedCode ("AOT")]
[RequiresDynamicCode ("AOT")]
public IApplication Run (Func? errorHandler = null, string? driverName = null)
where TRunnable : IRunnable, new ();
#region Iteration & Invoke
///
/// Raises the event.
///
///
/// This is called once per main loop iteration, before processing input, timeouts, or rendering.
///
public void RaiseIteration ();
/// This event is raised on each iteration of the main loop.
///
///
/// This event is raised before input processing, timeout callbacks, and rendering occur each iteration.
///
/// The event args contain the current application instance.
///
///
///
/// .
public event EventHandler>? Iteration;
/// Runs on the main UI loop thread.
/// The action to be invoked on the main processing thread.
///
///
/// If called from the main thread, the action is executed immediately. Otherwise, it is queued via
/// with and will be executed on the next main loop
/// iteration.
///
///
void Invoke (Action? action);
/// Runs on the main UI loop thread.
/// The action to be invoked on the main processing thread.
///
///
/// If called from the main thread, the action is executed immediately. Otherwise, it is queued via
/// with and will be executed on the next main loop
/// iteration.
///
///
void Invoke (Action action);
#endregion Iteration & Invoke
///
/// Set to to cause the session to stop running after first iteration.
///
///
///
/// Used primarily for unit testing. When , will be
/// called
/// automatically after the first main loop iteration.
///
///
bool StopAfterFirstIteration { get; set; }
/// Requests that the currently running Session stop. The Session will stop after the current iteration completes.
///
/// This will cause to return.
///
/// This is equivalent to calling with as the
/// parameter.
///
///
void RequestStop ();
///
/// Requests that the specified runnable session stop.
///
///
/// The runnable to stop. If , stops the current
/// .
///
///
///
/// This will cause to return.
///
///
/// Raises , ,
/// and events.
///
///
void RequestStop (IRunnable? runnable);
///
/// Building block API: Ends the session associated with the token and completes the execution of an
/// .
/// Not usually called directly by applications.
/// will automatically call this method when the session is stopped.
///
///
/// The returned by the
/// method.
///
///
///
/// This method removes the from the ,
/// raises the lifecycle events, and disposes the .
///
///
/// Raises , ,
/// and events.
///
///
void End (SessionToken sessionToken);
///
/// Raised when was called and the session is stopping. The event args contain a
/// reference to the
/// that was active during the session. This can be used to ensure the Runnable is disposed of properly.
///
///
/// If is , callers to
/// must also subscribe to and manually dispose of the token
/// when the application is done.
///
public event EventHandler? SessionEnded;
#endregion Session Management - Begin->Run->Iteration->Stop->End
#region Result Management
///
/// Gets the result from the last or
/// call.
///
///
/// The result from the last run session, or if no session has been run or the result was null.
///
object? GetResult ();
///
/// Gets the result from the last or
/// call, cast to type .
///
/// The expected result type.
///
/// The result cast to , or if the result is null or cannot be cast.
///
///
///
/// using (var app = Application.Create().Init())
/// {
/// app.Run<ColorPickerDialog>();
/// var selectedColor = app.GetResult<Color>();
/// if (selectedColor.HasValue)
/// {
/// // Use the color
/// }
/// }
///
///
T? GetResult () where T : class => GetResult () as T;
#endregion Result Management
#region Screen and Driver
/// Gets or sets the console driver being used.
///
///
/// Set by based on the driver parameter or platform default.
///
///
IDriver? Driver { get; set; }
///
/// Gets the clipboard for this application instance.
///
///
///
/// Provides access to the OS clipboard through the driver. Returns if
/// is not initialized.
///
///
IClipboard? Clipboard { get; }
///
/// Forces the use of the specified driver (one of "fake", "dotnet", "windows", or "unix"). If not
/// specified, the driver is selected based on the platform.
///
string ForceDriver { get; set; }
///
/// Gets or sets the size of the screen. By default, this is the size of the screen as reported by the
/// .
///
///
///
/// If the has not been initialized, this will return a default size of 2048x2048; useful
/// for unit tests.
///
///
Rectangle Screen { get; set; }
/// Raised when the terminal's size changed. The new size of the terminal is provided.
///
///
/// This event is raised when the driver detects a screen size change. The event provides the new screen
/// rectangle.
///
///
public event EventHandler>? ScreenChanged;
///
/// Gets or sets whether the screen will be cleared, and all Views redrawn, during the next Application iteration.
///
///
///
/// This is typically set to when a View's changes and that view
/// has no SuperView (e.g. when is moved or resized).
///
///
/// Automatically reset to after processes it.
///
///
bool ClearScreenNextIteration { get; set; }
#endregion Screen and Driver
#region Keyboard
///
/// Handles keyboard input and key bindings at the Application level.
///
///
///
/// Provides access to keyboard state, key bindings, and keyboard event handling. Set during .
///
///
IKeyboard Keyboard { get; set; }
#endregion Keyboard
#region Mouse
///
/// Handles mouse event state and processing.
///
///
///
/// Provides access to mouse state, mouse grabbing, and mouse event handling. Set during .
///
///
IMouse Mouse { get; set; }
#endregion Mouse
#region Layout and Drawing
///
/// Causes any Runnables that need layout to be laid out, then draws any Runnables that need display. Only Views
/// that need to be laid out (see ) will be laid out. Only Views that need to be drawn
/// (see ) will be drawn.
///
///
/// If the entire View hierarchy will be redrawn. The default is and
/// should only be overridden for testing.
///
///
///
/// This method is called automatically each main loop iteration when any views need layout or drawing.
///
///
/// If is , the screen will be cleared before
/// drawing and the flag will be reset to .
///
///
public void LayoutAndDraw (bool forceRedraw = false);
///
/// Calls on the most focused view.
///
///
/// Does nothing if there is no most focused view.
///
/// If the most focused view is not visible within its superview, the cursor will be hidden.
///
///
/// if a view positioned the cursor and the position is visible.
public bool PositionCursor ();
#endregion Layout and Drawing
#region Navigation and Popover
/// Gets or sets the navigation manager.
///
///
/// Manages focus navigation and tracking of the most focused view. Initialized during .
///
///
ApplicationNavigation? Navigation { get; set; }
/// Gets or sets the popover manager.
///
///
/// Manages application-level popover views. Initialized during .
///
///
ApplicationPopover? Popover { get; set; }
#endregion Navigation and Popover
#region Timeouts
/// Adds a timeout to the application.
/// The time span to wait before invoking the callback.
///
/// The callback to invoke. If it returns , the timeout will be reset and repeat. If it
/// returns , the timeout will stop and be removed.
///
///
/// Call with the returned value to stop the timeout.
///
///
///
/// When the time specified passes, the callback will be invoked on the main UI thread.
///
///
/// calls StopAll on to remove all timeouts.
///
///
object? AddTimeout (TimeSpan time, Func callback);
/// Removes a previously scheduled timeout.
/// The token returned by .
///
/// if the timeout is successfully removed; otherwise, .
/// This method also returns if the timeout is not found.
///
bool RemoveTimeout (object token);
///
/// Handles recurring events. These are invoked on the main UI thread - allowing for
/// safe updates to instances.
///
///
///
/// Provides low-level access to the timeout management system. Most applications should use
/// and instead.
///
///
ITimedEvents? TimedEvents { get; }
#endregion Timeouts
///
/// Gets a string representation of the Application as rendered by .
///
/// A string representation of the Application
public string ToString ();
}