[gtk/wip/matthiasc/focus2: 5/6] widget: Add a next-focus-child API



commit d3771c57edf782c2a1dbd29d85e3f2ed8bda13b5
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Mar 2 14:35:14 2019 -0500

    widget: Add a next-focus-child API
    
    Move things around to make the focus chain introspectable.
    Use the next-focus-child api in the move-focus implementation.
    
    We add a next_focus_child vfunc that containers can
    override to tweak the behavior.

 gtk/gtkwidget.c        |  9 ++++--
 gtk/gtkwidget.h        |  6 ++++
 gtk/gtkwidgetfocus.c   | 75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkwidgetprivate.h |  3 ++
 4 files changed, 89 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 0aaa77579c..8905298be9 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -931,6 +931,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->mnemonic_activate = gtk_widget_real_mnemonic_activate;
   klass->grab_focus = gtk_widget_real_grab_focus;
   klass->focus = gtk_widget_real_focus;
+  klass->next_focus_child = gtk_widget_next_focus_child;
   klass->move_focus = gtk_widget_real_move_focus;
   klass->keynav_failed = gtk_widget_real_keynav_failed;
   klass->drag_begin = NULL;
@@ -5441,10 +5442,12 @@ static void
 gtk_widget_real_move_focus (GtkWidget         *widget,
                             GtkDirectionType   direction)
 {
-  GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
+  GtkWidget *focus_child;
+  GtkWidget *next_focus;
 
-  if (widget != toplevel && GTK_IS_WINDOW (toplevel))
-    g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0, direction);
+  focus_child = gtk_root_get_focus (gtk_widget_get_root (widget));
+  next_focus = gtk_widget_get_next_focus (focus_child, direction);
+  gtk_widget_grab_focus (next_focus);
 }
 
 static gboolean
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index db4a81272c..c9d7d566aa 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -280,6 +280,9 @@ struct _GtkWidgetClass
   void     (* grab_focus)               (GtkWidget           *widget);
   gboolean (* focus)                    (GtkWidget           *widget,
                                          GtkDirectionType     direction);
+  GtkWidget * (* next_focus_child)      (GtkWidget           *widget,
+                                         GtkWidget           *child,
+                                         GtkDirectionType     direction);
 
   /* keyboard navigation */
   void     (* move_focus)               (GtkWidget           *widget,
@@ -480,6 +483,9 @@ gboolean   gtk_widget_has_visible_focus   (GtkWidget           *widget);
 GDK_AVAILABLE_IN_ALL
 void       gtk_widget_grab_focus          (GtkWidget           *widget);
 GDK_AVAILABLE_IN_ALL
+GtkWidget *gtk_widget_get_next_focus      (GtkWidget           *widget,
+                                           GtkDirectionType     direction);
+GDK_AVAILABLE_IN_ALL
 void       gtk_widget_set_focus_on_click  (GtkWidget           *widget,
                                            gboolean             focus_on_click);
 GDK_AVAILABLE_IN_ALL
diff --git a/gtk/gtkwidgetfocus.c b/gtk/gtkwidgetfocus.c
index c29adfdbe0..59c2c713eb 100644
--- a/gtk/gtkwidgetfocus.c
+++ b/gtk/gtkwidgetfocus.c
@@ -422,7 +422,8 @@ gtk_widget_focus_sort (GtkWidget        *widget,
            child != NULL;
            child = _gtk_widget_get_next_sibling (child))
         {
-          if (_gtk_widget_get_realized (child))
+          if (_gtk_widget_get_realized (child) &&
+              gtk_widget_get_sensitive (child))
             g_ptr_array_add (focus_order, child);
         }
     }
@@ -483,3 +484,75 @@ gtk_widget_focus_move (GtkWidget        *widget,
 
   return ret;
 }
+
+/**
+ * gtk_widget_get_next_focus:
+ * @widget: a #GtkWidget
+ * @direction: diretion to move in
+ *
+ * Finds the widget that would get focused if @widget was
+ * the focus widget, and focus was moved in @direcion.
+ *
+ * Returns: (nullable): (transfer none): the next focus widget
+ */
+GtkWidget *
+gtk_widget_get_next_focus (GtkWidget        *widget,
+                           GtkDirectionType  dir)
+{
+  GtkWidget *prev;
+  GtkWidget *next;
+
+  prev = NULL;
+  do {
+    next = GTK_WIDGET_GET_CLASS (widget)->next_focus_child (widget, prev, dir);
+    if (gtk_widget_get_can_focus (next))
+      {
+        return next;
+      }
+    else if (next == NULL)
+      {
+        prev = widget;
+        widget = gtk_widget_get_parent (widget);
+      }
+    else
+      {
+        widget = next;
+        prev = NULL;
+      }
+  } while (widget);
+
+  return NULL;
+}
+
+GtkWidget *
+gtk_widget_next_focus_child (GtkWidget        *widget,
+                             GtkWidget        *focus_child,
+                             GtkDirectionType  direction)
+{
+  GPtrArray *focus_order;
+  int i;
+  GtkWidget *next_child = NULL;
+
+  focus_order = g_ptr_array_new ();
+  gtk_widget_focus_sort (widget, direction, focus_order);
+
+  for (i = 0; i < focus_order->len; i++)
+    {
+      GtkWidget *child = g_ptr_array_index (focus_order, i);
+
+      if (focus_child)
+        {
+          if (focus_child == child)
+            focus_child = NULL;
+        }
+      else
+        {
+          next_child = child;
+          break;
+        }
+    }
+
+  g_ptr_array_unref (focus_order);
+
+  return next_child;
+}
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 6510565ddb..ec4ca27fae 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -319,6 +319,9 @@ void              gtk_widget_focus_sort                    (GtkWidget        *wi
                                                             GPtrArray        *focus_order);
 gboolean          gtk_widget_focus_move                    (GtkWidget        *widget,
                                                             GtkDirectionType  direction);
+GtkWidget *       gtk_widget_next_focus_child              (GtkWidget        *widget,
+                                                            GtkWidget        *child,
+                                                            GtkDirectionType  direction);
 void              gtk_widget_get_surface_allocation         (GtkWidget *widget,
                                                             GtkAllocation *allocation);
 


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