[gtk+/client-side-windows: 47/284] New approach to motion event handling



commit b771c9924d63259bc38f46349230ce48dda953e6
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Dec 15 10:24:54 2008 +0100

    New approach to motion event handling
---
 gdk/gdkdisplay.c        |  233 ++++++++++++----
 gdk/gdkdisplay.h        |   14 +-
 gdk/gdkinternals.h      |   11 +-
 gdk/gdkwindow.c         |  714 +++++++++++++++++++++++++++--------------------
 gdk/x11/gdkevents-x11.c |    2 +-
 gdk/x11/gdkwindow-x11.c |    7 +-
 6 files changed, 606 insertions(+), 375 deletions(-)

diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index bc515b5..d07b6a5 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -491,7 +491,7 @@ gdk_display_real_get_window_at_pointer (GdkDisplay *display,
   GdkWindow *window;
   gint x, y;
 
-  window = _gdk_windowing_window_at_pointer (display, &x, &y);
+  window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL);
 
   /* This might need corrections, as the native window returned
      may contain client side children */
@@ -737,6 +737,17 @@ generate_grab_broken_event (GdkWindow *window,
     }
 }
 
+static void
+set_window_under_pointer (GdkDisplay *display,
+			  GdkWindow *window)
+{
+  if (display->pointer_info.window_under_pointer)
+    g_object_unref (display->pointer_info.window_under_pointer);
+  display->pointer_info.window_under_pointer = window;
+  if (window)
+    g_object_ref (window);
+}
+
 void
 _gdk_display_set_has_pointer_grab (GdkDisplay *display,
 				   GdkWindow *window,
@@ -747,51 +758,89 @@ _gdk_display_set_has_pointer_grab (GdkDisplay *display,
 				   guint32 time,
 				   gboolean implicit)
 {
-  int wx, wy;
+  GdkWindow *pointer_window, *src_toplevel, *dest_toplevel, *src_window;
   
-  /* Normal GRAB events are sent by listening for enter and leave
-   * events on the native event window, which is then proxied
-   * into the virtual windows when the events are seen.
-   * However, there are two cases where X will not send these events:
-   * * When there is already a grab on the native parent of the
-   *   virtual grab window
-   * * When there is no grab, but the pointer is already in the
-   *   native parent of the virtual grab window
-   * In the first case we send the right GRAB events from the grab, but
-   * in the second case we need to generate our own UNGRAB crossing events.
-   */
   if (display->pointer_grab.window != NULL &&
       display->pointer_grab.window != window)
     {
       generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
 				  FALSE, display->pointer_grab.implicit,
 				  window);
-
-      /* Re-grabbing. Pretend we have no grab for now so that
-	 the GRAB events get delivered */
-      display->pointer_grab.window = NULL;
-      _gdk_syntesize_crossing_events (display, 
-				      display->pointer_grab.window,
-				      window,
-				      GDK_CROSSING_GRAB,
-				      /* These may be stale... */
-				      display->pointer_info.toplevel_x,
-				      display->pointer_info.toplevel_y,
-				      display->pointer_info.state,
-				      time, TRUE, TRUE);
     }
-  else if (_gdk_windowing_window_at_pointer (display, &wx, &wy) == native_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 (!implicit)
     {
-      _gdk_syntesize_crossing_events (display, 
-				      display->pointer_info.window_under_pointer,
-				      window,
-				      GDK_CROSSING_GRAB,
-				      /* These may be stale... */
-				      display->pointer_info.toplevel_x,
-				      display->pointer_info.toplevel_y,
-				      display->pointer_info.state,
-				      time, TRUE, TRUE);
+      GdkScreen *screen;
+      GdkWindowObject *w;
+      int x, y;
+      GdkModifierType state;
+
+      /* 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;
       
+      if (src_window != window)
+	{
+	  /* _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);
+	  else
+	    src_toplevel = NULL;
+	  dest_toplevel = gdk_window_get_toplevel (window);
+	  
+	  if (src_toplevel == NULL ||
+	      src_toplevel == dest_toplevel)
+	    {
+	      _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, FALSE);
+	    }
+	  else
+	    {
+	      _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, FALSE);
+	      _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, FALSE);
+	    }
+	}
+
+      /* !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)
+	set_window_under_pointer (display, NULL);
     }
 
   display->pointer_grab.window = window;
@@ -810,10 +859,12 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
 				     gboolean do_grab_one_pointer_release_event,
 				     guint32 time)
 {
-  int wx, wy;
+  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;
@@ -821,34 +872,98 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
   if (do_grab_one_pointer_release_event)
     display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
 
-  /* We need to set this to null befor syntesizing events to make sure they get
-     delivered to anything but the grab window */
+  /* Set first so crossing events get sent */
   display->pointer_grab.window = NULL;
   
-  /* Normal UNGRAB events are sent by listening for enter and leave
-   * events on the native event window, which is then proxied
-   * into the virtual windows when the events are seen.
-   * However, there are two cases where X will not send these events:
-   * * When this ungrab is due to a new grab on the native window that
-   *   is a parent of the currently grabbed virtual window
-   * * When there is no new grab, and the pointer is already in the
-   *   grabbed virtual windows parent native window
-   * In the first case we send the right GRAB events from the grab, but
-   * in the second case we need to generate our own UNGRAB crossing events.
+  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 (_gdk_windowing_window_at_pointer (display, &wx, &wy) == old_native_grab_window)
+  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)
+	{
+	  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 child window */
+      pointer_window =
+	_gdk_window_find_descendant_at ((GdkWindow *)w,
+					x, y,
+					NULL, NULL);
+    }
+  
+  
+  if (pointer_window == NULL)
     {
-      _gdk_syntesize_crossing_events (display, 
+      _gdk_syntesize_crossing_events (display,
 				      old_grab_window,
-				      display->pointer_info.window_under_pointer,
+				      NULL,
 				      GDK_CROSSING_UNGRAB,
-				      /* These may be stale... */
-				      display->pointer_info.toplevel_x,
-				      display->pointer_info.toplevel_y,
-				      display->pointer_info.state,
-				      time, TRUE, TRUE);
+				      x, y, state,
+				      time,
+				      NULL, FALSE);
+    }
+  else
+    {
+      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);
+
+	  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, FALSE);
+	    }
+	  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, FALSE);
+	      _gdk_syntesize_crossing_events (display,
+					      NULL,
+					      pointer_window,
+					      GDK_CROSSING_UNGRAB,
+					      x, y, state,
+					      time,
+					      NULL, FALSE);
+	    }
+	}
     }
