a11y: Add utilify method for text attributes

Simplify the AT-SPI implementation by having a convenience function to
extract the text attributes of a GtkAccessibleText, with or without the
default attributes.
This commit is contained in:
Emmanuele Bassi 2024-03-05 12:23:17 +00:00
parent 9aa90f8df0
commit 0626246367
3 changed files with 142 additions and 30 deletions

View File

@ -225,56 +225,42 @@ accessible_text_handle_method (GDBusConnection *connection,
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
gboolean include_defaults = FALSE;
int offset;
gsize n_attrs = 0;
gsize n_ranges = 0;
GtkAccessibleTextRange *ranges = NULL;
int start, end;
char **attr_names = NULL;
char **attr_values = NULL;
GHashTable *attrs;
gboolean res;
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
if (include_defaults)
res = gtk_accessible_text_get_attributes_run (accessible_text,
offset,
include_defaults,
&n_ranges,
&ranges,
&attr_names,
&attr_values);
if (!res)
{
gtk_accessible_text_get_default_attributes (accessible_text,
&attr_names,
&attr_values);
for (int i = 0; attr_names[i] != NULL; i++)
g_hash_table_insert (attrs, g_strdup (attr_names[i]), g_strdup (attr_values[i]));
g_strfreev (attr_names);
g_strfreev (attr_values);
/* No attributes */
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, 0, 0));
return;
}
gtk_accessible_text_get_attributes (accessible_text,
offset,
&n_attrs,
&ranges,
&attr_names,
&attr_values);
for (unsigned i = 0; attr_names[i] != NULL; i++)
g_variant_builder_add (&builder, "{ss}", attr_names[i], attr_values[i]);
start = 0;
end = G_MAXINT;
for (int i = 0; i < n_attrs; i++)
for (unsigned i = 0; i < n_ranges; i++)
{
g_hash_table_insert (attrs, g_strdup (attr_names[i]), g_strdup (attr_values[i]));
start = MAX (start, ranges[i].start);
end = MIN (end, start + ranges[i].length);
}
GHashTableIter attr_iter;
gpointer key, value;
g_hash_table_iter_init (&attr_iter, attrs);
while (g_hash_table_iter_next (&attr_iter, &key, &value))
g_variant_builder_add (&builder, "{ss}", key, value);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
g_clear_pointer (&attrs, g_hash_table_unref);
g_clear_pointer (&ranges, g_free);
g_strfreev (attr_names);
g_strfreev (attr_values);

View File

@ -309,6 +309,123 @@ gtk_accessible_text_get_default_attributes (GtkAccessibleText *self,
attribute_values);
}
/*< private >
* gtk_accessible_text_get_attributes_run:
* @self: the accessible object
* @offset: the offset, in characters
* @include_defaults: whether to include the default attributes in the
* returned array
* @n_ranges: (out): the number of attributes
* @ranges: (out) (array length=n_attributes) (optional): the ranges of the attributes
* inside the accessible object
* @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
* the names of the attributes inside the accessible object
* @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
* the values of the attributes inside the accessible object
*
* Retrieves the text attributes inside the accessible object.
*
* Each attribute is composed by:
*
* - a range
* - a name, typically in the form of a reverse DNS identifier
* - a value
*
* If this function returns true, `n_ranges` will be set to a value
* greater than or equal to one, @ranges will be set to a newly
* allocated array of [struct#Gtk.AccessibleTextRange] which should
* be freed with g_free(), @attribute_names and @attribute_values
* will be set to string arrays that should be freed with g_strfreev().
*
* Returns: true if the accessible object has at least an attribute,
* and false otherwise
*
* Since: 4.14
*/
gboolean
gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
unsigned int offset,
gboolean include_defaults,
gsize *n_ranges,
GtkAccessibleTextRange **ranges,
char ***attribute_names,
char ***attribute_values)
{
GHashTable *attrs;
GHashTableIter attr_iter;
gpointer key, value;
char **attr_names, **attr_values;
gboolean res;
GStrvBuilder *names_builder;
GStrvBuilder *values_builder;
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
if (include_defaults)
{
gtk_accessible_text_get_default_attributes (self,
&attr_names,
&attr_values);
for (unsigned i = 0; attr_names[i] != NULL; i++)
{
g_hash_table_insert (attrs,
g_steal_pointer (&attr_names[i]),
g_steal_pointer (&attr_values[i]));
}
g_free (attr_names);
g_free (attr_values);
}
res = gtk_accessible_text_get_attributes (self,
offset,
n_ranges,
ranges,
&attr_names,
&attr_values);
/* If there are no attributes, we can bail out early */
if (!res && !include_defaults)
{
g_hash_table_unref (attrs);
*attribute_names = NULL;
*attribute_values = NULL;
return FALSE;
}
/* The text attributes override the default ones */
for (unsigned i = 0; i < *n_ranges; i++)
{
g_hash_table_insert (attrs,
g_steal_pointer (&attr_names[i]),
g_steal_pointer (&attr_values[i]));
}
g_free (attr_names);
g_free (attr_values);
names_builder = g_strv_builder_new ();
values_builder = g_strv_builder_new ();
g_hash_table_iter_init (&attr_iter, attrs);
while (g_hash_table_iter_next (&attr_iter, &key, &value))
{
g_strv_builder_add (names_builder, key);
g_strv_builder_add (values_builder, value);
}
*attribute_names = g_strv_builder_end (names_builder);
*attribute_values = g_strv_builder_end (values_builder);
g_strv_builder_unref (names_builder);
g_strv_builder_unref (values_builder);
g_hash_table_unref (attrs);
return TRUE;
}
/**
* gtk_accessible_text_update_caret_position:
* @self: the accessible object

View File

@ -43,4 +43,13 @@ gtk_accessible_text_get_default_attributes (GtkAccessibleText *self,
char ***attribute_names,
char ***attribute_values);
gboolean
gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
unsigned int offset,
gboolean include_defaults,
gsize *n_ranges,
GtkAccessibleTextRange **ranges,
char ***attribute_names,
char ***attribute_values);
G_END_DECLS