You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.7 KiB

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lloyd Pique <lpique@google.com>
Date: Fri, 29 Jan 2021 15:01:46 -0800
Subject: [PATCH 3/3] client+server: Safe casts from wl_object *
This allows client or server code to safely convert an opaque pointer to a
wl_object, which has no accessors, into an opaque pointer to either wl_proxy
(client) or wl_resource (server), which does have some useful accessors.
This is helpful in implementing callbacks that are given a raw "union
wl_argument *" array, and that want to inspect the ".o" field beyond getting
the raw pointer value.
Right now the callback would have to assume that the "wl_resource *" or
"wl_proxy *" could be constructed by a simple cast from the "wl_object *" value,
as the wl_object is the first thing in both structures.
With these two conversion functions, clients and servers could be cleaned up to
no longer make that assumption, and maybe some day the core code could do
make a change that would break that assumption.
Signed-off-by: Lloyd Pique <lpique@google.com>
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index 547ae04..94c25e3 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -204,6 +204,9 @@ wl_proxy_get_class(struct wl_proxy *proxy);
void
wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);
+struct wl_proxy *
+wl_proxy_from_object(struct wl_object *object);
+
struct wl_display *
wl_display_connect(const char *name);
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 7f5a651..74d4861 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -2307,6 +2307,28 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
free(wrapper);
}
+/** Safely converts an object into its corresponding proxy
+ *
+ * \param object The object to convert
+ * \return A corresponding proxy, or NULL on failure
+ *
+ * Safely converts an object into its corresponding proxy.
+ *
+ * This is useful for implementing functions that are given a \c wl_argument
+ * array, and that need to do further introspection on the ".o" field, as it
+ * is otherwise an opaque type.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_from_object(struct wl_object *object)
+{
+ struct wl_proxy *proxy;
+ if (object == NULL)
+ return NULL;
+ return wl_container_of(object, proxy, object);
+}
+
WL_EXPORT void
wl_log_set_handler_client(wl_log_func_t handler)
{
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index 64d7169..e5f4e43 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -587,6 +587,9 @@ struct wl_listener *
wl_resource_get_destroy_listener(struct wl_resource *resource,
wl_notify_func_t notify);
+struct wl_resource *
+wl_resource_from_object(struct wl_object *object);
+
#define wl_resource_for_each(resource, list) \
for (resource = 0, resource = wl_resource_from_link((list)->next); \
wl_resource_get_link(resource) != (list); \
diff --git a/src/wayland-server.c b/src/wayland-server.c
index d83bdec..ca0d98d 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -858,6 +858,28 @@ wl_resource_get_class(struct wl_resource *resource)
return resource->object.interface->name;
}
+/** Safely converts an object into its corresponding resource
+ *
+ * \param object The object to convert
+ * \return A corresponding resource, or NULL on failure
+ *
+ * Safely converts an object into its corresponding resource.
+ *
+ * This is useful for implementing functions that are given a \c wl_argument
+ * array, and that need to do further introspection on the ".o" field, as it
+ * is otherwise an opaque type.
+ *
+ * \memberof wl_resource
+ */
+WL_EXPORT struct wl_resource *
+wl_resource_from_object(struct wl_object *object)
+{
+ struct wl_resource *resource;
+ if (object == NULL)
+ return NULL;
+ return wl_container_of(object, resource, object);
+}
+
WL_EXPORT void
wl_client_add_destroy_listener(struct wl_client *client,
struct wl_listener *listener)
diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c
index d0bca41..b66e761 100644
--- a/tests/protocol-logger-test.c
+++ b/tests/protocol-logger-test.c
@@ -225,10 +225,10 @@ client_log_to_stderr_demo(void *user_data,
break;
case 'o':
if (args[i].o) {
- // Note: server logger should instead cast to
- // wl_resource, and use wl_resource_get_class
- // and wl_resource_get_id.
- arg_proxy = (struct wl_proxy *)(args[i].o);
+ // Note: server logger should instead use
+ // wl_resource_from_object, and then
+ // wl_resource_get_class and wl_resource_get_id.
+ arg_proxy = wl_proxy_from_object(args[i].o);
arg_class = wl_proxy_get_class(arg_proxy);
fprintf(stderr, "%s@%u",