clutter: Add accessible state tracking
Currently, this has been living in StWidget, moving that to Clutter allows us to properly track the accessibility state changes in the actors provided inside Clutter as well as simplifying things for a future move from Atk. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4089>
This commit is contained in:
parent
a211ed553b
commit
9d72f658af
@ -356,54 +356,34 @@ 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;
|
||||
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);
|
||||
|
||||
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 (actor_state)
|
||||
combined_state = atk_state_set_or_sets (parent_state,
|
||||
actor_state);
|
||||
else
|
||||
combined_state = g_steal_pointer (&parent_state);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return state_set;
|
||||
return combined_state;
|
||||
}
|
||||
|
||||
static gint
|
||||
|
@ -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
|
||||
|
@ -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_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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user