Merge branch 'custom-bold-italic-fonts'

Closes #169
This commit is contained in:
Daniel Eklöf 2020-10-21 16:33:45 +02:00
commit 353e51b0a1
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 158 additions and 69 deletions

View file

@ -41,6 +41,10 @@
* Terminal content is now auto-scrolled when moving the mouse above or
below the window while selecting
(https://codeberg.org/dnkl/foot/issues/149).
* **font-bold**, **font-italic** and **font-bold-italic** options to
`foot.ini`. These options allow custom bold/italic fonts. They are
unset by default, meaning the bold/italic version of the regular
font is used (https://codeberg.org/dnkl/foot/issues/169).
### Changed

View file

@ -547,14 +547,28 @@ parse_section_main(const char *key, const char *value, struct config *conf,
}
}
else if (strcmp(key, "font") == 0) {
else if (strcmp(key, "font") == 0 ||
strcmp(key, "font-bold") == 0 ||
strcmp(key, "font-italic") == 0 ||
strcmp(key, "font-bold-italic") == 0)
{
size_t idx =
strcmp(key, "font") == 0 ? 0 :
strcmp(key, "font-bold") == 0 ? 1 :
strcmp(key, "font-italic") == 0 ? 2 : 3;
tll_foreach(conf->fonts[idx], it)
config_font_destroy(&it->item);
tll_free(conf->fonts[idx]);
char *copy = xstrdup(value);
for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ",")) {
/* Trim spaces, strictly speaking not necessary, but looks nice :) */
while (*font != '\0' && isspace(*font))
font++;
if (*font != '\0')
tll_push_back(conf->fonts, config_font_parse(font));
tll_push_back(conf->fonts[idx], config_font_parse(font));
}
free(copy);
}
@ -1904,7 +1918,7 @@ config_load(struct config *conf, const char *conf_path,
.pad_y = 2,
.bell_is_urgent = false,
.startup_mode = STARTUP_WINDOWED,
.fonts = tll_init(),
.fonts = {tll_init(), tll_init(), tll_init(), tll_init()},
.scrollback = {
.lines = 1000,
.indicator = {
@ -2028,8 +2042,8 @@ config_load(struct config *conf, const char *conf_path,
conf->colors.selection_bg >> 24 == 0;
out:
if (ret && tll_length(conf->fonts) == 0)
tll_push_back(conf->fonts, config_font_parse("monospace"));
if (ret && tll_length(conf->fonts[0]) == 0)
tll_push_back(conf->fonts[0], config_font_parse("monospace"));
free(conf_file.path);
if (conf_file.fd >= 0)
@ -2047,9 +2061,11 @@ config_free(struct config conf)
free(conf.app_id);
free(conf.word_delimiters);
free(conf.scrollback.indicator.text);
tll_foreach(conf.fonts, it)
config_font_destroy(&it->item);
tll_free(conf.fonts);
for (size_t i = 0; i < ALEN(conf.fonts); i++) {
tll_foreach(conf.fonts[i], it)
config_font_destroy(&it->item);
tll_free(conf.fonts[i]);
}
free(conf.server_socket_path);
tll_foreach(conf.bindings.key, it) {

View file

@ -16,6 +16,7 @@ struct config_font {
double pt_size;
int px_size;
};
typedef tll(struct config_font) config_font_list_t;
struct config_key_modifiers {
bool shift;
@ -77,7 +78,7 @@ struct config {
enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode;
tll(struct config_font) fonts;
config_font_list_t fonts[4];
struct {
int lines;

View file

@ -20,20 +20,30 @@ in this order:
# SECTION: default
*font*
*font*, *font-bold*, *font-italic*, *font-bold-italic*
Comma separated list of fonts to use, in fontconfig format (see
*FONT FORMAT*).
The first font is the primary font. The remaining fonts are
fallback fonts that will be used whenever a glyph cannot be found
in the primary font.
For each option, the first font is the primary font. The remaining
fonts are fallback fonts that will be used whenever a glyph cannot
be found in the primary font.
The fallback fonts are searched in the order they appear. If a
glyph cannot be found in any of the fallback fonts, the dynamic
fallback list from fontconfig (for the primary font) is
searched.
Default: _monospace_.
*font-bold*, *font-italic* and *font-bold-italic* allow custom
fonts to be used for bold/italic/bold+italic fonts. If left
unconfigured, the bold/italic variants of the regular font(s)
specified in *font* are used. *Note*: you _may_ have to tweak the
size(s) of the custom bold/italic fonts to match the regular font.
To disable bold and/or italic fonts, set e.g. *font-bold* to
_exactly_ the same value as *font*.
Default: _monospace_ (*font*), _not set_ (*font-bold*,
*font-italic*, *font-bold-italic*).
*pad*
Padding between border and glyphs, in pixels (subject to output

View file

@ -1,6 +1,9 @@
# -*- conf -*-
# font=monospace
# font-bold=<bold variant of regular font>
# font-italic=<italic variant of regular font>
# font-bold-italic=<bold+italic variant of regular font>
# initial-window-size-pixels=700x500 # Or,
# initial-window-size-chars=<COLSxROWS>
# initial-window-mode=windowed

11
main.c
View file

@ -27,6 +27,7 @@
#include "server.h"
#include "shm.h"
#include "terminal.h"
#include "util.h"
#include "version.h"
#include "xmalloc.h"
@ -387,11 +388,13 @@ main(int argc, char *const *argv)
if (login_shell)
conf.login_shell = true;
if (tll_length(conf_fonts) > 0) {
tll_foreach(conf.fonts, it)
config_font_destroy(&it->item);
tll_free(conf.fonts);
for (size_t i = 0; i < ALEN(conf.fonts); i++) {
tll_foreach(conf.fonts[i], it)
config_font_destroy(&it->item);
tll_free(conf.fonts[i]);
}
tll_foreach(conf_fonts, it)
tll_push_back(conf.fonts, config_font_parse(it->item));
tll_push_back(conf.fonts[0], config_font_parse(it->item));
tll_free(conf_fonts);
}
if (conf_width > 0 && conf_height > 0) {

View file

@ -764,39 +764,77 @@ font_loader_thread(void *_data)
static bool
reload_fonts(struct terminal *term)
{
const size_t count = tll_length(term->conf->fonts);
char *names[count];
const size_t counts[4] = {
tll_length(term->conf->fonts[0]),
tll_length(term->conf->fonts[1]),
tll_length(term->conf->fonts[2]),
tll_length(term->conf->fonts[3]),
};
size_t i = 0;
tll_foreach(term->conf->fonts, it) {
bool use_px_size = term->font_sizes[i].px_size > 0;
char size[64];
/* Configure size (which may have been changed run-time) */
char **names[4];
for (size_t i = 0; i < 4; i++) {
names[i] = xmalloc(counts[i] * sizeof(names[i][0]));
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 j = 0;
tll_foreach(term->conf->fonts[i], it) {
bool use_px_size = term->font_sizes[i][j].px_size > 0;
char size[64];
size_t len = strlen(it->item.pattern) + strlen(size) + 1;
names[i] = xmalloc(len);
if (use_px_size)
snprintf(size, sizeof(size), ":pixelsize=%d", term->font_sizes[i][j].px_size);
else
snprintf(size, sizeof(size), ":size=%.2f", term->font_sizes[i][j].pt_size);
strcpy(names[i], it->item.pattern);
strcat(names[i], size);
i++;
size_t len = strlen(it->item.pattern) + strlen(size) + 1;
names[i][j] = xmalloc(len);
strcpy(names[i][j], it->item.pattern);
strcat(names[i][j], size);
j++;
}
}
char attrs0[256], attrs1[256], attrs2[256], attrs3[256];
snprintf(attrs0, sizeof(attrs0), "dpi=%.2f", term->font_dpi);
snprintf(attrs1, sizeof(attrs1), "dpi=%.2f:weight=bold", term->font_dpi);
snprintf(attrs2, sizeof(attrs2), "dpi=%.2f:slant=italic", term->font_dpi);
snprintf(attrs3, sizeof(attrs3), "dpi=%.2f:weight=bold:slant=italic", term->font_dpi);
/* Did user configure custom bold/italic fonts?
* Or should we use the regular font, with weight/slant attributes? */
const bool custom_bold = counts[1] > 0;
const bool custom_italic = counts[2] > 0;
const bool custom_bold_italic = counts[3] > 0;
const size_t count_regular = counts[0];
const char **names_regular = (const char **)names[0];
const size_t count_bold = custom_bold ? counts[1] : counts[0];
const char **names_bold = (const char **)(custom_bold ? names[1] : names[0]);
const size_t count_italic = custom_italic ? counts[2] : counts[0];
const char **names_italic = (const char **)(custom_italic ? names[2] : names[0]);
const size_t count_bold_italic = custom_bold_italic ? counts[3] : counts[0];
const char **names_bold_italic = (const char **)(custom_bold_italic ? names[3] : names[0]);
char *attrs[4] = {NULL};
int attr_len[4] = {-1, -1, -1, -1}; /* -1, so that +1 (below) results in 0 */
for (size_t i = 0; i < 2; i++) {
attr_len[0] = snprintf(attrs[0], attr_len[0] + 1, "dpi=%.2f", term->font_dpi);
attr_len[1] = snprintf(attrs[1], attr_len[1] + 1, "dpi=%.2f:%s", term->font_dpi, !custom_bold ? "weight=bold" : "");
attr_len[2] = snprintf(attrs[2], attr_len[2] + 1, "dpi=%.2f:%s", term->font_dpi, !custom_italic ? "slant=italic" : "");
attr_len[3] = snprintf(attrs[3], attr_len[3] + 1, "dpi=%.2f:%s", term->font_dpi, !custom_bold_italic ? "weight=bold:slant=italic" : "");
if (i > 0)
continue;
for (size_t i = 0; i < 4; i++)
attrs[i] = xmalloc(attr_len[i] + 1);
}
struct fcft_font *fonts[4];
struct font_load_data data[4] = {
{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]},
{count_regular, names_regular, attrs[0], &fonts[0]},
{count_bold, names_bold, attrs[1], &fonts[1]},
{count_italic, names_italic, attrs[2], &fonts[2]},
{count_bold_italic, names_bold_italic, attrs[3], &fonts[3]},
};
thrd_t tids[4] = {0};
@ -819,6 +857,13 @@ reload_fonts(struct terminal *term)
success = false;
}
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < counts[i]; j++)
free(names[i][j]);
free(names[i]);
free(attrs[i]);
}
if (!success) {
LOG_ERR("failed to load primary fonts");
for (size_t i = 0; i < 4; i++) {
@ -827,19 +872,18 @@ reload_fonts(struct terminal *term)
}
}
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};
for (size_t i = 0; i < 4; i++) {
size_t j = 0;
tll_foreach(term->conf->fonts[i], it) {
term->font_sizes[i][j++] = (struct config_font){
.pt_size = it->item.pt_size, .px_size = it->item.px_size};
}
}
return reload_fonts(term);
@ -922,7 +966,12 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.ptmx = ptmx,
.ptmx_buffers = tll_init(),
.ptmx_paste_buffers = tll_init(),
.font_sizes = xmalloc(sizeof(term->font_sizes[0]) * tll_length(conf->fonts)),
.font_sizes = {
xmalloc(sizeof(term->font_sizes[0][0]) * tll_length(conf->fonts[0])),
xmalloc(sizeof(term->font_sizes[1][0]) * tll_length(conf->fonts[1])),
xmalloc(sizeof(term->font_sizes[2][0]) * tll_length(conf->fonts[2])),
xmalloc(sizeof(term->font_sizes[3][0]) * tll_length(conf->fonts[3])),
},
.font_dpi = 0.,
.font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */
? FCFT_SUBPIXEL_DEFAULT
@ -1025,10 +1074,10 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.cwd = xstrdup(cwd),
};
{
size_t i = 0;
tll_foreach(conf->fonts, it) {
term->font_sizes[i++] = (struct config_font){
for (size_t i = 0; i < 4; i++) {
size_t j = 0;
tll_foreach(conf->fonts[i], it) {
term->font_sizes[i][j++] = (struct config_font){
.pt_size = it->item.pt_size, .px_size = it->item.px_size};
}
}
@ -1277,7 +1326,8 @@ 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);
for (size_t i = 0; i < 4; i++)
free(term->font_sizes[i]);
free(term->search.buf);
@ -1518,22 +1568,24 @@ term_reset(struct terminal *term, bool hard)
static bool
term_font_size_adjust(struct terminal *term, double amount)
{
for (size_t i = 0; i < tll_length(term->conf->fonts); i++) {
double old_pt_size = term->font_sizes[i].pt_size;
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < tll_length(term->conf->fonts[i]); j++) {
double old_pt_size = term->font_sizes[i][j].pt_size;
/*
* 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.
*/
/*
* 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;
if (term->font_sizes[i][j].px_size > 0) {
double dpi = term->font_dpi;
old_pt_size = term->font_sizes[i][j].px_size * 72. / dpi;
}
term->font_sizes[i][j].pt_size = fmax(old_pt_size + amount, 0);
term->font_sizes[i][j].px_size = -1;
}
term->font_sizes[i].pt_size = fmax(old_pt_size + amount, 0);
term->font_sizes[i].px_size = -1;
}
return reload_fonts(term);

View file

@ -225,7 +225,7 @@ struct terminal {
struct composed *composed;
struct fcft_font *fonts[4];
struct config_font *font_sizes;
struct config_font *font_sizes[4];
float font_dpi;
enum fcft_subpixel font_subpixel;