Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/guiunit.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ward <matt.ward@microsoft.com>2021-02-24 01:11:58 +0300
committerMatt Ward <matt.ward@microsoft.com>2021-02-24 01:11:58 +0300
commitd0821012bf30ce2771d1bc878a34f6bd555b00ba (patch)
treefb2ad925057fd507a41e807aeb63039299e3916b
parent1d3cd2d05a062f41de07c397a187537bcad81370 (diff)
HACK: Add support for a console main loop
No way to currently run tests that require a UI main loop with XWT or Xamarin.Mac on .NET 6. Added a temporary hack that adds a console based main loop, using a queue, and also registers a SynchronisationContext with the same loop with MonoDevelop.Core.Runtime. This prevents tests in MonoDevelop.Core hanging waiting for tasks to complete on the UI thread.
-rw-r--r--src/framework/GuiUnit/TestRunner.cs1
-rw-r--r--src/framework/GuiUnit/XwtMainLoopIntegration.cs117
2 files changed, 118 insertions, 0 deletions
diff --git a/src/framework/GuiUnit/TestRunner.cs b/src/framework/GuiUnit/TestRunner.cs
index 3950cf3..7719fd4 100644
--- a/src/framework/GuiUnit/TestRunner.cs
+++ b/src/framework/GuiUnit/TestRunner.cs
@@ -59,6 +59,7 @@ namespace GuiUnit
try { mainLoop = mainLoop ?? new XwtMainLoopIntegration (); } catch { }
try { mainLoop = mainLoop ?? new MonoMacMainLoopIntegration (); } catch { }
try { mainLoop = mainLoop ?? new GtkMainLoopIntegration (); } catch { }
+ mainLoop = mainLoop ?? new ConsoleMainLoop ();
return mainLoop;
} set {
mainLoop = value;
diff --git a/src/framework/GuiUnit/XwtMainLoopIntegration.cs b/src/framework/GuiUnit/XwtMainLoopIntegration.cs
index 5d20936..7a74842 100644
--- a/src/framework/GuiUnit/XwtMainLoopIntegration.cs
+++ b/src/framework/GuiUnit/XwtMainLoopIntegration.cs
@@ -73,5 +73,122 @@ namespace GuiUnit
Application.GetMethod ("Exit").Invoke (null, null);
}
}
+
+ class ConsoleMainLoop : System.Threading.SynchronizationContext, IMainLoopIntegration
+ {
+ System.Collections.Generic.Queue<InvokerHelper> work =
+ new System.Collections.Generic.Queue<InvokerHelper>();
+
+ System.Collections.Generic.Queue<Tuple<System.Threading.SendOrPostCallback, object>> contextWork =
+ new System.Collections.Generic.Queue<Tuple<System.Threading.SendOrPostCallback, object>>();
+
+ bool endLoop;
+
+ public void InitializeToolkit()
+ {
+ var runtime = Type.GetType("MonoDevelop.Core.Runtime, MonoDevelop.Core");
+ if (runtime == null)
+ return;
+
+ var property = runtime.GetProperty ("MainSynchronizationContext", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+ if (property == null)
+ return;
+
+ System.Threading.SynchronizationContext.SetSynchronizationContext(this);
+ property.SetValue (null, System.Threading.SynchronizationContext.Current);
+ }
+
+ public void InvokeOnMainLoop (InvokerHelper helper)
+ {
+ lock (work)
+ {
+ work.Enqueue (helper);
+ System.Threading.Monitor.Pulse (work);
+ }
+ }
+
+ public void RunMainLoop ()
+ {
+ do
+ {
+ InvokerHelper next = null;
+ Tuple<System.Threading.SendOrPostCallback, object> nextContext = null;
+ lock (work)
+ {
+ if (work.Count > 0 && !endLoop)
+ next = work.Dequeue ();
+ else if (contextWork.Count > 0 && !endLoop)
+ nextContext = contextWork.Dequeue ();
+ else if (!endLoop)
+ System.Threading.Monitor.Wait (work);
+ }
+ if (next != null)
+ {
+ try
+ {
+ next.Invoke ();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine (ex);
+ }
+ }
+ if (nextContext != null)
+ {
+ try
+ {
+ nextContext.Item1(nextContext.Item2);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+ }
+ } while (!endLoop);
+ }
+
+ public void Shutdown ()
+ {
+ lock (work)
+ {
+ endLoop = true;
+ System.Threading.Monitor.Pulse (work);
+ }
+ }
+
+ public override void Post (System.Threading.SendOrPostCallback d, object state)
+ {
+ lock (work)
+ {
+ contextWork.Enqueue (new Tuple<System.Threading.SendOrPostCallback, object>(d, state));
+ System.Threading.Monitor.Pulse (work);
+ }
+ }
+
+ public override void Send (System.Threading.SendOrPostCallback d, object state)
+ {
+ var evt = new System.Threading.ManualResetEventSlim (false);
+ Exception exception = null;
+ Post (s =>
+ {
+ try
+ {
+ d.Invoke (state);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ }
+ finally
+ {
+ System.Threading.Thread.MemoryBarrier ();
+ evt.Set ();
+ }
+ }, null);
+ evt.Wait ();
+ if (exception != null)
+ throw exception;
+ }
+ }
}