Allow setting accessible parent and sibling explicitly
authorLukáš Tyrychtr <lukastyrychtr@gmail.com>
Tue, 14 Feb 2023 13:09:54 +0000 (14:09 +0100)
committerLukáš Tyrychtr <lukastyrychtr@gmail.com>
Tue, 14 Feb 2023 13:43:57 +0000 (14:43 +0100)
This allows to maintain the correct a11y hierarchy even when it contains
objects which are only GtkAccessibles.

gtk/gtkaccessible.c
gtk/gtkaccessible.h
gtk/gtkatcontext.c
gtk/gtkatcontextprivate.h

index 7143c14006d7318cd7a5f5bea32098bfdaa2e518..7d1da7d398d06547c9e322d825e55e4f49a968f1 100644 (file)
  * [vfunc@Gtk.Accessible.get_next_accessible_sibling] virtual functions.
  * Note that you can not create a top-level accessible object as of now,
  * which means that you must always have a parent accessible object.
+ * Also note that when an accessible object does not correspond to a widget,
+ * and it has children, whose implementation you don't control,
+ * it is necessary to ensure the correct shape of the a11y tree
+ * by calling gtk_accessible_set_accessible_parent() and
+ * gtk_accessible_set_next_accessible_sibling() as appropriate.
  */
 
 #include "config.h"
@@ -115,7 +120,43 @@ gtk_accessible_get_accessible_parent (GtkAccessible *self)
 {
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL);
 
