From fa17ee9bb991cc0b49326ea7b217daa12baefad2 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 18 Jul 2022 15:48:07 +0300 Subject: [PATCH] Introduced GtkInteropHelper.RunOnGlibThread, fixed demos --- .../NativeControls/Gtk/EmbedSample.Gtk.cs | 3 +-- .../NativeControls/Gtk/GtkHelper.cs | 9 ++----- src/Avalonia.X11/Interop/GtkInteropHelper.cs | 15 +++++++++++ src/Avalonia.X11/NativeDialogs/Gtk.cs | 27 ++++++++++++++++--- 4 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 src/Avalonia.X11/Interop/GtkInteropHelper.cs diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs index 521d3674eb9..81a5ba536fe 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs @@ -22,8 +22,7 @@ public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func var control = createDefault(); var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, - "..", - "nodes.mp4")); + "..", "NativeControls", "Gtk", "nodes.mp4")); _mplayer = Process.Start(new ProcessStartInfo("mplayer", $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") { diff --git a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs index 456f77a44d6..b1fef7c013d 100644 --- a/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Avalonia.Controls.Platform; using Avalonia.Platform.Interop; +using Avalonia.X11.Interop; using Avalonia.X11.NativeDialogs; using static Avalonia.X11.NativeDialogs.Gtk; using static Avalonia.X11.NativeDialogs.Glib; @@ -10,8 +11,6 @@ namespace ControlCatalog.NetCore; internal class GtkHelper { - private static Task s_gtkTask; - class FileChooser : INativeControlHostDestroyableControlHandle { private readonly IntPtr _widget; @@ -38,11 +37,7 @@ public void Destroy() public static INativeControlHostDestroyableControlHandle CreateGtkFileChooser(IntPtr parentXid) { - if (s_gtkTask == null) - s_gtkTask = StartGtk(); - if (!s_gtkTask.Result) - return null; - return RunOnGlibThread(() => + return GtkInteropHelper.RunOnGlibThread(() => { using (var title = new Utf8Buffer("Embedded")) { diff --git a/src/Avalonia.X11/Interop/GtkInteropHelper.cs b/src/Avalonia.X11/Interop/GtkInteropHelper.cs new file mode 100644 index 00000000000..de0b7558327 --- /dev/null +++ b/src/Avalonia.X11/Interop/GtkInteropHelper.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; + +namespace Avalonia.X11.Interop; + +public class GtkInteropHelper +{ + public static async Task RunOnGlibThread(Func cb) + { + if (!await NativeDialogs.Gtk.StartGtk().ConfigureAwait(false)) + throw new Win32Exception("Unable to initialize GTK"); + return await NativeDialogs.Glib.RunOnGlibThread(cb).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs index 8e2d920bc76..c9e482db86d 100644 --- a/src/Avalonia.X11/NativeDialogs/Gtk.cs +++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs @@ -3,6 +3,8 @@ using System.Threading; using System.Threading.Tasks; using Avalonia.Platform.Interop; +using JetBrains.Annotations; + // ReSharper disable IdentifierTypo namespace Avalonia.X11.NativeDialogs { @@ -256,10 +258,19 @@ public static extern void public static IntPtr GetForeignWindow(IntPtr xid) => gdk_x11_window_foreign_new_for_display(s_display, xid); + static object s_startGtkLock = new(); + static Task s_startGtkTask; + public static Task StartGtk() { - var tcs = new TaskCompletionSource(); - new Thread(() => + return StartGtkCore(); + lock (s_startGtkLock) + return s_startGtkTask ??= StartGtkCore(); + } + + private static void GtkThread(TaskCompletionSource tcs) + { + try { try { @@ -293,7 +304,17 @@ public static Task StartGtk() tcs.SetResult(true); while (true) gtk_main_iteration(); - }) {Name = "GTK3THREAD", IsBackground = true}.Start(); + } + catch + { + tcs.SetResult(false); + } + } + + private static Task StartGtkCore() + { + var tcs = new TaskCompletionSource(); + new Thread(() => GtkThread(tcs)) {Name = "GTK3THREAD", IsBackground = true}.Start(); return tcs.Task; } }