diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-12-10 22:32:45 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-12-10 22:32:45 -0500 |
commit | 123c6dc5586dd19d04055cc329e6507d602c869a (patch) | |
tree | b0efd9c5360bc0fa5d954c4b1a9ec4b82f1a84b1 | |
parent | 5dd6ad0057a38b6257d40903ec5a3e26f1068f11 (diff) | |
download | gtk+-123c6dc5586dd19d04055cc329e6507d602c869a.tar.gz |
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.
-rw-r--r-- | gtk/gtkstack.c | 41 |
1 files changed, 40 insertions, 1 deletions
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) |