Browse Source

Updated to the recent code base, implemented threading, resize and invalidate handling

pull/875/head
Nikita Tsukanov 10 years ago
parent
commit
f8e392a520
  1. 3
      Avalonia.sln
  2. 5
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  3. 3
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  4. 21
      src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs
  5. 64
      src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs
  6. 55
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  7. 3
      src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs
  8. 62
      src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs
  9. 16
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs

3
Avalonia.sln

@ -130,6 +130,9 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}"
ProjectSection(ProjectDependencies) = postProject
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {BB1F7BB5-6AD4-4776-94D9-C09D0A972658}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
EndProject

5
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2B888490-D14A-4BCA-AB4B-48676FA93C9B}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ControlCatalog.Desktop</RootNamespace>
<AssemblyName>ControlCatalog.Desktop</AssemblyName>
@ -33,6 +33,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll</HintPath>

3
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@ -41,6 +41,7 @@
<ItemGroup>
<Compile Include="Gtk3Platform.cs" />
<Compile Include="Interop\DynLoader.cs" />
<Compile Include="Interop\GlibTimeout.cs" />
<Compile Include="Interop\Native.cs" />
<Compile Include="Interop\NativeException.cs" />
<Compile Include="Interop\Resolver.cs" />
@ -64,7 +65,7 @@
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project>
<Name>Avalonia.SceneGraph</Name>
</ProjectReference>

21
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@ -10,6 +10,7 @@ using Avalonia.Gtk3.Interop;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Platform;
using Avalonia.Rendering;
namespace Avalonia.Gtk3
{
@ -35,6 +36,7 @@ namespace Avalonia.Gtk3
.Bind<IPlatformSettings>().ToConstant(Instance)
.Bind<IPlatformThreadingInterface>().ToConstant(Instance)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogStub>()
.Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
.Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoaderStub());
}
@ -67,11 +69,28 @@ namespace Avalonia.Gtk3
public IDisposable StartTimer(TimeSpan interval, Action tick)
{
return null;
return GlibTimeout.StarTimer((uint) interval.TotalMilliseconds, tick);
}
private bool _signaled = false;
object _lock = new object();
public void Signal()
{
lock(_lock)
if (!_signaled)
{
_signaled = true;
GlibTimeout.Add(0, () =>
{
lock (_lock)
{
_signaled = false;
}
Signaled?.Invoke();
return false;
});
}
}
public event Action Signaled;

64
src/Gtk/Avalonia.Gtk3/Interop/GlibTimeout.cs

@ -0,0 +1,64 @@
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 GlibTimeout
{
static bool Handler(IntPtr data)
{
var handle = GCHandle.FromIntPtr(data);
var cb = (Func<bool>) handle.Target;
if (!cb())
{
handle.Free();
return false;
}
return true;
}
private static readonly GCHandle PinnedHandle;
private static readonly Native.D.timeout_callback PinnedHandler;
static GlibTimeout()
{
PinnedHandler = Handler;
}
public static void Add(uint interval, Func<bool> callback)
{
var handle = GCHandle.Alloc(callback);
Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
}
class Timer : IDisposable
{
public bool Stopped;
public void Dispose()
{
Stopped = true;
}
}
public static IDisposable StarTimer(uint interval, Action tick)
{
var timer = new Timer ();
GlibTimeout.Add(interval,
() =>
{
if (timer.Stopped)
return false;
tick();
return !timer.Stopped;
});
return timer;
}
}
}

55
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -36,7 +36,19 @@ namespace Avalonia.Gtk3.Interop
[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_get_screen(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 IntPtr gtk_widget_set_events(IntPtr gtkWidget, uint flags);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate int gdk_screen_get_height(IntPtr screen);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate int gdk_screen_get_width(IntPtr screen);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_realize(IntPtr gtkWidget);
@ -50,12 +62,29 @@ namespace Avalonia.Gtk3.Interop
[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.Gtk)]
public delegate void gtk_window_resize(IntPtr gtkWindow, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_queue_draw_area(IntPtr gtkWindow, int x, int y, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_invalidate_rect(IntPtr window, ref GdkRectangle rect, bool invalidate_children);
[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), GtkImport(GtkDll.Glib)]
public delegate ulong g_timeout_add(uint interval, timeout_callback callback, IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool signal_widget_draw(IntPtr gtkWidget, IntPtr cairoContext, IntPtr userData);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool signal_onevent(IntPtr gtkWidget, IntPtr ev, IntPtr userData);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool timeout_callback(IntPtr data);
}
@ -69,12 +98,19 @@ namespace Avalonia.Gtk3.Interop
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_get_screen GtkWidgetGetScreen;
public static D.gtk_widget_realize GtkWidgetRealize;
public static D.gtk_window_get_size GtkWindowGetSize;
public static D.gtk_window_resize GtkWindowResize;
public static D.g_signal_connect_object GSignalConnectObject;
public static D.g_signal_handler_disconnect GSignalHandlerDisconnect;
public static D.g_timeout_add GTimeoutAdd;
public static D.gtk_widget_set_double_buffered GtkWidgetSetDoubleBuffered;
public static D.gtk_widget_set_events GtkWidgetSetEvents;
public static D.gdk_window_invalidate_rect GdkWindowInvalidateRect;
public static D.gtk_widget_queue_draw_area GtkWidgetQueueDrawArea;
public static D.gdk_screen_get_height GdkScreenGetHeight;
public static D.gdk_screen_get_width GdkScreenGetWidth;
}
@ -84,4 +120,21 @@ namespace Avalonia.Gtk3.Interop
TopLevel,
Popup
}
[StructLayout(LayoutKind.Sequential)]
public struct GdkRectangle
{
public int X, Y, Width, Height;
public static GdkRectangle FromRect(Rect rect)
{
return new GdkRectangle
{
X = (int) rect.X,
Y = (int) rect.Y,
Width = (int) rect.Width,
Height = (int) rect.Height
};
}
}
}

