summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2015-06-15 14:07:40 +0200
committerCarlos Garnacho <carlosg@gnome.org>2015-06-17 15:56:42 +0200
commit77d429bc4debc3840ccbed9faf5616792c3e4fb5 (patch)
tree070bfe5a4e4cb44fdaae6ec36f04211ebb05c027
parent76dc8aced5517b409e2cc7897e1d49a20a0c8ade (diff)
downloadgtk+-77d429bc4debc3840ccbed9faf5616792c3e4fb5.tar.gz
gtkmain: Ignore grab for events in child popovers
Popovers may be spawn when there's GTK+ grabs somewhere else (eg. text selection popover/handles in an entry in a modal popover). When this happens, events go to the grab widget (in this case the modal popover) and are effectively ignored by the event widget, even though it's can be conceptually a child of the grab widget. To get away with this, tweak a bit gtk_main_do_event(), so events going to popovers that are related to grab_widget or a child of it are received, as it would happen with regular children of grab_widget. https://bugzilla.gnome.org/show_bug.cgi?id=750993
-rw-r--r--gtk/gtkmain.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 35b0fa235d..6e5188b337 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1471,6 +1471,54 @@ rewrite_event_for_grabs (GdkEvent *event)
return NULL;
}
+static GtkWidget *
+widget_get_popover_ancestor (GtkWidget *widget,
+ GtkWindow *window)
+{
+ GtkWidget *parent = gtk_widget_get_parent (widget);
+
+ while (parent && parent != GTK_WIDGET (window))
+ {
+ widget = parent;
+ parent = gtk_widget_get_parent (widget);
+ }
+
+ if (!parent || parent != GTK_WIDGET (window))
+ return NULL;
+
+ if (_gtk_window_is_popover_widget (GTK_WINDOW (window), widget))
+ return widget;
+
+ return NULL;
+}
+
+static gboolean
+check_event_in_child_popover (GtkWidget *event_widget,
+ GtkWidget *grab_widget)
+{
+ GtkWidget *window, *popover = NULL, *popover_parent = NULL;
+
+ if (grab_widget == event_widget)
+ return FALSE;
+
+ window = gtk_widget_get_ancestor (event_widget, GTK_TYPE_WINDOW);
+
+ if (!window)
+ return FALSE;
+
+ popover = widget_get_popover_ancestor (event_widget, GTK_WINDOW (window));
+
+ if (!popover)
+ return FALSE;
+
+ popover_parent = _gtk_window_get_popover_parent (GTK_WINDOW (window), popover);
+
+ if (!popover_parent)
+ return FALSE;
+
+ return (popover_parent == grab_widget || gtk_widget_is_ancestor (popover_parent, grab_widget));
+}
+
/**
* gtk_main_do_event:
* @event: An event to process (normally passed by GDK)
@@ -1607,6 +1655,14 @@ gtk_main_do_event (GdkEvent *event)
gtk_widget_is_ancestor (event_widget, grab_widget)))
grab_widget = event_widget;
+ /* popovers are not really a "child" of their "parent" in the widget/window
+ * hierarchy sense, we however want to interact with popovers spawn by widgets
+ * within grab_widget. If this is the case, we let the event go through
+ * unaffected by the grab.
+ */
+ if (check_event_in_child_popover (event_widget, grab_widget))
+ grab_widget = event_widget;
+
/* If the widget receiving events is actually blocked by another
* device GTK+ grab
*/