a11y: Use GtkAccessible for tree traversal
authorLukáš Tyrychtr <lukastyrychtr@gmail.com>
Fri, 9 Sep 2022 12:16:20 +0000 (14:16 +0200)
committerEmmanuele Bassi <ebassi@gnome.org>
Fri, 3 Feb 2023 10:49:17 +0000 (11:49 +0100)
Remove the widget tree dependence from GtkAtSpiContext.

gtk/a11y/gtkatspicontext.c

index 8380d156b4b3ecfca72aa0d5954995119b3de5ac..034dbdc05acf72c76ae60f3593ce12bc9aef3b8e 100644 (file)
@@ -329,24 +329,24 @@ collect_relations (GtkAtSpiContext *self,
 /* }}} */
 /* {{{ Accessible implementation */
 static int
-get_index_in_parent (GtkWidget *widget)
+get_index_in (GtkAccessible *parent, GtkAccessible *child)
 {
-  GtkWidget *parent = gtk_widget_get_parent (widget);
-  GtkWidget *child;
+  GtkAccessible *candidate;
   int idx;
 
   if (parent == NULL)
     return -1;
 
   idx = 0;
-  for (child = gtk_widget_get_first_child (parent);
-       child;
-       child = gtk_widget_get_next_sibling (child))
+  while (true)
     {
-      if (child == widget)
+      candidate = gtk_accessible_get_child_at_index (parent, idx);
+      if (!candidate)
+        break;
+      if (candidate == child)
         return idx;
 
-      if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
+      if (!gtk_accessible_should_present (candidate))
         continue;
 
       idx++;
@@ -355,6 +355,13 @@ get_index_in_parent (GtkWidget *widget)
   return -1;
 }
 
+static int
+get_index_in_parent (GtkAccessible *accessible)
+{
+  GtkAccessible *parent = gtk_accessible_get_parent (accessible);
+  return get_index_in(parent, accessible);
+}
+
 static int
 get_index_in_toplevels (GtkWidget *widget)
 {
@@ -387,61 +394,21 @@ get_parent_context_ref (GtkAccessible *accessible)
 {
   GVariant *res = NULL;
 
-  if (GTK_IS_WIDGET (accessible))
-    {
-      GtkWidget *widget = GTK_WIDGET (accessible);
-      GtkWidget *parent = gtk_widget_get_parent (widget);
-
-      if (parent == NULL)
-        {
-          GtkATContext *context = gtk_accessible_get_at_context (accessible);
-          GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
-
-          res = gtk_at_spi_root_to_ref (self->root);
-        }
-      else if (GTK_IS_STACK (parent))
-        {
-          GtkStackPage *page =
-            gtk_stack_get_page (GTK_STACK (parent), widget);
-          GtkATContext *parent_context =
-            gtk_accessible_get_at_context (GTK_ACCESSIBLE (page));
-
-          if (parent_context != NULL)
-            {
-              gtk_at_context_realize (parent_context);
+  GtkAccessible *parent = gtk_accessible_get_parent (accessible);
 
-              res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context));
-            }
-        }
-      else
-        {
-          GtkATContext *parent_context =
-            gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent));
-
-          if (parent_context != NULL)
-            {
-              /* XXX: This realize() is needed otherwise opening a GtkPopover will
-               * emit a warning when getting the context's reference
-               */
-              gtk_at_context_realize (parent_context);
+  if (parent == NULL)
+    {
+      GtkATContext *context = gtk_accessible_get_at_context (accessible);
+      GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
 
-              res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context));
-            }
-        }
+      res = gtk_at_spi_root_to_ref (self->root);
     }
-  else if (GTK_IS_STACK_PAGE (accessible))
+  else
     {
-      GtkWidget *parent =
-        gtk_widget_get_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible)));
-      GtkATContext *parent_context =
-        gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent));
+      GtkATContext *parent_context = gtk_accessible_get_at_context (parent);
+      gtk_at_context_realize (parent_context);
 
-      if (parent_context != NULL)
-        {
-          gtk_at_context_realize (parent_context);
-
-          res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context));
-        }
+      res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context));
     }
 
   if (res == NULL)
@@ -528,43 +495,25 @@ handle_accessible_method (GDBusConnection       *connection,
 
       accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self));
 
