]> Pileus Git - ~andy/gtk/commitdiff
New approach for grab tracking code
authorAlexander Larsson <alexl@redhat.com>
Sat, 31 Jan 2009 18:42:44 +0000 (19:42 +0100)
committerAlexander Larsson <alex@localhost.localdomain>
Thu, 2 Apr 2009 08:15:30 +0000 (10:15 +0200)
We try to track the exact grab state, i.e. whats valid on the client
now and whats comming soon via the xserver roundtrip (and when).

gdk/gdkdisplay.c
gdk/gdkdisplay.h
gdk/gdkinternals.h
gdk/gdkoffscreenwindow.c
gdk/gdkwindow.c
gdk/x11/gdkasync.c
gdk/x11/gdkasync.h
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkevents-x11.c
gdk/x11/gdkmain-x11.c

index a8f027e73ef189e7f0529705875018d037959228..48d79e8542d964fce97fa5e353665eb461194b1d 100644 (file)
@@ -750,228 +750,434 @@ generate_grab_broken_event (GdkWindow *window,
     }
 }
 
-void
-_gdk_display_set_has_pointer_grab (GdkDisplay *display,
-                                  GdkWindow *window,
-                                  GdkWindow *native_window,
-                                  gboolean owner_events,
-                                  GdkEventMask event_mask,
-                                  unsigned long serial,
-                                  guint32 time,
-                                  gboolean implicit)
+/* Get the pointer grab in effects for events we just sent */
+GdkPointerGrabInfo *
+_gdk_display_get_active_pointer_grab (GdkDisplay *display)
 {
-  GdkWindow *src_toplevel, *dest_toplevel, *src_window;
+  GdkPointerGrabInfo *info;
+
+  if (display->pointer_grabs == NULL)
+    return NULL;
+
+  info = display->pointer_grabs->data;
+
+  if (info->activated)
+    return info;
   
-  if (display->pointer_grab.window != NULL &&
-      display->pointer_grab.window != window)
+  return NULL;
+}
+
+
+GdkPointerGrabInfo *
+_gdk_display_get_last_pointer_grab (GdkDisplay *display)
+{
+  GList *l;
+
+  l = display->pointer_grabs;
+
+  if (l == NULL)
+    return NULL;
+
+  while (l->next != NULL)
+    l = l->next;
+
+  return (GdkPointerGrabInfo *)l->data;
+}
+
+
+GdkPointerGrabInfo *
+_gdk_display_add_pointer_grab (GdkDisplay *display,
+                              GdkWindow *window,
+                              GdkWindow *native_window,
+                              gboolean owner_events,
+                              GdkEventMask event_mask,
+                              unsigned long serial_start,
+                              guint32 time,
+                              gboolean implicit)
+{
+  GdkPointerGrabInfo *info, *other_info;
+  GList *l;
+
+  info = g_new0 (GdkPointerGrabInfo, 1);
+
+  info->window = g_object_ref (window);
+  info->native_window = g_object_ref (native_window);
+  info->serial_start = serial_start;
+  info->serial_end = G_MAXULONG;
+  info->owner_events = owner_events;
+  info->event_mask = event_mask;
+  info->time = time;
+  info->implicit = implicit;
+  info->converted_implicit = FALSE;
+
+  /* Find the first grab that has a larger start time (if any) and insert
+   * before that. I.E we insert after already existing grabs with same
+   * start time */
+  for (l = display->pointer_grabs; l != NULL; l = l->next)
     {
-      generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
-                                 FALSE, display->pointer_grab.implicit,
-                                 window);
+      other_info = l->data;
+      
+      if (info->serial_start < other_info->serial_start)
+       break;
+    }
+  display->pointer_grabs =
+    g_list_insert_before (display->pointer_grabs, l, info);
+
+  /* Make sure the new grab end before next grab */
+  if (l)
+    {
+      other_info = l->data;
+      info->serial_end = other_info->serial_start;
     }
   
-  /* We need to generate crossing events for the grab.
-   * However, there are never any crossing events for implicit grabs
-   * TODO: ... Actually, this could happen if the pointer window doesn't have button mask so a parent gets the event... 
-   */
-  if (!implicit)
+  /* Find any previous grab and update its end time */
+  l = g_list_find  (display->pointer_grabs, info);
+  l = l->prev;
+  if (l)
     {
-      int x, y;
-      GdkModifierType state;
+      other_info = l->data;
+      other_info->serial_end = serial_start;
+    }
+
+  return info;
+}
+
+static void
+free_pointer_grab (GdkPointerGrabInfo *info)
+{
+  g_object_unref (info->window);
+  g_object_unref (info->native_window);
+  g_free (info);
+}
+
+/* _gdk_syntesize_crossing_events only works inside one toplevel.
+   This function splits things into two calls if needed, converting the
+   coordinates to the right toplevel */
+static void
+synthesize_crossing_events (GdkDisplay *display,
+                           GdkWindow *src_window,
+                           GdkWindow *dest_window,
+                           GdkCrossingMode crossing_mode,
+                           guint32 time,
+                           gulong serial)
+{
+  GdkWindow *src_toplevel, *dest_toplevel;
+  GdkModifierType state;
+  int x, y;
+  
+  if (src_window)
+    src_toplevel = gdk_window_get_toplevel (src_window);
+  else
+    src_toplevel = NULL;
+  if (dest_window)
+    dest_toplevel = gdk_window_get_toplevel (dest_window);
+  else
+    dest_toplevel = NULL;
+
+  if (src_toplevel == NULL && dest_toplevel == NULL)
+    return;
+  
+  if (src_toplevel == NULL ||
+      src_toplevel == dest_toplevel)
+    {
+      /* Same toplevels */
+      _gdk_windowing_window_get_pointer (display,
+                                        dest_toplevel,
+                                        &x, &y, &state);
+      _gdk_syntesize_crossing_events (display,
+                                     src_window,
+                                     dest_window,
+                                     crossing_mode,
+                                     x, y, state,
+                                     time,
+                                     NULL,
+                                     serial);
+    }
+  else if (dest_toplevel == NULL)
+    {
+      _gdk_windowing_window_get_pointer (display,
+                                        src_toplevel,
+                                        &x, &y, &state);
+      _gdk_syntesize_crossing_events (display,
+                                     src_window,
+                                     NULL,
+                                     crossing_mode,
+                                     x, y, state,
+                                     time,
+                                     NULL,
+                                     serial);
+    }
+  else
+    {
+      /* Different toplevels */
+      _gdk_windowing_window_get_pointer (display,
+                                        src_toplevel,
+                                        &x, &y, &state);
+      _gdk_syntesize_crossing_events (display,
+                                     src_window,
+                                     NULL,
+                                     crossing_mode,
+                                     x, y, state,
+                                     time,
+                                     NULL,
+                                     serial);
+      _gdk_windowing_window_get_pointer (display,
+                                        dest_toplevel,
+                                        &x, &y, &state);
+      _gdk_syntesize_crossing_events (display,
+                                     NULL,
+                                     dest_window,
+                                     crossing_mode,
+                                     x, y, state,
+                                     time,
+                                     NULL,
+                                     serial);
+    }
+}
 
