diff --git a/clutter/clutter/clutter-actor-accessible.c b/clutter/clutter/clutter-actor-accessible.c index e2bb30513..c3d9a8685 100644 --- a/clutter/clutter/clutter-actor-accessible.c +++ b/clutter/clutter/clutter-actor-accessible.c @@ -355,55 +355,35 @@ clutter_actor_accessible_get_index_in_parent (AtkObject *obj) static AtkStateSet* clutter_actor_accessible_ref_state_set (AtkObject *obj) { - ClutterActor *actor = NULL; - AtkStateSet *state_set = NULL; - ClutterStage *stage = NULL; - ClutterActor *focus_actor = NULL; - ClutterActorAccessible * actor_accessible = NULL; + ClutterActor *actor = NULL; + g_autoptr (AtkStateSet) parent_state = NULL; + AtkStateSet *combined_state, *actor_state = NULL; + ClutterActorAccessible *actor_accessible = NULL; g_return_val_if_fail (CLUTTER_IS_ACTOR_ACCESSIBLE (obj), NULL); - actor_accessible = CLUTTER_ACTOR_ACCESSIBLE (obj); + actor_accessible = CLUTTER_ACTOR_ACCESSIBLE (obj); - state_set = ATK_OBJECT_CLASS (clutter_actor_accessible_parent_class)->ref_state_set (obj); + parent_state = ATK_OBJECT_CLASS (clutter_actor_accessible_parent_class)->ref_state_set (obj); actor = CLUTTER_ACTOR_FROM_ACCESSIBLE (actor_accessible); if (actor == NULL) /* Object is defunct */ { - atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); + atk_state_set_add_state (parent_state, ATK_STATE_DEFUNCT); + combined_state = g_steal_pointer (&parent_state); } else { - if (clutter_actor_get_reactive (actor)) - { - atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); - atk_state_set_add_state (state_set, ATK_STATE_ENABLED); - } + actor_state = clutter_actor_get_accessible_state (actor); - if (clutter_actor_is_visible (actor)) - { - atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); - - /* It would be good to also check if the actor is on screen, - like the old and removed clutter_actor_is_on_stage*/ - if (clutter_actor_get_paint_visibility (actor)) - atk_state_set_add_state (state_set, ATK_STATE_SHOWING); - - } - - /* See focus section on implementation notes */ - atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); - - stage = CLUTTER_STAGE (clutter_actor_get_stage (actor)); - if (stage != NULL) - { - focus_actor = clutter_stage_get_key_focus (stage); - if (focus_actor == actor) - atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); - } + if (actor_state) + combined_state = atk_state_set_or_sets (parent_state, + actor_state); + else + combined_state = g_steal_pointer (&parent_state); } - return state_set; + return combined_state; } static gint diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h index 354559245..ce9096b56 100644 --- a/clutter/clutter/clutter-actor-private.h +++ b/clutter/clutter/clutter-actor-private.h @@ -300,4 +300,6 @@ const GList * clutter_actor_peek_actions (ClutterActor *self); void clutter_actor_set_implicitly_grabbed (ClutterActor *actor, gboolean is_implicitly_grabbed); +AtkStateSet * clutter_actor_get_accessible_state (ClutterActor *actor); + G_END_DECLS diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 46549824d..32806c63e 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -557,6 +557,7 @@ struct _ClutterActorPrivate /* Accessibility */ AtkObject *accessible; gchar *accessible_name; + AtkStateSet *accessible_state; /* request mode */ ClutterRequestMode request_mode; @@ -1431,7 +1432,6 @@ clutter_actor_real_map (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *iter; - AtkObject *accessible; g_assert (!clutter_actor_is_mapped (self)); @@ -1468,11 +1468,8 @@ clutter_actor_real_map (ClutterActor *self) */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]); - accessible = clutter_actor_get_accessible (self); - if (accessible && !clutter_actor_is_painting_unmapped (self)) - atk_object_notify_state_change (accessible, - ATK_STATE_SHOWING, - TRUE); + if (!clutter_actor_is_painting_unmapped (self)) + clutter_actor_add_accessible_state (self, ATK_STATE_SHOWING); for (iter = priv->first_child; iter != NULL; @@ -1542,6 +1539,7 @@ maybe_unset_key_focus (ClutterActor *self) return; clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL); + clutter_actor_remove_accessible_state (self, ATK_STATE_FOCUSED); } static void @@ -1573,7 +1571,6 @@ clutter_actor_real_unmap (ClutterActor *self) { ClutterActorPrivate *priv = self->priv; ClutterActor *iter; - AtkObject *accessible; g_assert (clutter_actor_is_mapped (self)); @@ -1605,11 +1602,8 @@ clutter_actor_real_unmap (ClutterActor *self) */ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]); - accessible = clutter_actor_get_accessible (self); - if (accessible && !clutter_actor_is_painting_unmapped (self)) - atk_object_notify_state_change (accessible, - ATK_STATE_SHOWING, - FALSE); + if (!clutter_actor_is_painting_unmapped (self)) + clutter_actor_remove_accessible_state (self, ATK_STATE_SHOWING); if (priv->n_pointers > 0) { @@ -1744,7 +1738,6 @@ void clutter_actor_show (ClutterActor *self) { ClutterActorPrivate *priv; - AtkObject *accessible; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -1782,11 +1775,7 @@ clutter_actor_show (ClutterActor *self) g_signal_emit (self, actor_signals[SHOW], 0); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]); - accessible = clutter_actor_get_accessible (self); - if (accessible) - atk_object_notify_state_change (accessible, - ATK_STATE_VISIBLE, - TRUE); + clutter_actor_add_accessible_state (self, ATK_STATE_VISIBLE); if (priv->parent != NULL) clutter_actor_queue_redraw (self); @@ -1842,7 +1831,6 @@ void clutter_actor_hide (ClutterActor *self) { ClutterActorPrivate *priv; - AtkObject *accessible; g_return_if_fail (CLUTTER_IS_ACTOR (self)); @@ -1880,12 +1868,7 @@ clutter_actor_hide (ClutterActor *self) g_signal_emit (self, actor_signals[HIDE], 0); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]); - accessible = clutter_actor_get_accessible (self); - if (accessible) - atk_object_notify_state_change (accessible, - ATK_STATE_VISIBLE, - FALSE); - + clutter_actor_remove_accessible_state (self, ATK_STATE_VISIBLE); if (priv->parent != NULL && priv->needs_allocation) clutter_actor_queue_redraw (priv->parent); @@ -5423,6 +5406,7 @@ clutter_actor_finalize (GObject *object) g_free (priv->name); g_free (priv->debug_name); + g_clear_object (&priv->accessible_state); G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object); } @@ -11878,7 +11862,6 @@ clutter_actor_set_reactive (ClutterActor *actor, gboolean reactive) { ClutterActorPrivate *priv; - AtkObject *accessible; g_return_if_fail (CLUTTER_IS_ACTOR (actor)); @@ -11894,11 +11877,16 @@ clutter_actor_set_reactive (ClutterActor *actor, g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]); - accessible = clutter_actor_get_accessible (actor); - if (accessible) - atk_object_notify_state_change (accessible, - ATK_STATE_SENSITIVE, - reactive); + if (reactive) + { + clutter_actor_add_accessible_state (actor, ATK_STATE_SENSITIVE); + clutter_actor_add_accessible_state (actor, ATK_STATE_ENABLED); + } + else + { + clutter_actor_remove_accessible_state (actor, ATK_STATE_SENSITIVE); + clutter_actor_remove_accessible_state (actor, ATK_STATE_ENABLED); + } if (!clutter_actor_get_reactive (actor) && priv->n_pointers > 0) { @@ -13003,7 +12991,10 @@ clutter_actor_grab_key_focus (ClutterActor *self) stage = _clutter_actor_get_stage_internal (self); if (stage != NULL) - clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self); + { + clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self); + clutter_actor_add_accessible_state (self, ATK_STATE_FOCUSED); + } } #ifdef HAVE_FONTS @@ -18802,3 +18793,84 @@ clutter_actor_get_accessible_role (ClutterActor *self) return role; } + +AtkStateSet * +clutter_actor_get_accessible_state (ClutterActor *actor) +{ + ClutterActorPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); + + priv = clutter_actor_get_instance_private (actor); + + return priv->accessible_state; +} + +/** + * clutter_actor_add_accessible_state: + * @actor: A #ClutterActor + * @state: #AtkStateType state to add + * + * This method adds @state as one of the accessible states for + * @actor. The list of states of an actor describes the current state + * of user interface element @actor and is provided so that assistive + * technologies know how to present @actor to the user. + * + * Usually you will have no need to add accessible states for an + * object, as the accessible object can extract most of the states + * from the object itself. + * This method is only required when one cannot extract the + * information automatically from the object itself (i.e.: a generic + * container used as a toggle menu item will not automatically include + * the toggled state). + */ +void +clutter_actor_add_accessible_state (ClutterActor *actor, + AtkStateType state) +{ + ClutterActorPrivate *priv; + AtkObject *accessible; + + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + priv = clutter_actor_get_instance_private (actor); + accessible = clutter_actor_get_accessible (actor); + + if (G_UNLIKELY (priv->accessible_state == NULL)) + { + priv->accessible_state = atk_state_set_new (); + /* Actors are all focusable until we merge focus management from St */ + atk_state_set_add_state (priv->accessible_state, ATK_STATE_FOCUSABLE); + } + + if (atk_state_set_add_state (priv->accessible_state, state) && accessible) + atk_object_notify_state_change (accessible, state, TRUE); +} + +/** + * clutter_actor_remove_accessible_state: + * @actor: A #ClutterActor + * @state: #AtkState state to remove + * + * This method removes @state as on of the accessible states for + * @actor. See [method@Clutter.Actor.add_accessible_state] for more information. + * + */ +void +clutter_actor_remove_accessible_state (ClutterActor *actor, + AtkStateType state) +{ + ClutterActorPrivate *priv; + AtkObject *accessible; + + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); + + priv = clutter_actor_get_instance_private (actor); + accessible = clutter_actor_get_accessible (actor); + + if (G_UNLIKELY (priv->accessible_state == NULL)) + return; + + if (atk_state_set_remove_state (priv->accessible_state, state) && accessible) + atk_object_notify_state_change (accessible, state, FALSE); +} diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h index e4e9938f8..917ee83e1 100644 --- a/clutter/clutter/clutter-actor.h +++ b/clutter/clutter/clutter-actor.h @@ -323,6 +323,12 @@ CLUTTER_EXPORT void clutter_actor_set_accessible (ClutterActor *self, AtkObject *accessible); CLUTTER_EXPORT +void clutter_actor_add_accessible_state (ClutterActor *actor, + AtkStateType state); +CLUTTER_EXPORT +void clutter_actor_remove_accessible_state (ClutterActor *actor, + AtkStateType state); +CLUTTER_EXPORT gboolean clutter_actor_is_visible (ClutterActor *self); CLUTTER_EXPORT gboolean clutter_actor_is_mapped (ClutterActor *self); diff --git a/clutter/clutter/clutter-stage-accessible.c b/clutter/clutter/clutter-stage-accessible.c index 42d759d9e..82e67d361 100644 --- a/clutter/clutter/clutter-stage-accessible.c +++ b/clutter/clutter/clutter-stage-accessible.c @@ -55,28 +55,6 @@ clutter_stage_accessible_init (ClutterStageAccessible *stage_accessible) { } -static AtkStateSet* -clutter_stage_accessible_ref_state_set (AtkObject *obj) -{ - ClutterStageAccessible *stage_accessible; - AtkStateSet *state_set; - ClutterStage *stage; - - g_return_val_if_fail (CLUTTER_IS_STAGE_ACCESSIBLE (obj), NULL); - stage_accessible = CLUTTER_STAGE_ACCESSIBLE (obj); - - state_set = ATK_OBJECT_CLASS (clutter_stage_accessible_parent_class)->ref_state_set (obj); - stage = CLUTTER_STAGE (CLUTTER_ACTOR_FROM_ACCESSIBLE (stage_accessible)); - - if (stage == NULL) - return state_set; - - if (clutter_stage_is_active (stage)) - atk_state_set_add_state (state_set, ATK_STATE_ACTIVE); - - return state_set; -} - /* AtkWindow */ static void clutter_stage_accessible_window_interface_init (AtkWindowIface *iface) @@ -87,8 +65,4 @@ clutter_stage_accessible_window_interface_init (AtkWindowIface *iface) static void clutter_stage_accessible_class_init (ClutterStageAccessibleClass *klass) { - AtkObjectClass *class = ATK_OBJECT_CLASS (klass); - - /* AtkObject */ - class->ref_state_set = clutter_stage_accessible_ref_state_set; } diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 10d4d76e3..c75e6fe9a 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -691,12 +691,17 @@ clutter_stage_set_active (ClutterStage *stage, return; priv->is_active = is_active; + + if (is_active) + clutter_actor_add_accessible_state (CLUTTER_ACTOR (stage), + ATK_STATE_ACTIVE); + else + clutter_actor_remove_accessible_state (CLUTTER_ACTOR (stage), + ATK_STATE_ACTIVE); + accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); if (accessible) { - atk_object_notify_state_change (accessible, - ATK_STATE_ACTIVE, - priv->is_active); /* Emit AtkWindow signals */ if (priv->is_active) g_signal_emit_by_name (accessible, "activate", 0); diff --git a/clutter/clutter/pango/clutter-text-accessible.c b/clutter/clutter/pango/clutter-text-accessible.c index e93da8b54..321282300 100644 --- a/clutter/clutter/pango/clutter-text-accessible.c +++ b/clutter/clutter/pango/clutter-text-accessible.c @@ -48,8 +48,6 @@ static void cally_text_finalize (GObject *obj); /* AtkObject */ static void cally_text_real_initialize (AtkObject *obj, gpointer data); -static AtkStateSet* cally_text_ref_state_set (AtkObject *obj); - /* atkaction */ static void _cally_text_activate_action (ClutterActorAccessible *accessible_actor); @@ -246,7 +244,6 @@ clutter_text_accessible_class_init (ClutterTextAccessibleClass *klass) gobject_class->finalize = cally_text_finalize; class->initialize = cally_text_real_initialize; - class->ref_state_set = cally_text_ref_state_set; } static void @@ -317,28 +314,6 @@ cally_text_real_initialize(AtkObject *obj, atk_object_set_role (obj, ATK_ROLE_TEXT); } -static AtkStateSet* -cally_text_ref_state_set (AtkObject *obj) -{ - AtkStateSet *result = NULL; - ClutterActor *actor = NULL; - - result = ATK_OBJECT_CLASS (clutter_text_accessible_parent_class)->ref_state_set (obj); - - actor = CLUTTER_ACTOR_FROM_ACCESSIBLE (obj); - - if (actor == NULL) - return result; - - if (clutter_text_get_editable (CLUTTER_TEXT (actor))) - atk_state_set_add_state (result, ATK_STATE_EDITABLE); - - if (clutter_text_get_selectable (CLUTTER_TEXT (actor))) - atk_state_set_add_state (result, ATK_STATE_SELECTABLE_TEXT); - - return result; -} - /***** pango stuff **** * * FIXME: all this pango related code used to implement diff --git a/clutter/clutter/pango/clutter-text.c b/clutter/clutter/pango/clutter-text.c index 416fbc6dd..01c389ef9 100644 --- a/clutter/clutter/pango/clutter-text.c +++ b/clutter/clutter/pango/clutter-text.c @@ -4856,7 +4856,6 @@ clutter_text_set_editable (ClutterText *self, ClutterBackend *backend = clutter_context_get_backend (context); ClutterInputMethod *method = clutter_backend_get_input_method (backend); ClutterTextPrivate *priv; - AtkObject *accessible; g_return_if_fail (CLUTTER_IS_TEXT (self)); @@ -4864,7 +4863,6 @@ clutter_text_set_editable (ClutterText *self, if (priv->editable != editable) { - accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (self)); priv->editable = editable; if (method) @@ -4878,10 +4876,12 @@ clutter_text_set_editable (ClutterText *self, clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]); - if (accessible) - atk_object_notify_state_change (accessible, - ATK_STATE_EDITABLE, - priv->editable); + if (editable) + clutter_actor_add_accessible_state (CLUTTER_ACTOR (self), + ATK_STATE_EDITABLE); + else + clutter_actor_remove_accessible_state (CLUTTER_ACTOR (self), + ATK_STATE_EDITABLE); } } @@ -4931,6 +4931,12 @@ clutter_text_set_selectable (ClutterText *self, clutter_text_queue_redraw (CLUTTER_ACTOR (self)); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTABLE]); + if (selectable) + clutter_actor_add_accessible_state (CLUTTER_ACTOR (self), + ATK_STATE_SELECTABLE_TEXT); + else + clutter_actor_remove_accessible_state (CLUTTER_ACTOR (self), + ATK_STATE_SELECTABLE_TEXT); } }