diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h index a803166ac..764705447 100644 --- a/clutter/clutter/clutter-actor-private.h +++ b/clutter/clutter/clutter-actor-private.h @@ -23,6 +23,7 @@ #define __CLUTTER_ACTOR_PRIVATE_H__ #include +#include G_BEGIN_DECLS @@ -272,6 +273,11 @@ gboolean clutter_actor_get_redraw_clip (ClutterActor *self, ClutterPaintVolume *dst_old_pv, ClutterPaintVolume *dst_new_pv); +void clutter_actor_attach_grab (ClutterActor *actor, + ClutterGrab *grab); +void clutter_actor_detach_grab (ClutterActor *actor, + ClutterGrab *grab); + G_END_DECLS #endif /* __CLUTTER_ACTOR_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 7d911632e..5319e42b4 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -801,6 +801,7 @@ struct _ClutterActorPrivate gulong layout_changed_id; GList *stage_views; + GList *grabs; /* bitfields: KEEP AT THE END */ @@ -1633,6 +1634,25 @@ maybe_unset_key_focus (ClutterActor *self) clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL); } +static void +clutter_actor_clear_grabs (ClutterActor *self) +{ + ClutterActorPrivate *priv = self->priv; + ClutterActor *stage; + + if (!priv->grabs) + return; + + stage = _clutter_actor_get_stage_internal (self); + g_assert (stage != NULL); + + /* Undo every grab that the actor may hold, priv->grabs + * will be updated internally in clutter_stage_unlink_grab(). + */ + while (priv->grabs) + clutter_stage_unlink_grab (CLUTTER_STAGE (stage), priv->grabs->data); +} + static void clutter_actor_real_unmap (ClutterActor *self) { @@ -1678,6 +1698,8 @@ clutter_actor_real_unmap (ClutterActor *self) /* relinquish keyboard focus if we were unmapped while owning it */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) maybe_unset_key_focus (self); + + clutter_actor_clear_grabs (self); } /** @@ -5586,6 +5608,8 @@ clutter_actor_finalize (GObject *object) _clutter_actor_get_debug_name ((ClutterActor *) object), g_type_name (G_OBJECT_TYPE (object))); + /* No new grabs should have happened after unmapping */ + g_assert (priv->grabs == NULL); g_free (priv->name); g_free (priv->debug_name); @@ -19684,3 +19708,21 @@ clutter_actor_get_redraw_clip (ClutterActor *self, return TRUE; } + +void +clutter_actor_attach_grab (ClutterActor *self, + ClutterGrab *grab) +{ + ClutterActorPrivate *priv = self->priv; + + priv->grabs = g_list_prepend (priv->grabs, grab); +} + +void +clutter_actor_detach_grab (ClutterActor *self, + ClutterGrab *grab) +{ + ClutterActorPrivate *priv = self->priv; + + priv->grabs = g_list_remove (priv->grabs, grab); +} diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h index ac8e51517..50502845b 100644 --- a/clutter/clutter/clutter-stage-private.h +++ b/clutter/clutter/clutter-stage-private.h @@ -22,6 +22,7 @@ #ifndef __CLUTTER_STAGE_PRIVATE_H__ #define __CLUTTER_STAGE_PRIVATE_H__ +#include #include #include #include @@ -149,6 +150,9 @@ ClutterActor * clutter_stage_pick_and_update_device (ClutterStage *s graphene_point_t point, uint32_t time_ms); +void clutter_stage_unlink_grab (ClutterStage *self, + ClutterGrab *grab); + G_END_DECLS #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 2e9165ada..19c8ebd70 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -3873,20 +3873,23 @@ clutter_stage_grab (ClutterStage *stage, priv->topmost_grab->prev = grab; priv->topmost_grab = grab; + clutter_actor_attach_grab (actor, grab); clutter_stage_notify_grab (stage, grab, grab->next); return grab; } void -clutter_grab_dismiss (ClutterGrab *grab) +clutter_stage_unlink_grab (ClutterStage *stage, + ClutterGrab *grab) { - ClutterStagePrivate *priv; + ClutterStagePrivate *priv = stage->priv; ClutterGrab *prev, *next; - g_return_if_fail (grab != NULL); + /* This grab is already detached */ + if (!grab->prev && !grab->next && priv->topmost_grab != grab) + return; - priv = grab->stage->priv; prev = grab->prev; next = grab->next; @@ -3903,6 +3906,18 @@ clutter_grab_dismiss (ClutterGrab *grab) clutter_stage_notify_grab (stage, next, grab); } + clutter_actor_detach_grab (grab->actor, grab); + + grab->next = NULL; + grab->prev = NULL; +} + +void +clutter_grab_dismiss (ClutterGrab *grab) +{ + g_return_if_fail (grab != NULL); + + clutter_stage_unlink_grab (grab->stage, grab); g_free (grab); }