Various fixes for GTK and DeferredRenderer support

This commit is contained in:
Nikita Tsukanov 2017-10-01 02:37:49 +03:00
Родитель 2abd980713
Коммит 70c24908a9
14 изменённых файлов: 281 добавлений и 82 удалений

Просмотреть файл

@ -11,6 +11,7 @@ namespace ControlCatalog
{
this.InitializeComponent();
this.AttachDevTools();
//Renderer.DrawFps = true;
//Renderer.DrawDirtyRects = Renderer.DrawFps = true;
}

Просмотреть файл

@ -44,21 +44,26 @@ namespace Avalonia.Threading
/// The job will be processed with the same priority as render.
/// </summary>
Render = 7,
/// <summary>
/// The job will be processed with the same priority as render.
/// </summary>
Layout = 8,
/// <summary>
/// The job will be processed with the same priority as data binding.
/// </summary>
DataBind = 8,
DataBind = 9,
/// <summary>
/// The job will be processed with normal priority.
/// </summary>
Normal = 9,
Normal = 10,
/// <summary>
/// The job will be processed before other asynchronous operations.
/// </summary>
Send = 10,
MaxValue = 10
Send = 11,
MaxValue = 11
}
}

Просмотреть файл

@ -203,7 +203,7 @@ namespace Avalonia.Layout
{
if (!_queued && !_running)
{
Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Render);
Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Layout);
_queued = true;
}
}

Просмотреть файл

@ -15,7 +15,7 @@ namespace Avalonia.Rendering
/// </remarks>
public class DefaultRenderLoop : IRenderLoop
{
private IPlatformThreadingInterface _threading;
private IRuntimePlatform _runtime;
private int _subscriberCount;
private EventHandler<EventArgs> _tick;
private IDisposable _subscription;
@ -78,12 +78,12 @@ namespace Avalonia.Rendering
/// </remarks>
protected virtual IDisposable StartCore(Action tick)
{
if (_threading == null)
if (_runtime == null)
{
_threading = AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>();
_runtime = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
}
return _threading.StartTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), tick);
return _runtime.StartSystemTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), tick);
}
/// <summary>

Просмотреть файл

@ -23,11 +23,11 @@ namespace Avalonia.Gtk3
public ILockedFramebuffer Lock()
{
if(_window.CurrentCairoContext == IntPtr.Zero)
throw new InvalidOperationException("Window is not in drawing state");
var width = (int) _window.ClientSize.Width;
var height = (int) _window.ClientSize.Height;
return new ImageSurfaceFramebuffer(_window.CurrentCairoContext, _window.GtkWidget, width, height);
// This method may be called from non-UI thread, don't touch anything that calls back to GTK/GDK
var s = _window.ClientSize;
var width = (int) s.Width;
var height = (int) s.Height;
return new ImageSurfaceFramebuffer(_window, width, height);
}
}
}

Просмотреть файл

