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 <tig@users.noreply.github.com>
This commit is contained in:
Thomas Nind
2025-03-02 17:57:28 +00:00
committed by GitHub
parent 72aaf27f91
commit 64b216b1e8
3 changed files with 68 additions and 1 deletions

View File

@@ -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)

View File

@@ -78,7 +78,8 @@ internal class MainLoopCoordinator<T> : 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)

View File

@@ -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);
}
}