+
+  /* We're now ungrabbed, update the window_under_pointer */
+  set_window_under_pointer (display, pointer_window);
   
   if (implicit)
     generate_grab_broken_event (old_grab_window,
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 790bc0b..e4ca845 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -58,14 +58,18 @@ typedef struct
   GdkWindow *grab_one_pointer_release_event;
 } GdkPointerGrabInfo;
 
-/* Tracks information about which window the pointer is in and
- * at what position the mouse is. This is useful when we need
- * to synthesize events later.
+/* 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,
+ * so in the case of a grab, either with owner_events==FALSE or with the
+ * pointer in no clients window the x/y coordinates may actually be outside
+ * the window.
  */
 typedef struct
 {
-  GdkWindow *window_under_pointer;
-  gdouble toplevel_x, toplevel_y;
+  GdkWindow *toplevel_under_pointer; /* The toplevel window with mouse inside, tracked via native events */
+  GdkWindow *window_under_pointer; /* The window that last got sent a normal enter event */
+  gdouble toplevel_x, toplevel_y; 
   guint32 state;
 } GdkPointerWindowInfo;
 
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 0acd617..51d3f7d 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -345,7 +345,12 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkDisplay       *display,
 					      GdkModifierType  *mask);
 GdkWindow* _gdk_windowing_window_at_pointer  (GdkDisplay       *display,
 					      gint             *win_x,
-					      gint             *win_y);
+					      gint             *win_y,
+					      GdkModifierType  *mask);
+void _gdk_windowing_got_event                (GdkDisplay       *display,
+					      GList            *event_link,
+					      GdkEvent         *event);
+
 
 /* Return the number of bits-per-pixel for images of the specified depth. */
 gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
@@ -521,8 +526,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay                 *display,
 				     gint                        toplevel_y,
 				     GdkModifierType             mask,
 				     guint32                     time_,
-				     gboolean                    do_first,
-				     gboolean                    do_last);
+				     GdkEvent                   *event_in_queue,
+				     gboolean                    before_event);
 
 void _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
 
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index de0f463..49a58d3 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -1159,6 +1159,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
   GdkWindowObject *temp_private;
   GdkWindow *temp_window;
   GdkScreen *screen;
+  GdkDisplay *display;
   GList *children;
   GList *tmp;
 
@@ -1169,11 +1170,13 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
   if (GDK_WINDOW_DESTROYED (window))
     return;
     
+  display = gdk_drawable_get_display (GDK_DRAWABLE (window));
   screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
   temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
   if (temp_window == window)
     g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
 
+
   switch (GDK_WINDOW_TYPE (window))
     {
     case GDK_WINDOW_ROOT:
@@ -1284,6 +1287,12 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
 	    gdk_window_redirect_free (private->redirect);
 
 	  private->redirect = NULL;
+
+	  if (display->pointer_info.toplevel_under_pointer == window)
+	    {
+	      g_object_unref (display->pointer_info.toplevel_under_pointer);
+	      display->pointer_info.toplevel_under_pointer = NULL;
+	    }
 	}
       break;
     }
@@ -6615,13 +6624,9 @@ static gboolean
 point_in_window (GdkWindowObject *window,
 		 double x, double y)
 {
-  int w, h;
-  
-  gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
-  
   return
-    x >= 0 &&  x < w &&
-    y >= 0 && y < h;
+    x >= 0 &&  x < window->width &&
+    y >= 0 && y < window->height;
 }
 
 static void
@@ -6856,22 +6861,22 @@ is_motion_type (GdkEventType type)
          type == GDK_LEAVE_NOTIFY;
 }
 
