[gtk+/client-side-windows] Initial version of input support



commit 7372379c24d183aa23e33cef031b774a5cb25ce4
Author: Alexander Larsson <alexl redhat com>
Date:   Fri May 29 16:39:12 2009 +0200

    Initial version of input support
---
 gdk/gdkdisplay.h          |    1 +
 gdk/gdkinternals.h        |    6 +
 gdk/gdkwindow.c           |  113 +++++++++++++++++-
 gdk/gdkwindowimpl.h       |    4 +
 gdk/x11/gdkdisplay-x11.h  |    5 -
 gdk/x11/gdkevents-x11.c   |   24 +---
 gdk/x11/gdkinput-x11.c    |  259 +++++++++++++++++++++--------------------
 gdk/x11/gdkinput-xfree.c  |  289 +++++++++++++++++++++++++++------------------
 gdk/x11/gdkinput.c        |  230 +++++++++++++++++-------------------
 gdk/x11/gdkinputprivate.h |   41 +++----
 gdk/x11/gdkmain-x11.c     |    3 +-
 gdk/x11/gdkwindow-x11.c   |    5 +-
 12 files changed, 557 insertions(+), 423 deletions(-)

diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 3c7bde3..2838d44 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -91,6 +91,7 @@ struct _GdkDisplay
   const GdkDisplayPointerHooks *pointer_hooks; /* Current hooks for querying pointer */
   
   guint closed : 1;		/* Whether this display has been closed */
+  guint ignore_core_events : 1; /* Don't send core motion and button event */
 
   guint double_click_distance;	/* Maximum distance between clicks in pixels */
   gint button_x[2];             /* The last 2 button click positions. */
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 94cce6a..a0c2d51 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -187,6 +187,7 @@ typedef struct
   gboolean grab_one_pointer_release_event;
 } GdkPointerGrabInfo;
 
+typedef struct _GdkInputWindow GdkInputWindow;
 
 /* Private version of GdkWindowObject. The initial part of this strucuture
    is public for historical reasons. Don't change that part */
@@ -260,6 +261,7 @@ struct _GdkWindowObject
   guint native_visibility : 2; /* the native visibility of a impl windows */
 
   GdkWindowPaint *implicit_paint;
+  GdkInputWindow *input_window; /* only for impl windows */
 
   GList *outstanding_moves;
 
@@ -640,6 +642,10 @@ GdkRegion *_gdk_window_calculate_full_clip_region    (GdkWindow     *window,
                                                       gint          *base_y_offset);
 gboolean    _gdk_window_has_impl (GdkWindow *window);
 GdkWindow * _gdk_window_get_impl_window (GdkWindow *window);
+GdkWindow *_gdk_window_get_input_window_for_event (GdkWindow *native_window,
+						   GdkEventType event_type,
+						   int x, int y,
+						   gulong serial);
 GdkRegion  *_gdk_region_new_from_yxbanded_rects (GdkRectangle *rects, int n_rects);
 
 /*****************************
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index a2b5d6d..b20cf69 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -1596,6 +1596,10 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
 					   NULL, NULL);
 	    }
 
+
+	  if (private->extension_events)
+	    GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_window_destroy (window);
+
 	  if (gdk_window_has_impl (private))
 	    {
 	      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->destroy (window, recursing_native, foreign_destroy);
@@ -8240,6 +8244,10 @@ send_crossing_event (GdkDisplay                 *display,
   else
     event_mask = GDK_ENTER_NOTIFY_MASK;
 
+  if (window->extension_events != 0)
+    GDK_WINDOW_IMPL_GET_IFACE (window->impl)->input_window_crossing (window,
+								     type == GDK_ENTER_NOTIFY);
+
   if (window->event_mask & event_mask)
     {
       event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
@@ -8724,7 +8732,7 @@ proxy_pointer_event (GdkDisplay                 *display,
 	    }
 	}
       
-      if (event_win)
+      if (event_win && !display->ignore_core_events)
 	{
 	  event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
 	  event->motion.time = time_;
@@ -8814,7 +8822,7 @@ proxy_button_event (GdkEvent *source_event,
 				type, state,
 				NULL, serial);
 
-  if (event_win == NULL)
+  if (event_win == NULL || display->ignore_core_events)
     return TRUE;
   
   event = _gdk_make_event (event_win, type, source_event, FALSE);
@@ -8914,6 +8922,22 @@ gdk_window_print_tree (GdkWindow *window,
 
 #endif /* DEBUG_WINDOW_PRINTING */
 
+static gboolean
+is_input_event (GdkDisplay *display,
+		GdkEvent *event)
+{
+  GdkDevice *core_pointer;
+
+  core_pointer = gdk_display_get_core_pointer (display);
+  if ((event->type == GDK_MOTION_NOTIFY &&
+       event->motion.device != core_pointer) ||
+      (event->type == GDK_BUTTON_PRESS ||
+       event->type == GDK_BUTTON_RELEASE) &&
+      event->button.device != core_pointer)
+    return TRUE;
+  return FALSE;
+}
+
 void
 _gdk_windowing_got_event (GdkDisplay *display,
 			  GList      *event_link,
@@ -8958,6 +8982,9 @@ _gdk_windowing_got_event (GdkDisplay *display,
       return;
     }
 
+  if (is_input_event (display, event))
+    return;
+
   if (!(is_button_type (event->type) ||
 	is_motion_type (event->type)) ||
       GDK_WINDOW_TYPE (event_private) == GDK_WINDOW_ROOT)
@@ -9075,5 +9102,87 @@ _gdk_windowing_got_event (GdkDisplay *display,
     }
 }
 
+
+static GdkWindow *
+get_extension_event_window (GdkDisplay                 *display,
+			    GdkWindow                  *pointer_window,
+			    GdkEventType                type,
+			    gulong                      serial)
+{
+  guint evmask;
+  GdkWindow *grab_window;
+  GdkWindowObject *w;
+  GdkPointerGrabInfo *grab;
+
+  grab = _gdk_display_has_pointer_grab (display, serial);
+
+  if (grab != NULL && !grab->owner_events)
+    {
+      evmask = grab->event_mask;
+
+      grab_window = grab->window;
+
+      if (evmask & type_masks[type])
+	return grab_window;
+      else
+	return NULL;
+    }
+
+  w = (GdkWindowObject *)pointer_window;
+  while (w != NULL)
+    {
+      evmask = w->extension_events;
+
+      if (evmask & type_masks[type])
+	return (GdkWindow *)w;
+
+      w = w->parent;
+    }
+
+  if (grab != NULL &&
+      grab->owner_events)
+    {
+      evmask = grab->event_mask;
+
+      if (evmask & type_masks[type])
+	return grab->window;
+      else
+	return NULL;
+    }
+
+  return NULL;
+}
+
+
+GdkWindow *
+_gdk_window_get_input_window_for_event (GdkWindow *native_window,
+					GdkEventType event_type,
+					int x, int y,
+					gulong serial)
+{
+  GdkDisplay *display;
+  GdkWindow *toplevel_window;
+  GdkWindow *pointer_window;
+  GdkWindow *event_win;
+  gdouble toplevel_x, toplevel_y;
+
+  toplevel_x = x;
+  toplevel_y = y;
+
+  display = gdk_drawable_get_display (native_window);
+  toplevel_window = convert_coords_to_toplevel (native_window,
+						toplevel_x, toplevel_y,
+						&toplevel_x, &toplevel_y);
+  pointer_window = get_pointer_window (display, toplevel_window,
+				       toplevel_x, toplevel_y, serial);
+  event_win = get_extension_event_window (display,
+					  pointer_window,
+					  event_type,
+					  serial);
+
+  return event_win;
+}
+
+
 #define __GDK_WINDOW_C__
 #include "gdkaliasdef.c"
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index d63e5a1..1bedb35 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -128,6 +128,10 @@ struct _GdkWindowImplIface
   void         (* destroy)              (GdkWindow       *window,
 					 gboolean         recursing,
 					 gboolean         foreign_destroy);
