[gtk+/client-side-windows: 209/284] New approach for grab tracking code



commit 26cbf87d7d70e9eae4dea4667aee40c9d154184f
Author: Alexander Larsson <alexl redhat com>
Date:   Sat Jan 31 19:42:44 2009 +0100

    New approach for grab tracking code
    
    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         |  585 +++++++++++++++++++++++++++++++---------------
 gdk/gdkdisplay.h         |   21 +--
 gdk/gdkinternals.h       |   49 +++-
 gdk/gdkoffscreenwindow.c |    5 +-
 gdk/gdkwindow.c          |  195 +++++++++-------
 gdk/x11/gdkasync.c       |    5 +-
 gdk/x11/gdkasync.h       |    5 +-
 gdk/x11/gdkdisplay-x11.c |   37 ++--
 gdk/x11/gdkevents-x11.c  |    2 +-
 gdk/x11/gdkmain-x11.c    |  111 ++++-----
 10 files changed, 630 insertions(+), 385 deletions(-)

diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index a8f027e..48d79e8 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -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__
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index c3a7d62..3c7bde3 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -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
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index dc7fec8..3382236 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -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);
 
diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c
index 703dcfa..6912653 100644
--- a/gdk/gdkoffscreenwindow.c
+++ b/gdk/gdkoffscreenwindow.c
@@ -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
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 102fc90..604feba 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -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)
     {
diff --git a/gdk/x11/gdkasync.c b/gdk/x11/gdkasync.c
index b230c1f..e412ed2 100644
--- a/gdk/x11/gdkasync.c
+++ b/gdk/x11/gdkasync.c
@@ -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;
diff --git a/gdk/x11/gdkasync.h b/gdk/x11/gdkasync.h
index 407e3c8..44aa18c 100644
--- a/gdk/x11/gdkasync.h
+++ b/gdk/x11/gdkasync.h
@@ -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
 {
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index a05bc51..a517404 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -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);
     }
 }
 
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index 617e87d..01ed9b6 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -2207,7 +2207,7 @@ gdk_event_translate (GdkDisplay *display,
   
   if (window)
     g_object_unref (window);
-  
+
   return return_val;
 }
 
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index aa11db3..b06b15e 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -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 ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]