[gtk/a11y-list-view-selection-fixes: 2/2] atspi: Implement Selection more correctly




commit 8701e65635689c7744afa4859508560444e375a2
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Oct 15 12:46:52 2020 -0400

    atspi: Implement Selection more correctly
    
    The Selection interface is defined in terms of child
    positions, so we need to always translate from that
    to model positions if we want to use the selection
    model apis.

 gtk/a11y/gtkatspiselection.c | 145 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 116 insertions(+), 29 deletions(-)
---
diff --git a/gtk/a11y/gtkatspiselection.c b/gtk/a11y/gtkatspiselection.c
index 1580a09a81..5812f2720c 100644
--- a/gtk/a11y/gtkatspiselection.c
+++ b/gtk/a11y/gtkatspiselection.c
@@ -239,88 +239,175 @@ listview_handle_method (GDBusConnection       *connection,
   if (g_strcmp0 (method_name, "GetSelectedChild") == 0)
     {
       int idx;
-      guint pos;
-      GtkBitset *set;
       GtkWidget *child;
-      GtkListItem *item;
 
       g_variant_get (parameters, "(i)", &idx);
 
-      set = gtk_selection_model_get_selection (model);
-      pos = gtk_bitset_get_nth (set, idx);
-      gtk_bitset_unref (set);
-
+      /* We are asked for the idx-the selected child *among the
+       * current children*
+       */
       for (child = gtk_widget_get_first_child (widget);
            child;
            child = gtk_widget_get_next_sibling (child))
         {
-          item = gtk_list_item_widget_get_list_item (GTK_LIST_ITEM_WIDGET (child));
-          if (pos == gtk_list_item_get_position (item))
-            break;
+          if (gtk_list_item_widget_get_selected (GTK_LIST_ITEM_WIDGET (child)))
+            {
+              if (idx == 0)
+                break;
+              idx--;
+            }
         }
 
       if (child == NULL)
-        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No 
selected child for %d", idx);
+        g_dbus_method_invocation_return_error (invocation,
+                                               G_DBUS_ERROR,
+                                               G_DBUS_ERROR_INVALID_ARGS,
+                                               "No selected child for %d", idx);
       else
         {
           GtkATContext *ctx = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child));
-          g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@(so))", 
gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (ctx))));
+          g_dbus_method_invocation_return_value (invocation,
+              g_variant_new ("(@(so))", gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (ctx))));
         }
     }
   else if (g_strcmp0 (method_name, "SelectChild") == 0)
     {
       int idx;
-      gboolean ret;
+      GtkWidget *child;
 
       g_variant_get (parameters, "(i)", &idx);
 
-      ret = gtk_selection_model_select_item (model, idx, FALSE);
+      for (child = gtk_widget_get_first_child (widget);
+           child;
+           child = gtk_widget_get_next_sibling (child))
+        {
+          if (idx == 0)
+            break;
+          idx--;
+        }
 
-      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+      if (child == NULL)
+        g_dbus_method_invocation_return_error (invocation,
+                                               G_DBUS_ERROR,
+                                               G_DBUS_ERROR_INVALID_ARGS,
+                                               "No child for %d", idx);
+      else
+        {
+          guint pos;
+          gboolean ret;
+
+          pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (child));
+          ret = gtk_selection_model_select_item (model, pos, FALSE);
+
+          g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+        }
     }
   else if (g_strcmp0 (method_name, "DeselectChild") == 0)
     {
       int idx;
-      gboolean ret;
+      GtkWidget *child;
 
       g_variant_get (parameters, "(i)", &idx);
 
-      ret = gtk_selection_model_select_item (model, idx, FALSE);
+      for (child = gtk_widget_get_first_child (widget);
+           child;
+           child = gtk_widget_get_next_sibling (child))
+        {
+          if (idx == 0)
+            break;
+          idx--;
+        }
 
-      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+      if (child == NULL)
+        g_dbus_method_invocation_return_error (invocation,
+                                               G_DBUS_ERROR,
+                                               G_DBUS_ERROR_INVALID_ARGS,
+                                               "No child for %d", idx);
+      else
+        {
+          guint pos;
+          gboolean ret;
+
+          pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (child));
+          ret = gtk_selection_model_unselect_item (model, pos);
+
+          g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+        }
     }
   else if (g_strcmp0 (method_name, "DeselectSelectedChild") == 0)
     {
       int idx;
-      guint pos;
-      GtkBitset *set;
-      gboolean ret;
+      GtkWidget *child;
 
       g_variant_get (parameters, "(i)", &idx);
 
-      set = gtk_selection_model_get_selection (model);
-      pos = gtk_bitset_get_nth (set, idx);
-      gtk_bitset_unref (set);
+      /* We are asked for the n-th selected child *among the current children* */
+      for (child = gtk_widget_get_first_child (widget);
+           child;
+           child = gtk_widget_get_next_sibling (child))
+        {
+          if (gtk_list_item_widget_get_selected (GTK_LIST_ITEM_WIDGET (child)))
+            {
+              if (idx == 0)
+                break;
+              idx--;
+            }
+        }
 
-      ret = gtk_selection_model_unselect_item (model, pos);
+      if (child == NULL)
+        g_dbus_method_invocation_return_error (invocation,
+                                               G_DBUS_ERROR,
+                                               G_DBUS_ERROR_INVALID_ARGS,
+                                               "No selected child for %d", idx);
+      else
+        {
+          guint pos;
+          gboolean ret;
 
-      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+          pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (child));
+          ret = gtk_selection_model_unselect_item (model, pos);
+
+          g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+        }
     }
   else if (g_strcmp0 (method_name, "IsChildSelected") == 0)
     {
       int idx;
-      gboolean ret;
+      GtkWidget *child;
 
       g_variant_get (parameters, "(i)", &idx);
 
-      ret = gtk_selection_model_is_selected (model, idx);
+      for (child = gtk_widget_get_first_child (widget);
+           child;
+           child = gtk_widget_get_next_sibling (child))
+        {
+          if (idx == 0)
+            break;
+          idx--;
+        }
 
-      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+      if (child == NULL)
+        g_dbus_method_invocation_return_error (invocation,
+                                               G_DBUS_ERROR,
+                                               G_DBUS_ERROR_INVALID_ARGS,
+                                               "No child for %d", idx);
+      else
+        {
+          gboolean ret;
+
+          ret = gtk_list_item_widget_get_selected (GTK_LIST_ITEM_WIDGET (child));
+
+          g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));
+        }
     }
   else if (g_strcmp0 (method_name, "SelectAll") == 0)
     {
       gboolean ret;
 
+      /* This is a bit inconsistent - the Selection interface is defined in terms
+       * of the current children, but this selects all items in the model, whether
+       * they are currently represented or not.
+       */
       ret = gtk_selection_model_select_all (model);
 
       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", ret));


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