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.
This commit is contained in:
Daniel Eklöf 2020-02-26 12:22:16 +01:00
parent f960e7aff7
commit ea97a0dc87
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 71 additions and 32 deletions

View file

@ -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;

View file

@ -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)