Compare commits

...

1 Commits

Author SHA1 Message Date
António Fernandes
d7922c189f listbase: Allow scroll_to() to grab focus on inactive windows
`gtk_[grid,column]_view_scroll_to()` does 2 things when asked to focus:
1. it sets the focus item tracker to point to the requested position.
2. then it grabs focus on the item widget if focus is within the view.

However, the way it checks whether focus is within the view is faulty.
The FOCUS_WITHIN flag is set only if the global input focus is within.
But what we want to know here is whether the GtkRoot:focus widget is
within, regardless of the window being active or not, otherwise we
are not holding to our documented promise:

> This function works no matter if the listview is shown or focused.
> If it isn’t, then the changes will take effect once that happens.

If the containing window doesn't is inactive, setting the focus item
tracker without grabbing focus is useless, because, once a the window
becomes active, it resets the focus states all the way up from the
`GtkRoot:focus` widget.  But `GtkRoot:focus` was not changed because
we didn't grab focus, so, if it is another item widget than the one
requested, then even the focus item tracker resets to the original
focus, as a side effect of .set_focus_child()

Therefore, even if the window is inactive, we should grab focus if
the  `GtkRoot:focus` is within the view.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/6266
2023-12-16 11:02:55 +00:00

View File

@@ -116,6 +116,25 @@ G_GNUC_UNUSED static void gtk_list_base_init (GtkListBase *self) { }
static GParamSpec *properties[N_PROPS] = { NULL, };
static gboolean
gtk_list_base_adjustment_is_focus_within (GtkListBase *self)
{
GtkRoot *root;
GtkWidget *focus_widget;
root = _gtk_widget_get_root (GTK_WIDGET (self));
if (root == NULL)
return FALSE;
focus_widget = gtk_root_get_focus (root);
if (focus_widget == NULL)
return FALSE;
return (focus_widget == GTK_WIDGET (self) ||
gtk_widget_is_ancestor (focus_widget, GTK_WIDGET (self)));
}
/*
* gtk_list_base_get_position_from_allocation:
* @self: a `GtkListBase`
@@ -2353,8 +2372,7 @@ gtk_list_base_scroll_to (GtkListBase *self,
gtk_list_item_tracker_set_position (priv->item_manager, priv->focus, pos, 0, 0);
/* XXX: Is this the proper check? */
if (gtk_widget_get_state_flags (GTK_WIDGET (self)) & GTK_STATE_FLAG_FOCUS_WITHIN)
if (gtk_list_base_adjustment_is_focus_within (self))
{
GtkListTile *tile = gtk_list_item_manager_get_nth (priv->item_manager, pos, NULL);