[gtk+] win32: Fix up wintab support



commit 24f9ca92ab36265aa486e52f456c20d91ad8135d
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Mar 30 14:59:17 2012 +0200

    win32: Fix up wintab support
    
    We now have a proper MASTER/SLAVE input device split, where
    the masters are virtual core input devices and we add fake hw
    slave devices for the system pointer and real slave devices for
    wintab devices.
    
    We also set the proper source_device on the events so you can
    tell which device sent it and properly decode the axis info.

 gdk/win32/Makefile.am              |    2 +
 gdk/win32/gdkdevice-virtual.c      |  429 ++++++++++++++++++++++++++++++++++++
 gdk/win32/gdkdevice-virtual.h      |   54 +++++
 gdk/win32/gdkdevice-win32.c        |  127 +-----------
 gdk/win32/gdkdevice-wintab.c       |  209 ++++++++----------
 gdk/win32/gdkdevice-wintab.h       |    9 +-
 gdk/win32/gdkdevicemanager-win32.c |  261 ++++++++++++----------
 gdk/win32/gdkdevicemanager-win32.h |    4 +
 gdk/win32/gdkevents-win32.c        |   80 +++++---
 gdk/win32/gdkinput.c               |    2 +-
 10 files changed, 779 insertions(+), 398 deletions(-)
---
diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am
index 7a4c133..492e1c5 100644
--- a/gdk/win32/Makefile.am
+++ b/gdk/win32/Makefile.am
@@ -29,6 +29,8 @@ libgdk_win32_la_SOURCES = \
 	gdkcursor-win32.c \
 	gdkdevicemanager-win32.c \
 	gdkdevicemanager-win32.h \
+	gdkdevice-virtual.c \
+	gdkdevice-virtual.h \
 	gdkdevice-win32.c \
 	gdkdevice-win32.h \
 	gdkdevice-wintab.c \
