diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | src/wayland-client-core.h | 7 | ||||
-rw-r--r-- | src/wayland-client.c | 65 | ||||
-rw-r--r-- | tests/proxy-test.c | 136 |
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); +} |