term: don't use deprecated fcft_size_adjust()

When resizing the font on-the-fly, we now do a complete
font-reload (this is basically what fcft_size_adjust() did anyway).

To get the correct size, we maintain the current size ourselves.

We get the initial size from the user-provided font pattern, by
converting the string to an FcPattern, and using FcPatternGet() to
retrieve both the FC_SIZE and FC_PIXEL_SIZE attributes. These
attributes are then removed from the pattern, and the pattern is
converted back to a string.

The terminal struct maintains a copy of the font sizes. These are
initially set to the sizes from the config.

When the user resizes the font, the terminal-local sizes are
adjusted. To ensure the primary and user-configured fallback fonts are
resizes equally much, convert any pixel sizes to point sizes at this
point.

When the font size is reset, we reload the font sizes from the
config (thus once again returning actual pixel-sizes, if that's what
the user has configured).
This commit is contained in:
Daniel Eklöf 2020-07-07 10:44:55 +02:00
parent 3063204289
commit 69e4213e4a
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
7 changed files with 126 additions and 107 deletions

View file

@ -5,7 +5,7 @@ arch=('x86_64' 'aarch64')
url=https://codeberg.org/dnkl/foot
license=(mit)
makedepends=('meson' 'ninja' 'scdoc' 'python' 'ncurses' 'wayland-protocols' 'tllist>=1.0.1')
depends=('libxkbcommon' 'wayland' 'pixman' 'fcft>=2.1.1')
depends=('libxkbcommon' 'wayland' 'pixman' 'fontconfig' 'fcft>=2.1.1')
source=()
pkgver() {

View file

@ -14,6 +14,7 @@
#include <linux/input-event-codes.h>
#include <xkbcommon/xkbcommon.h>
#include <fontconfig/fontconfig.h>
#define LOG_MODULE "config"
#define LOG_ENABLE_DBG 0
@ -265,7 +266,7 @@ parse_section_main(const char *key, const char *value, struct config *conf,
while (*font != '\0' && isspace(*font))
font++;
if (*font != '\0')
tll_push_back(conf->fonts, strdup(font));
tll_push_back(conf->fonts, config_font_parse(font));
}
free(copy);
}
@ -963,7 +964,7 @@ config_load(struct config *conf, const char *conf_path)
out:
if (ret && tll_length(conf->fonts) == 0)
tll_push_back(conf->fonts, strdup("monospace"));
tll_push_back(conf->fonts, config_font_parse("monospace"));
free(default_path);
return ret;
@ -976,7 +977,9 @@ config_free(struct config conf)
free(conf.shell);
free(conf.title);
free(conf.app_id);
tll_free_and_free(conf.fonts, free);
tll_foreach(conf.fonts, it)
config_font_destroy(&it->item);
tll_free(conf.fonts);
free(conf.server_socket_path);
for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++)
@ -984,3 +987,36 @@ config_free(struct config conf)
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++)
free(conf.bindings.search[i]);
}
struct config_font
config_font_parse(const char *pattern)
{
FcPattern *pat = FcNameParse((const FcChar8 *)pattern);
double pt_size = -1.0;
FcPatternGetDouble(pat, FC_SIZE, 0, &pt_size);
FcPatternRemove(pat, FC_SIZE, 0);
int px_size = -1;
FcPatternGetInteger(pat, FC_PIXEL_SIZE, 0, &px_size);
FcPatternRemove(pat, FC_PIXEL_SIZE, 0);
if (pt_size == -1. && px_size == -1)
pt_size = 8.0;
char *stripped_pattern = (char *)FcNameUnparse(pat);
FcPatternDestroy(pat);
return (struct config_font){
.pattern = stripped_pattern,
.pt_size = pt_size,
.px_size = px_size};
}
void
config_font_destroy(struct config_font *font)
{
if (font == NULL)
return;
free(font->pattern);
}

View file

