]> Pileus Git - ~andy/gtk/commitdiff
Robustify tracking of pointer grab window.
authorOwen Taylor <otaylor@redhat.com>
Sat, 2 Mar 2002 20:37:07 +0000 (20:37 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Sat, 2 Mar 2002 20:37:07 +0000 (20:37 +0000)
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)

13 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gdk/x11/gdkevents-x11.c
gdk/x11/gdkmain-x11.c
gdk/x11/gdkprivate-x11.h
gdk/x11/gdkwindow-x11.c
gtk/gtkmain.c
gtk/gtkrange.c

index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index a78504b4433cf55e7db0a7d488abe8fedfdde346..5fc8dfbc550127c84deaf4623bf40929ebc73747 100644 (file)
@@ -1,3 +1,25 @@
+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)
+
 Sat Mar  2 14:32:50 2002  Owen Taylor  <otaylor@redhat.com>
 
         * configure.in: Default to --disable-gtk-doc (avoid Jade
index 2d1e14bd588732092948de36ac671b4dcc0fab2c..babd7e35c8a30d0bbcfd44286efcb6753ab3a8f9 100644 (file)
@@ -1262,9 +1262,8 @@ gdk_event_translate (GdkEvent *event,
         gdk_synthesize_window_state (window,
                                      0,
                                      GDK_WINDOW_STATE_ICONIFIED);
-      
-      if (_gdk_xgrab_window == window_private)
-       _gdk_xgrab_window = NULL;
+
+      _gdk_xgrab_check_unmap (window, xevent->xany.serial);
       
       break;
       
index b6383a0dd4706d89839e335c4a2fe910d718eb00..0b87d8c0c0e5ad5cc85bb453a3029a12ffdcf248 100644 (file)
@@ -92,6 +92,18 @@ static gboolean gdk_synchronize = FALSE;
 static GSList *gdk_error_traps = NULL;               /* List of error traps */
 static GSList *gdk_error_trap_free_list = NULL;      /* Free list */
 
+/* Information about current pointer and keyboard grabs held by this
+ * client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window
+ * window is NULL, then the other associated fields are ignored
+ */
+static GdkWindowObject *gdk_pointer_xgrab_window = NULL;
+static gulong gdk_pointer_xgrab_serial;
+static gboolean gdk_pointer_xgrab_owner_events;
+
+static GdkWindowObject *gdk_keyboard_xgrab_window = NULL;
+static gulong gdk_keyboard_xgrab_serial;
+static gboolean gdk_keyboard_xgrab_owner_events;
+
 GdkArgDesc _gdk_windowing_args[] = {
   { "display",     GDK_ARG_STRING,   &_gdk_display_name,    (GdkArgFunc)NULL   },
   { "sync",        GDK_ARG_BOOL,     &gdk_synchronize,     (GdkArgFunc)NULL   },
@@ -251,6 +263,7 @@ gdk_pointer_grab (GdkWindow *         window,
   Window xwindow;
   Window xconfine_to;
   Cursor xcursor;
+  unsigned long serial;
   int i;
   
   g_return_val_if_fail (window != NULL, 0);
@@ -260,6 +273,7 @@ gdk_pointer_grab (GdkWindow *         window,
   cursor_private = (GdkCursorPrivate*) cursor;
   
   xwindow = GDK_WINDOW_XID (window);
+  serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
   
   if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
     xconfine_to = None;
@@ -308,7 +322,11 @@ gdk_pointer_grab (GdkWindow *        window,
     }
   
   if (return_val == GrabSuccess)
-    _gdk_xgrab_window = (GdkWindowObject *)window;
+    {
+      gdk_pointer_xgrab_window = (GdkWindowObject *)window;
+      gdk_pointer_xgrab_serial = serial;
+      gdk_pointer_xgrab_owner_events = owner_events;
+    }
 
   return gdk_x11_convert_grab_status (return_val);
 }
@@ -334,7 +352,7 @@ gdk_pointer_ungrab (guint32 time)
   _gdk_input_ungrab_pointer (time);
   
   XUngrabPointer (gdk_display, time);
-  _gdk_xgrab_window = NULL;
+  gdk_pointer_xgrab_window = NULL;
 }
 
 /*
@@ -355,7 +373,36 @@ gdk_pointer_ungrab (guint32 time)
 gboolean
 gdk_pointer_is_grabbed (void)
 {
-  return _gdk_xgrab_window != NULL;
+  return gdk_pointer_xgrab_window != NULL;
+}
+
+/**
+ * gdk_pointer_grab_info_libgtk_only:
+ * @grab_window: location to store current grab window
+ * @owner_events: location to store boolean indicating whether
+ *   the @owner_events flag to gdk_pointer_grab() was %TRUE.
+ * 
+ * Determines information about the current pointer grab.
+ * This is not public API and must not be used by applications.
+ * 
+ * Return value: %TRUE if this application currently has the
+ *  pointer grabbed.
+ **/
+gboolean
+gdk_pointer_grab_info_libgtk_only (GdkWindow **grab_window,
+                                  gboolean   *owner_events)
+{
+  if (gdk_pointer_xgrab_window)
+    {
+      if (grab_window)
+        *grab_window = (GdkWindow *)gdk_pointer_xgrab_window;
+      if (owner_events)
+        *owner_events = gdk_pointer_xgrab_owner_events;
+
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 /*
@@ -384,10 +431,13 @@ gdk_keyboard_grab (GdkWindow *       window,
                   guint32         time)
 {
   gint return_val;
+  unsigned long serial;
   
   g_return_val_if_fail (window != NULL, 0);
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
   
+  serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
+
   if (!GDK_WINDOW_DESTROYED (window))
     {
 #ifdef G_ENABLE_DEBUG
@@ -404,6 +454,13 @@ gdk_keyboard_grab (GdkWindow *        window,
   else
     return_val = AlreadyGrabbed;
 
+  if (return_val == GrabSuccess)
+    {
+      gdk_keyboard_xgrab_window = (GdkWindowObject *)window;
+      gdk_keyboard_xgrab_serial = serial;
+      gdk_keyboard_xgrab_owner_events = owner_events;
+    }
+
   return gdk_x11_convert_grab_status (return_val);
 }
 
@@ -426,6 +483,94 @@ void
 gdk_keyboard_ungrab (guint32 time)
 {
   XUngrabKeyboard (gdk_display, time);
+  gdk_keyboard_xgrab_window = NULL;
+}
+
+/**
+ * gdk_keyboard_grab_info_libgtk_only:
+ * @grab_window: location to store current grab window
+ * @owner_events: location to store boolean indicating whether
+ *   the @owner_events flag to gdk_keyboard_grab() was %TRUE.
+ * 
+ * Determines information about the current keyboard grab.
+ * This is not public API and must not be used by applications.
+ * 
+ * Return value: %TRUE if this application currently has the
+ *  keyboard grabbed.
+ **/
+gboolean
+gdk_keyboard_grab_info_libgtk_only (GdkWindow **grab_window,
+                                   gboolean   *owner_events)
+{
+  if (gdk_keyboard_xgrab_window)
+    {
+      if (grab_window)
+        *grab_window = (GdkWindow *)gdk_keyboard_xgrab_window;
+      if (owner_events)
+        *owner_events = gdk_keyboard_xgrab_owner_events;
+
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/**
+ * _gdk_xgrab_check_unmap:
+ * @window: a #GdkWindow
+ * @serial: serial from Unmap event (or from NextRequest(display)
+ *   if the unmap is being done by this client.)
+ * 
+ * Checks to see if an unmap request or event causes the current
+ * grab window to become not viewable, and if so, clear the
+ * the pointer we keep to it.
+ **/
+void
+_gdk_xgrab_check_unmap (GdkWindow *window,
+                       gulong     serial)
+{
+  if (gdk_pointer_xgrab_window && serial >= gdk_pointer_xgrab_serial)
+    {
+      GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+      GdkWindowObject *tmp = gdk_pointer_xgrab_window;
+      
+
+      while (tmp && tmp != private)
+       tmp = tmp->parent;
+
+      if (tmp)
+       gdk_pointer_xgrab_window = NULL;  
+    }
+
+  if (gdk_keyboard_xgrab_window && serial >= gdk_keyboard_xgrab_serial)
+    {
+      GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+      GdkWindowObject *tmp = gdk_keyboard_xgrab_window;
+      
+
+      while (tmp && tmp != private)
+       tmp = tmp->parent;
+
+      if (tmp)
+       gdk_keyboard_xgrab_window = NULL;  
+    }
+}
+
+/**
+ * _gdk_xgrab_check_destroy:
+ * @window: a #GdkWindow
+ * 
+ * Checks to see if window is the current grab window, and if
+ * so, clear the current grab window.
+ **/
+void
+_gdk_xgrab_check_destroy (GdkWindow *window)
+{
+  if ((GdkWindowObject *)window == gdk_pointer_xgrab_window)
+    gdk_pointer_xgrab_window = NULL;
+
+  if ((GdkWindowObject *)window == gdk_keyboard_xgrab_window)
+    gdk_keyboard_xgrab_window = NULL;
 }
 
 /*
index a495c518784620ae239aebf859d5d43b97868d65..2035e2066f7443dff63ba5dd7e44daedfbefa2e6 100644 (file)
@@ -165,6 +165,10 @@ GC _gdk_x11_gc_flush (GdkGC *gc);
 
 void _gdk_x11_initialize_locale (void);
 
+void _gdk_xgrab_check_unmap   (GdkWindow *window,
+                              gulong     serial);
+void _gdk_xgrab_check_destroy (GdkWindow *window);
+
 extern GdkDrawableClass  _gdk_x11_drawable_class;
 extern Window           _gdk_root_window;
 extern gboolean                 _gdk_use_xshm;
@@ -177,10 +181,6 @@ extern gchar               *_gdk_display_name;
 
 extern Window           _gdk_leader_window;
 
-extern GdkWindowObject *_gdk_xgrab_window;  /* Window that currently holds the
-                                           * x pointer grab
-                                           */
-
 /* Used to detect not-up-to-date keymap */
 extern guint _gdk_keymap_serial;
 
index 53779c08cedd9628e50e0ed6ee143a79c940efae..4779cb3829b79ad0b260b1681ebd20eb02913233 100644 (file)
@@ -169,6 +169,8 @@ gdk_window_impl_x11_finalize (GObject *object)
   
   wrapper = (GdkWindowObject*) draw_impl->wrapper;
 
+  _gdk_xgrab_check_destroy (GDK_WINDOW (wrapper));
+
   if (!GDK_WINDOW_DESTROYED (wrapper))
     {
       gdk_xid_table_remove (draw_impl->xid);
@@ -794,7 +796,9 @@ _gdk_windowing_window_destroy (GdkWindow *window,
        }
     }
   else if (!recursing && !foreign_destroy)
-    XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+    {
+      XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
+    }
 }
 
 /* This function is called when the XWindow is really gone.
@@ -819,6 +823,8 @@ gdk_window_destroy_notify (GdkWindow *window)
   gdk_xid_table_remove (GDK_WINDOW_XID (window));
   if (window_impl->focus_window)
     gdk_xid_table_remove (window_impl->focus_window);
+
+  _gdk_xgrab_check_destroy (window);
   
   gdk_drawable_unref (window);
 }
@@ -991,6 +997,13 @@ gdk_window_hide (GdkWindow *window)
 
   private = (GdkWindowObject*) window;
 
+  /* We'll get the unmap notify eventually, and handle it then,
+   * but checking here makes things more consistent if we are
+   * just doing stuff ourself.
+   */
+  _gdk_xgrab_check_unmap (window,
+                         NextRequest (GDK_WINDOW_XDISPLAY (window)));
+
   /* You can't simply unmap toplevel windows. */
   switch (private->window_type)
     {
index 2b659a467763411e176922af2537b1d2430de6e0..c38607a39cc66b9c588f0da5291268224d4f9b3d 100644 (file)
@@ -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
index e6d216680218979082d78781ba10526c6121c7ea..bdc50b99df66c19677f2a327dbc2c22a78a246b1 100644 (file)
@@ -1048,6 +1048,8 @@ range_grab_add (GtkRange      *range,
 {
   /* we don't actually gtk_grab, since a button is down */
 
+  gtk_grab_add (GTK_WIDGET (range));
+  
   range->layout->grab_location = location;
   range->layout->grab_button = button;
   
@@ -1058,6 +1060,8 @@ range_grab_add (GtkRange      *range,
 static void
 range_grab_remove (GtkRange *range)
 {
+  gtk_grab_remove (GTK_WIDGET (range));
+  
   range->layout->grab_location = MOUSE_OUTSIDE;
   range->layout->grab_button = 0;
 
@@ -1305,8 +1309,18 @@ gtk_range_button_release (GtkWidget      *widget,
 {
   GtkRange *range = GTK_RANGE (widget);
 
-  range->layout->mouse_x = event->x;
-  range->layout->mouse_y = event->y;
+  if (event->window == range->event_window)
+    {
+      range->layout->mouse_x = event->x;
+      range->layout->mouse_y = event->y;
+    }
+  else
+    {
+      gdk_window_get_pointer (range->event_window,
+                             &range->layout->mouse_x,
+                             &range->layout->mouse_y,
+                             NULL);
+    }
   
   if (range->layout->grab_button == event->button)
     {
@@ -1318,7 +1332,7 @@ gtk_range_button_release (GtkWidget      *widget,
       gtk_range_remove_step_timer (range);
       
       if (grab_location == MOUSE_SLIDER)
-        update_slider_position (range, event->x, event->y);
+        update_slider_position (range, range->layout->mouse_x, range->layout->mouse_y);
 
       /* Flush any pending discontinuous/delayed updates */
       gtk_range_update_value (range);