summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Wick <sebastian@sebastianwick.net>2021-10-25 04:34:49 +0200
committerDaniel Stone <daniels@collabora.com>2024-02-15 10:53:21 +0000
commit9c4213ed3eb3942766712df936775d827b846d0b (patch)
tree8e78708e916547e5dbaa247386e6d0b7f959ad5c
parent6a7284c63234c465a194b23ad28d527fa997bbcc (diff)
server: add wl_client_get_user_data/wl_client_set_user_data
The only way to attach some data to a wl_client seems to be setting up a destroy listener and use wl_container_of. Let's make it straight forward to attach some data. Having an explicit destroy callback for the user data makes managing the user data lifetime much more convenient. All other callbacks, be they wl_resource request listeners, destroy listeners or destructors, or wl_client destroy listeners, can assume that the wl_client user data still exists if it was set. Otherwise making that guarantee would be complicated. Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com> Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
-rw-r--r--src/wayland-server-core.h10
-rw-r--r--src/wayland-server.c46
-rw-r--r--tests/client-test.c15
3 files changed, 71 insertions, 0 deletions
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index df95821..00a5443 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -365,6 +365,16 @@ wl_client_for_each_resource(struct wl_client *client,
wl_client_for_each_resource_iterator_func_t iterator,
void *user_data);
+typedef void (*wl_user_data_destroy_func_t)(void *data);
+
+void
+wl_client_set_user_data(struct wl_client *client,
+ void *data,
+ wl_user_data_destroy_func_t dtor);
+
+void *
+wl_client_get_user_data(struct wl_client *client);
+
/** \class wl_listener
*
* \brief A single listener for Wayland signals
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 9fd1227..1e079a3 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -85,6 +85,8 @@ struct wl_client {
gid_t gid;
bool error;
struct wl_priv_signal resource_created_signal;
+ void *data;
+ wl_user_data_destroy_func_t data_dtor;
};
struct wl_display {
@@ -943,6 +945,10 @@ wl_client_destroy(struct wl_client *client)
wl_list_remove(&client->link);
wl_list_remove(&client->resource_created_signal.listener_list);
+
+ if (client->data_dtor)
+ client->data_dtor(client->data);
+
free(client);
}
@@ -2469,6 +2475,46 @@ wl_client_new_object(struct wl_client *client,
return resource;
}
+/** Set the client's user data
+ *
+ * User data is whatever the caller wants to store. Use dtor if
+ * the user data needs freeing as the very last step of destroying
+ * the client.
+ *
+ * \param client The client object
+ * \param data The user data pointer
+ * \param dtor Destroy function to be called after all resources have been
+ * destroyed and all destroy listeners have been called. Can be NULL.
+ *
+ * The argument to the destroy function is the user data pointer. If the
+ * destroy function is not NULL, it will be called even if user data is NULL.
+ *
+ * \since 1.22.90
+ * \sa wl_client_get_user_data
+ */
+WL_EXPORT void
+wl_client_set_user_data(struct wl_client *client,
+ void *data,
+ wl_user_data_destroy_func_t dtor)
+{
+ client->data = data;
+ client->data_dtor = dtor;
+}
+
+/** Get the client's user data
+ *
+ * \param client The client object
+ * \return The user data pointer
+ *
+ * \since 1.22.90
+ * \sa wl_client_set_user_data
+ */
+WL_EXPORT void *
+wl_client_get_user_data(struct wl_client *client)
+{
+ return client->data;
+}
+
struct wl_global *
wl_display_add_global(struct wl_display *display,
const struct wl_interface *interface,
diff --git a/tests/client-test.c b/tests/client-test.c
index 47be83f..659bac1 100644
--- a/tests/client-test.c
+++ b/tests/client-test.c
@@ -80,12 +80,21 @@ client_late_destroy_notify(struct wl_listener *l, void *data)
listener->late_done = true;
}
+static void
+client_user_data_destroy(void *data)
+{
+ bool *user_data_destroyed = data;
+
+ *user_data_destroyed = true;
+}
+
TEST(client_destroy_listener)
{
struct wl_display *display;
struct wl_client *client;
struct wl_resource *resource;
struct client_destroy_listener a, b;
+ bool user_data_destroyed = false;
int s[2];
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
@@ -94,6 +103,9 @@ TEST(client_destroy_listener)
client = wl_client_create(display, s[0]);
assert(client);
+ wl_client_set_user_data(client, &user_data_destroyed, client_user_data_destroy);
+ assert(wl_client_get_user_data(client) == &user_data_destroyed);
+
resource = wl_resource_create(client, &wl_callback_interface, 1, 0);
assert(resource);
@@ -128,6 +140,8 @@ TEST(client_destroy_listener)
wl_list_remove(&a.resource_listener.link);
wl_list_remove(&a.late_listener.link);
+ assert(!user_data_destroyed);
+
wl_client_destroy(client);
assert(!a.done);
@@ -136,6 +150,7 @@ TEST(client_destroy_listener)
assert(b.done);
assert(b.resource_done);
assert(b.late_done);
+ assert(user_data_destroyed);
close(s[0]);
close(s[1]);