listbase: Use set_focus_child properly
authorCorey Berla <corey@berla.me>
Mon, 24 Oct 2022 22:53:29 +0000 (15:53 -0700)
committerCorey Berla <corey@berla.me>
Wed, 14 Dec 2022 17:56:57 +0000 (07:56 -1000)
The EventControllerFocus on the list item, updates the list base focus
tracker and scrolled to position any time the list item enters focus.
This works when interacting within a single window, but has unexpected
results when changing focus between multiple windows.

Instead of using the focus controller workaround, just make
gtk_list_base_update_focus_tracker the set_focus_child vfunc

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5433
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5432
gtk/gtklistbase.c
gtk/gtklistitemwidget.c

index cedae1aa9b6534251c7481d7f607845849ec2159..1571be69c72592435c0e8d88db0bcf63832403dc 100644 (file)
@@ -802,28 +802,6 @@ gtk_list_base_compute_scroll_align (GtkListBase   *self,
     }
 }
 
-static void
-gtk_list_base_update_focus_tracker (GtkListBase *self)
-{
-  GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
-  GtkWidget *focus_child;
-  guint pos;
-
-  focus_child = gtk_widget_get_focus_child (GTK_WIDGET (self));
-  if (!GTK_IS_LIST_ITEM_WIDGET (focus_child))
-    return;
-
-  pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (focus_child));
-  if (pos != gtk_list_item_tracker_get_position (priv->item_manager, priv->focus))
-    {
-      gtk_list_item_tracker_set_position (priv->item_manager,
-                                          priv->focus,
-                                          pos,
-                                          0,
-                                          0);
-    }
-}
-
 static void
 gtk_list_base_scroll_to_item (GtkListBase *self,
                               guint        pos)
@@ -859,14 +837,6 @@ gtk_list_base_scroll_to_item (GtkListBase *self,
                             pos,
                             align_across, side_across,
                             align_along, side_along);
-
-  /* HACK HACK HACK
-   *
-   * GTK has no way to track the focused child. But we now that when a listitem
-   * gets focus, it calls this action. So we update our focus tracker from here
-   * because it's the closest we can get to accurate tracking.
-   */
-  gtk_list_base_update_focus_tracker (self);
 }
 
 static void
@@ -885,6 +855,32 @@ gtk_list_base_scroll_to_item_action (GtkWidget  *widget,
   gtk_list_base_scroll_to_item (self, pos);
 }
 
+static void
+gtk_list_base_set_focus_child (GtkWidget *widget,
+                               GtkWidget *child)
+{
+  GtkListBase *self = GTK_LIST_BASE (widget);
+  GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+  guint pos;
+
+  GTK_WIDGET_CLASS (gtk_list_base_parent_class)->set_focus_child (widget, child);
+
+  if (!GTK_IS_LIST_ITEM_WIDGET (child))
+    return;
+
+  pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (child));
+
+  if (pos != gtk_list_item_tracker_get_position (priv->item_manager, priv->focus))
+    {
+      gtk_list_base_scroll_to_item (self, pos);
+      gtk_list_item_tracker_set_position (priv->item_manager,
+                                          priv->focus,
+                                          pos,
+                                          0,
+                                          0);
+    }
+}
+
 static void
 gtk_list_base_select_item_action (GtkWidget  *widget,
                                   const char *action_name,
@@ -1143,6 +1139,7 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
 
   widget_class->focus = gtk_list_base_focus;
   widget_class->grab_focus = gtk_list_base_grab_focus;
+  widget_class->set_focus_child = gtk_list_base_set_focus_child;
 
   gobject_class->dispose = gtk_list_base_dispose;
   gobject_class->get_property = gtk_list_base_get_property;
index 2fb5e1633c5634c7703993b9e25416a62ee3c9d5..d19115020313fb782cb2be368d3b05efa2c1f2b7 100644 (file)
@@ -22,7 +22,6 @@
 #include "gtklistitemwidgetprivate.h"
 
 #include "gtkbinlayout.h"
-#include "gtkeventcontrollerfocus.h"
 #include "gtkeventcontrollermotion.h"
 #include "gtkgestureclick.h"
 #include "gtklistitemfactoryprivate.h"
@@ -467,19 +466,6 @@ gtk_list_item_widget_click_gesture_released (GtkGestureClick   *gesture,
   gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
 }
 
-static void
-gtk_list_item_widget_enter_cb (GtkEventControllerFocus *controller,
-                               GtkListItemWidget       *self)
-{
-  GtkWidget *widget = GTK_WIDGET (self);
-  GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
-
-  gtk_widget_activate_action (widget,
-                              "list.scroll-to-item",
-                              "u",
-                              priv->position);
-}
-
 static void
 gtk_list_item_widget_hover_cb (GtkEventControllerMotion *controller,
                                double                    x,
@@ -531,10 +517,6 @@ gtk_list_item_widget_init (GtkListItemWidget *self)
                     G_CALLBACK (gtk_list_item_widget_click_gesture_canceled), self);
   gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
 
-  controller = gtk_event_controller_focus_new ();
-  g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_enter_cb), self);
-  gtk_widget_add_controller (GTK_WIDGET (self), controller);
-
   controller = gtk_event_controller_motion_new ();
   g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_hover_cb), self);
   gtk_widget_add_controller (GTK_WIDGET (self), controller);