mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
commit
83fd67409b
9 changed files with 194 additions and 41 deletions
|
|
@ -30,6 +30,10 @@
|
|||
top/bottom side (https://codeberg.org/dnkl/foot/issues/273).
|
||||
* Completions for fish shell
|
||||
(https://codeberg.org/dnkl/foot/issues/11)
|
||||
* `line-height`, `letter-spacing`, `horizontal-letter-offset` and
|
||||
`vertical-letter-offset` to `foot.ini`. These options let you tweak
|
||||
cell size and glyph positioning
|
||||
(https://codeberg.org/dnkl/foot/issues/244).
|
||||
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define LOG_MODULE "box-drawing"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "macros.h"
|
||||
#include "stride.h"
|
||||
#include "terminal.h"
|
||||
|
|
@ -2068,8 +2069,8 @@ box_drawing(const struct terminal *term, wchar_t wc)
|
|||
.wc = wc,
|
||||
.cols = 1,
|
||||
.pix = pix,
|
||||
.x = 0,
|
||||
.y = term->fonts[0]->ascent,
|
||||
.x = -term->font_x_ofs,
|
||||
.y = term->font_y_ofs + term->fonts[0]->ascent,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.advance = {
|
||||
|
|
|
|||
89
config.c
89
config.c
|
|
@ -387,18 +387,21 @@ str_to_double(const char *s, double *res)
|
|||
}
|
||||
|
||||
static bool
|
||||
str_to_color(const char *s, uint32_t *color, bool allow_alpha, const char *path, int lineno,
|
||||
str_to_color(const char *s, uint32_t *color, bool allow_alpha,
|
||||
struct config *conf, const char *path, int lineno,
|
||||
const char *section, const char *key)
|
||||
{
|
||||
unsigned long value;
|
||||
if (!str_to_ulong(s, 16, &value)) {
|
||||
LOG_ERRNO("%s:%d: [%s]: %s: invalid color: %s", path, lineno, section, key, s);
|
||||
LOG_AND_NOTIFY_ERRNO(
|
||||
"%s:%d: [%s]: %s: invalid color: %s", path, lineno, section, key, s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!allow_alpha && (value & 0xff000000) != 0) {
|
||||
LOG_ERR("%s:%d: [%s]: %s: color value must not have an alpha component: %s",
|
||||
path, lineno, section, key, s);
|
||||
LOG_AND_NOTIFY_ERR(
|
||||
"%s:%d: [%s]: %s: color value must not have an alpha component: %s",
|
||||
path, lineno, section, key, s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +409,40 @@ str_to_color(const char *s, uint32_t *color, bool allow_alpha, const char *path,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
str_to_pt_or_px(const char *s, union pt_or_px *res, struct config *conf,
|
||||
const char *path, int lineno, const char *section, const char *key)
|
||||
{
|
||||
size_t len = s != NULL ? strlen(s) : 0;
|
||||
if (len >= 2 && s[len - 2] == 'p' && s[len - 1] == 'x') {
|
||||
errno = 0;
|
||||
char *end = NULL;
|
||||
|
||||
long value = strtol(s, &end, 10);
|
||||
if (!(errno == 0 && end == s + len - 2)) {
|
||||
LOG_AND_NOTIFY_ERR(
|
||||
"%s:%d: [%s]: %s: "
|
||||
"expected an integer directly followed by 'px', got '%s'",
|
||||
path, lineno, section, key, s);
|
||||
return false;
|
||||
}
|
||||
res->pt = 0;
|
||||
res->px = value;
|
||||
} else {
|
||||
double value;
|
||||
if (!str_to_double(s, &value)) {
|
||||
LOG_AND_NOTIFY_ERR(
|
||||
"%s:%d: [%s]: %s: expected a decimal value, got '%s'",
|
||||
path, lineno, section, key, s);
|
||||
return false;
|
||||
}
|
||||
res->pt = value;
|
||||
res->px = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_main(const char *key, const char *value, struct config *conf,
|
||||
const char *path, unsigned lineno)
|
||||
|
|
@ -555,6 +592,32 @@ parse_section_main(const char *key, const char *value, struct config *conf,
|
|||
free(copy);
|
||||
}
|
||||
|
||||
else if (strcmp(key, "line-height") == 0) {
|
||||
if (!str_to_pt_or_px(value, &conf->line_height,
|
||||
conf, path, lineno, "default", "line-height"))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "letter-spacing") == 0) {
|
||||
if (!str_to_pt_or_px(value, &conf->letter_spacing,
|
||||
conf, path, lineno, "default", "letter-spacing"))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "horizontal-letter-offset") == 0) {
|
||||
if (!str_to_pt_or_px(
|
||||
value, &conf->horizontal_letter_offset,
|
||||
conf, path, lineno, "default", "horizontal-letter-offset"))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "vertical-letter-offset") == 0) {
|
||||
if (!str_to_pt_or_px(
|
||||
value, &conf->horizontal_letter_offset,
|
||||
conf, path, lineno, "default", "vertical-letter-offset"))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "dpi-aware") == 0) {
|
||||
if (strcmp(value, "auto") == 0)
|
||||
conf->dpi_aware = DPI_AWARE_AUTO;
|
||||
|
|
@ -732,7 +795,7 @@ parse_section_colors(const char *key, const char *value, struct config *conf,
|
|||
}
|
||||
|
||||
uint32_t color_value;
|
||||
if (!str_to_color(value, &color_value, false, path, lineno, "colors", key))
|
||||
if (!str_to_color(value, &color_value, false, conf, path, lineno, "colors", key))
|
||||
return false;
|
||||
|
||||
*color = color_value;
|
||||
|
|
@ -767,8 +830,8 @@ parse_section_cursor(const char *key, const char *value, struct config *conf,
|
|||
|
||||
uint32_t text_color, cursor_color;
|
||||
if (text == NULL || cursor == NULL ||
|
||||
!str_to_color(text, &text_color, false, path, lineno, "cursor", "color") ||
|
||||
!str_to_color(cursor, &cursor_color, false, path, lineno, "cursor", "color"))
|
||||
!str_to_color(text, &text_color, false, conf, path, lineno, "cursor", "color") ||
|
||||
!str_to_color(cursor, &cursor_color, false, conf, path, lineno, "cursor", "color"))
|
||||
{
|
||||
LOG_AND_NOTIFY_ERR("%s:%d: invalid cursor colors: %s", path, lineno, value);
|
||||
free(value_copy);
|
||||
|
|
@ -827,7 +890,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
|
||||
else if (strcmp(key, "color") == 0) {
|
||||
uint32_t color;
|
||||
if (!str_to_color(value, &color, true, path, lineno, "csd", "color")) {
|
||||
if (!str_to_color(value, &color, true, conf, path, lineno, "csd", "color")) {
|
||||
LOG_AND_NOTIFY_ERR("%s:%d: invalid titlebar-color: %s", path, lineno, value);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -858,7 +921,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
|
||||
else if (strcmp(key, "button-minimize-color") == 0) {
|
||||
uint32_t color;
|
||||
if (!str_to_color(value, &color, true, path, lineno, "csd", "button-minimize-color")) {
|
||||
if (!str_to_color(value, &color, true, conf, path, lineno, "csd", "button-minimize-color")) {
|
||||
LOG_AND_NOTIFY_ERR("%s:%d: invalid button-minimize-color: %s", path, lineno, value);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -869,7 +932,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
|
||||
else if (strcmp(key, "button-maximize-color") == 0) {
|
||||
uint32_t color;
|
||||
if (!str_to_color(value, &color, true, path, lineno, "csd", "button-maximize-color")) {
|
||||
if (!str_to_color(value, &color, true, conf, path, lineno, "csd", "button-maximize-color")) {
|
||||
LOG_AND_NOTIFY_ERR("%s:%d: invalid button-maximize-color: %s", path, lineno, value);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -880,7 +943,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
|
|||
|
||||
else if (strcmp(key, "button-close-color") == 0) {
|
||||
uint32_t color;
|
||||
if (!str_to_color(value, &color, true, path, lineno, "csd", "button-close-color")) {
|
||||
if (!str_to_color(value, &color, true, conf, path, lineno, "csd", "button-close-color")) {
|
||||
LOG_AND_NOTIFY_ERR("%s:%d: invalid button-close-color: %s", path, lineno, value);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1979,6 +2042,10 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.bell_action = BELL_ACTION_NONE,
|
||||
.startup_mode = STARTUP_WINDOWED,
|
||||
.fonts = {tll_init(), tll_init(), tll_init(), tll_init()},
|
||||
.line_height = { .pt = 0, .px = -1, },
|
||||
.letter_spacing = { .pt = 0, .px = 0, },
|
||||
.horizontal_letter_offset = {.pt = 0, .px = 0, },
|
||||
.vertical_letter_offset = {.pt = 0, .px = 0, },
|
||||
.dpi_aware = DPI_AWARE_AUTO, /* DPI-aware when scaling-factor == 1 */
|
||||
.scrollback = {
|
||||
.lines = 1000,
|
||||
|
|
|
|||
14
config.h
14
config.h
|
|
@ -54,6 +54,12 @@ struct config_mouse_binding {
|
|||
} pipe;
|
||||
};
|
||||
|
||||
/* If px != 0 then px is valid, otherwise pt is valid */
|
||||
union pt_or_px {
|
||||
int16_t px;
|
||||
float pt;
|
||||
};
|
||||
|
||||
struct config {
|
||||
char *term;
|
||||
char *shell;
|
||||
|
|
@ -84,6 +90,14 @@ struct config {
|
|||
enum {DPI_AWARE_AUTO, DPI_AWARE_YES, DPI_AWARE_NO} dpi_aware;
|
||||
config_font_list_t fonts[4];
|
||||
|
||||
/* Custom font metrics (-1 = use real font metrics) */
|
||||
union pt_or_px line_height;
|
||||
union pt_or_px letter_spacing;
|
||||
|
||||
/* Adjusted letter x/y offsets */
|
||||
union pt_or_px horizontal_letter_offset;
|
||||
union pt_or_px vertical_letter_offset;
|
||||
|
||||
struct {
|
||||
int lines;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,19 @@ in this order:
|
|||
|
||||
# SECTION: default
|
||||
|
||||
*shell*
|
||||
Executable to launch. Typically a shell. Default: _$SHELL_ if set,
|
||||
otherwise the user's default shell (as specified in
|
||||
_/etc/passwd_). You can also pass arguments. For example
|
||||
*/bin/bash --norc*.
|
||||
|
||||
*login-shell*
|
||||
Boolean. If enabled, the shell will be launched as a login shell,
|
||||
by prepending a '-' to argv[0]. Default: _no_.
|
||||
|
||||
*term*
|
||||
Value to set the environment variable *TERM* to. Default: _foot_.
|
||||
|
||||
*font*, *font-bold*, *font-italic*, *font-bold-italic*
|
||||
|
||||
Comma separated list of fonts to use, in fontconfig format. That
|
||||
|
|
@ -51,6 +64,38 @@ in this order:
|
|||
Default: _monospace:size=8_ (*font*), _not set_ (*font-bold*,
|
||||
*font-italic*, *font-bold-italic*).
|
||||
|
||||
*line-height*
|
||||
An absolute value, in _points_, that override line height from the
|
||||
font metrics.
|
||||
|
||||
You can specify a height in _pixels_ by using the _px_ suffix:
|
||||
e.g. *line-height=12px*.
|
||||
|
||||
See also: *vertical-letter-offset*.
|
||||
|
||||
Default: _no set_.
|
||||
|
||||
*letter-spacing*
|
||||
Spacing between letters, in _points_. A positive value will
|
||||
increase the cell size, and a negative value shrinks it.
|
||||
|
||||
You can specify a letter spacing in _pixels_ by using the _px_
|
||||
suffix: e.g. *letter-spacing=2px*.
|
||||
|
||||
See also: *horizontal-letter-offset*.
|
||||
|
||||
Default: _0_.
|
||||
|
||||
*horizontal-letter-offset*, *vertical-letter-offset*
|
||||
Configure the horizontal and vertical offsets used when
|
||||
positioning glyphs within cells, in _points_, relative to the top
|
||||
left corner.
|
||||
|
||||
To specify an offset in _pixels_, append _px_:
|
||||
e.g. *horizontal-letter-offset=2px*.
|
||||
|
||||
Default: _0_.
|
||||
|
||||
*dpi-aware*
|
||||
*auto*, *yes*, or *no*. When set to *yes*, fonts are sized using
|
||||
the monitor's DPI, making a font of a given size have the same
|
||||
|
|
@ -111,19 +156,6 @@ in this order:
|
|||
*geometry*
|
||||
Deprecated. Alias for *initial-window-size-pixels*.
|
||||
|
||||
*shell*
|
||||
Executable to launch. Typically a shell. Default: _$SHELL_ if set,
|
||||
otherwise the user's default shell (as specified in
|
||||
_/etc/passwd_). You can also pass arguments. For example
|
||||
*/bin/bash --norc*.
|
||||
|
||||
*login-shell*
|
||||
Boolean. If enabled, the shell will be launched as a login shell,
|
||||
by prepending a '-' to argv[0]. Default: _no_.
|
||||
|
||||
*term*
|
||||
Value to set the environment variable *TERM* to. Default: _foot_.
|
||||
|
||||
*title*
|
||||
Initial window title. Default: _foot_.
|
||||
|
||||
|
|
|
|||
15
foot.ini
15
foot.ini
|
|
@ -1,22 +1,29 @@
|
|||
# -*- conf -*-
|
||||
|
||||
# shell=$SHELL (if set, otherwise user's default shell from /etc/passwd)
|
||||
# term=foot
|
||||
# login-shell=no
|
||||
|
||||
# font=monospace:size=8
|
||||
# font-bold=<bold variant of regular font>
|
||||
# font-italic=<italic variant of regular font>
|
||||
# font-bold-italic=<bold+italic variant of regular font>
|
||||
# line-height=<font metrics>
|
||||
# letter-spacing=0
|
||||
# horizontal-letter-offset=0
|
||||
# vertical-letter-offset=0
|
||||
# dpi-aware=yes
|
||||
|
||||
# initial-window-size-pixels=700x500 # Or,
|
||||
# initial-window-size-chars=<COLSxROWS>
|
||||
# initial-window-mode=windowed
|
||||
# pad=2x2 # optionally append 'center'
|
||||
# shell=$SHELL (if set, otherwise user's default shell from /etc/passwd)
|
||||
# term=foot
|
||||
# login-shell=no
|
||||
# workers=<number of logical CPUs>
|
||||
|
||||
# bold-text-in-bright=no
|
||||
# bell=none
|
||||
# word-delimiters=,│`|:"'()[]{}<>
|
||||
# notify=notify-send -a foot -i foot ${title} ${body}
|
||||
# workers=<number of logical CPUs>
|
||||
|
||||
[scrollback]
|
||||
# lines=1000
|
||||
|
|
|
|||
19
render.c
19
render.c
|
|
@ -256,7 +256,7 @@ color_dim_for_search(pixman_color_t *color)
|
|||
static inline int
|
||||
font_baseline(const struct terminal *term)
|
||||
{
|
||||
return term->fonts[0]->ascent;
|
||||
return term->font_y_ofs + term->fonts[0]->ascent;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -541,18 +541,20 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
pixman_image_t *clr_pix = pixman_image_create_solid_fill(&fg);
|
||||
|
||||
if (glyph != NULL) {
|
||||
const int letter_x_ofs = term->font_x_ofs;
|
||||
|
||||
if (unlikely(pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)) {
|
||||
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
|
||||
if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) {
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0,
|
||||
x + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
x + letter_x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
}
|
||||
} else {
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, clr_pix, glyph->pix, pix, 0, 0, 0, 0,
|
||||
x + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
x + letter_x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
|
||||
}
|
||||
|
|
@ -589,7 +591,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, clr_pix, g->pix, pix, 0, 0, 0, 0,
|
||||
x + x_ofs + g->x, y + font_baseline(term) - g->y,
|
||||
x + letter_x_ofs + x_ofs + g->x, y + font_baseline(term) - g->y,
|
||||
g->width, g->height);
|
||||
}
|
||||
}
|
||||
|
|
@ -1691,6 +1693,8 @@ render_osd(struct terminal *term,
|
|||
struct fcft_font *font = term->fonts[0];
|
||||
pixman_color_t fg = color_hex_to_pixman(_fg);
|
||||
|
||||
const int x_ofs = term->font_x_ofs;
|
||||
|
||||
for (size_t i = 0; i < wcslen(text); i++) {
|
||||
const struct fcft_glyph *glyph = fcft_glyph_rasterize(
|
||||
font, text[i], term->font_subpixel);
|
||||
|
|
@ -1701,7 +1705,7 @@ render_osd(struct terminal *term,
|
|||
pixman_image_t *src = pixman_image_create_solid_fill(&fg);
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
|
||||
x + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
x + x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
pixman_image_unref(src);
|
||||
|
||||
|
|
@ -2268,6 +2272,7 @@ render_search_box(struct terminal *term)
|
|||
|
||||
struct fcft_font *font = term->fonts[0];
|
||||
const int x_left = width - visible_width + margin;
|
||||
const int x_ofs = term->font_x_ofs;
|
||||
int x = x_left;
|
||||
int y = margin;
|
||||
pixman_color_t fg = color_hex_to_pixman(term->colors.table[0]);
|
||||
|
|
@ -2415,13 +2420,13 @@ render_search_box(struct terminal *term)
|
|||
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0,
|
||||
x + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
x + x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
} else {
|
||||
pixman_image_t *src = pixman_image_create_solid_fill(&fg);
|
||||
pixman_image_composite32(
|
||||
PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
|
||||
x + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
x + x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
|
||||
glyph->width, glyph->height);
|
||||
pixman_image_unref(src);
|
||||
}
|
||||
|
|
|
|||
29
terminal.c
29
terminal.c
|
|
@ -608,6 +608,15 @@ err_sem_destroy:
|
|||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
pt_or_px_as_pixels(const struct terminal *term,
|
||||
const union pt_or_px *pt_or_px)
|
||||
{
|
||||
return pt_or_px->px == 0
|
||||
? pt_or_px->pt * term->font_dpi / 72
|
||||
: pt_or_px->px;
|
||||
}
|
||||
|
||||
static bool
|
||||
term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4])
|
||||
{
|
||||
|
|
@ -629,10 +638,22 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4])
|
|||
const int old_cell_width = term->cell_width;
|
||||
const int old_cell_height = term->cell_height;
|
||||
|
||||
term->cell_width = term->fonts[0]->space_advance.x > 0
|
||||
? term->fonts[0]->space_advance.x : term->fonts[0]->max_advance.x;
|
||||
term->cell_height = max(term->fonts[0]->height,
|
||||
term->fonts[0]->ascent + term->fonts[0]->descent);
|
||||
const struct config *conf = term->conf;
|
||||
|
||||
term->cell_width =
|
||||
(term->fonts[0]->space_advance.x > 0
|
||||
? term->fonts[0]->space_advance.x
|
||||
: term->fonts[0]->max_advance.x)
|
||||
+ pt_or_px_as_pixels(term, &conf->letter_spacing);
|
||||
|
||||
term->cell_height = conf->line_height.px >= 0
|
||||
? pt_or_px_as_pixels(term, &conf->line_height)
|
||||
: max(term->fonts[0]->height,
|
||||
term->fonts[0]->ascent + term->fonts[0]->descent);
|
||||
|
||||
term->font_x_ofs = pt_or_px_as_pixels(term, &conf->horizontal_letter_offset);
|
||||
term->font_y_ofs = pt_or_px_as_pixels(term, &conf->vertical_letter_offset);
|
||||
|
||||
LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height);
|
||||
|
||||
if (term->cell_width < old_cell_width ||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,8 @@ struct terminal {
|
|||
struct config_font *font_sizes[4];
|
||||
float font_dpi;
|
||||
int font_scale;
|
||||
int16_t font_x_ofs;
|
||||
int16_t font_y_ofs;
|
||||
enum fcft_subpixel font_subpixel;
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue