From fe0842c2d0dd68d003ed73c3f174a68abfd585b5 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Sun, 7 Jan 2024 16:54:01 +0100 Subject: [PATCH 1/3] linux: add a function to check if we're running on X11 --- src/apprt/gtk/x11.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/apprt/gtk/x11.zig b/src/apprt/gtk/x11.zig index 8965a72e0..e2990c7ba 100644 --- a/src/apprt/gtk/x11.zig +++ b/src/apprt/gtk/x11.zig @@ -13,6 +13,12 @@ pub fn is_display(display: ?*c.GdkDisplay) bool { ) != 0; } +/// Returns true if the app is running on X11 +pub fn is_current_display_server() bool { + const display = c.gdk_display_get_default(); + return is_display(display); +} + pub const Xkb = struct { base_event_code: c_int, funcs: Funcs, From ad503b8c4fa76a0cf91ad7c81344ad1d6d637af2 Mon Sep 17 00:00:00 2001 From: Riccardo Binetti Date: Sun, 7 Jan 2024 17:05:39 +0100 Subject: [PATCH 2/3] linux: consider Xft.dpi to scale the content Many applications use Xft.dpi to scale their contents (e.g. Chromium, kitty, alacritty...). This value also gets set by DE setting managers and can be manually set in ~/.Xresources if using, e.g., i3. This should make HiDPI on Linux more consistent even when not using GTK-specific methods (e.g. GDK_SCALE=2). Note that we still consider GTK scaling, so it's possible to use the two independently. Closes #1243 --- src/apprt/gtk/Surface.zig | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 37c5155f0..ae6d05c97 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -20,6 +20,7 @@ const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig"); const inspector = @import("inspector.zig"); const gtk_key = @import("key.zig"); const c = @import("c.zig"); +const x11 = @import("x11.zig"); const log = std.log.scoped(.gtk_surface); @@ -660,8 +661,33 @@ pub fn shouldClose(self: *const Surface) bool { pub fn getContentScale(self: *const Surface) !apprt.ContentScale { // Future: detect GTK version 4.12+ and use gdk_surface_get_scale so we // can support fractional scaling. - const scale = c.gtk_widget_get_scale_factor(@ptrCast(self.gl_area)); - return .{ .x = @floatFromInt(scale), .y = @floatFromInt(scale) }; + const gtk_scale: f32 = @floatFromInt(c.gtk_widget_get_scale_factor(@ptrCast(self.gl_area))); + + // If we are on X11, we also have to scale using Xft.dpi + const xft_dpi_scale = if (x11.is_current_display_server()) getXftDpiScale() else 1.0; + + const scale = gtk_scale * xft_dpi_scale; + + return .{ .x = scale, .y = scale }; +} + +fn getXftDpiScale() f32 { + // Here we use GTK to retrieve gtk-xft-dpi, which is Xft.dpi multiplied by 1024 + // See https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html + const settings = c.gtk_settings_get_default(); + + var value: c.GValue = std.mem.zeroes(c.GValue); + defer c.g_value_unset(&value); + _ = c.g_value_init(&value, c.G_TYPE_INT); + + c.g_object_get_property(@ptrCast(@alignCast(settings)), "gtk-xft-dpi", &value); + const gtk_xft_dpi = c.g_value_get_int(&value); + + // Scale the value back to obtain Xft.dpi + const xft_dpi = @divExact(gtk_xft_dpi, 1024); + + // Divide by the default value of Xft.dpi (96) to derive a scale + return @as(f32, @floatFromInt(xft_dpi)) / 96.0; } pub fn getSize(self: *const Surface) !apprt.SurfaceSize { From b62c78b61d363bc826805ff7f7207e5b147f76be Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 7 Jan 2024 12:25:56 -0800 Subject: [PATCH 3/3] apprt/gtk: stylistic changes --- src/apprt/gtk/Surface.zig | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index ae6d05c97..90df1ff35 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -664,32 +664,27 @@ pub fn getContentScale(self: *const Surface) !apprt.ContentScale { const gtk_scale: f32 = @floatFromInt(c.gtk_widget_get_scale_factor(@ptrCast(self.gl_area))); // If we are on X11, we also have to scale using Xft.dpi - const xft_dpi_scale = if (x11.is_current_display_server()) getXftDpiScale() else 1.0; + const xft_dpi_scale = if (!x11.is_current_display_server()) 1.0 else xft_scale: { + // Here we use GTK to retrieve gtk-xft-dpi, which is Xft.dpi multiplied + // by 1024. See https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html + const settings = c.gtk_settings_get_default(); + + var value: c.GValue = std.mem.zeroes(c.GValue); + defer c.g_value_unset(&value); + _ = c.g_value_init(&value, c.G_TYPE_INT); + c.g_object_get_property(@ptrCast(@alignCast(settings)), "gtk-xft-dpi", &value); + const gtk_xft_dpi = c.g_value_get_int(&value); + + // As noted above Xft.dpi is multiplied by 1024, so we divide by 1024, + // then divide by the default value of Xft.dpi (96) to derive a scale + const xft_dpi: f32 = @floatFromInt(@divExact(gtk_xft_dpi, 1024)); + break :xft_scale xft_dpi / 96; + }; const scale = gtk_scale * xft_dpi_scale; - return .{ .x = scale, .y = scale }; } -fn getXftDpiScale() f32 { - // Here we use GTK to retrieve gtk-xft-dpi, which is Xft.dpi multiplied by 1024 - // See https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html - const settings = c.gtk_settings_get_default(); - - var value: c.GValue = std.mem.zeroes(c.GValue); - defer c.g_value_unset(&value); - _ = c.g_value_init(&value, c.G_TYPE_INT); - - c.g_object_get_property(@ptrCast(@alignCast(settings)), "gtk-xft-dpi", &value); - const gtk_xft_dpi = c.g_value_get_int(&value); - - // Scale the value back to obtain Xft.dpi - const xft_dpi = @divExact(gtk_xft_dpi, 1024); - - // Divide by the default value of Xft.dpi (96) to derive a scale - return @as(f32, @floatFromInt(xft_dpi)) / 96.0; -} - pub fn getSize(self: *const Surface) !apprt.SurfaceSize { return self.size; }