diff --git a/gdk/win32/gdkdevice-virtual.c b/gdk/win32/gdkdevice-virtual.c
new file mode 100644
index 0000000..3a779dc
--- /dev/null
+++ b/gdk/win32/gdkdevice-virtual.c
@@ -0,0 +1,429 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+
+#include <windowsx.h>
+#include <objbase.h>
+
+#include "gdkdisplayprivate.h"
+#include "gdkdevice-virtual.h"
+#include "gdkwin32.h"
+
+static gboolean gdk_device_virtual_get_history (GdkDevice      *device,
+						GdkWindow      *window,
+						guint32         start,
+						guint32         stop,
+						GdkTimeCoord ***events,
+						gint           *n_events);
+static void gdk_device_virtual_get_state (GdkDevice       *device,
+					  GdkWindow       *window,
+					  gdouble         *axes,
+					  GdkModifierType *mask);
+static void gdk_device_virtual_set_window_cursor (GdkDevice *device,
+						  GdkWindow *window,
+						  GdkCursor *cursor);
+static void gdk_device_virtual_warp (GdkDevice *device,
+				     GdkScreen *screen,
+				     gint       x,
+				     gint       y);
+static void gdk_device_virtual_query_state (GdkDevice        *device,
+					    GdkWindow        *window,
+					    GdkWindow       **root_window,
+					    GdkWindow       **child_window,
+					    gint             *root_x,
+					    gint             *root_y,
+					    gint             *win_x,
+					    gint             *win_y,
+					    GdkModifierType  *mask);
+static GdkGrabStatus gdk_device_virtual_grab   (GdkDevice     *device,
+						GdkWindow     *window,
+						gboolean       owner_events,
+						GdkEventMask   event_mask,
+						GdkWindow     *confine_to,
+						GdkCursor     *cursor,
+						guint32        time_);
+static void          gdk_device_virtual_ungrab (GdkDevice     *device,
+						guint32        time_);
+static GdkWindow * gdk_device_virtual_window_at_position (GdkDevice       *device,
+							  gint            *win_x,
+							  gint            *win_y,
+							  GdkModifierType *mask,
+							  gboolean         get_toplevel);
+static void      gdk_device_virtual_select_window_events (GdkDevice       *device,
+							  GdkWindow       *window,
+							  GdkEventMask     event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceVirtual, gdk_device_virtual, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_virtual_class_init (GdkDeviceVirtualClass *klass)
+{
+  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+  device_class->get_history = gdk_device_virtual_get_history;
+  device_class->get_state = gdk_device_virtual_get_state;
+  device_class->set_window_cursor = gdk_device_virtual_set_window_cursor;
+  device_class->warp = gdk_device_virtual_warp;
+  device_class->query_state = gdk_device_virtual_query_state;
+  device_class->grab = gdk_device_virtual_grab;
+  device_class->ungrab = gdk_device_virtual_ungrab;
+  device_class->window_at_position = gdk_device_virtual_window_at_position;
+  device_class->select_window_events = gdk_device_virtual_select_window_events;
+}
+
+static void
+gdk_device_virtual_init (GdkDeviceVirtual *device_virtual)
+{
+  GdkDevice *device;
+
+  device = GDK_DEVICE (device_virtual);
+
+}
+
+void
+_gdk_device_virtual_set_active (GdkDevice *device,
+				GdkDevice *new_active)
+{
+  GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
+  int n_axes, i;
+  GdkAtom label_atom;
+  GdkAxisUse use;
+  gdouble min_value, max_value, resolution;
+
+  if (virtual->active_device == new_active)
+    return;
+
+  virtual->active_device = new_active;
+  
+  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+    {
+      _gdk_device_reset_axes (device);
+      n_axes = gdk_device_get_n_axes (new_active);
+      for (i = 0; i < n_axes; i++)
+	{
+	  _gdk_device_get_axis_info (new_active, i,
+				     &label_atom, &use, 
+				     &min_value, &max_value, &resolution);
+	  _gdk_device_add_axis (device,
+				label_atom, use, 
+				min_value, max_value, resolution);
+	}
+    }
+
+  g_signal_emit_by_name (G_OBJECT (device), "changed");
+}
+
+static gboolean
+gdk_device_virtual_get_history (GdkDevice      *device,
+				GdkWindow      *window,
+				guint32         start,
+				guint32         stop,
+				GdkTimeCoord ***events,
+				gint           *n_events)
+{
+  /* History is only per slave device */
+  return FALSE;
+}
+
+static void
+gdk_device_virtual_get_state (GdkDevice       *device,
+			      GdkWindow       *window,
+			      gdouble         *axes,
+			      GdkModifierType *mask)
+{
+  GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
+  GdkDevice *active = virtual->active_device;
+
+  GDK_DEVICE_GET_CLASS (active)->get_state (active,
+					    window, axes, mask);
+}
+
+static void
+gdk_device_virtual_set_window_cursor (GdkDevice *device,
+				      GdkWindow *window,
+				      GdkCursor *cursor)
+{
+  GdkWin32Cursor *cursor_private;
+  GdkWindow *parent_window;
+  GdkWindowImplWin32 *impl;
+  HCURSOR hcursor;
+  HCURSOR hprevcursor;
+
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+  cursor_private = (GdkWin32Cursor*) cursor;
+
+  hprevcursor = impl->hcursor;
+
+  if (!cursor)
+    hcursor = NULL;
+  else
+    hcursor = cursor_private->hcursor;
+
+  if (hcursor != NULL)
+    {
+      /* If the pointer is over our window, set new cursor */
+      GdkWindow *curr_window = gdk_window_get_pointer (window, NULL, NULL, NULL);
+
+      if (curr_window == window ||
+          (curr_window && window == gdk_window_get_toplevel (curr_window)))
+        SetCursor (hcursor);
+      else
+        {
+          /* Climb up the tree and find whether our window is the
+           * first ancestor that has cursor defined, and if so, set
+           * new cursor.
+           */
+          while (curr_window && curr_window->impl &&
+                 !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->hcursor)
+            {
+              curr_window = curr_window->parent;
+              if (curr_window == GDK_WINDOW (window))
+                {
+                  SetCursor (hcursor);
+                  break;
+                }
+            }
+        }
+    }
+
+  /* Unset the previous cursor: Need to make sure it's no longer in
+   * use before we destroy it, in case we're not over our window but
+   * the cursor is still set to our old one.
+   */
+  if (hprevcursor != NULL &&
+      GetCursor () == hprevcursor)
+    {
+      /* Look for a suitable cursor to use instead */
+      hcursor = NULL;
+      parent_window = GDK_WINDOW (window)->parent;
+
+      while (hcursor == NULL)
+        {
+          if (parent_window)
+            {
+              impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
+              hcursor = impl->hcursor;
+              parent_window = parent_window->parent;
+            }
+          else
+            hcursor = LoadCursor (NULL, IDC_ARROW);
+        }
+
+      SetCursor (hcursor);
+    }
+}
+
+static void
+gdk_device_virtual_warp (GdkDevice *device,
+			 GdkScreen *screen,
+			 gint       x,
+			 gint       y)
+{
+  SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
+}
+
+static void
+gdk_device_virtual_query_state (GdkDevice        *device,
+				GdkWindow        *window,
+				GdkWindow       **root_window,
+				GdkWindow       **child_window,
+				gint             *root_x,
+				gint             *root_y,
+				gint             *win_x,
+				gint             *win_y,
+				GdkModifierType  *mask)
+{
+  GdkDeviceVirtual *virtual = GDK_DEVICE_VIRTUAL (device);
+
+  _gdk_device_query_state (virtual->active_device,
+			   window, root_window, child_window,
+			   root_x, root_y,
+			   win_x, win_y,
+			   mask);
+}
+
+static GdkGrabStatus
+gdk_device_virtual_grab (GdkDevice    *device,
+			 GdkWindow    *window,
+			 gboolean      owner_events,
+			 GdkEventMask  event_mask,
+			 GdkWindow    *confine_to,
+			 GdkCursor    *cursor,
+			 guint32       time_)
+{
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+  HCURSOR hcursor;
+  GdkWin32Cursor *cursor_private;
+
+  cursor_private = (GdkWin32Cursor*) cursor;
+
+  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+    {
+      if (!cursor)
+	hcursor = NULL;
+      else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
+	WIN32_API_FAILED ("CopyCursor");
+
+      if (_gdk_win32_grab_cursor != NULL)
+	{
+	  if (GetCursor () == _gdk_win32_grab_cursor)
+	    SetCursor (NULL);
+	  DestroyCursor (_gdk_win32_grab_cursor);
+	}
+
+      _gdk_win32_grab_cursor = hcursor;
+
+      if (_gdk_win32_grab_cursor != NULL)
+	SetCursor (_gdk_win32_grab_cursor);
+      else if (impl->hcursor != NULL)
+	SetCursor (impl->hcursor);
+      else
+	SetCursor (LoadCursor (NULL, IDC_ARROW));
+
+      SetCapture (GDK_WINDOW_HWND (window));
+    }
+
+  return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_virtual_ungrab (GdkDevice *device,
+                         guint32    time_)
+{
+  GdkDeviceGrabInfo *info;
+  GdkDisplay *display;
+
+  display = gdk_device_get_display (device);
+  info = _gdk_display_get_last_device_grab (display, device);
+
+  if (info)
+    info->serial_end = 0;
+
+  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+    {
+      if (_gdk_win32_grab_cursor != NULL)
+	{
+	  if (GetCursor () == _gdk_win32_grab_cursor)
+	    SetCursor (NULL);
+	  DestroyCursor (_gdk_win32_grab_cursor);
+	}
+      _gdk_win32_grab_cursor = NULL;
+
+      ReleaseCapture ();
+    }
+
+  _gdk_display_device_grab_update (display, device, NULL, 0);
+}
+
+static void
+screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
+{
+  *client_pt = screen_pt;
+  ScreenToClient (hwnd, client_pt);
+}
+
+static GdkWindow *
+gdk_device_virtual_window_at_position (GdkDevice       *device,
+				       gint            *win_x,
+				       gint            *win_y,
+				       GdkModifierType *mask,
+				       gboolean         get_toplevel)
+{
+  GdkWindow *window = NULL;
+  POINT screen_pt, client_pt;
+  HWND hwnd, hwndc;
+  RECT rect;
+
+  GetCursorPos (&screen_pt);
+
+  if (get_toplevel)
+    {
+      /* Only consider visible children of the desktop to avoid the various
+       * non-visible windows you often find on a running Windows box. These
+       * might overlap our windows and cause our walk to fail. As we assume
+       * WindowFromPoint() can find our windows, we follow similar logic
+       * here, and ignore invisible and disabled windows.
+       */
+      hwnd = GetDesktopWindow ();
+      do {
+        window = gdk_win32_handle_table_lookup (hwnd);
+
+        if (window != NULL &&
+            GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
+            GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+          break;
+
+        screen_to_client (hwnd, screen_pt, &client_pt);
+        hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED  |
+                                                         CWP_SKIPINVISIBLE);
+
+	/* Verify that we're really inside the client area of the window */
+	if (hwndc != hwnd)
+	  {
+	    GetClientRect (hwndc, &rect);
+	    screen_to_client (hwndc, screen_pt, &client_pt);
+	    if (!PtInRect (&rect, client_pt))
+	      hwndc = hwnd;
+	  }
+
+      } while (hwndc != hwnd && (hwnd = hwndc, 1));
+
+    }
+  else
+    {
+      hwnd = WindowFromPoint (screen_pt);
+
+      /* Verify that we're really inside the client area of the window */
+      GetClientRect (hwnd, &rect);
+      screen_to_client (hwnd, screen_pt, &client_pt);
+      if (!PtInRect (&rect, client_pt))
+	hwnd = NULL;
+
+      /* If we didn't hit any window at that point, return the desktop */
+      if (hwnd == NULL)
+        {
+          if (win_x)
+            *win_x = screen_pt.x + _gdk_offset_x;
+          if (win_y)
+            *win_y = screen_pt.y + _gdk_offset_y;
+          return _gdk_root;
+        }
+
+      window = gdk_win32_handle_table_lookup (hwnd);
+    }
+
+  if (window && (win_x || win_y))
+    {
+      if (win_x)
+        *win_x = client_pt.x;
+      if (win_y)
+        *win_y = client_pt.y;
+    }
+
+  return window;
+}
+
+static void
+gdk_device_virtual_select_window_events (GdkDevice    *device,
+					 GdkWindow    *window,
+					 GdkEventMask  event_mask)
+{
+}
diff --git a/gdk/win32/gdkdevice-virtual.h b/gdk/win32/gdkdevice-virtual.h
new file mode 100644
index 0000000..e552a5d
--- /dev/null
+++ b/gdk/win32/gdkdevice-virtual.h
@@ -0,0 +1,54 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2009 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_DEVICE_VIRTUAL_H__
+#define __GDK_DEVICE_VIRTUAL_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_VIRTUAL         (gdk_device_virtual_get_type ())
+#define GDK_DEVICE_VIRTUAL(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_VIRTUAL, GdkDeviceVirtual))
+#define GDK_DEVICE_VIRTUAL_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_VIRTUAL, GdkDeviceVirtualClass))
+#define GDK_IS_DEVICE_VIRTUAL(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_VIRTUAL))
+#define GDK_IS_DEVICE_VIRTUAL_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_VIRTUAL))
+#define GDK_DEVICE_VIRTUAL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_VIRTUAL, GdkDeviceVirtualClass))
+
+typedef struct _GdkDeviceVirtual GdkDeviceVirtual;
+typedef struct _GdkDeviceVirtualClass GdkDeviceVirtualClass;
+
+struct _GdkDeviceVirtual
+{
+  GdkDevice parent_instance;
+  GdkDevice *active_device;
+};
+
+struct _GdkDeviceVirtualClass
+{
+  GdkDeviceClass parent_class;
+};
+
+GType gdk_device_virtual_get_type (void) G_GNUC_CONST;
+
+void _gdk_device_virtual_set_active (GdkDevice *device,
+				     GdkDevice *new_active);
+
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_VIRTUAL_H__ */
diff --git a/gdk/win32/gdkdevice-win32.c b/gdk/win32/gdkdevice-win32.c
index 1cc1797..042ef34 100644
--- a/gdk/win32/gdkdevice-win32.c
+++ b/gdk/win32/gdkdevice-win32.c
@@ -133,74 +133,6 @@ gdk_device_win32_set_window_cursor (GdkDevice *device,
                                     GdkWindow *window,
                                     GdkCursor *cursor)
 {
-  GdkWin32Cursor *cursor_private;
-  GdkWindow *parent_window;
-  GdkWindowImplWin32 *impl;
-  HCURSOR hcursor;
-  HCURSOR hprevcursor;
-
-  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-  cursor_private = (GdkWin32Cursor*) cursor;
-
-  hprevcursor = impl->hcursor;
-
-  if (!cursor)
-    hcursor = NULL;
-  else
-    hcursor = cursor_private->hcursor;
-
-  if (hcursor != NULL)
-    {
-      /* If the pointer is over our window, set new cursor */
-      GdkWindow *curr_window = gdk_window_get_pointer (window, NULL, NULL, NULL);
-
-      if (curr_window == window ||
-          (curr_window && window == gdk_window_get_toplevel (curr_window)))
-        SetCursor (hcursor);
-      else
-        {
-          /* Climb up the tree and find whether our window is the
-           * first ancestor that has cursor defined, and if so, set
-           * new cursor.
-           */
-          while (curr_window && curr_window->impl &&
-                 !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->hcursor)
-            {
-              curr_window = curr_window->parent;
-              if (curr_window == GDK_WINDOW (window))
-                {
-                  SetCursor (hcursor);
-                  break;
-                }
-            }
-        }
-    }
-
-  /* Unset the previous cursor: Need to make sure it's no longer in
-   * use before we destroy it, in case we're not over our window but
-   * the cursor is still set to our old one.
-   */
-  if (hprevcursor != NULL &&
-      GetCursor () == hprevcursor)
-    {
-      /* Look for a suitable cursor to use instead */
-      hcursor = NULL;
-      parent_window = GDK_WINDOW (window)->parent;
-
-      while (hcursor == NULL)
-        {
-          if (parent_window)
-            {
-              impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
-              hcursor = impl->hcursor;
-              parent_window = parent_window->parent;
-            }
-          else
-            hcursor = LoadCursor (NULL, IDC_ARROW);
-        }
-
-      SetCursor (hcursor);
-    }
 }
 
 static void
@@ -209,7 +141,6 @@ gdk_device_win32_warp (GdkDevice *device,
                        gint       x,
                        gint       y)
 {
-  SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
 }
 
 static GdkModifierType
@@ -309,68 +240,14 @@ gdk_device_win32_grab (GdkDevice    *device,
                        GdkCursor    *cursor,
                        guint32       time_)
 {
-  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-  HCURSOR hcursor;
-  GdkWin32Cursor *cursor_private;
-
-  cursor_private = (GdkWin32Cursor*) cursor;
-
-  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
-    {
-      if (!cursor)
-	hcursor = NULL;
-      else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
-	WIN32_API_FAILED ("CopyCursor");
-
-      if (_gdk_win32_grab_cursor != NULL)
-	{
-	  if (GetCursor () == _gdk_win32_grab_cursor)
-	    SetCursor (NULL);
-	  DestroyCursor (_gdk_win32_grab_cursor);
-	}
-
-      _gdk_win32_grab_cursor = hcursor;
-
-      if (_gdk_win32_grab_cursor != NULL)
-	SetCursor (_gdk_win32_grab_cursor);
-      else if (impl->hcursor != NULL)
-	SetCursor (impl->hcursor);
-      else
-	SetCursor (LoadCursor (NULL, IDC_ARROW));
-
-      SetCapture (GDK_WINDOW_HWND (window));
-    }
-
-  return GDK_GRAB_SUCCESS;
+  /* No support for grabbing the slave atm */
+  return GDK_GRAB_NOT_VIEWABLE;
 }
 
 static void
 gdk_device_win32_ungrab (GdkDevice *device,
                          guint32    time_)
 {
-  GdkDeviceGrabInfo *info;
-  GdkDisplay *display;
-
-  display = gdk_device_get_display (device);
-  info = _gdk_display_get_last_device_grab (display, device);
-
-  if (info)
-    info->serial_end = 0;
-
-  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
-    {
-      if (_gdk_win32_grab_cursor != NULL)
-	{
-	  if (GetCursor () == _gdk_win32_grab_cursor)
-	    SetCursor (NULL);
-	  DestroyCursor (_gdk_win32_grab_cursor);
-	}
-      _gdk_win32_grab_cursor = NULL;
-
-      ReleaseCapture ();
-    }
-
-  _gdk_display_device_grab_update (display, device, NULL, 0);
 }
 
 static void
diff --git a/gdk/win32/gdkdevice-wintab.c b/gdk/win32/gdkdevice-wintab.c
index 0a44742..6af23ba 100644
--- a/gdk/win32/gdkdevice-wintab.c
+++ b/gdk/win32/gdkdevice-wintab.c
@@ -25,16 +25,6 @@
 #include "gdkwin32.h"
 #include "gdkdevice-wintab.h"
 
-static GQuark quark_window_input_info = 0;
-static GSList *input_windows = NULL;
-
-typedef struct
-{
-  gdouble root_x;
-  gdouble root_y;
-  GHashTable *device_events;
-} GdkWindowInputInfo;
-
 static gboolean gdk_device_wintab_get_history (GdkDevice      *device,
                                                GdkWindow      *window,
                                                guint32         start,
@@ -96,8 +86,6 @@ gdk_device_wintab_class_init (GdkDeviceWintabClass *klass)
   device_class->ungrab = gdk_device_wintab_ungrab;
   device_class->window_at_position = gdk_device_wintab_window_at_position;
   device_class->select_window_events = gdk_device_wintab_select_window_events;
-
-  quark_window_input_info = g_quark_from_static_string ("gdk-window-input-info");
 }
 
 static void
@@ -119,6 +107,32 @@ gdk_device_wintab_get_history (GdkDevice      *device,
   return FALSE;
 }
 
+static GdkModifierType
+get_current_mask (void)
+{
+  GdkModifierType mask;
+  BYTE kbd[256];
+
+  GetKeyboardState (kbd);
+  mask = 0;
+  if (kbd[VK_SHIFT] & 0x80)
+    mask |= GDK_SHIFT_MASK;
+  if (kbd[VK_CAPITAL] & 0x80)
+    mask |= GDK_LOCK_MASK;
+  if (kbd[VK_CONTROL] & 0x80)
+    mask |= GDK_CONTROL_MASK;
+  if (kbd[VK_MENU] & 0x80)
+    mask |= GDK_MOD1_MASK;
+  if (kbd[VK_LBUTTON] & 0x80)
+    mask |= GDK_BUTTON1_MASK;
+  if (kbd[VK_MBUTTON] & 0x80)
+    mask |= GDK_BUTTON2_MASK;
+  if (kbd[VK_RBUTTON] & 0x80)
+    mask |= GDK_BUTTON3_MASK;
+
+  return mask;
+}
+
 static void
 gdk_device_wintab_get_state (GdkDevice       *device,
                              GdkWindow       *window,
@@ -134,7 +148,7 @@ gdk_device_wintab_get_state (GdkDevice       *device,
    * second, the info should be fairly up to date */
   if (mask)
     {
-      gdk_window_get_pointer (window, NULL, NULL, mask);
+      *mask = get_current_mask ();
       *mask &= 0xFF; /* Mask away core pointer buttons */
       *mask |= ((device_wintab->button_state << 8)
                 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
@@ -142,7 +156,7 @@ gdk_device_wintab_get_state (GdkDevice       *device,
                    | GDK_BUTTON5_MASK));
     }
 
-  if (device_wintab->last_axis_data)
+  if (axes && device_wintab->last_axis_data)
     _gdk_device_wintab_translate_axes (device_wintab, window, axes, NULL, NULL);
 }
 
@@ -172,7 +186,66 @@ gdk_device_wintab_query_state (GdkDevice        *device,
                                gint             *win_y,
                                GdkModifierType  *mask)
 {
-  g_warning ("query_state unimplemented for wintab devices. Expect bad things.");
+  GdkDeviceWintab *device_wintab;
+  POINT point;
+  HWND hwnd, hwndc;
+
+  device_wintab = GDK_DEVICE_WINTAB (device);
+
+  hwnd = GDK_WINDOW_HWND (window);
+  GetCursorPos (&point);
+
+  if (root_x)
+    *root_x = point.x;
+
+  if (root_y)
+    *root_y = point.y;
+
+  ScreenToClient (hwnd, &point);
+
+  if (win_x)
+    *win_x = point.x;
+
+  if (win_y)
+    *win_y = point.y;
+
+  if (window == _gdk_root)
+    {
+      if (win_x)
+        *win_x += _gdk_offset_x;
+
+      if (win_y)
+        *win_y += _gdk_offset_y;
+    }
+
+  if (child_window)
+    {
+      hwndc = ChildWindowFromPoint (hwnd, point);
+
+      if (hwndc && hwndc != hwnd)
+        *child_window = gdk_win32_handle_table_lookup (hwndc);
+      else
+        *child_window = NULL; /* Direct child unknown to gdk */
+    }
+
+  if (root_window)
+    {
+      GdkScreen *screen;
+
+      screen = gdk_window_get_screen (window);
+      *root_window = gdk_screen_get_root_window (screen);
+    }
+
+  if (mask)
+    {
+      *mask = get_current_mask ();
+      *mask &= 0xFF; /* Mask away core pointer buttons */
+      *mask |= ((device_wintab->button_state << 8)
+                & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                   | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                   | GDK_BUTTON5_MASK));
+
+    }
 }
 
 static GdkGrabStatus
@@ -204,111 +277,10 @@ gdk_device_wintab_window_at_position (GdkDevice       *device,
 }
 
 static void
-input_info_free (GdkWindowInputInfo *info)
-{
-  g_hash_table_destroy (info->device_events);
-  g_free (info);
-}
-
-static void
 gdk_device_wintab_select_window_events (GdkDevice    *device,
                                         GdkWindow    *window,
                                         GdkEventMask  event_mask)
 {
-  GdkWindowInputInfo *info;
-
-  info = g_object_get_qdata (G_OBJECT (window),
-                             quark_window_input_info);
-  if (event_mask)
-    {
-      if (!info)
-        {
-          info = g_new0 (GdkWindowInputInfo, 1);
-          info->device_events = g_hash_table_new (NULL, NULL);
-
-          g_object_set_qdata_full (G_OBJECT (window),
-                                   quark_window_input_info,
-                                   info,
-                                   (GDestroyNotify) input_info_free);
-          input_windows = g_slist_prepend (input_windows, window);
-        }
-
-      g_hash_table_insert (info->device_events, device,
-                           GUINT_TO_POINTER (event_mask));
-    }
-  else if (info)
-    {
-      g_hash_table_remove (info->device_events, device);
-
-      if (g_hash_table_size (info->device_events) == 0)
-        {
-          g_object_set_qdata (G_OBJECT (window),
-                              quark_window_input_info,
-                              NULL);
-          input_windows = g_slist_remove (input_windows, window);
-        }
-    }
-}
-
-gboolean
-_gdk_device_wintab_wants_events (GdkWindow       *window)
-{
-  GdkWindowInputInfo *info;
-
-  info = g_object_get_qdata (G_OBJECT (window),
-                             quark_window_input_info);
-
-  return info != NULL;
-}
-
-GdkEventMask
-_gdk_device_wintab_get_events (GdkDeviceWintab *device,
-                               GdkWindow       *window)
-{
-  GdkWindowInputInfo *info;
-
-  info = g_object_get_qdata (G_OBJECT (window),
-                             quark_window_input_info);
-
-  if (!info)
-    return 0;
-
-  return GPOINTER_TO_UINT (g_hash_table_lookup (info->device_events, device));
-}
-
-gboolean
-_gdk_device_wintab_get_window_coords (GdkWindow *window,
-                                      gdouble   *root_x,
-                                      gdouble   *root_y)
-{
-  GdkWindowInputInfo *info;
-
-  info = g_object_get_qdata (G_OBJECT (window),
-                             quark_window_input_info);
-
-  if (!info)
-    return FALSE;
-
-  *root_x = info->root_x;
-  *root_y = info->root_y;
-
-  return TRUE;
-}
-
-void
-_gdk_device_wintab_update_window_coords (GdkWindow *window)
-{
-  GdkWindowInputInfo *info;
-  gint root_x, root_y;
-
-  info = g_object_get_qdata (G_OBJECT (window),
-                             quark_window_input_info);
-
-  g_return_if_fail (info != NULL);
-
-  gdk_window_get_origin (window, &root_x, &root_y);
-  info->root_x = (gdouble) root_x;
-  info->root_y = (gdouble) root_y;
 }
 
 void
@@ -320,7 +292,7 @@ _gdk_device_wintab_translate_axes (GdkDeviceWintab *device_wintab,
 {
   GdkDevice *device;
   GdkWindow *impl_window;
-  gdouble root_x, root_y;
+  gint root_x, root_y;
   gdouble temp_x, temp_y;
   gint i;
 
@@ -328,8 +300,7 @@ _gdk_device_wintab_translate_axes (GdkDeviceWintab *device_wintab,
   impl_window = _gdk_window_get_impl_window (window);
   temp_x = temp_y = 0;
 
-  if (!_gdk_device_wintab_get_window_coords (impl_window, &root_x, &root_y))
-    return;
+  gdk_window_get_origin (impl_window, &root_x, &root_y);
 
   for (i = 0; i < gdk_device_get_n_axes (device); i++)
     {
diff --git a/gdk/win32/gdkdevice-wintab.h b/gdk/win32/gdkdevice-wintab.h
index 987d8bf..bba08ff 100644
--- a/gdk/win32/gdkdevice-wintab.h
+++ b/gdk/win32/gdkdevice-wintab.h
@@ -39,6 +39,7 @@ struct _GdkDeviceWintab
 {
   GdkDevice parent_instance;
 
+  gboolean sends_core;
   gint *last_axis_data;
   gint button_state;
 
@@ -59,14 +60,6 @@ struct _GdkDeviceWintabClass
 
 GType gdk_device_wintab_get_type (void) G_GNUC_CONST;
 
-gboolean     _gdk_device_wintab_wants_events (GdkWindow *window);
-GdkEventMask _gdk_device_wintab_get_events (GdkDeviceWintab *device,
-                                            GdkWindow       *window);
-gboolean     _gdk_device_wintab_get_window_coords (GdkWindow *window,
-                                                   gdouble   *root_x,
-                                                   gdouble   *root_y);
-void         _gdk_device_wintab_update_window_coords (GdkWindow *window);
-
 void         _gdk_device_wintab_translate_axes (GdkDeviceWintab *device,
                                                 GdkWindow       *window,
                                                 gdouble         *axes,
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
index d51acbc..4d26b24 100644
--- a/gdk/win32/gdkdevicemanager-win32.c
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -27,6 +27,7 @@
 #include "gdkdevicemanager-win32.h"
 #include "gdkdeviceprivate.h"
 #include "gdkdevice-win32.h"
+#include "gdkdevice-virtual.h"
 #include "gdkdevice-wintab.h"
 #include "gdkdisplayprivate.h"
 
@@ -38,18 +39,18 @@
 #include <pktdef.h>
 
 #define DEBUG_WINTAB 1		/* Verbose debug messages enabled */
-#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
 #define TWOPI (2 * G_PI)
 
 static GList     *wintab_contexts = NULL;
 static GdkWindow *wintab_window = NULL;
-static guint      ignore_core_timer = 0;
 extern gint       _gdk_input_ignore_core;
 
 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);
@@ -58,6 +59,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;
@@ -86,25 +89,31 @@ gdk_device_manager_win32_class_init (GdkDeviceManagerWin32Class *klass)
 }
 
 static GdkDevice *
-create_core_pointer (GdkDeviceManager *device_manager)
+create_pointer (GdkDeviceManager *device_manager, 
+		GType g_type,
+		const char *name,
+		GdkDeviceType type)
 {
-  return g_object_new (GDK_TYPE_DEVICE_WIN32,
-                       "name", "Core Pointer",
-                       "type", GDK_DEVICE_TYPE_MASTER,
+  return g_object_new (g_type,
+                       "name", name,
+                       "type", type,
                        "input-source", GDK_SOURCE_MOUSE,
                        "input-mode", GDK_MODE_SCREEN,
-                       "has-cursor", TRUE,
+                       "has-cursor", type == GDK_DEVICE_TYPE_MASTER,
                        "display", _gdk_display,
                        "device-manager", device_manager,
                        NULL);
 }
 
 static GdkDevice *
-create_core_keyboard (GdkDeviceManager *device_manager)
+create_keyboard (GdkDeviceManager *device_manager, 
+		 GType g_type,
+		 const char *name,
+		 GdkDeviceType type)
 {
-  return g_object_new (GDK_TYPE_DEVICE_WIN32,
-                       "name", "Core Keyboard",
-                       "type", GDK_DEVICE_TYPE_MASTER,
+  return g_object_new (g_type,
+                       "name", name,
+                       "type", type,
                        "input-source", GDK_SOURCE_KEYBOARD,
                        "input-mode", GDK_MODE_SCREEN,
                        "has-cursor", FALSE,
@@ -419,6 +428,10 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
     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)
@@ -496,7 +509,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
 #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;
@@ -506,8 +519,8 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
       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),
@@ -537,7 +550,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
        * 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))
             {
@@ -575,14 +588,21 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
 
           device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
                                  "name", device_name,
-                                 "type", GDK_DEVICE_TYPE_SLAVE,
+                                 "type", GDK_DEVICE_TYPE_FLOATING,
                                  "input-source", GDK_SOURCE_PEN,
                                  "input-mode", GDK_MODE_SCREEN,
-                                 "has-cursor", FALSE,
+                                 "has-cursor", lc.lcOptions & CXO_SYSTEM,
                                  "display", _gdk_display,
                                  "device-manager", device_manager,
                                  NULL);
 
+	  device->sends_core = lc.lcOptions & CXO_SYSTEM;
+	  if (device->sends_core)
+	    {
+	      _gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device));
+	      _gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device));
+	    }
+
           g_free (csrname_utf8);
 
           device->hctx = *hctx;
@@ -684,8 +704,35 @@ gdk_device_manager_win32_constructed (GObject *object)
   GdkDeviceManagerWin32 *device_manager;
 
   device_manager = GDK_DEVICE_MANAGER_WIN32 (object);
-  device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager));
-  device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager));
+  device_manager->core_pointer = 
+    create_pointer (GDK_DEVICE_MANAGER (device_manager),
+		    GDK_TYPE_DEVICE_VIRTUAL,
+		    "Virtual Core Pointer",
+		    GDK_DEVICE_TYPE_MASTER);
+  device_manager->system_pointer = 
+    create_pointer (GDK_DEVICE_MANAGER (device_manager),
+		    GDK_TYPE_DEVICE_WIN32,
+		    "System Aggregated Pointer",
+		    GDK_DEVICE_TYPE_SLAVE);
+  _gdk_device_virtual_set_active (device_manager->core_pointer,
+				  device_manager->system_pointer);
+  _gdk_device_set_associated_device (device_manager->system_pointer, device_manager->core_pointer);
+  _gdk_device_add_slave (device_manager->core_pointer, device_manager->system_pointer);
+
+  device_manager->core_keyboard = 
+    create_keyboard (GDK_DEVICE_MANAGER (device_manager),
+		     GDK_TYPE_DEVICE_VIRTUAL,
+		     "Virtual Core Keyboard",
+		     GDK_DEVICE_TYPE_MASTER);
+  device_manager->system_keyboard = 
+    create_keyboard (GDK_DEVICE_MANAGER (device_manager),
+		    GDK_TYPE_DEVICE_WIN32,
+		     "System Aggregated Keyboard",
+		     GDK_DEVICE_TYPE_SLAVE);
+  _gdk_device_virtual_set_active (device_manager->core_keyboard,
+				  device_manager->system_keyboard);
+  _gdk_device_set_associated_device (device_manager->system_keyboard, device_manager->core_keyboard);
+  _gdk_device_add_slave (device_manager->core_keyboard, device_manager->system_keyboard);
 
   _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
   _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
