mirror of
https://github.com/brl/mutter.git
synced 2025-06-26 06:57:06 +00:00
wayland: Add wl_global filter manager
One can add a wl_global filter to a wl_display instance, which can be used to decide what clients should see what globals. This has so far been used to limit a Xwayland specific protocol extension to only Xwayland. In order to expand the logic about what globals are filtered to what clients, introduce a filter manager and port the Xwayland specific protocol filter to this new manager. Tests are added, using a new dummy protocol, to ensure that filtering is working as expected. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2810>
This commit is contained in:
@ -408,6 +408,9 @@ if have_native_tests
|
||||
'suite': 'wayland',
|
||||
'sources': [
|
||||
'wayland-unit-tests.c',
|
||||
dummy_client_header,
|
||||
dummy_server_header,
|
||||
dummy_protocol_code,
|
||||
wayland_test_utils,
|
||||
],
|
||||
},
|
||||
|
9
src/tests/protocol/dummy.xml
Normal file
9
src/tests/protocol/dummy.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="dummy">
|
||||
<description summary=""/>
|
||||
<interface name="dummy" version="1">
|
||||
<description summary=""/>
|
||||
<request name="destroy" type="destructor"/>
|
||||
<event name="event"/>
|
||||
</interface>
|
||||
</protocol>
|
@ -30,3 +30,36 @@ test_driver_protocol_code = custom_target(
|
||||
'@INPUT@', '@OUTPUT@',
|
||||
]
|
||||
)
|
||||
|
||||
dummy_server_header = custom_target(
|
||||
'dummy server header',
|
||||
input: 'dummy.xml',
|
||||
output: 'dummy-server-protocol.h',
|
||||
command: [
|
||||
wayland_scanner,
|
||||
'server-header',
|
||||
'@INPUT@', '@OUTPUT@',
|
||||
]
|
||||
)
|
||||
|
||||
dummy_client_header = custom_target(
|
||||
'dummy client header',
|
||||
input: 'dummy.xml',
|
||||
output: 'dummy-client-protocol.h',
|
||||
command: [
|
||||
wayland_scanner,
|
||||
'client-header',
|
||||
'@INPUT@', '@OUTPUT@',
|
||||
]
|
||||
)
|
||||
|
||||
dummy_protocol_code = custom_target(
|
||||
'dummy protocol code',
|
||||
input: 'dummy.xml',
|
||||
output: 'dummy-protocol.c',
|
||||
command: [
|
||||
wayland_scanner,
|
||||
'private-code',
|
||||
'@INPUT@', '@OUTPUT@',
|
||||
]
|
||||
)
|
||||
|
@ -29,8 +29,13 @@
|
||||
#include "tests/meta-test-utils.h"
|
||||
#include "tests/meta-wayland-test-driver.h"
|
||||
#include "tests/meta-wayland-test-utils.h"
|
||||
#include "wayland/meta-wayland-client-private.h"
|
||||
#include "wayland/meta-wayland-filter-manager.h"
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
#include "dummy-client-protocol.h"
|
||||
#include "dummy-server-protocol.h"
|
||||
|
||||
static MetaContext *test_context;
|
||||
static MetaWaylandTestDriver *test_driver;
|
||||
static MetaVirtualMonitor *virtual_monitor;
|
||||
@ -677,6 +682,176 @@ xdg_foreign_set_parent_of (void)
|
||||
meta_wayland_test_client_finish (wayland_test_client);
|
||||
}
|
||||
|
||||
static MetaWaylandAccess
|
||||
dummy_global_filter (const struct wl_client *client,
|
||||
const struct wl_global *global,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaWaylandClient *allowed_client = META_WAYLAND_CLIENT (user_data);
|
||||
|
||||
if (g_object_get_data (G_OBJECT (allowed_client),
|
||||
"test-client-destroyed"))
|
||||
return META_WAYLAND_ACCESS_DENIED;
|
||||
else if (meta_wayland_client_matches (allowed_client, client))
|
||||
return META_WAYLAND_ACCESS_ALLOWED;
|
||||
else
|
||||
return META_WAYLAND_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_bind (struct wl_client *client,
|
||||
void *data,
|
||||
uint32_t version,
|
||||
uint32_t id)
|
||||
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
handle_registry_global (void *user_data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t id,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
gboolean *global_seen = user_data;
|
||||
|
||||
if (strcmp (interface, dummy_interface.name) == 0)
|
||||
*global_seen = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_registry_global_remove (void *user_data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
handle_registry_global,
|
||||
handle_registry_global_remove
|
||||
};
|
||||
|
||||
static gpointer
|
||||
test_client_thread_func (gpointer user_data)
|
||||
{
|
||||
int fd = GPOINTER_TO_INT (user_data);
|
||||
struct wl_display *wl_display;
|
||||
struct wl_registry *wl_registry;
|
||||
gboolean global_seen = FALSE;
|
||||
|
||||
wl_display = wl_display_connect_to_fd (fd);
|
||||
g_assert_nonnull (wl_display);
|
||||
|
||||
wl_registry = wl_display_get_registry (wl_display);
|
||||
wl_registry_add_listener (wl_registry, ®istry_listener, &global_seen);
|
||||
wl_display_roundtrip (wl_display);
|
||||
wl_registry_destroy (wl_registry);
|
||||
|
||||
wl_display_disconnect (wl_display);
|
||||
|
||||
return GINT_TO_POINTER (global_seen);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_destroyed (MetaWaylandClient *client,
|
||||
gboolean *client_destroyed)
|
||||
{
|
||||
*client_destroyed = TRUE;
|
||||
g_object_set_data (G_OBJECT (client), "test-client-destroyed",
|
||||
GINT_TO_POINTER (TRUE));
|
||||
}
|
||||
|
||||
static void
|
||||
wayland_registry_filter (void)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
MetaWaylandCompositor *wayland_compositor =
|
||||
meta_context_get_wayland_compositor (test_context);
|
||||
MetaWaylandFilterManager *filter_manager =
|
||||
meta_wayland_compositor_get_filter_manager (wayland_compositor);
|
||||
struct wl_display *wayland_display =
|
||||
meta_wayland_compositor_get_wayland_display (wayland_compositor);
|
||||
struct wl_global *dummy_global;
|
||||
int fd;
|
||||
g_autoptr (MetaWaylandClient) client1 = NULL;
|
||||
g_autoptr (MetaWaylandClient) client2 = NULL;
|
||||
g_autoptr (MetaWaylandClient) client3 = NULL;
|
||||
g_autoptr (GThread) thread1 = NULL;
|
||||
g_autoptr (GThread) thread2 = NULL;
|
||||
g_autoptr (GThread) thread3 = NULL;
|
||||
gboolean client1_destroyed = FALSE;
|
||||
gboolean client2_destroyed = FALSE;
|
||||
gboolean client3_destroyed = FALSE;
|
||||
gboolean client1_saw_global;
|
||||
gboolean client2_saw_global;
|
||||
gboolean client3_saw_global;
|
||||
|
||||
client1 = meta_wayland_client_new_indirect (test_context, &error);
|
||||
g_assert_nonnull (client1);
|
||||
g_assert_null (error);
|
||||
client2 = meta_wayland_client_new_indirect (test_context, &error);
|
||||
g_assert_nonnull (client2);
|
||||
g_assert_null (error);
|
||||
client3 = meta_wayland_client_new_indirect (test_context, &error);
|
||||
g_assert_nonnull (client3);
|
||||
g_assert_null (error);
|
||||
|
||||
g_signal_connect (client1, "client-destroyed",
|
||||
G_CALLBACK (on_client_destroyed), &client1_destroyed);
|
||||
g_signal_connect (client2, "client-destroyed",
|
||||
G_CALLBACK (on_client_destroyed), &client2_destroyed);
|
||||
g_signal_connect (client3, "client-destroyed",
|
||||
G_CALLBACK (on_client_destroyed), &client3_destroyed);
|
||||
|
||||
dummy_global = wl_global_create (wayland_display,
|
||||
&dummy_interface,
|
||||
1, NULL, dummy_bind);
|
||||
meta_wayland_filter_manager_add_global (filter_manager,
|
||||
dummy_global,
|
||||
dummy_global_filter,
|
||||
client1);
|
||||
|
||||
fd = meta_wayland_client_setup_fd (client1, &error);
|
||||
g_assert_cmpint (fd, >=, 0);
|
||||
g_assert_null (error);
|
||||
thread1 = g_thread_new ("test client thread 1",
|
||||
test_client_thread_func,
|
||||
GINT_TO_POINTER (fd));
|
||||
|
||||
fd = meta_wayland_client_setup_fd (client2, &error);
|
||||
g_assert_cmpint (fd, >=, 0);
|
||||
g_assert_null (error);
|
||||
thread2 = g_thread_new ("test client thread 2",
|
||||
test_client_thread_func,
|
||||
GINT_TO_POINTER (fd));
|
||||
|
||||
while (!client1_destroyed || !client2_destroyed)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
client1_saw_global = GPOINTER_TO_INT (g_thread_join (thread1));
|
||||
client2_saw_global = GPOINTER_TO_INT (g_thread_join (thread2));
|
||||
|
||||
g_assert_true (client1_saw_global);
|
||||
g_assert_false (client2_saw_global);
|
||||
|
||||
meta_wayland_filter_manager_remove_global (filter_manager, dummy_global);
|
||||
wl_global_destroy (dummy_global);
|
||||
|
||||
fd = meta_wayland_client_setup_fd (client3, &error);
|
||||
g_assert_cmpint (fd, >=, 0);
|
||||
g_assert_null (error);
|
||||
thread3 = g_thread_new ("test client thread 3",
|
||||
test_client_thread_func,
|
||||
GINT_TO_POINTER (fd));
|
||||
while (!client3_destroyed)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
client3_saw_global = GPOINTER_TO_INT (g_thread_join (thread3));
|
||||
g_assert_false (client3_saw_global);
|
||||
}
|
||||
|
||||
static void
|
||||
on_before_tests (void)
|
||||
{
|
||||
@ -722,6 +897,8 @@ init_tests (void)
|
||||
toplevel_bounds_monitors);
|
||||
g_test_add_func ("/wayland/xdg-foreign/set-parent-of",
|
||||
xdg_foreign_set_parent_of);
|
||||
g_test_add_func ("/wayland/registry/filter",
|
||||
wayland_registry_filter);
|
||||
}
|
||||
|
||||
int
|
||||
|
Reference in New Issue
Block a user