|
|
@@ -1,10 +1,12 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
using System.Linq;
|
|
|
using System.Reflection;
|
|
|
using System.Runtime.InteropServices;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
+using Avalonia.Platform;
|
|
|
|
|
|
namespace Avalonia.Gtk3.Interop
|
|
|
{
|
|
|
@@ -22,64 +24,108 @@ namespace Avalonia.Gtk3.Interop
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- internal enum GtkDll
|
|
|
+ public enum GtkDll
|
|
|
{
|
|
|
Gdk,
|
|
|
Gtk,
|
|
|
Glib,
|
|
|
Gio,
|
|
|
- Gobject
|
|
|
+ Gobject,
|
|
|
+ Cairo
|
|
|
}
|
|
|
|
|
|
static class Resolver
|
|
|
{
|
|
|
- [DllImport("kernel32.dll")]
|
|
|
- static extern int GetVersion();
|
|
|
+ private static Lazy<OperatingSystemType> Platform =
|
|
|
+ new Lazy<OperatingSystemType>(
|
|
|
+ () => AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem);
|
|
|
|
|
|
- static bool IsWin32()
|
|
|
+ public static ICustomGtk3NativeLibraryResolver Custom { get; set; }
|
|
|
+
|
|
|
+
|
|
|
+ static string FormatName(string name, int version = 0)
|
|
|
+ {
|
|
|
+ if (Platform.Value == OperatingSystemType.WinNT)
|
|
|
+ return "lib" + name + "-" + version + ".dll";
|
|
|
+ if (Platform.Value == OperatingSystemType.Linux)
|
|
|
+ return "lib" + name + ".so" + "." + version;
|
|
|
+ if (Platform.Value == OperatingSystemType.OSX)
|
|
|
+ return "lib" + name + "." + version + ".dylib";
|
|
|
+ throw new Exception("Unknown platform, use custom name resolver");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ static string GetDllName(GtkDll dll)
|
|
|
{
|
|
|
+ var name = Custom?.GetName(dll);
|
|
|
+ if (name != null)
|
|
|
+ return name;
|
|
|
+
|
|
|
+ switch (dll)
|
|
|
+ {
|
|
|
+ case GtkDll.Cairo:
|
|
|
+ return FormatName("cairo", 2);
|
|
|
+ case GtkDll.Gdk:
|
|
|
+ return FormatName("gdk-3");
|
|
|
+ case GtkDll.Glib:
|
|
|
+ return FormatName("glib-2.0");
|
|
|
+ case GtkDll.Gio:
|
|
|
+ return FormatName("gio-2.0");
|
|
|
+ case GtkDll.Gtk:
|
|
|
+ return FormatName("gtk-3");
|
|
|
+ case GtkDll.Gobject:
|
|
|
+ return FormatName("gobject-2.0");
|
|
|
+ default:
|
|
|
+ throw new ArgumentException("Unknown lib: " + dll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static IntPtr LoadDll(IDynLoader loader, GtkDll dll)
|
|
|
+ {
|
|
|
+
|
|
|
+ var exceptions = new List<Exception>();
|
|
|
+
|
|
|
+ var name = GetDllName(dll);
|
|
|
+ if (Custom?.TrySystemFirst != false)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ return loader.LoadLibrary(name);
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ exceptions.Add(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var path = Custom?.Lookup(dll);
|
|
|
+ if (path == null && Custom?.BasePath != null)
|
|
|
+ path = Path.Combine(Custom.BasePath, name);
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
- GetVersion();
|
|
|
- return true;
|
|
|
+ return loader.LoadLibrary(path);
|
|
|
}
|
|
|
- catch
|
|
|
+ catch (Exception e)
|
|
|
{
|
|
|
- return false;
|
|
|
+ exceptions.Add(e);
|
|
|
}
|
|
|
+ throw new AggregateException("Unable to load " + dll, exceptions);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
public static void Resolve(string basePath = null)
|
|
|
{
|
|
|
- var loader = IsWin32() ? (IDynLoader)new Win32Loader() : new UnixLoader();
|
|
|
-
|
|
|
+ var loader = Platform.Value == OperatingSystemType.WinNT ? (IDynLoader)new Win32Loader() : new UnixLoader();
|
|
|
|
|
|
- var gdk = loader.LoadLibrary(basePath, "libgdk-3");
|
|
|
- var gtk = loader.LoadLibrary(basePath, "libgtk-3");
|
|
|
- var gio = loader.LoadLibrary(basePath, "libgio-2.0");
|
|
|
- var glib = loader.LoadLibrary(basePath, "libglib-2.0");
|
|
|
- var gobject = loader.LoadLibrary(basePath, "libgobject-2.0");
|
|
|
+ var dlls = Enum.GetValues(typeof(GtkDll)).Cast<GtkDll>().ToDictionary(x => x, x => LoadDll(loader, x));
|
|
|
+
|
|
|
foreach (var fieldInfo in typeof(Native).GetTypeInfo().DeclaredFields)
|
|
|
{
|
|
|
var import = fieldInfo.FieldType.GetTypeInfo().GetCustomAttributes(typeof(GtkImportAttribute), true).Cast<GtkImportAttribute>().FirstOrDefault();
|
|
|
if(import == null)
|
|
|
continue;
|
|
|
- IntPtr lib;
|
|
|
- if (import.Dll == GtkDll.Gtk)
|
|
|
- lib = gtk;
|
|
|
- else if (import.Dll == GtkDll.Gdk)
|
|
|
- lib = gdk;
|
|
|
- else if (import.Dll == GtkDll.Gio)
|
|
|
- lib = gio;
|
|
|
- else if (import.Dll == GtkDll.Glib)
|
|
|
- lib = glib;
|
|
|
- else if (import.Dll == GtkDll.Gobject)
|
|
|
- lib = gobject;
|
|
|
- else
|
|
|
- throw new ArgumentException("Invalid GtkImportAttribute for " + fieldInfo.FieldType);
|
|
|
-
|
|
|
+ IntPtr lib = dlls[import.Dll];
|
|
|
+
|
|
|
var funcPtr = loader.GetProcAddress(lib, import.Name ?? fieldInfo.FieldType.Name);
|
|
|
fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType));
|
|
|
}
|
|
|
@@ -90,7 +136,7 @@ namespace Avalonia.Gtk3.Interop
|
|
|
try
|
|
|
{
|
|
|
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle)Marshal
|
|
|
- .GetDelegateForFunctionPointer(loader.GetProcAddress(gdk, name), typeof(Native.D.gdk_get_native_handle));
|
|
|
+ .GetDelegateForFunctionPointer(loader.GetProcAddress(dlls[GtkDll.Gdk], name), typeof(Native.D.gdk_get_native_handle));
|
|
|
break;
|
|
|
}
|
|
|
catch { }
|
|
|
@@ -103,3 +149,4 @@ namespace Avalonia.Gtk3.Interop
|
|
|
|
|
|
}
|
|
|
}
|
|
|
+
|