aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_xdg_shell.h4
-rw-r--r--types/xdg_shell/wlr_xdg_surface.c4
-rw-r--r--types/xdg_shell/wlr_xdg_toplevel.c31
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,