#nullable enable
//
// MainLoop.cs: IMainLoopDriver and MainLoop for Terminal.Gui
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
using System.Collections.ObjectModel;
namespace Terminal.Gui.App;
/// Interface to create a platform specific driver.
internal interface IMainLoopDriver
{
/// Must report whether there are any events pending, or even block waiting for events.
/// , if there were pending events, otherwise.
bool EventsPending ();
/// The iteration function.
void Iteration ();
/// Initializes the , gets the calling main loop for the initialization.
/// Call to release resources.
/// Main loop.
void Setup (MainLoop mainLoop);
/// Tears down the driver. Releases resources created in .
void TearDown ();
/// Wakes up the that might be waiting on input, must be thread safe.
void Wakeup ();
}
/// The main event loop of v1 driver based applications.
///
/// Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
/// on Windows.
///
public class MainLoop : IDisposable
{
///
/// Gets the class responsible for handling timeouts
///
public ITimedEvents TimedEvents { get; } = new TimedEvents();
/// Creates a new MainLoop.
/// Use to release resources.
///
/// The instance (one of the implementations FakeMainLoop, UnixMainLoop,
/// NetMainLoop or WindowsMainLoop).
///
internal MainLoop (IMainLoopDriver driver)
{
MainLoopDriver = driver;
driver.Setup (this);
}
/// The current in use.
/// The main loop driver.
internal IMainLoopDriver? MainLoopDriver { get; private set; }
/// Used for unit tests.
internal bool Running { get; set; }
///
public void Dispose ()
{
GC.SuppressFinalize (this);
Stop ();
Running = false;
MainLoopDriver?.TearDown ();
MainLoopDriver = null;
}
/// Determines whether there are pending events to be processed.
///
/// You can use this method if you want to probe if events are pending. Typically used if you need to flush the
/// input queue while still running some of your own code in your main thread.
///
internal bool EventsPending () { return MainLoopDriver!.EventsPending (); }
/// Runs the . Used only for unit tests.
internal void Run ()
{
bool prev = Running;
Running = true;
while (Running)
{
EventsPending ();
RunIteration ();
}
Running = prev;
}
/// Runs one iteration of timers and file watches
///
/// Use this to process all pending events (timers handlers and file watches).
///
/// while (main.EventsPending ()) RunIteration ();
///
///
internal void RunIteration ()
{
RunAnsiScheduler ();
MainLoopDriver?.Iteration ();
TimedEvents.RunTimers ();
}
private void RunAnsiScheduler ()
{
Application.Driver?.GetRequestScheduler ().RunSchedule ();
}
/// Stops the main loop driver and calls . Used only for unit tests.
internal void Stop ()
{
Running = false;
Wakeup ();
}
/// Wakes up the that might be waiting on input.
internal void Wakeup () { MainLoopDriver?.Wakeup (); }
}