summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2022-07-21 11:07:04 +0100
committerDaniel Stone <daniels@collabora.com>2022-10-20 11:26:22 +0000
commit51d788de5b5b3443fa1ca71115d16a53281c5ed9 (patch)
tree8ff51dd8452cbc0d33745bf8c71739c0492eade7
parente886b456aba8b502e599b555b27b09e889bc3eb5 (diff)
downloadwayland-51d788de5b5b3443fa1ca71115d16a53281c5ed9.tar.gz
wayland-server: Add wl_client_add_destroy_late_listener
A late-destroy listener for a client is called after all the client's resources have been destroyed and the destroy callbacks emitted. This lives in parallel to the existing client destroy listener, called immediately before the client's objects get destroyed. Signed-off-by: Daniel Stone <daniels@collabora.com> Fixes: wayland/wayland#207
-rw-r--r--src/wayland-server-core.h8
-rw-r--r--src/wayland-server.c42
-rw-r--r--tests/client-test.c24
3 files changed, 74 insertions, 0 deletions
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index 7a1375f..d9917a0 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -330,6 +330,14 @@ struct wl_listener *
wl_client_get_destroy_listener(struct wl_client *client,
wl_notify_func_t notify);
+void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+ struct wl_listener *listener);
+
+struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+ wl_notify_func_t notify);
+
struct wl_resource *
wl_client_get_object(struct wl_client *client, uint32_t id);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 617d637..ee53f76 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -79,6 +79,7 @@ struct wl_client {
struct wl_list link;
struct wl_map objects;
struct wl_priv_signal destroy_signal;
+ struct wl_priv_signal destroy_late_signal;
pid_t pid;
uid_t uid;
gid_t gid;
@@ -547,6 +548,7 @@ wl_client_create(struct wl_display *display, int fd)
goto err_map;
wl_priv_signal_init(&client->destroy_signal);
+ wl_priv_signal_init(&client->destroy_late_signal);
if (bind_display(client, display) < 0)
goto err_map;
@@ -864,6 +866,17 @@ wl_resource_get_class(struct wl_resource *resource)
return resource->object.interface->name;
}
+/**
+ * Add a listener to be called at the beginning of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy has begun,
+ * before any of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ */
WL_EXPORT void
wl_client_add_destroy_listener(struct wl_client *client,
struct wl_listener *listener)
@@ -878,6 +891,32 @@ wl_client_get_destroy_listener(struct wl_client *client,
return wl_priv_signal_get(&client->destroy_signal, notify);
}
+/**
+ * Add a listener to be called at the end of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy is nearly
+ * complete, after all of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ * \since 1.22.0
+ */
+WL_EXPORT void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+ struct wl_listener *listener)
+{
+ wl_priv_signal_add(&client->destroy_late_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+ wl_notify_func_t notify)
+{
+ return wl_priv_signal_get(&client->destroy_late_signal, notify);
+}
+
WL_EXPORT void
wl_client_destroy(struct wl_client *client)
{
@@ -890,6 +929,9 @@ wl_client_destroy(struct wl_client *client)
wl_map_release(&client->objects);
wl_event_source_remove(client->source);
close(wl_connection_destroy(client->connection));
+
+ wl_priv_signal_final_emit(&client->destroy_late_signal, client);
+
wl_list_remove(&client->link);
wl_list_remove(&client->resource_created_signal.listener_list);
free(client);
diff --git a/tests/client-test.c b/tests/client-test.c
index d75e009..01ebc4e 100644
--- a/tests/client-test.c
+++ b/tests/client-test.c
@@ -41,6 +41,8 @@
struct client_destroy_listener {
struct wl_listener listener;
bool done;
+ struct wl_listener late_listener;
+ bool late_done;
};
static void
@@ -49,9 +51,20 @@ client_destroy_notify(struct wl_listener *l, void *data)
struct client_destroy_listener *listener =
wl_container_of(l, listener, listener);
+ assert(!listener->late_done);
listener->done = true;
}
+static void
+client_late_destroy_notify(struct wl_listener *l, void *data)
+{
+ struct client_destroy_listener *listener =
+ wl_container_of(l, listener, late_listener);
+
+ assert(listener->done);
+ listener->late_done = true;
+}
+
TEST(client_destroy_listener)
{
struct wl_display *display;
@@ -67,21 +80,32 @@ TEST(client_destroy_listener)
a.listener.notify = client_destroy_notify;
a.done = false;
+ a.late_listener.notify = client_late_destroy_notify;
+ a.late_done = false;
wl_client_add_destroy_listener(client, &a.listener);
+ wl_client_add_destroy_late_listener(client, &a.late_listener);
assert(wl_client_get_destroy_listener(client, client_destroy_notify) ==
&a.listener);
+ assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) ==
+ &a.late_listener);
b.listener.notify = client_destroy_notify;
b.done = false;
+ b.late_listener.notify = client_late_destroy_notify;
+ b.late_done = false;
wl_client_add_destroy_listener(client, &b.listener);
+ wl_client_add_destroy_late_listener(client, &b.late_listener);
wl_list_remove(&a.listener.link);
+ wl_list_remove(&a.late_listener.link);
wl_client_destroy(client);
assert(!a.done);
+ assert(!a.late_done);
assert(b.done);
+ assert(b.late_done);
close(s[0]);
close(s[1]);