Merge branch 'event-dispatch-listener' into 'main'

wayland-server: Add wl_client_add_event_dispatch_listener

See merge request wayland/wayland!358
This commit is contained in:
Thomas Lukaszewicz 2024-02-21 22:38:12 +00:00
commit 650a3c6d63
3 changed files with 80 additions and 5 deletions

View file

@ -342,6 +342,10 @@ struct wl_listener *
wl_client_get_destroy_late_listener(struct wl_client *client,
wl_notify_func_t notify);
void
wl_client_add_event_dispatch_listener(struct wl_client *client,
struct wl_listener *listener);
struct wl_resource *
wl_client_get_object(struct wl_client *client, uint32_t id);

View file

@ -80,6 +80,7 @@ struct wl_client {
struct wl_map objects;
struct wl_priv_signal destroy_signal;
struct wl_priv_signal destroy_late_signal;
struct wl_priv_signal event_dispatch_signal;
pid_t pid;
uid_t uid;
gid_t gid;
@ -214,12 +215,13 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
{
struct wl_closure *closure;
struct wl_object *object = &resource->object;
struct wl_client *client = resource->client;
if (resource->client->error)
if (client->error)
return;
if (!verify_objects(resource, opcode, args)) {
resource->client->error = true;
client->error = true;
return;
}
@ -227,14 +229,17 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
&object->interface->events[opcode]);
if (closure == NULL) {
resource->client->error = true;
client->error = true;
return;
}
log_closure(resource, closure, true);
if (send_func(closure, resource->client->connection))
resource->client->error = true;
if (send_func(closure, client->connection)) {
client->error = true;
} else {
wl_priv_signal_final_emit(&client->event_dispatch_signal, client);
}
wl_closure_destroy(closure);
}
@ -551,6 +556,7 @@ wl_client_create(struct wl_display *display, int fd)
wl_priv_signal_init(&client->destroy_signal);
wl_priv_signal_init(&client->destroy_late_signal);
wl_priv_signal_init(&client->event_dispatch_signal);
if (bind_display(client, display) < 0)
goto err_map;
@ -930,6 +936,27 @@ wl_client_get_destroy_late_listener(struct wl_client *client,
return wl_priv_signal_get(&client->destroy_late_signal, notify);
}
/** Add a listener to be called after successful event dispatch.
*
* \param client The client object.
* \param listener The listener to be added.
*
* After an event has been dispatched to this client, the listener will
* be notified.
*
* There is no requirement to remove the link of the wl_listener when the
* signal is emitted.
*
* \memberof wl_client
* \since 1.22.0
*/
WL_EXPORT void
wl_client_add_event_dispatch_listener(struct wl_client *client,
struct wl_listener *listener)
{
wl_priv_signal_add(&client->event_dispatch_signal, listener);
}
WL_EXPORT void
wl_client_destroy(struct wl_client *client)
{

View file

@ -158,3 +158,47 @@ TEST(client_destroy_listener)
wl_display_destroy(display);
}
struct event_dispatch_listener {
struct wl_listener listener;
bool done;
};
static void
event_dispatch_notify(struct wl_listener *l, void *data)
{
struct event_dispatch_listener *listener =
wl_container_of(l, listener, listener);
listener->done = true;
}
TEST(event_dispatch_listener)
{
struct wl_display *display;
struct wl_client *client;
struct wl_resource *resource;
struct event_dispatch_listener dispatch_listener;
int s[2];
assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
display = wl_display_create();
assert(display);
client = wl_client_create(display, s[0]);
assert(client);
dispatch_listener.listener.notify = event_dispatch_notify;
dispatch_listener.done = false;
wl_client_add_event_dispatch_listener(client, &dispatch_listener.listener);
resource = wl_resource_create(client, &wl_seat_interface, 4, 0);
assert(resource);
wl_seat_send_name(resource, "default");
wl_event_loop_dispatch(wl_display_get_event_loop(display), 0);
assert(dispatch_listener.done);
close(s[1]);
wl_client_destroy(client);
wl_display_destroy(display);
}