From 64b216b1e861d0c08b706dfa0dafffedf6fd289d Mon Sep 17 00:00:00 2001 From: Thomas Nind <31306100+tznind@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:57:28 +0000 Subject: [PATCH] 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 --- .../ConsoleDrivers/V2/ApplicationV2.cs | 3 + .../ConsoleDrivers/V2/MainLoopCoordinator.cs | 3 +- .../ConsoleDrivers/V2/ApplicationV2Tests.cs | 63 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs b/Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs index 36cd6a62c..41e0a5b4b 100644 --- a/Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs +++ b/Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs @@ -77,6 +77,9 @@ public class ApplicationV2 : ApplicationImpl Application.OnInitializedChanged (this, new (true)); Application.SubscribeDriverEvents (); + + SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ()); + Application.MainThreadId = Thread.CurrentThread.ManagedThreadId; } private void CreateDriver (string? driverName) diff --git a/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs b/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs index 28bad67ab..2effde3b7 100644 --- a/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs +++ b/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs @@ -78,7 +78,8 @@ internal class MainLoopCoordinator : IMainLoopCoordinator Task waitForSemaphore = _startupSemaphore.WaitAsync (); // 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. if (completedTask == _inputTask) diff --git a/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs b/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs index 1afd36784..ed1185b38 100644 --- a/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs +++ b/UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs @@ -284,4 +284,67 @@ public class ApplicationV2Tests 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); + } }