From 67758a7cb7207582671d223730123a63c0231642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 26 Jul 2020 10:01:26 +0200 Subject: [PATCH] render: scrollback indicator: wip: implement 'fixed:percent' indicator When scrollback indicator has been enabled, and the viewport isn't at the bottom, we now render a *static* indicator with the position in percent. We use the color scheme's blue color as background, and it's white color as foreground. This is subject to change... Should maybe be configurable as well. The Wayland surface + sub-surface are instantiated on-demand, and automatically destroyed when no longer used. --- render.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 100 insertions(+), 10 deletions(-) diff --git a/render.c b/render.c index ffab85ab..a64654f2 100644 --- a/render.c +++ b/render.c @@ -1293,6 +1293,53 @@ render_scrollback_position(struct terminal *term) if (term->conf->scrollback.indicator.style == SCROLLBACK_INDICATOR_STYLE_NONE) return; + struct wayland *wayl = term->wl; + struct wl_window *win = term->window; + + if (term->grid->view == term->grid->offset) { + if (win->scrollback_indicator_surface != NULL) { + wl_subsurface_destroy(win->scrollback_indicator_sub_surface); + wl_surface_destroy(win->scrollback_indicator_surface); + + win->scrollback_indicator_surface = NULL; + win->scrollback_indicator_sub_surface = NULL; + + LOG_INFO("destroyed indicator surfaces"); + } + return; + } + + if (win->scrollback_indicator_surface == NULL) { + win->scrollback_indicator_surface + = wl_compositor_create_surface(wayl->compositor); + + if (win->scrollback_indicator_surface == NULL) { + LOG_ERR("failed to create scrollback indicator surface"); + return; + } + + wl_surface_set_user_data(win->scrollback_indicator_surface, win); + + term->window->scrollback_indicator_sub_surface + = wl_subcompositor_get_subsurface( + wayl->sub_compositor, + win->scrollback_indicator_surface, + win->surface); + + if (win->scrollback_indicator_sub_surface == NULL) { + LOG_ERR("failed to create scrollback indicator sub-surface"); + wl_surface_destroy(win->scrollback_indicator_surface); + win->scrollback_indicator_surface = NULL; + return; + } + + wl_subsurface_set_sync(win->scrollback_indicator_sub_surface); + LOG_INFO("instantiated indicator surfaces"); + } + + assert(win->scrollback_indicator_surface != NULL); + assert(win->scrollback_indicator_sub_surface != NULL); + /* Find absolute row number of the scrollback start */ int scrollback_start = term->grid->offset + term->rows; while (term->grid->rows[scrollback_start & (term->grid->num_rows - 1)] == NULL) @@ -1309,24 +1356,67 @@ render_scrollback_position(struct terminal *term) * 0% -> at the beginning of the scrollback * 100% -> at the bottom, i.e. where new lines are inserted */ - int percentage __attribute__((unused)) = + int percentage = rebased_view + term->rows == term->grid->num_rows ? 100 : 100 * rebased_view / term->grid->num_rows; - int next_row_no = term->grid->view + term->rows; - next_row_no &= term->grid->num_rows - 1; + const int scale = term->scale; + const int margin = 3 * scale; + const int width = 2 * margin + 3 * term->cell_width; /* TODO: this is percent only */ + const int height = 2 * margin + term->cell_height; - /* Are we at the end of the scrollback? */ - bool at_bottom = rebased_view + term->rows == term->grid->num_rows || - term->grid->rows[next_row_no] == NULL; + unsigned long cookie = shm_cookie_scrollback_indicator(term); + struct buffer *buf = shm_get_buffer( + term->wl->shm, width, height, cookie, false, 1); - LOG_DBG("scrollback position: %d/%d (%d%%), at-bottom: %d", - rebased_view, term->grid->num_rows, percentage, at_bottom); + pixman_color_t bg = color_hex_to_pixman(term->colors.table[4]); + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix[0], &bg, 1, + &(pixman_rectangle16_t){0, 0, width, height}); - if (!at_bottom) { - /* TODO: insert rendering code here */ + struct fcft_font *font = term->fonts[0]; + pixman_color_t fg = color_hex_to_pixman(term->colors.table[7]); + + wchar_t text[64]; + swprintf(text, sizeof(text) / sizeof(text[0]), L"%d%%", percentage); + + unsigned x = width - margin - wcslen(text) * term->cell_width; + const unsigned y = margin; + + 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 + glyph->x, y + font_baseline(term) - glyph->y, + glyph->width, glyph->height); + pixman_image_unref(src); + + x += term->cell_width; } + + wl_subsurface_set_position( + win->scrollback_indicator_sub_surface, + (term->width - term->margins.right - width) / scale, + term->margins.top / scale + term->cell_height); + wl_surface_attach(win->scrollback_indicator_surface, buf->wl_buf, 0, 0); + wl_surface_damage_buffer(win->scrollback_indicator_surface, 0, 0, width, height); + wl_surface_set_buffer_scale(win->scrollback_indicator_surface, scale); + + struct wl_region *region = wl_compositor_create_region(wayl->compositor); + if (region != NULL) { + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(win->scrollback_indicator_surface, region); + wl_region_destroy(region); + } + + wl_surface_commit(win->scrollback_indicator_surface); } static void frame_callback(