Browse Source

Introduced GtkInteropHelper.RunOnGlibThread, fixed demos

Nikita Tsukanov 3 years ago
parent
commit
fa17ee9bb9

+ 1 - 2
samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs

@@ -22,8 +22,7 @@ public class EmbedSampleGtk : INativeDemoControl
 
         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}\"")
         {

+ 2 - 7
samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs

@@ -2,6 +2,7 @@ using System;
 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<bool> s_gtkTask;
-
     class FileChooser : INativeControlHostDestroyableControlHandle
     {
         private readonly IntPtr _widget;
@@ -38,11 +37,7 @@ internal class GtkHelper
 
     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"))
             {

+ 15 - 0
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<T> RunOnGlibThread<T>(Func<T> cb)
+    {
+        if (!await NativeDialogs.Gtk.StartGtk().ConfigureAwait(false))
+            throw new Win32Exception("Unable to initialize GTK");
+        return await NativeDialogs.Glib.RunOnGlibThread(cb).ConfigureAwait(false);
+    }
+}

+ 24 - 3
src/Avalonia.X11/NativeDialogs/Gtk.cs

@@ -3,6 +3,8 @@ using System.Runtime.InteropServices;
 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 @@ namespace Avalonia.X11.NativeDialogs
 
         public static IntPtr GetForeignWindow(IntPtr xid) => gdk_x11_window_foreign_new_for_display(s_display, xid);
 
+        static object s_startGtkLock = new();
+        static Task<bool> s_startGtkTask;
+
         public static Task<bool> StartGtk()
         {
-            var tcs = new TaskCompletionSource<bool>();
-            new Thread(() =>
+            return StartGtkCore();
+            lock (s_startGtkLock)
+                return s_startGtkTask ??= StartGtkCore();
+        }
+
+        private static void GtkThread(TaskCompletionSource<bool> tcs)
+        {
+            try
             {
                 try
                 {
@@ -293,7 +304,17 @@ namespace Avalonia.X11.NativeDialogs
                 tcs.SetResult(true);
                 while (true)
                     gtk_main_iteration();
-            }) {Name = "GTK3THREAD", IsBackground = true}.Start();
+            }
+            catch
+            {
+                tcs.SetResult(false);
+            }
+        }
+        
+        private static Task<bool> StartGtkCore()
+        {
+            var tcs = new TaskCompletionSource<bool>();
+            new Thread(() => GtkThread(tcs)) {Name = "GTK3THREAD", IsBackground = true}.Start();
             return tcs.Task;
         }
     }