[gtk/wip/otte/inscription: 5/8] inscription: Add a11y support for text interface




commit e437a9c348b795445e1dadc801497c1075c3738e
Author: Benjamin Otte <otte redhat com>
Date:   Thu Jun 9 07:14:30 2022 +0200

    inscription: Add a11y support for text interface
    
    This is entirely untested.

 gtk/a11y/gtkatspitext.c     | 271 ++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkinscription.c        |  11 +-
 gtk/gtkinscriptionprivate.h |  33 ++++++
 3 files changed, 314 insertions(+), 1 deletion(-)
---
diff --git a/gtk/a11y/gtkatspitext.c b/gtk/a11y/gtkatspitext.c
index e4a6140298..e7bd9275be 100644
--- a/gtk/a11y/gtkatspitext.c
+++ b/gtk/a11y/gtkatspitext.c
@@ -32,6 +32,7 @@
 #include "gtkatcontextprivate.h"
 #include "gtkdebug.h"
 #include "gtkeditable.h"
+#include "gtkinscriptionprivate.h"
 #include "gtklabelprivate.h"
 #include "gtkentryprivate.h"
 #include "gtksearchentryprivate.h"
@@ -406,6 +407,274 @@ static const GDBusInterfaceVTable label_vtable = {
   NULL,
 };
 
+/* }}} */
+/* {{{ GtkInscription */
+
+static void
+inscription_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);
+  GtkWidget *widget = GTK_WIDGET (accessible);
+
+  if (g_strcmp0 (method_name, "GetCaretOffset") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", 0));
+    }
+  else if (g_strcmp0 (method_name, "SetCaretOffset") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
+    }
+  else if (g_strcmp0 (method_name, "GetText") == 0)
+    {
+      int start, end;
+      const char *text;
+      int len;
+      char *string;
+
+      g_variant_get (parameters, "(ii)", &start, &end);
+
+      text = gtk_inscription_get_text (GTK_INSCRIPTION (widget));
+      len = g_utf8_strlen (text, -1);
+
+      start = CLAMP (start, 0, len);
+      end = CLAMP (end, 0, len);
+
+      if (end <= start)
+        string = g_strdup ("");
+      else
+        {
+          const char *p, *q;
+          p = g_utf8_offset_to_pointer (text, start);
+          q = g_utf8_offset_to_pointer (text, end);
+          string = g_strndup (p, q - p);
+        }
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", string));
+      g_free (string);
+    }
+  else if (g_strcmp0 (method_name, "GetTextBeforeOffset") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      int offset;
+      AtspiTextBoundaryType boundary_type;
+      char *string;
+      int start, end;
+
+      g_variant_get (parameters, "(iu)", &offset, &boundary_type);
+
+      string = gtk_pango_get_text_before (layout, offset, boundary_type, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
+      g_free (string);
+    }
+  else if (g_strcmp0 (method_name, "GetTextAtOffset") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      int offset;
+      AtspiTextBoundaryType boundary_type;
+      char *string;
+      int start, end;
+
+      g_variant_get (parameters, "(iu)", &offset, &boundary_type);
+
+      string = gtk_pango_get_text_at (layout, offset, boundary_type, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
+      g_free (string);
+    }
+  else if (g_strcmp0 (method_name, "GetTextAfterOffset") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      int offset;
+      AtspiTextBoundaryType boundary_type;
+      char *string;
+      int start, end;
+
+      g_variant_get (parameters, "(iu)", &offset, &boundary_type);
+
+      string = gtk_pango_get_text_after (layout, offset, boundary_type, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
+      g_free (string);
+    }
+  else if (g_strcmp0 (method_name, "GetCharacterAtOffset") == 0)
+    {
+      int offset;
+      const char *text;
+      gunichar ch = 0;
+
+      g_variant_get (parameters, "(i)", &offset);
+
+      text = gtk_inscription_get_text (GTK_INSCRIPTION (widget));
+
+      if (0 <= offset && offset < g_utf8_strlen (text, -1))
+        ch = g_utf8_get_char (g_utf8_offset_to_pointer (text, offset));
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", ch));
+    }
+  else if (g_strcmp0 (method_name, "GetStringAtOffset") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      int offset;
+      AtspiTextGranularity granularity;
+      char *string;
+      int start, end;
+
+      g_variant_get (parameters, "(iu)", &offset, &granularity);
+
+      string = gtk_pango_get_string_at (layout, offset, granularity, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sii)", string, start, end));
+      g_free (string);
+    }
+  else if (g_strcmp0 (method_name, "GetAttributes") == 0)
+    {
+      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;
+
+      g_variant_get (parameters, "(i)", &offset);
+
+      gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
+    }
+  else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
+      int offset;
+      const char *name;
+      int start, end;
+      GVariant *attrs;
+      const char *val;
+
+      g_variant_get (parameters, "(i&s)", &offset, &name);
+
+      gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
+
+      attrs = g_variant_builder_end (&builder);
+      if (!g_variant_lookup (attrs, name, "&s", &val))
+        val = "";
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
+      g_variant_unref (attrs);
+    }
+  else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
+      int offset;
+      gboolean include_defaults;
+      int start, end;
+
+      g_variant_get (parameters, "(ib)", &offset, &include_defaults);
+
+      if (include_defaults)
+        gtk_pango_get_default_attributes (layout, &builder);
+
+      gtk_pango_get_run_attributes (layout, &builder, offset, &start, &end);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
+    }
+  else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 ||
+           g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0)
+    {
+      PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (widget));;
+      GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
+
+      gtk_pango_get_default_attributes (layout, &builder);
+
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
+    }
+  else if (g_strcmp0 (method_name, "GetNSelections") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", 0));
+    }
+  else if (g_strcmp0 (method_name, "GetSelection") == 0)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No 
selections available");
+    }
+  else if (g_strcmp0 (method_name, "AddSelection") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
+    }
+  else if (g_strcmp0 (method_name, "RemoveSelection") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
+    }
+  else if (g_strcmp0 (method_name, "SetSelection") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
+    }
+  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 *
+inscription_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);
+  GtkWidget *widget = GTK_WIDGET (accessible);
+
+  if (g_strcmp0 (property_name, "CharacterCount") == 0)
+    {
+      const char *text;
+      int len;
+
+      text = gtk_inscription_get_text (GTK_INSCRIPTION (widget));
+      len = g_utf8_strlen (text, -1);
+
+      return g_variant_new_int32 (len);
+    }
+  else if (g_strcmp0 (property_name, "CaretOffset") == 0)
+    {
+      return g_variant_new_int32 (0);
+    }
+
+  return NULL;
+}
+
+static const GDBusInterfaceVTable inscription_vtable = {
+  inscription_handle_method,
+  inscription_get_property,
+  NULL,
+};
+
 /* }}} */
 /* {{{ GtkEditable */
 