3
src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs

@ -84,13 +84,14 @@ namespace Avalonia.Gtk3.Interop
fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType));
}
var nativeHandleNames = new[] {"gdk_x11_window_get_xid", "gdk_win32_window_get_handle"};
var nativeHandleNames = new[] { "gdk_win32_window_get_handle", "gdk_x11_window_get_xid", "gdk_quartz_window_get_nswindow" };
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));
break;
}
catch { }
}

62
src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Avalonia.Controls;
using Avalonia.Gtk3.Interop;
using Avalonia.Input;
@ -9,44 +11,69 @@ namespace Avalonia.Gtk3
{
abstract class TopLevelImpl : ITopLevelImpl, IPlatformHandle
{
protected readonly IntPtr _gtkWidget;
protected readonly IntPtr GtkWidget;
private IInputRoot _inputRoot;
protected readonly List<IDisposable> _disposables = new List<IDisposable>();
public TopLevelImpl(IntPtr gtkWidget)
{
_gtkWidget = gtkWidget;
GtkWidget = gtkWidget;
Native.GtkWidgetSetEvents(gtkWidget, uint.MaxValue);
Native.GtkWidgetRealize(gtkWidget);
Native.GtkWidgetSetDoubleBuffered(gtkWidget, false);
Signal.Connect<Native.D.signal_widget_draw>(_gtkWidget, "draw", OnDraw);
Connect<Native.D.signal_widget_draw>("draw", OnDraw);
Connect<Native.D.signal_onevent>("configure-event", OnConfigured);
}
private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata)
{
Debug.WriteLine("Configured");
Resized?.Invoke(ClientSize);
return false;
}
void Connect<T>(string name, T handler) => _disposables.Add(Signal.Connect<T>(GtkWidget, name, handler));
private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata)
{
Debug.WriteLine("Draw");
Paint?.Invoke(new Rect(ClientSize));
return true;
}
public void Dispose()
{
//STUB
foreach(var d in _disposables)
d.Dispose();
_disposables.Clear();
//TODO
}
public abstract Size ClientSize { get; set; }
public Size MaxClientSize => new Size(1024, 768); //STUB
public Size MaxClientSize
{
get
{
var s = Native.GtkWidgetGetScreen(GtkWidget);
return new Size(Native.GdkScreenGetWidth(s), Native.GdkScreenGetHeight(s));
}
}
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 Activated { get; set; } //TODO
public Action Closed { get; set; } //TODO
public Action Deactivated { get; set; } //TODO
public Action<RawInputEventArgs> Input { get; set; } //TODO
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 Action<Size> Resized { get; set; } //TODO
public Action<double> ScalingChanged { get; set; } //TODO
public Action<Point> PositionChanged { get; set; } //TODO
public void Activate()
{
throw new NotImplementedException();
@ -54,7 +81,7 @@ namespace Avalonia.Gtk3
public void Invalidate(Rect rect)
{
throw new NotImplementedException();
Native.GtkWidgetQueueDrawArea(GtkWidget, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
}
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
@ -74,9 +101,9 @@ namespace Avalonia.Gtk3
//STUB
}
public void Show() => Native.GtkWindowPresent(_gtkWidget);
public void Show() => Native.GtkWindowPresent(GtkWidget);
public void Hide() => Native.GtkWidgetHide(_gtkWidget);
public void Hide() => Native.GtkWidgetHide(GtkWidget);
public void BeginMoveDrag()
{
@ -90,6 +117,7 @@ namespace Avalonia.Gtk3
public Point Position { get; set; }
IntPtr IPlatformHandle.Handle => Native.GetNativeGdkWindowHandle(Native.GtkWidgetGetWindow(_gtkWidget));
IntPtr IPlatformHandle.Handle => Native.GetNativeGdkWindowHandle(Native.GtkWidgetGetWindow(GtkWidget));
public IEnumerable<object> Surfaces => new object[] {Handle};
}
}

16
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@ -11,7 +11,7 @@ namespace Avalonia.Gtk3
public void SetTitle(string title)
{
using (var t = new Utf8Buffer(title))
Native.GtkWindowSetTitle(_gtkWidget, t);
Native.GtkWindowSetTitle(GtkWidget, t);
}
public IDisposable ShowDialog()
@ -20,7 +20,7 @@ namespace Avalonia.Gtk3
//STUB
}
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(_gtkWidget, enabled);
public void SetSystemDecorations(bool enabled) => Native.GtkWindowSetDecorated(GtkWidget, enabled);
public void SetIcon(IWindowIconImpl icon)
{
@ -36,13 +36,15 @@ namespace Avalonia.Gtk3
get
{
int w, h;
Native.GtkWindowGetSize(_gtkWidget, out w, out h);
Native.GtkWindowGetSize(GtkWidget, out w, out h);
return new Size(w, h);
}
set
{
//STUB
}
set { Native.GtkWindowResize(GtkWidget, (int) value.Width, (int) value.Height); }
}
public void SetCoverTaskbarWhenMaximized(bool enable)
{
//Why do we even have that?
}
}
}

Loading…
Cancel
Save