-  return GTK_ACCESSIBLE_GET_IFACE (self)->get_accessible_parent (self);
+  GtkATContext *context;
+  GtkAccessible *parent = NULL;
+
+  context = gtk_accessible_get_at_context (self);
+  if (context != NULL)
+    parent = gtk_at_context_get_accessible_parent (context);
+  if (parent != NULL)
+    return parent;
+  else
+    return GTK_ACCESSIBLE_GET_IFACE (self)->get_accessible_parent (self);
+}
+
+/**
+ * gtk_accessible_set_accessible_parent:
+ * @self: a `GtkAccessible`
+ * @parent: the parent `GtkAccessible`
+ * @next_sibling: the next accessible sibling of this `GtkAccessible`
+ *
+ * Sets the parent and next sibling accessible of an accessible object
+ *
+ * Since: 4.10
+ */
+void
+gtk_accessible_set_accessible_parent (GtkAccessible *self,
+                                      GtkAccessible *parent,
+                                      GtkAccessible *next_sibling)
+{
+  g_return_if_fail (GTK_IS_ACCESSIBLE (self));
+  GtkATContext *context;
+
+  context = gtk_accessible_get_at_context (self);
+  if (context != NULL)
+  {
+    gtk_at_context_set_accessible_parent (context, parent);
+    gtk_at_context_set_next_accessible_sibling (context, next_sibling);
+  }
 }
 
 /**
@@ -151,7 +192,13 @@ gtk_accessible_get_next_accessible_sibling (GtkAccessible *self)
 {
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL);
 
-  return GTK_ACCESSIBLE_GET_IFACE (self)->get_next_accessible_sibling (self);
+  GtkATContext *context;
+
+  context = gtk_accessible_get_at_context (self);
+  if (context != NULL && gtk_at_context_get_accessible_parent (context) != NULL)
+    return gtk_at_context_get_next_accessible_sibling (context);
+  else
+    return GTK_ACCESSIBLE_GET_IFACE (self)->get_next_accessible_sibling (self);
 }
 
 /**
index 713a9b5ccfcbdc516cbe7667f42a0913714dbe3c..b9bb5476a5037140675074f163b92dea9c1b2907 100644 (file)
@@ -164,6 +164,11 @@ gboolean gtk_accessible_get_platform_state (GtkAccessible              *self,
 GDK_AVAILABLE_IN_4_10
 GtkAccessible * gtk_accessible_get_accessible_parent (GtkAccessible *self);
 
+GDK_AVAILABLE_IN_4_10
+void gtk_accessible_set_accessible_parent (GtkAccessible *self,
+                                           GtkAccessible *parent,
+                                           GtkAccessible *next_sibling);
+
 GDK_AVAILABLE_IN_4_10
 GtkAccessible * gtk_accessible_get_first_accessible_child (GtkAccessible *self);
 
index 07d330d59e07ba731c1d324c7a87f750886b51aa..040bc43850c57df853d316f66933bc5e121077e1 100644 (file)
@@ -447,6 +447,80 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
   return self->accessible_role;
 }
 
+/*< private >
+ * gtk_at_context_get_accessible_parent:
+ * @self: a `GtkAtContext`
+ *
+ * Retrieves the parent accessible object of the given `GtkAtContext`.
+ *
+ * Returns: (nullable) (transfer none): the parent accessible object, or `NULL` if not set.
+ */
+GtkAccessible *
+gtk_at_context_get_accessible_parent (GtkATContext *self)
+{
+  g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
+  
+  return self->accessible_parent;
+}
+
+/*< private >
+ * gtk_at_context_set_accessible_parent:
+ * @self: a `GtkAtContext`
+ * @parent: the parent `GtkAccessible` to set
+ *
+ * Sets the parent accessible object of the given `GtkAtContext`.
+ */
+void
+gtk_at_context_set_accessible_parent (GtkATContext *self,
+                                      GtkAccessible *parent)
+{
+  g_return_if_fail (GTK_IS_AT_CONTEXT (self));
+  
+  if (self->accessible_parent != parent)
+    {
+      if (self->accessible_parent != NULL)
+        g_object_unref (self->accessible_parent);
+      self->accessible_parent = g_object_ref (parent);
+    }
+}
+
+/*< private >
+ * gtk_at_context_get_next_accessible_sibling:
+ * @self: a `GtkAtContext`
+ *
+ * Retrieves the next accessible sibling of the given `GtkAtContext`.
+ *
+ * Returns: (nullable) (transfer none): the next accessible sibling.
+ */
+GtkAccessible *
+gtk_at_context_get_next_accessible_sibling (GtkATContext *self)
+{
+  g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
+  
+  return self->next_accessible_sibling;
+}
+
+/*< private >
+ * gtk_at_context_set_next_accessible_sibling:
+ * @self: a `GtkAtContext`
+ * @sibling: (nullable): the next accessible sibling
+ *
+ * Sets the next accessible sibling object of the given `GtkAtContext`.
+ */
+void
+gtk_at_context_set_next_accessible_sibling (GtkATContext *self,
+                                            GtkAccessible *sibling)
+{
+  g_return_if_fail (GTK_IS_AT_CONTEXT (self));
+  
+  if (self->next_accessible_sibling != sibling)
+    {
+      if (self->next_accessible_sibling != NULL)
+        g_object_unref (self->next_accessible_sibling);
+      self->next_accessible_sibling = g_object_ref (sibling);
+    }
+}
+
 /*< private >
  * gtk_at_context_set_display:
  * @self: a `GtkATContext`
index c0acfc7793058f528342c5f8729297664b5f7afd..e7ea71724376f0ce902c1f5a127c2c324ef4b5b1 100644 (file)
@@ -87,6 +87,8 @@ struct _GtkATContext
 
   GtkAccessibleRole accessible_role;
   GtkAccessible *accessible;
+  GtkAccessible *accessible_parent;
+  GtkAccessible *next_accessible_sibling;
   GdkDisplay *display;
 
   GtkAccessibleAttributeSet *states;
@@ -179,4 +181,15 @@ const char *    gtk_accessible_property_get_attribute_name      (GtkAccessiblePr
 const char *    gtk_accessible_relation_get_attribute_name      (GtkAccessibleRelation relation);
 const char *    gtk_accessible_state_get_attribute_name         (GtkAccessibleState    state);
 
+GtkAccessible *
+gtk_at_context_get_accessible_parent (GtkATContext *self);
+void
+gtk_at_context_set_accessible_parent (GtkATContext *self,
+                                      GtkAccessible *parent);
+GtkAccessible *
+gtk_at_context_get_next_accessible_sibling (GtkATContext *self);
+void
+gtk_at_context_set_next_accessible_sibling (GtkATContext *self,
+                                            GtkAccessible *sibling);
+
 G_END_DECLS