From 4f2ce2f7b6a70fb5abe012e90c06a92e7371f484 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 24 Oct 2011 10:59:23 +0200 Subject: [PATCH] gtk: emit ::captured-event starting from the GTK grab widget --- gtk/gtkmain.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index f6ee681023..b0c10a1dc2 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -133,7 +133,8 @@ #include "a11y/gailutil.h" static gboolean gtk_propagate_captured_event (GtkWidget *widget, - GdkEvent *event); + GdkEvent *event, + GtkWidget *topmost); /* Private type definitions */ @@ -1476,6 +1477,7 @@ gtk_main_do_event (GdkEvent *event) { GtkWidget *event_widget; GtkWidget *grab_widget = NULL; + GtkWidget *topmost_widget = NULL; GtkWindowGroup *window_group; GdkEvent *rewritten_event = NULL; GdkDevice *device; @@ -1535,6 +1537,14 @@ gtk_main_do_event (GdkEvent *event) if (!grab_widget) grab_widget = gtk_window_group_get_current_grab (window_group); + /* Find out the topmost widget where captured event propagation + * should start, which is the widget holding the GTK+ grab + * if any, otherwise it's left NULL and events are emitted + * from the toplevel (or topmost parentless parent). + */ + if (grab_widget) + topmost_widget = grab_widget; + /* 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. @@ -1639,7 +1649,7 @@ gtk_main_do_event (GdkEvent *event) case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - if (!gtk_propagate_captured_event (grab_widget, event)) + if (!gtk_propagate_captured_event (grab_widget, event, topmost_widget)) gtk_propagate_event (grab_widget, event); break; @@ -1689,7 +1699,7 @@ gtk_main_do_event (GdkEvent *event) case GDK_BUTTON_RELEASE: case GDK_PROXIMITY_IN: case GDK_PROXIMITY_OUT: - if (!gtk_propagate_captured_event (grab_widget, event)) + if (!gtk_propagate_captured_event (grab_widget, event, topmost_widget)) gtk_propagate_event (grab_widget, event); break; @@ -2339,7 +2349,8 @@ gtk_get_event_widget (GdkEvent *event) static gboolean propagate_event_up (GtkWidget *widget, - GdkEvent *event) + GdkEvent *event, + GtkWidget *topmost) { gboolean handled_event = FALSE; @@ -2366,6 +2377,9 @@ propagate_event_up (GtkWidget *widget, tmp = gtk_widget_get_parent (widget); g_object_unref (widget); + if (widget == topmost) + break; + widget = tmp; if (handled_event || !widget) @@ -2377,20 +2391,24 @@ propagate_event_up (GtkWidget *widget, static gboolean propagate_event_down (GtkWidget *widget, - GdkEvent *event) + GdkEvent *event, + GtkWidget *topmost) { gint handled_event = FALSE; GList *widgets = NULL; GList *l; widgets = g_list_prepend (widgets, g_object_ref (widget)); - while (TRUE) + while (widget && widget != topmost) { widget = gtk_widget_get_parent (widget); if (!widget) break; widgets = g_list_prepend (widgets, g_object_ref (widget)); + + if (widget == topmost) + break; } for (l = widgets; l && !handled_event; l = g_list_next (l)) @@ -2410,7 +2428,8 @@ propagate_event_down (GtkWidget *widget, static gboolean propagate_event (GtkWidget *widget, GdkEvent *event, - gboolean captured) + gboolean captured, + GtkWidget *topmost) { gboolean handled_event = FALSE; gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event); @@ -2452,7 +2471,9 @@ propagate_event (GtkWidget *widget, } /* Other events get propagated up/down the widget tree */ - return captured ? propagate_event_down (widget, event) : propagate_event_up (widget, event); + return captured ? + propagate_event_down (widget, event, topmost) : + propagate_event_up (widget, event, topmost); } /** @@ -2486,12 +2507,13 @@ gtk_propagate_event (GtkWidget *widget, g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (event != NULL); - propagate_event (widget, event, FALSE); + propagate_event (widget, event, FALSE, NULL); } static gboolean gtk_propagate_captured_event (GtkWidget *widget, - GdkEvent *event) + GdkEvent *event, + GtkWidget *topmost) { - return propagate_event (widget, event, TRUE); + return propagate_event (widget, event, TRUE, topmost); }