mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
config: add font-bold, font-italic and font-bold-italic options
These options lets the user configure custom fonts and styles, to use with the bold and italic cell attributes. By default, they are unset, meaning we use the bold/italic variants of the regular font. Closes #169.
This commit is contained in:
parent
b507d3a55e
commit
2c101a21ee
8 changed files with 155 additions and 69 deletions
|
|
@ -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
|
||||
|
|
|
|||
32
config.c
32
config.c
|
|
@ -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) {
|
||||
|
|
|
|||
3
config.h
3
config.h
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -20,20 +20,27 @@ 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.
|
||||
|
||||
Default: _monospace_ (*font*), _not set_ (*font-bold*,
|
||||
*font-italic*, *font-bold-italic*).
|
||||
|
||||
*pad*
|
||||
Padding between border and glyphs, in pixels (subject to output
|
||||
|
|
|
|||
3
foot.ini
3
foot.ini
|
|
@ -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
11
main.c
|
|
@ -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) {
|
||||
|
|
|
|||
152
terminal.c
152
terminal.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue