Browse Source

[GTK3] Implemented HiDPI support (needs GTK 3.10)

pull/884/head
Nikita Tsukanov 9 years ago
parent
commit
10bf738545
  1. 2
      src/Gtk/Avalonia.Gtk3/FramebufferManager.cs
  2. 21
      src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs
  3. 10
      src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs
  4. 9
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  5. 10
      src/Gtk/Avalonia.Gtk3/Interop/Resolver.cs
  6. 11
      src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

2
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@ -26,7 +26,7 @@ namespace Avalonia.Gtk3
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, width, height);
return new ImageSurfaceFramebuffer(_window.CurrentCairoContext, _window.GtkWidget, width, height);
}
}
}

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

@ -13,12 +13,19 @@ namespace Avalonia.Gtk3
class ImageSurfaceFramebuffer : ILockedFramebuffer
{
private IntPtr _context;
private readonly GtkWidget _widget;
private CairoSurface _surface;
private int _factor;
public ImageSurfaceFramebuffer(IntPtr context, int width, int height)
public ImageSurfaceFramebuffer(IntPtr context, GtkWidget widget, int width, int height)
{
_context = context;
_widget = widget;
_factor = (int)(Native.GtkWidgetGetScaleFactor?.Invoke(_widget) ?? 1u);
width *= _factor;
height *= _factor;
_surface = Native.CairoImageSurfaceCreate(1, width, height);
Width = width;
Height = height;
Address = Native.CairoImageSurfaceGetData(_surface);
@ -31,6 +38,7 @@ namespace Avalonia.Gtk3
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;
@ -43,8 +51,15 @@ namespace Avalonia.Gtk3
public int Height { get; }
public int RowBytes { get; }
//TODO: Proper DPI detect
public Size Dpi => new Size(96, 96);
public Size Dpi
{
get
{
return new Size(96, 96) * _factor;
}
}
public PixelFormat Format => PixelFormat.Bgra8888;
}

10
src/Gtk/Avalonia.Gtk3/Interop/DynLoader.cs

@ -13,7 +13,7 @@ namespace Avalonia.Gtk3.Interop
internal interface IDynLoader
{
IntPtr LoadLibrary(string dll);
IntPtr GetProcAddress(IntPtr dll, string proc);
IntPtr GetProcAddress(IntPtr dll, string proc, bool optional);
}
@ -91,10 +91,10 @@ namespace Avalonia.Gtk3.Interop
return handle;
}
public IntPtr GetProcAddress(IntPtr dll, string proc)
public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional)
{
var ptr = DlSym(dll, proc);
if (ptr == IntPtr.Zero)
if (ptr == IntPtr.Zero && !optional)
throw new NativeException(DlErrorString());
return ptr;
}
@ -118,10 +118,10 @@ namespace Avalonia.Gtk3.Interop
throw new NativeException("Error loading " + dll + " error " + err);
}
IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc)
IntPtr IDynLoader.GetProcAddress(IntPtr dll, string proc, bool optional)
{
var ptr = GetProcAddress(dll, proc);
if (ptr == IntPtr.Zero)
if (ptr == IntPtr.Zero && !optional)
throw new NativeException("Error " + Marshal.GetLastWin32Error());
return ptr;
}

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

@ -50,6 +50,10 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_get_window(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk, optional: true)]
public delegate uint gtk_widget_get_scale_factor(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate IntPtr gtk_widget_get_screen(GtkWidget gtkWidget);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
@ -130,6 +134,9 @@ 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_scale(IntPtr context, double sx, double sy);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate void cairo_paint(IntPtr context);
@ -275,6 +282,7 @@ 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_scale_factor GtkWidgetGetScaleFactor;
public static D.gtk_widget_get_screen GtkWidgetGetScreen;
public static D.gtk_widget_realize GtkWidgetRealize;
public static D.gtk_window_get_size GtkWindowGetSize;
@ -343,6 +351,7 @@ namespace Avalonia.Gtk3.Interop
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_scale CairoScale;
public static D.cairo_paint CairoPaint;
}

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

@ -128,9 +128,11 @@ namespace Avalonia.Gtk3.Interop
if(import == null)
continue;
IntPtr lib = dlls[import.Dll];
var funcPtr = loader.GetProcAddress(lib, import.Name ?? fieldInfo.FieldType.Name);
fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType));
var funcPtr = loader.GetProcAddress(lib, import.Name ?? fieldInfo.FieldType.Name, import.Optional);
if (funcPtr != IntPtr.Zero)
fieldInfo.SetValue(null, Marshal.GetDelegateForFunctionPointer(funcPtr, fieldInfo.FieldType));
}
var nativeHandleNames = new[] { "gdk_win32_window_get_handle", "gdk_x11_window_get_xid", "gdk_quartz_window_get_nswindow" };
@ -139,7 +141,7 @@ namespace Avalonia.Gtk3.Interop
try
{
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle)Marshal
.GetDelegateForFunctionPointer(loader.GetProcAddress(dlls[GtkDll.Gdk], name), typeof(Native.D.gdk_get_native_handle));
.GetDelegateForFunctionPointer(loader.GetProcAddress(dlls[GtkDll.Gdk], name, false), typeof(Native.D.gdk_get_native_handle));
break;
}
catch { }

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

@ -21,6 +21,7 @@ namespace Avalonia.Gtk3
protected readonly List<IDisposable> Disposables = new List<IDisposable>();
private Size _lastSize;
private Point _lastPosition;
private double _lastScaling;
private uint _lastKbdEvent;
private uint _lastSmoothScrollEvent;
@ -63,7 +64,12 @@ namespace Avalonia.Gtk3
PositionChanged?.Invoke(pos);
_lastPosition = pos;
}
var scaling = Scaling;
if (_lastScaling != scaling)
{
ScalingChanged?.Invoke(scaling);
_lastScaling = scaling;
}
return false;
}
@ -228,7 +234,8 @@ namespace Avalonia.Gtk3
}
public double Scaling => 1; //TODO: Implement scaling
public double Scaling => (double) 1 / (Native.GtkWidgetGetScaleFactor?.Invoke(GtkWidget) ?? 1);
public IPlatformHandle Handle => this;
string IPlatformHandle.HandleDescriptor => "HWND";

Loading…
Cancel
Save