/* gtkaccessible.c: Accessible interface * * Copyright 2020 GNOME Foundation * * SPDX-License-Identifier: LGPL-2.1-or-later * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ /** * SECTION:gtkaccessible * @Title: GtkAccessible * @Short_description: Accessible interface * * GtkAccessible provides an interface for describing a UI element, like a * #GtkWidget, in a way that can be consumed by Assistive Technologies, or * “AT”. Every accessible implementation has: * * - a “role”, represented by a value of the #GtkAccessibleRole enumeration * - an “attribute”, represented by a set of #GtkAccessibleState, * #GtkAccessibleProperty and #GtkAccessibleRelation values * * The role cannot be changed after instantiating a #GtkAccessible * implementation. * * The attributes are updated every time a UI element's state changes in a way that * should be reflected by assistive technologies. For instance, if a #GtkWidget * visibility changes, the %GTK_ACCESSIBLE_STATE_HIDDEN state will also change * to reflect the #GtkWidget:visible property. */ #include "config.h" #include "gtkaccessibleprivate.h" #include "gtkatcontextprivate.h" #include "gtkenums.h" #include "gtktypebuiltins.h" #include G_DEFINE_INTERFACE (GtkAccessible, gtk_accessible, G_TYPE_OBJECT) static void gtk_accessible_default_init (GtkAccessibleInterface *iface) { /** * GtkAccessible:accessible-role: * * The accessible role of the given #GtkAccessible implementation. * * The accessible role cannot be changed once set. */ GParamSpec *pspec = g_param_spec_enum ("accessible-role", "Accessible Role", "The role of the accessible object", GTK_TYPE_ACCESSIBLE_ROLE, GTK_ACCESSIBLE_ROLE_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, pspec); } /*< private > * gtk_accessible_get_at_context: * @self: a #GtkAccessible * * Retrieves the #GtkATContext for the given #GtkAccessible. * * Returns: (transfer none): the #GtkATContext */ GtkATContext * gtk_accessible_get_at_context (GtkAccessible *self) { g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL); return GTK_ACCESSIBLE_GET_IFACE (self)->get_at_context (self); } /** * gtk_accessible_get_accessible_role: * @self: a #GtkAccessible * * Retrieves the #GtkAccessibleRole for the given #GtkAccessible. * * Returns: a #GtkAccessibleRole */ GtkAccessibleRole gtk_accessible_get_accessible_role (GtkAccessible *self) { g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_NONE); GtkATContext *context = gtk_accessible_get_at_context (self); if (context == NULL) return GTK_ACCESSIBLE_ROLE_NONE; return gtk_at_context_get_accessible_role (context); } /** * gtk_accessible_update_state: * @self: a #GtkAccessible * @first_state: the first #GtkAccessibleState * @...: a list of state and value pairs, terminated by -1 * * Updates a list of accessible states. See the #GtkAccessibleState * documentation for the value types of accessible states. * * This function should be called by #GtkWidget types whenever an accessible * state change must be communicated to assistive technologies. * * Example: * |[ * value = GTK_ACCESSIBLE_TRISTATE_MIXED; * gtk_accessible_update_state (GTK_ACCESSIBLE (check_button), * GTK_ACCESSIBLE_STATE_CHECKED, value, * -1); * ]| */ void gtk_accessible_update_state (GtkAccessible *self, GtkAccessibleState first_state, ...) { GtkAccessibleState state; GtkATContext *context; va_list args; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; va_start (args, first_state); state = first_state; while (state != -1) { GError *error = NULL; GtkAccessibleValue *value = gtk_accessible_value_collect_for_state (state, &error, &args); if (error != NULL) { g_critical ("Unable to collect value for state “%s”: %s", gtk_accessible_state_get_attribute_name (state), error->message); g_error_free (error); goto out; } gtk_at_context_set_accessible_state (context, state, value); if (value != NULL) gtk_accessible_value_unref (value); state = va_arg (args, int); } gtk_at_context_update (context); out: va_end (args); } /** * gtk_accessible_update_state_value: (rename-to gtk_accessible_update_state) * @self: a #GtkAccessible * @n_states: the number of accessible states to set * @states: (array length=n_states): an array of #GtkAccessibleState * @values: (array length=n_states): an array of #GValues, one for each state * * Updates an array of accessible states. * * This function should be called by #GtkWidget types whenever an accessible * state change must be communicated to assistive technologies. * * This function is meant to be used by language bindings. */ void gtk_accessible_update_state_value (GtkAccessible *self, int n_states, GtkAccessibleState states[], const GValue values[]) { g_return_if_fail (GTK_IS_ACCESSIBLE (self)); g_return_if_fail (n_states > 0); GtkATContext *context = gtk_accessible_get_at_context (self); if (context == NULL) return; for (int i = 0; i < n_states; i++) { GtkAccessibleState state = states[i]; const GValue *value = &(values[i]); GError *error = NULL; GtkAccessibleValue *real_value = gtk_accessible_value_collect_for_state_value (state, value, &error); if (error != NULL) { g_critical ("Unable to collect the value for state “%s”: %s", gtk_accessible_state_get_attribute_name (state), error->message); g_error_free (error); break; } gtk_at_context_set_accessible_state (context, state, real_value); if (real_value != NULL) gtk_accessible_value_unref (real_value); } gtk_at_context_update (context); } /** * gtk_accessible_reset_state: * @self: a #GtkAccessible * @state: a #GtkAccessibleState * * Resets the accessible @state to its default value. */ void gtk_accessible_reset_state (GtkAccessible *self, GtkAccessibleState state) { GtkATContext *context; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; gtk_at_context_set_accessible_state (context, state, NULL); gtk_at_context_update (context); } /** * gtk_accessible_update_property: * @self: a #GtkAccessible * @first_property: the first #GtkAccessibleProperty * @...: a list of property and value pairs, terminated by -1 * * Updates a list of accessible properties. See the #GtkAccessibleProperty * documentation for the value types of accessible properties. * * This function should be called by #GtkWidget types whenever an accessible * property change must be communicated to assistive technologies. * * Example: * |[ * value = gtk_adjustment_get_value (adjustment); * gtk_accessible_update_property (GTK_ACCESSIBLE (spin_button), GTK_ACCESSIBLE_PROPERTY_VALUE_NOW, value, -1); * ]| */ void gtk_accessible_update_property (GtkAccessible *self, GtkAccessibleProperty first_property, ...) { GtkAccessibleProperty property; GtkATContext *context; va_list args; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; va_start (args, first_property); property = first_property; while (property != -1) { GError *error = NULL; GtkAccessibleValue *value = gtk_accessible_value_collect_for_property (property, &error, &args); if (error != NULL) { g_critical ("Unable to collect the value for property “%s”: %s", gtk_accessible_property_get_attribute_name (property), error->message); g_error_free (error); goto out; } gtk_at_context_set_accessible_property (context, property, value); if (value != NULL) gtk_accessible_value_unref (value); property = va_arg (args, int); } gtk_at_context_update (context); out: va_end (args); } /** * gtk_accessible_update_property_value: (rename-to gtk_accessible_update_property) * @self: a #GtkAccessible * @n_properties: the number of accessible properties to set * @properties: (array length=n_properties): an array of #GtkAccessibleProperty * @values: (array length=n_properties): an array of #GValues, one for each property * * Updates an array of accessible properties. * * This function should be called by #GtkWidget types whenever an accessible * property change must be communicated to assistive technologies. * * This function is meant to be used by language bindings. */ void gtk_accessible_update_property_value (GtkAccessible *self, int n_properties, GtkAccessibleProperty properties[], const GValue values[]) { g_return_if_fail (GTK_IS_ACCESSIBLE (self)); g_return_if_fail (n_properties > 0); GtkATContext *context = gtk_accessible_get_at_context (self); if (context == NULL) return; for (int i = 0; i < n_properties; i++) { GtkAccessibleProperty property = properties[i]; const GValue *value = &(values[i]); GError *error = NULL; GtkAccessibleValue *real_value = gtk_accessible_value_collect_for_property_value (property, value, &error); if (error != NULL) { g_critical ("Unable to collect the value for property “%s”: %s", gtk_accessible_property_get_attribute_name (property), error->message); g_error_free (error); break; } gtk_at_context_set_accessible_property (context, property, real_value); if (real_value != NULL) gtk_accessible_value_unref (real_value); } gtk_at_context_update (context); } /** * gtk_accessible_reset_property: * @self: a #GtkAccessible * @property: a #GtkAccessibleProperty * * Resets the accessible @property to its default value. */ void gtk_accessible_reset_property (GtkAccessible *self, GtkAccessibleProperty property) { GtkATContext *context; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; gtk_at_context_set_accessible_property (context, property, NULL); gtk_at_context_update (context); } /** * gtk_accessible_update_relation: * @self: a #GtkAccessible * @first_relation: the first #GtkAccessibleRelation * @...: a list of relation and value pairs, terminated by -1 * * Updates a list of accessible relations. * * This function should be called by #GtkWidget types whenever an accessible * relation change must be communicated to assistive technologies. */ void gtk_accessible_update_relation (GtkAccessible *self, GtkAccessibleRelation first_relation, ...) { GtkAccessibleRelation relation; GtkATContext *context; va_list args; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; va_start (args, first_relation); relation = first_relation; while (relation != -1) { GError *error = NULL; GtkAccessibleValue *value = gtk_accessible_value_collect_for_relation (relation, &error, &args); if (error != NULL) { g_critical ("Unable to collect the value for relation “%s”: %s", gtk_accessible_relation_get_attribute_name (relation), error->message); g_error_free (error); goto out; } gtk_at_context_set_accessible_relation (context, relation, value); if (value != NULL) gtk_accessible_value_unref (value); relation = va_arg (args, int); } gtk_at_context_update (context); out: va_end (args); } /** * gtk_accessible_update_relation_value: (rename-to gtk_accessible_update_relation) * @self: a #GtkAccessible * @n_relations: the number of accessible relations to set * @relations: (array length=n_relations): an array of #GtkAccessibleRelation * @values: (array length=n_relations): an array of #GValues, one for each relation * * Updates an array of accessible relations. * * This function should be called by #GtkWidget types whenever an accessible * relation change must be communicated to assistive technologies. * * This function is meant to be used by language bindings. */ void gtk_accessible_update_relation_value (GtkAccessible *self, int n_relations, GtkAccessibleRelation relations[], const GValue values[]) { g_return_if_fail (GTK_IS_ACCESSIBLE (self)); g_return_if_fail (n_relations > 0); GtkATContext *context = gtk_accessible_get_at_context (self); if (context == NULL) return; for (int i = 0; i < n_relations; i++) { GtkAccessibleRelation relation = relations[i]; const GValue *value = &(values[i]); GError *error = NULL; GtkAccessibleValue *real_value = gtk_accessible_value_collect_for_relation_value (relation, value, &error); if (error != NULL) { g_critical ("Unable to collect the value for relation “%s”: %s", gtk_accessible_relation_get_attribute_name (relation), error->message); g_error_free (error); break; } gtk_at_context_set_accessible_relation (context, relation, real_value); if (real_value != NULL) gtk_accessible_value_unref (real_value); } gtk_at_context_update (context); } /** * gtk_accessible_reset_relation: * @self: a #GtkAccessible * @relation: a #GtkAccessibleRelation * * Resets the accessible @relation to its default value. */ void gtk_accessible_reset_relation (GtkAccessible *self, GtkAccessibleRelation relation) { GtkATContext *context; g_return_if_fail (GTK_IS_ACCESSIBLE (self)); context = gtk_accessible_get_at_context (self); if (context == NULL) return; gtk_at_context_set_accessible_relation (context, relation, NULL); gtk_at_context_update (context); }