#nullable enable
using System.Collections.Concurrent;
namespace Terminal.Gui.App;
public partial class ApplicationImpl
{
///
public IDriver? Driver { get; set; }
///
public bool Force16Colors { get; set; }
///
public string ForceDriver { get; set; } = string.Empty;
///
public List Sixel { get; } = new ();
///
/// Creates the appropriate based on platform and driverName.
///
///
///
///
///
private void CreateDriver (string? driverName)
{
PlatformID p = Environment.OSVersion.Platform;
// Check component factory type first - this takes precedence over driverName
bool factoryIsWindows = _componentFactory is IComponentFactory;
bool factoryIsDotNet = _componentFactory is IComponentFactory;
bool factoryIsUnix = _componentFactory is IComponentFactory;
bool factoryIsFake = _componentFactory is IComponentFactory;
// Then check driverName
bool nameIsWindows = driverName?.Contains ("win", StringComparison.OrdinalIgnoreCase) ?? false;
bool nameIsDotNet = driverName?.Contains ("dotnet", StringComparison.OrdinalIgnoreCase) ?? false;
bool nameIsUnix = driverName?.Contains ("unix", StringComparison.OrdinalIgnoreCase) ?? false;
bool nameIsFake = driverName?.Contains ("fake", StringComparison.OrdinalIgnoreCase) ?? false;
// Decide which driver to use - component factory type takes priority
if (factoryIsFake || (!factoryIsWindows && !factoryIsDotNet && !factoryIsUnix && nameIsFake))
{
Coordinator = CreateSubcomponents (() => new FakeComponentFactory ());
_driverName = "fake";
}
else if (factoryIsWindows || (!factoryIsDotNet && !factoryIsUnix && nameIsWindows))
{
Coordinator = CreateSubcomponents (() => new WindowsComponentFactory ());
_driverName = "windows";
}
else if (factoryIsDotNet || (!factoryIsWindows && !factoryIsUnix && nameIsDotNet))
{
Coordinator = CreateSubcomponents (() => new NetComponentFactory ());
_driverName = "dotnet";
}
else if (factoryIsUnix || (!factoryIsWindows && !factoryIsDotNet && nameIsUnix))
{
Coordinator = CreateSubcomponents (() => new UnixComponentFactory ());
_driverName = "unix";
}
else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
{
Coordinator = CreateSubcomponents (() => new WindowsComponentFactory ());
_driverName = "windows";
}
else if (p == PlatformID.Unix)
{
Coordinator = CreateSubcomponents (() => new UnixComponentFactory ());
_driverName = "unix";
}
else
{
Logging.Information($"Falling back to dotnet driver.");
Coordinator = CreateSubcomponents (() => new NetComponentFactory ());
_driverName = "dotnet";
}
Logging.Trace ($"Created Subcomponents: {Coordinator}");
Coordinator.StartInputTaskAsync ().Wait ();
if (Driver == null)
{
throw new ("Driver was null even after booting MainLoopCoordinator");
}
}
private readonly IComponentFactory? _componentFactory;
///
/// INTERNAL: Gets or sets the main loop coordinator that orchestrates the application's event processing,
/// input handling, and rendering pipeline.
///
///
///
/// The is the central component responsible for:
///
/// - Managing the platform-specific input thread that reads from the console
/// - Coordinating the main application loop via
/// - Processing queued input events and translating them to Terminal.Gui events
/// - Managing the that handles rendering
/// - Executing scheduled timeouts and callbacks via
///
///
///
/// The coordinator is created in based on the selected driver
/// (Windows, Unix, .NET, or Fake) and is started by calling
/// .
///
///
internal IMainLoopCoordinator? Coordinator { get; private set; }
///
/// INTERNAL: Creates a with the appropriate component factory
/// for the specified input record type.
///
///
/// Platform-specific input type: (.NET/Fake),
/// (Windows), or (Unix).
///
///
/// Factory function to create the component factory if
/// is not of type .
///
///
/// A configured with the input queue,
/// main loop, timed events, and selected component factory.
///
private IMainLoopCoordinator CreateSubcomponents (Func> fallbackFactory) where TInputRecord : struct
{
ConcurrentQueue inputQueue = new ();
ApplicationMainLoop loop = new ();
IComponentFactory cf;
if (_componentFactory is IComponentFactory typedFactory)
{
cf = typedFactory;
}
else
{
cf = fallbackFactory ();
}
return new MainLoopCoordinator (_timedEvents, inputQueue, loop, cf);
}
internal void SubscribeDriverEvents ()
{
ArgumentNullException.ThrowIfNull (Driver);
Driver.SizeChanged += Driver_SizeChanged;
Driver.KeyDown += Driver_KeyDown;
Driver.KeyUp += Driver_KeyUp;
Driver.MouseEvent += Driver_MouseEvent;
}
internal void UnsubscribeDriverEvents ()
{
ArgumentNullException.ThrowIfNull (Driver);
Driver.SizeChanged -= Driver_SizeChanged;
Driver.KeyDown -= Driver_KeyDown;
Driver.KeyUp -= Driver_KeyUp;
Driver.MouseEvent -= Driver_MouseEvent;
}
private void Driver_KeyDown (object? sender, Key e) { Keyboard?.RaiseKeyDownEvent (e); }
private void Driver_KeyUp (object? sender, Key e) { Keyboard?.RaiseKeyUpEvent (e); }
private void Driver_MouseEvent (object? sender, MouseEventArgs e) { Mouse?.RaiseMouseEvent (e); }
}