@@ -1301,6 +1570,8 @@ gtk_atspi_get_text_vtable (GtkAccessible *accessible)
 {
   if (GTK_IS_LABEL (accessible))
     return &label_vtable;
+  else if (GTK_IS_INSCRIPTION (accessible))
+    return &inscription_vtable;
   else if (GTK_IS_EDITABLE (accessible) &&
            GTK_IS_TEXT (gtk_editable_get_delegate (GTK_EDITABLE (accessible))))
     return &editable_vtable;
diff --git a/gtk/gtkinscription.c b/gtk/gtkinscription.c
index 522d943933..ffe7ffd09c 100644
--- a/gtk/gtkinscription.c
+++ b/gtk/gtkinscription.c
@@ -19,7 +19,7 @@
 
 #include "config.h"
 
-#include "gtkinscription.h"
+#include "gtkinscriptionprivate.h"
 
 #include "gtkcssnodeprivate.h"
 #include "gtkcssstylechangeprivate.h"
@@ -653,6 +653,8 @@ gtk_inscription_class_init (GtkInscriptionClass *klass)
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
+
+  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_LABEL);
 }
 
 static void
@@ -669,6 +671,13 @@ gtk_inscription_init (GtkInscription *self)
   pango_layout_set_wrap (self->layout, PANGO_WRAP_WORD_CHAR);
 }
 
+/* for a11y */
+PangoLayout *
+gtk_inscription_get_layout (GtkInscription *self)
+{
+  return self->layout;
+}
+
 /**
  * gtk_inscription_new:
  * @text: (nullable): The text to display.
diff --git a/gtk/gtkinscriptionprivate.h b/gtk/gtkinscriptionprivate.h
new file mode 100644
index 0000000000..97de354e27
--- /dev/null
+++ b/gtk/gtkinscriptionprivate.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2022 Benjamin Otte
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_INSCRIPTION_PRIVATE_H__
+#define __GTK_INSCRIPTION_PRIVATE_H__
+
+
+#include <gtk/gtkinscription.h>
+
+
+G_BEGIN_DECLS
+
+PangoLayout *           gtk_inscription_get_layout              (GtkInscription *self);
+
+G_END_DECLS
+
+#endif /* __GTK_INSCRIPTION_PRIVATE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]