From 8ffc556d441013e06236f144020b91ea4e3a3f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 31 Aug 2021 19:42:22 +0200 Subject: [PATCH] main: verify primary font is monospaced at startup Load a couple of ASCII glyphs and check if their advance widths matches. If not, warn the user that the font is probably not monospaced. This can be disabled by setting tweak.font-monospace-warn=no. Closes #704. --- config.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ config.h | 4 ++++ doc/foot.ini.5.scd | 11 ++++++++++ main.c | 5 +++++ 4 files changed, 72 insertions(+) diff --git a/config.c b/config.c index ac6dd24d..ca1278df 100644 --- a/config.c +++ b/config.c @@ -2452,6 +2452,9 @@ parse_section_tweak( conf->tweak.box_drawing_solid_shades ? "yes" : "no"); } + else if (strcmp(key, "font-monospace-warn") == 0) + conf->tweak.font_monospace_warn = str_to_bool(value); + else { LOG_AND_NOTIFY_ERR("%s:%u: [tweak]: %s: invalid key", path, lineno, key); return false; @@ -2957,6 +2960,7 @@ config_load(struct config *conf, const char *conf_path, .damage_whole_window = false, .box_drawing_base_thickness = 0.04, .box_drawing_solid_shades = true, + .font_monospace_warn = true, }, .notifications = tll_init(), @@ -3356,3 +3360,51 @@ config_font_list_destroy(struct config_font_list *font_list) font_list->count = 0; font_list->arr = NULL; } + + +bool +check_if_font_is_monospaced(const char *pattern, + user_notifications_t *notifications) +{ + struct fcft_font *f = fcft_from_name( + 1, (const char *[]){pattern}, ":size=8"); + + if (f == NULL) + return true; + + static const wchar_t chars[] = {L'a', L'i', L'l', L'M', L'W'}; + + bool is_monospaced = true; + int last_width = -1; + + for (size_t i = 0; i < sizeof(chars) / sizeof(chars[0]); i++) { + const struct fcft_glyph *g = fcft_glyph_rasterize( + f, chars[i], FCFT_SUBPIXEL_NONE); + + if (g == NULL) + continue; + + if (last_width >= 0 && g->advance.x != last_width) { + LOG_WARN("%s: font does not appear to be monospace; " + "check your config, or disable this warning by " + "setting [tweak].font-monospace-warn=no", + pattern); + + user_notification_add( + notifications, + USER_NOTIFICATION_WARNING, + "%s: font does not appear to be monospace; " + "check your config, or disable this warning by " + "settting \033[1m[tweak].font-monospace-warn=no\033[22m", + pattern); + + is_monospaced = false; + break; + } + + last_width = g->advance.x; + } + + fcft_destroy(f); + return is_monospaced; +} diff --git a/config.h b/config.h index 40daaf3b..6646cca3 100644 --- a/config.h +++ b/config.h @@ -253,6 +253,7 @@ struct config { off_t max_shm_pool_size; float box_drawing_base_thickness; bool box_drawing_solid_shades; + bool font_monospace_warn; } tweak; user_notifications_t notifications; @@ -269,3 +270,6 @@ struct config *config_clone(const struct config *old); bool config_font_parse(const char *pattern, struct config_font *font); void config_font_list_destroy(struct config_font_list *font_list); + +bool check_if_font_is_monospaced( + const char *pattern, user_notifications_t *notifications); diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 65a3a4dc..a124316e 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -1022,6 +1022,17 @@ any of these options. Default: _double-width_ +*font-monospace-warn* + Boolean. When enabled, foot will use heuristics to try to verify + the primary font is a monospace font, and warn if it is not. + + Disable this if you still want to use the font, even if foot + thinks it is not monospaced. + + You may also want to disable it to get slightly faster startup times. + + Default: _yes_ + *max-shm-pool-size-mb* This option controls the amount of virtual address space used by the pixmap memory to which the terminal screen content is diff --git a/main.c b/main.c index b036b9f6..4f7b027d 100644 --- a/main.c +++ b/main.c @@ -480,6 +480,11 @@ main(int argc, char *const *argv) conf.presentation_timings = presentation_timings; conf.hold_at_exit = hold; + if (conf.tweak.font_monospace_warn && conf.fonts[0].count > 0) { + check_if_font_is_monospaced( + conf.fonts[0].arr[0].pattern, &conf.notifications); + } + struct fdm *fdm = NULL; struct reaper *reaper = NULL; struct wayland *wayl = NULL;