-      if (GTK_IS_STACK_PAGE (accessible))
-        {
-          if (idx == 0)
-            {
-              GtkWidget *child;
+      GtkAccessible *child;
 
-              child = gtk_stack_page_get_child (GTK_STACK_PAGE (accessible));
-              if (gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
-                context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child));
-            }
-        }
-      else if (GTK_IS_WIDGET (accessible))
+      real_idx = 0;
+      do
         {
-          GtkWidget *widget = GTK_WIDGET (accessible);
-          GtkWidget *child;
-
-          real_idx = 0;
-          for (child = gtk_widget_get_first_child (widget);
-               child;
-               child = gtk_widget_get_next_sibling (child))
-            {
-              if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
-                continue;
+          child = gtk_accessible_get_child_at_index (accessible, real_idx);
+          if (!gtk_accessible_should_present (child))
+              continue;
 
-              if (real_idx == idx)
-                break;
+          if (real_idx == idx)
+            break;
 
-              real_idx += 1;
-            }
+          real_idx += 1;
+        }
+      while (child != NULL);
 
-          if (child)
-            {
-              if (GTK_IS_STACK (accessible))
-                context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_stack_get_page (GTK_STACK (accessible), child)));
-              else
-                context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child));
-            }
+      if (child)
+        {
+          context = gtk_accessible_get_at_context (child);
         }
 
       if (context == NULL)
@@ -588,45 +537,27 @@ handle_accessible_method (GDBusConnection       *connection,
       GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(so)"));
 
       GtkAccessible *accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self));
-      if (GTK_IS_WIDGET (accessible))
-        {
-          GtkWidget *widget = GTK_WIDGET (accessible);
-          GtkWidget *child;
-
-          for (child = gtk_widget_get_first_child (widget);
-               child;
-               child = gtk_widget_get_next_sibling (child))
-            {
-              if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
-                continue;
 
-              GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child));
+      GtkAccessible *child;
+      guint idx = 0;
 
-              /* Realize the child ATContext in order to get its ref */
-              gtk_at_context_realize (context);
-
-              GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context));
-
-              if (ref != NULL)
-                g_variant_builder_add (&builder, "@(so)", ref);
-            }
-        }
-      else if (GTK_IS_STACK_PAGE (accessible))
+      while (true)
         {
-          GtkWidget *child = gtk_stack_page_get_child (GTK_STACK_PAGE (accessible));
+          child = gtk_accessible_get_child_at_index (accessible, idx);
+          if(!child)
+            break;
+          if (!gtk_accessible_should_present (child))
+            continue;
 
-          if (gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
-            {
-              GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child));
+          GtkATContext *context = gtk_accessible_get_at_context (child);
 
-              /* Realize the child ATContext in order to get its ref */
-              gtk_at_context_realize (context);
+          /* Realize the child ATContext in order to get its ref */
+          gtk_at_context_realize (context);
 
-              GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context));
+          GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context));
 
-              if (ref != NULL)
-                g_variant_builder_add (&builder, "@(so)", ref);
-            }
+          if (ref != NULL)
+            g_variant_builder_add (&builder, "@(so)", ref);
         }
 
       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &builder));
@@ -915,7 +846,7 @@ gtk_at_spi_context_state_change (GtkATContext                *ctx,
 
   if (changed_states & GTK_ACCESSIBLE_STATE_CHANGE_HIDDEN)
     {
-      GtkWidget *parent;
+      GtkAccessible *parent;
       GtkATContext *context;
       GtkAccessibleChildChange change;
 
@@ -932,14 +863,9 @@ gtk_at_spi_context_state_change (GtkATContext                *ctx,
         }
       else
         {
-          if (GTK_IS_WIDGET (accessible))
-            parent = gtk_widget_get_parent (GTK_WIDGET (accessible));
-          else if (GTK_IS_STACK_PAGE (accessible))
-            parent = gtk_widget_get_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible)));
-          else
-            g_assert_not_reached ();
+          parent = gtk_accessible_get_parent (accessible);
 
-          context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent));
+          context = gtk_accessible_get_at_context (parent);
           gtk_at_context_child_changed (context, change, accessible);
         }
     }
