[RFC PATCH wayland] wayland-server: Add API to control globals visibility
Olivier Fourdan
ofourdan at redhat.com
Wed Jul 6 13:45:00 UTC 2016
Add a new API to let compositor decide whether or not a wl_global
should be advertised to the clients via wl_registry_bind() or
display_get_registry()
By using its own filter, the compositor can decide which wl_global would
be listed to clients.
Compositors can use this mechanism to hide their own private interfaces
that regular clients should not use.
Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
---
src/wayland-server-core.h | 8 +++++++
src/wayland-server.c | 38 ++++++++++++++++++++++++++-----
tests/display-test.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index ad1292f..b02ebcd 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <stdint.h>
+#include <stdbool.h>
#include "wayland-util.h"
#include "wayland-version.h"
@@ -141,6 +142,9 @@ struct wl_client;
typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data,
uint32_t version, uint32_t id);
+typedef bool (*wl_display_filter_global_func_t)(const struct wl_client *client,
+ const struct wl_interface *interface);
+
uint32_t
wl_display_get_serial(struct wl_display *display);
@@ -155,6 +159,10 @@ struct wl_listener *
wl_display_get_destroy_listener(struct wl_display *display,
wl_notify_func_t notify);
+void
+wl_display_set_filter_global(struct wl_display *display,
+ wl_display_filter_global_func_t filter);
+
struct wl_global *
wl_global_create(struct wl_display *display,
const struct wl_interface *interface,
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 19aa2e8..55e532e 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -98,6 +98,7 @@ struct wl_display {
struct wl_signal destroy_signal;
struct wl_array additional_shm_formats;
+ wl_display_filter_global_func_t wl_display_global_filter;
};
struct wl_global {
@@ -740,7 +741,8 @@ registry_bind(struct wl_client *client,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"invalid version for global %s (%d): have %d, wanted %d",
interface, name, global->version, version);
- else
+ else if (display->wl_display_global_filter == NULL ||
+ display->wl_display_global_filter (client, global->interface))
global->bind(client, global->data, version, id);
}
@@ -795,11 +797,13 @@ display_get_registry(struct wl_client *client,
®istry_resource->link);
wl_list_for_each(global, &display->global_list, link)
- wl_resource_post_event(registry_resource,
- WL_REGISTRY_GLOBAL,
- global->name,
- global->interface->name,
- global->version);
+ if (display->wl_display_global_filter == NULL ||
+ display->wl_display_global_filter (client, global->interface))
+ wl_resource_post_event(registry_resource,
+ WL_REGISTRY_GLOBAL,
+ global->name,
+ global->interface->name,
+ global->version);
}
static const struct wl_display_interface display_interface = {
@@ -867,6 +871,7 @@ wl_display_create(void)
display->id = 1;
display->serial = 0;
+ display->wl_display_global_filter = NULL;
wl_array_init(&display->additional_shm_formats);
@@ -940,6 +945,27 @@ wl_display_destroy(struct wl_display *display)
free(display);
}
+/** Set-up a filter function for global objects
+ *
+ * \param display The Wayland display object.
+ * \param filter The global filter funtion.
+ * \return None.
+ *
+ * Setup a filter for the wl_display to advertise or hide global objects
+ * to clients.
+ * Using such a filter that will be called from wl_registry_bind()
+ * handler and display_get_registry(), the compositor can control which
+ * wl_global objects are advertised to any given client.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_set_filter_global(struct wl_display *display,
+ wl_display_filter_global_func_t filter)
+{
+ display->wl_display_global_filter = filter;
+}
+
WL_EXPORT struct wl_global *
wl_global_create(struct wl_display *display,
const struct wl_interface *interface, int version,
diff --git a/tests/display-test.c b/tests/display-test.c
index 17956db..1548c59 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -125,6 +125,7 @@ struct handler_info {
struct wl_seat *seat;
uint32_t bind_version;
bool use_unversioned;
+ bool has_data_offer;
};
static void
@@ -145,6 +146,8 @@ registry_handle_globals(void *data, struct wl_registry *registry,
hi->seat = wl_registry_bind(registry, id,
&wl_seat_interface, ver);
assert(hi->seat);
+ } else if (strcmp(intf, "wl_data_offer") == 0) {
+ hi->has_data_offer = true;
}
}
@@ -926,3 +929,57 @@ TEST(error_on_destroyed_object)
display_resume(d);
display_destroy(d);
}
+
+static bool
+display_global_filter(const struct wl_client *client,
+ const struct wl_interface *interface)
+{
+ /* Hide the wl_data_offer interface */
+ if (interface == &wl_data_offer_interface)
+ return false;
+
+ /* Show all the others */
+ return true;
+}
+
+static void
+bind_data_offer(struct wl_client *client, void *data,
+ uint32_t vers, uint32_t id)
+{
+ struct display *d = data;
+ struct client_info *ci;
+ struct wl_resource *res;
+
+ ci = find_client_info(d, client);
+ assert(ci);
+
+ res = wl_resource_create(client, &wl_data_offer_interface, vers, id);
+ assert(res);
+}
+
+TEST(filter)
+{
+ struct handler_info hi;
+ struct display *d;
+ struct wl_global *g1, *g2;
+
+ d = display_create();
+ wl_display_set_filter_global(d->wl_display, display_global_filter);
+
+ g1 = wl_global_create(d->wl_display, &wl_seat_interface,
+ 1, d, bind_seat);
+ g2 = wl_global_create(d->wl_display, &wl_data_offer_interface,
+ 1, d, bind_data_offer);
+
+ hi.has_data_offer = false;
+ client_create(d, seat_version, &hi);
+ assert(hi.seat != NULL);
+ assert(hi.has_data_offer != true);
+
+ display_run(d);
+
+ wl_global_destroy(g1);
+ wl_global_destroy(g2);
+
+ display_destroy(d);
+}
--
2.7.4
More information about the wayland-devel
mailing list