a11y: Translate GtkAccessibleText to AT-SPI

Handle GtkAccessibleText in our translation layer, as far as
possible.
This commit is contained in:
Matthias Clasen 2024-02-01 12:56:04 +01:00
parent 610a5d6c0d
commit 10c782b106

View File

@ -41,6 +41,7 @@
#include "gtkspinbuttonprivate.h"
#include "gtktextbufferprivate.h"
#include "gtktextviewprivate.h"
#include "gtkaccessibletext-private.h"
#include <gio/gio.h>
@ -64,6 +65,283 @@ atspi_granularity_to_gtk (AtspiTextGranularity granularity)
}
}
/* {{{ GtkAccessibleText */
static void
accessible_text_handle_method (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
GtkATContext *self = user_data;
GtkAccessible *accessible = gtk_at_context_get_accessible (self);
GtkAccessibleText *accessible_text = GTK_ACCESSIBLE_TEXT (accessible);
if (g_strcmp0 (method_name, "GetCaretOffset") == 0)
{
guint offset;
offset = gtk_accessible_text_get_caret_position (accessible_text);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", (int)offset));
}
else if (g_strcmp0 (method_name, "SetCaretOffset") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetText") == 0)
{
int start, end;
GBytes *contents;
g_variant_get (parameters, "(ii)", &start, &end);
contents = gtk_accessible_text_get_contents (accessible_text, start, end < 0 ? G_MAXUINT : end);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", g_bytes_get_data (contents, NULL)));
g_bytes_unref (contents);
}
else if (g_strcmp0 (method_name, "GetTextBeforeOffset") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
}
else if (g_strcmp0 (method_name, "GetTextAtOffset") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
}
else if (g_strcmp0 (method_name, "GetTextAfterOffset") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This method is deprecated in favor of GetStringAtOffset");
}
else if (g_strcmp0 (method_name, "GetCharacterAtOffset") == 0)
{
int offset;
gunichar ch = 0;
g_variant_get (parameters, "(i)", &offset);
GBytes *text = gtk_accessible_text_get_contents (accessible_text, offset, offset + 1);
if (text != NULL)
{
const char *str = g_bytes_get_data (text, NULL);
if (0 <= offset && offset < g_utf8_strlen (str, -1))
ch = g_utf8_get_char (g_utf8_offset_to_pointer (str, offset));
}
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", ch));
}
else if (g_strcmp0 (method_name, "GetStringAtOffset") == 0)
{
unsigned int start, end;
int offset;
AtspiTextGranularity granularity;
GBytes *bytes;
g_variant_get (parameters, "(iu)", &offset, &granularity);
bytes = gtk_accessible_text_get_contents_at (accessible_text, offset,
atspi_granularity_to_gtk (granularity),
&start, &end);
if (bytes == NULL)
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", "", -1, -1));
else
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", g_bytes_get_data (bytes, NULL), start, end));
g_bytes_unref (bytes);
}
else if (g_strcmp0 (method_name, "GetAttributes") == 0)
{
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
gsize n_attrs = 0;
GtkAccessibleTextRange *ranges = NULL;
int start, end;
char **attr_names = NULL;
char **attr_values = NULL;
g_variant_get (parameters, "(i)", &offset);
gtk_accessible_text_get_attributes (accessible_text,
offset,
&n_attrs,
&ranges,
&attr_names,
&attr_values);
start = 0;
end = G_MAXINT;
for (int i = 0; i < n_attrs; i++)
{
g_variant_builder_add (&builder, "{ss}", attr_names[i], attr_values[i]);
start = MAX (start, ranges[i].start);
end = MIN (end, start + ranges[i].length);
}
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
g_clear_pointer (&ranges, g_free);
g_strfreev (attr_names);
g_strfreev (attr_values);
}
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
{
int offset;
const char *name;
const char *val = "";
char **names, **values;
GtkAccessibleTextRange *ranges;
gsize n_ranges;
g_variant_get (parameters, "(i&s)", &offset, &name);
gtk_accessible_text_get_attributes (accessible_text, offset,
&n_ranges, &ranges,
&names, &values);
for (unsigned i = 0; names[i] != NULL; i++)
{
if (g_strcmp0 (names[i], name) == 0)
{
val = values[i];
break;
}
}
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
g_strfreev (names);
g_strfreev (values);
}
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 ||
g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetNSelections") == 0)
{
gsize n_ranges;
GtkAccessibleTextRange *ranges = NULL;
gtk_accessible_text_get_selection (accessible_text, &n_ranges, &ranges);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", (int)n_ranges));
g_clear_pointer (&ranges, g_free);
}
else if (g_strcmp0 (method_name, "GetSelection") == 0)
{
int num;
gsize n_ranges;
GtkAccessibleTextRange *ranges = NULL;
g_variant_get (parameters, "(i)", &num);
gtk_accessible_text_get_selection (accessible_text, &n_ranges, &ranges);
if (num < 0 || num >= n_ranges)
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Not a valid selection: %d", num);
else
{
int start = ranges[num].start;
int end = start + ranges[num].length;
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ii)", start, end));
}
g_clear_pointer (&ranges, g_free);
}
else if (g_strcmp0 (method_name, "AddSelection") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "RemoveSelection") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "SetSelection") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetCharacterExtents") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetRangeExtents") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "GetBoundedRanges") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "ScrollSubstringTo") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
else if (g_strcmp0 (method_name, "ScrollSubstringToPoint") == 0)
{
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
}
}
static GVariant *
accessible_text_get_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *property_name,
GError **error,
gpointer user_data)
{
GtkATContext *self = user_data;
GtkAccessible *accessible = gtk_at_context_get_accessible (self);
GtkAccessibleText *accessible_text = GTK_ACCESSIBLE_TEXT (accessible);
if (g_strcmp0 (property_name, "CharacterCount") == 0)
{
GBytes *contents;
const char *str;
gsize len;
contents = gtk_accessible_text_get_contents (accessible_text, 0, G_MAXUINT);
str = g_bytes_get_data (contents, NULL);
len = g_utf8_strlen (str, -1);
g_bytes_unref (contents);
return g_variant_new_int32 ((int) len);
}
else if (g_strcmp0 (property_name, "CaretOffset") == 0)
{
guint offset;
offset = gtk_accessible_text_get_caret_position (accessible_text);
return g_variant_new_int32 ((int) offset);
}
return NULL;
}
static const GDBusInterfaceVTable accessible_text_vtable = {
accessible_text_handle_method,
accessible_text_get_property,
NULL,
};
/* }}} */
/* {{{ GtkLabel */
static void
@ -195,7 +473,7 @@ label_handle_method (GDBusConnection *connection,
int offset;
AtspiTextGranularity granularity;
char *string;
int start, end;
unsigned int start, end;
g_variant_get (parameters, "(iu)", &offset, &granularity);
@ -211,7 +489,7 @@ label_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (widget));
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(i)", &offset);
@ -231,7 +509,7 @@ label_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (widget));
int offset;
const char *name;
int start, end;
unsigned int start, end;
const char *val = "";
char **names, **values;
@ -259,7 +537,7 @@ label_handle_method (GDBusConnection *connection,
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
gboolean include_defaults;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
@ -585,7 +863,7 @@ inscription_handle_method (GDBusConnection *connection,
int offset;
AtspiTextGranularity granularity;
char *string;
int start, end;
unsigned int start, end;
g_variant_get (parameters, "(iu)", &offset, &granularity);
@ -601,7 +879,7 @@ inscription_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(i)", &offset);
@ -621,7 +899,7 @@ inscription_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
int offset;
const char *name;
int start, end;
unsigned int start, end;
const char *val = "";
char **names, **values;
@ -649,7 +927,7 @@ inscription_handle_method (GDBusConnection *connection,
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
gboolean include_defaults;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
@ -921,7 +1199,7 @@ editable_handle_method (GDBusConnection *connection,
int offset;
AtspiTextGranularity granularity;
char *string;
int start, end;
unsigned int start, end;
g_variant_get (parameters, "(iu)", &offset, &granularity);
@ -937,7 +1215,7 @@ editable_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_text_get_layout (text_widget);
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(i)", &offset);
@ -957,7 +1235,7 @@ editable_handle_method (GDBusConnection *connection,
PangoLayout *layout = gtk_text_get_layout (text_widget);
int offset;
const char *name;
int start, end;
unsigned int start, end;
const char *val = "";
char **names, **values;
@ -985,7 +1263,7 @@ editable_handle_method (GDBusConnection *connection,
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
gboolean include_defaults;
int start, end;
unsigned int start, end;
char **names, **values;
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
@ -1707,7 +1985,9 @@ static const GDBusInterfaceVTable text_view_vtable = {
const GDBusInterfaceVTable *
gtk_atspi_get_text_vtable (GtkAccessible *accessible)
{
if (GTK_IS_LABEL (accessible))
if (GTK_IS_ACCESSIBLE_TEXT (accessible))
return &accessible_text_vtable;
else if (GTK_IS_LABEL (accessible))
return &label_vtable;
else if (GTK_IS_INSCRIPTION (accessible))
return &inscription_vtable;