clutter/stage: Cancel parts of implicit grabs when ClutterGrabs happen
A ClutterGrab takes precedence over implicit grabs, so when one happens, let's check which part of the implicit grab tree is inside the new ClutterGrab. Cancel and remove the parts which aren't, and if nothing is in there anymore, cancel the whole implicit grab. Emitting crossing events correctly here is getting quite tricky: - When the implicit grab didn't get cancelled by the ClutterGrab, we simply want to emit all GRAB_NOTIFY crossings to the implicit grab, as we do with all other crossings. - When the implicit grab did get cancelled and the new ClutterGrab wants to emit ENTER crossings, we want those to be emitted to the actual targets, so cancel the implicit grab before emission. - In the last case where the implicit grab did get cancelled and the new ClutterGrab wants to emit LEAVE crossings, those should be emitted to the implicit grab again, so we cancel the grab only after the emission of those. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2342>
This commit is contained in:
parent
2dd851d9f4
commit
debbd88f8c
@ -3845,13 +3845,27 @@ clutter_stage_pick_and_update_device (ClutterStage *stage,
|
||||
return new_actor;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_implicit_grab (PointerDeviceEntry *entry)
|
||||
{
|
||||
clutter_actor_set_implicitly_grabbed (entry->implicit_grab_actor, FALSE);
|
||||
entry->implicit_grab_actor = NULL;
|
||||
|
||||
g_array_remove_range (entry->event_emission_chain, 0,
|
||||
entry->event_emission_chain->len);
|
||||
|
||||
entry->press_count = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_notify_grab_on_pointer_entry (ClutterStage *stage,
|
||||
PointerDeviceEntry *entry,
|
||||
ClutterActor *grab_actor,
|
||||
ClutterActor *old_grab_actor)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
gboolean pointer_in_grab, pointer_in_old_grab;
|
||||
gboolean implicit_grab_cancelled = FALSE;
|
||||
ClutterEventType event_type = CLUTTER_NOTHING;
|
||||
ClutterActor *topmost, *deepmost;
|
||||
|
||||
@ -3867,6 +3881,62 @@ clutter_stage_notify_grab_on_pointer_entry (ClutterStage *stage,
|
||||
old_grab_actor == entry->current_actor ||
|
||||
clutter_actor_contains (old_grab_actor, entry->current_actor);
|
||||
|
||||
if (grab_actor && entry->press_count > 0)
|
||||
{
|
||||
ClutterInputDevice *device = entry->device;
|
||||
ClutterEventSequence *sequence = entry->sequence;
|
||||
unsigned int i;
|
||||
unsigned int n_removed = 0;
|
||||
|
||||
implicit_grab_cancelled = TRUE;
|
||||
|
||||
for (i = 0; i < entry->event_emission_chain->len; i++)
|
||||
{
|
||||
EventReceiver *receiver =
|
||||
&g_array_index (entry->event_emission_chain, EventReceiver, i);
|
||||
|
||||
if (receiver->actor)
|
||||
{
|
||||
if (!clutter_actor_contains (grab_actor, receiver->actor))
|
||||
{
|
||||
g_clear_object (&receiver->actor);
|
||||
n_removed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
implicit_grab_cancelled = FALSE;
|
||||
}
|
||||
}
|
||||
else if (receiver->action)
|
||||
{
|
||||
ClutterActor *action_actor =
|
||||
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (receiver->action));
|
||||
|
||||
if (!action_actor || !clutter_actor_contains (grab_actor, action_actor))
|
||||
{
|
||||
clutter_action_sequence_cancelled (receiver->action,
|
||||
device,
|
||||
sequence);
|
||||
g_clear_object (&receiver->action);
|
||||
n_removed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
implicit_grab_cancelled = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n_removed > 0)
|
||||
{
|
||||
CLUTTER_NOTE (GRABS,
|
||||
"[grab=%p device=%p sequence=%p implicit_grab_cancelled=%d] "
|
||||
"Cancelled %u actors and actions on implicit grab due to new seat grab",
|
||||
priv->topmost_grab, device, sequence, implicit_grab_cancelled,
|
||||
n_removed);
|
||||
}
|
||||
}
|
||||
|
||||
/* Equate NULL actors to the stage here, to ease calculations further down. */
|
||||
if (!grab_actor)
|
||||
grab_actor = CLUTTER_ACTOR (stage);
|
||||
@ -3874,7 +3944,10 @@ clutter_stage_notify_grab_on_pointer_entry (ClutterStage *stage,
|
||||
old_grab_actor = CLUTTER_ACTOR (stage);
|
||||
|
||||
if (grab_actor == old_grab_actor)
|
||||
return;
|
||||
{
|
||||
g_assert (!implicit_grab_cancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pointer_in_grab && pointer_in_old_grab)
|
||||
{
|
||||
@ -3921,10 +3994,16 @@ clutter_stage_notify_grab_on_pointer_entry (ClutterStage *stage,
|
||||
topmost = find_common_root_actor (stage, grab_actor, old_grab_actor);
|
||||
}
|
||||
|
||||
if (event_type == CLUTTER_ENTER && implicit_grab_cancelled)
|
||||
cleanup_implicit_grab (entry);
|
||||
|
||||
if (event_type != CLUTTER_NOTHING)
|
||||
{
|
||||
ClutterEvent *event;
|
||||
|
||||
if (entry->implicit_grab_actor)
|
||||
deepmost = find_common_root_actor (stage, entry->implicit_grab_actor, deepmost);
|
||||
|
||||
event = create_crossing_event (stage,
|
||||
entry->device,
|
||||
entry->sequence,
|
||||
@ -3945,6 +4024,10 @@ clutter_stage_notify_grab_on_pointer_entry (ClutterStage *stage,
|
||||
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
if ((event_type == CLUTTER_NOTHING || event_type == CLUTTER_LEAVE) &&
|
||||
implicit_grab_cancelled)
|
||||
cleanup_implicit_grab (entry);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4406,12 +4489,7 @@ clutter_stage_maybe_lost_implicit_grab (ClutterStage *self,
|
||||
|
||||
sync_crossings_on_implicit_grab_end (self, entry);
|
||||
|
||||
clutter_actor_set_implicitly_grabbed (entry->implicit_grab_actor, FALSE);
|
||||
entry->implicit_grab_actor = NULL;
|
||||
g_array_remove_range (entry->event_emission_chain, 0,
|
||||
entry->event_emission_chain->len);
|
||||
|
||||
entry->press_count = 0;
|
||||
cleanup_implicit_grab (entry);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4530,9 +4608,7 @@ clutter_stage_emit_event (ClutterStage *self,
|
||||
if (event->type == CLUTTER_BUTTON_RELEASE)
|
||||
sync_crossings_on_implicit_grab_end (self, entry);
|
||||
|
||||
clutter_actor_set_implicitly_grabbed (entry->implicit_grab_actor, FALSE);
|
||||
entry->implicit_grab_actor = NULL;
|
||||
g_array_remove_range (entry->event_emission_chain, 0, entry->event_emission_chain->len);
|
||||
cleanup_implicit_grab (entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user