@@ -696,7 +743,7 @@ gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
                                        GdkDeviceType     type)
 {
   GdkDeviceManagerWin32 *device_manager_win32;
-  GList *devices = NULL;
+  GList *devices = NULL, *l;
 
   device_manager_win32 = (GdkDeviceManagerWin32 *) device_manager;
 
@@ -705,10 +752,24 @@ gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
       devices = g_list_prepend (devices, device_manager_win32->core_keyboard);
       devices = g_list_prepend (devices, device_manager_win32->core_pointer);
     }
-  else if (type == GDK_DEVICE_TYPE_FLOATING)
-    devices = g_list_copy (device_manager_win32->wintab_devices);
+  else 
+    {
+      if (type == GDK_DEVICE_TYPE_SLAVE)
+	{
+	  devices = g_list_prepend (devices, device_manager_win32->system_keyboard);
+	  devices = g_list_prepend (devices, device_manager_win32->system_pointer);
+	}
+
+      for (l = device_manager_win32->wintab_devices; l != NULL; l = l->next)
+	{
+	  GdkDevice *device = l->data;
+
+	  if (gdk_device_get_device_type (device) == type)
+	    devices = g_list_prepend (devices, device);
+	}
+    }
 
-  return devices;
+  return g_list_reverse (devices);
 }
 
 static GdkDevice *