-static GdkWindow *
-find_common_ancestor (GdkWindow *win1,
-		      GdkWindow *win2)
+static GdkWindowObject *
+find_common_ancestor (GdkWindowObject *win1,
+		      GdkWindowObject *win2)
 {
   GdkWindowObject *tmp;
   GList *path1 = NULL, *path2 = NULL;
   GList *list1, *list2;
 
-  tmp = GDK_WINDOW_OBJECT (win1);
+  tmp = win1;
   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
     {
       path1 = g_list_prepend (path1, tmp);
       tmp = tmp->parent;
     }
 
-  tmp = GDK_WINDOW_OBJECT (win2);
+  tmp = win2;
   while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
     {
       path2 = g_list_prepend (path2, tmp);
@@ -6890,7 +6895,7 @@ find_common_ancestor (GdkWindow *win1,
   g_list_free (path1);
   g_list_free (path2);
 
-  return GDK_WINDOW (tmp);
+  return tmp;
 }
 
 GdkEvent *
@@ -6995,6 +7000,54 @@ _gdk_make_event (GdkWindow    *window,
   return event;
 }
 
+static void
+send_crossing_event (GdkDisplay                 *display,
+		     GdkWindowObject            *toplevel,
+		     GdkWindowObject            *window,
+		     GdkEventType                type,
+		     GdkCrossingMode             mode,
+		     GdkNotifyType               notify_type,
+		     GdkWindow                  *subwindow,
+		     gint                        toplevel_x,
+		     gint                        toplevel_y,
+		     GdkModifierType             mask,
+		     guint32                     time_,
+		     GdkEvent                   *event_in_queue,
+		     gboolean                    before_event)
+{
+  GdkEvent *event;
+  guint32 event_mask;
+
+  if (display->pointer_grab.window != NULL &&
+      !display->pointer_grab.owner_events &&
+      (GdkWindow *)window != display->pointer_grab.window)
+    return;
+  
+  if (type == GDK_LEAVE_NOTIFY)
+    event_mask = GDK_LEAVE_NOTIFY_MASK;
+  else
+    event_mask = GDK_ENTER_NOTIFY_MASK;
+
+  if (window->event_mask & event_mask)
+    {
+      event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, before_event);
+      event->crossing.time = time_;
+      event->crossing.subwindow = subwindow;
+      if (subwindow)
+	g_object_ref (subwindow);
+      convert_toplevel_coords_to_window ((GdkWindow *)window,
+					 toplevel_x, toplevel_y,
+					 &event->crossing.x, &event->crossing.y);
+      event->crossing.x_root = toplevel_x + toplevel->x;
+      event->crossing.y_root = toplevel_y + toplevel->y;
+      event->crossing.mode = mode;
+      event->crossing.detail = notify_type;
+      event->crossing.focus = FALSE;
+      event->crossing.state = mask;
+    }
+}
+  
+
 /* The coordinates are in the toplevel window that src/dest are in.
  * src and dest are always (if != NULL) in the same toplevel, as
  * we get a leave-notify and set the window_under_pointer to null
@@ -7009,159 +7062,134 @@ _gdk_syntesize_crossing_events (GdkDisplay                 *display,
 				gint                        toplevel_y,
 				GdkModifierType             mask,
 				guint32                     time_,
-				gboolean                    do_first,
-				gboolean                    do_last)
+				GdkEvent                   *event_in_queue,
+				gboolean                    before_event)
 {
-  GdkWindow *c;
-  GdkWindow *win, *last, *next;
-  GdkEvent *event;
+  GdkWindowObject *c;
+  GdkWindowObject *win, *last, *next;
   GList *path, *list;
   gboolean non_linear;
-  GdkWindow *a;
-  GdkWindow *b;
-  GdkWindow *event_win;
+  GdkWindowObject *a;
+  GdkWindowObject *b;
   GdkWindowObject *toplevel;
+  GdkNotifyType notify_type;
 
   /* TODO: Don't send events to toplevel, as we get those from the windowing system */
   
-  a = src;
-  b = dest;
+  a = (GdkWindowObject *)src;
+  b = (GdkWindowObject *)dest;
   if (a == b)
     return; /* No crossings generated between src and dest */
 
   c = find_common_ancestor (a, b);
+
   non_linear = (c != a) && (c != b);
 
   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
     {
-      toplevel = (GdkWindowObject *)gdk_window_get_toplevel (a);
+      toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)a);
       
       /* Traverse up from a to (excluding) c sending leave events */
