LegacyMainLoopDriver.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #nullable enable
  2. //
  3. // LegacyMainLoopDriver.cs: IMainLoopDriver and MainLoop for legacy v1 driver based applications
  4. //
  5. // Authors:
  6. // Miguel de Icaza ([email protected])
  7. //
  8. using System.Collections.ObjectModel;
  9. namespace Terminal.Gui.App;
  10. /// <summary>
  11. /// The main event loop of legacy v1 driver based applications.
  12. /// </summary>
  13. /// <remarks>
  14. /// <para>
  15. /// This class is provided for backward compatibility with the legacy FakeDriver implementation.
  16. /// New code should use the modern <see cref="ApplicationMainLoop{T}"/> architecture instead.
  17. /// </para>
  18. /// <para>
  19. /// Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
  20. /// on Windows.
  21. /// </para>
  22. /// </remarks>
  23. [Obsolete ("This class is for legacy FakeDriver compatibility only. Use ApplicationMainLoop<T> for new code.")]
  24. public class MainLoop : IDisposable
  25. {
  26. /// <summary>
  27. /// Gets the class responsible for handling timeouts
  28. /// </summary>
  29. public ITimedEvents TimedEvents { get; } = new TimedEvents();
  30. /// <summary>Creates a new MainLoop.</summary>
  31. /// <remarks>Use <see cref="Dispose"/> to release resources.</remarks>
  32. /// <param name="driver">
  33. /// The <see cref="IConsoleDriver"/> instance (one of the implementations FakeMainLoop, UnixMainLoop,
  34. /// NetMainLoop or WindowsMainLoop).
  35. /// </param>
  36. internal MainLoop (IMainLoopDriver driver)
  37. {
  38. MainLoopDriver = driver;
  39. driver.Setup (this);
  40. }
  41. /// <summary>The current <see cref="IMainLoopDriver"/> in use.</summary>
  42. /// <value>The main loop driver.</value>
  43. internal IMainLoopDriver? MainLoopDriver { get; private set; }
  44. /// <summary>Used for unit tests.</summary>
  45. internal bool Running { get; set; }
  46. /// <inheritdoc/>
  47. public void Dispose ()
  48. {
  49. GC.SuppressFinalize (this);
  50. Stop ();
  51. Running = false;
  52. MainLoopDriver?.TearDown ();
  53. MainLoopDriver = null;
  54. }
  55. /// <summary>Determines whether there are pending events to be processed.</summary>
  56. /// <remarks>
  57. /// You can use this method if you want to probe if events are pending. Typically used if you need to flush the
  58. /// input queue while still running some of your own code in your main thread.
  59. /// </remarks>
  60. internal bool EventsPending () { return MainLoopDriver!.EventsPending (); }
  61. /// <summary>Runs the <see cref="MainLoop"/>. Used only for unit tests.</summary>
  62. internal void Run ()
  63. {
  64. bool prev = Running;
  65. Running = true;
  66. while (Running)
  67. {
  68. EventsPending ();
  69. RunIteration ();
  70. }
  71. Running = prev;
  72. }
  73. /// <summary>Runs one iteration of timers and file watches</summary>
  74. /// <remarks>
  75. /// Use this to process all pending events (timers handlers and file watches).
  76. /// <code>
  77. /// while (main.EventsPending ()) RunIteration ();
  78. /// </code>
  79. /// </remarks>
  80. internal void RunIteration ()
  81. {
  82. RunAnsiScheduler ();
  83. MainLoopDriver?.Iteration ();
  84. TimedEvents.RunTimers ();
  85. }
  86. private void RunAnsiScheduler ()
  87. {
  88. Application.Driver?.GetRequestScheduler ().RunSchedule ();
  89. }
  90. /// <summary>Stops the main loop driver and calls <see cref="IMainLoopDriver.Wakeup"/>. Used only for unit tests.</summary>
  91. internal void Stop ()
  92. {
  93. Running = false;
  94. Wakeup ();
  95. }
  96. /// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input.</summary>
  97. internal void Wakeup () { MainLoopDriver?.Wakeup (); }
  98. }