diff options
-rw-r--r-- | src/wayland-server-core.h | 8 | ||||
-rw-r--r-- | src/wayland-server.c | 42 | ||||
-rw-r--r-- | tests/client-test.c | 24 |
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]); |