From 8e5f3a1f8388a2b72328bfaef91cb14755a3609f Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 11 May 2024 11:59:13 +0200 Subject: [PATCH] clutter: Add API to create inactive ClutterGrabs, and activate them explicitly This gives greater control to the callers on the place where a grab is being activated, this may make a difference in the handling of crossing events triggered through it, e.g. by having callers rely on having already obtained a ClutterGrab prior to handling the resulting effects. The "input only" grab has also been turned inactive by default, in order to to have the ClutterGrab pointer available for checks at the MetaWaylandEventHandler focus changing methods triggered through grab activation. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3463 Part-of: --- clutter/clutter/clutter-grab.h | 3 ++ clutter/clutter/clutter-stage.c | 73 ++++++++++++++++++++++++++------ clutter/clutter/clutter-stage.h | 4 ++ src/tests/clutter/conform/grab.c | 1 + src/wayland/meta-wayland-input.c | 2 + 5 files changed, 69 insertions(+), 14 deletions(-) diff --git a/clutter/clutter/clutter-grab.h b/clutter/clutter/clutter-grab.h index 36199acc9..0d00c8737 100644 --- a/clutter/clutter/clutter-grab.h +++ b/clutter/clutter/clutter-grab.h @@ -36,6 +36,9 @@ CLUTTER_EXPORT G_DECLARE_FINAL_TYPE (ClutterGrab, clutter_grab, CLUTTER, GRAB, GObject) +CLUTTER_EXPORT +void clutter_grab_activate (ClutterGrab *grab); + CLUTTER_EXPORT void clutter_grab_dismiss (ClutterGrab *grab); diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 62fd90954..9b27ff8b3 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -3834,18 +3834,45 @@ clutter_stage_grab_full (ClutterStage *stage, ClutterActor *actor, gboolean owns_actor) { - ClutterStagePrivate *priv; - ClutterGrab *grab; - gboolean was_grabbed; - g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL); g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); g_return_val_if_fail (stage == (ClutterStage *) _clutter_actor_get_stage_internal (actor), NULL); + return clutter_grab_new (stage, actor, owns_actor); +} + +/** + * clutter_grab_activate: + * @grab: a `ClutterGrab` + * + * Activates a grab onto its assigned actor. Events will be propagated as + * usual inside its hierarchy. Activating an already active grab will have + * no side effects. + * + * This method is necessary for grabs obtained through + * [method@Stage.grab_inactive]. Grabs obtained through [method@Stage.grab] + * will be activated implicitly. + * + * to undo the effects of this function, call [method@Grab.dismiss]. + **/ +void +clutter_grab_activate (ClutterGrab *grab) +{ + ClutterStage *stage; + ClutterStagePrivate *priv; + gboolean was_grabbed; + + g_return_if_fail (CLUTTER_IS_GRAB (grab)); + + stage = grab->stage; priv = clutter_stage_get_instance_private (stage); + /* This grab is already active */ + if (grab->prev || grab->next || priv->topmost_grab == grab) + return; + if (!priv->topmost_grab) { ClutterContext *context; @@ -3858,8 +3885,6 @@ clutter_stage_grab_full (ClutterStage *stage, clutter_seat_grab (seat, clutter_get_current_event_time ()); } - grab = clutter_grab_new (stage, actor, owns_actor); - grab->prev = NULL; grab->next = priv->topmost_grab; @@ -3880,10 +3905,10 @@ clutter_stage_grab_full (ClutterStage *stage, CLUTTER_NOTE (GRABS, "[grab=%p] Attached seat grab (n_grabs: %u) on actor: %s", - grab, n_grabs, _clutter_actor_get_debug_name (actor)); + grab, n_grabs, _clutter_actor_get_debug_name (grab->actor)); } - clutter_actor_attach_grab (actor, grab); + clutter_actor_attach_grab (grab->actor, grab); clutter_stage_notify_grab (stage, grab, grab->next); if (was_grabbed != !!priv->topmost_grab) @@ -3891,8 +3916,6 @@ clutter_stage_grab_full (ClutterStage *stage, if (grab->next) clutter_grab_notify (grab->next); - - return grab; } /** @@ -3909,15 +3932,37 @@ clutter_stage_grab_full (ClutterStage *stage, ClutterGrab * clutter_stage_grab (ClutterStage *stage, ClutterActor *actor) +{ + ClutterGrab *grab; + + grab = clutter_stage_grab_full (stage, actor, FALSE); + clutter_grab_activate (grab); + + return grab; +} + +/** + * clutter_stage_grab_inactive: + * @stage: The #ClutterStage + * @actor: The actor that will grab input + * + * Creates an inactive grab. The grab will become effective + * after [method@Grab.activate]. + * + * Returns: (transfer full): an opaque #ClutterGrab handle + **/ +ClutterGrab * +clutter_stage_grab_inactive (ClutterStage *stage, + ClutterActor *actor) { return clutter_stage_grab_full (stage, actor, FALSE); } ClutterGrab * -clutter_stage_grab_input_only (ClutterStage *stage, - ClutterEventHandler handler, - gpointer user_data, - GDestroyNotify user_data_destroy) +clutter_stage_grab_input_only (ClutterStage *stage, + ClutterEventHandler handler, + gpointer user_data, + GDestroyNotify user_data_destroy) { ClutterInputOnlyActor *input_only_actor; ClutterActor *actor; diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h index b9f21ca39..735c4bcd5 100644 --- a/clutter/clutter/clutter-stage.h +++ b/clutter/clutter/clutter-stage.h @@ -223,6 +223,10 @@ CLUTTER_EXPORT ClutterGrab * clutter_stage_grab (ClutterStage *stage, ClutterActor *actor); +CLUTTER_EXPORT +ClutterGrab * clutter_stage_grab_inactive (ClutterStage *stage, + ClutterActor *actor); + CLUTTER_EXPORT ClutterActor * clutter_stage_get_grab_actor (ClutterStage *stage); diff --git a/src/tests/clutter/conform/grab.c b/src/tests/clutter/conform/grab.c index c62eea6fb..ef958b99f 100644 --- a/src/tests/clutter/conform/grab.c +++ b/src/tests/clutter/conform/grab.c @@ -628,6 +628,7 @@ grab_input_only (void) grab = clutter_stage_grab_input_only (CLUTTER_STAGE (data.stage), handle_input_only_event, data.events, NULL); + clutter_grab_activate (grab); event_log_compare ((EventLog *) &grab1_log, data.events); clutter_virtual_input_device_notify_button (pointer, diff --git a/src/wayland/meta-wayland-input.c b/src/wayland/meta-wayland-input.c index 5e0ab3845..791536e75 100644 --- a/src/wayland/meta-wayland-input.c +++ b/src/wayland/meta-wayland-input.c @@ -303,6 +303,8 @@ meta_wayland_input_attach_event_handler (MetaWaylandInput *input, grab_handle_event, input, NULL); + clutter_grab_activate (input->grab); + g_signal_connect_swapped (input->grab, "notify::revoked", G_CALLBACK (on_grab_revocation_change), input);