+
+  void         (* input_window_destroy) (GdkWindow       *window);
+  void         (* input_window_crossing)(GdkWindow       *window,
+					 gboolean         enter);
 };
 
 /* Interface Functions */
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index e92418d..2873c2d 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -133,11 +133,6 @@ struct _GdkDisplayX11
   /* input GdkWindow list */
   GList *input_windows;
 
-  gint input_ignore_core;
-  /* information about network port and host for gxid daemon */
-  gchar *input_gxid_host;
-  gint   input_gxid_port;
-
   /* Startup notification */
   gchar *startup_notification_id;
 
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index 8d3141a..4565b39 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -1125,9 +1125,7 @@ gdk_event_translate (GdkDisplay *display,
 			   xevent->xbutton.x, xevent->xbutton.y,
 			   xevent->xbutton.button));
       
-      if (window_private == NULL || 
-	  ((window_private->extension_events != 0) &&
-           display_x11->input_ignore_core))
+      if (window_private == NULL)
 	{
 	  return_val = FALSE;
 	  break;
@@ -1201,9 +1199,7 @@ gdk_event_translate (GdkDisplay *display,
 			   xevent->xbutton.x, xevent->xbutton.y,
 			   xevent->xbutton.button));
       
-      if (window_private == NULL ||
-	  ((window_private->extension_events != 0) &&
-           display_x11->input_ignore_core))
+      if (window_private == NULL)
 	{
 	  return_val = FALSE;
 	  break;
@@ -1241,9 +1237,7 @@ gdk_event_translate (GdkDisplay *display,
 			   xevent->xmotion.x, xevent->xmotion.y,
 			   (xevent->xmotion.is_hint) ? "true" : "false"));
       
-      if (window_private == NULL ||
-	  ((window_private->extension_events != 0) &&
-           display_x11->input_ignore_core))
+      if (window_private == NULL)
 	{
 	  return_val = FALSE;
 	  break;
@@ -1304,12 +1298,6 @@ gdk_event_translate (GdkDisplay *display,
 	    }
 	}
 
-      /* Tell XInput stuff about it if appropriate */
-      if (window_private &&
-	  !GDK_WINDOW_DESTROYED (window) &&
-	  window_private->extension_events != 0)
-	_gdk_input_enter_event (&xevent->xcrossing, window);
-      
       event->crossing.type = GDK_ENTER_NOTIFY;
       event->crossing.window = window;
       
@@ -1854,7 +1842,7 @@ gdk_event_translate (GdkDisplay *display,
       if (window &&
 	  xevent->xconfigure.event == xevent->xconfigure.window &&
 	  !GDK_WINDOW_DESTROYED (window) &&
-	  (window_private->extension_events != 0))
+	  window_private->input_window != NULL)
 	_gdk_input_configure_event (&xevent->xconfigure, window);
       
 #ifdef HAVE_XSYNC
@@ -2171,8 +2159,8 @@ gdk_event_translate (GdkDisplay *display,
 	  
 	  if (window_private &&
 	      !GDK_WINDOW_DESTROYED (window_private) &&
-	      (window_private->extension_events != 0))
-	    return_val = _gdk_input_other_event(event, xevent, window);
+	      window_private->input_window)
+	    return_val = _gdk_input_other_event (event, xevent, window);
 	  else
 	    return_val = FALSE;
 	  
diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c
index 9e2d818..22e39a0 100644
--- a/gdk/x11/gdkinput-x11.c
+++ b/gdk/x11/gdkinput-x11.c
@@ -21,7 +21,7 @@
  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
 #include "config.h"
@@ -39,7 +39,7 @@ static GdkDevicePrivate *gdk_input_device_new            (GdkDisplay       *disp
 							  XDeviceInfo      *device,
 							  gint              include_core);
 static void              gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
-							  GdkInputWindow   *input_window,
+							  GdkWindow        *window,
 							  gint             *axis_data,
 							  gdouble          *axis_out,
 							  gdouble          *x_out,
@@ -64,37 +64,26 @@ _gdk_input_find_device (GdkDisplay *display,
 }
 
 void
-_gdk_input_get_root_relative_geometry(Display *display, Window w, int *x_ret, int *y_ret,
-				      int *width_ret, int *height_ret)
+_gdk_input_get_root_relative_geometry (GdkWindow *window,
+				       int *x_ret, int *y_ret)
 {
-  Window root, parent, child;
-  Window *children;
-  guint nchildren;
+  Window child;
   gint x,y;
-  guint width, height;
-  guint border_widthc, depthc;
-   
-  XQueryTree (display, w, &root, &parent, &children, &nchildren);
-  if (children)
-    XFree(children);
-  
-  XGetGeometry (display, w, &root, &x, &y, &width, &height, &border_widthc, &depthc);
-
-  XTranslateCoordinates (display, w, root, 0, 0, &x, &y, &child);
- 
+
+  XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
+			 GDK_WINDOW_XWINDOW (window),
+			 GDK_WINDOW_XROOTWIN (window),
+			 0, 0, &x, &y, &child);
+
   if (x_ret)
     *x_ret = x;
   if (y_ret)
     *y_ret = y;
