[gtk/ebassi/new-a11y: 13/29] Allow setting the accessible role at construction



commit 486e4366bb50dc6dc8e9ad2a3a63f1030829f2d3
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Jul 13 15:20:19 2020 +0100

    Allow setting the accessible role at construction
    
    Some widgets have different accessible roles depending on some
    parameter, so we cannot set the role at class init time. For those
    widgets, we add an "accessible-role" property to GtkAccessible, and we
    allow setting it (only) at construction time.

 gtk/gtkaccessible.c    | 40 +++++++++++++++++++++++++++++++
 gtk/gtkaccessible.h    | 15 +++++++-----
 gtk/gtkwidget.c        | 64 +++++++++++++++++++++++++++++++++++++++++++++++---
 gtk/gtkwidget.h        |  2 ++
 gtk/gtkwidgetprivate.h |  3 ++-
 5 files changed, 114 insertions(+), 10 deletions(-)
---
diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c
index c6e576c329..47bebc7543 100644
--- a/gtk/gtkaccessible.c
+++ b/gtk/gtkaccessible.c
@@ -46,6 +46,7 @@
 
 #include "gtkatcontextprivate.h"
 #include "gtkenums.h"
+#include "gtktypebuiltins.h"
 
 #include <stdarg.h>
 
@@ -54,8 +55,27 @@ G_DEFINE_INTERFACE (GtkAccessible, gtk_accessible, G_TYPE_OBJECT)
 static void
 gtk_accessible_default_init (GtkAccessibleInterface *iface)
 {
+  GParamSpec *pspec =
+    g_param_spec_enum ("accessible-role",
+                       "Accessible Role",
+                       "The role of the accessible object",
+                       GTK_TYPE_ACCESSIBLE_ROLE,
+                       GTK_ACCESSIBLE_ROLE_WIDGET,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       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)
 {
@@ -64,6 +84,26 @@ gtk_accessible_get_at_context (GtkAccessible *self)
   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_WIDGET);
+
+  GtkATContext *context = gtk_accessible_get_at_context (self);
+  if (context == NULL)
+    return GTK_ACCESSIBLE_ROLE_WIDGET;
+
+  return gtk_at_context_get_accessible_role (context);
+}
+
 /**
  * gtk_accessible_update_state:
  * @self: a #GtkAccessible
diff --git a/gtk/gtkaccessible.h b/gtk/gtkaccessible.h
index 9fe16616e5..5b943f89a2 100644
--- a/gtk/gtkaccessible.h
+++ b/gtk/gtkaccessible.h
@@ -32,12 +32,15 @@ GDK_AVAILABLE_IN_ALL
 G_DECLARE_INTERFACE (GtkAccessible, gtk_accessible, GTK, ACCESSIBLE, GObject)
 
 GDK_AVAILABLE_IN_ALL
-void    gtk_accessible_update_state             (GtkAccessible      *self,
-                                                 GtkAccessibleState  first_state,
-                                                 ...);
+GtkAccessibleRole       gtk_accessible_get_accessible_role      (GtkAccessible *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_accessible_update_state             (GtkAccessible      *self,
+                                                                 GtkAccessibleState  first_state,
+                                                                 ...);
 GDK_AVAILABLE_IN_ALL
-void    gtk_accessible_update_state_value       (GtkAccessible      *self,
-                                                 GtkAccessibleState  state,
-                                                 const GValue       *value);
+void                    gtk_accessible_update_state_value       (GtkAccessible      *self,
+                                                                 GtkAccessibleState  state,
+                                                                 const GValue       *value);
 
 G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index cebf881abf..d19bbe958e 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -511,7 +511,10 @@ enum {
   PROP_CSS_NAME,
   PROP_CSS_CLASSES,
   PROP_LAYOUT_MANAGER,
-  NUM_PROPERTIES
+  NUM_PROPERTIES,
+
+  /* GtkAccessible */
+  PROP_ACCESSIBLE_ROLE
 };
 
 static GParamSpec *widget_props[NUM_PROPERTIES] = { NULL, };
@@ -1334,6 +1337,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, widget_props);
 