-      /* We send GRAB crossing events from the window under the pointer to the
-        grab window. Except if there is an old grab then we start from that */
-      if (display->pointer_grab.window)
-       src_window = display->pointer_grab.window;
-      else
-       src_window = display->pointer_info.window_under_pointer;
 
-      /* Unset any current grab to make sure we send the events */
-      display->pointer_grab.window = NULL;
+static void
+switch_to_pointer_grab (GdkDisplay *display,
+                       GdkPointerGrabInfo *grab,
+                       GdkPointerGrabInfo *last_grab,
+                       guint32 time,
+                       gulong serial)
+{
+  GdkWindow *src_window, *pointer_window;
+  GdkWindowObject *w;
+  GList *old_grabs;
+  GdkModifierType state;
+  int x, y;
+
+  /* Temporarily unset pointer to make sure we send the crossing events below */
+  old_grabs = display->pointer_grabs;
+  display->pointer_grabs = NULL;
+  
+  if (grab)
+    {
+      /* New grab is in effect */
       
-      if (src_window != window)
+      /* We need to generate crossing events for the grab.
+       * However, there are never any crossing events for implicit grabs
+       * TODO: ... Actually, this could happen if the pointer window
+       *           doesn't have button mask so a parent gets the event... 
+       */
+      if (!grab->implicit)
        {
-         /* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */
-         if (src_window)
-           src_toplevel = gdk_window_get_toplevel (src_window);
+         /* We send GRAB crossing events from the window under the pointer to the
+            grab window. Except if there is an old grab then we start from that */
+         if (last_grab)
+           src_window = last_grab->window;
          else
-           src_toplevel = NULL;
-         dest_toplevel = gdk_window_get_toplevel (window);
+           src_window = display->pointer_info.window_under_pointer;
          
-         if (src_toplevel == NULL ||
-             src_toplevel == dest_toplevel)
+         if (src_window != grab->window)
            {
-             _gdk_windowing_window_get_pointer (display,
-                                                dest_toplevel,
-                                                &x, &y, &state);
-             _gdk_syntesize_crossing_events (display,
-                                             src_window,
-                                             window,
-                                             GDK_CROSSING_GRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
+             synthesize_crossing_events (display,
+                                         src_window, grab->window,
+                                         GDK_CROSSING_GRAB, time, serial);
            }
-         else
+         
+         /* !owner_event Grabbing a window that we're not inside, current status is
+            now NULL (i.e. outside grabbed window) */
+         if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
+           _gdk_display_set_window_under_pointer (display, NULL);
+       }
+  
+      grab->activated = TRUE;
+    }
+  else if (last_grab)
+    {
+      pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state);
+      if (pointer_window != NULL &&
+         (GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
+          GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
+       pointer_window = NULL;
+      
+      /* We force checked what window we're in, so we need to
+       * update the toplevel_under_pointer info, as that won't get told of
+       * this change.
+       */
+      if (display->pointer_info.toplevel_under_pointer)
+       g_object_unref (display->pointer_info.toplevel_under_pointer);
+      display->pointer_info.toplevel_under_pointer = NULL;
+      
+      if (pointer_window)
+       {
+         /* Convert to toplevel */
+         w = (GdkWindowObject *)pointer_window;
+         while (w->parent->window_type != GDK_WINDOW_ROOT)
            {
-             _gdk_windowing_window_get_pointer (display,
-                                                src_toplevel,
-                                                &x, &y, &state);
-             _gdk_syntesize_crossing_events (display,
-                                             src_window,
-                                             NULL,
-                                             GDK_CROSSING_GRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
-             _gdk_windowing_window_get_pointer (display,
-                                                dest_toplevel,
-                                                &x, &y, &state);
-             _gdk_syntesize_crossing_events (display,
-                                             NULL,
-                                             window,
-                                             GDK_CROSSING_GRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
+             x += w->x;
+             y += w->y;
+             w = w->parent;
            }
+         
+         /* w is now toplevel and x,y in toplevel coords */
+         display->pointer_info.toplevel_under_pointer = g_object_ref (w);
+         
+         /* Find (possibly virtual) child window */
+         pointer_window =
+           _gdk_window_find_descendant_at ((GdkWindow *)w,
+                                           x, y,
+                                           NULL, NULL);
        }
 
-      /* !owner_event Grabbing a window that we're not inside, current status is
-        now NULL (i.e. outside grabbed window) */
-      if (!owner_events && display->pointer_info.window_under_pointer != window)
-       _gdk_display_set_window_under_pointer (display, NULL);
+      if (pointer_window != last_grab->window)
+       synthesize_crossing_events (display,
+                                   last_grab->window, pointer_window,
+                                   GDK_CROSSING_UNGRAB, time, serial);
+      
+      /* We're now ungrabbed, update the window_under_pointer */
+      _gdk_display_set_window_under_pointer (display, pointer_window);
+      
+      if (last_grab->implicit_ungrab)
+       generate_grab_broken_event (last_grab->window,
+                                   FALSE, TRUE, 
+                                   NULL);
     }
+  
+  display->pointer_grabs = old_grabs;
 
-  display->pointer_grab.window = window;
-  display->pointer_grab.native_window = native_window;
-  display->pointer_grab.serial = serial;
-  display->pointer_grab.owner_events = owner_events;
-  display->pointer_grab.event_mask = event_mask;
-  display->pointer_grab.time = time;
-  display->pointer_grab.implicit = implicit;
-  display->pointer_grab.converted_implicit = FALSE;
 }
 
 void
-_gdk_display_unset_has_pointer_grab (GdkDisplay *display,
-                                    gboolean implicit,
-                                    gboolean do_grab_one_pointer_release_event,
-                                    guint32 time)
+_gdk_display_pointer_grab_update (GdkDisplay *display,
+                                 gulong current_serial)
 {
-  GdkWindow *pointer_window, *src_toplevel, *dest_toplevel;
-  GdkWindow *old_grab_window;
-  GdkWindow *old_native_grab_window;
-  int x, y;
-  GdkModifierType state;
-  GdkWindowObject *w;
-
-  old_grab_window = display->pointer_grab.window;
-  old_native_grab_window = display->pointer_grab.native_window;
+  GdkPointerGrabInfo *current_grab, *next_grab;
+  guint32 time;
+  
+  time = display->last_event_time;
 
-  if (old_grab_window == NULL)
-    return; /* This happens in the gdk_window_hide case */
+  while (display->pointer_grabs != NULL)
+    {
+      current_grab = display->pointer_grabs->data;
 
-  if (do_grab_one_pointer_release_event)
-    display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
+      if (current_grab->serial_start > current_serial)
+       return; /* Hasn't started yet */
+      
+      if (current_grab->serial_end > current_serial ||
+         (current_grab->serial_end == current_serial &&
+          current_grab->grab_one_pointer_release_event))
+       {
+         /* This one hasn't ended yet.
+            its the currently active one or scheduled to be active */
 
-  /* Set first so crossing events get sent */
-  display->pointer_grab.window = NULL;
-  
-  pointer_window = _gdk_windowing_window_at_pointer (display,  &x, &y, &state);
+         if (!current_grab->activated)
+           switch_to_pointer_grab (display, current_grab, NULL, time, current_serial);
          
-  if (pointer_window != NULL &&
-      (GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
-       GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
-    pointer_window = NULL;
-
-  /* We force checked what window we're in, so we need to
-   * update the toplevel_under_pointer info, as that won't get told of
-   * this change.
-   */
-  if (display->pointer_info.toplevel_under_pointer)
-    g_object_unref (display->pointer_info.toplevel_under_pointer);
-  display->pointer_info.toplevel_under_pointer = NULL;
-  
-  if (pointer_window)
-    {
-      /* Convert to toplevel */
-      w = (GdkWindowObject *)pointer_window;
-      while (w->parent->window_type != GDK_WINDOW_ROOT)
+         break;
+       }
+
+
+      next_grab = NULL;
+      if (display->pointer_grabs->next)
        {
-         x += w->x;
-         y += w->y;
-         w = w->parent;
+         /* This is the next active grab */
+         next_grab = display->pointer_grabs->next->data;
+         
+         if (next_grab->serial_start > current_serial)
+           next_grab = NULL; /* Actually its not yet active */
        }
 
-      /* w is now toplevel and x,y in toplevel coords */
+      if (next_grab == NULL ||
+         current_grab->window != next_grab->window)
+       generate_grab_broken_event (GDK_WINDOW (current_grab->window),
+                                   FALSE, current_grab->implicit,
+                                   next_grab? next_grab->window : NULL);
 
-      display->pointer_info.toplevel_under_pointer = g_object_ref (w);
+
+      /* Remove old grab */
+      display->pointer_grabs =
+       g_list_delete_link (display->pointer_grabs,
+                           display->pointer_grabs);
+      
+      switch_to_pointer_grab (display,
+                             next_grab, current_grab,
+                             time, current_serial);
       
-      /* Find child window */
-      pointer_window =
-       _gdk_window_find_descendant_at ((GdkWindow *)w,
-                                       x, y,
-                                       NULL, NULL);
+      free_pointer_grab (current_grab);
     }
-  
-  
-  if (pointer_window == NULL)
+}
+
+static gboolean
+is_parent_of (GdkWindow *parent,
+              GdkWindow *child)
+{
+  GdkWindow *w;
+
+  w = child;
+  while (w != NULL)
     {
-      _gdk_syntesize_crossing_events (display,
-                                     old_grab_window,
-                                     NULL,
-                                     GDK_CROSSING_UNGRAB,
-                                     x, y, state,
-                                     time,
-                                     NULL);
+      if (w == parent)
+       return TRUE;
+
+      w = gdk_window_get_parent (w);
     }
-  else
+
+  return FALSE;
+}
+
+static GList *
+find_pointer_grab (GdkDisplay *display,
+                  gulong serial)
+{
+  GdkPointerGrabInfo *grab;
+  GList *l;
+
+  for (l = display->pointer_grabs; l != NULL; l = l->next)
     {
-      if (pointer_window != old_grab_window)
-       {
-         /* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */
-         src_toplevel = gdk_window_get_toplevel (old_grab_window);
-         dest_toplevel = gdk_window_get_toplevel (pointer_window);
+      grab = l->data;
 
-         if (src_toplevel == dest_toplevel)
-           {
-             _gdk_syntesize_crossing_events (display,
-                                             display->pointer_info.window_under_pointer,
-                                             pointer_window,
-                                             GDK_CROSSING_UNGRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
-           }
-         else
-           {
-             /* TODO: We're reporting the wrong coords here. They are in pointer_window toplevel coords */
-             _gdk_syntesize_crossing_events (display,
-                                             display->pointer_info.window_under_pointer,
-                                             NULL,
-                                             GDK_CROSSING_UNGRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
-             _gdk_syntesize_crossing_events (display,
-                                             NULL,
-                                             pointer_window,
-                                             GDK_CROSSING_UNGRAB,
-                                             x, y, state,
-                                             time,
-                                             NULL);
-           }
-       }
+      if (serial >= grab->serial_start && serial < grab->serial_end)
+       return l;
     }
+  
+  return NULL;
+}
+
 
-  /* We're now ungrabbed, update the window_under_pointer */
-  _gdk_display_set_window_under_pointer (display, pointer_window);
+
+GdkPointerGrabInfo *
+_gdk_display_has_pointer_grab (GdkDisplay *display,
+                              gulong serial)
+{
+  GList *l;
+
+  l = find_pointer_grab (display, serial);
+  if (l)
+    return l->data;
   
-  if (implicit)
-    generate_grab_broken_event (old_grab_window,
-                               FALSE, implicit, 
-                               NULL);
+  return NULL;
+}
+
+/* Returns true if last grab was ended */
+gboolean
+_gdk_display_end_pointer_grab (GdkDisplay *display,
+                              gulong serial,
+                              GdkWindow *if_child,
+                              gboolean implicit)
+{
+  GdkPointerGrabInfo *grab;
+  GList *l;
+
+  l = find_pointer_grab (display, serial);
+  
+  if (l == NULL)
+    return FALSE;
+
+  grab = l->data;
+  if (grab &&
+      (if_child == NULL ||
+       is_parent_of (grab->window, if_child)))
+    {
+      grab->serial_end = serial;
+      grab->implicit_ungrab = implicit;
+      return l->next == NULL;
+    }
+  
+  return FALSE;
 }
 
 void
@@ -1055,14 +1261,18 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
                                   GdkWindow **grab_window,
                                   gboolean   *owner_events)
 {
+  GdkPointerGrabInfo *info;
+  
   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
 
-  if (display->pointer_grab.window)
+  info = _gdk_display_get_active_pointer_grab (display);
+  
+  if (info)
     {
       if (grab_window)
-        *grab_window = (GdkWindow *)display->pointer_grab.window;
+        *grab_window = info->window;
       if (owner_events)
-        *owner_events = display->pointer_grab.owner_events;
+        *owner_events = info->owner_events;
 
       return TRUE;
     }
@@ -1084,10 +1294,13 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
 gboolean
 gdk_display_pointer_is_grabbed (GdkDisplay *display)
 {
+  GdkPointerGrabInfo *info;
+  
   g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
+
+  info = _gdk_display_get_active_pointer_grab (display);
   
-  return (display->pointer_grab.window != NULL &&
-         !display->pointer_grab.implicit);
+  return (info && !info->implicit);
 }
 
 #define __GDK_DISPLAY_C__
index c3a7d62a66d07eaf528738410e0bd2345f044f65..3c7bde322fdaa739da9e7d59951099da1a95f0e6 100644 (file)
@@ -43,21 +43,6 @@ typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks;
 #define GDK_IS_DISPLAY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY))
 #define GDK_DISPLAY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY, GdkDisplayClass))
 
-/* Tracks information about the pointer grab on this display */
-typedef struct
-{
-  GdkWindow *window;
-  GdkWindow *native_window;
-  gulong serial;
-  gboolean owner_events;
-  guint event_mask;
-  gboolean implicit;
-  gboolean converted_implicit;
-  guint32 time;
-
-  GdkWindow *grab_one_pointer_release_event;
-} GdkPointerGrabInfo;
-
 /* Tracks information about the keyboard grab on this display */
 typedef struct
 {
@@ -68,7 +53,6 @@ typedef struct
   guint32 time;
 } GdkKeyboardGrabInfo;
 
-
 /* Tracks information about which window and position the pointer last was in.
  * This is useful when we need to synthesize events later.
  * Note that we track toplevel_under_pointer using enter/leave events,
@@ -112,9 +96,12 @@ struct _GdkDisplay
   gint button_x[2];             /* The last 2 button click positions. */
   gint button_y[2];
 
-  GdkPointerGrabInfo pointer_grab;
+  GList *pointer_grabs;
   GdkKeyboardGrabInfo keyboard_grab;
   GdkPointerWindowInfo pointer_info;
+
+  /* Last reported event time from server */
+  guint32 last_event_time;
 };
 
 struct _GdkDisplayClass
index dc7fec8c93657456fe4f4174698c769f68fb4731..33822365ac7b683fc5fd3986c4e1271fb458fcfd 100644 (file)
@@ -170,6 +170,24 @@ struct _GdkEventPrivate
   gpointer   windowing_data;
 };
 
+/* Tracks information about the pointer grab on this display */
+typedef struct
+{
+  GdkWindow *window;
+  GdkWindow *native_window;
+  gulong serial_start;
+  gulong serial_end; /* exclusive, i.e. not active on serial_end */
+  gboolean owner_events;
+  guint event_mask;
+  gboolean implicit;
+  gboolean converted_implicit;
+  guint32 time;
+
+  gboolean activated;
+  gboolean implicit_ungrab;
+  gboolean grab_one_pointer_release_event;
+} GdkPointerGrabInfo;
+
 extern GdkEventFunc   _gdk_event_func;    /* Callback for events */
 extern gpointer       _gdk_event_data;
 extern GDestroyNotify _gdk_event_notify;
@@ -464,18 +482,24 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
 void  _gdk_windowing_launch_failed         (GAppLaunchContext *context, 
                                            const char        *startup_notify_id);
 
-void _gdk_display_set_has_pointer_grab (GdkDisplay *display,
-                                       GdkWindow *window,
-                                       GdkWindow *native_window,
-                                       gboolean owner_events,
-                                       GdkEventMask event_mask,
-                                       unsigned long serial,
-                                       guint32 time,
+GdkPointerGrabInfo *_gdk_display_get_active_pointer_grab (GdkDisplay *display);
+void _gdk_display_pointer_grab_update                    (GdkDisplay *display,
+                                                         gulong current_serial);
+GdkPointerGrabInfo *_gdk_display_get_last_pointer_grab (GdkDisplay *display);
+GdkPointerGrabInfo *_gdk_display_add_pointer_grab  (GdkDisplay *display,
+                                                   GdkWindow *window,
+                                                   GdkWindow *native_window,
+                                                   gboolean owner_events,
+                                                   GdkEventMask event_mask,
+                                                   unsigned long serial_start,
+                                                   guint32 time,
+                                                   gboolean implicit);
+GdkPointerGrabInfo * _gdk_display_has_pointer_grab (GdkDisplay *display,
+                                                   gulong serial);
+gboolean _gdk_display_end_pointer_grab (GdkDisplay *display,
+                                       gulong serial,
+                                       GdkWindow *if_child,
                                        gboolean implicit);
-void _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
-                                         gboolean implicit,
-                                         gboolean do_grab_one_pointer_release_event,
-                                         guint32 time);
 void _gdk_display_set_has_keyboard_grab (GdkDisplay *display,
                                         GdkWindow *window,
                                         GdkWindow *native_window,
@@ -518,7 +542,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                     gint                        toplevel_y,
                                     GdkModifierType             mask,
                                     guint32                     time_,
-                                    GdkEvent                   *event_in_queue);
+                                    GdkEvent                   *event_in_queue,
+                                    gulong                      serial);
 void _gdk_display_set_window_under_pointer (GdkDisplay *display,
                                            GdkWindow *window);
 
index 703dcfa7ff045a2b658106b358fd5dc8fe6bd0d3..69126537db9ee0bc0d3cf5460642a2a08127eb0f 100644 (file)
@@ -851,7 +851,9 @@ gdk_offscreen_window_hide (GdkWindow *window)
 
   /* May need to break grabs on children */
   display = gdk_drawable_get_display (window);
-  
+
+  /* TODO: This needs updating to the new grab world */
+#if 0
   if (display->pointer_grab.window != NULL)
     {
       if (is_parent_of (window, display->pointer_grab.window))
@@ -866,6 +868,7 @@ gdk_offscreen_window_hide (GdkWindow *window)
          gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
        }
     }
+#endif
 }
 
 static void
index 102fc903e76e119e8a5301c2b40bdbf46fba289e..604febac628a7c40fc40232cf160a7820876caf1 100644 (file)
@@ -5725,20 +5725,11 @@ gdk_window_hide (GdkWindow *window)
       /* May need to break grabs on children */
       display = gdk_drawable_get_display (window);
 
-      if (display->pointer_grab.window != NULL)
-       {
-         if (is_parent_of (window, display->pointer_grab.window))
-           {
-             /* Call this ourselves, even though gdk_display_pointer_ungrab
-                does so too, since we want to pass implicit == TRUE so the
-                broken grab event is generated */
-             _gdk_display_unset_has_pointer_grab (display,
-                                                  TRUE,
-                                                  FALSE,
-                                                  GDK_CURRENT_TIME);
-             gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
-           }
-       }
+      if (_gdk_display_end_pointer_grab (display,
+                                        _gdk_windowing_window_get_next_serial (display),
+                                        window,
+                                        TRUE))
+       gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
 
       if (display->keyboard_grab.window != NULL)
        {
@@ -6561,6 +6552,7 @@ static void
 update_cursor (GdkDisplay *display)
 {
   GdkWindowObject *pointer_window, *cursor_window;
+  GdkPointerGrabInfo *grab;
   
   pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
   
@@ -6570,14 +6562,18 @@ update_cursor (GdkDisplay *display)
         cursor_window->parent->window_type != GDK_WINDOW_ROOT)
     cursor_window = cursor_window->parent;
 
-  if (display->pointer_grab.window != NULL &&
-      !is_parent_of (display->pointer_grab.window, (GdkWindow *)cursor_window))
-    cursor_window = (GdkWindowObject *)display->pointer_grab.window;
+  /* We ignore the serials here and just pick the last grab
+     we've sent, as that would shortly be used anyway. */
+  grab = _gdk_display_get_last_pointer_grab (display);
+  if (grab != NULL &&
+      !is_parent_of (grab->window, (GdkWindow *)cursor_window))
+    cursor_window = (GdkWindowObject *)grab->window;
 
   /* Set all cursors on toplevel, otherwise its tricky to keep track of
    * which native window has what cursor set. */
-  GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor (gdk_window_get_toplevel ((GdkWindow *)pointer_window),
-                                                               cursor_window->cursor);
+  GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor
+      (gdk_window_get_toplevel ((GdkWindow *)pointer_window),
+       cursor_window->cursor);
 }
 
 /**
@@ -7869,14 +7865,18 @@ send_crossing_event (GdkDisplay                 *display,
                     gint                        toplevel_y,
                     GdkModifierType             mask,
                     guint32                     time_,
-                    GdkEvent                   *event_in_queue)
+                    GdkEvent                   *event_in_queue,
+                    gulong                      serial)
 {
   GdkEvent *event;
   guint32 event_mask;
-
-  if (display->pointer_grab.window != NULL &&
-      !display->pointer_grab.owner_events &&
-      (GdkWindow *)window != display->pointer_grab.window)
+  GdkPointerGrabInfo *grab;
+  
+  grab = _gdk_display_has_pointer_grab (display, serial);
+  
+  if (grab != NULL &&
+      !grab->owner_events &&
+      (GdkWindow *)window != grab->window)
     return;
   
   if (type == GDK_LEAVE_NOTIFY)
@@ -7918,7 +7918,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                gint                        toplevel_y,
                                GdkModifierType             mask,
                                guint32                     time_,
-                               GdkEvent                   *event_in_queue)
+                               GdkEvent                   *event_in_queue,
+                               gulong                      serial)
 {
   GdkWindowObject *c;
   GdkWindowObject *win, *last, *next;
@@ -7958,7 +7959,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                           NULL,
                           toplevel_x, toplevel_y,
                           mask, time_,
-                          event_in_queue);
+                          event_in_queue,
+                          serial);
      
       if (c != a)
        {
@@ -7978,7 +7980,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                   (GdkWindow *)last,
                                   toplevel_x, toplevel_y,
                                   mask, time_,
-                                  event_in_queue);
+                                  event_in_queue,
+                                  serial);
              
              last = win;
              win = win->parent;
@@ -8023,7 +8026,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                                   (GdkWindow *)next,
                                   toplevel_x, toplevel_y,
                                   mask, time_,
-                                  event_in_queue);
+                                  event_in_queue,
+                                  serial);
            }
          g_list_free (path);
        }
@@ -8043,7 +8047,8 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
                           NULL,
                           toplevel_x, toplevel_y,
                           mask, time_,
-                          event_in_queue);
+                          event_in_queue,
+                          serial);
     }
 }
 
@@ -8067,9 +8072,11 @@ static GdkWindow *
 get_pointer_window (GdkDisplay *display,
                    GdkWindow *event_window,
                    gdouble toplevel_x,
-                   gdouble toplevel_y)
+                   gdouble toplevel_y,
+                   gulong serial)
 {
   GdkWindow *pointer_window;
+  GdkPointerGrabInfo *grab;
 
   if (event_window == display->pointer_info.toplevel_under_pointer)
     pointer_window =
@@ -8079,9 +8086,10 @@ get_pointer_window (GdkDisplay *display,
   else
     pointer_window = NULL;
 
-  if (display->pointer_grab.window != NULL &&
-      !display->pointer_grab.owner_events &&
-      pointer_window != display->pointer_grab.window)
+  grab = _gdk_display_has_pointer_grab (display, serial);
+  if (grab != NULL &&
+      !grab->owner_events &&
+      pointer_window != grab->window)
     pointer_window = NULL;
   
   return pointer_window;
@@ -8113,16 +8121,20 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
   GdkDisplay *display;
   GdkWindow *changed_toplevel;
   GdkWindow *new_window_under_pointer;
+  gulong serial;
 
+  display = gdk_drawable_get_display (changed_window);
+  
+  serial = _gdk_windowing_window_get_next_serial (display);
   changed_toplevel = get_toplevel (changed_window);
   
-  display = gdk_drawable_get_display (changed_window);
   if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
     {
       new_window_under_pointer =
        get_pointer_window (display, changed_toplevel,
                            display->pointer_info.toplevel_x,
-                           display->pointer_info.toplevel_y);
+                           display->pointer_info.toplevel_y,
+                           serial);
       if (new_window_under_pointer !=
          display->pointer_info.window_under_pointer)
        {
@@ -8134,7 +8146,8 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
                                          display->pointer_info.toplevel_y,
                                          display->pointer_info.state,
                                          GDK_CURRENT_TIME,
-                                         NULL);
+                                         NULL,
+                                         serial);
          _gdk_display_set_window_under_pointer (display, new_window_under_pointer);
        }
     }
@@ -8146,27 +8159,22 @@ get_event_window (GdkDisplay                 *display,
                  GdkWindow                  *pointer_window,
                  GdkEventType                type,
                  GdkModifierType             mask,
-                 guint                      *evmask_out)
+                 guint                      *evmask_out,
+                 gulong                      serial)
 {
   guint evmask;
   GdkWindow *grab_window;
   GdkWindowObject *w;
+  GdkPointerGrabInfo *grab;
+
+  grab = _gdk_display_has_pointer_grab (display, serial);
 
-  if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
-      (type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
+  if (grab != NULL && !grab->owner_events)
     {
-      evmask = display->pointer_grab.event_mask;
+      evmask = grab->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
-      if (type == GDK_BUTTON_RELEASE &&
-         display->pointer_grab.grab_one_pointer_release_event)
-       {
-         grab_window = display->pointer_grab.grab_one_pointer_release_event;
-         display->pointer_grab.grab_one_pointer_release_event = NULL;
-       }
-      else
-       grab_window = display->pointer_grab.window;
-
+      grab_window = grab->window;
       
       if (evmask & type_masks[type])
        {
@@ -8194,17 +8202,17 @@ get_event_window (GdkDisplay                 *display,
       w = w->parent;
     }
 
-  if (display->pointer_grab.window != NULL &&
-      display->pointer_grab.owner_events)
+  if (grab != NULL &&
+      grab->owner_events)
     {
-      evmask = display->pointer_grab.event_mask;
+      evmask = grab->event_mask;
       evmask = update_evmask_for_button_motion (evmask, mask);
 
       if (evmask & type_masks[type])
        {
          if (evmask_out)
            *evmask_out = evmask;
-         return display->pointer_grab.window;
+         return grab->window;
        }
       else
        return NULL;
@@ -8220,7 +8228,6 @@ proxy_pointer_event (GdkDisplay                 *display,
 {
   GdkWindow *toplevel_window;
   GdkWindow *pointer_window;
-  GdkWindow *cursor_window;
   GdkEvent *event;
   guint state;
   gdouble toplevel_x, toplevel_y;
@@ -8231,7 +8238,7 @@ proxy_pointer_event (GdkDisplay                 *display,
   gdk_event_get_state (source_event, &state);
   time_ = gdk_event_get_time (source_event);
 
-  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y, serial);
   if (display->pointer_info.window_under_pointer != pointer_window)
     {
       /* Either a toplevel crossing notify that ended up inside a child window,
@@ -8244,7 +8251,8 @@ proxy_pointer_event (GdkDisplay                 *display,
                                      GDK_CROSSING_NORMAL,
                                      toplevel_x, toplevel_y,
                                      state, time_,
-                                     source_event);
+                                     source_event,
+                                     serial);
 
       _gdk_display_set_window_under_pointer (display, pointer_window);
     }
@@ -8258,7 +8266,8 @@ proxy_pointer_event (GdkDisplay                 *display,
                                    pointer_window,
                                    source_event->type,
                                    state,
-                                   &evmask);
+                                   &evmask,
+                                   serial);
 
       is_hint = FALSE;
       
@@ -8291,22 +8300,14 @@ proxy_pointer_event (GdkDisplay                 *display,
        }
     }
 
-  /* TODO: set cursor from cursor_window, or grab cursor */
-  cursor_window = pointer_window;
-  if (display->pointer_grab.window &&
-      (pointer_window == NULL ||
-       !is_parent_of (display->pointer_grab.window, pointer_window)))
-    cursor_window = display->pointer_grab.window;
-  /* Actually, this should probably happen in synthesize crossing so it works with geometry changes */
-
-  
   /* unlink all move events from queue.
      We handle our own, including our emulated masks. */
   return TRUE;
 }
 
 static gboolean
-proxy_button_event (GdkEvent *source_event)
+proxy_button_event (GdkEvent *source_event,
+                   gulong serial)
 {
   GdkWindow *toplevel_window;
   GdkWindow *event_win;
@@ -8318,6 +8319,7 @@ proxy_button_event (GdkEvent *source_event)
   gdouble toplevel_x, toplevel_y;
   GdkDisplay *display;
   GdkWindowObject *w;
+  GdkPointerGrabInfo *grab;
 
   type = source_event->any.type;
   toplevel_window = source_event->any.window;
@@ -8326,10 +8328,11 @@ proxy_button_event (GdkEvent *source_event)
   time_ = gdk_event_get_time (source_event);
   display = gdk_drawable_get_display (source_event->any.window);
 
+  grab = _gdk_display_get_active_pointer_grab (display);
+  
   if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
-      display->pointer_grab.window == source_event->any.window &&
-      display->pointer_grab.implicit &&
-      !display->pointer_grab.converted_implicit)
+      grab && grab->window == toplevel_window &&
+      grab->implicit && !grab->converted_implicit)
     {
       pointer_window =
        _gdk_window_find_descendant_at (toplevel_window,
@@ -8347,25 +8350,25 @@ proxy_button_event (GdkEvent *source_event)
       pointer_window = (GdkWindow *)w;
       
       if (pointer_window != NULL &&
-         pointer_window != source_event->any.window)
-       _gdk_display_set_has_pointer_grab (display,
-                                          pointer_window,
-                                          display->pointer_grab.native_window,
-                                          display->pointer_grab.owner_events,
-                                          gdk_window_get_events (pointer_window),
-                                          display->pointer_grab.serial,
-                                          display->pointer_grab.time,
-                                          display->pointer_grab.implicit);
-      display->pointer_grab.converted_implicit = TRUE;
+         pointer_window != toplevel_window)
+       {
+         g_object_ref (pointer_window);
+         g_object_unref (grab->window);
+         grab->window = pointer_window;
+         grab->event_mask = gdk_window_get_events (pointer_window);
+       }
+      
+      grab->converted_implicit = TRUE;
     }
 
-  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+  pointer_window = get_pointer_window (display, toplevel_window,
+                                      toplevel_x, toplevel_y,
+                                      serial);
   
   event_win = get_event_window (display,
                                pointer_window,
-                               type,
-                               state,
-                               NULL);
+                               type, state,
+                               NULL, serial);
 
   if (event_win == NULL)
     return TRUE;
@@ -8478,7 +8481,14 @@ _gdk_windowing_got_event (GdkDisplay *display,
   gdouble x, y;
   gboolean unlink_event;
   guint old_state, old_button;
+  GdkPointerGrabInfo *button_release_grab;
 
+  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+    display->last_event_time = gdk_event_get_time (event);
+  
+  _gdk_display_pointer_grab_update (display,
+                                   serial);
+  
   event_window = event->any.window;
   if (!event_window)
     return;
@@ -8559,7 +8569,22 @@ _gdk_windowing_got_event (GdkDisplay *display,
                                         event,
                                        serial);
   else if (is_button_type (event->type))
-    unlink_event = proxy_button_event (event);
+    unlink_event = proxy_button_event (event,
+                                      serial);
+
+  if (event->type == GDK_BUTTON_RELEASE)
+    {
+      button_release_grab =
+       _gdk_display_has_pointer_grab (display, serial);
+      if (button_release_grab &&
+         button_release_grab->grab_one_pointer_release_event)
+       {
+         button_release_grab->grab_one_pointer_release_event = FALSE;
+         button_release_grab->serial_end = serial;
+         button_release_grab->implicit_ungrab = TRUE;
+         _gdk_display_pointer_grab_update (display, serial);
+       }
+    }
 
   if (unlink_event)
     {
index b230c1fabaeeee01337554e132976d2b91cb6785..e412ed2f7e4eccf48643e9a1ef3e06d60e856783 100644 (file)
@@ -118,6 +118,7 @@ struct _RoundtripState
   Display *dpy;
   _XAsyncHandler async;
   gulong get_input_focus_req;
+  GdkDisplay *display;
   GdkRoundTripCallback callback;
   gpointer data;
 };
@@ -758,7 +759,7 @@ roundtrip_callback_idle (gpointer data)
 {
   RoundtripState *state = (RoundtripState *)data;  
   
-  state->callback (state->data);
+  state->callback (state->display, state->data, state->get_input_focus_req);
 
   g_free (state);
 
@@ -790,6 +791,7 @@ roundtrip_handler (Display *dpy,
                            True);
        }
 
+      
       if (state->callback)
         gdk_threads_add_idle (roundtrip_callback_idle, state);
 
@@ -813,6 +815,7 @@ _gdk_x11_roundtrip_async (GdkDisplay           *display,
 
   state = g_new (RoundtripState, 1);
 
+  state->display = display;
   state->dpy = dpy;
   state->callback = callback;
   state->data = data;
index 407e3c8473e7d2477f04497b1ed5cf1e80f05372..44aa18c47c69403da5bf5f697e0d12d990eb0176 100644 (file)
@@ -31,8 +31,9 @@ typedef struct _GdkChildInfoX11 GdkChildInfoX11;
 typedef void (*GdkSendXEventCallback) (Window   window,
                                       gboolean success,
                                       gpointer data);
-typedef void (*GdkRoundTripCallback)  (gpointer data);
-
+typedef void (*GdkRoundTripCallback)  (GdkDisplay *display,
+                                      gpointer data,
+                                      gulong serial);
 
 struct _GdkChildInfoX11
 {
index a05bc511ceba459dc033578a4ac6d51faca1c243..a517404e1ed17100572daf6e3a185bbd7c345db6 100644 (file)
@@ -598,16 +598,11 @@ struct XPointerUngrabInfo {
 };
 
 static void
-pointer_ungrab_callback (gpointer _data)
+pointer_ungrab_callback (GdkDisplay *display,
+                        gpointer data,
+                        gulong serial)
 {
-  struct XPointerUngrabInfo *data = _data;
-
-  _gdk_display_unset_has_pointer_grab (data->display,
-                                      FALSE,
-                                      FALSE,
-                                      data->time);
-
-  g_free (data);
+  _gdk_display_pointer_grab_update (display, serial);
 }
 
 
@@ -631,30 +626,30 @@ gdk_display_pointer_ungrab (GdkDisplay *display,
 {
   Display *xdisplay;
   GdkDisplayX11 *display_x11;
+  GdkPointerGrabInfo *grab;
+  unsigned long serial;
 
   g_return_if_fail (GDK_IS_DISPLAY (display));
 
   display_x11 = GDK_DISPLAY_X11 (display);
   xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+  serial = NextRequest (xdisplay);
   
   _gdk_input_ungrab_pointer (display, time_);
   XUngrabPointer (xdisplay, time_);
   XFlush (xdisplay);
 
-  if (time_ == GDK_CURRENT_TIME ||
-      display->pointer_grab.time == GDK_CURRENT_TIME ||
-      !XSERVER_TIME_IS_LATER (display->pointer_grab.time, time_))
+  grab = _gdk_display_get_last_pointer_grab (display);
+  if (grab &&
+      (time_ == GDK_CURRENT_TIME ||
+       grab->time == GDK_CURRENT_TIME ||
+       !XSERVER_TIME_IS_LATER (grab->time, time_)))
     {
-      struct XPointerUngrabInfo *data;
-
-      data = g_new (struct XPointerUngrabInfo, 1);
-
-      data->display = GDK_DISPLAY_OBJECT (display_x11);
-      data->time = time_;
-
-      _gdk_x11_roundtrip_async (data->display, 
+      grab->serial_end = serial;
+      _gdk_x11_roundtrip_async (display, 
                                pointer_ungrab_callback,
-                               data);
+                               NULL);
     }
 }
 
index 617e87dc10b993b303ef982ca34de63ea46884f1..01ed9b65c56ea3c9595d66b711827dddbb78cec3 100644 (file)
@@ -2207,7 +2207,7 @@ gdk_event_translate (GdkDisplay *display,
   
   if (window)
     g_object_unref (window);
-  
+
   return return_val;
 }
 
index aa11db38d0db00a559410c4ef49112af7ea05c52..b06b15e6996d4afe33dc81d4ca9bb6f9c9583b84 100644 (file)
@@ -149,22 +149,11 @@ struct XPointerGrabInfo {
 };
 
 static void
-has_pointer_grab_callback (gpointer _data)
+has_pointer_grab_callback (GdkDisplay *display,
+                          gpointer data,
+                          gulong serial)
 {
-  struct XPointerGrabInfo *data = _data;
-
-  _gdk_display_set_has_pointer_grab (data->display,
-                                    data->window,
-                                    data->native_window,
-                                    data->owner_events,
-                                    data->event_mask,
-                                    data->serial,
-                                    data->time,
-                                    FALSE);
-
-  g_object_unref (data->window);
-  g_object_unref (data->native_window);
-  g_free (data);
+  _gdk_display_pointer_grab_update (display, serial);
 }
 
 /*
@@ -215,9 +204,17 @@ gdk_pointer_grab (GdkWindow *        window,
 
   native = gdk_window_get_toplevel (window);
 
+  /* We need a native window for confine to to work, ensure we have one */
+  if (confine_to)
+    gdk_window_set_has_native (confine_to, TRUE);
+  
   /* TODO: What do we do for offscreens and  their children? We need to proxy the grab somehow */
   if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
     return GDK_GRAB_SUCCESS;
+
+  if (!_gdk_window_has_impl (window) &&
+      !gdk_window_is_viewable (window))
+    return GDK_GRAB_NOT_VIEWABLE;
   
   if (confine_to)
     confine_to = _gdk_window_get_impl_window (confine_to);
@@ -285,21 +282,18 @@ gdk_pointer_grab (GdkWindow *       window,
   
   if (return_val == GrabSuccess)
     {
-      struct XPointerGrabInfo *data;
-
-      data = g_new (struct XPointerGrabInfo, 1);
-
-      data->display = GDK_DISPLAY_OBJECT (display_x11);
-      data->window = g_object_ref (window);
-      data->native_window = g_object_ref (native);
-      data->owner_events = owner_events;
-      data->event_mask = event_mask;
-      data->serial = serial;
-      data->time = time;
+      _gdk_display_add_pointer_grab (GDK_DISPLAY_OBJECT (display_x11),
+                                    window,
+                                    native,
+                                    owner_events,
+                                    event_mask,
+                                    serial,
+                                    time,
+                                    FALSE);
 
-      _gdk_x11_roundtrip_async (data->display
+      _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11)
                                has_pointer_grab_callback,
-                               data);
+                               NULL);
     }
 
   return gdk_x11_convert_grab_status (return_val);
@@ -394,19 +388,8 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
                        gulong     serial)
 {
   GdkDisplay *display = gdk_drawable_get_display (window);
-  
-  if (display->pointer_grab.window && 
-      serial >= display->pointer_grab.serial)
-    {
-      GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
-      GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->pointer_grab.native_window);
 
-      while (tmp && tmp != private)
-       tmp = tmp->parent;
-
-      if (tmp)
-       _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
-    }
+  _gdk_display_end_pointer_grab (display, serial, window, TRUE);
 
   if (display->keyboard_grab.window &&
       serial >= display->keyboard_grab.serial)
@@ -433,11 +416,21 @@ void
 _gdk_xgrab_check_destroy (GdkWindow *window)
 {
   GdkDisplay *display = gdk_drawable_get_display (window);
-  
-  if (window == display->pointer_grab.native_window &&
-      display->pointer_grab.window != NULL)
-    _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
+  GdkPointerGrabInfo *grab;
 
+  /* Make sure there is no lasting grab in this native
+     window */
+  grab = _gdk_display_get_last_pointer_grab (display);
+  if (grab && grab->native_window == window)
+    {
+      /* We don't know the actual serial to end, but it
+        doesn't really matter as this only happens
+        after we get told of the destroy from the
+        server so we know its ended in the server,
+        just make sure its ended. */
+      grab->serial_end = grab->serial_start;
+    }
+  
   if (window == display->keyboard_grab.native_window &&
       display->keyboard_grab.window != NULL)
     _gdk_display_unset_has_keyboard_grab (display, TRUE);
@@ -461,31 +454,31 @@ _gdk_xgrab_check_button_event (GdkWindow *window,
                               XEvent *xevent)
 {
   GdkDisplay *display = gdk_drawable_get_display (window);
+  gulong serial = xevent->xany.serial;
+  GdkPointerGrabInfo *grab;
   
   /* track implicit grabs for button presses */
   switch (xevent->type)
     {
     case ButtonPress:
-      if (!display->pointer_grab.window)
+      if (!_gdk_display_has_pointer_grab (display, serial))
        {
-         _gdk_display_set_has_pointer_grab (display,
-                                            window,
-                                            window,
-                                            FALSE,
-                                            gdk_window_get_events (window),
-                                            xevent->xany.serial,
-                                            xevent->xbutton.time,
-                                            TRUE);
+         _gdk_display_add_pointer_grab  (display,
+                                         window,
+                                         window,
+                                         FALSE,
+                                         gdk_window_get_events (window),
+                                         serial,
+                                         xevent->xbutton.time,
+                                         TRUE);
        }
       break;
     case ButtonRelease:
-      if (display->pointer_grab.window &&
-         display->pointer_grab.implicit &&
+      serial = serial; 
+      grab = _gdk_display_has_pointer_grab (display, serial);
+      if (grab && grab->implicit &&
          (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0)
-       {
-         _gdk_display_unset_has_pointer_grab (display, TRUE, TRUE,
-                                              xevent->xbutton.time);
-       }
+       grab->grab_one_pointer_release_event = TRUE;
       break;
     default:
       g_assert_not_reached ();