From e17c6fcbecf67a75bf8cd37995fac0e937b934cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:22:19 +0200 Subject: [PATCH 01/17] render: color_dim(): retain alpha channel --- render.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/render.c b/render.c index 6e0e82bf..f4ebc086 100644 --- a/render.c +++ b/render.c @@ -246,9 +246,10 @@ color_hex_to_pixman(uint32_t color) static inline uint32_t color_dim(uint32_t color) { + uint32_t alpha = color & 0xff000000; int hue, sat, lum; rgb_to_hsl(color, &hue, &sat, &lum); - return hsl_to_rgb(hue, sat, lum / 1.5); + return alpha | hsl_to_rgb(hue, sat, lum / 1.5); } static inline uint32_t From 7067c57399177c0559658086cbf7997fe3b8057a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:22:52 +0200 Subject: [PATCH 02/17] render: render_osd(): set clip region, use background alpha MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set clip region in render_osd(). This ensures we don’t step outside the pixman buffer when rendering the glyphs. Furthermore, don’t ignore the alpha channel in the background color. Move render_osd() to make it visible to the render_csd_*() functions. --- render.c | 114 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/render.c b/render.c index f4ebc086..94651c11 100644 --- a/render.c +++ b/render.c @@ -1576,6 +1576,67 @@ render_csd_part(struct terminal *term, pixman_image_unref(src); } +static void +render_osd(struct terminal *term, + struct wl_surface *surf, struct wl_subsurface *sub_surf, + struct buffer *buf, + const wchar_t *text, uint32_t _fg, uint32_t _bg, + unsigned x, unsigned y) +{ + pixman_region32_t clip; + pixman_region32_init_rect(&clip, 0, 0, buf->width, buf->height); + pixman_image_set_clip_region32(buf->pix[0], &clip); + pixman_region32_fini(&clip); + + uint16_t alpha = _bg >> 24 | (_bg >> 24 << 8); + pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, alpha); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &bg, 1, + &(pixman_rectangle16_t){0, 0, buf->width, buf->height}); + + 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); + + if (glyph == NULL) + continue; + + 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 + x_ofs + glyph->x, y + font_baseline(term) - glyph->y, + glyph->width, glyph->height); + pixman_image_unref(src); + + x += term->cell_width; + } + + pixman_image_set_clip_region32(buf->pix[0], NULL); + + xassert(buf->width % term->scale == 0); + xassert(buf->height % term->scale == 0); + + quirk_weston_subsurface_desync_on(sub_surf); + wl_surface_attach(surf, buf->wl_buf, 0, 0); + wl_surface_damage_buffer(surf, 0, 0, buf->width, buf->height); + wl_surface_set_buffer_scale(surf, term->scale); + + struct wl_region *region = wl_compositor_create_region(term->wl->compositor); + if (region != NULL) { + wl_region_add(region, 0, 0, buf->width, buf->height); + wl_surface_set_opaque_region(surf, region); + wl_region_destroy(region); + } + + wl_surface_commit(surf); + quirk_weston_subsurface_desync_off(sub_surf); +} + static void render_csd_title(struct terminal *term, const struct csd_data *info, struct buffer *buf) @@ -1913,59 +1974,6 @@ render_csd(struct terminal *term) render_csd_title(term, &infos[CSD_SURF_TITLE], bufs[CSD_SURF_TITLE]); } -static void -render_osd(struct terminal *term, - struct wl_surface *surf, struct wl_subsurface *sub_surf, - struct buffer *buf, - const wchar_t *text, uint32_t _fg, uint32_t _bg, - unsigned x, unsigned y) -{ - pixman_color_t bg = color_hex_to_pixman(_bg); - pixman_image_fill_rectangles( - PIXMAN_OP_SRC, buf->pix[0], &bg, 1, - &(pixman_rectangle16_t){0, 0, buf->width, buf->height}); - - 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); - - if (glyph == NULL) - continue; - - 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 + x_ofs + glyph->x, y + font_baseline(term) - glyph->y, - glyph->width, glyph->height); - pixman_image_unref(src); - - x += term->cell_width; - } - - xassert(buf->width % term->scale == 0); - xassert(buf->height % term->scale == 0); - - quirk_weston_subsurface_desync_on(sub_surf); - wl_surface_attach(surf, buf->wl_buf, 0, 0); - wl_surface_damage_buffer(surf, 0, 0, buf->width, buf->height); - wl_surface_set_buffer_scale(surf, term->scale); - - struct wl_region *region = wl_compositor_create_region(term->wl->compositor); - if (region != NULL) { - wl_region_add(region, 0, 0, buf->width, buf->height); - wl_surface_set_opaque_region(surf, region); - wl_region_destroy(region); - } - - wl_surface_commit(surf); - quirk_weston_subsurface_desync_off(sub_surf); -} - static void render_scrollback_position(struct terminal *term) { From bbc26da87b821fcab684a9c1dfaa52d0538b278b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:24:20 +0200 Subject: [PATCH 03/17] render: must now set alpha in bg color when calling render_osd() --- render.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/render.c b/render.c index 94651c11..c459dafa 100644 --- a/render.c +++ b/render.c @@ -2103,7 +2103,7 @@ render_scrollback_position(struct terminal *term) win->scrollback_indicator.surf, win->scrollback_indicator.sub, buf, text, - term->colors.table[0], term->colors.table[8 + 4], + term->colors.table[0], 0xffu << 24 | term->colors.table[8 + 4], width - margin - wcslen(text) * term->cell_width, margin); } @@ -2137,7 +2137,7 @@ render_render_timer(struct terminal *term, struct timeval render_time) win->render_timer.surf, win->render_timer.sub, buf, text, - term->colors.table[0], term->colors.table[8 + 1], + term->colors.table[0], 0xffu << 24 | term->colors.table[8 + 1], margin, margin); } @@ -2639,7 +2639,6 @@ render_search_box(struct terminal *term) pixman_image_set_clip_region32(buf->pix[0], &clip); pixman_region32_fini(&clip); - #define WINDOW_X(x) (margin + x) #define WINDOW_Y(y) (term->height - margin - height + y) @@ -3106,7 +3105,8 @@ render_urls(struct terminal *term) (term->margins.top + y) / term->scale); render_osd( - term, surf, sub_surf, bufs[i], label, fg, bg, x_margin, y_margin); + term, surf, sub_surf, bufs[i], label, + fg, 0xffu << 24 | bg, x_margin, y_margin); free(info[i].text); } From 468587b67f1c9c8dee6896d4319f0282a01ecb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:25:24 +0200 Subject: [PATCH 04/17] render: csd_title(): use render_osd() to render the current window title --- render.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/render.c b/render.c index c459dafa..43d50b83 100644 --- a/render.c +++ b/render.c @@ -1643,26 +1643,40 @@ render_csd_title(struct terminal *term, const struct csd_data *info, { xassert(term->window->csd_mode == CSD_YES); - struct wl_surface *surf = term->window->csd.surface[CSD_SURF_TITLE].surf; + struct wl_surf_subsurf *surf = &term->window->csd.surface[CSD_SURF_TITLE]; xassert(info->width > 0 && info->height > 0); xassert(info->width % term->scale == 0); xassert(info->height % term->scale == 0); - uint32_t _color = term->conf->colors.fg; - uint16_t alpha = 0xffff; + uint32_t bg = term->conf->csd.color.title_set + ? term->conf->csd.color.title + : 0xffu << 24 | term->conf->colors.fg; + uint32_t fg = term->conf->csd.color.buttons_set + ? term->conf->csd.color.buttons + : term->conf->colors.bg; - if (term->conf->csd.color.title_set) { - _color = term->conf->csd.color.title; - alpha = _color >> 24 | (_color >> 24 << 8); + if (!term->visual_focus) { + bg = color_dim(bg); + fg = color_dim(fg); } - if (!term->visual_focus) - _color = color_dim(_color); + const wchar_t *title_text = L""; + wchar_t *_title_text = NULL; - pixman_color_t color = color_hex_to_pixman_with_alpha(_color, alpha); - render_csd_part(term, surf, buf, info->width, info->height, &color); - csd_commit(term, surf, buf); + int chars = mbstowcs(NULL, term->window_title, 0); + if (chars >= 0) { + _title_text = xmalloc((chars + 1) * sizeof(wchar_t)); + mbstowcs(_title_text, term->window_title, chars + 1); + title_text = _title_text; + } + + const int margin = 10 * term->scale; + render_osd(term, surf->surf, surf->sub, buf, title_text, fg, bg, + margin, (buf->height - term->fonts[0]->height) / 2); + + csd_commit(term, surf->surf, buf); + free(_title_text); } static void From 61e4035c23ef61a0fcca5f56a8ac50afa64349ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:27:35 +0200 Subject: [PATCH 05/17] render: refresh CSDs when updating the title --- render.c | 1 + 1 file changed, 1 insertion(+) diff --git a/render.c b/render.c index 43d50b83..2e59a688 100644 --- a/render.c +++ b/render.c @@ -3141,6 +3141,7 @@ render_update_title(struct terminal *term) xdg_toplevel_set_title(term->window->xdg_toplevel, title); free(copy); + render_refresh_csd(term); } static void From 3d9536caff354e30bea463f4a7e617a9aa11ebc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 19:34:19 +0200 Subject: [PATCH 06/17] render: refresh CSD in render_refresh_title(), not render_update_title() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes an issue where the CSD title sometimes got stuck on an “old” title. --- render.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/render.c b/render.c index 2e59a688..1a66288b 100644 --- a/render.c +++ b/render.c @@ -3141,7 +3141,6 @@ render_update_title(struct terminal *term) xdg_toplevel_set_title(term->window->xdg_toplevel, title); free(copy); - render_refresh_csd(term); } static void @@ -3691,6 +3690,8 @@ render_refresh_title(struct terminal *term) term->render.title.last_update = now; render_update_title(term); } + + render_refresh_csd(term); } void From 5fe23c0215502b41fb40032a89d55e574e73169f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 21:23:01 +0200 Subject: [PATCH 07/17] render: render_osd(): pass font as argument --- render.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/render.c b/render.c index 1a66288b..91499a43 100644 --- a/render.c +++ b/render.c @@ -1579,7 +1579,7 @@ render_csd_part(struct terminal *term, static void render_osd(struct terminal *term, struct wl_surface *surf, struct wl_subsurface *sub_surf, - struct buffer *buf, + struct fcft_font *font, struct buffer *buf, const wchar_t *text, uint32_t _fg, uint32_t _bg, unsigned x, unsigned y) { @@ -1594,11 +1594,15 @@ render_osd(struct terminal *term, PIXMAN_OP_SRC, buf->pix[0], &bg, 1, &(pixman_rectangle16_t){0, 0, buf->width, buf->height}); - struct fcft_font *font = term->fonts[0]; pixman_color_t fg = color_hex_to_pixman(_fg); - const int x_ofs = term->font_x_ofs; + const int advance = + (font->space_advance.x > 0 + ? font->space_advance.x + : font->max_advance.x) + + term_pt_or_px_as_pixels(term, &term->conf->letter_spacing); + for (size_t i = 0; i < wcslen(text); i++) { const struct fcft_glyph *glyph = fcft_glyph_rasterize( font, text[i], term->font_subpixel); @@ -1609,11 +1613,11 @@ 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 + x_ofs + glyph->x, y + font_baseline(term) - glyph->y, + x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y, glyph->width, glyph->height); pixman_image_unref(src); - x += term->cell_width; + x += advance; } pixman_image_set_clip_region32(buf->pix[0], NULL); From 4a41575cb5d2738cf1fb341f0d4413dee1bf67cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 21:23:29 +0200 Subject: [PATCH 08/17] =?UTF-8?q?render:=20render=5Fosd()=20now=20needs=20?= =?UTF-8?q?a=20=E2=80=98font=E2=80=99=20argument?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- render.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/render.c b/render.c index 91499a43..82720d22 100644 --- a/render.c +++ b/render.c @@ -2120,7 +2120,7 @@ render_scrollback_position(struct terminal *term) term, win->scrollback_indicator.surf, win->scrollback_indicator.sub, - buf, text, + term->fonts[0], buf, text, term->colors.table[0], 0xffu << 24 | term->colors.table[8 + 4], width - margin - wcslen(text) * term->cell_width, margin); } @@ -2154,7 +2154,7 @@ render_render_timer(struct terminal *term, struct timeval render_time) term, win->render_timer.surf, win->render_timer.sub, - buf, text, + term->fonts[0], buf, text, term->colors.table[0], 0xffu << 24 | term->colors.table[8 + 1], margin, margin); } @@ -3123,7 +3123,7 @@ render_urls(struct terminal *term) (term->margins.top + y) / term->scale); render_osd( - term, surf, sub_surf, bufs[i], label, + term, surf, sub_surf, term->fonts[0], bufs[i], label, fg, 0xffu << 24 | bg, x_margin, y_margin); free(info[i].text); From 0cf7a196163d51c344361bb2b79c145003dc3555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 21:23:59 +0200 Subject: [PATCH 09/17] =?UTF-8?q?render:=20csd=5Ftitle():=20use=20a=20cust?= =?UTF-8?q?om=20font,=20sized=20based=20on=20the=20title=20bar=E2=80=99s?= =?UTF-8?q?=20height?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still use the primary font, but use a custom size, based on the title bar’s height. This fixes an issue where the window title could be way too small, or way too big. And changed size when the terminal font size was changed. --- render.c | 11 ++++++++--- wayland.c | 33 +++++++++++++++++++++++++++++++++ wayland.h | 2 ++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/render.c b/render.c index 82720d22..8fb810b9 100644 --- a/render.c +++ b/render.c @@ -1675,9 +1675,14 @@ render_csd_title(struct terminal *term, const struct csd_data *info, title_text = _title_text; } - const int margin = 10 * term->scale; - render_osd(term, surf->surf, surf->sub, buf, title_text, fg, bg, - margin, (buf->height - term->fonts[0]->height) / 2); + struct wl_window *win = term->window; + const int margin = win->csd.font->space_advance.x > 0 + ? win->csd.font->space_advance.x + : win->csd.font->max_advance.x; + + render_osd(term, surf->surf, surf->sub, win->csd.font, + buf, title_text, fg, bg, margin, + (buf->height - win->csd.font->height) / 2); csd_commit(term, surf->surf, buf); free(_title_text); diff --git a/wayland.c b/wayland.c index 0679dee3..40852ec0 100644 --- a/wayland.c +++ b/wayland.c @@ -30,6 +30,33 @@ #include "util.h" #include "xmalloc.h" +static void +csd_reload_font(struct wl_window *win, int old_scale) +{ + struct terminal *term = win->term; + const struct config *conf = term->conf; + + const int scale = term->scale; + + bool enable_csd = win->csd_mode == CSD_YES && !win->is_fullscreen; + if (!enable_csd) + return; + if (win->csd.font != NULL && scale == old_scale) + return; + + fcft_destroy(win->csd.font); + + char pixelsize[32]; + snprintf(pixelsize, sizeof(pixelsize), + "pixelsize=%u", conf->csd.title_height * scale * 1 / 2); + + LOG_DBG("loading CSD font \"%s:%s\" (old-scale=%d, scale=%d)", + conf->fonts->arr[0].pattern, pixelsize, old_scale, scale); + + win->csd.font = fcft_from_name( + 1, &(const char *){conf->fonts->arr[0].pattern}, pixelsize); +} + static void csd_instantiate(struct wl_window *win) { @@ -46,6 +73,8 @@ csd_instantiate(struct wl_window *win) win, win->csd.surface[CSD_SURF_TITLE].surf, &win->csd.surface[i]); xassert(ret); } + + csd_reload_font(win, -1); } static void @@ -53,6 +82,9 @@ csd_destroy(struct wl_window *win) { struct terminal *term = win->term; + fcft_destroy(term->window->csd.font); + term->window->csd.font = NULL; + for (size_t i = 0; i < ALEN(win->csd.surface); i++) wayl_win_subsurface_destroy(&win->csd.surface[i]); shm_purge(term->render.chains.csd); @@ -294,6 +326,7 @@ update_term_for_output_change(struct terminal *term) render_resize(term, term->width / term->scale, term->height / term->scale); term_font_dpi_changed(term, old_scale); term_font_subpixel_changed(term); + csd_reload_font(term->window, old_scale); } static void diff --git a/wayland.h b/wayland.h index f62819a4..bc044169 100644 --- a/wayland.h +++ b/wayland.h @@ -20,6 +20,7 @@ #include #endif +#include #include #include "fdm.h" @@ -402,6 +403,7 @@ struct wl_window { struct { struct wl_surf_subsurf surface[CSD_SURF_COUNT]; + struct fcft_font *font; int move_timeout_fd; uint32_t serial; } csd; From 9985b8c713346889fb50b787a35b0ec2fc48d43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 21:39:35 +0200 Subject: [PATCH 10/17] changelog: window title in CSDs --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9dfdecb..84d333f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ ## Unreleased ### Added + +* Window title in the CSDs + (https://codeberg.org/dnkl/foot/issues/638). + + ### Changed ### Deprecated ### Removed From 50f59fe575f339b36c1abdeb74f85be776fcdc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:21:31 +0200 Subject: [PATCH 11/17] config: add csd.font option --- config.c | 98 +++++++++++++++++++++++++++++++++++++++------- config.h | 2 + doc/foot.ini.5.scd | 4 ++ wayland.c | 9 +++-- 4 files changed, 95 insertions(+), 18 deletions(-) diff --git a/config.c b/config.c index a9acb58e..f671e7e0 100644 --- a/config.c +++ b/config.c @@ -503,6 +503,52 @@ str_to_pt_or_px(const char *s, struct pt_or_px *res, struct config *conf, return true; } +static struct config_font_list NOINLINE +str_to_fonts(const char *s, struct config *conf, const char *path, int lineno, + const char *section, const char *key) +{ + size_t count = 0; + size_t size = 0; + struct config_font *fonts = NULL; + + char *copy = xstrdup(s); + 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] == '\0') + continue; + + struct config_font font_data; + if (!config_font_parse(font, &font_data)) { + LOG_AND_NOTIFY_ERR( + "%s:%d: [%s]: %s: invalid font specification: %s", + path, lineno, section, key, font); + goto err; + } + + if (count + 1 > size) { + size += 4; + fonts = xrealloc(fonts, size * sizeof(fonts[0])); + } + + xassert(count + 1 <= size); + fonts[count++] = font_data; + } + + free(copy); + return (struct config_font_list){.arr = fonts, .count = count}; + +err: + free(copy); + free(fonts); + return (struct config_font_list){.arr = NULL, .count = 0}; +} + static void NOINLINE free_argv(struct argv *argv) { @@ -804,8 +850,9 @@ parse_section_main(const char *key, const char *value, struct config *conf, struct config_font font_data; if (!config_font_parse(font, &font_data)) { - LOG_ERR("%s:%d: [default]: %s: invalid font specification", - path, lineno, key); + LOG_AND_NOTIFY_ERR( + "%s:%d: [default]: %s: invalid font specification: %s", + path, lineno, key, font); free(copy); return false; } @@ -1328,6 +1375,17 @@ parse_section_csd(const char *key, const char *value, struct config *conf, } } + else if (strcmp(key, "font") == 0) { + struct config_font_list new_list = str_to_fonts( + value, conf, path, lineno, "csd", "font"); + + if (new_list.arr == NULL) + return false; + + config_font_list_destroy(&conf->csd.font); + conf->csd.font = new_list; + } + else if (strcmp(key, "color") == 0) { uint32_t color; if (!str_to_color(value, &color, true, conf, path, lineno, "csd", "color")) @@ -2706,6 +2764,20 @@ add_default_mouse_bindings(struct config *conf) memcpy(conf->bindings.mouse.arr, bindings, sizeof(bindings)); } +static void NOINLINE +config_font_list_clone(struct config_font_list *dst, + const struct config_font_list *src) +{ + dst->count = src->count; + dst->arr = xmalloc(dst->count * sizeof(dst->arr[0])); + + for (size_t j = 0; j < dst->count; j++) { + dst->arr[j].pt_size = src->arr[j].pt_size; + dst->arr[j].px_size = src->arr[j].px_size; + dst->arr[j].pattern = xstrdup(src->arr[j].pattern); + } +} + bool config_load(struct config *conf, const char *conf_path, user_notifications_t *initial_user_notifications, @@ -2811,6 +2883,7 @@ config_load(struct config *conf, const char *conf_path, }, .csd = { .preferred = CONF_CSD_PREFER_SERVER, + .font = {0}, .title_height = 26, .border_width = 5, .button_width = 26, @@ -2955,6 +3028,9 @@ out: } } + if (ret && conf->csd.font.count == 0) + config_font_list_clone(&conf->csd.font, &conf->fonts[0]); + #if defined(_DEBUG) for (size_t i = 0; i < conf->bindings.key.count; i++) xassert(conf->bindings.key.arr[i].action != BIND_ACTION_NONE); @@ -3107,19 +3183,9 @@ config_clone(const struct config *old) spawn_template_clone(&conf->bell.command, &old->bell.command); spawn_template_clone(&conf->notify, &old->notify); - for (size_t i = 0; i < ALEN(conf->fonts); i++) { - struct config_font_list *dst = &conf->fonts[i]; - const struct config_font_list *src = &old->fonts[i]; - - dst->count = src->count; - dst->arr = xmalloc(dst->count * sizeof(dst->arr[0])); - - for (size_t j = 0; j < dst->count; j++) { - dst->arr[j].pt_size = src->arr[j].pt_size; - dst->arr[j].px_size = src->arr[j].px_size; - dst->arr[j].pattern = xstrdup(src->arr[j].pattern); - } - } + for (size_t i = 0; i < ALEN(conf->fonts); i++) + config_font_list_clone(&conf->fonts[i], &old->fonts[i]); + config_font_list_clone(&conf->csd.font, &old->csd.font); conf->url.label_letters = xwcsdup(old->url.label_letters); spawn_template_clone(&conf->url.launch, &old->url.launch); @@ -3182,6 +3248,8 @@ config_free(struct config conf) config_font_list_destroy(&conf.fonts[i]); free(conf.server_socket_path); + config_font_list_destroy(&conf.csd.font); + free(conf.url.label_letters); spawn_template_free(&conf.url.launch); for (size_t i = 0; i < conf.url.prot_count; i++) diff --git a/config.h b/config.h index 729eba3e..ae7ff79a 100644 --- a/config.h +++ b/config.h @@ -228,6 +228,8 @@ struct config { uint32_t maximize; uint32_t close; } color; + + struct config_font_list font; } csd; size_t render_worker_count; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 8b2f1dc8..e0d70b1f 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -518,6 +518,10 @@ component. Titlebar AARRGGBB color. Default: use the default _foreground_ color. +*font* + Font to use for the title bar. This is a list of fonts, similar to + the main *font* option. Default: _primary font_. + *button-width* Width, in pixels (subject to output scaling), of the minimize/maximize/close buttons. Default: _26_. diff --git a/wayland.c b/wayland.c index 40852ec0..a83ef59d 100644 --- a/wayland.c +++ b/wayland.c @@ -46,15 +46,18 @@ csd_reload_font(struct wl_window *win, int old_scale) fcft_destroy(win->csd.font); + const char *patterns[conf->csd.font.count]; + for (size_t i = 0; i < conf->csd.font.count; i++) + patterns[i] = conf->csd.font.arr[i].pattern; + char pixelsize[32]; snprintf(pixelsize, sizeof(pixelsize), "pixelsize=%u", conf->csd.title_height * scale * 1 / 2); LOG_DBG("loading CSD font \"%s:%s\" (old-scale=%d, scale=%d)", - conf->fonts->arr[0].pattern, pixelsize, old_scale, scale); + patterns[0], pixelsize, old_scale, scale); - win->csd.font = fcft_from_name( - 1, &(const char *){conf->fonts->arr[0].pattern}, pixelsize); + win->csd.font = fcft_from_name(conf->csd.font.count, patterns, pixelsize); } static void From 5c683d2c089e4b30b35d0f5b9c816e1a88ae6e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:26:07 +0200 Subject: [PATCH 12/17] =?UTF-8?q?render:=20render=5Fosd():=20don=E2=80=99t?= =?UTF-8?q?=20assume=20a=20monospace=20font?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- render.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/render.c b/render.c index 8fb810b9..581d0cbb 100644 --- a/render.c +++ b/render.c @@ -1597,11 +1597,6 @@ render_osd(struct terminal *term, pixman_color_t fg = color_hex_to_pixman(_fg); const int x_ofs = term->font_x_ofs; - const int advance = - (font->space_advance.x > 0 - ? font->space_advance.x - : font->max_advance.x) - + term_pt_or_px_as_pixels(term, &term->conf->letter_spacing); for (size_t i = 0; i < wcslen(text); i++) { const struct fcft_glyph *glyph = fcft_glyph_rasterize( @@ -1617,7 +1612,7 @@ render_osd(struct terminal *term, glyph->width, glyph->height); pixman_image_unref(src); - x += advance; + x += glyph->advance.x; } pixman_image_set_clip_region32(buf->pix[0], NULL); From bf285ae00a749147fa15ac86bc38e8b1d7cae217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:27:05 +0200 Subject: [PATCH 13/17] =?UTF-8?q?render:=20render=5Fosd():=20don=E2=80=99t?= =?UTF-8?q?=20re-instantiate=20foreground=20color=20for=20each=20glyph?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- render.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/render.c b/render.c index 581d0cbb..d5e7a7d6 100644 --- a/render.c +++ b/render.c @@ -1597,6 +1597,7 @@ render_osd(struct terminal *term, pixman_color_t fg = color_hex_to_pixman(_fg); const int x_ofs = term->font_x_ofs; + pixman_image_t *src = pixman_image_create_solid_fill(&fg); for (size_t i = 0; i < wcslen(text); i++) { const struct fcft_glyph *glyph = fcft_glyph_rasterize( @@ -1615,6 +1616,7 @@ render_osd(struct terminal *term, x += glyph->advance.x; } + pixman_image_unref(src); pixman_image_set_clip_region32(buf->pix[0], NULL); xassert(buf->width % term->scale == 0); From e2e28db7deb762830bf3a3d178a561b8e683ff8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:27:10 +0200 Subject: [PATCH 14/17] render: render_osd(): fix rendering of color bitmap glyphs --- render.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/render.c b/render.c index d5e7a7d6..1f8c5809 100644 --- a/render.c +++ b/render.c @@ -1606,12 +1606,17 @@ render_osd(struct terminal *term, if (glyph == NULL) continue; - 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 + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y, - glyph->width, glyph->height); - pixman_image_unref(src); + 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, + 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, + glyph->width, glyph->height); + } x += glyph->advance.x; } From 7714fcde83c223f8143bb406eb2e2541ee932c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:35:00 +0200 Subject: [PATCH 15/17] render: render_osd(): use fcft_text_run_rasterize(), if available --- render.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/render.c b/render.c index 1f8c5809..f42279c9 100644 --- a/render.c +++ b/render.c @@ -1597,14 +1597,39 @@ render_osd(struct terminal *term, pixman_color_t fg = color_hex_to_pixman(_fg); const int x_ofs = term->font_x_ofs; + const size_t len = wcslen(text); + struct fcft_text_run *text_run = NULL; + const struct fcft_glyph **glyphs = NULL; + const struct fcft_glyph *_glyphs[len]; + size_t glyph_count = 0; + + if (fcft_capabilities() & FCFT_CAPABILITY_TEXT_RUN_SHAPING) { + text_run = fcft_text_run_rasterize(font, len, text, term->font_subpixel); + + if (text_run != NULL) { + glyphs = text_run->glyphs; + glyph_count = text_run->count; + } + } + + if (glyphs == NULL) { + for (size_t i = 0; i < len; i++) { + const struct fcft_glyph *glyph = fcft_glyph_rasterize( + font, text[i], term->font_subpixel); + + if (glyph == NULL) + continue; + + _glyphs[glyph_count++] = glyph; + } + + glyphs = _glyphs; + } + pixman_image_t *src = pixman_image_create_solid_fill(&fg); - for (size_t i = 0; i < wcslen(text); i++) { - const struct fcft_glyph *glyph = fcft_glyph_rasterize( - font, text[i], term->font_subpixel); - - if (glyph == NULL) - continue; + for (size_t i = 0; i < glyph_count; i++) { + const struct fcft_glyph *glyph = glyphs[i]; if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { pixman_image_composite32( @@ -1621,6 +1646,7 @@ render_osd(struct terminal *term, x += glyph->advance.x; } + fcft_text_run_destroy(text_run); pixman_image_unref(src); pixman_image_set_clip_region32(buf->pix[0], NULL); From 4c89006d067d0be9c86cbd716de87ec342c75b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:40:32 +0200 Subject: [PATCH 16/17] foot.ini: add csd.font --- foot.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/foot.ini b/foot.ini index 31167cd5..38f15b2e 100644 --- a/foot.ini +++ b/foot.ini @@ -94,6 +94,7 @@ [csd] # preferred=server # size=26 +# font= # color= # button-width=26 # button-color= From c38b3507bcda8567cdae5f1d81ddea336408a454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 22 Jul 2021 23:40:40 +0200 Subject: [PATCH 17/17] doc: foot.ini: mention that csd.font is sized using the title bar size --- doc/foot.ini.5.scd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index e0d70b1f..4a4be533 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -520,7 +520,9 @@ component. *font* Font to use for the title bar. This is a list of fonts, similar to - the main *font* option. Default: _primary font_. + the main *font* option. Note that the font will be sized using the + title bar size. That is, all *:size* and *:pixelsize* attributes + will be ignored. Default: _primary font_. *button-width* Width, in pixels (subject to output scaling), of the