@@ -1201,98 +1127,19 @@ gtk_at_spi_context_child_change (GtkATContext             *ctx,
   GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (ctx);
   GtkAccessible *accessible = gtk_at_context_get_accessible (ctx);
   GtkATContext *child_context = gtk_accessible_get_at_context (child);
-  GtkWidget *parent_widget;
-  GtkWidget *child_widget;
-  int idx = 0;
 
-  if (!GTK_IS_WIDGET (accessible))
-    return;
+  int idx = 0;
 
   if (child_context == NULL)
     return;
 
-  /* handle the stack page special case */
-  if (GTK_IS_WIDGET (child) &&
-      GTK_IS_STACK (gtk_widget_get_parent (GTK_WIDGET (child))))
+  if (gtk_accessible_get_parent (child) != accessible)
     {
-      GtkWidget *stack;
-      GtkStackPage *page;
-      GListModel *pages;
-
-      stack = gtk_widget_get_parent (GTK_WIDGET (child));
-      page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (child));
-      pages = G_LIST_MODEL (gtk_stack_get_pages (GTK_STACK (stack)));
       idx = 0;
-      for (guint i = 0; i < g_list_model_get_n_items (pages); i++)
-        {
-          GtkStackPage *item = g_list_model_get_item (pages, i);
-
-          g_object_unref (item);
-
-          if (!gtk_accessible_should_present (GTK_ACCESSIBLE (item)))
-            continue;
-
-          if (item == page)
-            break;
-
-          idx++;
-        }
-      g_object_unref (pages);
-
-      if (change & GTK_ACCESSIBLE_CHILD_CHANGE_ADDED)
-        {
-          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))),
-                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
-                                 idx,
-                                 GTK_ACCESSIBLE_CHILD_STATE_ADDED);
-
-          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
-                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)),
-                                 0,
-                                 GTK_ACCESSIBLE_CHILD_STATE_ADDED);
-        }
-
-      if (change & GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED)
-        {
-          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
-                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)),
-                                 0,
-                                 GTK_ACCESSIBLE_CHILD_STATE_REMOVED);
-          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))),
-                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
-                                 idx,
-                                 GTK_ACCESSIBLE_CHILD_STATE_REMOVED);
-
-        }
-
-      return;
     }
-
-  parent_widget = GTK_WIDGET (accessible);
-
-  if (GTK_IS_STACK_PAGE (child))
-    child_widget = gtk_stack_page_get_child (GTK_STACK_PAGE (child));
   else
-    child_widget = GTK_WIDGET (child);
-
-  if (gtk_widget_get_parent (child_widget) != parent_widget)
     {
-      idx = 0;
-    }
-  else
-    {
-      for (GtkWidget *iter = gtk_widget_get_first_child (parent_widget);
-           iter != NULL;
-           iter = gtk_widget_get_next_sibling (iter))
-        {
-          if (!gtk_accessible_should_present (GTK_ACCESSIBLE (iter)))
-            continue;
-
-          if (iter == child_widget)
-            break;
-
-          idx += 1;
-        }
+      idx = get_index_in(accessible, child);
     }
 
   if (change & GTK_ACCESSIBLE_CHILD_CHANGE_ADDED)
@@ -1858,12 +1705,8 @@ gtk_at_spi_context_get_index_in_parent (GtkAtSpiContext *self)
 
   if (GTK_IS_ROOT (accessible))
     idx = get_index_in_toplevels (GTK_WIDGET (accessible));
-  else if (GTK_IS_STACK_PAGE (accessible))
-    idx = get_index_in_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible)));
-  else if (GTK_IS_STACK (gtk_widget_get_parent (GTK_WIDGET (accessible))))
-    idx = 1;
   else
-    idx = get_index_in_parent (GTK_WIDGET (accessible));
+    idx = get_index_in_parent  (accessible);
 
   return idx;
 }
@@ -1874,26 +1717,20 @@ gtk_at_spi_context_get_child_count (GtkAtSpiContext *self)
   g_return_val_if_fail (GTK_IS_AT_SPI_CONTEXT (self), -1);
 
   GtkAccessible *accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self));
-  int n_children = -1;
+  int n_children = 0;
+  
+  GtkAccessible *child;
 
-  if (GTK_IS_WIDGET (accessible))
+    
+  while (true)
     {
-      GtkWidget *child;
-
-      n_children = 0;
-      for (child = gtk_widget_get_first_child (GTK_WIDGET (accessible));
-           child;
-           child = gtk_widget_get_next_sibling (child))
-        {
-          if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child)))
-            continue;
+      child = gtk_accessible_get_child_at_index (accessible, n_children);
+      if (!child)
+        break;
+      if (!gtk_accessible_should_present (child))
+        continue;
 
-          n_children++;
-        }
-    }
-  else if (GTK_IS_STACK_PAGE (accessible))
-    {
-      n_children = 1;
+      n_children++;
     }
 
   return n_children;