summaryrefslogtreecommitdiff
path: root/gtk/gtkmain.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2002-03-02 20:37:07 +0000
committerOwen Taylor <otaylor@src.gnome.org>2002-03-02 20:37:07 +0000
commitb54e5f4ca17d56f4844caa9485989f65b18babda (patch)
tree951f60c1491f4e7c62c9ead4e18a76c72833f35a /gtk/gtkmain.c
parentdfe5724765acc217ce43b4f96cc0d6dc2d73016c (diff)
downloadgdk-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.c133
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