From 7c20fb247c977fe545b1ef0ce9d8935b0424bf70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 17 Apr 2024 08:35:58 +0200 Subject: [PATCH] term: stash last known DPI, and use after a unmapped/mapped sequence A compositor may unmap, and then remap the window, for example when the window is minimized, or if the user switches workspace. With DPI aware rendering, we *need* to know on which output we're mapped, in order to use the correct DPI. This means the first frame we render, before being mapped, always guesses the DPI. In an unmap/map sequence, guessing the wrong DPI means the window will flicker. Fix by stashing the last used DPI value, and use that instead of guessing. This means the *only* time we _actually_ guess the DPI, is the very first frame, when starting up foot. --- CHANGELOG.md | 3 +++ terminal.c | 24 +++++++++++++++++++++--- terminal.h | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4276f0a..b4384f0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,9 @@ * Crash when printing double-width (or longer) characters to, or near, the last column, when auto-wrap (private mode 7) has been disabled. * Dynamically sized sixel being trimmed to nothing. +* Flickering with `dpi-aware=yes` and window is unmapped/remapped + (some compositors do this when window is minimized), in a + multi-monitor setup with different monitor DPIs. ### Security diff --git a/terminal.c b/terminal.c index e747009a..c027cfac 100644 --- a/terminal.c +++ b/terminal.c @@ -858,9 +858,25 @@ get_font_dpi(const struct terminal *term) xassert(tll_length(term->wl->monitors) > 0); const struct wl_window *win = term->window; - const struct monitor *mon = tll_length(win->on_outputs) > 0 - ? tll_back(win->on_outputs) - : &tll_front(term->wl->monitors); + const struct monitor *mon = NULL; + + if (tll_length(win->on_outputs) > 0) + mon = tll_back(win->on_outputs); + else { + if (term->font_dpi_before_unmap > 0.) { + /* + * Use last known "good" DPI + * + * This avoids flickering when window is unmapped/mapped + * (some compositors do this when a window is minimized), + * on a multi-monitor setup with different monitor DPIs. + */ + return term->font_dpi_before_unmap; + } + + if (tll_length(term->wl->monitors) > 0) + mon = &tll_front(term->wl->monitors); + } if (term_fractional_scaling(term)) return mon != NULL ? mon->dpi.physical : 96.; @@ -1182,6 +1198,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, xmalloc(sizeof(term->font_sizes[3][0]) * conf->fonts[3].count), }, .font_dpi = 0., + .font_dpi_before_unmap = -1., .font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */ ? FCFT_SUBPIXEL_DEFAULT : FCFT_SUBPIXEL_NONE), @@ -2250,6 +2267,7 @@ term_font_dpi_changed(struct terminal *term, float old_scale) } term->font_dpi = dpi; + term->font_dpi_before_unmap = dpi; term->font_is_sized_by_dpi = will_scale_using_dpi; if (!need_font_reload) diff --git a/terminal.h b/terminal.h index fa80e693..2a0845ef 100644 --- a/terminal.h +++ b/terminal.h @@ -406,6 +406,7 @@ struct terminal { struct config_font *font_sizes[4]; struct pt_or_px font_line_height; float font_dpi; + float font_dpi_before_unmap; bool font_is_sized_by_dpi; int16_t font_x_ofs; int16_t font_y_ofs;