commit 97069f84283298fd546b7300d7dc78989553f14a
parent 2011cc741cc12b50f6d85529a898b378ae78bd8d
Author: Michael Forney <mforney@mforney.org>
Date: Thu, 8 Nov 2018 21:38:59 -0800
xdg-shell: Handle role destruction in xdg_surface properly
xdg_surface should clear its `role` field upon destruction of its
role. Then, in its destructor, it can destroy the role only if it
has not already been destroyed.
This fixes a double-destruction of xdg_toplevel if it is destroyed
explicitly before the xdg_surface (as the spec requires).
Diffstat:
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/libswc/xdg_shell.c b/libswc/xdg_shell.c
@@ -36,7 +36,7 @@
struct xdg_surface {
struct wl_resource *resource, *role;
struct surface *surface;
- struct wl_listener surface_destroy_listener;
+ struct wl_listener surface_destroy_listener, role_destroy_listener;
uint32_t configure_serial;
};
@@ -375,6 +375,7 @@ get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id
return;
}
xdg_surface->role = toplevel->resource;
+ wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener);
}
static void
@@ -417,12 +418,21 @@ handle_surface_destroy(struct wl_listener *listener, void *data)
}
static void
+handle_role_destroy(struct wl_listener *listener, void *data)
+{
+ struct xdg_surface *xdg_surface = wl_container_of(listener, xdg_surface, role_destroy_listener);
+
+ xdg_surface->role = NULL;
+}
+
+static void
destroy_xdg_surface(struct wl_resource *resource)
{
struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
wl_list_remove(&xdg_surface->surface_destroy_listener.link);
- wl_resource_destroy(xdg_surface->role);
+ if (xdg_surface->role)
+ wl_resource_destroy(xdg_surface->role);
free(xdg_surface);
}
@@ -439,6 +449,7 @@ xdg_surface_new(struct wl_client *client, uint32_t version, uint32_t id, struct
goto error1;
xdg_surface->surface = surface;
xdg_surface->surface_destroy_listener.notify = &handle_surface_destroy;
+ xdg_surface->role_destroy_listener.notify = &handle_role_destroy;
wl_resource_add_destroy_listener(surface->resource, &xdg_surface->surface_destroy_listener);
wl_resource_set_implementation(xdg_surface->resource, &xdg_surface_impl, xdg_surface, destroy_xdg_surface);