diff options
author | Owen Taylor <otaylor@redhat.com> | 2002-03-02 20:37:07 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2002-03-02 20:37:07 +0000 |
commit | b54e5f4ca17d56f4844caa9485989f65b18babda (patch) | |
tree | 951f60c1491f4e7c62c9ead4e18a76c72833f35a /gtk/gtkmain.c | |
parent | dfe5724765acc217ce43b4f96cc0d6dc2d73016c (diff) | |
download | gdk-pixbuf-b54e5f4ca17d56f4844caa9485989f65b18babda.tar.gz |
Robustify tracking of pointer grab window.
Fri Mar 1 18:39:44 2002 Owen Taylor <otaylor@redhat.com>
* gdk/x11/{gdkevents-x11.c,gdkmain-x11.c,gdkprivate-x11.h,
gdkwindow-x11.c}: Robustify tracking of pointer grab window.
* gdk/x11/gdkmain-x11.c: Keep track of current keyboard
grab window.
* gdk/x11/gdkmain-x11.c (gdk_pointer_grab_info_libgtk_only,
gdk_keyboard_grab_info_libgtk_only): Private libgtk => libgtk
API for finding out current grab information.
* gtk/gtkmain.c (rewrite_event_for_grabs): Rewrite events
so that the effective behavior of owner_events = TRUE is changed
to "deliver events to same window group normally" instead
of "deliver events to same application normally. #69934
* gtk/gtkrange.c: Use an explicit gtk_grab_add() so that
it works within the GtkList combo, where there is a
owner_events = FALSE gdk_pointer_grab() already in effect.
(#65006, reported by Damon Chaplin)
Diffstat (limited to 'gtk/gtkmain.c')
-rw-r--r-- | gtk/gtkmain.c | 133 |
1 files changed, 131 insertions, 2 deletions
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 2b659a467..c38607a39 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -980,6 +980,121 @@ gtk_main_iteration_do (gboolean blocking) return TRUE; } +/* private libgtk to libgdk interfaces + */ +gboolean gdk_pointer_grab_info_libgtk_only (GdkWindow **grab_window, + gboolean *owner_events); +gboolean gdk_keyboard_grab_info_libgtk_only (GdkWindow **grab_window, + gboolean *owner_events); + +static void +rewrite_events_translate (GdkWindow *old_window, + GdkWindow *new_window, + gdouble *x, + gdouble *y) +{ + gint old_origin_x, old_origin_y; + gint new_origin_x, new_origin_y; + + gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y); + gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y); + + *x += new_origin_x - old_origin_x; + *y += new_origin_y - old_origin_y; +} + +GdkEvent * +rewrite_event_for_window (GdkEvent *event, + GdkWindow *new_window) +{ + event = gdk_event_copy (event); + + switch (event->type) + { + case GDK_SCROLL: + rewrite_events_translate (event->any.window, + new_window, + &event->scroll.x, &event->scroll.y); + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + rewrite_events_translate (event->any.window, + new_window, + &event->button.x, &event->button.y); + break; + case GDK_MOTION_NOTIFY: + rewrite_events_translate (event->any.window, + new_window, + &event->motion.x, &event->motion.y); + break; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + break; + + default: + return event; + } + + g_object_unref (event->any.window); + event->any.window = g_object_ref (new_window); + + return event; +} + +/* If there is a pointer or keyboard grab in effect with owner_events = TRUE, + * then what X11 does is deliver the event normally if it was going to this + * client, otherwise, delivers it in terms of the grab window. This function + * rewrites events to the effect that events going to the same window group + * are delivered normally, otherwise, the event is delivered in terms of the + * grab window. + */ +static GdkEvent * +rewrite_event_for_grabs (GdkEvent *event) +{ + GdkWindow *grab_window; + GtkWidget *event_widget, *grab_widget;; + gboolean owner_events; + + switch (event->type) + { + case GDK_SCROLL: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_MOTION_NOTIFY: + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + if (!gdk_pointer_grab_info_libgtk_only (&grab_window, &owner_events) || + !owner_events) + return NULL; + break; + + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (!gdk_keyboard_grab_info_libgtk_only (&grab_window, &owner_events) || + !owner_events) + return NULL; + break; + + default: + return NULL; + } + + event_widget = gtk_get_event_widget (event); + gdk_window_get_user_data (grab_window, (void**) &grab_widget); + + if (grab_widget && + gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget)) + return rewrite_event_for_window (event, grab_window); + else + return NULL; +} + void gtk_main_do_event (GdkEvent *event) { @@ -987,6 +1102,7 @@ gtk_main_do_event (GdkEvent *event) GtkWidget *grab_widget; GtkWindowGroup *window_group; GdkEvent *next_event; + GdkEvent *rewritten_event = NULL; GList *tmp_list; /* If there are any events pending then get the next one. @@ -1045,14 +1161,24 @@ gtk_main_do_event (GdkEvent *event) return; } + + /* If pointer or keyboard grabs are in effect, munge the events + * so that each window group looks like a separate app. + */ + rewritten_event = rewrite_event_for_grabs (event); + if (rewritten_event) + { + event = rewritten_event; + event_widget = gtk_get_event_widget (event); + } + window_group = gtk_main_get_window_group (event_widget); + /* Push the event onto a stack of current events for * gtk_current_event_get(). */ current_events = g_list_prepend (current_events, event); - window_group = gtk_main_get_window_group (event_widget); - /* If there is a grab in effect... */ if (window_group->grabs) @@ -1198,6 +1324,9 @@ gtk_main_do_event (GdkEvent *event) tmp_list = current_events; current_events = g_list_remove_link (current_events, tmp_list); g_list_free_1 (tmp_list); + + if (rewritten_event) + gdk_event_free (rewritten_event); } gboolean |