Преглед изворни кода

Fixes #3953 Add async support to v2 drivers (#3952)

* Add async support stuff

* Set main thread id

* Add v2 test to ensure `TaskScheduler.FromCurrentSynchronizationContext` works

* Remove uneeded async

---------

Co-authored-by: Tig <[email protected]>
Thomas Nind пре 4 месеци
родитељ
комит
64b216b1e8

+ 3 - 0
Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs

@@ -77,6 +77,9 @@ public class ApplicationV2 : ApplicationImpl
 
 
         Application.OnInitializedChanged (this, new (true));
         Application.OnInitializedChanged (this, new (true));
         Application.SubscribeDriverEvents ();
         Application.SubscribeDriverEvents ();
+
+        SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
+        Application.MainThreadId = Thread.CurrentThread.ManagedThreadId;
     }
     }
 
 
     private void CreateDriver (string? driverName)
     private void CreateDriver (string? driverName)

+ 2 - 1
Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs

@@ -78,7 +78,8 @@ internal class MainLoopCoordinator<T> : IMainLoopCoordinator
         Task waitForSemaphore = _startupSemaphore.WaitAsync ();
         Task waitForSemaphore = _startupSemaphore.WaitAsync ();
 
 
         // Wait for either the semaphore to be released or the input task to crash.
         // Wait for either the semaphore to be released or the input task to crash.
-        Task completedTask = await Task.WhenAny (waitForSemaphore, _inputTask).ConfigureAwait (false);
+        // ReSharper disable once UseConfigureAwaitFalse
+        Task completedTask = await Task.WhenAny (waitForSemaphore, _inputTask);
 
 
         // Check if the task was the input task and if it has failed.
         // Check if the task was the input task and if it has failed.
         if (completedTask == _inputTask)
         if (completedTask == _inputTask)

+ 63 - 0
UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs

@@ -284,4 +284,67 @@ public class ApplicationV2Tests
         Logging.Logger = beforeLogger;
         Logging.Logger = beforeLogger;
     }
     }
 
 
+    [Fact]
+    public void Test_Open_CallsContinueWithOnUIThread ()
+    {
+        var orig = ApplicationImpl.Instance;
+
+        var v2 = NewApplicationV2 ();
+        ApplicationImpl.ChangeInstance (v2);
+
+        v2.Init ();
+        var b = new Button ();
+
+        bool result = false;
+
+        b.Accepting +=
+            (_,_) =>
+            {
+
+                Task.Run (() =>
+                          {
+                              Task.Delay (300).Wait ();
+                          }).ContinueWith (
+                                           (t, _) =>
+                                           {
+                                               // no longer loading
+                                               Application.Invoke (() =>
+                                                                   {
+                                                                       result = true;
+                                                                       Application.RequestStop ();
+                                                                   });
+                                           },
+                                           TaskScheduler.FromCurrentSynchronizationContext ());
+            };
+
+        v2.AddTimeout (TimeSpan.FromMilliseconds (150),
+                                          ()=>
+                                          {
+                                              // Run asynchronous logic inside Task.Run
+                                              if (Application.Top != null)
+                                              {
+                                                  b.NewKeyDownEvent (Key.Enter);
+                                                  b.NewKeyUpEvent (Key.Enter);
+
+                                                  return false;
+                                              }
+
+                                              return true;
+                                          });
+
+        Assert.Null (Application.Top);
+
+        var w = new Window ();
+        w.Add (b);
+
+        // Blocks until the timeout call is hit
+        v2.Run (w);
+
+        Assert.Null (Application.Top);
+        v2.Shutdown ();
+
+        ApplicationImpl.ChangeInstance (orig);
+
+        Assert.True (result);
+    }
 }
 }