diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-01-29 21:41:16 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-01-29 21:41:16 -0500 |
commit | 3dbf5038fab8eb0d8c112ad179c5647e0306656e (patch) | |
tree | 02dbb1db3a9ff14bb7bdc6d73946e3a026f5f197 | |
parent | 456a2f3bcfe23c5a964d8f1e00b65d7e5445296e (diff) | |
download | gtk+-3dbf5038fab8eb0d8c112ad179c5647e0306656e.tar.gz |
Fix unsetting focus
Make _gtk_window_unset_focus_and_default queue the changes
for after the next draw. This achieves two things: first,
it avoids invalidating css at the wrong time (e.g. when
setting child-visible during size-allocation), and second,
it defers the focus change until after the widget is
hidden, so that moving the focus has the desired effect
of picking a different, visible widget.
Fixes: #3623
-rw-r--r-- | gtk/gtkwindow.c | 59 |
1 files changed, 29 insertions, 30 deletions
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 30f310197a..ac7f050738 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -225,6 +225,9 @@ typedef struct guint hide_on_close : 1; guint in_emit_close_request : 1; + guint move_focus : 1; + guint unset_default : 1; + GtkGesture *click_gesture; GtkEventController *application_shortcut_controller; @@ -4547,12 +4550,33 @@ surface_size_changed (GtkWidget *widget, gtk_widget_queue_allocate (widget); } +static void +maybe_unset_focus_and_default (GtkWindow *window) +{ + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + + if (priv->move_focus) + { + gtk_widget_child_focus (GTK_WIDGET (window), GTK_DIR_TAB_FORWARD); + priv->move_focus = FALSE; + } + + if (priv->unset_default) + { + gtk_window_set_default_widget (window, NULL); + priv->unset_default = FALSE; + } +} + static gboolean surface_render (GdkSurface *surface, cairo_region_t *region, GtkWidget *widget) { + GtkWindow *window = GTK_WINDOW (widget); + gtk_widget_render (widget, surface, region); + maybe_unset_focus_and_default (window); return TRUE; } @@ -4991,39 +5015,14 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); GtkWidget *child; - GtkWidget *parent; - GtkWidget *focus; - g_object_ref (window); - g_object_ref (widget); - - focus = priv->focus_widget; - if (focus && (focus == widget || gtk_widget_is_ancestor (focus, widget))) - { - parent = _gtk_widget_get_parent (widget); - - while (parent) - { - if (_gtk_widget_get_visible (parent)) - { - if (gtk_widget_grab_focus (parent)) - break; - } - - parent = gtk_widget_get_parent (parent); - } - } + child = priv->focus_widget; + if (child && (child == widget || gtk_widget_is_ancestor (child, widget))) + priv->move_focus = TRUE; child = priv->default_widget; - - while (child && child != widget) - child = _gtk_widget_get_parent (child); - - if (child == widget) - gtk_window_set_default_widget (window, NULL); - - g_object_unref (widget); - g_object_unref (window); + if (child && (child == widget || gtk_widget_is_ancestor (child, widget))) + priv->unset_default = TRUE; } #undef INCLUDE_CSD_SIZE |