@ -7,6 +7,12 @@
#include "terminal.h"
struct config_font {
char *pattern;
double pt_size;
int px_size;
};
struct config {
char *term;
char *shell;
@ -19,7 +25,7 @@ struct config {
unsigned pad_y;
enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode;
tll(char *) fonts;
tll(struct config_font) fonts;
int scrollback_lines;
@ -87,3 +93,6 @@ struct config {
bool config_load(struct config *conf, const char *path);
void config_free(struct config conf);
struct config_font config_font_parse(const char *pattern);
void config_font_destroy(struct config_font *font);

8
main.c
View file

@ -224,7 +224,7 @@ main(int argc, char *const *argv)
if (strlen(font) == 0)
continue;
tll_push_back(conf_fonts, strdup(font));
tll_push_back(conf_fonts, font);
}
break;
@ -342,9 +342,11 @@ main(int argc, char *const *argv)
if (login_shell)
conf.login_shell = true;
if (tll_length(conf_fonts) > 0) {
tll_free_and_free(conf.fonts, free);
tll_foreach(conf.fonts, it)
config_font_destroy(&it->item);
tll_free(conf.fonts);
tll_foreach(conf_fonts, it)
tll_push_back(conf.fonts, it->item);
tll_push_back(conf.fonts, config_font_parse(it->item));
tll_free(conf_fonts);
}
if (conf_width > 0)

View file

@ -56,6 +56,7 @@ wayland_protocols = dependency('wayland-protocols')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
xkb = dependency('xkbcommon')
fontconfig = dependency('fontconfig')
tllist = dependency('tllist', version: '>=1.0.1', fallback: 'tllist')
fcft = dependency('fcft', version: ['>=2.1.1', '<3.0.0'], fallback: 'fcft')
@ -126,7 +127,8 @@ executable(
'vt.c', 'vt.h',
'wayland.c', 'wayland.h',
wl_proto_src + wl_proto_headers, version,
dependencies: [math, threads, pixman, wayland_client, wayland_cursor, xkb, tllist, fcft],
dependencies: [math, threads, pixman, wayland_client, wayland_cursor, xkb, fontconfig,
tllist, fcft],
install: true)
executable(

View file

@ -664,27 +664,41 @@ font_loader_thread(void *_data)
}
static bool
load_fonts_from_conf(const struct terminal *term, const struct config *conf,
struct fcft_font *fonts[static 4])
reload_fonts(struct terminal *term)
{
const size_t count = tll_length(conf->fonts);
const char *names[count];
const size_t count = tll_length(term->conf->fonts);
char *names[count];
size_t i = 0;
tll_foreach(conf->fonts, it)
names[i++] = it->item;
tll_foreach(term->conf->fonts, it) {
bool use_px_size = term->font_sizes[i].px_size > 0;
char size[64];
char attrs0[64], attrs1[64], attrs2[64], attrs3[64];
if (use_px_size)
snprintf(size, sizeof(size), ":pixelsize=%d", term->font_sizes[i].px_size);
else
snprintf(size, sizeof(size), ":size=%.2f", term->font_sizes[i].pt_size);
size_t len = strlen(it->item.pattern) + strlen(size) + 1;
names[i] = malloc(len);
strcpy(names[i], it->item.pattern);
strcat(names[i], size);
i++;
}
char attrs0[256], attrs1[256], attrs2[256], attrs3[256];
snprintf(attrs0, sizeof(attrs0), "dpi=%u", term->font_dpi);
snprintf(attrs1, sizeof(attrs1), "dpi=%u:weight=bold", term->font_dpi);
snprintf(attrs2, sizeof(attrs2), "dpi=%u:slant=italic", term->font_dpi);
snprintf(attrs3, sizeof(attrs3), "dpi=%u:weight=bold:slant=italic", term->font_dpi);
struct fcft_font *fonts[4];
struct font_load_data data[4] = {
{count, names, attrs0, &fonts[0]},
{count, names, attrs1, &fonts[1]},
{count, names, attrs2, &fonts[2]},
{count, names, attrs3, &fonts[3]},
{count, (const char **)names, attrs0, &fonts[0]},
{count, (const char **)names, attrs1, &fonts[1]},
{count, (const char **)names, attrs2, &fonts[2]},
{count, (const char **)names, attrs3, &fonts[3]},
};
thrd_t tids[4] = {};
@ -715,7 +729,22 @@ load_fonts_from_conf(const struct terminal *term, const struct config *conf,
}
}
return success;
for (size_t i = 0; i < count; i++)
free(names[i]);
return success ? term_set_fonts(term, fonts) : success;
}
static bool
load_fonts_from_conf(struct terminal *term)
{
size_t i = 0;
tll_foreach(term->conf->fonts, it) {
term->font_sizes[i++] = (struct config_font){
.pt_size = it->item.pt_size, .px_size = it->item.px_size};
}
return reload_fonts(term);
}
struct terminal *
@ -802,8 +831,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.quit = false,
.ptmx = ptmx,
.ptmx_buffer = tll_init(),
.font_sizes = malloc(sizeof(term->font_sizes[0]) * tll_length(conf->fonts)),
.font_dpi = 0,
.font_adjustments = 0,
.font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */
? FCFT_SUBPIXEL_DEFAULT
: FCFT_SUBPIXEL_NONE),
@ -900,6 +929,14 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.cwd = strdup(cwd),
};
{
size_t i = 0;
tll_foreach(conf->fonts, it) {
term->font_sizes[i++] = (struct config_font){
.pt_size = it->item.pt_size, .px_size = it->item.px_size};
}
}
/* Start the slave/client */
if ((term->slave = slave_spawn(
term->ptmx, argc, term->cwd, argv,
@ -1144,6 +1181,7 @@ term_destroy(struct terminal *term)
for (size_t i = 0; i < sizeof(term->fonts) / sizeof(term->fonts[0]); i++)
fcft_destroy(term->fonts[i]);
free(term->font_sizes);
free(term->search.buf);
@ -1377,57 +1415,31 @@ term_reset(struct terminal *term, bool hard)
term_damage_all(term);
}
struct font_adjust_data {
struct fcft_font *font_in;
double amount;
struct fcft_font *font_out;
};
static int
font_size_adjust_thread(void *_data)
{
struct font_adjust_data *data = _data;
data->font_out = fcft_size_adjust(data->font_in, data->amount);
return data->font_out != NULL;
}
static bool
term_font_size_adjust(struct terminal *term, double amount)
{
struct font_adjust_data data[4] = {
{term->fonts[0], amount},
{term->fonts[1], amount},
{term->fonts[2], amount},
{term->fonts[3], amount},
};
for (size_t i = 0; i < tll_length(term->conf->fonts); i++) {
double old_pt_size = term->font_sizes[i].pt_size;
thrd_t tids[4] = {};
for (size_t i = 0; i < 4; i++) {
int ret = thrd_create(&tids[i], &font_size_adjust_thread, &data[i]);
if (ret != thrd_success) {
LOG_ERR("failed to create font adjustmen thread: %s (%d)",
thrd_err_as_string(ret), ret);
break;
/*
* To ensure primary and user-configured fallback fonts are
* resizes by the same amount, convert pixel sizes to point
* sizes, and to the adjustment on point sizes only.
*/
if (term->font_sizes[i].px_size > 0) {
double dpi = term->font_dpi;
old_pt_size = term->font_sizes[i].px_size * 72. / dpi;
}
}
for (size_t i = 0; i < 4; i++) {
if (tids[i] != 0)
thrd_join(tids[i], NULL);
}
if (data[0].font_out == NULL || data[1].font_out == NULL ||
data[2].font_out == NULL || data[3].font_out == NULL)
{
for (size_t i = 0; i < 4; i++)
fcft_destroy(data[i].font_out);
return false;
term->font_sizes[i].pt_size = old_pt_size + amount;
term->font_sizes[i].px_size = -1;
}
const int old_cell_width = term->cell_width;
const int old_cell_height = term->cell_height;
if (!term_set_fonts(term, (struct fcft_font *[]){data[0].font_out, data[1].font_out, data[2].font_out, data[3].font_out}))
if (!reload_fonts(term))
return false;
if (term->cell_width < old_cell_width ||
@ -1457,7 +1469,6 @@ term_font_size_increase(struct terminal *term)
if (!term_font_size_adjust(term, 0.5))
return false;
term->font_adjustments++;
return true;
}
@ -1467,20 +1478,13 @@ term_font_size_decrease(struct terminal *term)
if (!term_font_size_adjust(term, -0.5))
return false;
term->font_adjustments--;
return true;
}
bool
term_font_size_reset(struct terminal *term)
{
struct fcft_font *fonts[4];
if (!load_fonts_from_conf(term, term->conf, fonts))
return false;
term_set_fonts(term, fonts);
term->font_adjustments = 0;
return true;
return load_fonts_from_conf(term);
}
bool
@ -1493,41 +1497,7 @@ term_font_dpi_changed(struct terminal *term)
LOG_DBG("DPI changed (%u -> %u): reloading fonts", term->font_dpi, dpi);
term->font_dpi = dpi;
struct fcft_font *fonts[4];
if (!load_fonts_from_conf(term, term->conf, fonts))
return false;
if (term->font_adjustments == 0)
return term_set_fonts(term, fonts);
/* User has adjusted the font size run-time, re-apply */
double amount = term->font_adjustments * 0.5;
struct fcft_font *adjusted_fonts[4] = {
fcft_size_adjust(fonts[0], amount),
fcft_size_adjust(fonts[1], amount),
fcft_size_adjust(fonts[2], amount),
fcft_size_adjust(fonts[3], amount),
};
if (adjusted_fonts[0] == NULL || adjusted_fonts[1] == NULL ||
adjusted_fonts[2] == NULL || adjusted_fonts[3] == NULL)
{
for (size_t i = 0; i < 4; i++)
fcft_destroy(adjusted_fonts[i]);
/* At least use the newly re-loaded default fonts */
term->font_adjustments = 0;
return term_set_fonts(term, fonts);
} else {
for (size_t i = 0; i < 4; i++)
fcft_destroy(fonts[i]);
return term_set_fonts(term, adjusted_fonts);
}
assert(false);
return false;
return reload_fonts(term);
}
void

View file

@ -222,8 +222,8 @@ struct terminal {
struct composed *composed;
struct fcft_font *fonts[4];
struct config_font *font_sizes;
int font_dpi;
int font_adjustments;
enum fcft_subpixel font_subpixel;
tll(struct ptmx_buffer) ptmx_buffer;