summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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]);