From 088fc6fc565471ab57889fd81d10e574b90e2f39 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Oct 2017 13:09:29 +0300 Subject: [PATCH 1/3] [GTK3] Fixed DPI support for DeferredRenderer --- src/Gtk/Avalonia.Gtk3/FramebufferManager.cs | 2 +- .../Avalonia.Gtk3/ImageSurfaceFramebuffer.cs | 26 ++++++++----------- src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 6 ++++- src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs | 3 ++- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs index 00d1ec05f3..b0cc668569 100644 --- a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs +++ b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs @@ -27,7 +27,7 @@ namespace Avalonia.Gtk3 var s = _window.ClientSize; var width = (int) s.Width; var height = (int) s.Height; - return new ImageSurfaceFramebuffer(_window, width, height); + return new ImageSurfaceFramebuffer(_window, width, height, _window.LastKnownScaleFactor); } } } diff --git a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs index 34a95df47e..53771dd369 100644 --- a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs +++ b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs @@ -19,11 +19,11 @@ namespace Avalonia.Gtk3 private CairoSurface _surface; private int _factor; private object _lock = new object(); - public ImageSurfaceFramebuffer(WindowBaseImpl impl, int width, int height) + public ImageSurfaceFramebuffer(WindowBaseImpl impl, int width, int height, int factor) { _impl = impl; _widget = impl.GtkWidget; - _factor = (int)(Native.GtkWidgetGetScaleFactor?.Invoke(_widget) ?? 1u); + _factor = factor; width *= _factor; height *= _factor; _surface = Native.CairoImageSurfaceCreate(1, width, height); @@ -32,23 +32,21 @@ namespace Avalonia.Gtk3 Height = height; Address = Native.CairoImageSurfaceGetData(_surface); RowBytes = Native.CairoImageSurfaceGetStride(_surface); + Native.CairoSurfaceSetDeviceScale(_surface, factor, factor); Native.CairoSurfaceFlush(_surface); } - static void Draw(IntPtr context, CairoSurface surface, double factor) + static void Draw(IntPtr context, CairoSurface surface) { - 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) + static void DrawToWidget(GtkWidget widget, CairoSurface surface, int width, int height) { if(surface == null || widget.IsClosed) return; @@ -58,7 +56,7 @@ namespace Avalonia.Gtk3 var rc = new GdkRectangle {Width = width, Height = height}; Native.GdkWindowBeginPaintRect(window, ref rc); var context = Native.GdkCairoCreate(window); - Draw(context, surface, factor); + Draw(context, surface); /* _frames++; var el = St.Elapsed; @@ -84,15 +82,13 @@ namespace Avalonia.Gtk3 { 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) + public RenderOp(GtkWidget widget, CairoSurface _surface, int width, int height) { _widget = widget; this._surface = _surface; - _factor = factor; _width = width; _height = height; } @@ -105,7 +101,7 @@ namespace Avalonia.Gtk3 public void RenderNow() { - DrawToWidget(_widget, _surface, _width, _height, _factor); + DrawToWidget(_widget, _surface, _width, _height); } } @@ -116,13 +112,13 @@ namespace Avalonia.Gtk3 if (Dispatcher.UIThread.CheckAccess()) { if (_impl.CurrentCairoContext != IntPtr.Zero) - Draw(_impl.CurrentCairoContext, _surface, _factor); + Draw(_impl.CurrentCairoContext, _surface); else - DrawToWidget(_widget, _surface, Width, Height, _factor); + DrawToWidget(_widget, _surface, Width, Height); _surface.Dispose(); } else - _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Width, Height)); + _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, Width, Height)); _surface = null; } } diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index a6a08c3614..3c6c60ba10 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -178,7 +178,10 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] public delegate void cairo_surface_destroy(IntPtr surface); - + + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] + public delegate void cairo_surface_set_device_scale(CairoSurface surface, double sx, double sy); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] public delegate void cairo_set_source_surface(IntPtr cr, CairoSurface surface, double x, double y); @@ -465,6 +468,7 @@ namespace Avalonia.Gtk3.Interop 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_surface_set_device_scale CairoSurfaceSetDeviceScale; public static D.cairo_set_source_surface CairoSetSourceSurface; public static D.cairo_set_source_rgba CairoSetSourceRgba; public static D.cairo_scale CairoScale; diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index 009ef6763c..bfec3db756 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -306,7 +306,7 @@ namespace Avalonia.Gtk3 public IMouseDevice MouseDevice => Gtk3Platform.Mouse; - public double Scaling => (double) 1 / (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1); + public double Scaling => LastKnownScaleFactor = (int) (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1); public IPlatformHandle Handle => this; @@ -387,6 +387,7 @@ namespace Avalonia.Gtk3 public Size ClientSize { get; private set; } + public int LastKnownScaleFactor { get; private set; } public void Resize(Size value) { From e877f6e86468b7f9476e9f770321b0d389cb0b58 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Oct 2017 16:09:35 +0300 Subject: [PATCH 2/3] [GTK3] Revert to manually scaling the surface, cairo_surface_set_device_scale is not supported on Ubuntu 14.04 --- .../Avalonia.Gtk3/ImageSurfaceFramebuffer.cs | 22 +++++++++++-------- src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 4 ---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs index 53771dd369..182da7df58 100644 --- a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs +++ b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs @@ -32,21 +32,23 @@ namespace Avalonia.Gtk3 Height = height; Address = Native.CairoImageSurfaceGetData(_surface); RowBytes = Native.CairoImageSurfaceGetStride(_surface); - Native.CairoSurfaceSetDeviceScale(_surface, factor, factor); Native.CairoSurfaceFlush(_surface); } - static void Draw(IntPtr context, CairoSurface 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) + static void DrawToWidget(GtkWidget widget, CairoSurface surface, int width, int height, double factor) { if(surface == null || widget.IsClosed) return; @@ -56,7 +58,7 @@ namespace Avalonia.Gtk3 var rc = new GdkRectangle {Width = width, Height = height}; Native.GdkWindowBeginPaintRect(window, ref rc); var context = Native.GdkCairoCreate(window); - Draw(context, surface); + Draw(context, surface, factor); /* _frames++; var el = St.Elapsed; @@ -82,13 +84,15 @@ namespace Avalonia.Gtk3 { 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, int width, 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; } @@ -101,7 +105,7 @@ namespace Avalonia.Gtk3 public void RenderNow() { - DrawToWidget(_widget, _surface, _width, _height); + DrawToWidget(_widget, _surface, _width, _height, _factor); } } @@ -112,13 +116,13 @@ namespace Avalonia.Gtk3 if (Dispatcher.UIThread.CheckAccess()) { if (_impl.CurrentCairoContext != IntPtr.Zero) - Draw(_impl.CurrentCairoContext, _surface); + Draw(_impl.CurrentCairoContext, _surface, _factor); else - DrawToWidget(_widget, _surface, Width, Height); + DrawToWidget(_widget, _surface, Width, Height, _factor); _surface.Dispose(); } else - _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, Width, Height)); + _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Width, Height)); _surface = null; } } diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 3c6c60ba10..14b498077c 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -179,9 +179,6 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] public delegate void cairo_surface_destroy(IntPtr surface); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] - public delegate void cairo_surface_set_device_scale(CairoSurface surface, double sx, double sy); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)] public delegate void cairo_set_source_surface(IntPtr cr, CairoSurface surface, double x, double y); @@ -468,7 +465,6 @@ namespace Avalonia.Gtk3.Interop 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_surface_set_device_scale CairoSurfaceSetDeviceScale; public static D.cairo_set_source_surface CairoSetSourceSurface; public static D.cairo_set_source_rgba CairoSetSourceRgba; public static D.cairo_scale CairoScale; From 1380436b76a165c06a395e64124f0c2d438fb964 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 3 Oct 2017 16:41:47 +0300 Subject: [PATCH 3/3] [GTK3] Use GTK window state management functions instead of GDK --- src/Gtk/Avalonia.Gtk3/Interop/Native.cs | 24 ++++++++++++------------ src/Gtk/Avalonia.Gtk3/WindowImpl.cs | 9 ++++----- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs index 14b498077c..c96fb23366 100644 --- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs +++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs @@ -236,17 +236,17 @@ namespace Avalonia.Gtk3.Interop [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate GdkWindowState gdk_window_get_state(IntPtr window); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] - public delegate void gdk_window_iconify(IntPtr window); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_iconify(GtkWindow window); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] - public delegate void gdk_window_deiconify(IntPtr window); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_deiconify(GtkWindow window); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] - public delegate void gdk_window_maximize(IntPtr window); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_maximize(GtkWindow window); - [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] - public delegate void gdk_window_unmaximize(IntPtr window); + [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)] + public delegate void gtk_window_unmaximize(GtkWindow window); [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)] public delegate void gtk_window_set_geometry_hints(GtkWindow window, IntPtr geometry_widget, ref GdkGeometry geometry, GdkWindowHints geom_mask); @@ -437,10 +437,10 @@ namespace Avalonia.Gtk3.Interop public static D.gdk_window_get_origin GdkWindowGetOrigin; public static D.gdk_window_get_pointer GdkWindowGetPointer; public static D.gdk_window_get_state GdkWindowGetState; - public static D.gdk_window_iconify GdkWindowIconify; - public static D.gdk_window_deiconify GdkWindowDeiconify; - public static D.gdk_window_maximize GdkWindowMaximize; - public static D.gdk_window_unmaximize GdkWindowUnmaximize; + public static D.gtk_window_iconify GtkWindowIconify; + public static D.gtk_window_deiconify GtkWindowDeiconify; + public static D.gtk_window_maximize GtkWindowMaximize; + public static D.gtk_window_unmaximize GtkWindowUnmaximize; public static D.gdk_window_begin_move_drag GdkWindowBeginMoveDrag; public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag; public static D.gdk_event_request_motions GdkEventRequestMotions; diff --git a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs index a4bc45c0a1..c586661a7a 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowImpl.cs @@ -32,15 +32,14 @@ namespace Avalonia.Gtk3 } set { - var w = Native.GtkWidgetGetWindow(GtkWidget); if (value == WindowState.Minimized) - Native.GdkWindowIconify(w); + Native.GtkWindowIconify(GtkWidget); else if (value == WindowState.Maximized) - Native.GdkWindowMaximize(w); + Native.GtkWindowMaximize(GtkWidget); else { - Native.GdkWindowUnmaximize(w); - Native.GdkWindowDeiconify(w); + Native.GtkWindowUnmaximize(GtkWidget); + Native.GtkWindowDeiconify(GtkWidget); } } }