Skip to content

Commit 64b216b

Browse files
tznindtig
andauthored
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>
1 parent 72aaf27 commit 64b216b

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed

Terminal.Gui/ConsoleDrivers/V2/ApplicationV2.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ public override void Init (IConsoleDriver? driver = null, string? driverName = n
7777

7878
Application.OnInitializedChanged (this, new (true));
7979
Application.SubscribeDriverEvents ();
80+
81+
SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
82+
Application.MainThreadId = Thread.CurrentThread.ManagedThreadId;
8083
}
8184

8285
private void CreateDriver (string? driverName)

Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ public async Task StartAsync ()
7878
Task waitForSemaphore = _startupSemaphore.WaitAsync ();
7979

8080
// Wait for either the semaphore to be released or the input task to crash.
81-
Task completedTask = await Task.WhenAny (waitForSemaphore, _inputTask).ConfigureAwait (false);
81+
// ReSharper disable once UseConfigureAwaitFalse
82+
Task completedTask = await Task.WhenAny (waitForSemaphore, _inputTask);
8283

8384
// Check if the task was the input task and if it has failed.
8485
if (completedTask == _inputTask)

UnitTests/ConsoleDrivers/V2/ApplicationV2Tests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,67 @@ public void TestRepeatedInitCalls_WarnsAndIgnores ()
284284
Logging.Logger = beforeLogger;
285285
}
286286

287+
[Fact]
288+
public void Test_Open_CallsContinueWithOnUIThread ()
289+
{
290+
var orig = ApplicationImpl.Instance;
291+
292+
var v2 = NewApplicationV2 ();
293+
ApplicationImpl.ChangeInstance (v2);
294+
295+
v2.Init ();
296+
var b = new Button ();
297+
298+
bool result = false;
299+
300+
b.Accepting +=
301+
(_,_) =>
302+
{
303+
304+
Task.Run (() =>
305+
{
306+
Task.Delay (300).Wait ();
307+
}).ContinueWith (
308+
(t, _) =>
309+
{
310+
// no longer loading
311+
Application.Invoke (() =>
312+
{
313+
result = true;
314+
Application.RequestStop ();
315+
});
316+
},
317+
TaskScheduler.FromCurrentSynchronizationContext ());
318+
};
319+
320+
v2.AddTimeout (TimeSpan.FromMilliseconds (150),
321+
()=>
322+
{
323+
// Run asynchronous logic inside Task.Run
324+
if (Application.Top != null)
325+
{
326+
b.NewKeyDownEvent (Key.Enter);
327+
b.NewKeyUpEvent (Key.Enter);
328+
329+
return false;
330+
}
331+
332+
return true;
333+
});
334+
335+
Assert.Null (Application.Top);
336+
337+
var w = new Window ();
338+
w.Add (b);
339+
340+
// Blocks until the timeout call is hit
341+
v2.Run (w);
342+
343+
Assert.Null (Application.Top);
344+
v2.Shutdown ();
345+
346+
ApplicationImpl.ChangeInstance (orig);
347+
348+
Assert.True (result);
349+
}
287350
}

0 commit comments

Comments
 (0)