[PATCH v2] wayland-server: Add API to control globals visibility
Olivier Fourdan
ofourdan at redhat.com
Mon Aug 1 13:22:59 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>
---
v2: Follow-up on Jonas' comments on v1:
Add global's data as user data in callback filter function
Pass wl_global instead of wl_interface in callback filter function
Add wl_global_get_interface() to retrieve the wl_interface from the
given wl_global
Post an error if a client tries to bind a global which is filtered
out.
Note: Hey Jonas, I am not quite sure what you meant by "Probably want a
void *user_data here", did you mean to pass the wl_global's data
or add a new void * alltogether? I took it you meant the former.
src/wayland-server-core.h | 12 ++++++++++
src/wayland-server.c | 54 +++++++++++++++++++++++++++++++++++++++----
tests/display-test.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 119 insertions(+), 5 deletions(-)
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index ad1292f..6ccceb8 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"
@@ -164,6 +165,17 @@ wl_global_create(struct wl_display *display,
void
wl_global_destroy(struct wl_global *global);
+typedef bool (*wl_display_filter_global_func_t)(const struct wl_client *client,
+ const struct wl_global *global,
+ void *data);
+
+void
+wl_display_set_filter_global(struct wl_display *display,
+ wl_display_filter_global_func_t filter);
+
+const struct wl_interface *
+wl_global_get_interface(const struct wl_global *global);
+
struct wl_client *
wl_client_create(struct wl_display *display, int fd);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 19aa2e8..032e5e0 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 {
@@ -714,6 +715,16 @@ wl_client_destroy(struct wl_client *client)
free(client);
}
+static bool
+filter_global(const struct wl_client *client,
+ const struct wl_global *global)
+{
+ struct wl_display *display = client->display;
+
+ return display->wl_display_global_filter == NULL ||
+ display->wl_display_global_filter(client, global, global->data);
+}
+
static void
registry_bind(struct wl_client *client,
struct wl_resource *resource, uint32_t name,
@@ -740,6 +751,10 @@ 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 if (!filter_global(client, global))
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid global %s (%d)", interface, name);
else
global->bind(client, global->data, version, id);
}
@@ -795,11 +810,12 @@ 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 (filter_global(client, global))
+ 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 +883,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 +957,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,
@@ -997,6 +1035,12 @@ wl_global_destroy(struct wl_global *global)
free(global);
}
+WL_EXPORT const struct wl_interface *
+wl_global_get_interface(const struct wl_global *global)
+{
+ return global->interface;
+}
+
/** Get the current serial number
*
* \param display The display object
diff --git a/tests/display-test.c b/tests/display-test.c
index 17956db..5230913 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,58 @@ TEST(error_on_destroyed_object)
display_resume(d);
display_destroy(d);
}
+
+static bool
+display_global_filter(const struct wl_client *client,
+ const struct wl_global *global,
+ void *data)
+{
+ /* Hide the wl_data_offer interface */
+ if (wl_global_get_interface(global) == &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