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,