summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--src/wayland-client-core.h7
-rw-r--r--src/wayland-client.c65
-rw-r--r--tests/proxy-test.c136
4 files changed, 211 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index a0b11d5..868910c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -174,6 +174,7 @@ built_test_programs = \
sanity-test \
socket-test \
queue-test \
+ proxy-test \
signal-test \
newsignal-test \
resources-test \
@@ -258,6 +259,8 @@ socket_test_SOURCES = tests/socket-test.c
socket_test_LDADD = libtest-runner.la
queue_test_SOURCES = tests/queue-test.c
queue_test_LDADD = libtest-runner.la
+proxy_test_SOURCES = tests/proxy-test.c
+proxy_test_LDADD = libtest-runner.la
signal_test_SOURCES = tests/signal-test.c
signal_test_LDADD = libtest-runner.la
# wayland-server.c is needed here to access wl_priv_* functions
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index 03e781b..0cd96e0 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -191,6 +191,13 @@ wl_proxy_get_version(struct wl_proxy *proxy);
uint32_t
wl_proxy_get_id(struct wl_proxy *proxy);
+void
+wl_proxy_set_tag(struct wl_proxy *proxy,
+ const char * const *tag);
+
+const char * const *
+wl_proxy_get_tag(struct wl_proxy *proxy);
+
const char *
wl_proxy_get_class(struct wl_proxy *proxy);
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 38756f1..0821af1 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -69,6 +69,7 @@ struct wl_proxy {
void *user_data;
wl_dispatcher_func_t dispatcher;
uint32_t version;
+ const char * const *tag;
};
struct wl_event_queue {
@@ -2059,6 +2060,70 @@ wl_proxy_get_id(struct wl_proxy *proxy)
return proxy->object.id;
}
+/** Set the tag of a proxy object
+ *
+ * A toolkit or application can set a unique tag on a proxy in order to
+ * identify whether an object is managed by itself or some external part.
+ *
+ * To create a tag, the recommended way is to define a statically allocated
+ * constant char array containing some descriptive string. The tag will be the
+ * pointer to the non-const pointer to the beginning of the array.
+ *
+ * For example, to define and set a tag on a surface managed by a certain
+ * subsystem:
+ *
+ * static const char *my_tag = "my tag";
+ *
+ * wl_proxy_set_tag((struct wl_proxy *) surface, &my_tag);
+ *
+ * Then, in a callback with wl_surface as an argument, in order to check
+ * whether it's a surface managed by the same subsystem.
+ *
+ * const char * const *tag;
+ *
+ * tag = wl_proxy_get_tag((struct wl_proxy *) surface);
+ * if (tag != &my_tag)
+ * return;
+ *
+ * ...
+ *
+ * For debugging purposes, a tag should be suitable to be included in a debug
+ * log entry, e.g.
+ *
+ * const char * const *tag;
+ *
+ * tag = wl_proxy_get_tag((struct wl_proxy *) surface);
+ * printf("Got a surface with the tag %p (%s)\n",
+ * tag, (tag && *tag) ? *tag : "");
+ *
+ * \param proxy The proxy object
+ * \param tag The tag
+ *
+ * \memberof wl_proxy
+ * \since 1.17.90
+ */
+WL_EXPORT void
+wl_proxy_set_tag(struct wl_proxy *proxy,
+ const char * const *tag)
+{
+ proxy->tag = tag;
+}
+
+/** Get the tag of a proxy object
+ *
+ * See wl_proxy_set_tag for details.
+ *
+ * \param proxy The proxy object
+ *
+ * \memberof wl_proxy
+ * \since 1.17.90
+ */
+WL_EXPORT const char * const *
+wl_proxy_get_tag(struct wl_proxy *proxy)
+{
+ return proxy->tag;
+}
+
/** Get the interface name (class) of a proxy object
*
* \param proxy The proxy object
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
new file mode 100644
index 0000000..d91a73d
--- /dev/null
+++ b/tests/proxy-test.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "wayland-server.h"
+#include "wayland-client.h"
+#include "test-runner.h"
+
+static struct {
+ struct wl_display *display;
+ struct wl_event_loop *loop;
+ int sync_count;
+} server;
+
+static struct {
+ struct wl_display *display;
+ struct wl_callback *callback_a;
+ struct wl_callback *callback_b;
+ int callback_count;
+} client;
+
+static const char *tag_a = "tag";
+static const char *tag_b = "tag";
+
+static void
+callback_done(void *data, struct wl_callback *cb, uint32_t time)
+{
+ const char * const *expected_tag;
+ const char * const *tag;
+
+ if (cb == client.callback_a)
+ expected_tag = &tag_a;
+ else if (cb == client.callback_b)
+ expected_tag = &tag_b;
+ else
+ assert(!"unexpected callback");
+
+ tag = wl_proxy_get_tag((struct wl_proxy *) cb);
+
+ assert(tag == expected_tag);
+ assert(strcmp(*tag, "tag") == 0);
+
+ wl_callback_destroy(cb);
+
+ client.callback_count++;
+}
+
+static const struct wl_callback_listener callback_listener = {
+ callback_done,
+};
+
+static void
+logger_func(void *user_data,
+ enum wl_protocol_logger_type type,
+ const struct wl_protocol_logger_message *message)
+{
+ if (type != WL_PROTOCOL_LOGGER_REQUEST)
+ return;
+
+ assert(strcmp(wl_resource_get_class(message->resource),
+ "wl_display") == 0);
+ assert(strcmp(message->message->name, "sync") == 0);
+
+ server.sync_count++;
+}
+
+TEST(proxy_tag)
+{
+ const char *socket;
+ struct wl_protocol_logger *logger;
+
+ assert(&tag_a != &tag_b);
+
+ server.display = wl_display_create();
+ assert(server.display);
+ server.loop = wl_display_get_event_loop(server.display);
+ assert(server.loop);
+ socket = wl_display_add_socket_auto(server.display);
+ assert(socket);
+ logger = wl_display_add_protocol_logger(server.display,
+ logger_func, NULL);
+ assert(logger);
+
+ client.display = wl_display_connect(socket);
+ assert(client.display);
+
+ client.callback_a = wl_display_sync(client.display);
+ wl_callback_add_listener(client.callback_a, &callback_listener, NULL);
+ wl_proxy_set_tag((struct wl_proxy *) client.callback_a,
+ &tag_a);
+
+ client.callback_b = wl_display_sync(client.display);
+ wl_callback_add_listener(client.callback_b, &callback_listener, NULL);
+ wl_proxy_set_tag((struct wl_proxy *) client.callback_b,
+ &tag_b);
+
+ wl_display_flush(client.display);
+
+ while (server.sync_count < 2) {
+ wl_event_loop_dispatch(server.loop, -1);
+ wl_display_flush_clients(server.display);
+ }
+
+ wl_display_dispatch(client.display);
+
+ assert(client.callback_count == 2);
+
+ wl_display_disconnect(client.display);
+ wl_event_loop_dispatch(server.loop, 100);
+
+ wl_display_destroy(server.display);
+}