From 67773ab88de8394177f46cc116fa38f3ac1ed77b Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 17 Nov 2023 23:29:39 +0100 Subject: [PATCH] wayland: Add argument to grab when attaching MetaWaylandEventInterface Add the mechanism to integrate MetaWaylandEventInterface with grabs, callers may now specify whether a grab is required, in which case one is created, shared by all the event interface stack. ClutterStage grab state is also tracked, so the MetaWaylandEventInterface in charge will focus or unfocus depending on whether input should be handled (if ungrabbed, or grabbed by the MetaWaylandInput itself), or not (if grabbed by something else). At the moment nothing uses this mechanism yet, later commits will add the first users. Part-of: --- src/wayland/meta-wayland-data-device.c | 1 + src/wayland/meta-wayland-input.c | 101 +++++++++++++++++- src/wayland/meta-wayland-input.h | 1 + .../meta-wayland-pointer-constraints.c | 1 + src/wayland/meta-wayland-popup.c | 2 +- src/wayland/meta-wayland-seat.c | 3 +- src/wayland/meta-xwayland-grab-keyboard.c | 2 +- 7 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index 6c2f6628e..9e94e1d24 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -745,6 +745,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_devic drag_grab->handler = meta_wayland_input_attach_event_handler (input, event_iface, + FALSE, drag_grab); meta_wayland_data_source_set_seat (source, seat); } diff --git a/src/wayland/meta-wayland-input.c b/src/wayland/meta-wayland-input.c index 8115c489d..a0caa7253 100644 --- a/src/wayland/meta-wayland-input.c +++ b/src/wayland/meta-wayland-input.c @@ -27,12 +27,14 @@ #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-tablet-seat.h" +#include "wayland/meta-wayland.h" struct _MetaWaylandEventHandler { const MetaWaylandEventInterface *iface; MetaWaylandInput *input; gpointer user_data; + gboolean grabbing; struct wl_list link; }; @@ -42,10 +44,20 @@ struct _MetaWaylandInput MetaWaylandSeat *seat; struct wl_list event_handler_list; + ClutterStage *stage; + ClutterGrab *grab; }; +static void meta_wayland_input_sync_focus (MetaWaylandInput *input); + G_DEFINE_FINAL_TYPE (MetaWaylandInput, meta_wayland_input, G_TYPE_OBJECT) +static void +on_stage_is_grabbed_change (MetaWaylandInput *input) +{ + meta_wayland_input_sync_focus (input); +} + static void meta_wayland_input_init (MetaWaylandInput *input) { @@ -58,6 +70,10 @@ meta_wayland_input_finalize (GObject *object) MetaWaylandInput *input = META_WAYLAND_INPUT (object); MetaWaylandEventHandler *handler, *next; + g_signal_handlers_disconnect_by_func (input->stage, + on_stage_is_grabbed_change, + input); + wl_list_for_each_safe (handler, next, &input->event_handler_list, link) meta_wayland_input_detach_event_handler (input, handler); @@ -76,9 +92,18 @@ MetaWaylandInput * meta_wayland_input_new (MetaWaylandSeat *seat) { MetaWaylandInput *input; + MetaWaylandCompositor *compositor = seat->compositor; + MetaContext *context = + meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); input = g_object_new (META_TYPE_WAYLAND_INPUT, NULL); input->seat = seat; + input->stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + + g_signal_connect_swapped (input->stage, "notify::is-grabbed", + G_CALLBACK (on_stage_is_grabbed_change), + input); return input; } @@ -88,14 +113,18 @@ meta_wayland_event_handler_invalidate_focus (MetaWaylandEventHandler *handler, ClutterInputDevice *device, ClutterEventSequence *sequence) { + MetaWaylandInput *input = handler->input; MetaWaylandSurface *surface = NULL; if (!handler->iface->focus) return; - /* Only the first handler can focus other than a NULL surface */ - if (meta_wayland_input_is_current_handler (handler->input, handler) && - handler->iface->get_focus_surface) + if (handler->iface->get_focus_surface && + /* Only the first handler can focus other than a NULL surface */ + meta_wayland_input_is_current_handler (input, handler) && + /* Stage should either be ungrabbed, or grabbed to self */ + (!clutter_stage_get_grab_actor (input->stage) || + (input->grab && !clutter_grab_is_revoked (input->grab)))) { surface = handler->iface->get_focus_surface (handler, device, sequence, @@ -212,9 +241,35 @@ meta_wayland_event_handler_handle_event (MetaWaylandEventHandler *handler, g_assert_not_reached (); } +static void +meta_wayland_input_sync_focus (MetaWaylandInput *input) +{ + MetaWaylandEventHandler *handler; + + g_assert (!wl_list_empty (&input->event_handler_list)); + handler = wl_container_of (input->event_handler_list.next, handler, link); + meta_wayland_event_handler_invalidate_all_focus (handler); +} + +static void +on_grab_revocation_change (MetaWaylandInput *input) +{ + meta_wayland_input_sync_focus (input); +} + +static gboolean +grab_handle_event (const ClutterEvent *event, + gpointer user_data) +{ + MetaWaylandInput *input = user_data; + + return meta_wayland_input_handle_event (input, event); +} + MetaWaylandEventHandler * meta_wayland_input_attach_event_handler (MetaWaylandInput *input, const MetaWaylandEventInterface *iface, + gboolean grab, gpointer user_data) { MetaWaylandEventHandler *handler; @@ -222,15 +277,45 @@ meta_wayland_input_attach_event_handler (MetaWaylandInput *input, handler = g_new0 (MetaWaylandEventHandler, 1); handler->iface = iface; handler->input = input; + handler->grabbing = grab; handler->user_data = user_data; wl_list_init (&handler->link); wl_list_insert (&input->event_handler_list, &handler->link); + if (grab && !input->grab) + { + MetaWaylandCompositor *compositor = input->seat->compositor; + MetaContext *context = + meta_wayland_compositor_get_context (compositor); + MetaBackend *backend = meta_context_get_backend (context); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + + input->grab = clutter_stage_grab_input_only (stage, + grab_handle_event, + input, + NULL); + g_signal_connect_swapped (input->grab, "notify::revoked", + G_CALLBACK (on_grab_revocation_change), + input); + } + meta_wayland_event_handler_invalidate_all_focus (handler); return handler; } +static gboolean +should_be_grabbed (MetaWaylandInput *input) +{ + MetaWaylandEventHandler *handler; + gboolean grabbing = FALSE; + + wl_list_for_each (handler, &input->event_handler_list, link) + grabbing |= handler->grabbing; + + return grabbing; +} + void meta_wayland_input_detach_event_handler (MetaWaylandInput *input, MetaWaylandEventHandler *handler) @@ -249,6 +334,16 @@ meta_wayland_input_detach_event_handler (MetaWaylandInput *input, meta_wayland_event_handler_invalidate_all_focus (head); } + if (input->grab && !should_be_grabbed (input)) + { + g_signal_handlers_disconnect_by_func (input->grab, + on_grab_revocation_change, + input); + + clutter_grab_dismiss (input->grab); + g_clear_object (&input->grab); + } + g_free (handler); } diff --git a/src/wayland/meta-wayland-input.h b/src/wayland/meta-wayland-input.h index 5eff00435..8342457ba 100644 --- a/src/wayland/meta-wayland-input.h +++ b/src/wayland/meta-wayland-input.h @@ -77,6 +77,7 @@ MetaWaylandInput * meta_wayland_input_new (MetaWaylandSeat *seat); MetaWaylandEventHandler * meta_wayland_input_attach_event_handler (MetaWaylandInput *input, const MetaWaylandEventInterface *iface, + gboolean grab, gpointer user_data); gboolean meta_wayland_input_is_current_handler (MetaWaylandInput *input, diff --git a/src/wayland/meta-wayland-pointer-constraints.c b/src/wayland/meta-wayland-pointer-constraints.c index d067a327e..178197d7e 100644 --- a/src/wayland/meta-wayland-pointer-constraints.c +++ b/src/wayland/meta-wayland-pointer-constraints.c @@ -397,6 +397,7 @@ meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint constraint->handler = meta_wayland_input_attach_event_handler (input, &pointer_constraints_event_interface, + FALSE, constraint); constraint->confinement = diff --git a/src/wayland/meta-wayland-popup.c b/src/wayland/meta-wayland-popup.c index 2af5cb853..d157029fd 100644 --- a/src/wayland/meta-wayland-popup.c +++ b/src/wayland/meta-wayland-popup.c @@ -207,7 +207,7 @@ meta_wayland_popup_grab_create (MetaWaylandSeat *seat, grab->handler = meta_wayland_input_attach_event_handler (input, &popup_event_interface, - grab); + FALSE, grab); return grab; } diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index a99eae99b..28efa70ee 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -308,7 +308,8 @@ meta_wayland_seat_new (MetaWaylandCompositor *compositor, seat->input_handler = meta_wayland_input_new (seat); seat->default_handler = meta_wayland_input_attach_event_handler (seat->input_handler, - &default_event_interface, seat); + &default_event_interface, + FALSE, seat); return seat; } diff --git a/src/wayland/meta-xwayland-grab-keyboard.c b/src/wayland/meta-xwayland-grab-keyboard.c index 88dd8c78e..dbf3c5b07 100644 --- a/src/wayland/meta-xwayland-grab-keyboard.c +++ b/src/wayland/meta-xwayland-grab-keyboard.c @@ -251,7 +251,7 @@ meta_xwayland_keyboard_grab_activate (MetaXwaylandKeyboardActiveGrab *active_gra active_grab->handler = meta_wayland_input_attach_event_handler (input, &grab_event_interface, - active_grab); + FALSE, active_grab); } }