소스 검색

moved mainloop out of CursesDriver

Charlie Kindel 5 년 전
부모
커밋
140bb276ee

+ 0 - 1
Example/demo.cs

@@ -2,7 +2,6 @@ using Terminal.Gui;
 using System;
 using System.Linq;
 using System.IO;
-using Mono.Terminal;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;

+ 1 - 2
Terminal.Gui/ConsoleDrivers/CursesDriver.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -8,7 +8,6 @@ using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
-using Mono.Terminal;
 using NStack;
 using Unix.Terminal;
 
@@ -447,7 +446,7 @@ namespace Terminal.Gui {
 			this.mouseHandler = mouseHandler;
 			this.mainLoop = mainLoop;
 
-			(mainLoop.Driver as Mono.Terminal.UnixMainLoop).AddWatch (0, Mono.Terminal.UnixMainLoop.Condition.PollIn, x => {
+			(mainLoop.Driver as UnixMainLoop).AddWatch (0, UnixMainLoop.Condition.PollIn, x => {
 				ProcessInput (keyHandler, keyDownHandler, keyUpHandler, mouseHandler);
 				return true;
 			});

+ 0 - 0
Terminal.Gui/MonoCurses/README.md → Terminal.Gui/ConsoleDrivers/CursesDriver/README.md


+ 1 - 229
Terminal.Gui/MonoCurses/mainloop.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -30,36 +30,7 @@ using System;
 using System.Runtime.InteropServices;
 using System.Threading;
 
-namespace Mono.Terminal {
-
-	/// <summary>
-	/// Public interface to create your own platform specific main loop driver.
-	/// </summary>
-	public interface IMainLoopDriver {
-		/// <summary>
-		/// Initializes the main loop driver, gets the calling main loop for the initialization.
-		/// </summary>
-		/// <param name="mainLoop">Main loop.</param>
-		void Setup (MainLoop mainLoop);
-
-		/// <summary>
-		/// Wakes up the mainloop that might be waiting on input, must be thread safe.
-		/// </summary>
-		void Wakeup ();
-
-		/// <summary>
-		/// Must report whether there are any events pending, or even block waiting for events.
-		/// </summary>
-		/// <returns><c>true</c>, if there were pending events, <c>false</c> otherwise.</returns>
-		/// <param name="wait">If set to <c>true</c> wait until an event is available, otherwise return immediately.</param>
-		bool EventsPending (bool wait);
-
-		/// <summary>
-		/// The interation function.
-		/// </summary>
-		void MainIteration ();
-	}
-
+namespace Terminal.Gui {
 	/// <summary>
 	/// Unix main loop, suitable for using on Posix systems
 	/// </summary>
@@ -323,203 +294,4 @@ namespace Mono.Terminal {
 			}
 		}
 	}
-
-	/// <summary>
-	///   Simple main loop implementation that can be used to monitor
-	///   file descriptor, run timers and idle handlers.
-	/// </summary>
-	/// <remarks>
-	///   Monitoring of file descriptors is only available on Unix, there
-	///   does not seem to be a way of supporting this on Windows.
-	/// </remarks>
-	public class 	MainLoop {
-		internal class Timeout {
-			public TimeSpan Span;
-			public Func<MainLoop,bool> Callback;
-		}
-
-		internal SortedList <long, Timeout> timeouts = new SortedList<long,Timeout> ();
-		internal List<Func<bool>> idleHandlers = new List<Func<bool>> ();
-
-		IMainLoopDriver driver;
-
-		/// <summary>
-		/// The current IMainLoopDriver in use.
-		/// </summary>
-		/// <value>The driver.</value>
-		public IMainLoopDriver Driver => driver;
-
-		/// <summary>
-		///  Creates a new Mainloop, to run it you must provide a driver, and choose
-		///  one of the implementations UnixMainLoop, NetMainLoop or WindowsMainLoop.
-		/// </summary>
-		public MainLoop (IMainLoopDriver driver)
-		{
-			this.driver = driver;
-			driver.Setup (this);
-		}
-
-		/// <summary>
-		///   Runs @action on the thread that is processing events
-		/// </summary>
-		public void Invoke (Action action)
-		{
-			AddIdle (()=> {
-				action ();
-				return false;
-			});
-		}
-
-		/// <summary>
-		///   Executes the specified @idleHandler on the idle loop.  The return value is a token to remove it.
-		/// </summary>
-		public Func<bool> AddIdle (Func<bool> idleHandler)
-		{
-			lock (idleHandlers)
-				idleHandlers.Add (idleHandler);
-
-			return idleHandler;
-		}
-
-		/// <summary>
-		///   Removes the specified idleHandler from processing.
-		/// </summary>
-		public void RemoveIdle (Func<bool> idleHandler)
-		{
-			lock (idleHandler)
-				idleHandlers.Remove (idleHandler);
-		}
-
-		void AddTimeout (TimeSpan time, Timeout timeout)
-		{
-			timeouts.Add ((DateTime.UtcNow + time).Ticks, timeout);
-		}
-
-		/// <summary>
-		///   Adds a timeout to the mainloop.
-		/// </summary>
-		/// <remarks>
-		///   When time time specified passes, the callback will be invoked.
-		///   If the callback returns true, the timeout will be reset, repeating
-		///   the invocation. If it returns false, the timeout will stop.
-		///
-		///   The returned value is a token that can be used to stop the timeout
-		///   by calling RemoveTimeout.
-		/// </remarks>
-		public object AddTimeout (TimeSpan time, Func<MainLoop,bool> callback)
-		{
-			if (callback == null)
-				throw new ArgumentNullException (nameof (callback));
-			var timeout = new Timeout () {
-				Span = time,
-				Callback = callback
-			};
-			AddTimeout (time, timeout);
-			return timeout;
-		}
-
-		/// <summary>
-		///   Removes a previously scheduled timeout
-		/// </summary>
-		/// <remarks>
-		///   The token parameter is the value returned by AddTimeout.
-		/// </remarks>
-		public void RemoveTimeout (object token)
-		{
-			var idx = timeouts.IndexOfValue (token as Timeout);
-			if (idx == -1)
-				return;
-			timeouts.RemoveAt (idx);
-		}
-
-		void RunTimers ()
-		{
-			long now = DateTime.UtcNow.Ticks;
-			var copy = timeouts;
-			timeouts = new SortedList<long,Timeout> ();
-			foreach (var k in copy.Keys){
-				var timeout = copy [k];
-				if (k < now) {
-					if (timeout.Callback (this))
-						AddTimeout (timeout.Span, timeout);
-				} else
-					timeouts.Add (k, timeout);
-			}
-		}
-
-		void RunIdle ()
-		{
-			List<Func<bool>> iterate;
-			lock (idleHandlers){
-				iterate = idleHandlers;
-				idleHandlers = new List<Func<bool>> ();
-			}
-
-			foreach (var idle in iterate){
-				if (idle ())
-					lock (idleHandlers)
-						idleHandlers.Add (idle);
-			}
-		}
-
-		bool running;
-
-		/// <summary>
-		///   Stops the mainloop.
-		/// </summary>
-		public void Stop ()
-		{
-			running = false;
-			driver.Wakeup ();
-		}
-
-		/// <summary>
-		///   Determines whether there are pending events to be processed.
-		/// </summary>
-		/// <remarks>
-		///   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.
-		/// </remarks>
-		public bool EventsPending (bool wait = false)
-		{
-			return driver.EventsPending (wait);
-		}
-
-		/// <summary>
-		///   Runs one iteration of timers and file watches
-		/// </summary>
-		/// <remarks>
-		///   You use this to process all pending events (timers, idle handlers and file watches).
-		///
-		///   You can use it like this:
-		///     while (main.EvensPending ()) MainIteration ();
-		/// </remarks>
-		public void MainIteration ()
-		{
-			if (timeouts.Count > 0)
-				RunTimers ();
-
-			driver.MainIteration ();
-
-			lock (idleHandlers){
-				if (idleHandlers.Count > 0)
-					RunIdle();
-			}
-		}
-
-		/// <summary>
-		///   Runs the mainloop.
-		/// </summary>
-		public void Run ()
-		{
-			bool prev = running;
-			running = true;
-			while (running){
-				EventsPending (true);
-				MainIteration ();
-			}
-			running = prev;
-		}
-	}
 }

+ 1 - 1
Terminal.Gui/MonoCurses/UnmanagedLibrary.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs

@@ -23,7 +23,7 @@ using System.Threading;
 
 
 
-namespace Mono.Terminal.Internal {
+namespace Unix.Terminal {
 	/// <summary>
 	/// Represents a dynamically loaded unmanaged library in a (partially) platform independent manner.
 	/// First, the native library is loaded using dlopen (on Unix systems) or using LoadLibrary (on Windows).

+ 0 - 1
Terminal.Gui/MonoCurses/binding.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -44,7 +44,6 @@
 using System;
 using System.IO;
 using System.Runtime.InteropServices;
-using Mono.Terminal.Internal;
 
 namespace Unix.Terminal {
 #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

+ 0 - 0
Terminal.Gui/MonoCurses/constants.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/constants.cs


+ 0 - 0
Terminal.Gui/MonoCurses/handles.cs → Terminal.Gui/ConsoleDrivers/CursesDriver/handles.cs


+ 0 - 1
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -7,7 +7,6 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using Mono.Terminal;
 using NStack;
 
 namespace Terminal.Gui {

+ 1 - 2
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -31,7 +31,6 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
-using Mono.Terminal;
 using NStack;
 
 namespace Terminal.Gui {
@@ -425,7 +424,7 @@ namespace Terminal.Gui {
 		}
 	}
 
-	internal class WindowsDriver : ConsoleDriver, Mono.Terminal.IMainLoopDriver {
+	internal class WindowsDriver : ConsoleDriver, IMainLoopDriver {
 		static bool sync = false;
 		ManualResetEventSlim eventReady = new ManualResetEventSlim (false);
 		ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);

+ 1 - 6
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs → Terminal.Gui/Core/ConsoleDriver.cs

@@ -4,14 +4,9 @@
 // Authors:
 //   Miguel de Icaza ([email protected])
 //
+using NStack;
 using System;
-using System.Collections.Generic;
 using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography;
-using Mono.Terminal;
-using NStack;
-using Unix.Terminal;
 
 namespace Terminal.Gui {
 

+ 7 - 7
Terminal.Gui/Core.cs → Terminal.Gui/Core/Core.cs

@@ -2039,7 +2039,7 @@ namespace Terminal.Gui {
 		/// The <see cref="MainLoop"/>  driver for the applicaiton
 		/// </summary>
 		/// <value>The main loop.</value>
-		public static Mono.Terminal.MainLoop MainLoop { get; private set; }
+		public static MainLoop MainLoop { get; private set; }
 
 		static Stack<Toplevel> toplevels = new Stack<Toplevel> ();
 
@@ -2066,9 +2066,9 @@ namespace Terminal.Gui {
 		// users use async/await on their code
 		//
 		class MainLoopSyncContext : SynchronizationContext {
-			Mono.Terminal.MainLoop mainLoop;
+			MainLoop mainLoop;
 
-			public MainLoopSyncContext (Mono.Terminal.MainLoop mainLoop)
+			public MainLoopSyncContext (MainLoop mainLoop)
 			{
 				this.mainLoop = mainLoop;
 			}
@@ -2127,21 +2127,21 @@ namespace Terminal.Gui {
 
 			if (Driver == null) {
 				var p = Environment.OSVersion.Platform;
-				Mono.Terminal.IMainLoopDriver mainLoopDriver;
+				IMainLoopDriver mainLoopDriver;
 
 				if (UseSystemConsole) {
-					mainLoopDriver = new Mono.Terminal.NetMainLoop ();
+					mainLoopDriver = new NetMainLoop ();
 					Driver = new NetDriver ();
 				} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
 					var windowsDriver = new WindowsDriver ();
 					mainLoopDriver = windowsDriver;
 					Driver = windowsDriver;
 				} else {
-					mainLoopDriver = new Mono.Terminal.UnixMainLoop ();
+					mainLoopDriver = new UnixMainLoop ();
 					Driver = new CursesDriver ();
 				}
 				Driver.Init (TerminalResized);
-				MainLoop = new Mono.Terminal.MainLoop (mainLoopDriver);
+				MainLoop = new MainLoop (mainLoopDriver);
 				SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop));
 			}
 			Top = topLevelFactory ();

+ 0 - 0
Terminal.Gui/Event.cs → Terminal.Gui/Core/Event.cs


+ 233 - 0
Terminal.Gui/Core/MainLoop.cs

@@ -0,0 +1,233 @@
+
+using System;
+using System.Collections.Generic;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Public interface to create your own platform specific main loop driver.
+	/// </summary>
+	public interface IMainLoopDriver {
+		/// <summary>
+		/// Initializes the main loop driver, gets the calling main loop for the initialization.
+		/// </summary>
+		/// <param name="mainLoop">Main loop.</param>
+		void Setup (MainLoop mainLoop);
+
+		/// <summary>
+		/// Wakes up the mainloop that might be waiting on input, must be thread safe.
+		/// </summary>
+		void Wakeup ();
+
+		/// <summary>
+		/// Must report whether there are any events pending, or even block waiting for events.
+		/// </summary>
+		/// <returns><c>true</c>, if there were pending events, <c>false</c> otherwise.</returns>
+		/// <param name="wait">If set to <c>true</c> wait until an event is available, otherwise return immediately.</param>
+		bool EventsPending (bool wait);
+
+		/// <summary>
+		/// The interation function.
+		/// </summary>
+		void MainIteration ();
+	}
+
+	/// <summary>
+	///   Simple main loop implementation that can be used to monitor
+	///   file descriptor, run timers and idle handlers.
+	/// </summary>
+	/// <remarks>
+	///   Monitoring of file descriptors is only available on Unix, there
+	///   does not seem to be a way of supporting this on Windows.
+	/// </remarks>
+	public class MainLoop {
+		internal class Timeout {
+			public TimeSpan Span;
+			public Func<MainLoop, bool> Callback;
+		}
+
+		internal SortedList<long, Timeout> timeouts = new SortedList<long, Timeout> ();
+		internal List<Func<bool>> idleHandlers = new List<Func<bool>> ();
+
+		IMainLoopDriver driver;
+
+		/// <summary>
+		/// The current IMainLoopDriver in use.
+		/// </summary>
+		/// <value>The driver.</value>
+		public IMainLoopDriver Driver => driver;
+
+		/// <summary>
+		///  Creates a new Mainloop, to run it you must provide a driver, and choose
+		///  one of the implementations UnixMainLoop, NetMainLoop or WindowsMainLoop.
+		/// </summary>
+		public MainLoop (IMainLoopDriver driver)
+		{
+			this.driver = driver;
+			driver.Setup (this);
+		}
+
+		/// <summary>
+		///   Runs @action on the thread that is processing events
+		/// </summary>
+		public void Invoke (Action action)
+		{
+			AddIdle (() => {
+				action ();
+				return false;
+			});
+		}
+
+		/// <summary>
+		///   Executes the specified @idleHandler on the idle loop.  The return value is a token to remove it.
+		/// </summary>
+		public Func<bool> AddIdle (Func<bool> idleHandler)
+		{
+			lock (idleHandlers)
+				idleHandlers.Add (idleHandler);
+
+			return idleHandler;
+		}
+
+		/// <summary>
+		///   Removes the specified idleHandler from processing.
+		/// </summary>
+		public void RemoveIdle (Func<bool> idleHandler)
+		{
+			lock (idleHandler)
+				idleHandlers.Remove (idleHandler);
+		}
+
+		void AddTimeout (TimeSpan time, Timeout timeout)
+		{
+			timeouts.Add ((DateTime.UtcNow + time).Ticks, timeout);
+		}
+
+		/// <summary>
+		///   Adds a timeout to the mainloop.
+		/// </summary>
+		/// <remarks>
+		///   When time time specified passes, the callback will be invoked.
+		///   If the callback returns true, the timeout will be reset, repeating
+		///   the invocation. If it returns false, the timeout will stop.
+		///
+		///   The returned value is a token that can be used to stop the timeout
+		///   by calling RemoveTimeout.
+		/// </remarks>
+		public object AddTimeout (TimeSpan time, Func<MainLoop, bool> callback)
+		{
+			if (callback == null)
+				throw new ArgumentNullException (nameof (callback));
+			var timeout = new Timeout () {
+				Span = time,
+				Callback = callback
+			};
+			AddTimeout (time, timeout);
+			return timeout;
+		}
+
+		/// <summary>
+		///   Removes a previously scheduled timeout
+		/// </summary>
+		/// <remarks>
+		///   The token parameter is the value returned by AddTimeout.
+		/// </remarks>
+		public void RemoveTimeout (object token)
+		{
+			var idx = timeouts.IndexOfValue (token as Timeout);
+			if (idx == -1)
+				return;
+			timeouts.RemoveAt (idx);
+		}
+
+		void RunTimers ()
+		{
+			long now = DateTime.UtcNow.Ticks;
+			var copy = timeouts;
+			timeouts = new SortedList<long, Timeout> ();
+			foreach (var k in copy.Keys) {
+				var timeout = copy [k];
+				if (k < now) {
+					if (timeout.Callback (this))
+						AddTimeout (timeout.Span, timeout);
+				} else
+					timeouts.Add (k, timeout);
+			}
+		}
+
+		void RunIdle ()
+		{
+			List<Func<bool>> iterate;
+			lock (idleHandlers) {
+				iterate = idleHandlers;
+				idleHandlers = new List<Func<bool>> ();
+			}
+
+			foreach (var idle in iterate) {
+				if (idle ())
+					lock (idleHandlers)
+						idleHandlers.Add (idle);
+			}
+		}
+
+		bool running;
+
+		/// <summary>
+		///   Stops the mainloop.
+		/// </summary>
+		public void Stop ()
+		{
+			running = false;
+			driver.Wakeup ();
+		}
+
+		/// <summary>
+		///   Determines whether there are pending events to be processed.
+		/// </summary>
+		/// <remarks>
+		///   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.
+		/// </remarks>
+		public bool EventsPending (bool wait = false)
+		{
+			return driver.EventsPending (wait);
+		}
+
+		/// <summary>
+		///   Runs one iteration of timers and file watches
+		/// </summary>
+		/// <remarks>
+		///   You use this to process all pending events (timers, idle handlers and file watches).
+		///
+		///   You can use it like this:
+		///     while (main.EvensPending ()) MainIteration ();
+		/// </remarks>
+		public void MainIteration ()
+		{
+			if (timeouts.Count > 0)
+				RunTimers ();
+
+			driver.MainIteration ();
+
+			lock (idleHandlers) {
+				if (idleHandlers.Count > 0)
+					RunIdle ();
+			}
+		}
+
+		/// <summary>
+		///   Runs the mainloop.
+		/// </summary>
+		public void Run ()
+		{
+			bool prev = running;
+			running = true;
+			while (running) {
+				EventsPending (true);
+				MainIteration ();
+			}
+			running = prev;
+		}
+	}
+}