From 4f510e170366862f52043db8d5a40872b07c1ea2 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Mon, 25 Feb 2019 19:01:34 +0100 Subject: [PATCH] Query the X11 screen's DPI instead of monitor When changing the DPI via xrandr --dpi , xrandr will send a RRScreenChangeEvent and the DPI value should get adjusted. Falsely, we thought randr_update() would catch up and query the right monitor values. But nothing changes, because we query the XRRMonitorInfo. The monitor info contains the real physical width and height of the monitor's screen. But xrandr --dpi only changes the - let's say - virtual screen size of the virtual overall screen (and therefore changing the DPI to the matching value). Important commands to understand: - Changes dpi of the virtual screen xrandr --dpi - Gives info about the "virtual" screen size (used by DisplayWidth) xdpyinfo | grep -B1 resolution - Gives info about the "physical" screen size (used by XRRMonitorInfo) xrandr -q I know, that I'm probably not right and might not understand the topic in its full size yet[0]. But I'm 100% sure, that the terms "monitor", "screen", "screens", "output" and "display" do not have a consistent naming scheme. [0] https://twitter.com/dechampsgu/status/857924498280124416 Fixes #382 --- src/draw.c | 2 +- src/x11/screen.c | 43 +++++++++++++++++++++++++------------------ src/x11/screen.h | 2 +- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/draw.c b/src/draw.c index e1032c0..7dbe55f 100644 --- a/src/draw.c +++ b/src/draw.c @@ -237,7 +237,7 @@ static PangoLayout *layout_create(cairo_t *c) struct screen_info *screen = get_active_screen(); PangoContext *context = pango_cairo_create_context(c); - pango_cairo_context_set_resolution(context, get_dpi_for_screen(screen)); + pango_cairo_context_set_resolution(context, screen_dpi_get(screen)); PangoLayout *layout = pango_layout_new(context); diff --git a/src/x11/screen.c b/src/x11/screen.c index fd23c56..8afde38 100644 --- a/src/x11/screen.c +++ b/src/x11/screen.c @@ -37,7 +37,7 @@ static int x_follow_tear_down_error_handler(void); static int FollowXErrorHandler(Display *display, XErrorEvent *e); static Window get_focused_window(void); -static double get_xft_dpi_value(void) +static double screen_dpi_get_from_xft(void) { static double dpi = -1; //Only run this once, we don't expect dpi changes during runtime @@ -64,6 +64,30 @@ static double get_xft_dpi_value(void) return dpi; } +static double screen_dpi_get_from_monitor(struct screen_info *scr) +{ + return (double)scr->h * 25.4 / (double)scr->mmh; +} + +double screen_dpi_get(struct screen_info *scr) +{ + if ( ! settings.force_xinerama + && settings.per_monitor_dpi) + return screen_dpi_get_from_monitor(scr); + + if (screen_dpi_get_from_xft() > 0) + return screen_dpi_get_from_xft(); + + // Calculate the DPI on the overall screen size. + // xrandr --dpi does only change the overall screen's millimeters, + // but not the physical screen's sizes. + // + // The screen parameter is XDefaultScreen(), as our scr->id references + // the xrandr monitor and not the xrandr screen + return ((((double)DisplayWidth (xctx.dpy, XDefaultScreen(xctx.dpy))) * 25.4) / + ((double)DisplayWidthMM(xctx.dpy, XDefaultScreen(xctx.dpy)))); +} + void init_screens(void) { if (!settings.force_xinerama) { @@ -132,11 +156,6 @@ void randr_update(void) XRRFreeMonitors(m); } -static int autodetect_dpi(struct screen_info *scr) -{ - return (double)scr->h * 25.4 / (double)scr->mmh; -} - void screen_check_event(XEvent event) { if (XRRUpdateConfiguration(&event)) { @@ -349,18 +368,6 @@ sc_cleanup: return &screens[ret]; } -double get_dpi_for_screen(struct screen_info *scr) -{ - double dpi = 0; - if ((!settings.force_xinerama && settings.per_monitor_dpi && - (dpi = autodetect_dpi(scr)))) - return dpi; - else if ((dpi = get_xft_dpi_value())) - return dpi; - else - return 96; -} - /* * Return the window that currently has * the keyboard focus. diff --git a/src/x11/screen.h b/src/x11/screen.h index 864c230..b8d8dc4 100644 --- a/src/x11/screen.h +++ b/src/x11/screen.h @@ -20,7 +20,7 @@ void init_screens(void); void screen_check_event(XEvent event); struct screen_info *get_active_screen(void); -double get_dpi_for_screen(struct screen_info *scr); +double screen_dpi_get(struct screen_info *scr); /** * Find the currently focused window and check if it's in