From 31b95ce47f214965323d980bd09a7a1bed65ed7e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 22 Jun 2020 15:31:36 +0200 Subject: [PATCH] gtkmain: Look up transient-for hierarchies to determine modality Windows that are not modal, but are transient-for a modal window should still be able to receive and handle events. Inspect the window hierarchy in those cases, so these windows are handled just like widgets within the modal dialog. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2851 Related: https://gitlab.gnome.org/GNOME/gtk/-/issues/2850 --- gtk/gtkmain.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 84e7efdc8d..fd43c9eb77 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1663,6 +1663,25 @@ handle_key_event (GdkEvent *event) return focus_widget ? focus_widget : event_widget; } +static gboolean +is_transient_for (GtkWindow *child, + GtkWindow *parent) +{ + GtkWindow *transient_for; + + transient_for = gtk_window_get_transient_for (child); + + while (transient_for) + { + if (transient_for == parent) + return TRUE; + + transient_for = gtk_window_get_transient_for (transient_for); + } + + return FALSE; +} + void gtk_main_do_event (GdkEvent *event) { @@ -1726,11 +1745,16 @@ gtk_main_do_event (GdkEvent *event) /* If the grab widget is an ancestor of the event widget * then we send the event to the original event widget. - * This is the key to implementing modality. + * This is the key to implementing modality. This also applies + * across windows that are directly or indirectly transient-for + * the modal one. */ if (!grab_widget || ((gtk_widget_is_sensitive (target_widget) || gdk_event_get_event_type (event) == GDK_SCROLL) && - gtk_widget_is_ancestor (target_widget, grab_widget))) + gtk_widget_is_ancestor (target_widget, grab_widget)) || + (GTK_IS_WINDOW (grab_widget) && + grab_widget != event_widget && + is_transient_for (GTK_WINDOW (event_widget), GTK_WINDOW (grab_widget)))) grab_widget = target_widget; g_object_ref (target_widget);