@ -22,6 +22,7 @@ namespace Avalonia.Gtk3
internal static readonly MouseDevice Mouse = new MouseDevice();
internal static readonly KeyboardDevice Keyboard = new KeyboardDevice();
internal static IntPtr App { get; set; }
public static bool UseDeferredRendering = true;
public static void Initialize()
{
Resolver.Resolve();
@ -66,12 +67,17 @@ namespace Avalonia.Gtk3
public IDisposable StartTimer(TimeSpan interval, Action tick)
{
return GlibTimeout.StarTimer((uint) interval.TotalMilliseconds, tick);
var msec = interval.TotalMilliseconds;
if (msec <= 0)
throw new ArgumentException("Don't know how to create a timer with zero or negative interval");
var imsec = (uint) msec;
if (imsec == 0)
imsec = 1;
return GlibTimeout.StarTimer(imsec, tick);
}
private bool[] _signaled = new bool[(int) DispatcherPriority.MaxValue + 1];
object _lock = new object();
public void Signal(DispatcherPriority prio)
{
var idx = (int) prio;
@ -97,7 +103,6 @@ namespace Avalonia.Gtk3
private static bool s_tlsMarker;
public bool CurrentThreadIsLoopThread => s_tlsMarker;
}
}
@ -105,10 +110,11 @@ namespace Avalonia
{
public static class Gtk3AppBuilderExtensions
{
public static T UseGtk3<T>(this AppBuilderBase<T> builder, ICustomGtk3NativeLibraryResolver resolver = null)
public static T UseGtk3<T>(this AppBuilderBase<T> builder, bool deferredRendering = true, ICustomGtk3NativeLibraryResolver resolver = null)
where T : AppBuilderBase<T>, new()
{
Resolver.Custom = resolver;
Gtk3Platform.UseDeferredRendering = deferredRendering;
return builder.UseWindowingSubsystem(Gtk3Platform.Initialize, "GTK3");
}
}

Просмотреть файл

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Gtk3
{
public interface IDeferredRenderOperation : IDisposable
{
void RenderNow();
}
}

Просмотреть файл

@ -1,26 +1,28 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
using Avalonia.Threading;
namespace Avalonia.Gtk3
{
class ImageSurfaceFramebuffer : ILockedFramebuffer
{
private IntPtr _context;
private readonly WindowBaseImpl _impl;
private readonly GtkWidget _widget;
private CairoSurface _surface;
private int _factor;
public ImageSurfaceFramebuffer(IntPtr context, GtkWidget widget, int width, int height)
private object _lock = new object();
public ImageSurfaceFramebuffer(WindowBaseImpl impl, int width, int height)
{
_context = context;
_widget = widget;
_impl = impl;
_widget = impl.GtkWidget;
_factor = (int)(Native.GtkWidgetGetScaleFactor?.Invoke(_widget) ?? 1u);
width *= _factor;
height *= _factor;
@ -32,18 +34,97 @@ namespace Avalonia.Gtk3
RowBytes = Native.CairoImageSurfaceGetStride(_surface);
Native.CairoSurfaceFlush(_surface);
}
static void Draw(IntPtr context, CairoSurface surface, double factor)
{
Native.CairoSurfaceMarkDirty(surface);
Native.CairoScale(context, 1d / factor, 1d / factor);
Native.CairoSetSourceSurface(context, surface, 0, 0);
Native.CairoPaint(context);
}
/*
static Stopwatch St =Stopwatch.StartNew();
private static int _frames;
private static int _fps;*/
static void DrawToWidget(GtkWidget widget, CairoSurface surface, int width, int height, double factor)
{
if(surface == null || widget.IsClosed)
return;
var window = Native.GtkWidgetGetWindow(widget);
if(window == IntPtr.Zero)
return;
var rc = new GdkRectangle {Width = width, Height = height};
Native.GdkWindowBeginPaintRect(window, ref rc);
var context = Native.GdkCairoCreate(window);
Draw(context, surface, factor);
/*
_frames++;
var el = St.Elapsed;
if (el.TotalSeconds > 1)
{
_fps = (int) (_frames / el.TotalSeconds);
_frames = 0;
St = Stopwatch.StartNew();
}
Native.CairoSetSourceRgba(context, 1, 0, 0, 1);
Native.CairoMoveTo(context, 20, 20);
Native.CairoSetFontSize(context, 30);
using (var txt = new Utf8Buffer("FPS: " + _fps))
Native.CairoShowText(context, txt);
*/
Native.CairoDestroy(context);
Native.GdkWindowEndPaint(window);
}
class RenderOp : IDeferredRenderOperation
{
private readonly GtkWidget _widget;
private CairoSurface _surface;
private readonly double _factor;
private readonly int _width;
private readonly int _height;
public RenderOp(GtkWidget widget, CairoSurface _surface, double factor, int width, int height)
{
_widget = widget;
this._surface = _surface;
_factor = factor;
_width = width;
_height = height;
}
public void Dispose()
{
_surface?.Dispose();
_surface = null;
}
public void RenderNow()
{
DrawToWidget(_widget, _surface, _width, _height, _factor);
}
}
public void Dispose()
{
if(_context == IntPtr.Zero || _surface == null)
return;
Native.CairoSurfaceMarkDirty(_surface);
Native.CairoScale(_context, 1d / _factor, 1d / _factor);
Native.CairoSetSourceSurface(_context, _surface, 0, 0);
Native.CairoPaint(_context);
_context = IntPtr.Zero;
_surface.Dispose();
_surface = null;
lock (_lock)
{
if (Dispatcher.UIThread.CheckAccess())
{
if (_impl.CurrentCairoContext != IntPtr.Zero)
Draw(_impl.CurrentCairoContext, _surface, _factor);
else
DrawToWidget(_widget, _surface, Width, Height, _factor);
_surface.Dispose();
}
else
_impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Width, Height));
_surface = null;
}
}
public IntPtr Address { get; }

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Avalonia.Gtk3.Interop

Просмотреть файл

@ -22,23 +22,25 @@ namespace Avalonia.Gtk3.Interop
if (prio == DispatcherPriority.Send)
return High;
if (prio == DispatcherPriority.Normal)
return Default - 4;
if (prio == DispatcherPriority.DataBind)
return Default - 3;
if (prio == DispatcherPriority.Render)
return Default -2;
if (prio == DispatcherPriority.Loaded)
return Default - 1;
if (prio == DispatcherPriority.Input)
return Default;
if (prio == DispatcherPriority.DataBind)
return Default + 1;
if (prio == DispatcherPriority.Layout)
return Default + 2;
if (prio == DispatcherPriority.Render)
return Default + 3;
if (prio == DispatcherPriority.Loaded)
return GtkPaint + 20;
if (prio == DispatcherPriority.Input)
return GtkPaint + 21;
if (prio == DispatcherPriority.Background)
return DefaultIdle;
return DefaultIdle + 1;
if (prio == DispatcherPriority.ContextIdle)
return DefaultIdle + 100;
return DefaultIdle + 2;
if (prio == DispatcherPriority.ApplicationIdle)
return DefaultIdle + 200;
return DefaultIdle + 3;
if (prio == DispatcherPriority.SystemIdle)
return DefaultIdle + 200;
return DefaultIdle + 4;
throw new ArgumentException("Unknown priority");
}

