From ea97a0dc87f7d8f070de747f0e3adc35780c6cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 26 Feb 2020 12:22:16 +0100 Subject: [PATCH] wayland: instantiate sub-surfaces on-demand While most compositors handle instantiated but not-yet-mapped sub-surfaces correctly, e.g. kwin does not. For example, it will incorrectly offset the main surface both horizontally and vertically with a couple of pixels, leaving two transparent areas at the top and left, between the SSDs and the main surface. Note that a workaround is to position the sub-surfaces inside the main surface while they're unmapped. However, since the surfaces may be larger than the main surface (the CSDs, for examples, always are), this doesn't quite work since kwin, at least, resizes the window to include the sub-surfaces, even when unmapped. So, instead we instantiate all sub-surfaces on demand, when we know where to position them, and when they should be mapped. --- search.c | 23 ++++++++++++++-- wayland.c | 80 ++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/search.c b/search.c index a39c75a8..590c7577 100644 --- a/search.c +++ b/search.c @@ -40,8 +40,14 @@ search_ensure_size(struct terminal *term, size_t wanted_size) static void search_cancel_keep_selection(struct terminal *term) { - wl_surface_attach(term->window->search_surface, NULL, 0, 0); - wl_surface_commit(term->window->search_surface); + struct wl_window *win = term->window; + if (win->search_sub_surface != NULL) + wl_subsurface_destroy(win->search_sub_surface); + if (win->search_surface != NULL) + wl_surface_destroy(win->search_surface); + + win->search_surface = NULL; + win->search_sub_surface = NULL; free(term->search.buf); term->search.buf = NULL; @@ -65,6 +71,19 @@ search_begin(struct terminal *term) search_cancel_keep_selection(term); selection_cancel(term); + /* On-demand instantiate wayland surface */ + struct wl_window *win = term->window; + struct wayland *wayl = term->wl; + win->search_surface = wl_compositor_create_surface(wayl->compositor); + win->search_sub_surface = wl_subcompositor_get_subsurface( + wayl->sub_compositor, win->search_surface, win->surface); + wl_subsurface_set_desync(win->search_sub_surface); + + struct wl_region *region = wl_compositor_create_region(term->wl->compositor); + wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_set_opaque_region(win->search_surface, region); + wl_region_destroy(region); + term->search.original_view = term->grid->view; term->search.view_followed_offset = term->grid->view == term->grid->offset; term->is_searching = true; diff --git a/wayland.c b/wayland.c index 140c3de9..a9bfa8c8 100644 --- a/wayland.c +++ b/wayland.c @@ -29,6 +29,7 @@ #include "render.h" #include "selection.h" +#define ALEN(v) (sizeof(v) / sizeof(v[0])) #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -541,6 +542,39 @@ static const struct xdg_surface_listener xdg_surface_listener = { .configure = &xdg_surface_configure, }; +static void +csd_instantiate(struct wl_window *win) +{ + struct wayland *wayl = win->term->wl; + assert(wayl != NULL); + + for (size_t i = 0; i < ALEN(win->csd.surface); i++) { + assert(win->csd.surface[i] == NULL); + assert(win->csd.sub_surface[i] == NULL); + + win->csd.surface[i] = wl_compositor_create_surface(wayl->compositor); + win->csd.sub_surface[i] = wl_subcompositor_get_subsurface( + wayl->sub_compositor, win->csd.surface[i], win->surface); + + wl_subsurface_set_sync(win->csd.sub_surface[i]); + wl_surface_commit(win->csd.surface[i]); + } +} + +static void +csd_destroy(struct wl_window *win) +{ + for (size_t i = 0; i < ALEN(win->csd.surface); i++) { + if (win->csd.sub_surface[i] != NULL) + wl_subsurface_destroy(win->csd.sub_surface[i]); + if (win->csd.surface[i] != NULL) + wl_surface_destroy(win->csd.surface[i]); + + win->csd.surface[i] = NULL; + win->csd.sub_surface[i] = NULL; + } +} + static void xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, @@ -552,11 +586,13 @@ xdg_toplevel_decoration_configure(void *data, case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: LOG_DBG("using client-side decorations"); win->use_csd = CSD_YES; + csd_instantiate(win); break; case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: LOG_DBG("using server-side decorations"); win->use_csd = CSD_NO; + csd_destroy(win); break; default: @@ -941,26 +977,12 @@ wayl_win_init(struct terminal *term) #endif zxdg_toplevel_decoration_v1_add_listener( win->xdg_toplevel_decoration, &xdg_toplevel_decoration_listener, win); + } else { + /* No decoration manager - thus we *must* draw our own decorations */ + win->use_csd = CSD_YES; + csd_instantiate(win); } - for (size_t i = 0; i < 5; i++) { - win->csd.surface[i] = wl_compositor_create_surface(wayl->compositor); - win->csd.sub_surface[i] = wl_subcompositor_get_subsurface( - wayl->sub_compositor, win->csd.surface[i], win->surface); - wl_subsurface_set_sync(win->csd.sub_surface[i]); - } - - /* Scrollback search box */ - win->search_surface = wl_compositor_create_surface(wayl->compositor); - win->search_sub_surface = wl_subcompositor_get_subsurface( - wayl->sub_compositor, win->search_surface, win->surface); - wl_subsurface_set_desync(win->search_sub_surface); - - struct wl_region *region = wl_compositor_create_region(term->wl->compositor); - wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); - wl_surface_set_opaque_region(win->search_surface, region); - wl_region_destroy(region); - wl_surface_commit(win->surface); return win; @@ -986,13 +1008,17 @@ wayl_win_destroy(struct wl_window *win) */ /* Scrollback search */ - wl_surface_attach(win->search_surface, NULL, 0, 0); - wl_surface_commit(win->search_surface); + if (win->search_surface != NULL) { + wl_surface_attach(win->search_surface, NULL, 0, 0); + wl_surface_commit(win->search_surface); + } /* CSD */ - for (size_t i = 0; i < 5; i++) { - wl_surface_attach(win->csd.surface[i], NULL, 0, 0); - wl_surface_commit(win->csd.surface[i]); + for (size_t i = 0; i < ALEN(win->csd.surface); i++) { + if (win->csd.surface[i] != NULL) { + wl_surface_attach(win->csd.surface[i], NULL, 0, 0); + wl_surface_commit(win->csd.surface[i]); + } } wayl_roundtrip(win->term->wl); @@ -1004,13 +1030,7 @@ wayl_win_destroy(struct wl_window *win) tll_free(win->on_outputs); - for (size_t i = 0; i < 5; i++) { - if (win->csd.sub_surface[i] != NULL) - wl_subsurface_destroy(win->csd.sub_surface[i]); - if (win->csd.surface[i] != NULL) - wl_surface_destroy(win->csd.surface[i]); - } - + csd_destroy(win); if (win->search_sub_surface != NULL) wl_subsurface_destroy(win->search_sub_surface); if (win->search_surface != NULL)