@@ -791,41 +852,6 @@ get_modifier_key_state (void)
   return state;
 }
 
-static gboolean
-ignore_core_timefunc (gpointer data)
-{
-  /* The delay has passed */
-  _gdk_input_ignore_core = FALSE;
-  ignore_core_timer = 0;
-
-  return FALSE; /* remove timeout */
-}
-
-/*
- * Set or unset the _gdk_input_ignore_core variable that tells GDK
- * to ignore events for the core pointer when the tablet is in proximity
- * The unsetting is delayed slightly so that if a tablet event arrives
- * just after proximity out, it does not cause a core pointer event
- * which e.g. causes GIMP to switch tools.
- */
-static void
-set_ignore_core (gboolean ignore)
-{
-  if (ignore)
-    {
-      _gdk_input_ignore_core = TRUE;
-      /* Remove any pending clear */
-      if (ignore_core_timer)
-        {
-          g_source_remove (ignore_core_timer);
-          ignore_core_timer = 0;
-        }
-    }
-  else if (!ignore_core_timer)
-    ignore_core_timer = gdk_threads_add_timeout (PROXIMITY_OUT_DELAY,
-                                                 ignore_core_timefunc, NULL);
-}
-
 static GdkDeviceWintab *
 _gdk_device_manager_find_wintab_device (HCTX hctx,
                                         UINT cursor)
