[gtk+/gtk-2-24-quartz] win32: Make WINTAB support work



commit be1effbed8079dedee6e582c4f6c52b6a3d781f8
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Oct 31 08:15:34 2011 +0100

    win32: Make WINTAB support work
    
    Lots of rework to make input events work in the csw world

 gdk/gdkinternals.h           |    1 +
 gdk/gdkwindow.c              |    6 +
 gdk/win32/gdkevents-win32.c  |   56 +---
 gdk/win32/gdkinput-win32.c   |  582 ++++++++++++++++++-----------------------
 gdk/win32/gdkinput-win32.h   |   25 +--
 gdk/win32/gdkinput.c         |  231 +++++++++---------
 gdk/win32/gdkprivate-win32.h |    3 +-
 gdk/win32/gdkwindow-win32.c  |    4 +-
 gdk/win32/gdkwindow-win32.h  |    2 +-
 gdk/x11/gdkinput-xfree.c     |    2 +
 10 files changed, 409 insertions(+), 503 deletions(-)
---
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index e861a4e..3234f2e 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -672,6 +672,7 @@ 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,
+						   GdkModifierType mask,
 						   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 bf56a4a..101e5c1 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -11100,6 +11100,7 @@ static GdkWindow *
 get_extension_event_window (GdkDisplay                 *display,
 			    GdkWindow                  *pointer_window,
 			    GdkEventType                type,
+			    GdkModifierType             mask,
 			    gulong                      serial)
 {
   guint evmask;
@@ -11112,6 +11113,7 @@ get_extension_event_window (GdkDisplay                 *display,
   if (grab != NULL && !grab->owner_events)
     {
       evmask = grab->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
 
       grab_window = grab->window;
 
@@ -11125,6 +11127,7 @@ get_extension_event_window (GdkDisplay                 *display,
   while (w != NULL)
     {
       evmask = w->extension_events;
+      evmask = update_evmask_for_button_motion (evmask, mask);
 
       if (evmask & type_masks[type])
 	return (GdkWindow *)w;
@@ -11136,6 +11139,7 @@ get_extension_event_window (GdkDisplay                 *display,
       grab->owner_events)
     {
       evmask = grab->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
 
       if (evmask & type_masks[type])
 	return grab->window;
@@ -11150,6 +11154,7 @@ get_extension_event_window (GdkDisplay                 *display,
 GdkWindow *
 _gdk_window_get_input_window_for_event (GdkWindow *native_window,
 					GdkEventType event_type,
+					GdkModifierType mask,
 					int x, int y,
 					gulong serial)
 {
@@ -11171,6 +11176,7 @@ _gdk_window_get_input_window_for_event (GdkWindow *native_window,
   event_win = get_extension_event_window (display,
 					  pointer_window,
 					  event_type,
+					  mask,
 					  serial);
 
   return event_win;
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index b3dd781..854758d 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -515,6 +515,9 @@ gdk_display_pointer_ungrab (GdkDisplay *display,
       info->serial_end = 0;
       ReleaseCapture ();
     }
+
+  _gdk_input_ungrab_pointer (time);
+
   /* TODO_CSW: cursor, confines, etc */
 
   _gdk_display_pointer_grab_update (display, 0);
@@ -1242,10 +1245,11 @@ send_crossing_event (GdkDisplay                 *display,
   event->crossing.state = mask;
 
   _gdk_win32_append_event (event);
-
-  if (type == GDK_ENTER_NOTIFY &&
-      ((GdkWindowObject *) window)->extension_events != 0)
-    _gdk_input_enter_event ((GdkWindow *)window);
+  
+  /*
+  if (((GdkWindowObject *) window)->extension_events != 0)
+    _gdk_input_crossing_event ((GdkWindow *)window, type == GDK_ENTER_NOTIFY);
+  */
 }
 
 static GdkWindowObject *
@@ -1526,8 +1530,7 @@ propagate (GdkWindow  **window,
 	   gboolean     grab_owner_events,
 	   gint	        grab_mask,
 	   gboolean   (*doesnt_want_it) (gint mask,
-					 MSG *msg),
-	   gboolean    	check_extended)
+					 MSG *msg))
 {
   if (grab_window != NULL && !grab_owner_events)
     {
@@ -1536,13 +1539,6 @@ propagate (GdkWindow  **window,
       /* See if the event should be ignored because an extended input
        * device is used
        */
-      if (check_extended &&
-	  ((GdkWindowObject *) grab_window)->extension_events != 0 &&
-	  _gdk_input_ignore_core)
-	{
-	  GDK_NOTE (EVENTS, g_print (" (ignored for grabber)"));
-	  return FALSE;
-	}
       if ((*doesnt_want_it) (grab_mask, msg))
 	{
 	  GDK_NOTE (EVENTS, g_print (" (grabber doesn't want it)"));
@@ -1561,13 +1557,6 @@ propagate (GdkWindow  **window,
    */
   while (TRUE)
     {
-      if (check_extended &&
-	  ((GdkWindowObject *) *window)->extension_events != 0 &&
-	  _gdk_input_ignore_core)
-	{
-	  GDK_NOTE (EVENTS, g_print (" (ignored)"));
-	  return FALSE;
-	}
       if ((*doesnt_want_it) (((GdkWindowObject *) *window)->event_mask, msg))
 	{
 	  /* Owner doesn't want it, propagate to parent. */
@@ -1579,13 +1568,6 @@ propagate (GdkWindow  **window,
 		{
 		  /* Event source is grabbed with owner_events TRUE */
 
-		  if (check_extended &&
-		      ((GdkWindowObject *) grab_window)->extension_events != 0 &&
-		      _gdk_input_ignore_core)
-		    {
-		      GDK_NOTE (EVENTS, g_print (" (ignored for grabber)"));
-		      return FALSE;
-		    }
 		  if ((*doesnt_want_it) (grab_mask, msg))
 		    {
 		      /* Grabber doesn't want it either */
@@ -2267,7 +2249,7 @@ gdk_event_translate (MSG  *msg,
 		      _gdk_display->keyboard_grab.window,
 		      _gdk_display->keyboard_grab.owner_events,
 		      GDK_ALL_EVENTS_MASK,
-		      doesnt_want_key, FALSE))
+		      doesnt_want_key))
 	break;
 
       if (GDK_WINDOW_DESTROYED (window))
@@ -2375,7 +2357,7 @@ gdk_event_translate (MSG  *msg,
 		      _gdk_display->keyboard_grab.window,
 		      _gdk_display->keyboard_grab.owner_events,
 		      GDK_ALL_EVENTS_MASK,
-		      doesnt_want_char, FALSE))
+		      doesnt_want_char))
 	break;
 
       if (GDK_WINDOW_DESTROYED (window))
@@ -2439,7 +2421,7 @@ gdk_event_translate (MSG  *msg,
 			 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
 
       assign_object (&window, find_window_for_mouse_event (window, msg));
-      /* TODO_CSW?: there used to some synthesize and propagate */
+
       if (GDK_WINDOW_DESTROYED (window))
 	break;
 
@@ -2479,15 +2461,6 @@ gdk_event_translate (MSG  *msg,
 			 GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam)));
 
       assign_object (&window, find_window_for_mouse_event (window, msg));
-#if 0
-      if (((GdkWindowObject *) window)->extension_events != 0 &&
-	  _gdk_input_ignore_core)
-	{
-	  GDK_NOTE (EVENTS, g_print (" (ignored)"));
-	  break;
-	}
-#endif
-
       grab = _gdk_display_get_last_pointer_grab (_gdk_display);
       if (grab != NULL && grab->implicit)
 	{
@@ -2987,7 +2960,7 @@ gdk_event_translate (MSG  *msg,
 	      !GDK_WINDOW_DESTROYED (window))
 	    _gdk_win32_emit_configure_event (window);
 
-	  if (((GdkWindowObject *) window)->extension_events != 0)
+	  if (((GdkWindowObject *) window)->input_window != NULL)
 	    _gdk_input_configure_event (window);
 	}
 
@@ -3483,8 +3456,7 @@ gdk_event_translate (MSG  *msg,
     wintab:
 
       event = gdk_event_new (GDK_NOTHING);
-      event->any.window = window;
-      g_object_ref (window);
+      event->any.window = NULL;
 
       if (_gdk_input_other_event (event, msg, window))
 	_gdk_win32_append_event (event);
diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c
index 19fb928..53622c7 100644
--- a/gdk/win32/gdkinput-win32.c
+++ b/gdk/win32/gdkinput-win32.c
@@ -58,16 +58,14 @@ static GList     *wintab_contexts = NULL;
 
 static GdkWindow *wintab_window = NULL;
 
-static GdkWindow *x_grab_window = NULL; /* Window that currently holds
-					 * the extended inputs grab
-					 */
-static GdkEventMask x_grab_mask;
-static gboolean x_grab_owner_events;
+static GdkDevicePrivate *_gdk_device_in_proximity;
 
 typedef UINT (WINAPI *t_WTInfoA) (UINT a, UINT b, LPVOID c);
 typedef UINT (WINAPI *t_WTInfoW) (UINT a, UINT b, LPVOID c);
 typedef BOOL (WINAPI *t_WTEnable) (HCTX a, BOOL b);
 typedef HCTX (WINAPI *t_WTOpenA) (HWND a, LPLOGCONTEXTA b, BOOL c);
+typedef BOOL (WINAPI *t_WTGetA) (HCTX a, LPLOGCONTEXTA b);
+typedef BOOL (WINAPI *t_WTSetA) (HCTX a, LPLOGCONTEXTA b);
 typedef BOOL (WINAPI *t_WTOverlap) (HCTX a, BOOL b);
 typedef BOOL (WINAPI *t_WTPacket) (HCTX a, UINT b, LPVOID c);
 typedef int (WINAPI *t_WTQueueSizeSet) (HCTX a, int b);
@@ -76,6 +74,8 @@ static t_WTInfoA p_WTInfoA;
 static t_WTInfoW p_WTInfoW;
 static t_WTEnable p_WTEnable;
 static t_WTOpenA p_WTOpenA;
+static t_WTGetA p_WTGetA;
+static t_WTSetA p_WTSetA;
 static t_WTOverlap p_WTOverlap;
 static t_WTPacket p_WTPacket;
 static t_WTQueueSizeSet p_WTQueueSizeSet;
@@ -384,6 +384,10 @@ _gdk_input_wintab_init_check (void)
     return;
   if ((p_WTOpenA = (t_WTOpenA) GetProcAddress (wintab32, "WTOpenA")) == NULL)
     return;
+  if ((p_WTGetA = (t_WTGetA) GetProcAddress (wintab32, "WTGetA")) == NULL)
+    return;
+  if ((p_WTSetA = (t_WTSetA) GetProcAddress (wintab32, "WTSetA")) == NULL)
+    return;
   if ((p_WTOverlap = (t_WTOverlap) GetProcAddress (wintab32, "WTOverlap")) == NULL)
     return;
   if ((p_WTPacket = (t_WTPacket) GetProcAddress (wintab32, "WTPacket")) == NULL)
@@ -461,7 +465,7 @@ _gdk_input_wintab_init_check (void)
 #if DEBUG_WINTAB
       GDK_NOTE (INPUT, (g_print("Default context:\n"), print_lc(&lc)));
 #endif
-      lc.lcOptions |= CXO_MESSAGES;
+      lc.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES;
       lc.lcStatus = 0;
       lc.lcMsgBase = WT_DEFBASE;
       lc.lcPktRate = 0;
@@ -471,8 +475,8 @@ _gdk_input_wintab_init_check (void)
       lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
       lc.lcOutOrgX = axis_x.axMin;
       lc.lcOutOrgY = axis_y.axMin;
-      lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
-      lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+      lc.lcOutExtX = axis_x.axMax - axis_x.axMin + 1;
+      lc.lcOutExtY = axis_y.axMax - axis_y.axMin + 1;
       lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
 #if DEBUG_WINTAB
       GDK_NOTE (INPUT, (g_print("context for device %d:\n", devix),
@@ -488,9 +492,7 @@ _gdk_input_wintab_init_check (void)
 				devix, *hctx));
       
       wintab_contexts = g_list_append (wintab_contexts, hctx);
-#if 0
-      (*p_WTEnable) (*hctx, TRUE);
-#endif
+
       (*p_WTOverlap) (*hctx, TRUE);
 
 #if DEBUG_WINTAB
@@ -502,7 +504,7 @@ _gdk_input_wintab_init_check (void)
        * with a smaller queue size.
        */
       GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
-      for (i = 32; i >= 1; i >>= 1)
+      for (i = 128; i >= 1; i >>= 1)
 	{
 	  if ((*p_WTQueueSizeSet) (*hctx, i))
 	    {
@@ -663,41 +665,44 @@ decode_tilt (gint   *axis_data,
 
 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 *priv, *impl_window;
   GdkWindowImplWin32 *root_impl;
-  GdkWindowObject *window_object;
 
   int i;
   int x_axis = 0;
   int y_axis = 0;
 
-  double device_width, device_height;
+  double device_width, device_height, x_min, y_min;
   double x_offset, y_offset, x_scale, y_scale;
 
-  window_object = GDK_WINDOW_OBJECT (input_window->window);
+  priv = (GdkWindowObject *) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
 
   for (i=0; i<gdkdev->info.num_axes; i++)
     {
       switch (gdkdev->info.axes[i].use)
-		{
-		case GDK_AXIS_X:
-		  x_axis = i;
-		  break;
-		case GDK_AXIS_Y:
-		  y_axis = i;
-		  break;
-		default:
-		  break;
-		}
+	{
+	case GDK_AXIS_X:
+	  x_axis = i;
+	  break;
+	case GDK_AXIS_Y:
+	  y_axis = i;
+	  break;
+	default:
+	  break;
+	}
     }
   
   device_width = gdkdev->axes[x_axis].max_value - gdkdev->axes[x_axis].min_value;
+  x_min = gdkdev->axes[x_axis].min_value;
   device_height = gdkdev->axes[y_axis].max_value - gdkdev->axes[y_axis].min_value;
+  y_min = gdkdev->axes[y_axis].min_value;
 
   if (gdkdev->info.mode == GDK_MODE_SCREEN) 
     {
@@ -705,56 +710,56 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
       x_scale = GDK_WINDOW_OBJECT (_gdk_root)->width / device_width;
       y_scale = GDK_WINDOW_OBJECT (_gdk_root)->height / device_height;
 
-      x_offset = - input_window->root_x;
-      y_offset = - input_window->root_y;
+      x_offset = - impl_window->input_window->root_x - priv->abs_x;
+      y_offset = - impl_window->input_window->root_y - priv->abs_y;
     }
   else				/* GDK_MODE_WINDOW */
     {
-      double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
-	(device_width*gdkdev->axes[x_axis].resolution);
+      double x_resolution = gdkdev->axes[x_axis].resolution;
+      double y_resolution = gdkdev->axes[y_axis].resolution;
+      double device_aspect = (device_height*y_resolution) / (device_width * x_resolution);
 
-      if (device_aspect * window_object->width >= window_object->height)
-		{
-		  /* device taller than window */
-		  x_scale = window_object->width / device_width;
-		  y_scale = (x_scale * gdkdev->axes[x_axis].resolution) / gdkdev->axes[y_axis].resolution;
+      if (device_aspect * priv->width >= priv->height)
+	{
+	  /* device taller than window */
+	  x_scale = priv->width / device_width;
+	  y_scale = (x_scale * x_resolution) / y_resolution;
 
-		  x_offset = 0;
-		  y_offset = -(device_height * y_scale - window_object->height) / 2;
-		}
+	  x_offset = 0;
+	  y_offset = -(device_height * y_scale - priv->height) / 2;
+	}
       else
-		{
-		  /* window taller than device */
-		  y_scale = window_object->height / device_height;
-		  x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
-			/ gdkdev->axes[x_axis].resolution;
+	{
+	  /* window taller than device */
+	  y_scale = priv->height / device_height;
+	  x_scale = (y_scale * y_resolution)  / x_resolution;
 
-		  y_offset = 0;
-		  x_offset = - (device_width * x_scale - window_object->width) / 2;
-		}
+	  y_offset = 0;
+	  x_offset = - (device_width * x_scale - priv->width) / 2;
+	}
     }
 
   for (i = 0; i < gdkdev->info.num_axes; i++)
     {
       switch (gdkdev->info.axes[i].use)
-		{
-		case GDK_AXIS_X:
-		  axis_out[i] = x_offset + x_scale * axis_data[x_axis];
-		  if (x_out)
-			*x_out = axis_out[i];
-		  break;
-		case GDK_AXIS_Y:
-		  axis_out[i] = y_offset + y_scale * axis_data[y_axis];
-		  if (y_out)
-			*y_out = axis_out[i];
-		  break;
-		default:
-		  axis_out[i] =
-			(gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
-			 gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
-			(gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
-		  break;
-		}
+	{
+	case GDK_AXIS_X:
+	  axis_out[i] = x_offset + x_scale * axis_data[x_axis];
+	  if (x_out)
+	    *x_out = axis_out[i];
+	  break;
+	case GDK_AXIS_Y:
+	  axis_out[i] = y_offset + y_scale * axis_data[y_axis];
+	  if (y_out)
+	    *y_out = axis_out[i];
+	  break;
+	default:
+	  axis_out[i] =
+	    (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
+	     gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
+	    (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
+	  break;
+	}
     }
 }
 
@@ -763,25 +768,30 @@ gdk_input_get_root_relative_geometry (HWND w,
 				      int  *x_ret,
 				      int  *y_ret)
 {
-  RECT rect;
+  POINT pt;
 
-  GetWindowRect (w, &rect);
+  pt.x = 0;
+  pt.y = 0;
+  ClientToScreen (w, &pt);
 
   if (x_ret)
-    *x_ret = rect.left + _gdk_offset_x;
+    *x_ret = pt.x + _gdk_offset_x;
   if (y_ret)
-    *y_ret = rect.top + _gdk_offset_y;
+    *y_ret = pt.y + _gdk_offset_y;
 }
 
 void
 _gdk_input_configure_event (GdkWindow         *window)
 {
   GdkInputWindow *input_window;
+  GdkWindowObject *impl_window;
   int root_x, root_y;
 
-  input_window = _gdk_input_window_find (window);
   g_return_if_fail (window != NULL);
 
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  input_window = impl_window->input_window;
+
   gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
 					&root_x, &root_y);
 
@@ -789,21 +799,6 @@ _gdk_input_configure_event (GdkWindow         *window)
   input_window->root_y = root_y;
 }
 
-void 
-_gdk_input_enter_event (GdkWindow        *window)
-{
-  GdkInputWindow *input_window;
-  int root_x, root_y;
-
-  input_window = _gdk_input_window_find (window);
-  g_return_if_fail (window != NULL);
-
-  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
-
-  input_window->root_x = root_x;
-  input_window->root_y = root_y;
-}
-
 /*
  * Get the currently active keyboard modifiers (ignoring the mouse buttons)
  * We could use gdk_window_get_pointer but that function does a lot of other
@@ -829,6 +824,7 @@ get_modifier_key_state (void)
   return state;
 }
 
+#if 0
 static guint ignore_core_timer = 0;
 
 static gboolean
@@ -867,18 +863,78 @@ set_ignore_core (gboolean ignore)
 					 ignore_core_timefunc, NULL);
 }
 
+#endif
+
+void
+_gdk_input_update_for_device_mode (GdkDevicePrivate *gdkdev)
+{
+  LOGCONTEXT lc;
+
+  if (gdkdev != _gdk_device_in_proximity)
+    return;
+
+  if (p_WTGetA (gdkdev->hctx, &lc))
+    {
+      if (gdkdev->info.mode == GDK_MODE_SCREEN &&
+	  (lc.lcOptions & CXO_SYSTEM) == 0)
+	{
+	  lc.lcOptions |= CXO_SYSTEM;
+	  p_WTSetA (gdkdev->hctx, &lc);
+	}
+      else if (gdkdev->info.mode == GDK_MODE_WINDOW &&
+	       (lc.lcOptions & CXO_SYSTEM) != 0)
+	{
+	  lc.lcOptions &= ~CXO_SYSTEM;
+	  p_WTSetA (gdkdev->hctx, &lc);
+	}
+    }
+}
+
+static GdkWindow *
+find_window_for_input_event (MSG* msg, int *x, int *y)
+{
+  POINT pt;
+  GdkWindow *window;
+  HWND hwnd;
+  RECT rect;
+
+  pt = msg->pt;
+
+  window = NULL;
+  hwnd = WindowFromPoint (pt);
+  if (hwnd != NULL)
+    {
+      POINT client_pt = pt;
+
+      ScreenToClient (hwnd, &client_pt);
+      GetClientRect (hwnd, &rect);
+      if (PtInRect (&rect, client_pt))
+	window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
+    }
+
+  /* need to also adjust the coordinates to the new window */
+  if (window)
+    ScreenToClient (GDK_WINDOW_HWND (window), &pt);
+
+  *x = pt.x;
+  *y = pt.y;
+
+  if (window)
+    return window;
+
+  return _gdk_root;
+}
+
 gboolean 
 _gdk_input_other_event (GdkEvent  *event,
 			MSG       *msg,
 			GdkWindow *window)
 {
-  GdkDisplay *display;
-  GdkWindowObject *obj, *grab_obj;
+  GdkWindowObject *obj, *impl_window;
+  GdkWindow *native_window;
   GdkInputWindow *input_window;
   GdkDevicePrivate *gdkdev = NULL;
-  GdkEventMask masktest;
   guint key_state;
-  POINT pt;
 
   PACKET packet;
   gint k;
@@ -889,31 +945,24 @@ _gdk_input_other_event (GdkEvent  *event,
    */
   static guint button_map[8] = {0, 1, 4, 5, 2, 3, 6, 7};
 
-  if (event->any.window != wintab_window)
+  if (window != wintab_window)
     {
       g_warning ("_gdk_input_other_event: not wintab_window?");
       return FALSE;
     }
 
-  window = gdk_window_at_pointer (&x, &y);
-  if (window == NULL)
-    window = _gdk_root;
-
-  g_object_ref (window);
-  display = gdk_drawable_get_display (window);
+  native_window = find_window_for_input_event (msg, &x, &y);
 
   GDK_NOTE (EVENTS_OR_INPUT,
-	    g_print ("_gdk_input_other_event: window=%p %+d%+d\n",
-		     GDK_WINDOW_HWND (window), x, y));
-  
-  if (msg->message == WT_PACKET)
+	    g_print ("_gdk_input_other_event: native_window=%p %+d%+d\n",
+		     GDK_WINDOW_HWND (native_window), x, y));
+
+  if (msg->message == WT_PACKET || msg->message == WT_CSRCHANGE)
     {
       if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
 	return FALSE;
     }
 
-  obj = GDK_WINDOW_OBJECT (window);
-
   switch (msg->message)
     {
     case WT_PACKET:
@@ -925,11 +974,6 @@ _gdk_input_other_event (GdkEvent  *event,
 	  GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
 	  return FALSE;
 	}
-      if (window == _gdk_root && x_grab_window == NULL)
-	{
-	  GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
-	  return FALSE;
-	}
 
       if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
 						 packet.pkCursor)) == NULL)
@@ -979,104 +1023,50 @@ _gdk_input_other_event (GdkEvent  *event,
 	    }
 
 	  if (!(translated_buttons & button_mask))
-	    {
-	      event->any.type = GDK_BUTTON_RELEASE;
-	      masktest = GDK_BUTTON_RELEASE_MASK;
-	    }
+	    event->any.type = GDK_BUTTON_RELEASE;
 	  else
-	    {
-	      event->any.type = GDK_BUTTON_PRESS;
-	      masktest = GDK_BUTTON_PRESS_MASK;
-	    }
+	    event->any.type = GDK_BUTTON_PRESS;
 	  gdkdev->button_state ^= button_mask;
 	}
       else
 	{
 	  event->any.type = GDK_MOTION_NOTIFY;
-	  masktest = GDK_POINTER_MOTION_MASK;
-	  if (gdkdev->button_state & (1 << 0))
-	    masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
-	  if (gdkdev->button_state & (1 << 1))
-	    masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
-	  if (gdkdev->button_state & (1 << 2))
-	    masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
 	}
 
-      /* See if input is grabbed */
-      /* FIXME: x_grab_owner_events should probably be handled somehow */
-      if (x_grab_window != NULL)
-	{
-	  grab_obj = GDK_WINDOW_OBJECT (x_grab_window);
-	  if (!GDK_WINDOW_IMPL_WIN32 (grab_obj->impl)->extension_events_selected
-	      || !(grab_obj->extension_events & masktest)
-	      || !(x_grab_mask && masktest))
-	    {
-	      GDK_NOTE (EVENTS_OR_INPUT, 
-			g_print ("... grabber doesn't want it\n"));
-	      return FALSE;
-	    }
-	  GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
+      if (native_window == _gdk_root)
+	return FALSE;
 
-	  g_object_ref(x_grab_window);
-	  g_object_unref(window);
-	  window = x_grab_window;
-	  obj = grab_obj;
-	}
-      /* Now we can check if the window wants the event, and
-       * propagate if necessary.
-       */
-    loop:
-      if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
-	  || !(obj->extension_events & masktest))
-	{
-	  GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
+      window = _gdk_window_get_input_window_for_event (native_window,
+						       event->any.type,
+						       gdkdev->button_state << 8,
+						       x, y, 0);
 
-	  if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
-	    return FALSE;
+      obj = GDK_WINDOW_OBJECT (window);
 
-	  /* It is not good to propagate the extended events up to the parent
-	   * if this window wants normal (not extended) motion/button events */
-	  if (obj->event_mask & masktest)
-	    {
-	      GDK_NOTE (EVENTS_OR_INPUT, 
-			g_print ("... wants ordinary event, ignoring this\n"));
-	      return FALSE;
-	    }
-	  
-	  pt.x = x;
-	  pt.y = y;
-	  ClientToScreen (GDK_WINDOW_HWND (window), &pt);
-	  g_object_unref (window);
-	  window = (GdkWindow *) obj->parent;
-	  obj = GDK_WINDOW_OBJECT (window);
-	  g_object_ref (window);
-	  ScreenToClient (GDK_WINDOW_HWND (window), &pt);
-	  x = pt.x;
-	  y = pt.y;
-	  GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
-					      GDK_WINDOW_HWND (window), x, y));
-	  goto loop;
-	}
-
-      input_window = _gdk_input_window_find (window);
+      if (window == NULL ||
+	  obj->extension_events == 0)
+	return FALSE;
+      
+      impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+      input_window = impl_window->input_window;
 
       g_assert (input_window != NULL);
 
-      if (gdkdev->info.mode == GDK_MODE_WINDOW
-	  && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
+      if (gdkdev->info.mode == GDK_MODE_WINDOW && 
+	  (obj->extension_events & GDK_ALL_DEVICES_MASK) == 0)
 	return FALSE;
 
       event->any.window = window;
       key_state = get_modifier_key_state ();
-      if (event->any.type == GDK_BUTTON_PRESS
-	  || event->any.type == GDK_BUTTON_RELEASE)
+      if (event->any.type == GDK_BUTTON_PRESS || 
+	  event->any.type == GDK_BUTTON_RELEASE)
 	{
 	  event->button.time = _gdk_win32_get_next_tick (msg->time);
 	  event->button.device = &gdkdev->info;
 	  
 	  event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
 
-	  gdk_input_translate_coordinates (gdkdev, input_window,
+	  gdk_input_translate_coordinates (gdkdev, window,
 					   gdkdev->last_axis_data,
 					   event->button.axes,
 					   &event->button.x, 
@@ -1107,7 +1097,7 @@ _gdk_input_other_event (GdkEvent  *event,
 
 	  event->motion.axes = g_new(gdouble, gdkdev->info.num_axes);
 
-	  gdk_input_translate_coordinates (gdkdev, input_window,
+	  gdk_input_translate_coordinates (gdkdev, window,
 					   gdkdev->last_axis_data,
 					   event->motion.axes,
 					   &event->motion.x, 
@@ -1130,49 +1120,104 @@ _gdk_input_other_event (GdkEvent  *event,
 	}
       return TRUE;
 
-    case WT_PROXIMITY:
-      if (LOWORD (msg->lParam) == 0)
-	{
-	  event->proximity.type = GDK_PROXIMITY_OUT;
-	  set_ignore_core (FALSE);
-	}
-      else
+    case WT_CSRCHANGE:
+      if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
+						 packet.pkCursor)) == NULL)
+	return FALSE;
+
+      _gdk_device_in_proximity = gdkdev;
+
+      _gdk_input_update_for_device_mode (gdkdev);
+
+      window = NULL;
+      if (native_window != _gdk_root)
+	window = _gdk_window_get_input_window_for_event (native_window,
+							 GDK_PROXIMITY_IN,
+							 0,
+							 x, y, 0);
+      if (window)
 	{
 	  event->proximity.type = GDK_PROXIMITY_IN;
-	  set_ignore_core (TRUE);
+	  event->proximity.window = window;
+	  event->proximity.time = _gdk_win32_get_next_tick (msg->time);
+	  event->proximity.device = &_gdk_device_in_proximity->info;
 	}
-      event->proximity.time = _gdk_win32_get_next_tick (msg->time);
-      event->proximity.device = &gdkdev->info;
 
       GDK_NOTE (EVENTS_OR_INPUT,
-		g_print ("WINTAB proximity %s\n",
-			 (event->proximity.type == GDK_PROXIMITY_IN ?
-			  "in" : "out")));
+		g_print ("WINTAB proximity in\n"));
+
       return TRUE;
+
+    case WT_PROXIMITY:
+      /* TODO: Set ignore_core if in input_window */
+      if (LOWORD (msg->lParam) == 0)
+	{
+	  _gdk_input_in_proximity = FALSE;
+
+	  window = NULL;
+	  if (native_window != _gdk_root)
+	    window = _gdk_window_get_input_window_for_event (native_window,
+							     GDK_PROXIMITY_IN,
+							     0,
+							     x, y, 0);
+	  if (window)
+	    {
+	      event->proximity.type = GDK_PROXIMITY_OUT;
+	      event->proximity.window = window;
+	      event->proximity.time = _gdk_win32_get_next_tick (msg->time);
+	      event->proximity.device = &_gdk_device_in_proximity->info;
+	    }
+
+	  GDK_NOTE (EVENTS_OR_INPUT,
+		    g_print ("WINTAB proximity out\n"));
+
+	  return TRUE;
+	}
+      else
+	_gdk_input_in_proximity = TRUE;
+
+      _gdk_input_check_proximity ();
+
+      break;
     }
   return FALSE;
 }
 
-gboolean
-_gdk_input_enable_window (GdkWindow        *window,
-			  GdkDevicePrivate *gdkdev)
+void
+_gdk_input_select_events (GdkWindow *impl_window)
 {
-  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
-
-  impl->extension_events_selected = TRUE;
+  guint event_mask;
+  GdkWindowObject *w;
+  GdkInputWindow *iw;
+  GList *l, *dev_list;
+  
 
-  return TRUE;
-}
+  iw = ((GdkWindowObject *)impl_window)->input_window;
 
-gboolean
-_gdk_input_disable_window (GdkWindow        *window,
-			   GdkDevicePrivate *gdkdev)
-{
-  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+  event_mask = 0;
+  for (dev_list = _gdk_input_devices; dev_list; dev_list = dev_list->next)
+    {
+      GdkDevicePrivate *gdkdev = dev_list->data;
 
-  impl->extension_events_selected = FALSE;
+      if (!GDK_IS_CORE (gdkdev) &&
+	  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;
 
-  return TRUE;
+  GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *)impl_window)->impl)->extension_events_mask = event_mask;
 }
 
 gint
@@ -1182,131 +1227,20 @@ _gdk_input_grab_pointer (GdkWindow    *window,
 			 GdkWindow    *confine_to,
 			 guint32       time)
 {
-  GdkInputWindow *input_window, *new_window;
-  gboolean need_ungrab;
-  GdkDevicePrivate *gdkdev;
-  GList *tmp_list;
-
-  tmp_list = _gdk_input_windows;
-  new_window = NULL;
-  need_ungrab = FALSE;
-
   GDK_NOTE (INPUT, g_print ("_gdk_input_grab_pointer: %p %d %p\n",
 			   GDK_WINDOW_HWND (window),
 			   owner_events,
 			   (confine_to ? GDK_WINDOW_HWND (confine_to) : 0)));
 
-  while (tmp_list)
-    {
-      input_window = (GdkInputWindow *)tmp_list->data;
-
-      if (input_window->window == window)
-	new_window = input_window;
-      else if (input_window->grabbed)
-	{
-	  input_window->grabbed = FALSE;
-	  need_ungrab = TRUE;
-	}
-
-      tmp_list = tmp_list->next;
-    }
-
-  if (new_window)
-    {
-      new_window->grabbed = TRUE;
-      x_grab_window = window;
-      x_grab_mask = event_mask;
-      x_grab_owner_events = owner_events;
-
-      /* FIXME: Do we need to handle confine_to and time? */
-      
-      tmp_list = _gdk_input_devices;
-      while (tmp_list)
-	{
-	  gdkdev = (GdkDevicePrivate *)tmp_list->data;
-	  if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
-	    {
-#if 0	      
-	      /* XXX */
-	      gdk_input_common_find_events (window, gdkdev,
-					    event_mask,
-					    event_classes, &num_classes);
-	      
-	      result = XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
-				    GDK_WINDOW_XWINDOW (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)
-		return result;
-#endif
-	    }
-	  tmp_list = tmp_list->next;
-	}
-    }
-  else
-    { 
-      x_grab_window = NULL;
-#if 0
-      tmp_list = _gdk_input_devices;
-      while (tmp_list)
-	{
-	  gdkdev = (GdkDevicePrivate *)tmp_list->data;
-	  if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
-	      ((gdkdev->button_state != 0) || need_ungrab))
-	    {
-#if 0
-	      /* XXX */
-	      XUngrabDevice (gdk_display, gdkdev->xdevice, time);
-#endif
-	      gdkdev->button_state = 0;
-	    }
-	  
-	  tmp_list = tmp_list->next;
-	}
-#endif
-    }
-
   return GDK_GRAB_SUCCESS;
 }
 
 void 
 _gdk_input_ungrab_pointer (guint32 time)
 {
-  GdkInputWindow *input_window;
-  GdkDevicePrivate *gdkdev;
-  GList *tmp_list;
 
   GDK_NOTE (INPUT, g_print ("_gdk_input_ungrab_pointer\n"));
 
-  tmp_list = _gdk_input_windows;
-  while (tmp_list)
-    {
-      input_window = (GdkInputWindow *)tmp_list->data;
-      if (input_window->grabbed)
-	break;
-      tmp_list = tmp_list->next;
-    }
-
-  if (tmp_list)			/* we found a grabbed window */
-    {
-      input_window->grabbed = FALSE;
-
-      tmp_list = _gdk_input_devices;
-      while (tmp_list)
-	{
-	  gdkdev = (GdkDevicePrivate *)tmp_list->data;
-#if 0
-	  /* XXX */
-	  if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
-	    XUngrabDevice (gdk_display, gdkdev->xdevice, time);
-#endif
-	  tmp_list = tmp_list->next;
-	}
-    }
-  x_grab_window = NULL;
 }
 
 gboolean
@@ -1344,7 +1278,6 @@ gdk_device_get_state (GdkDevice       *device,
   else
     {
       GdkDevicePrivate *gdkdev;
-      GdkInputWindow *input_window;
       
       gdkdev = (GdkDevicePrivate *)device;
       /* For now just use the last known button and axis state of the device.
@@ -1359,12 +1292,10 @@ gdk_device_get_state (GdkDevice       *device,
 		       | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
 		       | GDK_BUTTON5_MASK));
 	}
-      input_window = _gdk_input_window_find (window);
-      g_return_if_fail (input_window != NULL);
       /* For some reason, input_window is sometimes NULL when I use The GIMP 2
        * (bug #141543?). Avoid crashing if debugging is disabled. */
-      if (axes && gdkdev->last_axis_data && input_window)
-	gdk_input_translate_coordinates (gdkdev, input_window,
+      if (axes && gdkdev->last_axis_data)
+	gdk_input_translate_coordinates (gdkdev, window,
 					 gdkdev->last_axis_data,
 					 axes, NULL, NULL);
     }
@@ -1397,7 +1328,6 @@ _gdk_input_set_tablet_active (void)
 void 
 _gdk_input_init (GdkDisplay *display)
 {
-  _gdk_input_ignore_core = FALSE;
   _gdk_input_devices = NULL;
 
   _gdk_init_input_core (display);
diff --git a/gdk/win32/gdkinput-win32.h b/gdk/win32/gdkinput-win32.h
index 608d8f9..746bcaf 100644
--- a/gdk/win32/gdkinput-win32.h
+++ b/gdk/win32/gdkinput-win32.h
@@ -70,24 +70,19 @@ struct _GdkDevicePrivate
   AXIS orientation_axes[2];
 };
 
+/* 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;
+  GdkWindow *impl_window; /* an impl 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 */
@@ -97,7 +92,7 @@ struct _GdkInputWindow
 extern GList *_gdk_input_devices;
 extern GList *_gdk_input_windows;
 
-extern gint   _gdk_input_ignore_core;
+extern gboolean _gdk_input_in_proximity;
 
 /* Function declarations */
 void             _gdk_init_input_core (GdkDisplay *display);
@@ -109,7 +104,6 @@ GdkTimeCoord ** _gdk_device_allocate_history (GdkDevice *device,
  * (just wintab for now)
  */
 void             _gdk_input_configure_event  (GdkWindow        *window);
-void             _gdk_input_enter_event      (GdkWindow        *window);
 gboolean         _gdk_input_other_event      (GdkEvent         *event,
 					      MSG              *msg,
 					      GdkWindow        *window);
@@ -124,10 +118,7 @@ GdkInputWindow  *_gdk_input_window_find      (GdkWindow        *window);
 
 void             _gdk_input_window_destroy   (GdkWindow *window);
 
-gint             _gdk_input_enable_window    (GdkWindow        *window,
-					      GdkDevicePrivate *gdkdev);
-gint             _gdk_input_disable_window   (GdkWindow        *window,
-					      GdkDevicePrivate *gdkdev);
+void             _gdk_input_select_events    (GdkWindow        *impl_window);
 gint             _gdk_input_grab_pointer     (GdkWindow        *window,
 					      gint              owner_events,
 					      GdkEventMask      event_mask,
@@ -143,5 +134,7 @@ gboolean         _gdk_device_get_history     (GdkDevice         *device,
 
 void		_gdk_input_wintab_init_check (void);
 void		_gdk_input_set_tablet_active (void);
+void            _gdk_input_update_for_device_mode (GdkDevicePrivate *gdkdev);
+void            _gdk_input_check_proximity (void);
 
 #endif /* __GDK_INPUT_WIN32_H__ */
diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c
index 2612afb..c386443 100644
--- a/gdk/win32/gdkinput.c
+++ b/gdk/win32/gdkinput.c
@@ -46,10 +46,10 @@ static GdkDeviceAxis gdk_input_core_axes[] = {
 
 /* Global variables  */
 
-gint              _gdk_input_ignore_core;
-
 GList            *_gdk_input_devices;
 GList            *_gdk_input_windows;
+gboolean          _gdk_input_in_proximity = 0;
+gboolean          _gdk_input_inside_input_window = 0;
 
 void
 _gdk_init_input_core (GdkDisplay *display)
@@ -291,30 +291,63 @@ gdk_device_free_history (GdkTimeCoord **events,
   g_free (events);
 }
 
-GdkInputWindow *
-_gdk_input_window_find(GdkWindow *window)
-{
-  GList *tmp_list;
-
-  for (tmp_list=_gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
-    if (((GdkInputWindow *)(tmp_list->data))->window == window)
-      return (GdkInputWindow *)(tmp_list->data);
-
-  return NULL;      /* Not found */
-}
-
 /* 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 */
 
+static void
+unset_extension_events (GdkWindow *window)
+{
+  GdkWindowObject *window_private;
+  GdkWindowObject *impl_window;
+  GdkInputWindow *iw;
+
+  window_private = (GdkWindowObject*) window;
+  impl_window = (GdkWindowObject *)_gdk_window_get_impl_window (window);
+  iw = impl_window->input_window;
+
+  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;
+	  _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
+	  g_free (iw);
+	}
+    }
+
+  window_private->extension_events = 0;
+}
+
+static void
+gdk_input_get_root_relative_geometry (HWND w,
+				      int  *x_ret,
+				      int  *y_ret)
+{
+  POINT pt;
+
+  pt.x = 0;
+  pt.y = 0;
+  ClientToScreen (w, &pt);
+
+  if (x_ret)
+    *x_ret = pt.x + _gdk_offset_x;
+  if (y_ret)
+    *y_ret = pt.y + _gdk_offset_y;
+}
+
 void
 gdk_input_set_extension_events (GdkWindow *window, gint mask,
 				GdkExtensionMode mode)
 {
   GdkWindowObject *window_private;
-  GList *tmp_list;
+  GdkWindowObject *impl_window;
   GdkInputWindow *iw;
 
   g_return_if_fail (window != NULL);
@@ -324,68 +357,81 @@ 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 = impl_window->input_window;
+
   if (mask != 0)
     {
       _gdk_input_wintab_init_check ();
 
-      iw = g_new(GdkInputWindow,1);
+      if (!iw)
+	{
+	  iw = g_new0 (GdkInputWindow,1);
 
-      iw->window = window;
-      iw->mode = mode;
+	  iw->impl_window = (GdkWindow *)impl_window;
 
-      iw->obscuring = NULL;
-      iw->num_obscuring = 0;
-      iw->grabbed = FALSE;
+	  iw->windows = NULL;
 
-      _gdk_input_windows = g_list_append(_gdk_input_windows,iw);
-      window_private->extension_events = mask;
+	  _gdk_input_windows = g_list_append(_gdk_input_windows, iw);
 
-      /* Add enter window events to the event mask */
-      if (g_list_length (_gdk_input_devices) > 1)
-	gdk_window_set_events (window,
-			       gdk_window_get_events (window) | 
-			       GDK_ENTER_NOTIFY_MASK);
-    }
-  else
-    {
-      iw = _gdk_input_window_find (window);
-      if (iw)
-	{
-	  _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
-	  g_free(iw);
+	  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &iw->root_x, &iw->root_y);
+
+	  impl_window->input_window = iw;
 	}
 
-      window_private->extension_events = 0;
+      if (window_private->extension_events == 0)
+	iw->windows = g_list_append (iw->windows, window);
+      window_private->extension_events = mask;
     }
-
-  for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+  else
     {
-      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);
-	}
+      unset_extension_events (window);
     }
+
+  _gdk_input_select_events ((GdkWindow *)impl_window);
 }
 
 void
 _gdk_input_window_destroy (GdkWindow *window)
 {
-  GdkInputWindow *input_window;
+  unset_extension_events (window);
+}
 
-  input_window = _gdk_input_window_find (window);
-  g_return_if_fail (input_window != NULL);
+void
+_gdk_input_check_proximity (void)
+{
+  GList *l;
+  gboolean new_proximity = FALSE;
 
-  _gdk_input_windows = g_list_remove (_gdk_input_windows,input_window);
-  g_free(input_window);
+  if (!_gdk_input_inside_input_window)
+    {
+      _gdk_display->ignore_core_events = FALSE;
+      return;
+    }
+
+  for (l = _gdk_input_devices; l != NULL; l = l->next)
+    {
+      GdkDevicePrivate *gdkdev = l->data;
+
+      if (gdkdev->info.mode != GDK_MODE_DISABLED &&
+	  !GDK_IS_CORE (gdkdev))
+	{
+	  if (_gdk_input_in_proximity)
+	    {
+	      new_proximity = TRUE;
+	      break;
+	    }
+	}
+    }
+
+  _gdk_display->ignore_core_events = new_proximity;
 }
 
 void
@@ -394,53 +440,27 @@ _gdk_input_crossing_event (GdkWindow *window,
 {
   if (enter)
     {
-#if 0 /* No idea what to do... */
       GdkWindowObject *priv = (GdkWindowObject *)window;
       GdkInputWindow *input_window;
       gint root_x, root_y;
-#if 0
-      gdk_input_check_proximity(display);
-#endif
+
+      _gdk_input_inside_input_window = TRUE;
+
       input_window = priv->input_window;
       if (input_window != NULL)
 	{
-	  _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
+	  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), 
+						&root_x, &root_y);
 	  input_window->root_x = root_x;
 	  input_window->root_y = root_y;
 	}
-#endif
     }
   else
-    _gdk_input_ignore_core = FALSE;
-}
-
-void
-_gdk_input_exit (void)
-{
-  GList *tmp_list;
-  GdkDevicePrivate *gdkdev;
-
-  for (tmp_list = _gdk_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_free(gdkdev->info.name);
-	  g_free(gdkdev->axes);
-	  g_free(gdkdev->info.axes);
-	  g_free(gdkdev->info.keys);
-	  g_free(gdkdev);
-	}
+      _gdk_input_inside_input_window = FALSE;
     }
 
-  g_list_free(_gdk_input_devices);
-
-  for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
-    g_free(tmp_list->data);
-
-  g_list_free(_gdk_input_windows);
+  _gdk_input_check_proximity ();
 }
 
 gboolean
@@ -473,7 +493,6 @@ gdk_device_set_mode (GdkDevice   *device,
 {
   GList *tmp_list;
   GdkDevicePrivate *gdkdev;
-  GdkInputMode old_mode;
   GdkInputWindow *input_window;
 
   if (GDK_IS_CORE (device))
@@ -484,39 +503,21 @@ gdk_device_set_mode (GdkDevice   *device,
   if (device->mode == mode)
     return TRUE;
 
-  old_mode = device->mode;
   device->mode = mode;
 
   if (mode == GDK_MODE_WINDOW)
-    {
-      device->has_cursor = FALSE;
-      for (tmp_list = _gdk_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;
+
+  for (tmp_list = _gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
     {
-      device->has_cursor = TRUE;
-      for (tmp_list = _gdk_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 = _gdk_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);
     }
 
+  if (!GDK_IS_CORE (gdkdev))
+    _gdk_input_update_for_device_mode (gdkdev);
+
   return TRUE;
 }
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index f9779f7..7899533 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -494,7 +494,8 @@ gboolean _gdk_win32_pixbuf_to_hicon_supports_alpha (void);
 
 void _gdk_win32_append_event (GdkEvent *event);
 void _gdk_win32_emit_configure_event (GdkWindow *window);
-
+GdkWindow *_gdk_win32_find_window_for_mouse_event (GdkWindow* reported_window,
+						   MSG*       msg);
 
 /* Initialization */
 void _gdk_windowing_window_init (GdkScreen *screen);
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index b0b2524..473b671 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -125,7 +125,7 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
   impl->hicon_small = NULL;
   impl->hint_flags = 0;
   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
-  impl->extension_events_selected = FALSE;
+  impl->extension_events_mask = 0;
   impl->transient_owner = NULL;
   impl->transient_children = NULL;
   impl->num_transients = 0;
@@ -558,7 +558,7 @@ _gdk_window_impl_new (GdkWindow     *window,
   if (attributes_mask & GDK_WA_VISUAL)
     g_assert (visual == attributes->visual);
 
-  impl->extension_events_selected = FALSE;
+  impl->extension_events_mask = 0;
   impl->override_redirect = override_redirect;
 
   /* wclass is not any longer set always, but if is ... */
diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h
index 67868d7..096db33 100644
--- a/gdk/win32/gdkwindow-win32.h
+++ b/gdk/win32/gdkwindow-win32.h
@@ -84,7 +84,7 @@ struct _GdkWindowImplWin32
 
   GdkWindowTypeHint type_hint;
 
-  gboolean extension_events_selected;
+  GdkEventMask extension_events_mask;
 
   GdkWindow *transient_owner;
   GSList    *transient_children;
diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c
index bf63959..5d87ccd 100644
--- a/gdk/x11/gdkinput-xfree.c
+++ b/gdk/x11/gdkinput-xfree.c
@@ -266,6 +266,8 @@ _gdk_input_other_event (GdkEvent *event,
   else
     window = _gdk_window_get_input_window_for_event (event_window,
                                                      event_type,
+						     /* TODO: Seems wrong, but the code used to ignore button motion handling here... */
+						     0, 
                                                      x, y,
                                                      xevent->xany.serial);
   priv = (GdkWindowObject *)window;



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