Просмотреть файл

@ -4,6 +4,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Threading;
namespace Avalonia.Gtk3.Interop
{
@ -33,7 +34,8 @@ namespace Avalonia.Gtk3.Interop
public static void Add(int priority, uint interval, Func<bool> callback)
{
var handle = GCHandle.Alloc(callback);
Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
//Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
Native.GTimeoutAddFull(priority, interval, PinnedHandler, GCHandle.ToIntPtr(handle), IntPtr.Zero);
}
class Timer : IDisposable
@ -48,8 +50,10 @@ namespace Avalonia.Gtk3.Interop
public static IDisposable StarTimer(uint interval, Action tick)
{
if (interval == 0)
throw new ArgumentException("Don't know how to create a timer with zero or negative interval");
var timer = new Timer ();
GlibTimeout.Add(101, interval,
GlibTimeout.Add(GlibPriority.FromDispatcherPriority(DispatcherPriority.Background), interval,
() =>
{
if (timer.Stopped)

Просмотреть файл

@ -169,6 +169,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_surface_mark_dirty(CairoSurface surface);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_surface_write_to_png(CairoSurface surface, Utf8Buffer path);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_surface_flush(CairoSurface surface);
@ -178,15 +181,36 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_set_source_surface(IntPtr cr, CairoSurface surface, double x, double y);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_set_source_rgba(IntPtr cr, double r, double g, double b, double a);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_scale(IntPtr context, double sx, double sy);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_paint(IntPtr context);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_show_text(IntPtr context, Utf8Buffer text);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_set_font_size(IntPtr context, double size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_select_font_face(IntPtr context, Utf8Buffer face, int slant, int weight);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_move_to(IntPtr context, double x, double y);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_destroy(IntPtr context);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_queue_draw_area(GtkWidget widget, int x, int y, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_widget_add_tick_callback(GtkWidget widget, TickCallback callback, IntPtr userData, IntPtr destroy);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate GtkImContext gtk_im_multicontext_new();
@ -238,6 +262,12 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_process_updates(IntPtr window, bool updateChildren);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_begin_paint_rect(IntPtr window, ref GdkRectangle rect);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_window_end_paint(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate void gdk_event_request_motions(IntPtr ev);
@ -276,6 +306,9 @@ namespace Avalonia.Gtk3.Interop
public delegate bool gdk_pixbuf_save_to_bufferv(Pixbuf pixbuf, out IntPtr buffer, out IntPtr buffer_size,
Utf8Buffer type, IntPtr option_keys, IntPtr option_values, out IntPtr error);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
public delegate IntPtr gdk_cairo_create(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
public delegate void g_object_unref(IntPtr instance);
@ -326,6 +359,11 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void GtkClipboardTextReceivedFunc(IntPtr clipboard, IntPtr utf8string, IntPtr userdata);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool TickCallback(IntPtr widget, IntPtr clock, IntPtr userdata);
}
public static D.gdk_display_get_n_screens GdkDisplayGetNScreens;
@ -380,6 +418,7 @@ namespace Avalonia.Gtk3.Interop
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.gtk_widget_add_tick_callback GtkWidgetAddTickCallback;
public static D.gtk_widget_activate GtkWidgetActivate;
public static D.gtk_clipboard_get_for_display GtkClipboardGetForDisplay;
public static D.gtk_clipboard_request_text GtkClipboardRequestText;
@ -406,6 +445,9 @@ namespace Avalonia.Gtk3.Interop
public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag;
public static D.gdk_event_request_motions GdkEventRequestMotions;
public static D.gdk_window_process_updates GdkWindowProcessUpdates;
public static D.gdk_window_begin_paint_rect GdkWindowBeginPaintRect;
public static D.gdk_window_end_paint GdkWindowEndPaint;
public static D.gdk_pixbuf_new_from_file GdkPixbufNewFromFile;
public static D.gtk_icon_theme_get_default GtkIconThemeGetDefault;
@ -414,16 +456,24 @@ namespace Avalonia.Gtk3.Interop
public static D.gdk_window_set_cursor GdkWindowSetCursor;
public static D.gdk_pixbuf_new_from_stream GdkPixbufNewFromStream;
public static D.gdk_pixbuf_save_to_bufferv GdkPixbufSaveToBufferv;
public static D.gdk_cairo_create GdkCairoCreate;
public static D.cairo_image_surface_create CairoImageSurfaceCreate;
public static D.cairo_image_surface_get_data CairoImageSurfaceGetData;
public static D.cairo_image_surface_get_stride CairoImageSurfaceGetStride;
public static D.cairo_surface_mark_dirty CairoSurfaceMarkDirty;
public static D.cairo_surface_write_to_png CairoSurfaceWriteToPng;
public static D.cairo_surface_flush CairoSurfaceFlush;
public static D.cairo_surface_destroy CairoSurfaceDestroy;
public static D.cairo_set_source_surface CairoSetSourceSurface;
public static D.cairo_set_source_rgba CairoSetSourceRgba;
public static D.cairo_scale CairoScale;
public static D.cairo_paint CairoPaint;
public static D.cairo_show_text CairoShowText;
public static D.cairo_select_font_face CairoSelectFontFace;
public static D.cairo_set_font_size CairoSetFontSize;
public static D.cairo_move_to CairoMoveTo;
public static D.cairo_destroy CairoDestroy;
}
public enum GtkWindowType

Просмотреть файл

@ -10,7 +10,7 @@ namespace Avalonia.Gtk3
{
public int ScreenCount
{
get => _allScreens.Length;
get => AllScreens.Length;
}
private Screen[] _allScreens;
@ -23,7 +23,7 @@ namespace Avalonia.Gtk3
IntPtr display = Native.GdkGetDefaultDisplay();
GdkScreen screen = Native.GdkDisplayGetDefaultScreen(display);
short primary = Native.GdkScreenGetPrimaryMonitor(screen);
Screen[] screens = new Screen[ScreenCount];
Screen[] screens = new Screen[Native.GdkScreenGetNMonitors(screen)];
for (short i = 0; i < screens.Length; i++)
{
GdkRectangle workArea = new GdkRectangle(), geometry = new GdkRectangle();

Просмотреть файл

@ -26,7 +26,9 @@ namespace Avalonia.Gtk3
private double _lastScaling;
private uint _lastKbdEvent;
private uint _lastSmoothScrollEvent;
private bool _hasDirtyRects;
private GCHandle _gcHandle;
private object _lock = new object();
private IDeferredRenderOperation _nextRenderOperation;
public WindowBaseImpl(GtkWindow gtkWidget)
{
@ -52,11 +54,25 @@ namespace Avalonia.Gtk3
Connect<Native.D.signal_generic>("destroy", OnDestroy);
Native.GtkWidgetRealize(gtkWidget);
_lastSize = ClientSize;
GlibTimeout.Add(0, 16, () =>
{
Invalidate(default(Rect));
return true;
});
if (Gtk3Platform.UseDeferredRendering)
{
Native.GtkWidgetSetDoubleBuffered(gtkWidget, false);
_gcHandle = GCHandle.Alloc(this);
Native.GtkWidgetAddTickCallback(GtkWidget, PinnedStaticCallback, GCHandle.ToIntPtr(_gcHandle), IntPtr.Zero);
}
}
private bool OnConfigured(IntPtr gtkwidget, IntPtr ev, IntPtr userdata)
{
var size = ClientSize;
int w, h;
Native.GtkWindowGetSize(GtkWidget, out w, out h);
var size = ClientSize = new Size(w, h);
if (_lastSize != size)
{
Resized?.Invoke(size);
@ -224,13 +240,52 @@ namespace Avalonia.Gtk3
private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata)
{
_hasDirtyRects = false;
CurrentCairoContext = cairocontext;
Paint?.Invoke(new Rect(ClientSize));
CurrentCairoContext = IntPtr.Zero;
if (!Gtk3Platform.UseDeferredRendering)
{
CurrentCairoContext = cairocontext;
Paint?.Invoke(new Rect(ClientSize));
CurrentCairoContext = IntPtr.Zero;
}
return true;
}
private static Native.D.TickCallback PinnedStaticCallback = StaticTickCallback;
static bool StaticTickCallback(IntPtr widget, IntPtr clock, IntPtr userData)
{
var impl = (WindowBaseImpl) GCHandle.FromIntPtr(userData).Target;
impl.OnRenderTick();
return true;
}
public void SetNextRenderOperation(IDeferredRenderOperation op)
{
lock (_lock)
{
_nextRenderOperation?.Dispose();
_nextRenderOperation = op;
}
}
private void OnRenderTick()
{
IDeferredRenderOperation op = null;
lock (_lock)
{
if (_nextRenderOperation != null)
{
op = _nextRenderOperation;
_nextRenderOperation = null;
}
}
if (op != null)
{
op?.RenderNow();
op?.Dispose();
}
}
public void Dispose()
{
//We are calling it here, since signal handler will be detached
@ -239,6 +294,10 @@ namespace Avalonia.Gtk3
foreach(var d in Disposables.AsEnumerable().Reverse())
d.Dispose();
Disposables.Clear();
if (_gcHandle.IsAllocated)
{
_gcHandle.Free();
}
}
public Size MaxClientSize
@ -273,20 +332,8 @@ namespace Avalonia.Gtk3
{
if(GtkWidget.IsClosed)
return;
Native.GtkWidgetQueueDrawArea(GtkWidget, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
if (!_hasDirtyRects)
{
_hasDirtyRects = true;
Dispatcher.UIThread.InvokeAsync(() =>
{
if (GtkWidget.IsClosed)
return;
var window = Native.GtkWidgetGetWindow(GtkWidget);
if (window == IntPtr.Zero)
return;
Native.GdkWindowProcessUpdates(window, false);
}, DispatcherPriority.Render);
}
var s = ClientSize;
Native.GtkWidgetQueueDrawArea(GtkWidget, 0, 0, (int) s.Width, (int) s.Height);
}
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
@ -339,17 +386,7 @@ namespace Avalonia.Gtk3
}
public Size ClientSize
{
get
{
if (GtkWidget.IsClosed)
return new Size();
int w, h;
Native.GtkWindowGetSize(GtkWidget, out w, out h);
return new Size(w, h);
}
}
public Size ClientSize { get; private set; }
public void Resize(Size value)
{
@ -376,7 +413,10 @@ namespace Avalonia.Gtk3
public IRenderer CreateRenderer(IRenderRoot root)
{
return new ImmediateRenderer(root);
var loop = AvaloniaLocator.Current.GetService<IRenderLoop>();
return Gtk3Platform.UseDeferredRendering
? (IRenderer) new DeferredRenderer(root, loop)
: new ImmediateRenderer(root);
}
}
}