From 66912cbfb5e44d44670582fad932932f9de6794b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 29 Aug 2019 19:34:41 +0200 Subject: [PATCH] search: use a sub-surface to render the search buffer --- main.c | 5 ++ search.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++----- terminal.h | 1 + 3 files changed, 141 insertions(+), 14 deletions(-) diff --git a/main.c b/main.c index 60d041f1..b78305f7 100644 --- a/main.c +++ b/main.c @@ -197,6 +197,11 @@ handle_global(void *data, struct wl_registry *registry, term->wl.registry, name, &wl_compositor_interface, 4); } + else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + term->wl.sub_compositor = wl_registry_bind( + term->wl.registry, name, &wl_subcompositor_interface, 1); + } + else if (strcmp(interface, wl_shm_interface.name) == 0) { term->wl.shm = wl_registry_bind( term->wl.registry, name, &wl_shm_interface, 1); diff --git a/search.c b/search.c index 6aa6be5c..558f98c7 100644 --- a/search.c +++ b/search.c @@ -1,6 +1,8 @@ #include "search.h" #include + +#include #include #define LOG_MODULE "search" @@ -9,11 +11,98 @@ #include "grid.h" #include "render.h" #include "selection.h" +#include "shm.h" -void -search_begin(struct terminal *term) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +static struct wl_surface *wl_surf; +static struct wl_subsurface *sub_surf; + + +static inline pixman_color_t +color_hex_to_pixman_with_alpha(uint32_t color, uint16_t alpha) { - LOG_DBG("search: begin"); + int alpha_div = 0xffff / alpha; + return (pixman_color_t){ + .red = ((color >> 16 & 0xff) | (color >> 8 & 0xff00)) / alpha_div, + .green = ((color >> 8 & 0xff) | (color >> 0 & 0xff00)) / alpha_div, + .blue = ((color >> 0 & 0xff) | (color << 8 & 0xff00)) / alpha_div, + .alpha = alpha, + }; +} + +static inline pixman_color_t +color_hex_to_pixman(uint32_t color) +{ + /* Count on the compiler optimizing this */ + return color_hex_to_pixman_with_alpha(color, 0xffff); +} + +/* TODO: move to render.c? */ +static void +render(struct terminal *term) +{ + assert(sub_surf != NULL); + + /* TODO: at least sway allows the subsurface to extend outside the + * main window. Do we want that? */ + const int scale = term->scale >= 1 ? term->scale : 1; + const int margin = scale * 3; + const int width = 2 * margin + max(20, term->search.len) * term->cell_width; + const int height = 2 * margin + 1 * term->cell_height; + + struct buffer *buf = shm_get_buffer(term->wl.shm, width, height, 1); + + /* Background - yellow on empty/match, red on mismatch */ + pixman_color_t color = color_hex_to_pixman( + term->search.match_len == term->search.len ? 0xffff00 : 0xff0000); + + pixman_image_fill_rectangles( + PIXMAN_OP_SRC, buf->pix, &color, + 1, &(pixman_rectangle16_t){0, 0, width, height}); + + int x = margin; + int y = margin; + pixman_color_t fg = color_hex_to_pixman(0x000000); + + /* Text (what the user entered - *not* match(es)) */ + for (size_t i = 0; i < term->search.len; i++) { + const struct glyph *glyph = font_glyph_for_wc(&term->fonts[0], term->search.buf[i]); + 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, + x + glyph->x, y + term->fextents.ascent - glyph->y, + glyph->width, glyph->height); + pixman_image_unref(src); + + x += glyph->width; + } + + LOG_INFO("match length: %zu", term->search.match_len); + + wl_subsurface_set_position( + sub_surf, term->width - width - margin, term->height - height - margin); + + wl_surface_damage_buffer(wl_surf, 0, 0, width, height); + wl_surface_attach(wl_surf, buf->wl_buf, 0, 0); + wl_surface_set_buffer_scale(wl_surf, scale); + wl_surface_commit(wl_surf); +} + +static void +search_cancel_keep_selection(struct terminal *term) +{ + if (sub_surf != NULL) { + wl_subsurface_destroy(sub_surf); + sub_surf = NULL; + } + if (wl_surf != NULL) { + wl_surface_destroy(wl_surf); + wl_surf = NULL; + } free(term->search.buf); term->search.buf = NULL; @@ -21,35 +110,65 @@ search_begin(struct terminal *term) term->search.sz = 0; term->search.match = (struct coord){-1, -1}; term->search.match_len = 0; + term->is_searching = false; + + render_refresh(term); +} + +void +search_begin(struct terminal *term) +{ + LOG_DBG("search: begin"); + + search_cancel_keep_selection(term); + selection_cancel(term); + term->search.original_view = term->grid->view; term->search.view_followed_offset = term->grid->view == term->grid->offset; term->is_searching = true; - selection_cancel(term); + wl_surf = wl_compositor_create_surface(term->wl.compositor); + if (wl_surf != NULL) { + sub_surf = wl_subcompositor_get_subsurface( + term->wl.sub_compositor, wl_surf, term->wl.surface); + + if (sub_surf != NULL) { + /* Sub-surface updates may occur without updating the main + * window */ + wl_subsurface_set_desync(sub_surf); + } + } + + if (wl_surf == NULL || sub_surf == NULL) { + LOG_ERR("failed to create sub-surface for search box"); + if (wl_surf != NULL) + wl_surface_destroy(wl_surf); + assert(sub_surf == NULL); + } + + render(term); render_refresh(term); } void search_cancel(struct terminal *term) { - LOG_DBG("search: cancel"); + if (!term->is_searching) + return; - free(term->search.buf); - term->search.buf = NULL; - term->search.len = 0; - term->search.sz = 0; - term->is_searching = false; - - render_refresh(term); + search_cancel_keep_selection(term); + selection_cancel(term); } static void search_update(struct terminal *term) { if (term->search.len == 0) { + LOG_INFO("len == 0"); term->search.match = (struct coord){-1, -1}; term->search.match_len = 0; selection_cancel(term); + render(term); return; } @@ -187,6 +306,7 @@ search_update(struct terminal *term) term->search.match.col = start_col; term->search.match_len = match_len; + render(term); return; } @@ -198,7 +318,7 @@ search_update(struct terminal *term) term->search.match = (struct coord){-1, -1}; term->search.match_len = 0; selection_cancel(term); - + render(term); #undef ROW_DEC } @@ -225,12 +345,13 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask term->grid->view = term->search.original_view; term_damage_view(term); search_cancel(term); + return; } /* "Commit" search - copy selection to primary and cancel search */ else if (mods == 0 && sym == XKB_KEY_Return) { selection_finalize(term, term->input_serial); - search_cancel(term); + search_cancel_keep_selection(term); return; } diff --git a/terminal.h b/terminal.h index 18130392..755c7b4a 100644 --- a/terminal.h +++ b/terminal.h @@ -41,6 +41,7 @@ struct wayland { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; + struct wl_subcompositor *sub_compositor; struct wl_surface *surface; struct wl_shm *shm; struct wl_seat *seat;