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(