Skip to content

Commit

Permalink
gtkmain: Ignore grab for events in child popovers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
garnacho committed Jun 17, 2015
1 parent 76dc8ac commit 77d429b
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions gtk/gtkmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
*/
Expand Down

0 comments on commit 77d429b

Please sign in to comment.