diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 4279d3476..b31a4d01d 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -1701,6 +1701,13 @@ clutter_actor_real_unmap (ClutterActor *self) */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]); + if (priv->has_pointer) + { + ClutterActor *stage = _clutter_actor_get_stage_internal (self); + + clutter_stage_invalidate_focus (CLUTTER_STAGE (stage), self); + } + /* relinquish keyboard focus if we were unmapped while owning it */ if (!CLUTTER_ACTOR_IS_TOPLEVEL (self)) maybe_unset_key_focus (self); @@ -12440,8 +12447,12 @@ void clutter_actor_set_reactive (ClutterActor *actor, gboolean reactive) { + ClutterActorPrivate *priv; + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + priv = actor->priv; + if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor)) return; @@ -12451,6 +12462,13 @@ clutter_actor_set_reactive (ClutterActor *actor, CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE); g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]); + + if (!CLUTTER_ACTOR_IS_REACTIVE (actor) && priv->has_pointer) + { + ClutterActor *stage = _clutter_actor_get_stage_internal (actor); + + clutter_stage_invalidate_focus (CLUTTER_STAGE (stage), actor); + } } /** diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h index efa341cc1..e9ba5707e 100644 --- a/clutter/clutter/clutter-stage-private.h +++ b/clutter/clutter/clutter-stage-private.h @@ -154,6 +154,9 @@ ClutterActor * clutter_stage_pick_and_update_device (ClutterStage *s void clutter_stage_unlink_grab (ClutterStage *self, ClutterGrab *grab); +void clutter_stage_invalidate_focus (ClutterStage *self, + ClutterActor *actor); + G_END_DECLS #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 5cd09a2c4..705bd92a8 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -3150,53 +3150,62 @@ clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage) priv->actor_needs_immediate_relayout = TRUE; } -static void -on_device_actor_reactive_changed (ClutterActor *actor, - GParamSpec *pspec, - PointerDeviceEntry *entry) +void +clutter_stage_invalidate_focus (ClutterStage *self, + ClutterActor *actor) { - ClutterStage *self = entry->stage; + ClutterStagePrivate *priv = self->priv; + GHashTableIter iter; + gpointer value; - g_assert (!clutter_actor_get_reactive (actor)); + if (CLUTTER_ACTOR_IN_DESTRUCTION (self)) + return; - clutter_stage_pick_and_update_device (self, - entry->device, - entry->sequence, - CLUTTER_DEVICE_UPDATE_IGNORE_CACHE | - CLUTTER_DEVICE_UPDATE_EMIT_CROSSING, - entry->coords, - CLUTTER_CURRENT_TIME); -} + g_assert (!clutter_actor_is_mapped (actor) || !clutter_actor_get_reactive (actor)); -static void -on_device_actor_destroyed (ClutterActor *actor, - PointerDeviceEntry *entry) -{ - /* Simply unset the current_actor pointer here, there's no need to - * unset has_pointer or to disconnect any signals because the actor - * is gone anyway. - */ - entry->current_actor = NULL; - g_clear_pointer (&entry->clear_area, cairo_region_destroy); - clutter_stage_repick_device (entry->stage, entry->device); + g_hash_table_iter_init (&iter, priv->pointer_devices); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + PointerDeviceEntry *entry = value; + + if (entry->current_actor != actor) + continue; + + clutter_stage_pick_and_update_device (self, + entry->device, + NULL, + CLUTTER_DEVICE_UPDATE_IGNORE_CACHE | + CLUTTER_DEVICE_UPDATE_EMIT_CROSSING, + entry->coords, + CLUTTER_CURRENT_TIME); + } + + g_hash_table_iter_init (&iter, priv->touch_sequences); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + PointerDeviceEntry *entry = value; + + if (entry->current_actor != actor) + continue; + + clutter_stage_pick_and_update_device (self, + entry->device, + entry->sequence, + CLUTTER_DEVICE_UPDATE_IGNORE_CACHE | + CLUTTER_DEVICE_UPDATE_EMIT_CROSSING, + entry->coords, + CLUTTER_CURRENT_TIME); + } + + if (actor != CLUTTER_ACTOR (self)) + g_assert (!clutter_actor_has_pointer (actor)); } static void free_pointer_device_entry (PointerDeviceEntry *entry) { if (entry->current_actor) - { - ClutterActor *actor = entry->current_actor; - - g_signal_handlers_disconnect_by_func (actor, - G_CALLBACK (on_device_actor_reactive_changed), - entry); - g_signal_handlers_disconnect_by_func (actor, - G_CALLBACK (on_device_actor_destroyed), - entry); - - _clutter_actor_set_has_pointer (actor, FALSE); - } + _clutter_actor_set_has_pointer (entry->current_actor, FALSE); g_clear_pointer (&entry->clear_area, cairo_region_destroy); @@ -3240,30 +3249,12 @@ clutter_stage_update_device_entry (ClutterStage *self, if (entry->current_actor != actor) { if (entry->current_actor) - { - ClutterActor *old_actor = entry->current_actor; - - g_signal_handlers_disconnect_by_func (old_actor, - G_CALLBACK (on_device_actor_reactive_changed), - entry); - g_signal_handlers_disconnect_by_func (old_actor, - G_CALLBACK (on_device_actor_destroyed), - entry); - - _clutter_actor_set_has_pointer (old_actor, FALSE); - } + _clutter_actor_set_has_pointer (entry->current_actor, FALSE); entry->current_actor = actor; if (actor) - { - g_signal_connect (actor, "notify::reactive", - G_CALLBACK (on_device_actor_reactive_changed), entry); - g_signal_connect (actor, "destroy", - G_CALLBACK (on_device_actor_destroyed), entry); - - _clutter_actor_set_has_pointer (actor, TRUE); - } + _clutter_actor_set_has_pointer (actor, TRUE); } g_clear_pointer (&entry->clear_area, cairo_region_destroy);