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
This commit is contained in:
Riccardo Binetti
2024-01-07 17:05:39 +01:00
parent fe0842c2d0
commit ad503b8c4f

View File

@ -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 {