From 71725a8eae6f8196d8e13a1b50af4f8ee4ebe971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlad=20P=C4=83n=C4=83zan?= Date: Sat, 5 Dec 2020 18:32:44 +0200 Subject: [PATCH] Add layer shell subsurfaces Damage subsurfaces created by layer surfaces on map, unmap and commit. This fixes the flicker of Gtk Popovers. Fixes #5617 --- include/sway/layers.h | 11 ++++++ sway/desktop/layer_shell.c | 80 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/sway/layers.h b/include/sway/layers.h index 025776f8e..457634c24 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -20,6 +20,7 @@ struct sway_layer_surface { struct wl_listener surface_commit; struct wl_listener output_destroy; struct wl_listener new_popup; + struct wl_listener new_subsurface; struct wlr_box geo; enum zwlr_layer_shell_v1_layer layer; @@ -39,6 +40,16 @@ struct sway_layer_popup { struct wl_listener new_popup; }; +struct sway_layer_subsurface { + struct wlr_subsurface *wlr_subsurface; + struct sway_layer_surface *layer_surface; + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener commit; +}; + struct sway_output; void arrange_layers(struct sway_output *output); diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 738b17979..d4ca4fb43 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -351,6 +351,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&sway_layer->unmap.link); wl_list_remove(&sway_layer->surface_commit.link); wl_list_remove(&sway_layer->new_popup.link); + wl_list_remove(&sway_layer->new_subsurface.link); if (sway_layer->layer_surface->output != NULL) { struct sway_output *output = sway_layer->layer_surface->output->data; if (output != NULL) { @@ -380,6 +381,82 @@ static void handle_unmap(struct wl_listener *listener, void *data) { unmap(sway_layer); } +static void subsurface_damage(struct sway_layer_subsurface *subsurface, + bool whole) { + struct sway_layer_surface *layer = subsurface->layer_surface; + struct wlr_output *wlr_output = layer->layer_surface->output; + if (!wlr_output) { + return; + } + struct sway_output *output = wlr_output->data; + int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; + int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; + output_damage_surface( + output, ox, oy, subsurface->wlr_subsurface->surface, whole); +} + +static void subsurface_handle_unmap(struct wl_listener *listener, void *data) { + struct sway_layer_subsurface *subsurface = + wl_container_of(listener, subsurface, unmap); + subsurface_damage(subsurface, true); +} + +static void subsurface_handle_map(struct wl_listener *listener, void *data) { + struct sway_layer_subsurface *subsurface = + wl_container_of(listener, subsurface, map); + subsurface_damage(subsurface, true); +} + +static void subsurface_handle_commit(struct wl_listener *listener, void *data) { + struct sway_layer_subsurface *subsurface = + wl_container_of(listener, subsurface, commit); + subsurface_damage(subsurface, false); +} + +static void subsurface_handle_destroy(struct wl_listener *listener, + void *data) { + struct sway_layer_subsurface *subsurface = + wl_container_of(listener, subsurface, destroy); + + wl_list_remove(&subsurface->map.link); + wl_list_remove(&subsurface->unmap.link); + wl_list_remove(&subsurface->destroy.link); + wl_list_remove(&subsurface->commit.link); + free(subsurface); +} + +static struct sway_layer_subsurface *create_subsurface( + struct wlr_subsurface *wlr_subsurface, + struct sway_layer_surface *layer_surface) { + struct sway_layer_subsurface *subsurface = + calloc(1, sizeof(struct sway_layer_surface)); + if (subsurface == NULL) { + return NULL; + } + + subsurface->wlr_subsurface = wlr_subsurface; + subsurface->layer_surface = layer_surface; + + subsurface->map.notify = subsurface_handle_map; + wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); + subsurface->unmap.notify = subsurface_handle_unmap; + wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); + subsurface->destroy.notify = subsurface_handle_destroy; + wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); + subsurface->commit.notify = subsurface_handle_commit; + wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit); + + return subsurface; +} + +static void handle_new_subsurface(struct wl_listener *listener, void *data) { + struct sway_layer_surface *sway_layer_surface = + wl_container_of(listener, sway_layer_surface, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + create_subsurface(wlr_subsurface, sway_layer_surface); +} + + static struct sway_layer_surface *popup_get_layer( struct sway_layer_popup *popup) { while (popup->parent_type == LAYER_PARENT_POPUP) { @@ -563,6 +640,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); sway_layer->new_popup.notify = handle_new_popup; wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); + sway_layer->new_subsurface.notify = handle_new_subsurface; + wl_signal_add(&layer_surface->surface->events.new_subsurface, + &sway_layer->new_subsurface); sway_layer->layer_surface = layer_surface; layer_surface->data = sway_layer;