@@ -855,15 +881,16 @@ _gdk_input_other_event (GdkEvent  *event,
                         MSG       *msg,
                         GdkWindow *window)
 {
+  GdkDeviceManagerWin32 *device_manager;
   GdkDisplay *display;
-  GdkDeviceWintab *device = NULL;
+  GdkDeviceWintab *source_device = NULL;
   GdkDeviceGrabInfo *last_grab;
   GdkEventMask masktest;
   guint key_state;
   POINT pt;
 
   PACKET packet;
-  gdouble root_x, root_y;
+  gint root_x, root_y;
   gint num_axes;
   gint x, y;
   guint translated_buttons, button_diff, button_mask;
@@ -878,6 +905,8 @@ _gdk_input_other_event (GdkEvent  *event,
       return FALSE;
     }
 
+  device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
+
   window = gdk_window_at_pointer (&x, &y);
   if (window == NULL)
     window = _gdk_root;
@@ -889,7 +918,7 @@ _gdk_input_other_event (GdkEvent  *event,
 	    g_print ("_gdk_input_other_event: window=%p %+d%+d\n",
                GDK_WINDOW_HWND (window), x, y));
 
-  if (msg->message == WT_PACKET)
+  if (msg->message == WT_PACKET || msg->message == WT_CSRCHANGE)
     {
       if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
         return FALSE;
@@ -907,14 +936,14 @@ _gdk_input_other_event (GdkEvent  *event,
           return FALSE;
         }
 
-      if ((device = _gdk_device_manager_find_wintab_device ((HCTX) msg->lParam,
-                                                            packet.pkCursor)) == NULL)
+      if ((source_device = _gdk_device_manager_find_wintab_device ((HCTX) msg->lParam,
+								   packet.pkCursor)) == NULL)
         return FALSE;
 
-      if (gdk_device_get_mode (GDK_DEVICE (device)) == GDK_MODE_DISABLED)
+      if (gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED)
         return FALSE;
 
-      last_grab = _gdk_display_get_last_device_grab (_gdk_display, GDK_DEVICE (device));
+      last_grab = _gdk_display_get_last_device_grab (_gdk_display, GDK_DEVICE (source_device));
 
       if (last_grab && last_grab->window)
         {
@@ -930,29 +959,29 @@ _gdk_input_other_event (GdkEvent  *event,
         }
 
       num_axes = 0;
-      if (device->pktdata & PK_X)
-        device->last_axis_data[num_axes++] = packet.pkX;
-      if (device->pktdata & PK_Y)
-        device->last_axis_data[num_axes++] = packet.pkY;
-      if (device->pktdata & PK_NORMAL_PRESSURE)
-        device->last_axis_data[num_axes++] = packet.pkNormalPressure;
-      if (device->pktdata & PK_ORIENTATION)
+      if (source_device->pktdata & PK_X)
+        source_device->last_axis_data[num_axes++] = packet.pkX;
+      if (source_device->pktdata & PK_Y)
+        source_device->last_axis_data[num_axes++] = packet.pkY;
+      if (source_device->pktdata & PK_NORMAL_PRESSURE)
+        source_device->last_axis_data[num_axes++] = packet.pkNormalPressure;
+      if (source_device->pktdata & PK_ORIENTATION)
         {
-          decode_tilt (device->last_axis_data + num_axes,
-                       device->orientation_axes, &packet);
+          decode_tilt (source_device->last_axis_data + num_axes,
+                       source_device->orientation_axes, &packet);
           num_axes += 2;
         }
 
       translated_buttons = button_map[packet.pkButtons & 0x07] | (packet.pkButtons & ~0x07);
 
-      if (translated_buttons != device->button_state)
+      if (translated_buttons != source_device->button_state)
         {
           /* At least one button has changed state so produce a button event
            * If more than one button has changed state (unlikely),
            * just care about the first and act on the next the next time
            * we get a packet
            */
-          button_diff = translated_buttons ^ device->button_state;
+          button_diff = translated_buttons ^ source_device->button_state;
 
           /* Gdk buttons are numbered 1.. */
           event->button.button = 1;
@@ -977,39 +1006,33 @@ _gdk_input_other_event (GdkEvent  *event,
               event->any.type = GDK_BUTTON_PRESS;
               masktest = GDK_BUTTON_PRESS_MASK;
             }
-          device->button_state ^= button_mask;
+          source_device->button_state ^= button_mask;
         }
       else
         {
           event->any.type = GDK_MOTION_NOTIFY;
           masktest = GDK_POINTER_MOTION_MASK;
-          if (device->button_state & (1 << 0))
+          if (source_device->button_state & (1 << 0))
             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
-          if (device->button_state & (1 << 1))
+          if (source_device->button_state & (1 << 1))
             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
-          if (device->button_state & (1 << 2))
+          if (source_device->button_state & (1 << 2))
             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
         }
 
       /* Now we can check if the window wants the event, and
        * propagate if necessary.
        */
-      while (gdk_window_get_device_events (window, GDK_DEVICE (device)) == 0)
+      while ((gdk_window_get_device_events (window, GDK_DEVICE (source_device)) & masktest) == 0 &&
+	     (gdk_device_get_device_type (GDK_DEVICE (source_device)) == GDK_DEVICE_TYPE_SLAVE &&
+	      (gdk_window_get_events (window) & masktest) == 0))
         {
           GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
 
-          if (window->parent == GDK_WINDOW (_gdk_root))
+          if (window->parent == GDK_WINDOW (_gdk_root) ||
+	      window->parent == NULL)
             return FALSE;
 
-          /* It is not good to propagate the extended events up to the parent
-           * if this window wants normal (not extended) motion/button events */
-          if (window->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);
@@ -1023,21 +1046,20 @@ _gdk_input_other_event (GdkEvent  *event,
                                               GDK_WINDOW_HWND (window), x, y));
         }
 
-      if (gdk_window_get_device_events (window, GDK_DEVICE (device)) == 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)
         {
           event->button.time = _gdk_win32_get_next_tick (msg->time);
-          gdk_event_set_device (event, GDK_DEVICE (device));
+	  if (source_device->sends_core)
+	    gdk_event_set_device (event, device_manager->core_pointer);
+          gdk_event_set_source_device (event, GDK_DEVICE (source_device));
 
           event->button.axes = g_new (gdouble, num_axes);
-          _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+	  gdk_window_get_origin (window, &root_x, &root_y);
 
-          _gdk_device_wintab_translate_axes (device,
+          _gdk_device_wintab_translate_axes (source_device,
                                              window,
                                              event->button.axes,
                                              &event->button.x,
@@ -1047,7 +1069,7 @@ _gdk_input_other_event (GdkEvent  *event,
           event->button.y_root = event->button.y + root_y;
 
           event->button.state =
-            key_state | ((device->button_state << 8)
+            key_state | ((source_device->button_state << 8)
                          & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
                             | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
                             | GDK_BUTTON5_MASK));
@@ -1063,12 +1085,13 @@ _gdk_input_other_event (GdkEvent  *event,
         {
           event->motion.time = _gdk_win32_get_next_tick (msg->time);
           event->motion.is_hint = FALSE;
-          gdk_event_set_device (event, GDK_DEVICE (device));
+          gdk_event_set_device (event, device_manager->core_pointer);
+          gdk_event_set_source_device (event, GDK_DEVICE (source_device));
 
           event->motion.axes = g_new (gdouble, num_axes);
-          _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+	  gdk_window_get_origin (window, &root_x, &root_y);
 
-          _gdk_device_wintab_translate_axes (device,
+          _gdk_device_wintab_translate_axes (source_device,
                                              window,
                                              event->motion.axes,
                                              &event->motion.x,
@@ -1078,7 +1101,7 @@ _gdk_input_other_event (GdkEvent  *event,
           event->motion.y_root = event->motion.y + root_y;
 
           event->motion.state =
-            key_state | ((device->button_state << 8)
+            key_state | ((source_device->button_state << 8)
                          & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
                             | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
                             | GDK_BUTTON5_MASK));
@@ -1089,25 +1112,31 @@ _gdk_input_other_event (GdkEvent  *event,
         }
       return TRUE;
 
+    case WT_CSRCHANGE:
+      if ((source_device = _gdk_device_manager_find_wintab_device ((HCTX) msg->lParam,
+								   packet.pkCursor)) == NULL)
+        return FALSE;
+
+      if (gdk_device_get_mode (GDK_DEVICE (source_device)) == GDK_MODE_DISABLED)
+        return FALSE;
+
+      if (source_device->sends_core)
+	{
+	  _gdk_device_virtual_set_active (device_manager->core_pointer, GDK_DEVICE (source_device));
+	  _gdk_input_ignore_core = TRUE;
+	}
+
+      return FALSE;
+
     case WT_PROXIMITY:
       if (LOWORD (msg->lParam) == 0)
         {
-          event->proximity.type = GDK_PROXIMITY_OUT;
-          set_ignore_core (FALSE);
+	  _gdk_input_ignore_core = FALSE;
+	  _gdk_device_virtual_set_active (device_manager->core_pointer,
+					  device_manager->system_pointer);
         }
-      else
-        {
-          event->proximity.type = GDK_PROXIMITY_IN;
-          set_ignore_core (TRUE);
-        }
-      event->proximity.time = _gdk_win32_get_next_tick (msg->time);
-      gdk_event_set_device (event, GDK_DEVICE (device));
 
-      GDK_NOTE (EVENTS_OR_INPUT,
-                g_print ("WINTAB proximity %s\n",
-                         (event->proximity.type == GDK_PROXIMITY_IN ?
-                          "in" : "out")));
-      return TRUE;
+      return FALSE;
     }
 
   return FALSE;
diff --git a/gdk/win32/gdkdevicemanager-win32.h b/gdk/win32/gdkdevicemanager-win32.h
index 66f847f..2fbea06 100644
--- a/gdk/win32/gdkdevicemanager-win32.h
+++ b/gdk/win32/gdkdevicemanager-win32.h
@@ -35,8 +35,12 @@ typedef struct _GdkDeviceManagerWin32Class GdkDeviceManagerWin32Class;
 struct _GdkDeviceManagerWin32
 {
   GdkDeviceManager parent_object;
+  /* Master Devices */
   GdkDevice *core_pointer;
   GdkDevice *core_keyboard;
+  /* Fake slave devices */
+  GdkDevice *system_pointer;
+  GdkDevice *system_keyboard;
   GList *wintab_devices;
 };
 
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index fc01381..2bc7c12 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -192,14 +192,17 @@ generate_focus_event (GdkDeviceManager *device_manager,
                       gboolean          in)
 {
   GdkDevice *device;
+  GdkDevice *source_device;
   GdkEvent *event;
 
   device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+  source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_keyboard;
 
   event = gdk_event_new (GDK_FOCUS_CHANGE);
   event->focus_change.window = window;
   event->focus_change.in = in;
   gdk_event_set_device (event, device);
+  gdk_event_set_source_device (event, source_device);
 
   _gdk_win32_append_event (event);
 }
@@ -212,11 +215,18 @@ generate_grab_broken_event (GdkDeviceManager *device_manager,
 {
   GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
   GdkDevice *device;
+  GdkDevice *source_device;
 
   if (keyboard)
-    device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+    {
+      device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+      source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_keyboard;
+    }
   else
-    device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
+    {
+      device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
+      source_device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->system_pointer;
+    }
 
   event->grab_broken.window = window;
   event->grab_broken.send_event = 0;
@@ -224,6 +234,7 @@ generate_grab_broken_event (GdkDeviceManager *device_manager,
   event->grab_broken.implicit = FALSE;
   event->grab_broken.grab_window = grab_window;
   gdk_event_set_device (event, device);
+  gdk_event_set_source_device (event, device);
 
   _gdk_win32_append_event (event);
 }
@@ -1130,13 +1141,10 @@ send_crossing_event (GdkDisplay                 *display,
   event->crossing.detail = notify_type;
   event->crossing.focus = FALSE;
   event->crossing.state = mask;
-  gdk_event_set_device (event, _gdk_display->core_pointer);
+  gdk_event_set_device (event, device_manager->core_pointer);
+  gdk_event_set_source_device (event, device_manager->system_pointer);
 
   _gdk_win32_append_event (event);
-
-  if (type == GDK_ENTER_NOTIFY &&
-      _gdk_device_wintab_wants_events (window))
-    _gdk_device_wintab_update_window_coords (window);
 }
 
 static GdkWindow *
@@ -1655,6 +1663,12 @@ generate_button_event (GdkEventType      type,
                        MSG              *msg)
 {
   GdkEvent *event = gdk_event_new (type);
+  GdkDeviceManagerWin32 *device_manager;
+
+  if (_gdk_input_ignore_core)
+    return;
+
+  device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
 
   event->button.window = window;
   event->button.time = _gdk_win32_get_next_tick (msg->time);
@@ -1665,7 +1679,8 @@ generate_button_event (GdkEventType      type,
   event->button.axes = NULL;
   event->button.state = build_pointer_event_state (msg);
   event->button.button = button;
-  gdk_event_set_device (event, _gdk_display->core_pointer);
+  gdk_event_set_device (event, device_manager->core_pointer);
+  gdk_event_set_source_device (event, device_manager->system_pointer);
 
   _gdk_win32_append_event (event);
 }
@@ -1841,6 +1856,7 @@ gdk_event_translate (MSG  *msg,
   GdkWindow *orig_window, *new_window;
 
   GdkDeviceManager *device_manager;
+  GdkDeviceManagerWin32 *device_manager_win32;
 
   GdkDeviceGrabInfo *keyboard_grab = NULL;
   GdkDeviceGrabInfo *pointer_grab = NULL;
@@ -1892,11 +1908,12 @@ gdk_event_translate (MSG  *msg,
     }
 
   device_manager = gdk_display_get_device_manager (_gdk_display);
+  device_manager_win32 = GDK_DEVICE_MANAGER_WIN32 (device_manager);
 
   keyboard_grab = _gdk_display_get_last_device_grab (_gdk_display,
-                                                     GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+                                                     device_manager_win32->core_keyboard);
   pointer_grab = _gdk_display_get_last_device_grab (_gdk_display,
-                                                    GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer);
+                                                    device_manager_win32->core_pointer);
 
   g_object_ref (window);
 
@@ -2051,7 +2068,8 @@ gdk_event_translate (MSG  *msg,
       event->key.string = NULL;
       event->key.length = 0;
       event->key.hardware_keycode = msg->wParam;
-      gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+      gdk_event_set_device (event, device_manager_win32->core_keyboard);
+      gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
       if (HIWORD (msg->lParam) & KF_EXTENDED)
 	{
 	  switch (msg->wParam)
@@ -2168,7 +2186,8 @@ gdk_event_translate (MSG  *msg,
 	      /* Build a key press event */
 	      event = gdk_event_new (GDK_KEY_PRESS);
 	      event->key.window = window;
-        gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+	      gdk_event_set_device (event, device_manager_win32->core_keyboard);
+	      gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
 	      build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
 
 	      _gdk_win32_append_event (event);
@@ -2179,7 +2198,8 @@ gdk_event_translate (MSG  *msg,
 	      /* Build a key release event.  */
 	      event = gdk_event_new (GDK_KEY_RELEASE);
 	      event->key.window = window;
-        gdk_event_set_device (event, GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+	      gdk_event_set_device (event, device_manager_win32->core_keyboard);
+	      gdk_event_set_source_device (event, device_manager_win32->system_keyboard);
 	      build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
 
 	      _gdk_win32_append_event (event);
@@ -2361,19 +2381,23 @@ gdk_event_translate (MSG  *msg,
       current_root_x = msg->pt.x + _gdk_offset_x;
       current_root_y = msg->pt.y + _gdk_offset_y;
 
-      event = gdk_event_new (GDK_MOTION_NOTIFY);
-      event->motion.window = window;
-      event->motion.time = _gdk_win32_get_next_tick (msg->time);
-      event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
-      event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
-      event->motion.x_root = current_root_x;
-      event->motion.y_root = current_root_y;
-      event->motion.axes = NULL;
-      event->motion.state = build_pointer_event_state (msg);
-      event->motion.is_hint = FALSE;
-      gdk_event_set_device (event, _gdk_display->core_pointer);
+      if (!_gdk_input_ignore_core)
+	{
+	  event = gdk_event_new (GDK_MOTION_NOTIFY);
+	  event->motion.window = window;
+	  event->motion.time = _gdk_win32_get_next_tick (msg->time);
+	  event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
+	  event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
+	  event->motion.x_root = current_root_x;
+	  event->motion.y_root = current_root_y;
+	  event->motion.axes = NULL;
+	  event->motion.state = build_pointer_event_state (msg);
+	  event->motion.is_hint = FALSE;
+	  gdk_event_set_device (event, device_manager_win32->core_pointer);
+	  gdk_event_set_source_device (event, device_manager_win32->system_pointer);
 
-      _gdk_win32_append_event (event);
+	  _gdk_win32_append_event (event);
+	}
 
       return_val = TRUE;
       break;
@@ -2485,7 +2509,8 @@ gdk_event_translate (MSG  *msg,
       event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
       event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
       event->scroll.state = build_pointer_event_state (msg);
-      gdk_event_set_device (event, _gdk_display->core_pointer);
+      gdk_event_set_device (event, device_manager_win32->core_pointer);
+      gdk_event_set_source_device (event, device_manager_win32->system_pointer);
 
       _gdk_win32_append_event (event);
       
@@ -2763,9 +2788,6 @@ gdk_event_translate (MSG  *msg,
 	      !IsIconic (msg->hwnd) &&
 	      !GDK_WINDOW_DESTROYED (window))
 	    _gdk_win32_emit_configure_event (window);
-
-	  if (_gdk_device_wintab_wants_events (window))
-	    _gdk_device_wintab_update_window_coords (window);
 	}
 
       if ((windowpos->flags & SWP_HIDEWINDOW) &&
diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c
index 223cf46..19101cb 100644
--- a/gdk/win32/gdkinput.c
+++ b/gdk/win32/gdkinput.c
@@ -75,6 +75,6 @@ _gdk_input_init (GdkDisplay *display)
   _gdk_input_devices = g_list_concat (_gdk_input_devices,
                                       g_list_copy (device_manager->wintab_devices));
 
-  _gdk_input_wintab_init_check (device_manager);
+  _gdk_input_wintab_init_check (GDK_DEVICE_MANAGER (device_manager));
 
 }



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