-
-      event_win = get_target_window_for_pointer_event (display, a, GDK_LEAVE_NOTIFY, mask);
-      if (do_first && event_win)
+      if (non_linear)
+	notify_type = GDK_NOTIFY_NONLINEAR;
+      else if (c == a)
+	notify_type = GDK_NOTIFY_INFERIOR;
+      else
+	notify_type = GDK_NOTIFY_ANCESTOR;
+      send_crossing_event (display, toplevel,
+			   a, GDK_LEAVE_NOTIFY,
+			   mode,
+			   notify_type,
+			   NULL,
+			   toplevel_x, toplevel_y,
+			   mask, time_,
+			   event_in_queue, before_event);
+     
+      if (c != a)
 	{
-	  event = _gdk_make_event (event_win, GDK_LEAVE_NOTIFY, NULL, FALSE);
-	  event->crossing.time = time_;
-	  event->crossing.subwindow = NULL;
-	  convert_toplevel_coords_to_window (event_win,
-					     toplevel_x, toplevel_y,
-					     &event->crossing.x, &event->crossing.y);
-	  event->crossing.x_root = toplevel_x + toplevel->x;
-	  event->crossing.y_root = toplevel_y + toplevel->y;
-	  event->crossing.mode = mode;
 	  if (non_linear)
-	    event->crossing.detail = GDK_NOTIFY_NONLINEAR;
-	  else if (c == a)
-	    event->crossing.detail = GDK_NOTIFY_INFERIOR;
+	    notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
 	  else
-	    event->crossing.detail = GDK_NOTIFY_ANCESTOR;
-	  event->crossing.focus = FALSE;
-	  event->crossing.state = mask;
-	}
-      
-      if (c != a)
-	{
+	    notify_type = GDK_NOTIFY_VIRTUAL;
+	  
 	  last = a;
-	  win = GDK_WINDOW (GDK_WINDOW_OBJECT (a)->parent);
+	  win = a->parent;
 	  while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
 	    {
-	      event_win = get_target_window_for_pointer_event (display, win, GDK_LEAVE_NOTIFY, mask);
-	      if (event_win)
-		{
-		  event = _gdk_make_event (event_win, GDK_LEAVE_NOTIFY, NULL, FALSE);
-		  event->crossing.time = time_;
-		  event->crossing.subwindow = g_object_ref (last);
-		  convert_toplevel_coords_to_window (event_win,
-						     toplevel_x, toplevel_y,
-						     &event->crossing.x, &event->crossing.y);
-		  event->crossing.x_root = toplevel_x + toplevel->x;
-		  event->crossing.y_root = toplevel_y + toplevel->y;
-		  event->crossing.mode = mode;
-		  if (non_linear)
-		    event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
-		  else
-		    event->crossing.detail = GDK_NOTIFY_VIRTUAL;
-		  event->crossing.focus = FALSE;
-		  event->crossing.state = mask;
-		}
+	      send_crossing_event (display, toplevel,
+				   win, GDK_LEAVE_NOTIFY,
+				   mode,
+				   notify_type,
+				   (GdkWindow *)last,
+				   toplevel_x, toplevel_y,
+				   mask, time_,
+				   event_in_queue, before_event);
+	      
 	      last = win;
-	      win = GDK_WINDOW (GDK_WINDOW_OBJECT (win)->parent);
+	      win = win->parent;
 	    }
 	}
     }
 
   if (b) /* Might not be a dest, e.g. if we're moving out of the window */
     {
-      toplevel = (GdkWindowObject *)gdk_window_get_toplevel (b);
+      toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b);
       
       /* Traverse down from c to b */
       if (c != b)
 	{
 	  path = NULL;
-	  win = GDK_WINDOW (GDK_WINDOW_OBJECT (b)->parent);
+	  win = b->parent;
 	  while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
 	    {
 	      path = g_list_prepend (path, win);
-	      win = GDK_WINDOW( GDK_WINDOW_OBJECT (win)->parent);
+	      win = win->parent;
 	    }
 	  
+	  if (non_linear)
+	    notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
+	  else
+	    notify_type = GDK_NOTIFY_VIRTUAL;
+	  
 	  list = path;
 	  while (list)
 	    {
-	      win = (GdkWindow *)list->data;
+	      win = (GdkWindowObject *)list->data;
 	      list = g_list_next (list);
 	      if (list)
-		next = (GdkWindow *)list->data;
+		next = (GdkWindowObject *)list->data;
 	      else
 		next = b;
-	      
-	      event_win = get_target_window_for_pointer_event (display, win, GDK_ENTER_NOTIFY, mask);
-	      if (event_win)
-		{
-		  event = _gdk_make_event (event_win, GDK_ENTER_NOTIFY, NULL, FALSE);
-		  event->crossing.time = time_;
-		  event->crossing.subwindow = g_object_ref (next);
-		  convert_toplevel_coords_to_window (event_win,
-						     toplevel_x, toplevel_y,
-						     &event->crossing.x, &event->crossing.y);
-		  event->crossing.x_root = toplevel_x + toplevel->x;
-		  event->crossing.y_root = toplevel_y + toplevel->y;
-		  event->crossing.mode = mode;
-		  if (non_linear)
-		    event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
-		  else
-		    event->crossing.detail = GDK_NOTIFY_VIRTUAL;
-		  event->crossing.focus = FALSE;
-		  event->crossing.state = mask;
-		}
+
+	      send_crossing_event (display, toplevel,
+				   win, GDK_ENTER_NOTIFY,
+				   mode,
+				   notify_type,
+				   (GdkWindow *)next,
+				   toplevel_x, toplevel_y,
+				   mask, time_,
+				   event_in_queue, before_event);
 	    }
 	  g_list_free (path);
 	}
+
+
+      if (non_linear)
+	notify_type = GDK_NOTIFY_NONLINEAR;
+      else if (c == a)
+	notify_type = GDK_NOTIFY_ANCESTOR;
+      else
+	notify_type = GDK_NOTIFY_INFERIOR;
       
