18 changed files with 895 additions and 1 deletions
@ -0,0 +1 @@ |
|||||
|
project.lock.json |
||||
@ -0,0 +1,80 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> |
||||
|
<PropertyGroup> |
||||
|
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion> |
||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
|
<ProjectGuid>{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}</ProjectGuid> |
||||
|
<OutputType>Library</OutputType> |
||||
|
<AppDesignerFolder>Properties</AppDesignerFolder> |
||||
|
<RootNamespace>Avalonia.Gtk3</RootNamespace> |
||||
|
<AssemblyName>Avalonia.Gtk3</AssemblyName> |
||||
|
<DefaultLanguage>en-US</DefaultLanguage> |
||||
|
<FileAlignment>512</FileAlignment> |
||||
|
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
||||
|
<TargetFrameworkProfile> |
||||
|
</TargetFrameworkProfile> |
||||
|
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
|
<DebugSymbols>true</DebugSymbols> |
||||
|
<DebugType>full</DebugType> |
||||
|
<Optimize>false</Optimize> |
||||
|
<OutputPath>bin\Debug\</OutputPath> |
||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
|
<ErrorReport>prompt</ErrorReport> |
||||
|
<WarningLevel>4</WarningLevel> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
|
<DebugType>pdbonly</DebugType> |
||||
|
<Optimize>true</Optimize> |
||||
|
<OutputPath>bin\Release\</OutputPath> |
||||
|
<DefineConstants>TRACE</DefineConstants> |
||||
|
<ErrorReport>prompt</ErrorReport> |
||||
|
<WarningLevel>4</WarningLevel> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<!-- A reference to the entire .NET Framework is automatically included --> |
||||
|
<None Include="project.json" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<Compile Include="Gtk3Platform.cs" /> |
||||
|
<Compile Include="Interop\DynLoader.cs" /> |
||||
|
<Compile Include="Interop\Native.cs" /> |
||||
|
<Compile Include="Interop\NativeException.cs" /> |
||||
|
<Compile Include="Interop\Resolver.cs" /> |
||||
|
<Compile Include="Interop\Signal.cs" /> |
||||
|
<Compile Include="Properties\AssemblyInfo.cs" /> |
||||
|
<Compile Include="Stubs.cs" /> |
||||
|
<Compile Include="TopLevelImpl.cs" /> |
||||
|
<Compile Include="Interop\Utf8Buffer.cs" /> |
||||
|
<Compile Include="WindowImpl.cs" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj"> |
||||
|
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project> |
||||
|
<Name>Avalonia.Base</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj"> |
||||
|
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project> |
||||
|
<Name>Avalonia.Controls</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj"> |
||||
|
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project> |
||||
|
<Name>Avalonia.Input</Name> |
||||
|
</ProjectReference> |
||||
|
<ProjectReference Include="..\..\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj"> |
||||
|
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project> |
||||
|
<Name>Avalonia.SceneGraph</Name> |
||||
|
</ProjectReference> |
||||
|
</ItemGroup> |
||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> |
||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
||||
|
Other similar extension points exist, see Microsoft.Common.targets. |
||||
|
<Target Name="BeforeBuild"> |
||||
|
</Target> |
||||
|
<Target Name="AfterBuild"> |
||||
|
</Target> |
||||
|
--> |
||||
|
</Project> |
||||
@ -0,0 +1,91 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Platform; |
||||
|
using Avalonia.Gtk3.Interop; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Input.Platform; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Gtk3 |
||||
|
{ |
||||
|
public class Gtk3Platform : IWindowingPlatform, IPlatformSettings, IPlatformThreadingInterface |
||||
|
{ |
||||
|
internal static readonly Gtk3Platform Instance = new Gtk3Platform(); |
||||
|
internal static readonly MouseDevice Mouse = new MouseDevice(); |
||||
|
internal static readonly KeyboardDevice Keyboard = new KeyboardDevice(); |
||||
|
internal static IntPtr App { get; set; } |
||||
|
public static void Initialize() |
||||
|
{ |
||||
|
Resolver.Resolve(); |
||||
|
Native.GtkInit(0, IntPtr.Zero); |
||||
|
App = Native.GtkApplicationNew("avalonia.app." + Guid.NewGuid(), 0); |
||||
|
//Mark current thread as UI thread
|
||||
|
s_tlsMarker = true; |
||||
|
|
||||
|
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>().ToConstant(Instance) |
||||
|
.Bind<IClipboard>().ToSingleton<ClipboardStub>() |
||||
|
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactoryStub()) |
||||
|
.Bind<IKeyboardDevice>().ToConstant(Keyboard) |
||||
|
.Bind<IMouseDevice>().ToConstant(Mouse) |
||||
|
.Bind<IPlatformSettings>().ToConstant(Instance) |
||||
|
.Bind<IPlatformThreadingInterface>().ToConstant(Instance) |
||||
|
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogStub>() |
||||
|
.Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoaderStub()); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public IWindowImpl CreateWindow() => new WindowImpl(); |
||||
|
|
||||
|
public IEmbeddableWindowImpl CreateEmbeddableWindow() |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public IPopupImpl CreatePopup() |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
public Size DoubleClickSize => new Size(4, 4); |
||||
|
|
||||
|
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(100); //STUB
|
||||
|
public double RenderScalingFactor { get; } = 1; |
||||
|
public double LayoutScalingFactor { get; } = 1; |
||||
|
|
||||
|
public void RunLoop(CancellationToken cancellationToken) |
||||
|
{ |
||||
|
while (!cancellationToken.IsCancellationRequested) |
||||
|
Native.GtkMainIteration(); |
||||
|
} |
||||
|
|
||||
|
public IDisposable StartTimer(TimeSpan interval, Action tick) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public void Signal() |
||||
|
{ |
||||
|
} |
||||
|
public event Action Signaled; |
||||
|
|
||||
|
|
||||
|
[ThreadStatic] |
||||
|
private static bool s_tlsMarker; |
||||
|
|
||||
|
public bool CurrentThreadIsLoopThread => s_tlsMarker; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public static class Gtk3AppBuilderExtensions |
||||
|
{ |
||||
|
public static T UseGtk3<T>(this AppBuilderBase<T> builder) where T : AppBuilderBase<T>, new() |
||||
|
=> builder.UseWindowingSubsystem(Gtk3Platform.Initialize, "GTK3"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,142 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
/* |
||||
|
* Source code imported from https://github.com/kekekeks/evhttp-sharp
|
||||
|
* Source is provided under MIT license for Avalonia project and derived works |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
internal interface IDynLoader |
||||
|
{ |
||||
|
IntPtr LoadLibrary(string basePath, string dll); |
||||
|
IntPtr GetProcAddress(IntPtr dll, string proc); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
class UnixLoader : IDynLoader |
||||
|
{ |
||||
|
// ReSharper disable InconsistentNaming
|
||||
|
static class LinuxImports |
||||
|
{ |
||||
|
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlopen(string path, int flags); |
||||
|
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
||||
|
|
||||
|
[DllImport("libdl.so.2")] |
||||
|
private static extern IntPtr dlerror(); |
||||
|
|
||||
|
public static void Init() |
||||
|
{ |
||||
|
DlOpen = dlopen; |
||||
|
DlSym = dlsym; |
||||
|
DlError = dlerror; |
||||
|
Postfix = ".so.0"; |
||||
|
} |
||||
|
} |
||||
|
static class OsXImports |
||||
|
{ |
||||
|
|
||||
|
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
private static extern IntPtr dlopen(string path, int flags); |
||||
|
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
||||
|
|
||||
|
[DllImport("/usr/lib/libSystem.dylib")] |
||||
|
private static extern IntPtr dlerror(); |
||||
|
|
||||
|
public static void Init() |
||||
|
{ |
||||
|
DlOpen = dlopen; |
||||
|
DlSym = dlsym; |
||||
|
DlError = dlerror; |
||||
|
Postfix = ".dylib"; //TODO
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
[DllImport("libc")] |
||||
|
static extern int uname(IntPtr buf); |
||||
|
|
||||
|
|
||||
|
|
||||
|
static UnixLoader() |
||||
|
{ |
||||
|
var buffer = Marshal.AllocHGlobal(0x1000); |
||||
|
uname(buffer); |
||||
|
var unixName = Marshal.PtrToStringAnsi(buffer); |
||||
|
Marshal.FreeHGlobal(buffer); |
||||
|
if(unixName == "Darwin") |
||||
|
OsXImports.Init(); |
||||
|
else |
||||
|
LinuxImports.Init(); |
||||
|
} |
||||
|
|
||||
|
private static Func<string, int, IntPtr> DlOpen; |
||||
|
private static Func<IntPtr, string, IntPtr> DlSym; |
||||
|
private static Func<IntPtr> DlError; |
||||
|
private static string Postfix; |
||||
|
// ReSharper restore InconsistentNaming
|
||||
|
|
||||
|
static string DlErrorString() |
||||
|
{ |
||||
|
|
||||
|
return Marshal.PtrToStringAnsi(DlError()); |
||||
|
} |
||||
|
|
||||
|
public IntPtr LoadLibrary(string basePath, string dll) |
||||
|
{ |
||||
|
dll += Postfix; |
||||
|
if (basePath != null) |
||||
|
dll = System.IO.Path.Combine(basePath, dll); |
||||
|
var handle = DlOpen(dll, 1); |
||||
|
if (handle == IntPtr.Zero) |
||||
|
throw new NativeException(DlErrorString()); |
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
public IntPtr GetProcAddress(IntPtr dll, string proc) |
||||
|
{ |
||||
|
var ptr = DlSym(dll, proc); |
||||
|
if (ptr == IntPtr.Zero) |
||||
|
throw new NativeException(DlErrorString()); |
||||
|
return ptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class Win32Loader : IDynLoader |
||||
|
{ |
||||
|
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] |
||||
|
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); |
||||
|
|
||||
|
[DllImport("kernel32", EntryPoint = "LoadLibraryW", SetLastError = true, CharSet = CharSet.Unicode)] |
||||
|
private static extern IntPtr LoadLibrary(string lpszLib); |
||||
|
|
||||
|
IntPtr IDynLoader.LoadLibrary(string basePath, string dll) |
||||
|
{ |
||||
|
dll += "-0.dll"; |
||||
|
if (basePath != null) |
||||
|
dll = System.IO.Path.Combine(basePath, dll); |
||||
|
var handle = LoadLibrary(dll); |
||||
|
if (handle == IntPtr.Zero) |
||||
|
throw new NativeException("Error " + Marshal.GetLastWin32Error()); |
||||
|
return handle; |
||||
|
} |
||||
|
|
||||
|
IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc) |
||||
|
{ |
||||
|
var ptr = GetProcAddress(dll, proc); |
||||
|
if (ptr == IntPtr.Zero) |
||||
|
throw new NativeException("Error " + Marshal.GetLastWin32Error()); |
||||
|
return ptr; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
static class Native |
||||
|
{ |
||||
|
public static class D |
||||
|
{ |
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate IntPtr gtk_application_new([MarshalAs(UnmanagedType.AnsiBStr)] string appId, int flags); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_main_iteration(); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate IntPtr gtk_window_new(GtkWindowType windowType); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate IntPtr gtk_init(int argc, IntPtr argv); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_window_present(IntPtr gtkWindow); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_widget_hide(IntPtr gtkWidget); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] //No manual import
|
||||
|
public delegate IntPtr gdk_get_native_handle(IntPtr gdkWindow); |
||||
|
|
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate IntPtr gtk_widget_get_window(IntPtr gtkWidget); |
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate IntPtr gtk_widget_set_double_buffered(IntPtr gtkWidget, bool value); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_widget_realize(IntPtr gtkWidget); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_window_set_title(IntPtr gtkWindow, Utf8Buffer title); |
||||
|
|
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_window_set_decorated(IntPtr gtkWindow, bool decorated); |
||||
|
|
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] |
||||
|
public delegate void gtk_window_get_size(IntPtr gtkWindow, out int width, out int height); |
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)] |
||||
|
public delegate ulong g_signal_connect_object(IntPtr instance, [MarshalAs(UnmanagedType.AnsiBStr)]string signal, IntPtr handler, IntPtr userData, int flags); |
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)] |
||||
|
public delegate ulong g_signal_handler_disconnect(IntPtr instance, ulong connectionId); |
||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] |
||||
|
public delegate bool signal_widget_draw(IntPtr gtkWidget, IntPtr cairoContext, IntPtr userData); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static D.gtk_window_set_decorated GtkWindowSetDecorated; |
||||
|
public static D.gtk_window_set_title GtkWindowSetTitle; |
||||
|
public static D.gtk_application_new GtkApplicationNew; |
||||
|
public static D.gtk_main_iteration GtkMainIteration; |
||||
|
public static D.gtk_window_new GtkWindowNew; |
||||
|
public static D.gtk_init GtkInit; |
||||
|
public static D.gtk_window_present GtkWindowPresent; |
||||
|
public static D.gtk_widget_hide GtkWidgetHide; |
||||
|
public static D.gdk_get_native_handle GetNativeGdkWindowHandle; |
||||
|
public static D.gtk_widget_get_window GtkWidgetGetWindow; |
||||
|
public static D.gtk_widget_realize GtkWidgetRealize; |
||||
|
public static D.gtk_window_get_size GtkWindowGetSize; |
||||
|
public static D.g_signal_connect_object GSignalConnectObject; |
||||
|
public static D.g_signal_handler_disconnect GSignalHandlerDisconnect; |
||||
|
public static D.gtk_widget_set_double_buffered GtkWidgetSetDoubleBuffered; |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
public enum GtkWindowType |
||||
|
{ |
||||
|
TopLevel, |
||||
|
Popup |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
public class NativeException : Exception |
||||
|
{ |
||||
|
public NativeException() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public NativeException(string message) : base(message) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public NativeException(string message, Exception inner) : base(message, inner) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
internal class GtkImportAttribute : Attribute |
||||
|
{ |
||||
|
public GtkDll Dll { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
public bool Optional { get; set; } |
||||
|
|
||||
|
public GtkImportAttribute(GtkDll dll, string name = null, bool optional = false) |
||||
|
{ |
||||
|
Dll = dll; |
||||
|
Name = name; |
||||
|
Optional = optional; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal enum GtkDll |
||||
|
{ |
||||
|
Gdk, |
||||
|
Gtk, |
||||
|
Glib, |
||||
|
Gio, |
||||
|
Gobject |
||||
|
} |
||||
|
|
||||
|
static class Resolver |
||||
|
{ |
||||
|
[DllImport("kernel32.dll")] |
||||
|
static extern int GetVersion(); |
||||
|
|
||||
|
static bool IsWin32() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
GetVersion(); |
||||
|
return true; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
public static void Resolve(string basePath = null) |
||||
|
{ |
||||
|
var loader = IsWin32() ? (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"); |
||||
|
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); |
||||
|
|
||||
|
var funcPtr = loader.GetProcAddress(lib, import.Name ?? fieldInfo.FieldType.Name); |
||||
|
fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType)); |
||||
|
} |
||||
|
|
||||
|
var nativeHandleNames = new[] {"gdk_x11_window_get_xid", "gdk_win32_window_get_handle"}; |
||||
|
foreach (var name in nativeHandleNames) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle)Marshal |
||||
|
.GetDelegateForFunctionPointer(loader.GetProcAddress(gdk, name), typeof(Native.D.gdk_get_native_handle)); |
||||
|
} |
||||
|
catch { } |
||||
|
} |
||||
|
if (Native.GetNativeGdkWindowHandle == null) |
||||
|
throw new Exception($"Unable to locate any of [{string.Join(", ", nativeHandleNames)}] in libgdk"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
public class Signal |
||||
|
{ |
||||
|
class ConnectedSignal : IDisposable |
||||
|
{ |
||||
|
private readonly IntPtr _instance; |
||||
|
private GCHandle _handle; |
||||
|
private readonly ulong _id; |
||||
|
|
||||
|
public ConnectedSignal(IntPtr instance, GCHandle handle, ulong id) |
||||
|
{ |
||||
|
_instance = instance; |
||||
|
_handle = handle; |
||||
|
_id = id; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
if (_handle.IsAllocated) |
||||
|
{ |
||||
|
Native.GSignalHandlerDisconnect(_instance, _id); |
||||
|
_handle.Free(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static IDisposable Connect<T>(IntPtr obj, string name, T handler) |
||||
|
{ |
||||
|
var handle = GCHandle.Alloc(handler); |
||||
|
var ptr = Marshal.GetFunctionPointerForDelegate((Delegate)(object)handler); |
||||
|
var id = Native.GSignalConnectObject(obj, name, ptr, IntPtr.Zero, 0); |
||||
|
if (id == 0) |
||||
|
throw new ArgumentException("Unable to connect to signal " + name); |
||||
|
return new ConnectedSignal(obj, handle, id); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Avalonia.Gtk3.Interop |
||||
|
{ |
||||
|
class Utf8Buffer : SafeHandle |
||||
|
{ |
||||
|
private GCHandle _gchandle; |
||||
|
private byte[] _data; |
||||
|
|
||||
|
public Utf8Buffer(string s) : base(IntPtr.Zero, true) |
||||
|
{ |
||||
|
_data = Encoding.UTF8.GetBytes(s); |
||||
|
_gchandle = GCHandle.Alloc(_data, GCHandleType.Pinned); |
||||
|
handle = _gchandle.AddrOfPinnedObject(); |
||||
|
} |
||||
|
|
||||
|
protected override bool ReleaseHandle() |
||||
|
{ |
||||
|
if (handle != IntPtr.Zero) |
||||
|
{ |
||||
|
handle = IntPtr.Zero; |
||||
|
_data = null; |
||||
|
_gchandle.Free(); |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public override bool IsInvalid => handle == IntPtr.Zero; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System.Resources; |
||||
|
using System.Reflection; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
// General Information about an assembly is controlled through the following
|
||||
|
// set of attributes. Change these attribute values to modify the information
|
||||
|
// associated with an assembly.
|
||||
|
[assembly: AssemblyTitle("Avalonia.Gtk3")] |
||||
|
[assembly: AssemblyDescription("")] |
||||
|
[assembly: AssemblyConfiguration("")] |
||||
|
[assembly: AssemblyCompany("")] |
||||
|
[assembly: AssemblyProduct("Avalonia.Gtk3")] |
||||
|
[assembly: AssemblyCopyright("Copyright © 2016")] |
||||
|
[assembly: AssemblyTrademark("")] |
||||
|
[assembly: AssemblyCulture("")] |
||||
|
[assembly: NeutralResourcesLanguage("en")] |
||||
|
|
||||
|
// Version information for an assembly consists of the following four values:
|
||||
|
//
|
||||
|
// Major Version
|
||||
|
// Minor Version
|
||||
|
// Build Number
|
||||
|
// Revision
|
||||
|
//
|
||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
|
// by using the '*' as shown below:
|
||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
[assembly: AssemblyVersion("1.0.0.0")] |
||||
|
[assembly: AssemblyFileVersion("1.0.0.0")] |
||||
@ -0,0 +1,9 @@ |
|||||
|
P/Invoke based GTK3 backend |
||||
|
=========================== |
||||
|
|
||||
|
Code is EXPERIMENTAL at this point. It also needs Direct2D/Skia for rendering. |
||||
|
|
||||
|
Windows GTK3 binaries aren't included in the repo, you need to download them from http://www.tarnyko.net/repo/gtk3_build_system/gtk+-bundle_3.4.2-20130513_win32.zip |
||||
|
Then you need to extract them somewhere and add `bin` directory to PATH. Support for specifying exact path to binaries will be implemented later. |
||||
|
|
||||
|
On Linux it should work out of the box with system-provided GTK3. On OSX you should be able to wire GTK3 using DYLD_LIBRARY_PATH environment variable. |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Platform; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Input.Platform; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
//TODO: This file should be empty once everything is implemented
|
||||
|
|
||||
|
namespace Avalonia.Gtk3 |
||||
|
{ |
||||
|
class ClipboardStub : IClipboard |
||||
|
{ |
||||
|
public Task<string> GetTextAsync() => Task.FromResult(""); |
||||
|
|
||||
|
public Task SetTextAsync(string text) => Task.FromResult(0); |
||||
|
|
||||
|
public Task ClearAsync() => Task.FromResult(0); |
||||
|
} |
||||
|
|
||||
|
class CursorFactoryStub : IStandardCursorFactory |
||||
|
{ |
||||
|
public IPlatformHandle GetCursor(StandardCursorType cursorType) => new PlatformHandle(IntPtr.Zero, "STUB"); |
||||
|
} |
||||
|
|
||||
|
class SystemDialogStub : ISystemDialogImpl |
||||
|
{ |
||||
|
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) => Task.FromResult(new string[0]); |
||||
|
|
||||
|
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) |
||||
|
=> Task.FromResult((string) null); |
||||
|
} |
||||
|
|
||||
|
class PlatformIconLoaderStub : IPlatformIconLoader |
||||
|
{ |
||||
|
public IWindowIconImpl LoadIcon(string fileName) => null; |
||||
|
|
||||
|
public IWindowIconImpl LoadIcon(Stream stream) => null; |
||||
|
|
||||
|
public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) => null; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Gtk3.Interop; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Input.Raw; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Gtk3 |
||||
|
{ |
||||
|
abstract class TopLevelImpl : ITopLevelImpl, IPlatformHandle |
||||
|
{ |
||||
|
protected readonly IntPtr _gtkWidget; |
||||
|
private IInputRoot _inputRoot; |
||||
|
|
||||
|
public TopLevelImpl(IntPtr gtkWidget) |
||||
|
{ |
||||
|
_gtkWidget = gtkWidget; |
||||
|
Native.GtkWidgetRealize(gtkWidget); |
||||
|
Native.GtkWidgetSetDoubleBuffered(gtkWidget, false); |
||||
|
Signal.Connect<Native.D.signal_widget_draw>(_gtkWidget, "draw", OnDraw); |
||||
|
} |
||||
|
|
||||
|
private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata) |
||||
|
{ |
||||
|
Paint?.Invoke(new Rect(ClientSize)); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public abstract Size ClientSize { get; set; } |
||||
|
|
||||
|
public Size MaxClientSize => new Size(1024, 768); //STUB
|
||||
|
public double Scaling => 1; //TODO: Implement scaling
|
||||
|
public IPlatformHandle Handle => this; |
||||
|
|
||||
|
string IPlatformHandle.HandleDescriptor => "HWND"; |
||||
|
|
||||
|
public Action Activated { get; set; } |
||||
|
public Action Closed { get; set; } |
||||
|
public Action Deactivated { get; set; } |
||||
|
public Action<RawInputEventArgs> Input { get; set; } |
||||
|
public Action<Rect> Paint { get; set; } |
||||
|
public Action<Size> Resized { get; set; } |
||||
|
public Action<double> ScalingChanged { get; set; } |
||||
|
public Action<Point> PositionChanged { get; set; } |
||||
|
public void Activate() |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public void Invalidate(Rect rect) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot; |
||||
|
|
||||
|
public Point PointToClient(Point point) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public Point PointToScreen(Point point) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public void SetCursor(IPlatformHandle cursor) |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public void Show() => Native.GtkWindowPresent(_gtkWidget); |
||||
|
|
||||
|
public void Hide() => Native.GtkWidgetHide(_gtkWidget); |
||||
|
|
||||
|
public void BeginMoveDrag() |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public void BeginResizeDrag(WindowEdge edge) |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public Point Position { get; set; } |
||||
|
|
||||
|
IntPtr IPlatformHandle.Handle => Native.GetNativeGdkWindowHandle(Native.GtkWidgetGetWindow(_gtkWidget)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Gtk3.Interop; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Gtk3 |
||||
|
{ |
||||
|
class WindowImpl : TopLevelImpl, IWindowImpl |
||||
|
{ |
||||
|
public WindowState WindowState { get; set; } //STUB
|
||||
|
public void SetTitle(string title) |
||||
|
{ |
||||
|
using (var t = new Utf8Buffer(title)) |
||||
|
Native.GtkWindowSetTitle(_gtkWidget, t); |
||||
|
} |
||||
|
|
||||
|
public IDisposable ShowDialog() |
||||
|
{ |
||||
|
return null; |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(_gtkWidget, enabled); |
||||
|
|
||||
|
public void SetIcon(IWindowIconImpl icon) |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
|
||||
|
public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel)) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override Size ClientSize |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
int w, h; |
||||
|
Native.GtkWindowGetSize(_gtkWidget, out w, out h); |
||||
|
return new Size(w, h); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
//STUB
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"supports": {}, |
||||
|
"dependencies": { |
||||
|
"Microsoft.NETCore.Portable.Compatibility": "1.0.1", |
||||
|
"NETStandard.Library": "1.6.0" |
||||
|
}, |
||||
|
"frameworks": { |
||||
|
"netstandard1.1": {} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue