Merge branch 'master' into releases/1.15

This commit is contained in:
Daniel Eklöf 2023-07-30 13:17:31 +02:00
commit 89d0fe561f
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
19 changed files with 345 additions and 179 deletions

View file

@ -47,6 +47,9 @@ tasks:
ninja -C bld/release -k0
meson test -C bld/release --print-errorlogs
- codespell: |
python3 -m venv codespell-venv
source codespell-venv/bin/activate
pip install codespell
cd foot
~/.local/bin/codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
deactivate

View file

@ -8,8 +8,11 @@ pipeline:
commands:
- apk add python3
- apk add py3-pip
- python3 -m venv codespell-venv
- source codespell-venv/bin/activate
- pip install codespell
- codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
- deactivate
subprojects:
when:

View file

@ -1,5 +1,6 @@
# Changelog
* [Unreleased](#unreleased)
* [1.15.1](#1-15-1)
* [1.15.0](#1-15-0)
* [1.14.0](#1-14-0)
@ -43,6 +44,50 @@
* [1.2.0](#1-2-0)
## Unreleased
### Added
* `[tweak].bold-text-in-bright-amount` option ([#1434][1434]).
* `-Dterminfo-base-name` meson option, allowing you to name the
terminfo files to something other than `-Ddefault-terminfo`. Use
case: have foot default to using the terminfo from ncurses (`foot`,
`foot-direct`), while still packaging foot's terminfo files, but
under a different name (e.g. `foot-extra`, `foot-extra-direct`).
[1434]: https://codeberg.org/dnkl/foot/issues/1434
### Changed
### Deprecated
### Removed
### Fixed
* Crash when copying text that contains invalid UTF-8 ([#1423][1423]).
* Wrong font size after suspending the monitor ([#1431][1431]).
* Vertical alignment in URL jump labels, and the scrollback position
indicator ([#1430][1430]).
* Regression: line- and box drawing characters not covering the full
height of the line, when a custom `line-height` is being used
([#1430][1430]).
* Crash when compositor does not implement the _viewporter_ interface
([#1444][1444]).
* CSD rendering with fractional scaling ([#1441][1441]).
* Regression: crash with certain combinations of
`--window-size-chars=NxM` and desktop scaling factors
([#1446][1446]).
[1423]: https://codeberg.org/dnkl/foot/issues/1423
[1431]: https://codeberg.org/dnkl/foot/issues/1431
[1430]: https://codeberg.org/dnkl/foot/issues/1430
[1444]: https://codeberg.org/dnkl/foot/issues/1444
[1441]: https://codeberg.org/dnkl/foot/issues/1441
[1446]: https://codeberg.org/dnkl/foot/issues/1446
### Security
### Contributors
## 1.15.1
### Changed

View file

@ -151,6 +151,7 @@ Available compile-time options:
| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc |
| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) |
| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | None |
| `-Dterminfo-base-name` | string | `-Ddefault-terminfo` | Base name of the generated terminfo files | None |
| `-Dcustom-terminfo-install-location` | string | `${datadir}/terminfo` | Value to set `TERMINFO` to | None |
| `-Dsystemd-units-dir` | string | `${systemduserunitdir}` | Where to install the systemd service files (absolute) | None |
| `-Dutmp-backend` | combo | `auto` | Which utmp backend to use (`none`, `libutempter`, `ulog` or `auto`) | libutempter or ulog |
@ -165,8 +166,18 @@ under a different name. Setting this changes the default value of
`$TERM`, and the names of the terminfo files (if
`-Dterminfo=enabled`).
`-Dcustom-terminfo-install-location` enables foots terminfo to
co-exist with ncurses version, without changing the terminfo
If you want foot to use the terminfo files from ncurses, but still
package foot's own terminfo files under a different name, you can use
the `-Dterminfo-base-name` option. Many distributions use the name
`foot-extra`, and thus it might be a good idea to re-use that:
```sh
meson ... -Ddefault-terminfo=foot -Dterminfo-base-name=foot-extra
```
(or just leave out `-Ddefault-terminfo`, since it defaults to `foot` anyway).
Finally, `-Dcustom-terminfo-install-location` enables foots terminfo
to co-exist with ncurses version, without changing the terminfo
names. The idea is that you install foots terminfo to a non-standard
location, for example `/usr/share/foot/terminfo`. Use
`-Dcustom-terminfo-install-location` to tell foot where the terminfo

View file

@ -3011,7 +3011,7 @@ box_drawing(const struct terminal *term, char32_t wc)
.cols = 1,
.pix = buf.pix,
.x = -term->font_x_ofs,
.y = term->font_y_ofs + term->fonts[0]->ascent,
.y = term_font_baseline(term),
.width = width,
.height = height,
.advance = {

View file

@ -480,7 +480,7 @@ value_to_dimensions(struct context *ctx, uint32_t *x, uint32_t *y)
}
static bool NOINLINE
value_to_double(struct context *ctx, float *res)
value_to_float(struct context *ctx, float *res)
{
const char *s = ctx->value;
@ -659,7 +659,7 @@ value_to_pt_or_px(struct context *ctx, struct pt_or_px *res)
res->px = value;
} else {
float value;
if (!value_to_double(ctx, &value))
if (!value_to_float(ctx, &value))
return false;
res->pt = value;
res->px = 0;
@ -1089,7 +1089,7 @@ parse_section_scrollback(struct context *ctx)
}
else if (strcmp(key, "multiplier") == 0)
return value_to_double(ctx, &conf->scrollback.multiplier);
return value_to_float(ctx, &conf->scrollback.multiplier);
else {
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
@ -1298,7 +1298,7 @@ parse_section_colors(struct context *ctx)
else if (strcmp(key, "alpha") == 0) {
float alpha;
if (!value_to_double(ctx, &alpha))
if (!value_to_float(ctx, &alpha))
return false;
if (alpha < 0. || alpha > 1.) {
@ -2461,7 +2461,7 @@ parse_section_tweak(struct context *ctx)
}
else if (strcmp(key, "box-drawing-base-thickness") == 0)
return value_to_double(ctx, &conf->tweak.box_drawing_base_thickness);
return value_to_float(ctx, &conf->tweak.box_drawing_base_thickness);
else if (strcmp(key, "box-drawing-solid-shades") == 0)
return value_to_bool(ctx, &conf->tweak.box_drawing_solid_shades);
@ -2472,6 +2472,9 @@ parse_section_tweak(struct context *ctx)
else if (strcmp(key, "sixel") == 0)
return value_to_bool(ctx, &conf->tweak.sixel);
else if (strcmp(key, "bold-text-in-bright-amount") == 0)
return value_to_float(ctx, &conf->bold_in_bright.amount);
else {
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
return false;
@ -2939,6 +2942,7 @@ config_load(struct config *conf, const char *conf_path,
.bold_in_bright = {
.enabled = false,
.palette_based = false,
.amount = 1.3,
},
.startup_mode = STARTUP_WINDOWED,
.fonts = {{0}},

View file

@ -133,6 +133,7 @@ struct config {
struct {
bool enabled;
bool palette_based;
float amount;
} bold_in_bright;
enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode;

12
csi.c
View file

@ -1208,8 +1208,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
char reply[64];
size_t n = xsnprintf(
reply, sizeof(reply), "\033[4;%d;%dt",
(int)round(height / term->scale),
(int)(width / term->scale));
(int)roundf(height / term->scale),
(int)roundf((width / term->scale)));
term_to_slave(term, reply, n);
}
break;
@ -1233,8 +1233,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
char reply[64];
size_t n = xsnprintf(
reply, sizeof(reply), "\033[6;%d;%dt",
(int)round(term->cell_height / term->scale),
(int)round(term->cell_width / term->scale));
(int)roundf(term->cell_height / term->scale),
(int)roundf(term->cell_width / term->scale));
term_to_slave(term, reply, n);
break;
}
@ -1252,8 +1252,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
char reply[64];
size_t n = xsnprintf(
reply, sizeof(reply), "\033[9;%d;%dt",
(int)round(it->item->dim.px_real.height / term->cell_height / term->scale),
(int)round(it->item->dim.px_real.width / term->cell_width / term->scale));
(int)roundf(it->item->dim.px_real.height / term->cell_height / term->scale),
(int)roundf(it->item->dim.px_real.width / term->cell_width / term->scale));
term_to_slave(term, reply, n);
break;
}

View file

@ -1337,7 +1337,13 @@ any of these options.
Default: _512_. Maximum allowed: _2048_ (2GB).
*sixel*
Boolean. When enabled, foot will process sixel images. Default: _yes_
Boolean. When enabled, foot will process sixel images. Default:
_yes_
*bold-text-in-bright-amount*
Amount by which bold fonts are brightened when
*bold-text-in-bright* is set to *yes* (the *palette-based* variant
is not affected by this option). Default: _1.3_.
# SEE ALSO

6
hsl.c
View file

@ -83,7 +83,7 @@ hsl_to_rgb(int hue, int sat, int lum)
b += m;
return (
(int)round(r * 255.) << 16 |
(int)round(g * 255.) << 8 |
(int)round(b * 255.) << 0);
(uint8_t)round(r * 255.) << 16 |
(uint8_t)round(g * 255.) << 8 |
(uint8_t)round(b * 255.) << 0);
}

View file

@ -352,11 +352,16 @@ if get_option('themes')
install_subdir('themes', install_dir: join_paths(get_option('datadir'), 'foot'))
endif
terminfo_base_name = get_option('terminfo-base-name')
if terminfo_base_name == ''
terminfo_base_name = get_option('default-terminfo')
endif
tic = find_program('tic', native: true, required: get_option('terminfo'))
if tic.found()
conf_data = configuration_data(
{
'default_terminfo': get_option('default-terminfo'),
'default_terminfo': terminfo_base_name
}
)
@ -367,9 +372,9 @@ if tic.found()
)
custom_target(
'terminfo',
output: get_option('default-terminfo')[0],
output: terminfo_base_name[0],
input: preprocessed,
command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(get_option('default-terminfo')), '@INPUT@'],
command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(terminfo_base_name), '@INPUT@'],
install: true,
install_dir: terminfo_install_location
)
@ -395,6 +400,7 @@ summary(
'utmp backend': utmp_backend,
'utmp helper default path': utmp_default_helper_path,
'Build terminfo': tic.found(),
'Terminfo base name': terminfo_base_name,
'Terminfo install location': terminfo_install_location,
'Default TERM': get_option('default-terminfo'),
'Set TERMINFO': get_option('custom-terminfo-install-location') != '',

View file

@ -15,7 +15,8 @@ option('tests', type: 'boolean', value: true, description: 'Build tests')
option('terminfo', type: 'feature', value: 'enabled', description: 'Build and install foot\'s terminfo files.')
option('default-terminfo', type: 'string', value: 'foot',
description: 'Default value of the "term" option in foot.ini.')
option('terminfo-base-name', type: 'string',
description: 'Base name of the generated terminfo files. Defaults to the value of the \'default-terminfo\' meson option')
option('custom-terminfo-install-location', type: 'string', value: '',
description: 'Path to foot\'s terminfo, relative to ${prefix}. If set, foot will set $TERMINFO to this value in the client process.')

235
render.c
View file

@ -299,25 +299,16 @@ color_brighten(const struct terminal *term, uint32_t color)
int hue, sat, lum;
rgb_to_hsl(color, &hue, &sat, &lum);
return hsl_to_rgb(hue, sat, min(100, lum * 1.3));
}
static inline int
font_baseline(const struct terminal *term)
{
const struct fcft_font *font = term->fonts[0];
const int line_height = term->cell_height;
const int font_height = font->ascent + font->descent;
const int glyph_top_y = round((line_height - font_height) / 2.);
return term->font_y_ofs + glyph_top_y + font->ascent;
lum = (int)roundf(lum * term->conf->bold_in_bright.amount);
return hsl_to_rgb(hue, sat, min(lum, 100));
}
static void
draw_unfocused_block(const struct terminal *term, pixman_image_t *pix,
const pixman_color_t *color, int x, int y, int cell_cols)
{
const int scale = round(term->scale);
const int scale = (int)roundf(term->scale);
const int width = min(min(scale, term->cell_width), term->cell_height);
pixman_image_fill_rectangles(
@ -335,7 +326,7 @@ draw_beam_cursor(const struct terminal *term, pixman_image_t *pix,
const struct fcft_font *font,
const pixman_color_t *color, int x, int y)
{
int baseline = y + font_baseline(term) - term->fonts[0]->ascent;
int baseline = y + term_font_baseline(term) - term->fonts[0]->ascent;
pixman_image_fill_rectangles(
PIXMAN_OP_SRC, pix, color,
1, &(pixman_rectangle16_t){
@ -347,7 +338,7 @@ draw_beam_cursor(const struct terminal *term, pixman_image_t *pix,
static int
underline_offset(const struct terminal *term, const struct fcft_font *font)
{
return font_baseline(term) -
return term_font_baseline(term) -
(term->conf->use_custom_underline_offset
? -term_pt_or_px_as_pixels(term, &term->conf->underline_offset)
: font->underline.position);
@ -401,7 +392,7 @@ draw_strikeout(const struct terminal *term, pixman_image_t *pix,
pixman_image_fill_rectangles(
PIXMAN_OP_SRC, pix, color,
1, &(pixman_rectangle16_t){
x, y + font_baseline(term) - font->strikeout.position,
x, y + term_font_baseline(term) - font->strikeout.position,
cols * term->cell_width, font->strikeout.thickness});
}
@ -767,13 +758,13 @@ render_cell(struct terminal *term, pixman_image_t *pix,
if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) {
pixman_image_composite32(
PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0,
pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y,
pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - g_y,
glyph->width, glyph->height);
}
} else {
pixman_image_composite32(
PIXMAN_OP_OVER, clr_pix, glyph->pix, pix, 0, 0, 0, 0,
pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y,
pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - g_y,
glyph->width, glyph->height);
/* Combining characters */
@ -813,7 +804,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
/* Some fonts use a negative offset, while others use a
* "normal" offset */
pen_x + x_ofs + g->x,
y + font_baseline(term) - g->y,
y + term_font_baseline(term) - g->y,
g->width, g->height);
}
}
@ -1817,33 +1808,49 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
const bool borders_visible = wayl_win_csd_borders_visible(term->window);
const bool title_visible = wayl_win_csd_titlebar_visible(term->window);
/* Only title bar is rendered in maximized mode */
const float scale = term->scale;
const int border_width = borders_visible
? term->conf->csd.border_width * term->scale : 0;
? roundf(term->conf->csd.border_width * scale) : 0;
const int title_height = title_visible
? term->conf->csd.title_height * term->scale : 0;
? roundf(term->conf->csd.title_height * scale) : 0;
const int button_width = title_visible
? term->conf->csd.button_width * term->scale : 0;
? roundf(term->conf->csd.button_width * scale) : 0;
const int button_close_width = term->width >= 1 * button_width
? button_width : 0;
const int button_maximize_width =
term->width >= 2 * button_width && term->window->wm_capabilities.maximize
? button_width : 0;
? button_width : 0;
const int button_minimize_width =
term->width >= 3 * button_width && term->window->wm_capabilities.minimize
? button_width : 0;
? button_width : 0;
/*
* With fractional scaling, we must ensure the offset, when
* divided by the scale (in set_position()), and the scaled back
* (by the compositor), matches the actual pixel count made up by
* the titlebar and the border.
*/
const int top_offset = roundf(
scale * (roundf(-title_height / scale) - roundf(border_width / scale)));
const int top_bottom_width = roundf(
scale * (roundf(term->width / scale) + 2 * roundf(border_width / scale)));
const int left_right_height = roundf(
scale * (roundf(title_height / scale) + roundf(term->height / scale)));
switch (surf_idx) {
case CSD_SURF_TITLE: return (struct csd_data){ 0, -title_height, term->width, title_height};
case CSD_SURF_LEFT: return (struct csd_data){-border_width, -title_height, border_width, title_height + term->height};
case CSD_SURF_RIGHT: return (struct csd_data){ term->width, -title_height, border_width, title_height + term->height};
case CSD_SURF_TOP: return (struct csd_data){-border_width, -title_height - border_width, term->width + 2 * border_width, border_width};
case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, term->width + 2 * border_width, border_width};
case CSD_SURF_TITLE: return (struct csd_data){ 0, -title_height, term->width, title_height};
case CSD_SURF_LEFT: return (struct csd_data){-border_width, -title_height, border_width, left_right_height};
case CSD_SURF_RIGHT: return (struct csd_data){ term->width, -title_height, border_width, left_right_height};
case CSD_SURF_TOP: return (struct csd_data){-border_width, top_offset, top_bottom_width, border_width};
case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, top_bottom_width, border_width};
/* Positioned relative to CSD_SURF_TITLE */
case CSD_SURF_MINIMIZE: return (struct csd_data){term->width - 3 * button_width, 0, button_minimize_width, title_height};
@ -1937,12 +1944,12 @@ render_osd(struct terminal *term, const struct wayl_sub_surface *sub_surf,
if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
pixman_image_composite32(
PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0,
x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y,
x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent /*term_font_baseline(term)*/ - glyph->y,
glyph->width, glyph->height);
} else {
pixman_image_composite32(
PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y,
x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent /* term_font_baseline(term)*/ - glyph->y,
glyph->width, glyph->height);
}
@ -2033,8 +2040,8 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx,
*/
float scale = term->scale;
int bwidth = round(term->conf->csd.border_width * scale);
int vwidth = round(term->conf->csd.border_width_visible * scale); /* Visible size */
int bwidth = (int)roundf(term->conf->csd.border_width * scale);
int vwidth = (int)roundf(term->conf->csd.border_width_visible * scale); /* Visible size */
xassert(bwidth >= vwidth);
@ -2379,6 +2386,7 @@ render_csd(struct terminal *term)
if (term->window->is_fullscreen)
return;
const float scale = term->scale;
struct csd_data infos[CSD_SURF_COUNT];
int widths[CSD_SURF_COUNT];
int heights[CSD_SURF_COUNT];
@ -2406,8 +2414,7 @@ render_csd(struct terminal *term)
widths[i] = width;
heights[i] = height;
wl_subsurface_set_position(sub, x / term->scale, y / term->scale);
wl_subsurface_set_position(sub, roundf(x / scale), roundf(y / scale));
}
struct buffer *bufs[CSD_SURF_COUNT];
@ -2498,7 +2505,7 @@ render_scrollback_position(struct terminal *term)
char lineno_str[64];
snprintf(lineno_str, sizeof(lineno_str), "%d", rebased_view + 1);
mbstoc32(_text, lineno_str, ALEN(_text));
cell_count = ceil(log10(term->grid->num_rows));
cell_count = (int)ceilf(log10f(term->grid->num_rows));
break;
}
@ -2508,13 +2515,14 @@ render_scrollback_position(struct terminal *term)
break;
}
const int scale = term->scale;
const int margin = 3 * scale;
const float scale = term->scale;
const int margin = (int)roundf(3. * scale);
const int width =
(2 * margin + cell_count * term->cell_width + scale - 1) / scale * scale;
const int height =
(2 * margin + term->cell_height + scale - 1) / scale * scale;
int width = margin + cell_count * term->cell_width + margin;
int height = margin + term->cell_height + margin;
width = roundf(scale * ceilf(width / scale));
height = roundf(scale * ceilf(height / scale));
/* *Where* to render - parent relative coordinates */
int surf_top = 0;
@ -2542,8 +2550,11 @@ render_scrollback_position(struct terminal *term)
}
}
const int x = (term->width - margin - width) / scale * scale;
const int y = (term->margins.top + surf_top) / scale * scale;
int x = term->width - margin - width;
int y = term->margins.top + surf_top;
x = roundf(scale * ceilf(x / scale));
y = roundf(scale * ceilf(y / scale));
if (y + height > term->height) {
wl_surface_attach(win->scrollback_indicator.surface.surf, NULL, 0, 0);
@ -2555,7 +2566,7 @@ render_scrollback_position(struct terminal *term)
struct buffer *buf = shm_get_buffer(chain, width, height);
wl_subsurface_set_position(
win->scrollback_indicator.sub, x / scale, y / scale);
win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale));
uint32_t fg = term->colors.table[0];
uint32_t bg = term->colors.table[8 + 4];
@ -2584,21 +2595,23 @@ render_render_timer(struct terminal *term, struct timespec render_time)
char32_t text[256];
mbstoc32(text, usecs_str, ALEN(text));
const int scale = round(term->scale);
const float scale = term->scale;
const int cell_count = c32len(text);
const int margin = 3 * scale;
const int width =
(2 * margin + cell_count * term->cell_width + scale - 1) / scale * scale;
const int height =
(2 * margin + term->cell_height + scale - 1) / scale * scale;
const int margin = (int)roundf(3. * scale);
int width = margin + cell_count * term->cell_width + margin;
int height = margin + term->cell_height + margin;
width = roundf(scale * ceilf(width / scale));
height = roundf(scale * ceilf(height / scale));
struct buffer_chain *chain = term->render.chains.render_timer;
struct buffer *buf = shm_get_buffer(chain, width, height);
wl_subsurface_set_position(
win->render_timer.sub,
margin / term->scale,
(term->margins.top + term->cell_height - margin) / term->scale);
roundf(margin / scale),
roundf((term->margins.top + term->cell_height - margin) / scale));
render_osd(
term,
@ -3143,18 +3156,21 @@ render_search_box(struct terminal *term)
const size_t total_cells = c32swidth(text, text_len);
const size_t wanted_visible_cells = max(20, total_cells);
xassert(term->scale >= 1);
const int rounded_scale = round(term->scale);
const float scale = term->scale;
xassert(scale >= 1.);
const size_t margin = (size_t)roundf(3 * scale);
const size_t margin = 3 * rounded_scale;
const size_t width = term->width - 2 * margin;
const size_t visible_width = min(
term->width - 2 * margin,
(2 * margin + wanted_visible_cells * term->cell_width + rounded_scale - 1) / rounded_scale * rounded_scale);
const size_t height = min(
size_t width = term->width - 2 * margin;
size_t height = min(
term->height - 2 * margin,
(2 * margin + 1 * term->cell_height + rounded_scale - 1) / rounded_scale * rounded_scale);
margin + 1 * term->cell_height + margin);
width = roundf(scale * ceilf((term->width - 2 * margin) / scale));
height = roundf(scale * ceilf(height / scale));
size_t visible_width = min(
term->width - 2 * margin,
margin + wanted_visible_cells * term->cell_width + margin);
const size_t visible_cells = (visible_width - 2 * margin) / term->cell_width;
size_t glyph_offset = term->render.search_glyph_offset;
@ -3364,7 +3380,7 @@ 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 + x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
x + x_ofs + glyph->x, y + term_font_baseline(term) - glyph->y,
glyph->width, glyph->height);
} else {
int combining_ofs = width == 0
@ -3376,7 +3392,7 @@ render_search_box(struct terminal *term)
pixman_image_composite32(
PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
x + x_ofs + combining_ofs + glyph->x,
y + font_baseline(term) - glyph->y,
y + term_font_baseline(term) - glyph->y,
glyph->width, glyph->height);
pixman_image_unref(src);
}
@ -3401,10 +3417,10 @@ render_search_box(struct terminal *term)
/* TODO: this is only necessary on a window resize */
wl_subsurface_set_position(
term->window->search.sub,
margin / term->scale,
max(0, (int32_t)term->height - height - margin) / term->scale);
roundf(margin / scale),
roundf(max(0, (int32_t)term->height - height - margin) / scale));
wayl_surface_scale(term->window, &term->window->search.surface, buf, term->scale);
wayl_surface_scale(term->window, &term->window->search.surface, buf, scale);
wl_surface_attach(term->window->search.surface.surf, buf->wl_buf, 0, 0);
wl_surface_damage_buffer(term->window->search.surface.surf, 0, 0, width, height);
@ -3431,9 +3447,9 @@ render_urls(struct terminal *term)
struct wl_window *win = term->window;
xassert(tll_length(win->urls) > 0);
const int scale = round(term->scale);
const int x_margin = 2 * scale;
const int y_margin = 1 * scale;
const float scale = term->scale;
const int x_margin = (int)roundf(2 * scale);
const int y_margin = (int)roundf(1 * scale);
/* Calculate view start, counted from the *current* scrollback start */
const int scrollback_end
@ -3603,10 +3619,11 @@ render_urls(struct terminal *term)
if (cols == 0)
continue;
const int width =
(2 * x_margin + cols * term->cell_width + scale - 1) / scale * scale;
const int height =
(2 * y_margin + term->cell_height + scale - 1) / scale * scale;
int width = x_margin + cols * term->cell_width + x_margin;
int height = y_margin + term->cell_height + y_margin;
width = roundf(scale * ceilf(width / scale));
height = roundf(scale * ceilf(height / scale));
info[render_count].url = &it->item;
info[render_count].text = xc32dup(label);
@ -3642,8 +3659,8 @@ render_urls(struct terminal *term)
wl_subsurface_set_position(
sub_surf->sub,
(term->margins.left + x) / term->scale,
(term->margins.top + y) / term->scale);
roundf((term->margins.left + x) / scale),
roundf((term->margins.top + y) / scale));
render_osd(
term, sub_surf, term->fonts[0], bufs[i], label,
@ -3916,22 +3933,9 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
width += 2 * term->conf->pad_x * scale;
height += 2 * term->conf->pad_y * scale;
/*
* Ensure we can scale to logical size, and back to
* pixels without truncating.
*/
if (wayl_fractional_scaling(term->wl)) {
xassert((int)round(scale) == (int)scale);
int iscale = scale;
if (width % iscale)
width += iscale - width % iscale;
if (height % iscale)
height += iscale - height % iscale;
xassert(width % iscale == 0);
xassert(height % iscale == 0);
}
/* Ensure width/height is a valid multiple of scale */
width = roundf(scale * roundf(width / scale));
height = roundf(scale * roundf(height / scale));
break;
}
}
@ -3942,8 +3946,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
const int min_rows = 1;
/* Minimum window size (must be divisible by the scaling factor)*/
const int min_width = (min_cols * term->cell_width + scale - 1) / scale * scale;
const int min_height = (min_rows * term->cell_height + scale - 1) / scale * scale;
const int min_width = roundf(scale * ceilf((min_cols * term->cell_width) / scale));
const int min_height = roundf(scale * ceilf((min_rows * term->cell_height) / scale));
width = max(width, min_width);
height = max(height, min_height);
@ -4203,22 +4207,43 @@ damage_view:
const bool title_shown = wayl_win_csd_titlebar_visible(term->window);
const bool border_shown = wayl_win_csd_borders_visible(term->window);
const int title_height =
title_shown ? term->conf->csd.title_height : 0;
const int border_width =
border_shown ? term->conf->csd.border_width_visible : 0;
const int title = title_shown
? roundf(term->conf->csd.title_height * scale)
: 0;
const int border = border_shown
? roundf(term->conf->csd.border_width_visible * scale)
: 0;
/* Must use surface logical coordinates (same calculations as
in get_csd_data(), but with different inputs) */
const int toplevel_min_width = roundf(border / scale) +
roundf(min_width / scale) +
roundf(border / scale);
const int toplevel_min_height = roundf(border / scale) +
roundf(title / scale) +
roundf(min_height / scale) +
roundf(border / scale);
const int toplevel_width = roundf(border / scale) +
roundf(term->width / scale) +
roundf(border / scale);
const int toplevel_height = roundf(border / scale) +
roundf(title / scale) +
roundf(term->height / scale) +
roundf(border / scale);
const int x = roundf(-border / scale);
const int y = roundf(-title / scale) - roundf(border / scale);
xdg_toplevel_set_min_size(
term->window->xdg_toplevel,
min_width / scale + 2 * border_width,
min_height / scale + title_height + 2 * border_width);
toplevel_min_width, toplevel_min_height);
xdg_surface_set_window_geometry(
term->window->xdg_surface,
-border_width,
-title_height - border_width,
term->width / term->scale + 2 * border_width,
term->height / term->scale + title_height + 2 * border_width);
x, y, toplevel_width, toplevel_height);
}
tll_free(term->normal.scroll_damage);

View file

@ -1662,7 +1662,7 @@ send_clipboard_or_primary(struct seat *seat, int fd, const char *selection,
return;
}
size_t len = strlen(selection);
size_t len = selection != NULL ? strlen(selection) : 0;
size_t async_idx = 0;
switch (async_write(fd, selection, len, &async_idx)) {
@ -1701,7 +1701,6 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
struct seat *seat = data;
const struct wl_clipboard *clipboard = &seat->clipboard;
xassert(clipboard->text != NULL);
send_clipboard_or_primary(seat, fd, clipboard->text, "clipboard");
}
@ -1756,7 +1755,6 @@ primary_send(void *data,
struct seat *seat = data;
const struct wl_primary *primary = &seat->primary;
xassert(primary->text != NULL);
send_clipboard_or_primary(seat, fd, primary->text, "primary");
}

View file

@ -784,8 +784,8 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4],
/* Use force, since cell-width/height may have changed */
render_resize_force(
term,
round(term->width / term->scale),
round(term->height / term->scale));
(int)roundf(term->width / term->scale),
(int)roundf(term->height / term->scale));
}
return true;
}
@ -825,7 +825,7 @@ get_font_dpi(const struct terminal *term)
? tll_back(win->on_outputs)
: &tll_front(term->wl->monitors);
if (wayl_fractional_scaling(term->wl))
if (term_fractional_scaling(term))
return mon->dpi.physical;
else
return mon->dpi.scaled;
@ -880,12 +880,12 @@ int
term_pt_or_px_as_pixels(const struct terminal *term,
const struct pt_or_px *pt_or_px)
{
double scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
float scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
float dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
return pt_or_px->px == 0
? round(pt_or_px->pt * scale * dpi / 72)
: pt_or_px->px * scale;
? (int)roundf(pt_or_px->pt * scale * dpi / 72)
: (int)roundf(pt_or_px->px * scale);
}
struct font_load_data {
@ -932,7 +932,7 @@ reload_fonts(struct terminal *term, bool resize_grid)
if (use_px_size)
snprintf(size, sizeof(size), ":pixelsize=%d",
(int)round(term->font_sizes[i][j].px_size * scale));
(int)roundf(term->font_sizes[i][j].px_size * scale));
else
snprintf(size, sizeof(size), ":size=%.2f",
term->font_sizes[i][j].pt_size * scale);
@ -2077,6 +2077,16 @@ term_font_size_reset(struct terminal *term)
return load_fonts_from_conf(term);
}
bool
term_fractional_scaling(const struct terminal *term)
{
#if defined(HAVE_FRACTIONAL_SCALE)
return term->wl->fractional_scale_manager != NULL && term->window->scale > 0.;
#else
return false;
#endif
}
bool
term_update_scale(struct terminal *term)
{
@ -2093,7 +2103,7 @@ term_update_scale(struct terminal *term)
* - if there arent any outputs available, use 1.0
*/
const float new_scale =
(wayl_fractional_scaling(term->wl) && win->scale > 0.
(term_fractional_scaling(term)
? win->scale
: (tll_length(win->on_outputs) > 0
? tll_back(win->on_outputs)->scale
@ -2166,6 +2176,17 @@ term_font_subpixel_changed(struct terminal *term)
render_refresh(term);
}
int
term_font_baseline(const struct terminal *term)
{
const struct fcft_font *font = term->fonts[0];
const int line_height = term->cell_height;
const int font_height = max(font->height, font->ascent + font->descent);
const int glyph_top_y = round((line_height - font_height) / 2.);
return term->font_y_ofs + glyph_top_y + font->ascent;
}
void
term_damage_rows(struct terminal *term, int start, int end)
{

View file

@ -736,12 +736,14 @@ bool term_to_slave(struct terminal *term, const void *data, size_t len);
bool term_paste_data_to_slave(
struct terminal *term, const void *data, size_t len);
bool term_fractional_scaling(const struct terminal *term);
bool term_update_scale(struct terminal *term);
bool term_font_size_increase(struct terminal *term);
bool term_font_size_decrease(struct terminal *term);
bool term_font_size_reset(struct terminal *term);
bool term_font_dpi_changed(struct terminal *term, float old_scale);
void term_font_subpixel_changed(struct terminal *term);
int term_font_baseline(const struct terminal *term);
int term_pt_or_px_as_pixels(
const struct terminal *term, const struct pt_or_px *pt_or_px);

View file

@ -265,7 +265,7 @@ test_uint32(struct context *ctx, bool (*parse_fun)(struct context *ctx),
}
static void
test_double(struct context *ctx, bool (*parse_fun)(struct context *ctx),
test_float(struct context *ctx, bool (*parse_fun)(struct context *ctx),
const char *key, const float *ptr)
{
ctx->key = key;
@ -580,7 +580,7 @@ test_section_scrollback(void)
test_uint32(&ctx, &parse_section_scrollback, "lines",
&conf.scrollback.lines);
test_double(&ctx, parse_section_scrollback, "multiplier", &conf.scrollback.multiplier);
test_float(&ctx, parse_section_scrollback, "multiplier", &conf.scrollback.multiplier);
test_enum(
&ctx, &parse_section_scrollback, "indicator-position",
@ -1312,7 +1312,7 @@ test_section_tweak(void)
RENDER_TIMER_BOTH},
(int *)&conf.tweak.render_timer);
test_double(&ctx, &parse_section_tweak, "box-drawing-base-thickness",
test_float(&ctx, &parse_section_tweak, "box-drawing-base-thickness",
&conf.tweak.box_drawing_base_thickness);
test_boolean(&ctx, &parse_section_tweak, "box-drawing-solid-shades",
&conf.tweak.box_drawing_solid_shades);
@ -1345,6 +1345,9 @@ test_section_tweak(void)
test_boolean(&ctx, &parse_section_tweak, "font-monospace-warn",
&conf.tweak.font_monospace_warn);
test_float(&ctx, &parse_section_tweak, "bold-text-in-bright-amount",
&conf.bold_in_bright.amount);
#if 0 /* Must be equal to, or less than INT32_MAX */
test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb",
&conf.tweak.max_shm_pool_size);

21
vt.c
View file

@ -913,6 +913,16 @@ action_utf8_33(struct terminal *term, uint8_t c)
{
// wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
term->vt.utf8 |= c & 0x3f;
const char32_t utf32 = term->vt.utf8;
if (unlikely(utf32 >= 0xd800 && utf32 <= 0xdfff)) {
/* Invalid sequence - invalid UTF-16 surrogate halves */
return;
}
/* Note: the E0 range contains overlong encodings. We dont try to
detect, as theyll still decode to valid UTF-32. */
action_utf8_print(term, term->vt.utf8);
}
@ -942,6 +952,17 @@ action_utf8_44(struct terminal *term, uint8_t c)
{
// wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
term->vt.utf8 |= c & 0x3f;
const char32_t utf32 = term->vt.utf8;
if (unlikely(utf32 > 0x10FFFF)) {
/* Invalid UTF-8 */
return;
}
/* Note: the F0 range contains overlong encodings. We dont try to
detect, as theyll still decode to valid UTF-32. */
action_utf8_print(term, term->vt.utf8);
}

View file

@ -57,7 +57,7 @@ csd_reload_font(struct wl_window *win, float old_scale)
char pixelsize[32];
snprintf(pixelsize, sizeof(pixelsize), "pixelsize=%u",
(int)round(conf->csd.title_height * scale * 1 / 2));
(int)roundf(conf->csd.title_height * scale * 1 / 2));
LOG_DBG("loading CSD font \"%s:%s\" (old-scale=%.2f, scale=%.2f)",
patterns[0], pixelsize, old_scale, scale);
@ -315,15 +315,17 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
}
#if defined(HAVE_FRACTIONAL_SCALE)
xassert(seat->pointer.surface.viewport == NULL);
seat->pointer.surface.viewport = wp_viewporter_get_viewport(
seat->wayl->viewporter, seat->pointer.surface.surf);
if (seat->wayl->viewporter != NULL) {
xassert(seat->pointer.surface.viewport == NULL);
seat->pointer.surface.viewport = wp_viewporter_get_viewport(
seat->wayl->viewporter, seat->pointer.surface.surf);
if (seat->pointer.surface.viewport == NULL) {
LOG_ERR("%s: failed to create pointer viewport", seat->name);
wl_surface_destroy(seat->pointer.surface.surf);
seat->pointer.surface.surf = NULL;
return;
if (seat->pointer.surface.viewport == NULL) {
LOG_ERR("%s: failed to create pointer viewport", seat->name);
wl_surface_destroy(seat->pointer.surface.surf);
seat->pointer.surface.surf = NULL;
return;
}
}
#endif
@ -351,8 +353,10 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
wl_surface_destroy(seat->pointer.surface.surf);
#if defined(HAVE_FRACTIONAL_SCALE)
wp_viewport_destroy(seat->pointer.surface.viewport);
seat->pointer.surface.viewport = NULL;
if (seat->pointer.surface.viewport != NULL) {
wp_viewport_destroy(seat->pointer.surface.viewport);
seat->pointer.surface.viewport = NULL;
}
#endif
if (seat->pointer.theme != NULL)
@ -416,7 +420,7 @@ update_term_for_output_change(struct terminal *term)
* buffer dimensions may not have been updated (in which case
* render_size() normally shortcuts and returns early).
*/
render_resize_force(term, round(logical_width), round(logical_height));
render_resize_force(term, (int)roundf(logical_width), (int)roundf(logical_height));
}
else if (scale_updated) {
@ -425,7 +429,7 @@ update_term_for_output_change(struct terminal *term)
* been updated, even though the window logical dimensions
* havent changed.
*/
render_resize(term, round(logical_width), round(logical_height));
render_resize(term, (int)roundf(logical_width), (int)roundf(logical_height));
}
}
@ -620,6 +624,8 @@ xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
static void
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
{
struct monitor *mon = data;
update_terms_on_monitor(mon);
}
static void
@ -1526,7 +1532,7 @@ wayl_init(struct fdm *fdm, struct key_binding_manager *key_binding_manager,
LOG_INFO(
"%s: %dx%d+%dx%d@%dHz %s %.2f\" scale=%d, DPI=%.2f/%.2f (physical/scaled)",
it->item.name, it->item.dim.px_real.width, it->item.dim.px_real.height,
it->item.x, it->item.y, (int)round(it->item.refresh),
it->item.x, it->item.y, (int)roundf(it->item.refresh),
it->item.model != NULL ? it->item.model : it->item.description,
it->item.inch, it->item.scale,
it->item.dpi.physical, it->item.dpi.scaled);
@ -1994,33 +2000,35 @@ wayl_roundtrip(struct wayland *wayl)
wayl_flush(wayl);
}
bool
wayl_fractional_scaling(const struct wayland *wayl)
{
#if defined(HAVE_FRACTIONAL_SCALE)
return wayl->fractional_scale_manager != NULL;
#else
return false;
#endif
}
void
wayl_surface_scale_explicit_width_height(
static void
surface_scale_explicit_width_height(
const struct wl_window *win, const struct wayl_surface *surf,
int width, int height, float scale)
int width, int height, float scale, bool verify)
{
if (wayl_fractional_scaling(win->term->wl) && win->scale > 0.) {
if (term_fractional_scaling(win->term)) {
#if defined(HAVE_FRACTIONAL_SCALE)
LOG_DBG("scaling by a factor of %.2f using fractional scaling "
"(width=%d, height=%d) ", scale, width, height);
if (verify) {
if ((int)roundf(scale * (int)roundf(width / scale)) != width) {
BUG("width=%d is not valid with scaling factor %.2f (%d != %d)",
width, scale,
(int)roundf(scale * (int)roundf(width / scale)),
width);
}
if ((int)roundf(scale * (int)roundf(height / scale)) != height) {
BUG("height=%d is not valid with scaling factor %.2f (%d != %d)",
height, scale,
(int)roundf(scale * (int)roundf(height / scale)),
height);
}
}
wl_surface_set_buffer_scale(surf->surf, 1);
wp_viewport_set_destination(
surf->viewport,
round((float)width / scale),
round((float)height / scale));
surf->viewport, roundf(width / scale), roundf(height / scale));
#else
BUG("wayl_fraction_scaling() returned true, "
"but fractional scaling was not available at compile time");
@ -2029,9 +2037,9 @@ wayl_surface_scale_explicit_width_height(
LOG_DBG("scaling by a factor of %.2f using legacy mode "
"(width=%d, height=%d)", scale, width, height);
xassert(scale == floor(scale));
xassert(scale == floorf(scale));
const int iscale = (int)scale;
const int iscale = (int)floorf(scale);
xassert(width % iscale == 0);
xassert(height % iscale == 0);
@ -2039,12 +2047,20 @@ wayl_surface_scale_explicit_width_height(
}
}
void
wayl_surface_scale_explicit_width_height(
const struct wl_window *win, const struct wayl_surface *surf,
int width, int height, float scale)
{
surface_scale_explicit_width_height(win, surf, width, height, scale, false);
}
void
wayl_surface_scale(const struct wl_window *win, const struct wayl_surface *surf,
const struct buffer *buf, float scale)
{
wayl_surface_scale_explicit_width_height(
win, surf, buf->width, buf->height, scale);
surface_scale_explicit_width_height(
win, surf, buf->width, buf->height, scale, true);
}
void