+  g_object_class_override_property (gobject_class, PROP_ACCESSIBLE_ROLE, "accessible-role");
+
   /**
    * GtkWidget::destroy:
    * @object: the object which received the signal
@@ -1714,6 +1719,9 @@ gtk_widget_set_property (GObject         *object,
     case PROP_LAYOUT_MANAGER:
       gtk_widget_set_layout_manager (widget, g_value_dup_object (value));
       break;
+    case PROP_ACCESSIBLE_ROLE:
+      priv->accessible_role = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1844,6 +1852,16 @@ gtk_widget_get_property (GObject         *object,
     case PROP_LAYOUT_MANAGER:
       g_value_set_object (value, gtk_widget_get_layout_manager (widget));
       break;
+    case PROP_ACCESSIBLE_ROLE:
+      {
+        GtkAccessibleRole role = priv->accessible_role;
+
+        if (priv->accessible_role == GTK_ACCESSIBLE_ROLE_WIDGET)
+          role = gtk_widget_class_get_accessible_role (GTK_WIDGET_GET_CLASS (widget));
+
+        g_value_set_enum (value, role);
+      }
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2257,6 +2275,8 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
   priv->halign = GTK_ALIGN_FILL;
   priv->valign = GTK_ALIGN_FILL;
 
+  priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET;
+
   priv->width_request = -1;
   priv->height_request = -1;
 
@@ -8075,9 +8095,23 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
     {
       GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
       GtkWidgetClassPrivate *class_priv = widget_class->priv;
+      GtkAccessibleRole role;
 
-      priv->at_context =
-        gtk_at_context_create (class_priv->accessible_role, accessible);
+      /* Widgets have two options to set the accessible role: either they
+       * define it in their class_init() function, and the role applies to
+       * all instances; or an instance is created with the :accessible-role
+       * property (from GtkAccessible) set to anything other than the default
+       * GTK_ACCESSIBLE_ROLE_WIDGET value.
+       *
+       * In either case, the accessible role cannot be set post-construction.
+       */
+      if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
+        role = priv->accessible_role;
+      else
+        role = class_priv->accessible_role;
+
+      priv->at_context = gtk_at_context_create (role, accessible);
+      priv->accessible_role = role;
     }
 
   return priv->at_context;
@@ -12138,3 +12172,27 @@ gtk_widget_class_set_accessible_role (GtkWidgetClass    *widget_class,
   priv = widget_class->priv;
   priv->accessible_role = accessible_role;
 }
+
+/**
+ * gtk_widget_class_get_accessible_role:
+ * @widget_class: a #GtkWidgetClass
+ *
+ * Retrieves the accessible role used by the given #GtkWidget class.
+ *
+ * Different accessible roles have different states, and are rendered
+ * differently by assistive technologies.
+ *
+ * See also: gtk_accessible_get_accessible_role()
+ *
+ * Returns: the accessible role for the widget class
+ */
+GtkAccessibleRole
+gtk_widget_class_get_accessible_role (GtkWidgetClass *widget_class)
+{
+  GtkWidgetClassPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), GTK_ACCESSIBLE_ROLE_WIDGET);
+
+  priv = widget_class->priv;
+  return priv->accessible_role;
+}
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index a897237860..08b9bf2de2 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -980,6 +980,8 @@ void                    gtk_widget_action_set_enabled (GtkWidget  *widget,
 GDK_AVAILABLE_IN_ALL
 void                    gtk_widget_class_set_accessible_role    (GtkWidgetClass    *widget_class,
                                                                  GtkAccessibleRole  accessible_role);
+GDK_AVAILABLE_IN_ALL
+GtkAccessibleRole       gtk_widget_class_get_accessible_role    (GtkWidgetClass    *widget_class);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRequisition, gtk_requisition_free)
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index f0df306bde..d417edc77c 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -191,7 +191,8 @@ struct _GtkWidgetPrivate
   char *tooltip_markup;
   char *tooltip_text;
 
-  /* Accessible context */
+  /* Accessibility */
+  GtkAccessibleRole accessible_role;
   GtkATContext *at_context;
 };
 


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