-  if (width_ret)
-    *width_ret = width;
-  if (height_ret)
-    *height_ret = height;
 }
 
 static GdkDevicePrivate *
 gdk_input_device_new (GdkDisplay  *display,
-		      XDeviceInfo *device, 
+		      XDeviceInfo *device,
 		      gint         include_core)
 {
   GdkDevicePrivate *gdkdev;
@@ -121,7 +110,7 @@ gdk_input_device_new (GdkDisplay  *display,
      for comparison purposes */
 
   tmp_name = g_ascii_strdown (gdkdev->info.name, -1);
-  
+
   if (!strcmp (tmp_name, "pointer"))
     gdkdev->info.source = GDK_SOURCE_MOUSE;
   else if (!strcmp (tmp_name, "wacom") ||
@@ -151,7 +140,7 @@ gdk_input_device_new (GdkDisplay  *display,
   gdkdev->button_state = 0;
 
   class = device->inputclassinfo;
-  for (i=0;i<device->num_classes;i++) 
+  for (i=0;i<device->num_classes;i++)
     {
       switch (class->class) {
       case ButtonClass:
@@ -160,7 +149,7 @@ gdk_input_device_new (GdkDisplay  *display,
 	{
 	  XKeyInfo *xki = (XKeyInfo *)class;
 	  /* Hack to catch XFree86 3.3.1 bug. Other devices better
-	   * not have exactly 25 keys... 
+	   * not have exactly 25 keys...
 	   */
 	  if ((xki->min_keycode == 8) && (xki->max_keycode == 32))
 	    {
@@ -190,7 +179,7 @@ gdk_input_device_new (GdkDisplay  *display,
 	  gdkdev->info.axes = g_new0 (GdkDeviceAxis, xvi->num_axes);
 	  for (j=0;j<xvi->num_axes;j++)
 	    {
-	      gdkdev->axes[j].resolution = 
+	      gdkdev->axes[j].resolution =
 		gdkdev->axes[j].xresolution = xvi->axes[j].resolution;
 	      gdkdev->axes[j].min_value =
 		gdkdev->axes[j].xmin_value = xvi->axes[j].min_value;
@@ -211,7 +200,7 @@ gdk_input_device_new (GdkDisplay  *display,
 	    gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_YTILT);
 	  if (j<xvi->num_axes)
 	    gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_WHEEL);
-		       
+
 	  break;
 	}
       }
@@ -247,20 +236,19 @@ gdk_input_device_new (GdkDisplay  *display,
  error:
 
   g_object_unref (gdkdev);
-  
+
   return NULL;
 }
 
 void
-_gdk_input_common_find_events(GdkWindow *window,
-			      GdkDevicePrivate *gdkdev,
-			      gint mask,
-			      XEventClass *classes,
-			      int *num_classes)
+_gdk_input_common_find_events (GdkDevicePrivate *gdkdev,
+			       gint mask,
+			       XEventClass *classes,
+			       int *num_classes)
 {
   gint i;
   XEventClass class;
-  
+
   i = 0;
   if (mask & GDK_BUTTON_PRESS_MASK)
     {
@@ -354,25 +342,42 @@ _gdk_input_common_find_events(GdkWindow *window,
 }
 
 void
-_gdk_input_common_select_events(GdkWindow *window,
-				GdkDevicePrivate *gdkdev)
+_gdk_input_select_events (GdkWindow *impl_window,
+			  GdkDevicePrivate *gdkdev)
 {
   XEventClass classes[GDK_MAX_DEVICE_CLASSES];
   gint num_classes;
+  guint event_mask;
+  GdkWindowObject *w;
+  GdkInputWindow *iw;
+  GList *l;
 
-  if (gdkdev->info.mode == GDK_MODE_DISABLED)
-    _gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes);
-  else
-    _gdk_input_common_find_events(window, gdkdev, 
-				  ((GdkWindowObject *)window)->extension_events,
-				  classes, &num_classes);
-  
-  XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
-			 GDK_WINDOW_XWINDOW (window),
+  event_mask = 0;
+  iw = ((GdkWindowObject *)impl_window)->input_window;
+
+  if (gdkdev->info.mode != GDK_MODE_DISABLED &&
+      iw != NULL)
+    {
+      for (l = iw->windows; l != NULL; l = l->next)
+	{
+	  w = l->data;
+	  if (gdkdev->info.has_cursor || (w->extension_events & GDK_ALL_DEVICES_MASK))
+	    event_mask |= w->extension_events;
+	}
+    }
+  event_mask &= ~GDK_ALL_DEVICES_MASK;
+
+  if (event_mask)
+    event_mask |= GDK_PROXIMITY_OUT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
+
+  _gdk_input_common_find_events (gdkdev, event_mask,
+				 classes, &num_classes);
+  XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (impl_window),
+			 GDK_WINDOW_XWINDOW (impl_window),
 			 classes, num_classes);
 }
 
-gint 
+gint
 _gdk_input_common_init (GdkDisplay *display,
 			gint        include_core)
 {
@@ -391,7 +396,7 @@ _gdk_input_common_init (GdkDisplay *display,
 					    event_base, 15 /* Number of events */);
 
       devices = XListInputDevices(display_x11->xdisplay, &num_devices);
-  
+
       for(loop=0; loop<num_devices; loop++)
 	{
 	  GdkDevicePrivate *gdkdev = gdk_input_device_new(display,
@@ -410,21 +415,23 @@ _gdk_input_common_init (GdkDisplay *display,
 
 static void
 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
-				 GdkInputWindow   *input_window,
+				 GdkWindow        *window,
 				 gint             *axis_data,
 				 gdouble          *axis_out,
 				 gdouble          *x_out,
 				 gdouble          *y_out)
 {
-  GdkWindowObject *window_private;
+  GdkWindowObject *priv, *impl_window;
+
   int i;
   int x_axis = 0;
   int y_axis = 0;
 
   double device_width, device_height;
   double x_offset, y_offset, x_scale, y_scale;
-  
-  window_private = (GdkWindowObject *) input_window->window;
+
+  priv = (GdkWindowObject *) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
 
   for (i=0; i<gdkdev->info.num_axes; i++)
     {
@@ -440,26 +447,24 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
 	  break;
 	}
     }
-  
-  device_width = gdkdev->axes[x_axis].max_value - 
-		   gdkdev->axes[x_axis].min_value;
-  device_height = gdkdev->axes[y_axis].max_value - 
-                    gdkdev->axes[y_axis].min_value;
 
-  if (gdkdev->info.mode == GDK_MODE_SCREEN) 
+  device_width = gdkdev->axes[x_axis].max_value - gdkdev->axes[x_axis].min_value;
+  device_height = gdkdev->axes[y_axis].max_value - gdkdev->axes[y_axis].min_value;
+
+  if (gdkdev->info.mode == GDK_MODE_SCREEN)
     {
-      x_scale = gdk_screen_get_width (gdk_drawable_get_screen (input_window->window)) / device_width;
-      y_scale = gdk_screen_get_height (gdk_drawable_get_screen (input_window->window)) / device_height;
+      x_scale = gdk_screen_get_width (gdk_drawable_get_screen (window)) / device_width;
+      y_scale = gdk_screen_get_height (gdk_drawable_get_screen (window)) / device_height;
 
-      x_offset = - input_window->root_x;
-      y_offset = - input_window->root_y;
+      x_offset = - impl_window->input_window->root_x;
+      y_offset = - impl_window->input_window->root_y;
     }
   else				/* GDK_MODE_WINDOW */
     {
       double x_resolution = gdkdev->axes[x_axis].resolution;
       double y_resolution = gdkdev->axes[y_axis].resolution;
       double device_aspect;
-      /* 
+      /*
        * Some drivers incorrectly report the resolution of the device
        * as zero (in partiular linuxwacom < 0.5.3 with usb tablets).
        * This causes the device_aspect to become NaN and totally
@@ -475,27 +480,24 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
 	  y_resolution = 1;
 	}
       device_aspect = (device_height*y_resolution) /
-        (device_width*x_resolution);
-      if (device_aspect * window_private->width >= window_private->height)
+	(device_width*x_resolution);
+      if (device_aspect * priv->width >= priv->height)
 	{
 	  /* device taller than window */
-	  x_scale = window_private->width / device_width;
-	  y_scale = (x_scale * x_resolution)
-	    / y_resolution;
+	  x_scale = priv->width / device_width;
+	  y_scale = (x_scale * x_resolution) / y_resolution;
 
 	  x_offset = 0;
-	  y_offset = -(device_height * y_scale - 
-		       window_private->height)/2;
+	  y_offset = -(device_height * y_scale -  priv->height)/2;
 	}
       else
 	{
 	  /* window taller than device */
-	  y_scale = window_private->height / device_height;
-	  x_scale = (y_scale * y_resolution)
-	    / x_resolution;
+	  y_scale = priv->height / device_height;
+	  x_scale = (y_scale * y_resolution) / x_resolution;
 
 	  y_offset = 0;
-	  x_offset = - (device_width * x_scale - window_private->width)/2;
+	  x_offset = - (device_width * x_scale - priv->width)/2;
 	}
     }
 
@@ -504,13 +506,13 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
       switch (gdkdev->info.axes[i].use)
 	{
 	case GDK_AXIS_X:
-	  axis_out[i] = x_offset + x_scale * (axis_data[x_axis] - 
+	  axis_out[i] = x_offset + x_scale * (axis_data[x_axis] -
 	    gdkdev->axes[x_axis].min_value);
 	  if (x_out)
 	    *x_out = axis_out[i];
 	  break;
 	case GDK_AXIS_Y:
-	  axis_out[i] = y_offset + y_scale * (axis_data[y_axis] - 
+	  axis_out[i] = y_offset + y_scale * (axis_data[y_axis] -
 	    gdkdev->axes[y_axis].min_value);
 	  if (y_out)
 	    *y_out = axis_out[i];
@@ -541,11 +543,18 @@ gdk_input_translate_state(guint state, guint device_state)
 gboolean
 _gdk_input_common_other_event (GdkEvent         *event,
 			       XEvent           *xevent,
-			       GdkInputWindow   *input_window,
+			       GdkWindow        *window,
 			       GdkDevicePrivate *gdkdev)
 {
+  GdkWindowObject *priv, *impl_window;
+  GdkInputWindow *input_window;
+
+  priv = (GdkWindowObject *) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  input_window = impl_window->input_window;
+
   if ((xevent->type == gdkdev->buttonpress_type) ||
-      (xevent->type == gdkdev->buttonrelease_type)) 
+      (xevent->type == gdkdev->buttonrelease_type))
     {
       XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent);
 
@@ -560,16 +569,16 @@ _gdk_input_common_other_event (GdkEvent         *event,
 	  gdkdev->button_state &= ~(1 << xdbe->button);
 	}
       event->button.device = &gdkdev->info;
-      event->button.window = input_window->window;
+      event->button.window = window;
       event->button.time = xdbe->time;
 
       event->button.axes = g_new (gdouble, gdkdev->info.num_axes);
-      gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data,
-				       event->button.axes, 
-				       &event->button.x,&event->button.y);
-      event->button.x_root = event->button.x + input_window->root_x;
-      event->button.y_root = event->button.y + input_window->root_y;
-      event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state);
+      gdk_input_translate_coordinates (gdkdev, window, xdbe->axis_data,
+				       event->button.axes,
+				       &event->button.x, &event->button.y);
+      event->button.x_root = event->button.x + priv->abs_x + input_window->root_x;
+      event->button.y_root = event->button.y + priv->abs_y + input_window->root_y;
+      event->button.state = gdk_input_translate_state (xdbe->state,xdbe->device_state);
       event->button.button = xdbe->button;
 
       if (event->button.type == GDK_BUTTON_PRESS)
@@ -588,8 +597,8 @@ _gdk_input_common_other_event (GdkEvent         *event,
        * a valid timestamp.
        */
       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
-        gdk_x11_window_set_user_time (gdk_window_get_toplevel (input_window->window),
-                                      gdk_event_get_time (event));
+	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+				      gdk_event_get_time (event));
       return TRUE;
   }
 
@@ -611,21 +620,21 @@ _gdk_input_common_other_event (GdkEvent         *event,
 	  g_warning ("Invalid device key code received");
 	  return FALSE;
 	}
-      
+
       event->key.keyval = gdkdev->info.keys[xdke->keycode - gdkdev->min_keycode].keyval;
 
-      if (event->key.keyval == 0) 
+      if (event->key.keyval == 0)
 	{
 	  GDK_NOTE (EVENTS,
 	    g_print ("\t\ttranslation - NONE\n"));
-	  
+
 	  return FALSE;
 	}
 
       event->key.type = (xdke->type == gdkdev->keypress_type) ?
 	GDK_KEY_PRESS : GDK_KEY_RELEASE;
 
-      event->key.window = input_window->window;
+      event->key.window = window;
       event->key.time = xdke->time;
 
       event->key.state = gdk_input_translate_state(xdke->state, xdke->device_state)
@@ -654,26 +663,26 @@ _gdk_input_common_other_event (GdkEvent         *event,
        * a valid timestamp.
        */
       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
-        gdk_x11_window_set_user_time (gdk_window_get_toplevel (input_window->window),
-                                      gdk_event_get_time (event));
+	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+				      gdk_event_get_time (event));
       return TRUE;
     }
 
-  if (xevent->type == gdkdev->motionnotify_type) 
+  if (xevent->type == gdkdev->motionnotify_type)
     {
       XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent);
 
       event->motion.device = &gdkdev->info;
-      
+
       event->motion.axes = g_new (gdouble, gdkdev->info.num_axes);
-      gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data,
+      gdk_input_translate_coordinates(gdkdev,window,xdme->axis_data,
 				      event->motion.axes,
 				      &event->motion.x,&event->motion.y);
-      event->motion.x_root = event->motion.x + input_window->root_x;
-      event->motion.y_root = event->motion.y + input_window->root_y;
+      event->motion.x_root = event->motion.x + priv->abs_x + input_window->root_x;
+      event->motion.y_root = event->motion.y + priv->abs_y + input_window->root_y;
 
       event->motion.type = GDK_MOTION_NOTIFY;
-      event->motion.window = input_window->window;
+      event->motion.window = window;
       event->motion.time = xdme->time;
       event->motion.state = gdk_input_translate_state(xdme->state,
 						      xdme->device_state);
@@ -686,14 +695,14 @@ _gdk_input_common_other_event (GdkEvent         *event,
 		 event->motion.x, event->motion.y,
 		 event->motion.state,
 		 (xdme->is_hint) ? "true" : "false"));
-      
-      
+
+
       /* Update the timestamp of the latest user interaction, if the event has
        * a valid timestamp.
        */
       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
-        gdk_x11_window_set_user_time (gdk_window_get_toplevel (input_window->window),
-                                      gdk_event_get_time (event));
+	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+				      gdk_event_get_time (event));
       return TRUE;
     }
 
@@ -704,16 +713,16 @@ _gdk_input_common_other_event (GdkEvent         *event,
 
       event->proximity.device = &gdkdev->info;
       event->proximity.type = (xevent->type == gdkdev->proximityin_type)?
-  	GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT;
-      event->proximity.window = input_window->window;
+	GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT;
+      event->proximity.window = window;
       event->proximity.time = xpne->time;
-      
+
       /* Update the timestamp of the latest user interaction, if the event has
        * a valid timestamp.
        */
       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
-        gdk_x11_window_set_user_time (gdk_window_get_toplevel (input_window->window),
-                                      gdk_event_get_time (event));
+	gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+				      gdk_event_get_time (event));
       return TRUE;
   }
 
@@ -730,18 +739,17 @@ _gdk_device_get_history (GdkDevice         *device,
 {
   GdkTimeCoord **coords;
   XDeviceTimeCoord *device_coords;
-  GdkInputWindow *input_window;
+  GdkWindow *impl_window;
   GdkDevicePrivate *gdkdev;
   gint mode_return;
   gint axis_count_return;
   gint i;
 
   gdkdev = (GdkDevicePrivate *)device;
-  input_window = _gdk_input_window_find (window);
 
-  g_return_val_if_fail (input_window != NULL, FALSE);
+  impl_window = _gdk_window_get_impl_window (window);
 
-  device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (window),
+  device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (impl_window),
 					  gdkdev->xdevice,
 					  start, stop,
 					  n_events, &mode_return,
@@ -752,13 +760,13 @@ _gdk_device_get_history (GdkDevice         *device,
       coords = _gdk_device_allocate_history (device, *n_events);
 
       for (i = 0; i < *n_events; i++)
-        {
-          coords[i]->time = device_coords[i].time;
+	{
+	  coords[i]->time = device_coords[i].time;
 
-          gdk_input_translate_coordinates (gdkdev, input_window,
-                                           device_coords[i].data,
-                                           coords[i]->axes, NULL, NULL);
-        }
+	  gdk_input_translate_coordinates (gdkdev, window,
+					   device_coords[i].data,
+					   coords[i]->axes, NULL, NULL);
+	}
 
       XFreeDeviceMotionEvents (device_coords);
 
@@ -770,7 +778,7 @@ _gdk_device_get_history (GdkDevice         *device,
     return FALSE;
 }
 
-void 
+void
 gdk_device_get_state (GdkDevice       *device,
 		      GdkWindow       *window,
 		      gdouble         *axes,
@@ -784,7 +792,7 @@ gdk_device_get_state (GdkDevice       *device,
   if (GDK_IS_CORE (device))
     {
       gint x_int, y_int;
-      
+
       gdk_window_get_pointer (window, &x_int, &y_int, mask);
 
       if (axes)
@@ -796,16 +804,13 @@ gdk_device_get_state (GdkDevice       *device,
   else
     {
       GdkDevicePrivate *gdkdev;
-      GdkInputWindow *input_window;
       XDeviceState *state;
       XInputClass *input_class;
-      
+
       if (mask)
 	gdk_window_get_pointer (window, NULL, NULL, mask);
-      
+
       gdkdev = (GdkDevicePrivate *)device;
-      input_window = _gdk_input_window_find (window);
-      g_return_if_fail (input_window != NULL);
 
       state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
 				 gdkdev->xdevice);
@@ -816,11 +821,11 @@ gdk_device_get_state (GdkDevice       *device,
 	    {
 	    case ValuatorClass:
 	      if (axes)
-		gdk_input_translate_coordinates (gdkdev, input_window,
+		gdk_input_translate_coordinates (gdkdev, window,
 						 ((XValuatorState *)input_class)->valuators,
 						 axes, NULL, NULL);
 	      break;
-	      
+
 	    case ButtonClass:
 	      if (mask)
 		{
diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c
index b51516b..10fd33d 100644
--- a/gdk/x11/gdkinput-xfree.c
+++ b/gdk/x11/gdkinput-xfree.c
@@ -26,18 +26,18 @@
  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
 /* forward declarations */
 
 static void gdk_input_check_proximity (GdkDisplay *display);
 
-void 
+void
 _gdk_input_init(GdkDisplay *display)
 {
   _gdk_init_input_core (display);
-  GDK_DISPLAY_X11 (display)->input_ignore_core = FALSE;
+  display->ignore_core_events = FALSE;
   _gdk_input_common_init (display, FALSE);
 }
 
@@ -47,7 +47,6 @@ gdk_device_set_mode (GdkDevice      *device,
 {
   GList *tmp_list;
   GdkDevicePrivate *gdkdev;
-  GdkInputMode old_mode;
   GdkInputWindow *input_window;
   GdkDisplayX11 *display_impl;
 
@@ -59,58 +58,35 @@ gdk_device_set_mode (GdkDevice      *device,
   if (device->mode == mode)
     return TRUE;
 
-  old_mode = device->mode;
   device->mode = mode;
 
-  display_impl = GDK_DISPLAY_X11 (gdkdev->display);
-
   if (mode == GDK_MODE_WINDOW)
-    {
-      device->has_cursor = FALSE;
-      for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
-	{
-	  input_window = (GdkInputWindow *)tmp_list->data;
-	  if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
-	    _gdk_input_enable_window (input_window->window, gdkdev);
-	  else
-	    if (old_mode != GDK_MODE_DISABLED)
-	      _gdk_input_disable_window (input_window->window, gdkdev);
-	}
-    }
+    device->has_cursor = FALSE;
   else if (mode == GDK_MODE_SCREEN)
+    device->has_cursor = TRUE;
+
+  display_impl = GDK_DISPLAY_X11 (gdkdev->display);
+  for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
     {
-      device->has_cursor = TRUE;
-      for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
-	_gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window,
-				  gdkdev);
-    }
-  else  /* mode == GDK_MODE_DISABLED */
-    {
-      for (tmp_list = display_impl->input_windows; tmp_list; tmp_list = tmp_list->next)
-	{
-	  input_window = (GdkInputWindow *)tmp_list->data;
-	  if (old_mode != GDK_MODE_WINDOW ||
-	      input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
-	    _gdk_input_disable_window (input_window->window, gdkdev);
-	}
+      input_window = (GdkInputWindow *)tmp_list->data;
+      _gdk_input_select_events (input_window->impl_window, gdkdev);
     }
 
   return TRUE;
-  
 }
 
 static void
 gdk_input_check_proximity (GdkDisplay *display)
 {
-  gint new_proximity = 0;
   GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
   GList *tmp_list = display_impl->input_devices;
+  gint new_proximity = 0;
 
-  while (tmp_list && !new_proximity) 
+  while (tmp_list && !new_proximity)
     {
       GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
 
-      if (gdkdev->info.mode != GDK_MODE_DISABLED 
+      if (gdkdev->info.mode != GDK_MODE_DISABLED
 	  && !GDK_IS_CORE (gdkdev)
 	  && gdkdev->xdevice)
 	{
@@ -118,7 +94,7 @@ gdk_input_check_proximity (GdkDisplay *display)
 						  gdkdev->xdevice);
 	  XInputClass *xic;
 	  int i;
-	  
+
 	  xic = state->data;
 	  for (i=0; i<state->num_classes; i++)
 	    {
@@ -135,117 +111,197 @@ gdk_input_check_proximity (GdkDisplay *display)
 	    }
 
 	  XFreeDeviceState (state);
- 	}
+	}
       tmp_list = tmp_list->next;
     }
 
-  display_impl->input_ignore_core = new_proximity;
+  display->ignore_core_events = new_proximity;
 }
 
 void
 _gdk_input_configure_event (XConfigureEvent *xevent,
 			    GdkWindow       *window)
 {
+  GdkWindowObject *priv = (GdkWindowObject *)window;
   GdkInputWindow *input_window;
   gint root_x, root_y;
 
-  input_window = _gdk_input_window_find(window);
-  g_return_if_fail (input_window != NULL);
-
-  _gdk_input_get_root_relative_geometry(GDK_WINDOW_XDISPLAY (window),
-					GDK_WINDOW_XWINDOW (window),
-					&root_x, &root_y, NULL, NULL);
-
-  input_window->root_x = root_x;
-  input_window->root_y = root_y;
+  input_window = priv->input_window;
+  if (input_window != NULL)
+    {
+      _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
+      input_window->root_x = root_x;
+      input_window->root_y = root_y;
+    }
 }
 
-void 
-_gdk_input_enter_event (XCrossingEvent *xevent, 
-			GdkWindow      *window)
+void
+_gdk_input_crossing_event (GdkWindow *window,
+			   gboolean enter)
 {
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+  GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
+  GdkWindowObject *priv = (GdkWindowObject *)window;
   GdkInputWindow *input_window;
   gint root_x, root_y;
 
-  input_window = _gdk_input_window_find (window);
-  g_return_if_fail (input_window != NULL);
+  if (enter)
+    {
+      gdk_input_check_proximity(display);
+
+      input_window = priv->input_window;
+      if (input_window != NULL)
+	{
+	  _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
+	  input_window->root_x = root_x;
+	  input_window->root_y = root_y;
+	}
+    }
+  else
+    display->ignore_core_events = FALSE;
+}
+
+static GdkEventType
+get_input_event_type (GdkDevicePrivate *gdkdev,
+		      XEvent *xevent,
+		      int *core_x, int *core_y)
+{
+  if (xevent->type == gdkdev->buttonpress_type)
+    {
+      XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_BUTTON_PRESS;
+    }
+
+  if (xevent->type == gdkdev->buttonrelease_type)
+    {
+      XDeviceButtonEvent *xie = (XDeviceButtonEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_BUTTON_RELEASE;
+    }
+
+  if (xevent->type == gdkdev->keypress_type)
+    {
+      XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_KEY_PRESS;
+    }
+
+  if (xevent->type == gdkdev->keyrelease_type)
+    {
+      XDeviceKeyEvent *xie = (XDeviceKeyEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_KEY_RELEASE;
+    }
+
+  if (xevent->type == gdkdev->motionnotify_type)
+    {
+      XDeviceMotionEvent *xie = (XDeviceMotionEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_MOTION_NOTIFY;
+    }
 
-  gdk_input_check_proximity(GDK_WINDOW_DISPLAY (window));
+  if (xevent->type == gdkdev->proximityin_type)
+    {
+      XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_PROXIMITY_IN;
+    }
 
-  _gdk_input_get_root_relative_geometry(GDK_WINDOW_XDISPLAY (window),
-					GDK_WINDOW_XWINDOW(window),
-					&root_x, &root_y, NULL, NULL);
+  if (xevent->type == gdkdev->proximityout_type)
+    {
+      XProximityNotifyEvent *xie = (XProximityNotifyEvent *)(xevent);
+      *core_x = xie->x;
+      *core_y = xie->y;
+      return GDK_PROXIMITY_OUT;
+    }
 
-  input_window->root_x = root_x;
-  input_window->root_y = root_y;
+  *core_x = 0;
+  *core_y = 0;
+  return GDK_NOTHING;
 }
 
-gboolean 
-_gdk_input_other_event (GdkEvent *event, 
-			XEvent *xevent, 
-			GdkWindow *window)
+
+gboolean
+_gdk_input_other_event (GdkEvent *event,
+			XEvent *xevent,
+			GdkWindow *event_window)
 {
-  GdkInputWindow *input_window;
-  
+  GdkWindow *window;
+  GdkWindowObject *priv;
+  GdkInputWindow *iw;
   GdkDevicePrivate *gdkdev;
   gint return_val;
-  GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
-
-  input_window = _gdk_input_window_find(window);
-  g_return_val_if_fail (input_window != NULL, FALSE);
+  GdkEventType event_type;
+  int x, y;
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (event_window);
+  GdkDisplayX11 *display_impl = GDK_DISPLAY_X11 (display);
 
   /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
      but it's potentially faster than scanning through the types of
      every device. If we were deceived, then it won't match any of
      the types for the device anyways */
-  gdkdev = _gdk_input_find_device (GDK_WINDOW_DISPLAY (window),
+  gdkdev = _gdk_input_find_device (display,
 				   ((XDeviceButtonEvent *)xevent)->deviceid);
   if (!gdkdev)
     return FALSE;			/* we don't handle it - not an XInput event */
 
-  /* FIXME: It would be nice if we could just get rid of the events 
-     entirely, instead of having to ignore them */
+  event_type = get_input_event_type (gdkdev, xevent, &x, &y);
+  if (event_type == GDK_NOTHING)
+    return FALSE;
+
+  window = _gdk_window_get_input_window_for_event (event_window,
+						   event_type,
+						   x, y,
+						   xevent->xany.serial);
+  /* If we're not getting any event window its likely because we're outside the
+     window and there is no grab. We should still report according to the
+     implicit grab though. */
+  iw = ((GdkWindowObject *)event_window)->input_window;
+  if (window == NULL)
+    window = iw->button_down_window;
+
+  priv = (GdkWindowObject *)window;
+  if (window == NULL)
+    return FALSE;
+
   if (gdkdev->info.mode == GDK_MODE_DISABLED ||
-      (gdkdev->info.mode == GDK_MODE_WINDOW 
-       && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR))
+      !(gdkdev->info.has_cursor || (priv->extension_events & GDK_ALL_DEVICES_MASK)))
     return FALSE;
-  
-  if (!display_impl->input_ignore_core)
-    gdk_input_check_proximity(GDK_WINDOW_DISPLAY (window));
 
-  return_val = _gdk_input_common_other_event (event, xevent, 
-					      input_window, gdkdev);
+  if (!display->ignore_core_events && priv->extension_events != 0)
+    gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
 
-  if (return_val && event->type == GDK_PROXIMITY_OUT &&
-      display_impl->input_ignore_core)
-    gdk_input_check_proximity(GDK_WINDOW_DISPLAY (window));
+  return_val = _gdk_input_common_other_event (event, xevent, window, gdkdev);
 
-  return return_val;
-}
+  if (return_val && event->type == GDK_BUTTON_PRESS)
+    iw->button_down_window = window;
+  if (return_val && event->type == GDK_BUTTON_RELEASE)
+    iw->button_down_window = NULL;
 
-gboolean
-_gdk_input_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
-{
-  /* FIXME: watchout, gdkdev might be core pointer, never opened */
-  _gdk_input_common_select_events (window, gdkdev);
-  return TRUE;
-}
+  if (return_val && event->type == GDK_PROXIMITY_OUT &&
+      display->ignore_core_events)
+    gdk_input_check_proximity (GDK_WINDOW_DISPLAY (window));
 
-gboolean
-_gdk_input_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev)
-{
-  _gdk_input_common_select_events (window, gdkdev);
-  return TRUE;
+  return return_val;
 }
 
-gint 
-_gdk_input_grab_pointer (GdkWindow *     window,
+gint
+_gdk_input_grab_pointer (GdkWindow      *window,
+			 GdkWindow      *native_window, /* This is the toplevel */
 			 gint            owner_events,
 			 GdkEventMask    event_mask,
 			 GdkWindow *     confine_to,
 			 guint32         time)
 {
-  GdkInputWindow *input_window, *new_window;
+  GdkInputWindow *input_window;
+  GdkWindowObject *priv, *impl_window;
   gboolean need_ungrab;
   GdkDevicePrivate *gdkdev;
   GList *tmp_list;
@@ -255,36 +311,36 @@ _gdk_input_grab_pointer (GdkWindow *     window,
   GdkDisplayX11 *display_impl  = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
 
   tmp_list = display_impl->input_windows;
-  new_window = NULL;
   need_ungrab = FALSE;
 
   while (tmp_list)
     {
       input_window = (GdkInputWindow *)tmp_list->data;
 
-      if (input_window->window == window)
-	new_window = input_window;
-      else if (input_window->grabbed)
+      if (input_window->grabbed)
 	{
 	  input_window->grabbed = FALSE;
 	  need_ungrab = TRUE;
+	  break;
 	}
-
       tmp_list = tmp_list->next;
     }
 
-  if (new_window)
+  priv = (GdkWindowObject *)window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  input_window = impl_window->input_window;
+  if (priv->extension_events)
     {
-      new_window->grabbed = TRUE;
-      
+      g_assert (input_window != NULL);
+      input_window->grabbed = TRUE;
+
       tmp_list = display_impl->input_devices;
       while (tmp_list)
 	{
 	  gdkdev = (GdkDevicePrivate *)tmp_list->data;
 	  if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
 	    {
-	      _gdk_input_common_find_events (window, gdkdev,
-					     event_mask,
+	      _gdk_input_common_find_events (gdkdev, event_mask,
 					     event_classes, &num_classes);
 #ifdef G_ENABLE_DEBUG
 	      if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
@@ -292,10 +348,10 @@ _gdk_input_grab_pointer (GdkWindow *     window,
 	      else
 #endif
 		result = XGrabDevice (display_impl->xdisplay, gdkdev->xdevice,
-				      GDK_WINDOW_XWINDOW (window),
+				      GDK_WINDOW_XWINDOW (native_window),
 				      owner_events, num_classes, event_classes,
 				      GrabModeAsync, GrabModeAsync, time);
-	      
+
 	      /* FIXME: if failure occurs on something other than the first
 		 device, things will be badly inconsistent */
 	      if (result != Success)
@@ -305,7 +361,7 @@ _gdk_input_grab_pointer (GdkWindow *     window,
 	}
     }
   else
-    { 
+    {
       tmp_list = display_impl->input_devices;
       while (tmp_list)
 	{
@@ -316,17 +372,16 @@ _gdk_input_grab_pointer (GdkWindow *     window,
 	      XUngrabDevice (display_impl->xdisplay, gdkdev->xdevice, time);
 	      gdkdev->button_state = 0;
 	    }
-	  
+
 	  tmp_list = tmp_list->next;
 	}
     }
 
   return Success;
-      
 }
 
-void 
-_gdk_input_ungrab_pointer (GdkDisplay *display, 
+void
+_gdk_input_ungrab_pointer (GdkDisplay *display,
 			   guint32 time)
 {
   GdkInputWindow *input_window = NULL; /* Quiet GCC */
diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c
index 95a301d..c33f09c 100644
--- a/gdk/x11/gdkinput.c
+++ b/gdk/x11/gdkinput.c
@@ -21,7 +21,7 @@
  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
 #include "config.h"
@@ -47,10 +47,10 @@ void
 _gdk_init_input_core (GdkDisplay *display)
 {
   GdkDevicePrivate *private;
-  
+
   display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
   private = (GdkDevicePrivate *)display->core_pointer;
-  
+
   display->core_pointer->name = "Core Pointer";
   display->core_pointer->source = GDK_SOURCE_MOUSE;
   display->core_pointer->mode = GDK_MODE_SCREEN;
@@ -87,12 +87,12 @@ gdk_device_get_type (void)
 	  0,              /* n_preallocs */
 	  (GInstanceInitFunc) NULL,
 	};
-      
+
       object_type = g_type_register_static (G_TYPE_OBJECT,
-                                            g_intern_static_string ("GdkDevice"),
-                                            &object_info, 0);
+					    g_intern_static_string ("GdkDevice"),
+					    &object_info, 0);
     }
-  
+
   return object_type;
 }
 
@@ -115,10 +115,10 @@ gdk_device_dispose (GObject *object)
     {
 #ifndef XINPUT_NONE
       if (gdkdev->xdevice)
-        {
-          XCloseDevice (GDK_DISPLAY_XDISPLAY (gdkdev->display), gdkdev->xdevice);
-          gdkdev->xdevice = NULL;
-        }
+	{
+	  XCloseDevice (GDK_DISPLAY_XDISPLAY (gdkdev->display), gdkdev->xdevice);
+	  gdkdev->xdevice = NULL;
+	}
       g_free (gdkdev->axes);
       gdkdev->axes = NULL;
 #endif /* !XINPUT_NONE */
@@ -140,7 +140,7 @@ gdk_device_dispose (GObject *object)
  *
  * Returns the list of available input devices for the default display.
  * The list is statically allocated and should not be freed.
- * 
+ *
  * Return value: a list of #GdkDevice
  **/
 GList *
@@ -155,16 +155,16 @@ gdk_devices_list (void)
  *
  * Returns the list of available input devices attached to @display.
  * The list is statically allocated and should not be freed.
- * 
+ *
  * Return value: a list of #GdkDevice
  *
  * Since: 2.2
  **/
-GList * 
+GList *
 gdk_display_list_devices (GdkDisplay *display)
 {
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-  
+
   return GDK_DISPLAY_X11 (display)->input_devices;
 }
 
@@ -219,6 +219,22 @@ gdk_device_set_axis_use (GdkDevice   *device,
     }
 }
 
+static gboolean
+impl_coord_in_window (GdkWindow *window,
+		      int impl_x,
+		      int impl_y)
+{
+  GdkWindowObject *priv = (GdkWindowObject *)window;
+
+  if (impl_x < priv->abs_x ||
+      impl_x > priv->abs_x + priv->width)
+    return FALSE;
+  if (impl_y < priv->abs_y ||
+      impl_y > priv->abs_y + priv->height)
+    return FALSE;
+  return TRUE;
+}
+
 /**
  * gdk_device_get_history:
  * @device: a #GdkDevice
@@ -227,14 +243,14 @@ gdk_device_set_axis_use (GdkDevice   *device,
  * @stop: ending timestamp for the range of events to return
  * @events: location to store a newly-allocated array of #GdkTimeCoord, or %NULL
  * @n_events: location to store the length of @events, or %NULL
- * 
+ *
  * Obtains the motion history for a device; given a starting and
  * ending timestamp, return all events in the motion history for
  * the device in the given range of time. Some windowing systems
  * do not support motion history, in which case, %FALSE will
  * be returned. (This is not distinguishable from the case where
  * motion history is supported and no events were found.)
- * 
+ *
  * Return value: %TRUE if the windowing system supports motion history and
  *  at least one event was found.
  **/
@@ -247,29 +263,38 @@ gdk_device_get_history  (GdkDevice         *device,
 			 gint              *n_events)
 {
   GdkTimeCoord **coords = NULL;
+  GdkWindow *impl_window;
   gboolean result = FALSE;
   int tmp_n_events = 0;
-  int i;
+  int i, j;
 
   g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), FALSE);
 
+  impl_window = _gdk_window_get_impl_window (window);
+
   if (GDK_WINDOW_DESTROYED (window))
     /* Nothing */ ;
   else if (GDK_IS_CORE (device))
     {
       XTimeCoord *xcoords;
-      
+
       xcoords = XGetMotionEvents (GDK_DRAWABLE_XDISPLAY (window),
-				  GDK_DRAWABLE_XID (window),
+				  GDK_DRAWABLE_XID (impl_window),
 				  start, stop, &tmp_n_events);
       if (xcoords)
 	{
+	  GdkWindowObject *priv = (GdkWindowObject *)window;
 	  coords = _gdk_device_allocate_history (device, tmp_n_events);
+	  j = 0;
 	  for (i=0; i<tmp_n_events; i++)
 	    {
-	      coords[i]->time = xcoords[i].time;
-	      coords[i]->axes[0] = xcoords[i].x;
-	      coords[i]->axes[1] = xcoords[i].y;
+	      if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
+		{
+		  coords[j]->time = xcoords[i].time;
+		  coords[j]->axes[0] = xcoords[i].x - priv->abs_x;
+		  coords[j]->axes[1] = xcoords[i].y - priv->abs_y;
+		  j++;
+		}
 	    }
 
 	  XFree (xcoords);
@@ -292,7 +317,7 @@ gdk_device_get_history  (GdkDevice         *device,
   return result;
 }
 
-GdkTimeCoord ** 
+GdkTimeCoord **
 _gdk_device_allocate_history (GdkDevice *device,
 			      gint       n_events)
 {
@@ -306,41 +331,48 @@ _gdk_device_allocate_history (GdkDevice *device,
   return result;
 }
 
-void 
+void
 gdk_device_free_history (GdkTimeCoord **events,
 			 gint           n_events)
 {
   gint i;
-  
+
   for (i=0; i<n_events; i++)
     g_free (events[i]);
 
   g_free (events);
 }
 
-GdkInputWindow *
-_gdk_input_window_find(GdkWindow *window)
+static void
+unset_extension_events (GdkWindow *window)
 {
-  GList *tmp_list;
-  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+  GdkWindowObject *window_private;
+  GdkWindowObject *impl_window;
+  GdkDisplayX11 *display_x11;
+  GdkInputWindow *iw;
 
-  /* Ensure we have a native window, or the input stuff won't work.
-     Its possible we could emulate this also, but at least this should make
-     it work. */
-  gdk_window_set_has_native (window, TRUE);
+  window_private = (GdkWindowObject*) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  iw = impl_window->input_window;
 
-  for (tmp_list=display_x11->input_windows; tmp_list; tmp_list=tmp_list->next)
-    if (((GdkInputWindow *)(tmp_list->data))->window == window)
-      return (GdkInputWindow *)(tmp_list->data);
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
 
-  return NULL;      /* Not found */
-}
+  if (window_private->extension_events != 0)
+    {
+      g_assert (iw != NULL);
+      g_assert (g_list_find (iw->windows, window) != NULL);
+
+      iw->windows = g_list_remove (iw->windows, window);
+      if (iw->windows == NULL)
+	{
+	  impl_window->input_window = NULL;
+	  display_x11->input_windows = g_list_remove (display_x11->input_windows, iw);
+	  g_free (iw);
+	}
+    }
 
-/* FIXME: this routine currently needs to be called between creation
-   and the corresponding configure event (because it doesn't get the
-   root_relative_geometry).  This should work with
-   gtk_window_set_extension_events, but will likely fail in other
-   cases */
+  window_private->extension_events = 0;
+}
 
 void
 gdk_input_set_extension_events (GdkWindow *window, gint mask,
@@ -348,6 +380,7 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
 {
   GdkWindowObject *window_private;
   GList *tmp_list;
+  GdkWindowObject *impl_window;
   GdkInputWindow *iw;
   GdkDisplayX11 *display_x11;
 
@@ -359,52 +392,44 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+
+  if (mode == GDK_EXTENSION_EVENTS_ALL && mask != 0)
+    mask |= GDK_ALL_DEVICES_MASK;
+
   if (mode == GDK_EXTENSION_EVENTS_NONE)
     mask = 0;
 
-  iw = _gdk_input_window_find (window);
+  iw = impl_window->input_window;
 
   if (mask != 0)
     {
       if (!iw)
-        {
-          iw = g_new(GdkInputWindow,1);
-
-          iw->window = window;
-          iw->mode = mode;
+	{
+	  iw = g_new0 (GdkInputWindow,1);
 
-          iw->obscuring = NULL;
-          iw->num_obscuring = 0;
-          iw->grabbed = FALSE;
+	  iw->impl_window = (GdkWindow *)impl_window;
 
-          display_x11->input_windows = g_list_append(display_x11->input_windows,iw);
-        }
+	  iw->windows = NULL;
+	  iw->grabbed = FALSE;
 
-      window_private->extension_events = mask;
+	  display_x11->input_windows = g_list_append (display_x11->input_windows, iw);
 
 #ifndef XINPUT_NONE
-      /* Add enter window events to the event mask */
-      /* this is not needed for XINPUT_NONE */
-      gdk_window_set_events (window,
-			     gdk_window_get_events (window) | 
-			     GDK_ENTER_NOTIFY_MASK);
-
-      /* we might not receive ConfigureNotify so get the root_relative_geometry
-       * now, just in case */
-      _gdk_input_get_root_relative_geometry (GDK_WINDOW_XDISPLAY (window),
-                                             GDK_WINDOW_XWINDOW (window),
-                                             &iw->root_x, &iw->root_y, NULL, NULL);
+	  /* we might not receive ConfigureNotify so get the root_relative_geometry
+	   * now, just in case */
+	  _gdk_input_get_root_relative_geometry (window, &iw->root_x, &iw->root_y);
 #endif /* !XINPUT_NONE */
+	  impl_window->input_window = iw;
+	}
+
+      if (window_private->extension_events == 0)
+	iw->windows = g_list_append (iw->windows, window);
+      window_private->extension_events = mask;
     }
   else
     {
-      if (iw)
-	{
-	  display_x11->input_windows = g_list_remove(display_x11->input_windows,iw);
-	  g_free(iw);
-	}
-
-      window_private->extension_events = 0;
+      unset_extension_events (window);
     }
 
   for (tmp_list = display_x11->input_devices; tmp_list; tmp_list = tmp_list->next)
@@ -412,57 +437,14 @@ gdk_input_set_extension_events (GdkWindow *window, gint mask,
       GdkDevicePrivate *gdkdev = tmp_list->data;
 
       if (!GDK_IS_CORE (gdkdev))
-	{
-	  if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
-	      && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
-	    _gdk_input_enable_window (window,gdkdev);
-	  else
-	    _gdk_input_disable_window (window,gdkdev);
-	}
+	_gdk_input_select_events ((GdkWindow *)impl_window, gdkdev);
     }
 }
 
 void
 _gdk_input_window_destroy (GdkWindow *window)
 {
-  GdkInputWindow *input_window;
-  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
-
-  input_window = _gdk_input_window_find (window);
-  g_return_if_fail (input_window != NULL);
-
-  display_x11->input_windows = g_list_remove (display_x11->input_windows, input_window);
-  g_free(input_window);
-}
-
-void
-_gdk_input_exit (void)
-{
-  GList *tmp_list;
-  GSList *display_list;
-  GdkDevicePrivate *gdkdev;
-
-  for (display_list = _gdk_displays ; display_list ; display_list = display_list->next)
-    {
-      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display_list->data);
-      
-      for (tmp_list = display_x11->input_devices; tmp_list; tmp_list = tmp_list->next)
-	{
-	  gdkdev = (GdkDevicePrivate *)(tmp_list->data);
-	  if (!GDK_IS_CORE (gdkdev))
-	    {
-	      gdk_device_set_mode (&gdkdev->info, GDK_MODE_DISABLED);
-	      g_object_unref(gdkdev);
-	    }
-	}
-      
-      g_list_free(display_x11->input_devices);
-      
-      for (tmp_list = display_x11->input_windows; tmp_list; tmp_list = tmp_list->next)
-	g_free(tmp_list->data);
-      
-      g_list_free(display_x11->input_windows);
-    }
+  unset_extension_events (window);
 }
 
 /**
@@ -471,10 +453,10 @@ _gdk_input_exit (void)
  * @axes: pointer to an array of axes
  * @use: the use to look for
  * @value: location to store the found value.
- * 
+ *
  * Interprets an array of double as axis values for a given device,
  * and locates the value in the array for a given axis use.
- * 
+ *
  * Return value: %TRUE if the given axis use was found, otherwise %FALSE
  **/
 gboolean
@@ -484,12 +466,12 @@ gdk_device_get_axis (GdkDevice  *device,
 		     gdouble    *value)
 {
   gint i;
-  
+
   g_return_val_if_fail (device != NULL, FALSE);
 
   if (axes == NULL)
     return FALSE;
-  
+
   for (i=0; i<device->num_axes; i++)
     if (device->axes[i].use == use)
       {
@@ -497,7 +479,7 @@ gdk_device_get_axis (GdkDevice  *device,
 	  *value = axes[i];
 	return TRUE;
       }
-  
+
   return FALSE;
 }
 
diff --git a/gdk/x11/gdkinputprivate.h b/gdk/x11/gdkinputprivate.h
index 5cbd809..217e28c 100644
--- a/gdk/x11/gdkinputprivate.h
+++ b/gdk/x11/gdkinputprivate.h
@@ -41,7 +41,6 @@
 
 typedef struct _GdkAxisInfo    GdkAxisInfo;
 typedef struct _GdkDevicePrivate GdkDevicePrivate;
-typedef struct _GdkInputWindow GdkInputWindow;
 
 /* information about a device axis */
 struct _GdkAxisInfo
@@ -102,28 +101,25 @@ struct _GdkDeviceClass
   GObjectClass parent_class;
 };
 
+/* Addition used for extension_events mask */
+#define GDK_ALL_DEVICES_MASK (1<<30)
+
 struct _GdkInputWindow
 {
-  /* gdk window */
-  GdkWindow *window;
+  GList *windows; /* GdkWindow:s with extension_events set */
 
-  /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */
-  GdkExtensionMode mode;
+  /* gdk window */
+  GdkWindow *impl_window; /* an impl window */
+  GdkWindow *button_down_window;
 
   /* position relative to root window */
   gint root_x;
   gint root_y;
 
-  /* rectangles relative to window of windows obscuring this one */
-  GdkRectangle *obscuring;
-  gint num_obscuring;
-
   /* Is there a pointer grab for this window ? */
   gint grabbed;
 };
 
-
-
 /* Global data */
 
 #define GDK_IS_CORE(d) (((GdkDevice *)(d)) == ((GdkDevicePrivate *)(d))->display->core_pointer)
@@ -139,18 +135,15 @@ void            _gdk_init_input_core         (GdkDisplay *display);
 /* The following functions are provided by each implementation
  * (xfree, gxi, and none)
  */
-gint             _gdk_input_enable_window     (GdkWindow        *window,
-					      GdkDevicePrivate *gdkdev);
-gint             _gdk_input_disable_window    (GdkWindow        *window,
-					      GdkDevicePrivate *gdkdev);
 void             _gdk_input_configure_event  (XConfigureEvent  *xevent,
 					      GdkWindow        *window);
-void             _gdk_input_enter_event      (XCrossingEvent   *xevent,
-					      GdkWindow        *window);
+void             _gdk_input_crossing_event   (GdkWindow        *window,
+					      gboolean          enter);
 gboolean         _gdk_input_other_event      (GdkEvent         *event,
 					      XEvent           *xevent,
 					      GdkWindow        *window);
 gint             _gdk_input_grab_pointer     (GdkWindow        *window,
+					      GdkWindow        *native_window,
 					      gint              owner_events,
 					      GdkEventMask      event_mask,
 					      GdkWindow        *confine_to,
@@ -172,22 +165,18 @@ gint               _gdk_input_common_init               (GdkDisplay	  *display,
 							 gint              include_core);
 GdkDevicePrivate * _gdk_input_find_device               (GdkDisplay	  *display,
 							 guint32           id);
-void               _gdk_input_get_root_relative_geometry(Display          *display,
-							 Window            w,
+void               _gdk_input_get_root_relative_geometry(GdkWindow        *window,
 							 int              *x_ret,
-							 int              *y_ret,
-							 int              *width_ret,
-							 int              *height_ret);
-void               _gdk_input_common_find_events        (GdkWindow        *window,
-							 GdkDevicePrivate *gdkdev,
+							 int              *y_ret);
+void               _gdk_input_common_find_events        (GdkDevicePrivate *gdkdev,
 							 gint              mask,
 							 XEventClass      *classes,
 							 int              *num_classes);
-void               _gdk_input_common_select_events      (GdkWindow        *window,
+void               _gdk_input_select_events             (GdkWindow        *impl_window,
 							 GdkDevicePrivate *gdkdev);
 gint               _gdk_input_common_other_event        (GdkEvent         *event,
 							 XEvent           *xevent,
-							 GdkInputWindow   *input_window,
+							 GdkWindow        *window,
 							 GdkDevicePrivate *gdkdev);
 
 #endif /* !XINPUT_NONE */
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index 41639c4..08c7cff 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -251,7 +251,8 @@ gdk_pointer_grab (GdkWindow *	  window,
    */
   xevent_mask &= ~PointerMotionHintMask;
   
-  return_val = _gdk_input_grab_pointer (native,
+  return_val = _gdk_input_grab_pointer (window,
+					native,
 					owner_events,
 					event_mask,
 					confine_to,
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index e29dc7b..4d38fcb 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -1036,9 +1036,6 @@ _gdk_x11_window_destroy (GdkWindow *window,
 
   _gdk_selection_window_destroyed (window);
   
-  if (private->extension_events != 0)
-    _gdk_input_window_destroy (window);
-
   toplevel = _gdk_x11_window_get_toplevel (window);
   if (toplevel)
     gdk_toplevel_x11_free_contents (GDK_WINDOW_DISPLAY (window), toplevel);
@@ -5585,6 +5582,8 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
   iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
   iface->queue_translation = _gdk_x11_window_queue_translation;
   iface->destroy = _gdk_x11_window_destroy;
+  iface->input_window_destroy = _gdk_input_window_destroy;
+  iface->input_window_crossing = _gdk_input_crossing_event;
 }
 
 #define __GDK_WINDOW_X11_C__



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