container: Only do custom focus management if a focus chain is set
authorTimm Bäder <mail@baedert.org>
Sat, 17 Mar 2018 08:54:22 +0000 (09:54 +0100)
committerTimm Bäder <mail@baedert.org>
Sat, 17 Mar 2018 11:09:30 +0000 (12:09 +0100)
Otherwise, the process should be the same one we use in GtkWidget.

gtk/gtkcontainer.c
gtk/gtkwidgetfocus.c

index 39151d9a59e4f5b3f1f64a7d13210de3428941e0..05e0a837dcf7563ae058a225bed057d258b68c70 100644 (file)
@@ -192,9 +192,6 @@ static gboolean gtk_container_focus                (GtkWidget         *widget,
 static void     gtk_container_real_set_focus_child (GtkContainer      *container,
                                                     GtkWidget         *widget);
 
-static gboolean gtk_container_focus_move           (GtkContainer      *container,
-                                                    GList             *children,
-                                                    GtkDirectionType   direction);
 static void     gtk_container_children_callback    (GtkWidget         *widget,
                                                     gpointer           client_data);
 static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget   *widget);
@@ -1951,20 +1948,6 @@ get_focus_chain (GtkContainer *container)
   return g_object_get_qdata (G_OBJECT (container), quark_focus_chain);
 }
 
-/* same as gtk_container_get_children, except it includes internals
- */
-static GList *
-gtk_container_get_all_children (GtkContainer *container)
-{
-  GList *children = NULL;
-
-  gtk_container_forall (container,
-                         gtk_container_children_callback,
-                         &children);
-
-  return children;
-}
-
 static GtkWidgetPath *
 gtk_container_real_get_path_for_child (GtkContainer *container,
                                        GtkWidget    *child)
@@ -1979,14 +1962,28 @@ gtk_container_real_get_path_for_child (GtkContainer *container,
   return path;
 }
 
+/* Utility function, equivalent to g_list_reverse */
+static void
+reverse_ptr_array (GPtrArray *arr)
+{
+  int i;
+
+  for (i = 0; i < arr->len / 2; i ++)
+    {
+      void *a = g_ptr_array_index (arr, i);
+      void *b = g_ptr_array_index (arr, arr->len - 1 - i);
+
+      arr->pdata[i] = b;
+      arr->pdata[arr->len - 1 - i] = a;
+    }
+}
+
 static gboolean
 gtk_container_focus (GtkWidget        *widget,
                      GtkDirectionType  direction)
 {
   GtkContainerPrivate *priv;
-  GList *children;
-  GList *sorted_children;
-  gint return_val;
+  gint return_val = FALSE;
   GtkContainer *container;
 
   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
@@ -1994,42 +1991,39 @@ gtk_container_focus (GtkWidget        *widget,
   container = GTK_CONTAINER (widget);
   priv = gtk_container_get_instance_private (container);
 
-  return_val = FALSE;
-
-  if (gtk_widget_get_can_focus (widget))
+  if (!priv->has_focus_chain)
     {
-      if (!gtk_widget_has_focus (widget))
-        {
-          gtk_widget_grab_focus (widget);
-          return_val = TRUE;
-        }
+      return_val = GTK_WIDGET_CLASS (gtk_container_parent_class)->focus (widget, direction);
     }
   else
     {
-      /* Get a list of the containers children, allowing focus
-       * chain to override.
-       */
-      if (priv->has_focus_chain)
-        children = g_list_copy (get_focus_chain (container));
-      else
-        children = gtk_container_get_all_children (container);
+      GList *focus_chain;
+      GList *l;
+      GPtrArray *child_array;
 
-      if (priv->has_focus_chain &&
-          (direction == GTK_DIR_TAB_FORWARD ||
-           direction == GTK_DIR_TAB_BACKWARD))
-        {
-          sorted_children = g_list_copy (children);
+      /* Here we compute the next focus child based on the focus chain set on @container.
+       * If we move via TAB, we consider the focus chain widgets in the order given to us (or in reverse).
+       * If UP/DOWN/LEFT/RIGHT are used, we sort the focus chain like normal, using their allocation. */
+      focus_chain = get_focus_chain (container);
+      child_array = g_ptr_array_sized_new (g_list_length (focus_chain));
 
-          if (direction == GTK_DIR_TAB_BACKWARD)
-            sorted_children = g_list_reverse (sorted_children);
+      for (l = focus_chain; l; l = l->next)
+        g_ptr_array_add (child_array, l->data);
+
+      if (direction == GTK_DIR_TAB_BACKWARD)
+        {
+          /* Reverse order for gtk_widget_focus_move to consider */
+          reverse_ptr_array (child_array);
+        }
+      else if (direction != GTK_DIR_TAB_FORWARD)
+        {
+          /* Nothing to be done. We don't sort the children, and we don't reverse them either. */
+          gtk_widget_focus_sort (widget, direction, child_array);
         }
-      else
-        sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
 
-      return_val = gtk_container_focus_move (container, sorted_children, direction);
+      return_val = gtk_widget_focus_move (widget, direction, child_array);
 
-      g_list_free (sorted_children);
-      g_list_free (children);
+      g_ptr_array_free (child_array, TRUE);
     }
 
   return return_val;
@@ -2472,46 +2466,6 @@ _gtk_container_focus_sort (GtkContainer     *container,
     }
 }
 
-static gboolean
-gtk_container_focus_move (GtkContainer     *container,
-                          GList            *children,
-                          GtkDirectionType  direction)
-{
-  GtkWidget *focus_child;
-  GtkWidget *child;
-
-  focus_child = gtk_widget_get_focus_child (GTK_WIDGET (container));
-
-  while (children)
-    {
-      child = children->data;
-      children = children->next;
-
-      if (!child)
-        continue;
-
-      if (focus_child)
-        {
-          if (focus_child == child)
-            {
-              focus_child = NULL;
-
-                if (gtk_widget_child_focus (child, direction))
-                  return TRUE;
-            }
-        }
-      else if (_gtk_widget_is_drawable (child) &&
-               gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
-        {
-          if (gtk_widget_child_focus (child, direction))
-            return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-
 static void
 gtk_container_children_callback (GtkWidget *widget,
                                  gpointer   client_data)
index 3fb4adec38fe370bd82e4cdc16e03404b624b224..40990007e601c878a5e25ef348e8aa1f54ec66c0 100644 (file)
@@ -424,15 +424,18 @@ gtk_widget_focus_sort (GtkWidget        *widget,
 {
   GtkWidget *child;
 
-  g_assert (focus_order->len == 0);
+  g_assert (focus_order != NULL);
 
-  /* Initialize the list with all realized child widgets */
-  for (child = _gtk_widget_get_first_child (widget);
-       child != NULL;
-       child = _gtk_widget_get_next_sibling (child))
+  if (focus_order->len == 0)
     {
-      if (_gtk_widget_get_realized (child))
-        g_ptr_array_add (focus_order, child);
+      /* Initialize the list with all realized child widgets */
+      for (child = _gtk_widget_get_first_child (widget);
+           child != NULL;
+           child = _gtk_widget_get_next_sibling (child))
+        {
+          if (_gtk_widget_get_realized (child))
+            g_ptr_array_add (focus_order, child);
+        }
     }
 
   /* Now sort that list depending on @direction */