From f003a4c6cc6f98c047571c5784712ba486dc17c6 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 17 May 2021 23:44:28 +0200 Subject: [PATCH 1/3] gtkwindow: Simplify GTK grab notification The _gtk_widget_grab_notify() function just (maybe) did a) reset controllers and b) hide toplevels. The second part was a testing remnant introduced in commit 024d832d943, not part of the original fix. Do the former more concisely, called from the place where we figure out whether a widget's ability to receive events changed due to GTK grabs. It's across those changes that we are interested in resetting the controllers. With the gestures being reset both ways, GtkWindowHandle (and probably other) gestures are now able to reset after a GTK grab takes input away (e.g. GtkMenuButton). This could be seen as a sudden jump the next time they'd be dragged with the mouse, as the gesture would "resume" the previous interaction. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3942 --- gtk/gtkwidget.c | 28 ---------------------------- gtk/gtkwidgetprivate.h | 2 -- gtk/gtkwindow.c | 4 ++-- 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index c45810a455..a7bdf8b08f 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -748,34 +748,6 @@ gtk_widget_real_contains (GtkWidget *widget, &GRAPHENE_POINT_INIT (x, y)); } -/* - * _gtk_widget_grab_notify: - * @widget: a `GtkWidget` - * @was_grabbed: whether a grab is now in effect - * - * Emits the `GtkWidget`::grab-notify signal on @widget. - */ -void -_gtk_widget_grab_notify (GtkWidget *widget, - gboolean was_grabbed) -{ - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - GList *l; - - if (was_grabbed) - return; - - for (l = g_list_last (priv->event_controllers); l; l = l->prev) - { - GtkEventController *controller = l->data; - - gtk_event_controller_reset (controller); - } - - if (GTK_IS_NATIVE (widget)) - gtk_widget_hide (widget); -} - static void gtk_widget_real_root (GtkWidget *widget) { diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 4aee55cb6b..2863787e24 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -247,8 +247,6 @@ void _gtk_widget_set_has_grab (GtkWidget *widget, gboolean has_grab); gboolean gtk_widget_has_grab (GtkWidget *widget); -void _gtk_widget_grab_notify (GtkWidget *widget, - gboolean was_grabbed); void _gtk_widget_propagate_display_changed (GtkWidget *widget, GdkDisplay *previous_display); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index d7048ed412..add3caf85e 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -6732,8 +6732,6 @@ gtk_grab_notify_foreach (GtkWidget *child, GDK_CROSSING_GTK_UNGRAB); } - _gtk_widget_grab_notify (child, was_shadowed); - g_object_unref (child); } @@ -6776,6 +6774,8 @@ gtk_window_propagate_grab_notify (GtkWindow *window, from_grab, was_shadowed, is_shadowed); + + gtk_widget_reset_controllers (l->data); } g_list_free_full (widgets, g_object_unref); From 0a5d21ca9e234137ff488bbd6379330108eb218a Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 17 May 2021 23:55:47 +0200 Subject: [PATCH 2/3] gtkwindow: Rename function With gtk_grab_notify_foreach() just taking care of emitting crossing notifications due to the GTK grab change, rename it to a more apt gtk_synthesize_grab_crossing(). --- gtk/gtkwindow.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index add3caf85e..33e1379a25 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -6703,13 +6703,13 @@ gtk_window_get_foci_on_widget (GtkWindow *window, } static void -gtk_grab_notify_foreach (GtkWidget *child, - GdkDevice *device, - GtkWidget *new_grab_widget, - GtkWidget *old_grab_widget, - gboolean from_grab, - gboolean was_shadowed, - gboolean is_shadowed) +gtk_synthesize_grab_crossing (GtkWidget *child, + GdkDevice *device, + GtkWidget *new_grab_widget, + GtkWidget *old_grab_widget, + gboolean from_grab, + gboolean was_shadowed, + gboolean is_shadowed) { g_object_ref (child); @@ -6767,13 +6767,13 @@ gtk_window_propagate_grab_notify (GtkWindow *window, if (was_shadowed == is_shadowed) break; - gtk_grab_notify_foreach (l->data, - device, - old_grab_widget, - new_grab_widget, - from_grab, - was_shadowed, - is_shadowed); + gtk_synthesize_grab_crossing (l->data, + device, + old_grab_widget, + new_grab_widget, + from_grab, + was_shadowed, + is_shadowed); gtk_widget_reset_controllers (l->data); } From 6b7b23211483abb1aa80f1439915b1de2eedd5ec Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 17 May 2021 23:57:17 +0200 Subject: [PATCH 3/3] gtkwindow: Fix "shadowed" checks for GTK grabs We iterate here from the target widget up the toplevel checking for the previous and new grab, there's however 2 bugs here: - The check for is_shadowed was different to the check for was_shadowed - The loop started with the assumption that the widgets did not hold a grab, just to change it if the grab widget was found. (or maybe it's the other way around? it's unclear with the differing checks for past/present state). Make these checks consistent, and ensure we start with the right assumption for the past/present grabbing state, and accounting that new/old grab widgets may or may not be part of the pick stack. --- gtk/gtkwindow.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 33e1379a25..5d6ba32897 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -6748,6 +6748,10 @@ gtk_window_propagate_grab_notify (GtkWindow *window, while (target) { + if (target == old_grab_widget) + was_grabbed = TRUE; + if (target == new_grab_widget) + is_grabbed = TRUE; widgets = g_list_prepend (widgets, g_object_ref (target)); target = gtk_widget_get_parent (target); } @@ -6758,11 +6762,13 @@ gtk_window_propagate_grab_notify (GtkWindow *window, { gboolean was_shadowed, is_shadowed; - was_grabbed |= (l->data == old_grab_widget); - is_grabbed |= (l->data == new_grab_widget); - was_shadowed = old_grab_widget && !was_grabbed; - is_shadowed = new_grab_widget && is_grabbed; + is_shadowed = new_grab_widget && !is_grabbed; + + if (l->data == old_grab_widget) + was_grabbed = FALSE; + if (l->data == new_grab_widget) + is_grabbed = FALSE; if (was_shadowed == is_shadowed) break;