commit 97069f8

Michael Forney  ·  2018-11-09 05:38:59 +0000 UTC
parent 2011cc7
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).
1 files changed,  +13, -2
+13, -2
 1@@ -36,7 +36,7 @@
 2 struct xdg_surface {
 3 	struct wl_resource *resource, *role;
 4 	struct surface *surface;
 5-	struct wl_listener surface_destroy_listener;
 6+	struct wl_listener surface_destroy_listener, role_destroy_listener;
 7 	uint32_t configure_serial;
 8 };
 9 
10@@ -375,6 +375,7 @@ get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id
11 		return;
12 	}
13 	xdg_surface->role = toplevel->resource;
14+	wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener);
15 }
16 
17 static void
18@@ -416,13 +417,22 @@ handle_surface_destroy(struct wl_listener *listener, void *data)
19 	wl_resource_destroy(xdg_surface->resource);
20 }
21 
22+static void
23+handle_role_destroy(struct wl_listener *listener, void *data)
24+{
25+	struct xdg_surface *xdg_surface = wl_container_of(listener, xdg_surface, role_destroy_listener);
26+
27+	xdg_surface->role = NULL;
28+}
29+
30 static void
31 destroy_xdg_surface(struct wl_resource *resource)
32 {
33 	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
34 
35 	wl_list_remove(&xdg_surface->surface_destroy_listener.link);
36-	wl_resource_destroy(xdg_surface->role);
37+	if (xdg_surface->role)
38+		wl_resource_destroy(xdg_surface->role);
39 	free(xdg_surface);
40 }
41 
42@@ -439,6 +449,7 @@ xdg_surface_new(struct wl_client *client, uint32_t version, uint32_t id, struct
43 		goto error1;
44 	xdg_surface->surface = surface;
45 	xdg_surface->surface_destroy_listener.notify = &handle_surface_destroy;
46+	xdg_surface->role_destroy_listener.notify = &handle_role_destroy;
47 	wl_resource_add_destroy_listener(surface->resource, &xdg_surface->surface_destroy_listener);
48 	wl_resource_set_implementation(xdg_surface->resource, &xdg_surface_impl, xdg_surface, destroy_xdg_surface);
49