From 9914784594713f184c58e37def1d136c6af394a9 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 14 Aug 2019 20:36:08 -0400 Subject: [PATCH] wlr_xdg_toplevel: reparent on parent unmap From the xdg-shell specification: If the parent is unmapped then its children are managed as though the parent of the now-unmapped parent has become the parent of this surface. If no parent exists for the now-unmapped parent then the children are managed as though they have no parent surface. --- include/wlr/types/wlr_xdg_shell.h | 4 +++- types/xdg_shell/wlr_xdg_surface.c | 4 ++++ types/xdg_shell/wlr_xdg_toplevel.c | 31 ++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index e8c12ae9..70572bf5 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -117,9 +117,11 @@ struct wlr_xdg_toplevel_state { struct wlr_xdg_toplevel { struct wl_resource *resource; struct wlr_xdg_surface *base; - struct wlr_xdg_surface *parent; bool added; + struct wlr_xdg_surface *parent; + struct wl_listener parent_unmap; + struct wlr_xdg_toplevel_state client_pending; struct wlr_xdg_toplevel_state server_pending; struct wlr_xdg_toplevel_state current; diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c index e3f13e0e..fcd3e0c9 100644 --- a/types/xdg_shell/wlr_xdg_surface.c +++ b/types/xdg_shell/wlr_xdg_surface.c @@ -41,6 +41,10 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) { switch (surface->role) { case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + if (surface->toplevel->parent) { + wl_list_remove(&surface->toplevel->parent_unmap.link); + surface->toplevel->parent = NULL; + } free(surface->toplevel->title); surface->toplevel->title = NULL; free(surface->toplevel->app_id); diff --git a/types/xdg_shell/wlr_xdg_toplevel.c b/types/xdg_shell/wlr_xdg_toplevel.c index 96bb0537..3524bd34 100644 --- a/types/xdg_shell/wlr_xdg_toplevel.c +++ b/types/xdg_shell/wlr_xdg_toplevel.c @@ -207,6 +207,34 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource( return wl_resource_get_user_data(resource); } +static void set_parent(struct wlr_xdg_surface *surface, + struct wlr_xdg_surface *parent); + +static void handle_parent_unmap(struct wl_listener *listener, void *data) { + struct wlr_xdg_toplevel *toplevel = + wl_container_of(listener, toplevel, parent_unmap); + set_parent(toplevel->base, toplevel->parent->toplevel->parent); +} + +static void set_parent(struct wlr_xdg_surface *surface, + struct wlr_xdg_surface *parent) { + assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + assert(!parent || parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + + if (surface->toplevel->parent) { + wl_list_remove(&surface->toplevel->parent_unmap.link); + } + + surface->toplevel->parent = parent; + if (surface->toplevel->parent) { + surface->toplevel->parent_unmap.notify = handle_parent_unmap; + wl_signal_add(&surface->toplevel->parent->events.unmap, + &surface->toplevel->parent_unmap); + } + + wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); +} + static void xdg_toplevel_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { struct wlr_xdg_surface *surface = @@ -217,8 +245,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client, parent = wlr_xdg_surface_from_toplevel_resource(parent_resource); } - surface->toplevel->parent = parent; - wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface); + set_parent(surface, parent); } static void xdg_toplevel_handle_set_title(struct wl_client *client,