-      event_win = get_target_window_for_pointer_event (display, b, GDK_ENTER_NOTIFY, mask);
-      if (do_last && event_win)
-	{
-	  event = _gdk_make_event (event_win, GDK_ENTER_NOTIFY, NULL, FALSE);
-	  event->crossing.time = time_;
-	  event->crossing.subwindow = NULL;
-	  convert_toplevel_coords_to_window (event_win,
-					     toplevel_x, toplevel_y,
-					     &event->crossing.x, &event->crossing.y);
-	  event->crossing.x_root = toplevel_x + toplevel->x;
-	  event->crossing.y_root = toplevel_y + toplevel->y;
-	  event->crossing.mode = mode;
-	  if (non_linear)
-	    event->crossing.detail = GDK_NOTIFY_NONLINEAR;
-	  else if (c == a)
-	    event->crossing.detail = GDK_NOTIFY_ANCESTOR;
-	  else
-	    event->crossing.detail = GDK_NOTIFY_INFERIOR;
-	  event->crossing.focus = FALSE;
-	  event->crossing.state = mask;
-	}
+      send_crossing_event (display, toplevel,
+			   b, GDK_ENTER_NOTIFY,
+			   mode,
+			   notify_type,
+			   NULL,
+			   toplevel_x, toplevel_y,
+			   mask, time_,
+			   event_in_queue, before_event);
     }
-
 }
 
 static GdkWindow *
@@ -7176,146 +7204,182 @@ get_toplevel (GdkWindow *w)
   return GDK_WINDOW (private);
 }
 
