From 123c6dc5586dd19d04055cc329e6507d602c869a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 10 Dec 2014 22:32:45 -0500 Subject: [PATCH] GtkStack: Improve focus handling Add notebook-like focus handling: Keep track of the last focused descendent of each page, and focus it again when switching back to the page. If there is no last focused child, we move the focus into the page as if the user had hit Tab. --- gtk/gtkstack.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c index 9726beddb4..b880c6473d 100644 --- a/gtk/gtkstack.c +++ b/gtk/gtkstack.c @@ -112,6 +112,7 @@ struct _GtkStackChildInfo { gchar *title; gchar *icon_name; gboolean needs_attention; + GtkWidget *last_focus; }; typedef struct { @@ -996,6 +997,9 @@ set_visible_child (GtkStack *stack, GtkStackChildInfo *info; GtkWidget *widget = GTK_WIDGET (stack); GList *l; + GtkWidget *toplevel; + GtkWidget *focus; + gboolean contains_focus = FALSE; /* If none, pick first visible */ if (child_info == NULL) @@ -1014,6 +1018,25 @@ set_visible_child (GtkStack *stack, if (child_info == priv->visible_child) return; + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_WINDOW (toplevel)) + { + focus = gtk_window_get_focus (GTK_WINDOW (toplevel)); + if (focus && + priv->visible_child && + gtk_widget_is_ancestor (focus, priv->visible_child->widget)) + { + contains_focus = TRUE; + + if (priv->visible_child->last_focus) + g_object_remove_weak_pointer (G_OBJECT (priv->visible_child->last_focus), + (gpointer *)&priv->visible_child->last_focus); + priv->visible_child->last_focus = focus; + g_object_add_weak_pointer (G_OBJECT (priv->visible_child->last_focus), + (gpointer *)&priv->visible_child->last_focus); + } + } + if (priv->last_visible_child) gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE); priv->last_visible_child = NULL; @@ -1033,7 +1056,17 @@ set_visible_child (GtkStack *stack, priv->visible_child = child_info; if (child_info) - gtk_widget_set_child_visible (child_info->widget, TRUE); + { + gtk_widget_set_child_visible (child_info->widget, TRUE); + + if (contains_focus) + { + if (child_info->last_focus) + gtk_widget_grab_focus (child_info->last_focus); + else + gtk_widget_child_focus (child_info->widget, GTK_DIR_TAB_FORWARD); + } + } if ((child_info == NULL || priv->last_visible_child == NULL) && is_direction_dependent_transition (transition_type)) @@ -1164,6 +1197,7 @@ gtk_stack_add (GtkContainer *container, child_info->title = NULL; child_info->icon_name = NULL; child_info->needs_attention = FALSE; + child_info->last_focus = NULL; priv->children = g_list_append (priv->children, child_info); @@ -1224,6 +1258,11 @@ gtk_stack_remove (GtkContainer *container, g_free (child_info->name); g_free (child_info->title); g_free (child_info->icon_name); + + if (child_info->last_focus) + g_object_remove_weak_pointer (G_OBJECT (child_info->last_focus), + (gpointer *)&child_info->last_focus); + g_slice_free (GtkStackChildInfo, child_info); if ((priv->hhomogeneous || priv->vhomogeneous) && was_visible)