Getting Physical DPI with Fractional Scaling

I’m trying to obtain both the logical (scaled) DPI and the real (physical) DPI for a monitor when fractional scaling is enabled. I need the logical DPI to size my widgets correctly and the physical DPI to render textures at their true size so they stay sharp.

What I have so far (logical DPI)

// Get display geometry
let geometry = monitor.geometry();
let logical_width = geometry.width() as f64;
let logical_height = geometry.height() as f64;

// Physical size of the panel (mm) – obtained from monitor.physical_width() / height()
let width_mm = monitor.physical_width() as f64;
let height_mm = monitor.physical_height() as f64;

// Calculate the logical DPI
let layout_dpi_x = (logical_width / (width_mm / 25.4)).round();
let layout_dpi_y = (logical_height / (height_mm / 25.4)).round();
let layout_dpi = ((layout_dpi_x + layout_dpi_y) / 2.0).round() as u32;

This works fine on a 1× scale, but once I enable a fractional scale (e.g., 125 % or 150 %), monitor.geometry() returns the scaled size, so layout_dpi reflects the logical DPI rather than the true pixel density.

Is there a way to get the physical DPI or the physical display resolution directly, or failing that, a way to retrieve the scale factor that GNOME is applying (e.g., 1.25, 1.5, not necessarily the direct integer scale that is then downscaled by GTK) so I can convert between logical and physical DPI?

Using the DPI is not something that will help you, because hardware lies.

You can get the scaling factor communicated by the compositor to GTK using Gdk.Monitor.get_scale(), but it’s rare that you’d ever need this. You should ask the scaling factor of the surface that will draw a widget, by getting the root widget using Gtk.Widget.get_root(), then using Gtk.Native.get_surface(). Once you have the surface, you can use Gdk.Surface.get_scale() to get the scaling factor.