+/* Returns the window inside the event window with the pointer in it
+ * at the specified coordinates, or NULL if its not in any child of
+ * the toplevel. It also takes into account !owner_events grabs.
+ */
+static GdkWindow *
+get_pointer_window (GdkDisplay *display,
+		    GdkWindow *event_window,
+		    gdouble toplevel_x,
+		    gdouble toplevel_y)
+{
+  GdkWindow *pointer_window;
+
+  if (event_window == display->pointer_info.toplevel_under_pointer)
+    pointer_window =
+      _gdk_window_find_descendant_at (event_window,
+				      toplevel_x, toplevel_y,
+				      NULL, NULL);
+  else
+    pointer_window = NULL;
+
+  if (display->pointer_grab.window != NULL &&
+      !display->pointer_grab.owner_events &&
+      pointer_window != display->pointer_grab.window)
+    pointer_window = NULL;
+  
+  return pointer_window;
+}
+
+static void
+set_window_under_pointer (GdkDisplay *display,
+			  GdkWindow *window)
+{
+  if (display->pointer_info.window_under_pointer)
+    g_object_unref (display->pointer_info.window_under_pointer);
+  display->pointer_info.window_under_pointer = window;
+  if (window)
+    g_object_ref (window);
+}
+
 void
 _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
 {
   GdkDisplay *display;
   GdkWindow *changed_toplevel;
-  GdkWindow *pointer_toplevel;
+  GdkWindow *pointer_toplevel, *grab_toplevel;
   GdkWindow *new_window_under_pointer;
 
   changed_toplevel = get_toplevel (changed_window);
   
   display = gdk_drawable_get_display (changed_window);
-  if (display->pointer_info.window_under_pointer)
+  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);
+      if (new_window_under_pointer !=
+	  display->pointer_info.window_under_pointer)
+	{
+	  _gdk_syntesize_crossing_events (display,
+					  display->pointer_info.window_under_pointer,
+					  new_window_under_pointer,
+					  GDK_CROSSING_NORMAL,
+					  display->pointer_info.toplevel_x,
+					  display->pointer_info.toplevel_y,
+					  display->pointer_info.state,
+					  GDK_CURRENT_TIME,
+					  NULL, FALSE);
+	  set_window_under_pointer (display, new_window_under_pointer);
+	}
+    }
+}
+
+/* Don't use for crossing events */
+static GdkWindow *
+get_event_window (GdkDisplay                 *display,
+		  GdkWindow                  *pointer_window,
+		  GdkEventType                type,
+		  GdkModifierType             mask)
+{
+  guint evmask;
+  GdkWindow *grab_window;
+  GdkWindowObject *w;
+
+  if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
+      (type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
     {
-      pointer_toplevel = get_toplevel (display->pointer_info.window_under_pointer);
+      evmask = display->pointer_grab.event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
 
-      if (pointer_toplevel == changed_toplevel)
+      if (type == GDK_BUTTON_RELEASE &&
+	  display->pointer_grab.grab_one_pointer_release_event)
 	{
-	  new_window_under_pointer =
-	    _gdk_window_find_descendant_at (pointer_toplevel,
-					    display->pointer_info.toplevel_x,
-					    display->pointer_info.toplevel_y,
-					    NULL, NULL);
-	  if (new_window_under_pointer !=
-	      display->pointer_info.window_under_pointer)
-	    {
-	      _gdk_syntesize_crossing_events (display,
-					      display->pointer_info.window_under_pointer,
-					      new_window_under_pointer,
-					      GDK_CROSSING_NORMAL,
-					      display->pointer_info.toplevel_x,
-					      display->pointer_info.toplevel_y,
-					      display->pointer_info.state,
-					      GDK_CURRENT_TIME,
-					      TRUE, TRUE);
-	      
-	      if (display->pointer_info.window_under_pointer)
-		g_object_unref (display->pointer_info.window_under_pointer);
-	      display->pointer_info.window_under_pointer = NULL;
-	      if (new_window_under_pointer)
-		display->pointer_info.window_under_pointer = g_object_ref (new_window_under_pointer);
-	    }
+	  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;
+
+      if (evmask & type_masks[type])
+	return grab_window;
+      else
+	return NULL;
     }
+
+  w = (GdkWindowObject *)pointer_window;
+  while (w != NULL)
+    {
+      evmask = w->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (evmask & type_masks[type])
+	return (GdkWindow *)w;
+
+      w = w->parent;
+    }
+
+  if (display->pointer_grab.window != NULL &&
+      display->pointer_grab.owner_events)
+    {
+      evmask = display->pointer_grab.event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (evmask & type_masks[type])
+	return display->pointer_grab.window;
+      else
+	return NULL;
+    }
+
+  return NULL;
 }
 
 static gboolean
 proxy_pointer_event (GdkDisplay                 *display,
-		     GdkWindow                  *pointer_window,
-		     gdouble                     toplevel_x,
-                     gdouble                     toplevel_y,
 		     GdkEvent                   *source_event)
 {
-  GdkWindow *event_window;
-  GdkWindow *event_win, *cursor_window;
-  gboolean crossing_event;
+  GdkWindow *toplevel_window;
+  GdkWindow *pointer_window;
+  GdkWindow *cursor_window;
   gboolean sent_motion;
   GdkEvent *event;
   guint state;
+  gdouble toplevel_x, toplevel_y;
   guint32 time_;
 
-  event_window = source_event->any.window;
-  
+  toplevel_window = source_event->any.window;
+  gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
   gdk_event_get_state (source_event, &state);
   time_ = gdk_event_get_time (source_event);
 
-  crossing_event =
-    source_event->type == GDK_ENTER_NOTIFY ||
-    source_event->type == GDK_LEAVE_NOTIFY;
-
-  if (crossing_event)
+  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+  if (display->pointer_info.window_under_pointer != pointer_window)
     {
-      GdkEventCrossing *crossing = &source_event->crossing;
-
-      if (crossing->mode == GDK_CROSSING_GRAB)
-	{
-	  if (crossing->type == GDK_LEAVE_NOTIFY &&
-	      display->pointer_info.window_under_pointer != NULL)
-	    {
-	      _gdk_syntesize_crossing_events (display,
-					      display->pointer_info.window_under_pointer,
-					      event_window,
-					      GDK_CROSSING_GRAB,
-					      toplevel_x, toplevel_y, state, time_,
-					      TRUE, FALSE);
-	    }
+      /* Either a toplevel crossing notify that ended up inside a child window,
+	 or a motion notify that got into another child window  */
+      /* Different than last time, send crossing events */
 
-	  if (crossing->type == GDK_ENTER_NOTIFY &&
-	      display->pointer_grab.window != NULL)
-	    {
-	      _gdk_syntesize_crossing_events (display,
-					      event_window,
-					      display->pointer_grab.window,
-					      GDK_CROSSING_GRAB,
-					      toplevel_x, toplevel_y, state, time_,
-					      FALSE, TRUE);
-	    }
-	}
+      _gdk_syntesize_crossing_events (display,
+				      display->pointer_info.window_under_pointer,
+				      pointer_window,
+				      GDK_CROSSING_NORMAL,
+				      toplevel_x, toplevel_y,
+				      state, time_,
+				      source_event, source_event->type == GDK_LEAVE_NOTIFY);
 
-      if (crossing->mode == GDK_CROSSING_UNGRAB)
-	{
-	  if (crossing->type == GDK_LEAVE_NOTIFY &&
-	      display->pointer_grab.window != NULL)
-	    {
-	      _gdk_syntesize_crossing_events (display,
-					      display->pointer_grab.window,
-					      event_window,
-					      GDK_CROSSING_UNGRAB,
-					      toplevel_x, toplevel_y, state, time_,
-					      TRUE, FALSE);
-	    }
-
-	  if (crossing->type == GDK_ENTER_NOTIFY &&
-	      display->pointer_info.window_under_pointer != NULL)
-	    {
-	      _gdk_syntesize_crossing_events (display,
-					      event_window,
-					      display->pointer_info.window_under_pointer,
-					      GDK_CROSSING_UNGRAB,
-					      toplevel_x, toplevel_y, state, time_,
-					      FALSE, TRUE);
-	    }
-	}
+      set_window_under_pointer (display, pointer_window);
     }
-
-  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;
-
-  /* TODO: set cursor from cursor_window, or grab cursor */
-
-  sent_motion = FALSE;
-  if (!crossing_event &&
-      (display->pointer_info.window_under_pointer == pointer_window ||
-       (display->pointer_grab.window != NULL &&
-	!display->pointer_grab.owner_events)))
+  else if (source_event->type == GDK_MOTION_NOTIFY)
     {
-      /* send motion events */
-      event_win = get_target_window_for_pointer_event (display, pointer_window, GDK_MOTION_NOTIFY, state);
+      GdkWindow *event_win;
+
+      event_win = get_event_window (display,
+				    pointer_window,
+				    source_event->type,
+				    state);
+      
       if (event_win)
 	{
 	  sent_motion = TRUE;
@@ -7334,43 +7398,52 @@ proxy_pointer_event (GdkDisplay                 *display,
 	}
     }
 
-  _gdk_syntesize_crossing_events (display,
-				  display->pointer_info.window_under_pointer,
-				  pointer_window,
-				  GDK_CROSSING_NORMAL,
-				  toplevel_x, toplevel_y,
-				  state, time_,
-				  TRUE, TRUE);
+  /* 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 move event from parent if we sent a motion event */
-  return source_event->type == GDK_MOTION_NOTIFY && sent_motion;
+  
+  /* unlink all move events from queue.
+     We handle our own, including our emulated masks. */
+  return TRUE;
 }
 
 static gboolean
-proxy_button_event (GdkWindow                  *pointer_window,
-		    gdouble                     toplevel_x,
-                    gdouble                     toplevel_y,
-		    GdkEvent                   *source_event)
+proxy_button_event (GdkEvent *source_event)
 {
+  GdkWindow *toplevel_window;
   GdkWindow *event_win;
+  GdkWindow *pointer_window;
   GdkEvent *event;
   guint state;
   guint32 time_;
   GdkEventType type;
+  gdouble toplevel_x, toplevel_y;
   GdkDisplay *display;
 
   type = source_event->any.type;
+  toplevel_window = source_event->any.window;
+  gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
   gdk_event_get_state (source_event, &state);
   time_ = gdk_event_get_time (source_event);
   display = gdk_drawable_get_display (source_event->any.window);
-  
+
   if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
-      pointer_window != NULL &&
       display->pointer_grab.window == source_event->any.window &&
       display->pointer_grab.implicit &&
       !display->pointer_grab.converted_implicit)
     {
-      if (pointer_window != source_event->any.window)
+      pointer_window =
+	_gdk_window_find_descendant_at (toplevel_window,
+					toplevel_x, toplevel_y,
+					NULL, NULL);
+      
+      if (pointer_window != NULL &&
+	  pointer_window != source_event->any.window)
 	_gdk_display_set_has_pointer_grab (display,
 					   pointer_window,
 					   display->pointer_grab.native_window,
@@ -7382,57 +7455,51 @@ proxy_button_event (GdkWindow                  *pointer_window,
       display->pointer_grab.converted_implicit = TRUE;
     }
 
-  event_win = get_target_window_for_pointer_event (display,
-						   pointer_window,
-                                                   type,
-                                                   state);
+  pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+  
+  event_win = get_event_window (display,
+				pointer_window,
+				type,
+				state);
 
   if (event_win == NULL)
     return TRUE;
   
-  if (event_win != source_event->any.window)
-    {
-       event = _gdk_make_event (event_win, type, source_event, FALSE);
-
-      switch (type)
-        {
-        case GDK_BUTTON_PRESS:
-        case GDK_BUTTON_RELEASE:
-          event->button.button = source_event->button.button;
-	  convert_toplevel_coords_to_window (event_win,
-					     toplevel_x, toplevel_y,
-					     &event->button.x, &event->button.y);
-          event->button.x_root = source_event->button.x_root;
-          event->button.y_root = source_event->button.y_root;
-          event->button.state = state;
-          event->button.device = source_event->button.device;
-
-	  if (type == GDK_BUTTON_PRESS)
-	    _gdk_event_button_generate (display, event);
-          return TRUE;
-
-        case GDK_SCROLL:
-          event->scroll.direction = source_event->scroll.direction;
-	  convert_toplevel_coords_to_window (event_win,
-					     toplevel_x, toplevel_y,
-					     &event->scroll.x, &event->scroll.y);
-          event->scroll.x_root = source_event->scroll.x_root;
-          event->scroll.y_root = source_event->scroll.y_root;
-          event->scroll.state = state;
-          event->scroll.device = source_event->scroll.device;
-          return TRUE;
-
-        default:
-          return FALSE;
-        }
-    }
-  else
+  event = _gdk_make_event (event_win, type, source_event, FALSE);
+  
+  switch (type)
     {
-      /* Same window as original window, keep the event */
-      if (source_event->type == GDK_BUTTON_PRESS)
-	_gdk_event_button_generate (display, source_event);
+    case GDK_BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+      event->button.button = source_event->button.button;
+      convert_toplevel_coords_to_window (event_win,
+					 toplevel_x, toplevel_y,
+					 &event->button.x, &event->button.y);
+      event->button.x_root = source_event->button.x_root;
+      event->button.y_root = source_event->button.y_root;
+      event->button.state = state;
+      event->button.device = source_event->button.device;
+      
+      if (type == GDK_BUTTON_PRESS)
+	_gdk_event_button_generate (display, event);
+      return TRUE;
+      
+    case GDK_SCROLL:
+      event->scroll.direction = source_event->scroll.direction;
+      convert_toplevel_coords_to_window (event_win,
+					 toplevel_x, toplevel_y,
+					 &event->scroll.x, &event->scroll.y);
+      event->scroll.x_root = source_event->scroll.x_root;
+      event->scroll.y_root = source_event->scroll.y_root;
+      event->scroll.state = state;
+      event->scroll.device = source_event->scroll.device;
+      return TRUE;
+      
+    default:
       return FALSE;
     }
+
+  return TRUE; /* Always unlink original, we want to obey the emulated event mask */
 }
 
 void
@@ -7441,9 +7508,8 @@ _gdk_windowing_got_event (GdkDisplay *display,
 			  GdkEvent   *event)
 {
   GdkWindow *event_window;
-  GdkWindow *pointer_window;
   GdkWindowObject *event_private;
-  gdouble x, y, child_x, child_y;
+  gdouble x, y;
   gboolean unlink_event;
 
   event_window = event->any.window;
@@ -7466,40 +7532,78 @@ _gdk_windowing_got_event (GdkDisplay *display,
 					    event_private->window_type);
       
      /* We should only get these events on toplevel windows */
-      g_warning ("got unexpected event of type %s on non-toplevel window (type %s)",
+      g_warning ("got unexpected event of type %s on non-toplevel window (gtype %s, type %d)",
 		 event_type_value->value_name,
-		 window_type_value->value_name);
+		 window_type_value->value_name,
+		 GDK_WINDOW_TYPE (event_window));
       return;
     }
-  
-  gdk_event_get_coords (event, &x, &y);
-  pointer_window = _gdk_window_find_descendant_at (event_window, x, y,
-						   &child_x,
-						   &child_y);
-  unlink_event = FALSE;
-  if (is_motion_type (event->type))
-    unlink_event = proxy_pointer_event (display,
-					pointer_window,
-					x, y,
-                                        event);
-  else if (is_button_type (event->type))
-    unlink_event = proxy_button_event (pointer_window, x, y,
-                                       event);
 
+  if ((event->type == GDK_ENTER_NOTIFY ||
+       event->type == GDK_LEAVE_NOTIFY) &&
+      (event->crossing.mode == GDK_CROSSING_GRAB ||
+       event->crossing.mode == GDK_CROSSING_UNGRAB))
+    {
+      /* We synthesize all crossing events due to grabs are synthesized,
+       * so we ignore the native ones. This is partly to get easier non-X
+       * portability, and because of problems with race conditions due to
+       * the cached state in the client and the real state in the xserver
+       * when grabbing.
+       */
+
+      /* Some grab in another window (by perhaps another client) did a grab.
+       * The pointer is still in this window, but we won't get told if it
+       * moves out, so NULL this now and set it back to the right value at
+       * ungrab time.
+       */
+      if (event->type == GDK_LEAVE_NOTIFY &&
+	  event->crossing.mode == GDK_CROSSING_GRAB)
+	{
+	  g_assert (display->pointer_info.toplevel_under_pointer == event_window);
+	  g_object_unref (display->pointer_info.toplevel_under_pointer);
+	  display->pointer_info.toplevel_under_pointer = NULL;
+	}
+      
+      /* We ended up in this window after some (perhaps other clients)
+	 grab, so update the toplevel_under_window state */
+      if (event->type == GDK_ENTER_NOTIFY &&
+	  event->crossing.mode == GDK_CROSSING_UNGRAB)
+	{
+	  if (display->pointer_info.toplevel_under_pointer)
+	    g_object_unref (display->pointer_info.toplevel_under_pointer);
+	  display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+	}
+      
+      return TRUE;
+    }
+  
   /* Store last pointer window and position/state */
+  if (event->type == GDK_ENTER_NOTIFY &&
+      event->crossing.detail != GDK_NOTIFY_INFERIOR)
+    {
+      g_assert (display->pointer_info.toplevel_under_pointer == NULL);
+      display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
+    }
+  else if (event->type == GDK_LEAVE_NOTIFY &&
+	   event->crossing.detail != GDK_NOTIFY_INFERIOR)
+    {
+      g_assert (display->pointer_info.toplevel_under_pointer == event_window);
+      g_object_unref (display->pointer_info.toplevel_under_pointer);
+      display->pointer_info.toplevel_under_pointer = NULL;
+    }
 
+  gdk_event_get_coords (event, &x, &y);
   display->pointer_info.toplevel_x = x;
   display->pointer_info.toplevel_y = y;
   gdk_event_get_state (event, &display->pointer_info.state);
+
   
-  if (pointer_window != display->pointer_info.window_under_pointer)
-    {
-      if (display->pointer_info.window_under_pointer)
-	g_object_unref (display->pointer_info.window_under_pointer);
-      display->pointer_info.window_under_pointer = NULL;
-      if (pointer_window)
-	display->pointer_info.window_under_pointer = g_object_ref (pointer_window);
-    }
+  unlink_event = FALSE;
+  if (is_motion_type (event->type))
+    unlink_event = proxy_pointer_event (display,
+                                        event);
+  else if (is_button_type (event->type))
+    unlink_event = proxy_button_event (event);
 
   if (unlink_event)
     {
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index 2a8c32c..4f02dc2 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -987,7 +987,7 @@ gdk_event_translate (GdkDisplay *display,
 	  display_x11->keyboard_xgrab_window != NULL &&
 	  (
 	   /* The window is not a descendant of the grabbed window */
-	   !is_parent_of (display_x11->keyboard_xgrab_window, window) ||
+	   !is_parent_of ((GdkWindow *)display_x11->keyboard_xgrab_window, window) ||
 	   /* Or owner event is false */
 	   !display_x11->keyboard_xgrab_owner_events
 	   )
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 21fe7d6..27ab045 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -3185,7 +3185,8 @@ gdk_display_warp_pointer (GdkDisplay *display,
 GdkWindow*
 _gdk_windowing_window_at_pointer (GdkDisplay *display,
                                   gint       *win_x,
-				  gint       *win_y)
+				  gint       *win_y,
+				  GdkModifierType *mask)
 {
   GdkWindow *window;
   GdkScreen *screen;
@@ -3294,7 +3295,9 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
   window = gdk_window_lookup_for_display (display, xwindow_last);
   *win_x = window ? winx : -1;
   *win_y = window ? winy : -1;
-
+  if (mask)
+    *mask = xmask;
+  
   return window;
 }
 



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