From db05ef9c63a73bc5d3fba947f27e0c0b6589a661 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 2 Aug 2024 19:37:11 +0200 Subject: [PATCH] clutter/actor: Move few accessible bits from StWidget As they are better fit in ClutterActor The accessible_role is intentionally put in the public fields as ClutterActorAccessible needs access to that without going in recursion Part-of: --- clutter/clutter/clutter-actor-accessible.c | 48 +++++- clutter/clutter/clutter-actor.c | 172 ++++++++++++++++++++- clutter/clutter/clutter-actor.h | 11 ++ 3 files changed, 225 insertions(+), 6 deletions(-) diff --git a/clutter/clutter/clutter-actor-accessible.c b/clutter/clutter/clutter-actor-accessible.c index 374d2470d..3fa110fe0 100644 --- a/clutter/clutter/clutter-actor-accessible.c +++ b/clutter/clutter/clutter-actor-accessible.c @@ -27,7 +27,7 @@ * * Implementation of the ATK interfaces for [class@Clutter.Actor] * - * #ClutterAccessible implements the required ATK interfaces of [class@Clutter.Actor] + * #ClutterActorAccessible implements the required ATK interfaces of [class@Clutter.Actor] * exposing the common elements on each actor (position, extents, etc). */ @@ -57,7 +57,7 @@ * buttons. So in this environment, it doesn't make sense to keep * adding them as default. * - * Anyway, current implementation of AtkAction is done at ClutterAccessible + * Anyway, current implementation of AtkAction is done at ClutterActorAccessible * providing methods to add and remove actions. This is based on the * one used at gailcell, and proposed as a change on #AtkAction * interface: @@ -70,6 +70,7 @@ #include +#include #include #include "clutter/clutter-actor-private.h" @@ -161,6 +162,45 @@ clutter_actor_accessible_initialize (AtkObject *obj, interface would be a panel */ } +/* AtkObject */ +static const gchar * +clutter_actor_accessible_get_name (AtkObject *obj) +{ + const gchar* name = NULL; + ClutterActor *actor; + + g_return_val_if_fail (CLUTTER_IS_ACTOR_ACCESSIBLE (obj), NULL); + + actor = CLUTTER_ACTOR_FROM_ACCESSIBLE (obj); + if (actor) + name = clutter_actor_get_accessible_name (actor); + + if (!name) + name = ATK_OBJECT_CLASS (clutter_actor_accessible_parent_class)->get_name (obj); + + return name; +} + +static AtkRole +clutter_actor_accessible_get_role (AtkObject *obj) +{ + ClutterActor *actor = NULL; + AtkRole role = ATK_ROLE_INVALID; + + g_return_val_if_fail (CLUTTER_IS_ACTOR_ACCESSIBLE (obj), role); + + actor = CLUTTER_ACTOR_FROM_ACCESSIBLE (obj); + + if (actor == NULL) + return role; + + role = actor->accessible_role; + if (role == ATK_ROLE_INVALID) + role = ATK_OBJECT_CLASS (clutter_actor_accessible_parent_class)->get_role (obj); + + return role; +} + static void clutter_actor_accessible_class_init (ClutterActorAccessibleClass *klass) { @@ -171,6 +211,8 @@ clutter_actor_accessible_class_init (ClutterActorAccessibleClass *klass) gobject_class->finalize = clutter_actor_accessible_finalize; /* AtkObject */ + class->get_role = clutter_actor_accessible_get_role; + class->get_name = clutter_actor_accessible_get_name; class->get_parent = clutter_actor_accessible_get_parent; class->get_index_in_parent = clutter_actor_accessible_get_index_in_parent; class->ref_state_set = clutter_actor_accessible_ref_state_set; @@ -204,8 +246,6 @@ clutter_actor_accessible_finalize (GObject *obj) G_OBJECT_CLASS (clutter_actor_accessible_parent_class)->finalize (obj); } -/* AtkObject */ - static AtkObject * clutter_actor_accessible_get_parent (AtkObject *obj) { diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 13e08c712..24d6090c0 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -515,6 +515,7 @@ #include "clutter/clutter-stage-view-private.h" #include "clutter/clutter-timeline.h" #include "clutter/clutter-transition.h" +#include "glib-object.h" static const CoglColor transparent = { 0x00, 0x00, 0x00, 0x00 }; @@ -547,6 +548,7 @@ struct _ClutterActorPrivate /* Accessibility */ AtkObject *accessible; + gchar *accessible_name; /* request mode */ ClutterRequestMode request_mode; @@ -853,6 +855,10 @@ enum PROP_COLOR_STATE, + /* Accessible */ + PROP_ACCESSIBLE_ROLE, + PROP_ACCESSIBLE_NAME, + PROP_LAST }; @@ -4843,6 +4849,14 @@ clutter_actor_set_property (GObject *object, clutter_actor_set_color_state_internal (actor, g_value_get_object (value)); break; + case PROP_ACCESSIBLE_ROLE: + clutter_actor_set_accessible_role (actor, g_value_get_enum (value)); + break; + + case PROP_ACCESSIBLE_NAME: + clutter_actor_set_accessible_name (actor, g_value_get_string (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -5300,6 +5314,14 @@ clutter_actor_get_property (GObject *object, g_value_set_object (value, priv->color_state); break; + case PROP_ACCESSIBLE_ROLE: + g_value_set_enum (value, clutter_actor_get_accessible_role (actor)); + break; + + case PROP_ACCESSIBLE_NAME: + g_value_set_string (value, priv->accessible_name); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -5345,6 +5367,8 @@ clutter_actor_dispose (GObject *object) g_clear_signal_handler (&priv->resolution_changed_id, backend); g_clear_signal_handler (&priv->font_changed_id, backend); + g_clear_pointer (&priv->accessible_name, g_free); + g_clear_object (&priv->pango_context); g_clear_object (&priv->actions); g_clear_object (&priv->color_state); @@ -6843,6 +6867,27 @@ clutter_actor_class_init (ClutterActorClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + /** + * ClutterActor:accessible-role: + * + * The accessible role of this object + */ + obj_props[PROP_ACCESSIBLE_ROLE] = + g_param_spec_enum ("accessible-role", NULL, NULL, + ATK_TYPE_ROLE, + ATK_ROLE_INVALID, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY); + + /** + * ClutterActor:accessible-name: + * + * Object instance's name for assistive technology access. + */ + obj_props[PROP_ACCESSIBLE_NAME] = + g_param_spec_string ("accessible-name", NULL, NULL, + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, PROP_LAST, obj_props); /** @@ -18440,8 +18485,7 @@ clutter_actor_has_accessible (ClutterActor *actor) * @accessible: an accessible * * This method allows to set a customly created accessible object to - * this widget. For example if you define a new subclass of - * #StWidgetAccessible at the javascript code. + * this widget * * NULL is a valid value for @accessible. That contemplates the * hypothetical case of not needing anymore a custom accessible object @@ -18687,3 +18731,127 @@ clutter_actor_class_get_layout_manager_type (ClutterActorClass *actor_class) return actor_class->layout_manager_type; } + +/** + * clutter_actor_set_accessible_name: + * @self: widget to set the accessible name for + * @name: (nullable): a character string to be set as the accessible name + * + * This method sets @name as the accessible name for @self. + * + * Usually you will have no need to set the accessible name for an + * object, as usually there is a label for most of the interface + * elements. + */ +void +clutter_actor_set_accessible_name (ClutterActor *self, + const gchar *name) +{ + ClutterActorPrivate *priv; + AtkObject *accessible; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + priv = self->priv; + if (g_strcmp0 (name, priv->accessible_name) == 0) + return; + + if (priv->accessible_name != NULL) + g_free (priv->accessible_name); + + accessible = clutter_actor_get_accessible (self); + priv->accessible_name = g_strdup (name); + + if (accessible) + g_object_notify (G_OBJECT (accessible), "accessible-name"); + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACCESSIBLE_NAME]); +} + +/** + * clutter_actor_get_accessible_name: + * @self: widget to get the accessible name for + * + * Gets the accessible name for this widget. See + * clutter_actor_set_accessible_name() for more information. + * + * Returns: a character string representing the accessible name + * of the widget. + */ +const gchar * +clutter_actor_get_accessible_name (ClutterActor *actor) +{ + g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL); + + return actor->priv->accessible_name; +} + +/** + * clutter_actor_set_accessible_role: + * @self: widget to set the accessible role for + * @role: The role to use + * + * This method sets @role as the accessible role for @self. This + * role describes what kind of user interface element @self is and + * is provided so that assistive technologies know how to present + * @self to the user. + * + * Usually you will have no need to set the accessible role for an + * object, as this information is extracted from the context of the + * object (ie: a #StButton has by default a push button role). This + * method is only required when you need to redefine the role + * currently associated with the widget, for instance if it is being + * used in an unusual way (ie: a #StButton used as a togglebutton), or + * if a generic object is used directly (ie: a container as a menu + * item). + * + * If @role is #ATK_ROLE_INVALID, the role will not be changed + * and the accessible's default role will be used instead. + */ +void +clutter_actor_set_accessible_role (ClutterActor *self, + AtkRole role) +{ + AtkObject *accessible; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + if (self->accessible_role == role) + return; + + accessible = clutter_actor_get_accessible (self); + self->accessible_role = role; + + if (accessible) + g_object_notify (G_OBJECT (accessible), "accessible-role"); + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACCESSIBLE_ROLE]); +} + + +/** + * clutter_actor_get_accessible_role: + * @self: widget to get the accessible role for + * + * Gets the #AtkRole for this widget. See + * clutter_actor_set_accessible_role() for more information. + * + * Returns: accessible #AtkRole for this widget + */ +AtkRole +clutter_actor_get_accessible_role (ClutterActor *self) +{ + AtkRole role = ATK_ROLE_INVALID; + AtkObject *accessible; + + g_return_val_if_fail (CLUTTER_IS_ACTOR (self), role); + + accessible = clutter_actor_get_accessible (self); + + if (self->accessible_role != ATK_ROLE_INVALID) + role = self->accessible_role; + else if (accessible != NULL) + role = atk_object_get_role (accessible); + + return role; +} diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h index 5e693e406..d03355709 100644 --- a/clutter/clutter/clutter-actor.h +++ b/clutter/clutter/clutter-actor.h @@ -64,6 +64,7 @@ struct _ClutterActor /*< public >*/ guint32 flags; + AtkRole accessible_role; /*< private >*/ guint32 private_flags; @@ -309,6 +310,16 @@ void clutter_actor_set_name CLUTTER_EXPORT const gchar * clutter_actor_get_name (ClutterActor *self); CLUTTER_EXPORT +void clutter_actor_set_accessible_role (ClutterActor *self, + AtkRole role); +CLUTTER_EXPORT +AtkRole clutter_actor_get_accessible_role (ClutterActor *self); +CLUTTER_EXPORT +void clutter_actor_set_accessible_name (ClutterActor *self, + const gchar *name); +CLUTTER_EXPORT +const gchar * clutter_actor_get_accessible_name (ClutterActor *self); +CLUTTER_EXPORT AtkObject * clutter_actor_get_accessible (ClutterActor *self); CLUTTER_EXPORT gboolean clutter_actor_has_accessible (ClutterActor *self);