[gtk+/xi2] win32: Implement GdkDeviceManager and new _gdk_windowing_* functions.



commit d729fafee6eb64b54e1988827b9963049e68bf6e
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun May 16 21:28:28 2010 +0200

    win32: Implement GdkDeviceManager and new _gdk_windowing_* functions.
    
    GdkDeviceManagerWin32 provides GdkDeviceWin32 (pointer, keyboard) and
    GdkDeviceWintab (tablets with wintab support), all events that should
    be containing a GdkDevice are doing so now.

 gdk/win32/Makefile.am              |    8 +-
 gdk/win32/gdkdevice-win32.c        |  396 ++++++++++
 gdk/win32/gdkdevice-win32.h        |   51 ++
 gdk/win32/gdkdevice-wintab.c       |  386 ++++++++++
 gdk/win32/gdkdevice-wintab.h       |   79 ++
 gdk/win32/gdkdevicemanager-win32.c | 1089 ++++++++++++++++++++++++++++
 gdk/win32/gdkdevicemanager-win32.h |   59 ++
 gdk/win32/gdkdnd-win32.c           |  222 ++++--
 gdk/win32/gdkevents-win32.c        |  266 ++++----
 gdk/win32/gdkinput-win32.c         | 1392 ------------------------------------
 gdk/win32/gdkinput-win32.h         |  147 ----
 gdk/win32/gdkinput.c               |  379 +---------
 gdk/win32/gdkmain-win32.c          |    3 +-
 gdk/win32/gdkwindow-win32.c        |  246 ++-----
 14 files changed, 2440 insertions(+), 2283 deletions(-)
---
diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am
index 17d048e..e6c5b2d 100644
--- a/gdk/win32/Makefile.am
+++ b/gdk/win32/Makefile.am
@@ -29,6 +29,12 @@ libgdk_win32_la_SOURCES = \
 	gdkapplaunchcontext-win32.c \
 	gdkcolor-win32.c \
 	gdkcursor-win32.c \
+	gdkdevicemanager-win32.c \
+	gdkdevicemanager-win32.h \
+	gdkdevice-win32.c \
+	gdkdevice-win32.h \
+	gdkdevice-wintab.c \
+	gdkdevice-wintab.h \
 	gdkdisplay-win32.c \
 	gdkdnd-win32.c \
 	gdkdrawable-win32.c \
@@ -41,8 +47,6 @@ libgdk_win32_la_SOURCES = \
 	gdkim-win32.c \
 	gdkimage-win32.c \
 	gdkinput.c \
-	gdkinput-win32.c \
-	gdkinput-win32.h \
 	gdkkeys-win32.c \
 	gdkmain-win32.c \
 	gdkpixmap-win32.c \
diff --git a/gdk/win32/gdkdevice-win32.c b/gdk/win32/gdkdevice-win32.c
new file mode 100644
index 0000000..9e4eb81
--- /dev/null
+++ b/gdk/win32/gdkdevice-win32.c
@@ -0,0 +1,396 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+
+#include <windowsx.h>
+#include <objbase.h>
+
+#include "gdkdevice-win32.h"
+#include "gdkwin32.h"
+
+static gboolean gdk_device_win32_get_history (GdkDevice      *device,
+                                              GdkWindow      *window,
+                                              guint32         start,
+                                              guint32         stop,
+                                              GdkTimeCoord ***events,
+                                              guint          *n_events);
+static void gdk_device_win32_get_state (GdkDevice       *device,
+                                        GdkWindow       *window,
+                                        gdouble         *axes,
+                                        GdkModifierType *mask);
+static void gdk_device_win32_set_window_cursor (GdkDevice *device,
+                                                GdkWindow *window,
+                                                GdkCursor *cursor);
+static void gdk_device_win32_warp (GdkDevice *device,
+                                   GdkScreen *screen,
+                                   gint       x,
+                                   gint       y);
+static gboolean gdk_device_win32_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_win32_grab   (GdkDevice     *device,
+                                              GdkWindow     *window,
+                                              gboolean       owner_events,
+                                              GdkEventMask   event_mask,
+                                              GdkWindow     *confine_to,
+                                              GdkCursor     *cursor,
+                                              guint32        time_);
+static void          gdk_device_win32_ungrab (GdkDevice     *device,
+                                              guint32        time_);
+static GdkWindow * gdk_device_win32_window_at_position (GdkDevice       *device,
+                                                        gint            *win_x,
+                                                        gint            *win_y,
+                                                        GdkModifierType *mask,
+                                                        gboolean         get_toplevel);
+static void      gdk_device_win32_select_window_events (GdkDevice       *device,
+                                                        GdkWindow       *window,
+                                                        GdkEventMask     event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceWin32, gdk_device_win32, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_win32_class_init (GdkDeviceWin32Class *klass)
+{
+  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+  device_class->get_history = gdk_device_win32_get_history;
+  device_class->get_state = gdk_device_win32_get_state;
+  device_class->set_window_cursor = gdk_device_win32_set_window_cursor;
+  device_class->warp = gdk_device_win32_warp;
+  device_class->query_state = gdk_device_win32_query_state;
+  device_class->grab = gdk_device_win32_grab;
+  device_class->ungrab = gdk_device_win32_ungrab;
+  device_class->window_at_position = gdk_device_win32_window_at_position;
+  device_class->select_window_events = gdk_device_win32_select_window_events;
+}
+
+static void
+gdk_device_win32_init (GdkDeviceWin32 *device_win32)
+{
+  GdkDevice *device;
+
+  device = GDK_DEVICE (device_win32);
+
+  _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
+  _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
+}
+
+static gboolean
+gdk_device_win32_get_history (GdkDevice      *device,
+                              GdkWindow      *window,
+                              guint32         start,
+                              guint32         stop,
+                              GdkTimeCoord ***events,
+                              guint          *n_events)
+{
+  return FALSE;
+}
+
+static void
+gdk_device_win32_get_state (GdkDevice       *device,
+                            GdkWindow       *window,
+                            gdouble         *axes,
+                            GdkModifierType *mask)
+{
+  gint x_int, y_int;
+
+  gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+  if (axes)
+    {
+      axes[0] = x_int;
+      axes[1] = y_int;
+    }
+}
+
+static void
+gdk_device_win32_set_window_cursor (GdkDevice *device,
+                                    GdkWindow *window,
+                                    GdkCursor *cursor)
+{
+  GdkCursorPrivate *cursor_private;
+  GdkWindowObject *parent_window;
+  GdkWindowImplWin32 *impl;
+  HCURSOR hcursor;
+  HCURSOR hprevcursor;
+
+  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+  cursor_private = (GdkCursorPrivate*) 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.
+           */
+          GdkWindowObject *curr_window_obj = GDK_WINDOW_OBJECT (curr_window);
+
+          while (curr_window_obj &&
+                 !GDK_WINDOW_IMPL_WIN32 (curr_window_obj->impl)->hcursor)
+            {
+              curr_window_obj = curr_window_obj->parent;
+              if (curr_window_obj == GDK_WINDOW_OBJECT (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_OBJECT (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_win32_warp (GdkDevice *device,
+                       GdkScreen *screen,
+                       gint       x,
+                       gint       y)
+{
+  SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
+}
+
+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 gboolean
+gdk_device_win32_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)
+{
+  gboolean return_val;
+  POINT point;
+  HWND hwnd, hwndc;
+
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
+  
+  return_val = TRUE;
+
+  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 ((GdkNativeWindow) hwndc);
+      else
+        *child_window = NULL; /* Direct child unknown to gdk */
+    }
+
+  if (root_window)
+    {
+      GdkScreen *screen;
+
+      screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+      *root_window = gdk_screen_get_root_window (screen);
+    }
+
+  if (mask)
+    *mask = get_current_mask ();
+
+  return TRUE;
+}
+
+static GdkGrabStatus
+gdk_device_win32_grab (GdkDevice    *device,
+                       GdkWindow    *window,
+                       gboolean      owner_events,
+                       GdkEventMask  event_mask,
+                       GdkWindow    *confine_to,
+                       GdkCursor    *cursor,
+                       guint32       time_)
+{
+  if (device->source != GDK_SOURCE_KEYBOARD)
+    SetCapture (GDK_WINDOW_HWND (window));
+
+  return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_win32_ungrab (GdkDevice *device,
+                         guint32    time_)
+{
+  GdkDisplay *display;
+
+  display = gdk_device_get_display (device);
+
+  if (device->source != GDK_SOURCE_KEYBOARD)
+    ReleaseCapture ();
+}
+
+static GdkWindow *
+gdk_device_win32_window_at_position (GdkDevice       *device,
+                                     gint            *win_x,
+                                     gint            *win_y,
+                                     GdkModifierType *mask,
+                                     gboolean         get_toplevel)
+{
+  GdkWindow *window;
+  POINT point, pointc;
+  HWND hwnd, hwndc;
+  RECT rect;
+
+  GetCursorPos (&pointc);
+  point = pointc;
+  hwnd = WindowFromPoint (point);
+
+  if (hwnd == NULL)
+    {
+      window = _gdk_root;
+      *win_x = pointc.x + _gdk_offset_x;
+      *win_y = pointc.y + _gdk_offset_y;
+      return window;
+    }
+
+  ScreenToClient (hwnd, &point);
+
+  do
+    {
+      if (get_toplevel &&
+          (window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd)) != NULL &&
+          GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+        break;
+
+      hwndc = ChildWindowFromPoint (hwnd, point);
+      ClientToScreen (hwnd, &point);
+      ScreenToClient (hwndc, &point);
+    }
+  while (hwndc != hwnd && (hwnd = hwndc, 1));
+
+  window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
+
+  if (window && (win_x || win_y))
+    {
+      GetClientRect (hwnd, &rect);
+      *win_x = point.x - rect.left;
+      *win_y = point.y - rect.top;
+    }
+
+  return window;
+}
+
+static void
+gdk_device_win32_select_window_events (GdkDevice    *device,
+                                       GdkWindow    *window,
+                                       GdkEventMask  event_mask)
+{
+}
diff --git a/gdk/win32/gdkdevice-win32.h b/gdk/win32/gdkdevice-win32.h
new file mode 100644
index 0000000..ef9c322
--- /dev/null
+++ b/gdk/win32/gdkdevice-win32.h
@@ -0,0 +1,51 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDK_DEVICE_WIN32_H__
+#define __GDK_DEVICE_WIN32_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_WIN32         (gdk_device_win32_get_type ())
+#define GDK_DEVICE_WIN32(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32))
+#define GDK_DEVICE_WIN32_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32Class))
+#define GDK_IS_DEVICE_WIN32(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_WIN32))
+#define GDK_IS_DEVICE_WIN32_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_WIN32))
+#define GDK_DEVICE_WIN32_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_WIN32, GdkDeviceWin32Class))
+
+typedef struct _GdkDeviceWin32 GdkDeviceWin32;
+typedef struct _GdkDeviceWin32Class GdkDeviceWin32Class;
+
+struct _GdkDeviceWin32
+{
+  GdkDevice parent_instance;
+};
+
+struct _GdkDeviceWin32Class
+{
+  GdkDeviceClass parent_class;
+};
+
+GType gdk_device_win32_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_WIN32_H__ */
diff --git a/gdk/win32/gdkdevice-wintab.c b/gdk/win32/gdkdevice-wintab.c
new file mode 100644
index 0000000..392e10b
--- /dev/null
+++ b/gdk/win32/gdkdevice-wintab.c
@@ -0,0 +1,386 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <gdk/gdkwindow.h>
+
+#include <windowsx.h>
+#include <objbase.h>
+
+#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,
+                                               guint32         stop,
+                                               GdkTimeCoord ***events,
+                                               guint          *n_events);
+static void gdk_device_wintab_get_state (GdkDevice       *device,
+                                         GdkWindow       *window,
+                                         gdouble         *axes,
+                                         GdkModifierType *mask);
+static void gdk_device_wintab_set_window_cursor (GdkDevice *device,
+                                                 GdkWindow *window,
+                                                 GdkCursor *cursor);
+static void gdk_device_wintab_warp (GdkDevice *device,
+                                    GdkScreen *screen,
+                                    gint       x,
+                                    gint       y);
+static gboolean gdk_device_wintab_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_wintab_grab   (GdkDevice     *device,
+                                               GdkWindow     *window,
+                                               gboolean       owner_events,
+                                               GdkEventMask   event_mask,
+                                               GdkWindow     *confine_to,
+                                               GdkCursor     *cursor,
+                                               guint32        time_);
+static void          gdk_device_wintab_ungrab (GdkDevice     *device,
+                                               guint32        time_);
+static GdkWindow * gdk_device_wintab_window_at_position (GdkDevice       *device,
+                                                         gint            *win_x,
+                                                         gint            *win_y,
+                                                         GdkModifierType *mask,
+                                                         gboolean         get_toplevel);
+static void      gdk_device_wintab_select_window_events (GdkDevice       *device,
+                                                         GdkWindow       *window,
+                                                         GdkEventMask     event_mask);
+
+
+G_DEFINE_TYPE (GdkDeviceWintab, gdk_device_wintab, GDK_TYPE_DEVICE)
+
+static void
+gdk_device_wintab_class_init (GdkDeviceWintabClass *klass)
+{
+  GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+  device_class->get_history = gdk_device_wintab_get_history;
+  device_class->get_state = gdk_device_wintab_get_state;
+  device_class->set_window_cursor = gdk_device_wintab_set_window_cursor;
+  device_class->warp = gdk_device_wintab_warp;
+  device_class->query_state = gdk_device_wintab_query_state;
+  device_class->grab = gdk_device_wintab_grab;
+  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
+gdk_device_wintab_init (GdkDeviceWintab *device_wintab)
+{
+  GdkDevice *device;
+
+  device = GDK_DEVICE (device_wintab);
+}
+
+static gboolean
+gdk_device_wintab_get_history (GdkDevice      *device,
+                               GdkWindow      *window,
+                               guint32         start,
+                               guint32         stop,
+                               GdkTimeCoord ***events,
+                               guint          *n_events)
+{
+  return FALSE;
+}
+
+static void
+gdk_device_wintab_get_state (GdkDevice       *device,
+                             GdkWindow       *window,
+                             gdouble         *axes,
+                             GdkModifierType *mask)
+{
+  GdkDeviceWintab *device_wintab;
+
+  device_wintab = GDK_DEVICE_WINTAB (device);
+
+  /* For now just use the last known button and axis state of the device.
+   * Since graphical tablets send an insane amount of motion events each
+   * second, the info should be fairly up to date */
+  if (mask)
+    {
+      gdk_window_get_pointer (window, NULL, NULL, 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));
+    }
+
+  if (device_wintab->last_axis_data)
+    _gdk_device_wintab_translate_axes (device, window, axes, NULL, NULL);
+}
+
+static void
+gdk_device_wintab_set_window_cursor (GdkDevice *device,
+                                     GdkWindow *window,
+                                     GdkCursor *cursor)
+{
+}
+
+static void
+gdk_device_wintab_warp (GdkDevice *device,
+                        GdkScreen *screen,
+                        gint       x,
+                        gint       y)
+{
+}
+
+static gboolean
+gdk_device_wintab_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)
+{
+  return FALSE;
+}
+
+static GdkGrabStatus
+gdk_device_wintab_grab (GdkDevice    *device,
+                        GdkWindow    *window,
+                        gboolean      owner_events,
+                        GdkEventMask  event_mask,
+                        GdkWindow    *confine_to,
+                        GdkCursor    *cursor,
+                        guint32       time_)
+{
+  return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_device_wintab_ungrab (GdkDevice *device,
+                          guint32    time_)
+{
+}
+
+static GdkWindow *
+gdk_device_wintab_window_at_position (GdkDevice       *device,
+                                      gint            *win_x,
+                                      gint            *win_y,
+                                      GdkModifierType *mask,
+                                      gboolean         get_toplevel)
+{
+  return NULL;
+}
+
+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);
+        }
+    }
+}
+
+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
+_gdk_device_wintab_translate_axes (GdkDeviceWintab *device_wintab,
+                                   GdkWindow       *window,
+                                   gdouble         *axes,
+                                   gdouble         *x,
+                                   gdouble         *y)
+{
+  GdkDevice *device;
+  GdkWindow *impl_window;
+  gdouble root_x, root_y;
+  gdouble temp_x, temp_y;
+  gint i;
+
+  device = GDK_DEVICE (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;
+
+  for (i = 0; i < device->num_axes; i++)
+    {
+      GdkAxisUse use;
+
+      use = _gdk_device_get_axis_use (device, i);
+
+      switch (use)
+        {
+        case GDK_AXIS_X:
+        case GDK_AXIS_Y:
+          if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
+            _gdk_device_translate_window_coord (device, window, i,
+                                                device_wintab->last_axis_data[i],
+                                                &axes[i]);
+          else
+            _gdk_device_translate_screen_coord (device, window,
+                                                root_x, root_y, i,
+                                                device_wintab->last_axis_data[i],
+                                                &axes[i]);
+          if (use == GDK_AXIS_X)
+            temp_x = axes[i];
+          else if (use == GDK_AXIS_Y)
+            temp_y = axes[i];
+
+          break;
+        default:
+          _gdk_device_translate_axis (device, i,
+                                      device_wintab->last_axis_data[i],
+                                      &axes[i]);
+          break;
+        }
+    }
+
+  if (x)
+    *x = temp_x;
+
+  if (y)
+    *y = temp_y;
+}
+
+void
+_gdk_input_check_extension_events (GdkDevice *device)
+{
+  GSList *l;
+
+  if (!GDK_IS_DEVICE_WINTAB (device))
+    return;
+
+  for (l = input_windows; l; l = l->next)
+    {
+      GdkWindowObject *window_private;
+      GdkEventMask event_mask = 0;
+
+      window_private = l->data;
+
+      if (gdk_device_get_mode (device) != GDK_MODE_DISABLED)
+        event_mask = window_private->extension_events;
+
+      gdk_window_set_device_events (GDK_WINDOW (window_private),
+                                    device, event_mask);
+    }
+}
diff --git a/gdk/win32/gdkdevice-wintab.h b/gdk/win32/gdkdevice-wintab.h
new file mode 100644
index 0000000..79fae8a
--- /dev/null
+++ b/gdk/win32/gdkdevice-wintab.h
@@ -0,0 +1,79 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDK_DEVICE_WINTAB_H__
+#define __GDK_DEVICE_WINTAB_H__
+
+#include <gdk/gdkdeviceprivate.h>
+
+#include <windows.h>
+#include <wintab.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_WINTAB         (gdk_device_wintab_get_type ())
+#define GDK_DEVICE_WINTAB(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintab))
+#define GDK_DEVICE_WINTAB_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintabClass))
+#define GDK_IS_DEVICE_WINTAB(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_WINTAB))
+#define GDK_IS_DEVICE_WINTAB_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_WINTAB))
+#define GDK_DEVICE_WINTAB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_WINTAB, GdkDeviceWintabClass))
+
+typedef struct _GdkDeviceWintab GdkDeviceWintab;
+typedef struct _GdkDeviceWintabClass GdkDeviceWintabClass;
+
+struct _GdkDeviceWintab
+{
+  GdkDevice parent_instance;
+
+  gint *last_axis_data;
+  gint button_state;
+
+  /* WINTAB stuff: */
+  HCTX hctx;
+  /* Cursor number */
+  UINT cursor;
+  /* The cursor's CSR_PKTDATA */
+  WTPKT pktdata;
+  /* Azimuth and altitude axis */
+  AXIS orientation_axes[2];
+};
+
+struct _GdkDeviceWintabClass
+{
+  GdkDeviceClass parent_class;
+};
+
+GType gdk_device_wintab_get_type (void) G_GNUC_CONST;
+
+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,
+                                                gdouble         *x,
+                                                gdouble         *y);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_WINTAB_H__ */
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
new file mode 100644
index 0000000..eea8142
--- /dev/null
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -0,0 +1,1089 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <gdk/gdk.h>
+#include "gdkprivate-win32.h"
+#include "gdkdevicemanager-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-win32.h"
+#include "gdkdevice-wintab.h"
+
+#include <windows.h>
+#include <wintab.h>
+
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y  | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+/* We want everything in absolute mode */
+#define PACKETMODE (0)
+#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_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);
+
+static t_WTInfoA p_WTInfoA;
+static t_WTInfoW p_WTInfoW;
+static t_WTEnable p_WTEnable;
+static t_WTOpenA p_WTOpenA;
+static t_WTOverlap p_WTOverlap;
+static t_WTPacket p_WTPacket;
+static t_WTQueueSizeSet p_WTQueueSizeSet;
+
+
+static void    gdk_device_manager_win32_finalize    (GObject *object);
+static void    gdk_device_manager_win32_constructed (GObject *object);
+
+static GList * gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
+                                                      GdkDeviceType     type);
+
+
+G_DEFINE_TYPE (GdkDeviceManagerWin32, gdk_device_manager_win32, GDK_TYPE_DEVICE_MANAGER)
+
+static void
+gdk_device_manager_win32_class_init (GdkDeviceManagerWin32Class *klass)
+{
+  GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gdk_device_manager_win32_finalize;
+  object_class->constructed = gdk_device_manager_win32_constructed;
+  device_manager_class->list_devices = gdk_device_manager_win32_list_devices;
+}
+
+static GdkDevice *
+create_core_pointer (GdkDeviceManager *device_manager)
+{
+  return g_object_new (GDK_TYPE_DEVICE_WIN32,
+                       "name", "Core Pointer",
+                       "type", GDK_DEVICE_TYPE_MASTER,
+                       "input-source", GDK_SOURCE_MOUSE,
+                       "input-mode", GDK_MODE_SCREEN,
+                       "has-cursor", TRUE,
+                       "display", _gdk_display,
+                       "device-manager", device_manager,
+                       NULL);
+}
+
+static GdkDevice *
+create_core_keyboard (GdkDeviceManager *device_manager)
+{
+  return g_object_new (GDK_TYPE_DEVICE_WIN32,
+                       "name", "Core Keyboard",
+                       "type", GDK_DEVICE_TYPE_MASTER,
+                       "input-source", GDK_SOURCE_KEYBOARD,
+                       "input-mode", GDK_MODE_SCREEN,
+                       "has-cursor", FALSE,
+                       "display", _gdk_display,
+                       "device-manager", device_manager,
+                       NULL);
+}
+
+static void
+gdk_device_manager_win32_init (GdkDeviceManagerWin32 *device_manager_win32)
+{
+}
+
+static void
+gdk_device_manager_win32_finalize (GObject *object)
+{
+  GdkDeviceManagerWin32 *device_manager_win32;
+
+  device_manager_win32 = GDK_DEVICE_MANAGER_WIN32 (object);
+
+  g_object_unref (device_manager_win32->core_pointer);
+  g_object_unref (device_manager_win32->core_keyboard);
+
+  G_OBJECT_CLASS (gdk_device_manager_win32_parent_class)->finalize (object);
+}
+
+#if DEBUG_WINTAB
+
+static void
+print_lc(LOGCONTEXT *lc)
+{
+  g_print ("lcName = %s\n", lc->lcName);
+  g_print ("lcOptions =");
+  if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
+  if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
+  if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
+  if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
+  if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
+  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
+  g_print ("\n");
+  g_print ("lcStatus =");
+  if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
+  if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
+  if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
+  g_print ("\n");
+  g_print ("lcLocks =");
+  if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
+  if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
+  if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
+  if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
+  g_print ("\n");
+  g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
+	  lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
+  g_print ("lcPktData =");
+  if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktData & PK_X) g_print (" PK_X");
+  if (lc->lcPktData & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktData & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcPktMode =");
+  if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktMode & PK_X) g_print (" PK_X");
+  if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcMoveMask =");
+  if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcMoveMask & PK_X) g_print (" PK_X");
+  if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
+  if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
+  if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
+	  (guint) lc->lcBtnDnMask, (guint) lc->lcBtnUpMask);
+  g_print ("lcInOrgX = %ld, lcInOrgY = %ld, lcInOrgZ = %ld\n",
+	  lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
+  g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
+	  lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
+  g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
+	  lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
+  g_print ("lcOutExtX = %ld, lcOutExtY = %ld, lcOutExtZ = %ld\n",
+	  lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
+  g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
+	  lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
+  g_print ("lcSysMode = %d\n", lc->lcSysMode);
+  g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
+	  lc->lcSysOrgX, lc->lcSysOrgY);
+  g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
+	  lc->lcSysExtX, lc->lcSysExtY);
+  g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
+	  lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
+}
+
+static void
+print_cursor (int index)
+{
+  int size;
+  int i;
+  char *name;
+  BOOL active;
+  WTPKT wtpkt;
+  BYTE buttons;
+  BYTE buttonbits;
+  char *btnnames;
+  char *p;
+  BYTE buttonmap[32];
+  BYTE sysbtnmap[32];
+  BYTE npbutton;
+  UINT npbtnmarks[2];
+  UINT *npresponse;
+  BYTE tpbutton;
+  UINT tpbtnmarks[2];
+  UINT *tpresponse;
+  DWORD physid;
+  UINT mode;
+  UINT minpktdata;
+  UINT minbuttons;
+  UINT capabilities;
+
+  size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, NULL);
+  name = g_malloc (size + 1);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_NAME, name);
+  g_print ("NAME: %s\n", name);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_ACTIVE, &active);
+  g_print ("ACTIVE: %s\n", active ? "YES" : "NO");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_PKTDATA, &wtpkt);
+  g_print ("PKTDATA: %#x:", (guint) wtpkt);
+#define BIT(x) if (wtpkt & PK_##x) g_print (" " #x)
+  BIT (CONTEXT);
+  BIT (STATUS);
+  BIT (TIME);
+  BIT (CHANGED);
+  BIT (SERIAL_NUMBER);
+  BIT (BUTTONS);
+  BIT (X);
+  BIT (Y);
+  BIT (Z);
+  BIT (NORMAL_PRESSURE);
+  BIT (TANGENT_PRESSURE);
+  BIT (ORIENTATION);
+  BIT (ROTATION);
+#undef BIT
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONS, &buttons);
+  g_print ("BUTTONS: %d\n", buttons);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONBITS, &buttonbits);
+  g_print ("BUTTONBITS: %d\n", buttonbits);
+  size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, NULL);
+  g_print ("BTNNAMES:");
+  if (size > 0)
+    {
+      btnnames = g_malloc (size + 1);
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_BTNNAMES, btnnames);
+      p = btnnames;
+      while (*p)
+        {
+          g_print (" %s", p);
+          p += strlen (p) + 1;
+        }
+    }
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_BUTTONMAP, buttonmap);
+  g_print ("BUTTONMAP:");
+  for (i = 0; i < buttons; i++)
+    g_print (" %d", buttonmap[i]);
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_SYSBTNMAP, sysbtnmap);
+  g_print ("SYSBTNMAP:");
+  for (i = 0; i < buttons; i++)
+    g_print (" %d", sysbtnmap[i]);
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBUTTON, &npbutton);
+  g_print ("NPBUTTON: %d\n", npbutton);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPBTNMARKS, npbtnmarks);
+  g_print ("NPBTNMARKS: %d %d\n", npbtnmarks[0], npbtnmarks[1]);
+  size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, NULL);
+  g_print ("NPRESPONSE:");
+  if (size > 0)
+    {
+      npresponse = g_malloc (size);
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_NPRESPONSE, npresponse);
+      for (i = 0; i < size / sizeof (UINT); i++)
+        g_print (" %d", npresponse[i]);
+    }
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBUTTON, &tpbutton);
+  g_print ("TPBUTTON: %d\n", tpbutton);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPBTNMARKS, tpbtnmarks);
+  g_print ("TPBTNMARKS: %d %d\n", tpbtnmarks[0], tpbtnmarks[1]);
+  size = (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, NULL);
+  g_print ("TPRESPONSE:");
+  if (size > 0)
+    {
+      tpresponse = g_malloc (size);
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_TPRESPONSE, tpresponse);
+      for (i = 0; i < size / sizeof (UINT); i++)
+        g_print (" %d", tpresponse[i]);
+    }
+  g_print ("\n");
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_PHYSID, &physid);
+  g_print ("PHYSID: %#x\n", (guint) physid);
+  (*p_WTInfoA) (WTI_CURSORS + index, CSR_CAPABILITIES, &capabilities);
+  g_print ("CAPABILITIES: %#x:", capabilities);
+#define BIT(x) if (capabilities & CRC_##x) g_print (" " #x)
+  BIT (MULTIMODE);
+  BIT (AGGREGATE);
+  BIT (INVERT);
+#undef BIT
+  g_print ("\n");
+  if (capabilities & CRC_MULTIMODE)
+    {
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_MODE, &mode);
+      g_print ("MODE: %d\n", mode);
+    }
+  if (capabilities & CRC_AGGREGATE)
+    {
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINPKTDATA, &minpktdata);
+      g_print ("MINPKTDATA: %d\n", minpktdata);
+      (*p_WTInfoA) (WTI_CURSORS + index, CSR_MINBUTTONS, &minbuttons);
+      g_print ("MINBUTTONS: %d\n", minbuttons);
+    }
+}
+#endif
+
+static void
+_gdk_input_wintab_init_check (GdkDeviceManagerWin32 *device_manager)
+{
+  static gboolean wintab_initialized = FALSE;
+  GdkDeviceWintab *device;
+  GdkWindowAttr wa;
+  WORD specversion;
+  HCTX *hctx;
+  UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
+  BOOL active;
+  DWORD physid;
+  AXIS axis_x, axis_y, axis_npressure, axis_or[3];
+  int i, devix, cursorix, num_axes = 0;
+  wchar_t devname[100], csrname[100];
+  gchar *devname_utf8, *csrname_utf8, *device_name;
+  BOOL defcontext_done;
+  HMODULE wintab32;
+
+  if (wintab_initialized)
+    return;
+
+  wintab_initialized = TRUE;
+
+  wintab_contexts = NULL;
+
+  if (_gdk_input_ignore_wintab)
+    return;
+
+  if ((wintab32 = LoadLibrary ("wintab32.dll")) == NULL)
+    return;
+
+  if ((p_WTInfoA = (t_WTInfoA) GetProcAddress (wintab32, "WTInfoA")) == NULL)
+    return;
+  if ((p_WTInfoW = (t_WTInfoW) GetProcAddress (wintab32, "WTInfoW")) == NULL)
+    return;
+  if ((p_WTEnable = (t_WTEnable) GetProcAddress (wintab32, "WTEnable")) == NULL)
+    return;
+  if ((p_WTOpenA = (t_WTOpenA) GetProcAddress (wintab32, "WTOpenA")) == NULL)
+    return;
+  if ((p_WTOverlap = (t_WTOverlap) GetProcAddress (wintab32, "WTOverlap")) == NULL)
+    return;
+  if ((p_WTPacket = (t_WTPacket) GetProcAddress (wintab32, "WTPacket")) == NULL)
+    return;
+  if ((p_WTQueueSizeSet = (t_WTQueueSizeSet) GetProcAddress (wintab32, "WTQueueSizeSet")) == NULL)
+    return;
+
+  if (!(*p_WTInfoA) (0, 0, NULL))
+    return;
+
+  (*p_WTInfoA) (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
+  GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
+			    HIBYTE (specversion), LOBYTE (specversion)));
+  (*p_WTInfoA) (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
+  (*p_WTInfoA) (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
+#if DEBUG_WINTAB
+  GDK_NOTE (INPUT, g_print ("NDEVICES: %d, NCURSORS: %d\n",
+			    ndevices, ncursors));
+#endif
+  /* Create a dummy window to receive wintab events */
+  wa.wclass = GDK_INPUT_OUTPUT;
+  wa.event_mask = GDK_ALL_EVENTS_MASK;
+  wa.width = 2;
+  wa.height = 2;
+  wa.x = -100;
+  wa.y = -100;
+  wa.window_type = GDK_WINDOW_TOPLEVEL;
+  if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
+    {
+      g_warning ("gdk_input_wintab_init: gdk_window_new failed");
+      return;
+    }
+  g_object_ref (wintab_window);
+
+  for (devix = 0; devix < ndevices; devix++)
+    {
+      LOGCONTEXT lc;
+
+      /* We open the Wintab device (hmm, what if there are several, or
+       * can there even be several, probably not?) as a system
+       * pointing device, i.e. it controls the normal Windows
+       * cursor. This seems much more natural.
+       */
+
+      (*p_WTInfoW) (WTI_DEVICES + devix, DVC_NAME, devname);
+      devname_utf8 = g_utf16_to_utf8 (devname, -1, NULL, NULL, NULL);
+#ifdef DEBUG_WINTAB
+      GDK_NOTE (INPUT, (g_print("Device %d: %s\n", devix, devname_utf8)));
+#endif
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
+
+      defcontext_done = FALSE;
+      if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
+        {
+          /* Try to get device-specific default context */
+          /* Some drivers, e.g. Aiptek, don't provide this info */
+          if ((*p_WTInfoA) (WTI_DSCTXS + devix, 0, &lc) > 0)
+            defcontext_done = TRUE;
+#if DEBUG_WINTAB
+          if (defcontext_done)
+            GDK_NOTE (INPUT, (g_print("Using device-specific default context\n")));
+          else
+            GDK_NOTE (INPUT, (g_print("Note: Driver did not provide device specific default context info despite claiming to support version 1.1\n")));
+#endif
+        }
+
+      if (!defcontext_done)
+        (*p_WTInfoA) (WTI_DEFSYSCTX, 0, &lc);
+#if DEBUG_WINTAB
+      GDK_NOTE (INPUT, (g_print("Default context:\n"), print_lc(&lc)));
+#endif
+      lc.lcOptions |= CXO_MESSAGES;
+      lc.lcStatus = 0;
+      lc.lcMsgBase = WT_DEFBASE;
+      lc.lcPktRate = 0;
+      lc.lcPktData = PACKETDATA;
+      lc.lcPktMode = PACKETMODE;
+      lc.lcMoveMask = PACKETDATA;
+      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.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+#if DEBUG_WINTAB
+      GDK_NOTE (INPUT, (g_print("context for device %d:\n", devix),
+			print_lc(&lc)));
+#endif
+      hctx = g_new (HCTX, 1);
+      if ((*hctx = (*p_WTOpenA) (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
+        {
+          g_warning ("gdk_input_wintab_init: WTOpen failed");
+          return;
+        }
+      GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
+                                devix, *hctx));
+
+      wintab_contexts = g_list_append (wintab_contexts, hctx);
+#if 0
+      (*p_WTEnable) (*hctx, TRUE);
+#endif
+      (*p_WTOverlap) (*hctx, TRUE);
+
+#if DEBUG_WINTAB
+      GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
+			print_lc(&lc)));
+#endif
+      /* Increase packet queue size to reduce the risk of lost packets.
+       * According to the specs, if the function fails we must try again
+       * with a smaller queue size.
+       */
+      GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
+      for (i = 32; i >= 1; i >>= 1)
+        {
+          if ((*p_WTQueueSizeSet) (*hctx, i))
+            {
+              GDK_NOTE (INPUT, g_print("Queue size set to %d\n", i));
+              break;
+            }
+        }
+      if (!i)
+        GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
+      for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
+        {
+#ifdef DEBUG_WINTAB
+          GDK_NOTE (INPUT, (g_print("Cursor %d:\n", cursorix), print_cursor (cursorix)));
+#endif
+          active = FALSE;
+          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
+          if (!active)
+            continue;
+
+          /* Wacom tablets seem to report cursors corresponding to
+           * nonexistent pens or pucks. At least my ArtPad II reports
+           * six cursors: a puck, pressure stylus and eraser stylus,
+           * and then the same three again. I only have a
+           * pressure-sensitive pen. The puck instances, and the
+           * second instances of the styluses report physid zero. So
+           * at least for Wacom, skip cursors with physid zero.
+           */
+          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PHYSID, &physid);
+          if (wcscmp (devname, L"WACOM Tablet") == 0 && physid == 0)
+            continue;
+
+          (*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
+          csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
+          device_name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
+
+          device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
+                                 "name", device_name,
+                                 "type", GDK_DEVICE_TYPE_SLAVE,
+                                 "source", GDK_SOURCE_PEN,
+                                 "mode", GDK_MODE_SCREEN,
+                                 "has-cursor", FALSE,
+                                 "display", _gdk_display,
+                                 "device-manager", device_manager,
+                                 NULL);
+
+          g_free (csrname_utf8);
+
+          device->hctx = *hctx;
+          device->cursor = cursorix;
+          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &device->pktdata);
+
+          if (device->pktdata & PK_X)
+            {
+              _gdk_device_add_axis (GDK_DEVICE (device),
+                                    GDK_NONE,
+                                    GDK_AXIS_X,
+                                    axis_x.axMin,
+                                    axis_x.axMax,
+                                    axis_x.axResolution / 65535);
+              num_axes++;
+            }
+
+          if (device->pktdata & PK_Y)
+            {
+              _gdk_device_add_axis (GDK_DEVICE (device),
+                                    GDK_NONE,
+                                    GDK_AXIS_Y,
+                                    axis_y.axMin,
+                                    axis_y.axMax,
+                                    axis_y.axResolution / 65535);
+              num_axes++;
+            }
+
+
+          if (device->pktdata & PK_NORMAL_PRESSURE)
+            {
+              _gdk_device_add_axis (GDK_DEVICE (device),
+                                    GDK_NONE,
+                                    GDK_AXIS_PRESSURE,
+                                    axis_npressure.axMin,
+                                    axis_npressure.axMax,
+                                    axis_npressure.axResolution / 65535);
+              num_axes++;
+            }
+
+          /* The wintab driver for the Wacom ArtPad II reports
+           * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't
+           * actually sense tilt. Catch this by noticing that the
+           * orientation axis's azimuth resolution is zero.
+           */
+          if ((device->pktdata & PK_ORIENTATION) && axis_or[0].axResolution == 0)
+            {
+              device->orientation_axes[0] = axis_or[0];
+              device->orientation_axes[1] = axis_or[1];
+
+              /* Wintab gives us aximuth and altitude, which
+               * we convert to x and y tilt in the -1000..1000 range
+               */
+              _gdk_device_add_axis (GDK_DEVICE (device),
+                                    GDK_NONE,
+                                    GDK_AXIS_XTILT,
+                                    -1000,
+                                    1000,
+                                    1000);
+
+              _gdk_device_add_axis (GDK_DEVICE (device),
+                                    GDK_NONE,
+                                    GDK_AXIS_YTILT,
+                                    -1000,
+                                    1000,
+                                    1000);
+              num_axes += 2;
+            }
+
+          device->last_axis_data = g_new (gint, num_axes);
+
+          GDK_NOTE (INPUT, g_print ("device: (%d) %s axes: %d\n",
+                                    cursorix,
+                                    device_name,
+                                    num_axes));
+
+#if 0
+          for (i = 0; i < gdkdev->info.num_axes; i++)
+            GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d %d\n",
+                                      i,
+                                      gdkdev->axes[i].min_value,
+                                      gdkdev->axes[i].max_value,
+                                      gdkdev->axes[i].resolution));
+#endif
+
+          device_manager->wintab_devices = g_list_append (device_manager->wintab_devices,
+                                                          device);
+
+          g_free (device_name);
+        }
+
+      g_free (devname_utf8);
+    }
+}
+
+static void
+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));
+
+  _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);
+
+  _gdk_input_wintab_init_check (device_manager);
+}
+
+static GList *
+gdk_device_manager_win32_list_devices (GdkDeviceManager *device_manager,
+                                       GdkDeviceType     type)
+{
+  GdkDeviceManagerWin32 *device_manager_win32;
+  GList *devices = NULL;
+
+  device_manager_win32 = (GdkDeviceManagerWin32 *) device_manager;
+
+  if (type == GDK_DEVICE_TYPE_MASTER)
+    {
+      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);
+
+  return devices;
+}
+
+void
+_gdk_input_set_tablet_active (void)
+{
+  GList *tmp_list;
+  HCTX *hctx;
+
+  /* Bring the contexts to the top of the overlap order when one of the
+   * application's windows is activated */
+
+  if (!wintab_contexts)
+    return; /* No tablet devices found, or Wintab not initialized yet */
+
+  GDK_NOTE (INPUT, g_print ("_gdk_input_set_tablet_active: "
+                            "Bringing Wintab contexts to the top of the overlap order\n"));
+
+  tmp_list = wintab_contexts;
+
+  while (tmp_list)
+    {
+      hctx = (HCTX *) (tmp_list->data);
+      (*p_WTOverlap) (*hctx, TRUE);
+      tmp_list = tmp_list->next;
+    }
+}
+
+static void
+decode_tilt (gint   *axis_data,
+             AXIS   *axes,
+             PACKET *packet)
+{
+  double az, el;
+
+  /* As I don't have a tilt-sensing tablet,
+   * I cannot test this code.
+   */
+  az = TWOPI * packet->pkOrientation.orAzimuth /
+    (axes[0].axResolution / 65536.);
+  el = TWOPI * packet->pkOrientation.orAltitude /
+    (axes[1].axResolution / 65536.);
+
+  /* X tilt */
+  axis_data[0] = cos (az) * cos (el) * 1000;
+  /* Y tilt */
+  axis_data[1] = sin (az) * cos (el) * 1000;
+}
+
+/*
+ * 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
+ * expensive things besides getting the modifiers. This code is somewhat based
+ * on build_pointer_event_state from gdkevents-win32.c
+ */
+static guint
+get_modifier_key_state (void)
+{
+  guint state;
+
+  state = 0;
+  /* High-order bit is up/down, low order bit is toggled/untoggled */
+  if (GetKeyState (VK_CONTROL) < 0)
+    state |= GDK_CONTROL_MASK;
+  if (GetKeyState (VK_SHIFT) < 0)
+    state |= GDK_SHIFT_MASK;
+  if (GetKeyState (VK_MENU) < 0)
+    state |= GDK_MOD1_MASK;
+  if (GetKeyState (VK_CAPITAL) & 0x1)
+    state |= GDK_LOCK_MASK;
+
+  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)
+{
+  GdkDeviceManagerWin32 *device_manager;
+  GdkDeviceWintab *device;
+  GList *tmp_list;
+
+  device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
+  tmp_list = device_manager->wintab_devices;
+
+  while (tmp_list)
+    {
+      device = tmp_list->data;
+      tmp_list = tmp_list->next;
+
+      if (device->hctx == hctx &&
+          device->cursor == cursor)
+        return device;
+    }
+
+  return NULL;
+}
+
+gboolean
+_gdk_input_other_event (GdkEvent  *event,
+                        MSG       *msg,
+                        GdkWindow *window)
+{
+  GdkDisplay *display;
+  GdkWindowObject *obj;
+  GdkDeviceWintab *device = NULL;
+  GdkDeviceGrabInfo *last_grab;
+  GdkEventMask masktest;
+  guint key_state;
+  POINT pt;
+
+  PACKET packet;
+  gdouble root_x, root_y;
+  gint num_axes;
+  gint x, y;
+  guint translated_buttons, button_diff, button_mask;
+  /* Translation from tablet button state to GDK button state for
+   * buttons 1-3 - swap button 2 and 3.
+   */
+  static guint button_map[8] = {0, 1, 4, 5, 2, 3, 6, 7};
+
+  if (event->any.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);
+
+  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)
+    {
+      if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
+        return FALSE;
+    }
+
+  obj = GDK_WINDOW_OBJECT (window);
+
+  switch (msg->message)
+    {
+    case WT_PACKET:
+      /* Don't produce any button or motion events while a window is being
+       * moved or resized, see bug #151090.
+       */
+      if (_modal_operation_in_progress)
+        {
+          GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
+          return FALSE;
+        }
+
+      if ((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)
+        return FALSE;
+
+      last_grab = _gdk_display_get_last_device_grab (_gdk_display, GDK_DEVICE (device));
+
+      if (last_grab && last_grab->window)
+        {
+          g_object_unref (window);
+
+          window = g_object_ref (last_grab->window);
+          obj = GDK_WINDOW_OBJECT (window);
+        }
+
+      if (window == _gdk_root)
+        {
+          GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
+          return FALSE;
+        }
+
+      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)
+        {
+          decode_tilt (device->last_axis_data + num_axes,
+                       device->orientation_axes, &packet);
+          num_axes += 2;
+        }
+
+      translated_buttons = button_map[packet.pkButtons & 0x07] | (packet.pkButtons & ~0x07);
+
+      if (translated_buttons != 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;
+
+          /* Gdk buttons are numbered 1.. */
+          event->button.button = 1;
+
+          for (button_mask = 1; button_mask != 0x80000000;
+               button_mask <<= 1, event->button.button++)
+            {
+              if (button_diff & button_mask)
+                {
+                  /* Found a button that has changed state */
+                  break;
+                }
+            }
+
+          if (!(translated_buttons & button_mask))
+            {
+              event->any.type = GDK_BUTTON_RELEASE;
+              masktest = GDK_BUTTON_RELEASE_MASK;
+            }
+          else
+            {
+              event->any.type = GDK_BUTTON_PRESS;
+              masktest = GDK_BUTTON_PRESS_MASK;
+            }
+          device->button_state ^= button_mask;
+        }
+      else
+        {
+          event->any.type = GDK_MOTION_NOTIFY;
+          masktest = GDK_POINTER_MOTION_MASK;
+          if (device->button_state & (1 << 0))
+            masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
+          if (device->button_state & (1 << 1))
+            masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
+          if (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)
+        {
+          GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
+
+          if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
+            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 (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));
+        }
+
+      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));
+
+          event->button.axes = g_new (gdouble, num_axes);
+          _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+
+          _gdk_device_wintab_translate_axes (device,
+                                             window,
+                                             event->button.axes,
+                                             &event->button.x,
+                                             &event->button.y);
+
+          event->button.x_root = event->button.x + root_x;
+          event->button.y_root = event->button.y + root_y;
+
+          event->button.state =
+            key_state | ((device->button_state << 8)
+                         & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                            | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                            | GDK_BUTTON5_MASK));
+
+          GDK_NOTE (EVENTS_OR_INPUT,
+                    g_print ("WINTAB button %s:%d %g,%g\n",
+                             (event->button.type == GDK_BUTTON_PRESS ?
+                              "press" : "release"),
+                             event->button.button,
+                             event->button.x, event->button.y));
+        }
+      else
+        {
+          event->motion.time = _gdk_win32_get_next_tick (msg->time);
+          event->motion.is_hint = FALSE;
+          gdk_event_set_device (event, GDK_DEVICE (device));
+
+          event->motion.axes = g_new (gdouble, num_axes);
+          _gdk_device_wintab_get_window_coords (window, &root_x, &root_y);
+
+          _gdk_device_wintab_translate_axes (device,
+                                             window,
+                                             event->motion.axes,
+                                             &event->motion.x,
+                                             &event->motion.y);
+
+          event->motion.x_root = event->motion.x + root_x;
+          event->motion.y_root = event->motion.y + root_y;
+
+          event->motion.state =
+            key_state | ((device->button_state << 8)
+                         & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                            | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                            | GDK_BUTTON5_MASK));
+
+          GDK_NOTE (EVENTS_OR_INPUT,
+                    g_print ("WINTAB motion: %g,%g\n",
+                             event->motion.x, event->motion.y));
+        }
+      return TRUE;
+
+    case WT_PROXIMITY:
+      if (LOWORD (msg->lParam) == 0)
+        {
+          event->proximity.type = GDK_PROXIMITY_OUT;
+          set_ignore_core (FALSE);
+        }
+      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;
+}
diff --git a/gdk/win32/gdkdevicemanager-win32.h b/gdk/win32/gdkdevicemanager-win32.h
new file mode 100644
index 0000000..69d26b7
--- /dev/null
+++ b/gdk/win32/gdkdevicemanager-win32.h
@@ -0,0 +1,59 @@
+/* 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDK_DEVICE_MANAGER_WIN32_H__
+#define __GDK_DEVICE_MANAGER_WIN32_H__
+
+#include <gdk/gdkdevicemanager.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_DEVICE_MANAGER_WIN32         (gdk_device_manager_win32_get_type ())
+#define GDK_DEVICE_MANAGER_WIN32(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32))
+#define GDK_DEVICE_MANAGER_WIN32_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32Class))
+#define GDK_IS_DEVICE_MANAGER_WIN32(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_DEVICE_MANAGER_WIN32))
+#define GDK_IS_DEVICE_MANAGER_WIN32_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_DEVICE_MANAGER_WIN32))
+#define GDK_DEVICE_MANAGER_WIN32_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_DEVICE_MANAGER_WIN32, GdkDeviceManagerWin32Class))
+
+typedef struct _GdkDeviceManagerWin32 GdkDeviceManagerWin32;
+typedef struct _GdkDeviceManagerWin32Class GdkDeviceManagerWin32Class;
+
+struct _GdkDeviceManagerWin32
+{
+  GdkDeviceManager parent_object;
+  GdkDevice *core_pointer;
+  GdkDevice *core_keyboard;
+  GList *wintab_devices;
+};
+
+struct _GdkDeviceManagerWin32Class
+{
+  GdkDeviceManagerClass parent_class;
+};
+
+GType gdk_device_manager_win32_get_type (void) G_GNUC_CONST;
+
+void     _gdk_input_set_tablet_active (void);
+gboolean _gdk_input_other_event       (GdkEvent  *event,
+                                       MSG       *msg,
+                                       GdkWindow *window);
+
+G_END_DECLS
+
+#endif /* __GDK_DEVICE_MANAGER_WIN32_H__ */
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
index 9f4d37b..7ee5781 100644
--- a/gdk/win32/gdkdnd-win32.c
+++ b/gdk/win32/gdkdnd-win32.c
@@ -98,6 +98,7 @@ typedef enum {
  * this is used on both source and destination sides.
  */
 struct _GdkDragContextPrivateWin32 {
+  GdkDevice *device;
   gboolean being_finalized;
   gint ref_count;
   IUnknown *iface;
@@ -219,6 +220,39 @@ gdk_drag_context_unref (GdkDragContext *context)
   g_object_unref (context);
 }
 
+GdkDevice *
+gdk_drag_context_get_device (GdkDragContext *context)
+{
+  GdkDragContextPrivateWin32 *private;
+
+  g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+
+  private = PRIVATE_DATA (context);
+
+  return private->device;
+}
+
+void
+gdk_drag_context_set_device (GdkDragContext *context,
+                             GdkDevice      *device)
+{
+  GdkDragContextPrivateWin32 *private;
+
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+
+  private = PRIVATE_DATA (context);
+
+  if (private->device)
+    {
+      g_object_unref (private->device);
+      private->device = NULL;
+    }
+
+  if (device)
+    private->device = g_object_ref (device);
+}
+
 static GdkDragContext *
 gdk_drag_context_find (gboolean   is_source,
 		       GdkWindow *source,
@@ -441,24 +475,28 @@ dnd_event_put (GdkEventType    type,
 	       const POINTL    pt,
 	       gboolean        to_dest_window)
 {
-  GdkEvent e;
-  e.type = type;
+  GdkEvent *e;
+
+  e = gdk_event_new (type);
+
   if (to_dest_window)
-    e.dnd.window = context->dest_window;
+    e->dnd.window = context->dest_window;
   else
-    e.dnd.window = context->source_window;
-  e.dnd.send_event = FALSE;
-  e.dnd.context = context;
-  e.dnd.time = GDK_CURRENT_TIME;
-  e.dnd.x_root = pt.x + _gdk_offset_x;
-  e.dnd.y_root = pt.x + _gdk_offset_y;
+    e->dnd.window = context->source_window;
+  e->dnd.send_event = FALSE;
+  e->dnd.context = g_object_ref (context);
+  e->dnd.time = GDK_CURRENT_TIME;
+  e->dnd.x_root = pt.x + _gdk_offset_x;
+  e->dnd.y_root = pt.x + _gdk_offset_y;
 
-  gdk_drag_context_ref (e.dnd.context);
-  if (e.dnd.window != NULL)
-    g_object_ref (e.dnd.window);
+  if (e->dnd.window != NULL)
+    g_object_ref (e->dnd.window);
 
-  GDK_NOTE (EVENTS, _gdk_win32_print_event (&e));
-  gdk_event_put (&e);
+  gdk_event_set_device (e, gdk_drag_context_get_device (context));
+
+  GDK_NOTE (EVENTS, _gdk_win32_print_event (e));
+  gdk_event_put (e);
+  gdk_event_free (e);
 }
 
 static HRESULT STDMETHODCALLTYPE
@@ -1189,6 +1227,7 @@ target_context_new (GdkWindow *window)
 {
   target_drag_context *result;
   GdkDragContextPrivateWin32 *private;
+  GdkDevice *device;
 
   result = g_new0 (target_drag_context, 1);
 
@@ -1198,6 +1237,9 @@ target_context_new (GdkWindow *window)
   result->context->protocol = GDK_DRAG_PROTO_OLE2;
   result->context->is_source = FALSE;
 
+  device = gdk_display_get_core_pointer (_gdk_display);
+  gdk_drag_context_set_device (result->context, device);
+
   result->context->source_window = NULL;
 
   result->context->dest_window = window;
@@ -1224,6 +1266,7 @@ source_context_new (GdkWindow *window,
 {
   source_drag_context *result;
   GdkDragContextPrivateWin32 *private;
+  GdkDevice *device;
 
   result = g_new0 (source_drag_context, 1);
 
@@ -1233,6 +1276,9 @@ source_context_new (GdkWindow *window,
   result->context->protocol = GDK_DRAG_PROTO_OLE2;
   result->context->is_source = TRUE;
 
+  device = gdk_display_get_core_pointer (_gdk_display);
+  gdk_drag_context_set_device (result->context, device);
+
   result->context->source_window = window;
   g_object_ref (window);
 
@@ -1444,6 +1490,7 @@ gdk_dropfiles_filter (GdkXEvent *xev,
   POINT pt;
   gint nfiles, i;
   gchar *fileName, *linkedFile;
+  GdkDevice *device;
 
   if (msg->message == WM_DROPFILES)
     {
@@ -1453,6 +1500,9 @@ gdk_dropfiles_filter (GdkXEvent *xev,
       context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
       context->is_source = FALSE;
 
+      device = gdk_display_get_core_pointer (_gdk_display);
+      gdk_drag_context_set_device (context, device);
+
       context->source_window = _gdk_root;
       g_object_ref (context->source_window);
 
@@ -1468,6 +1518,7 @@ gdk_dropfiles_filter (GdkXEvent *xev,
 
       event->dnd.type = GDK_DROP_START;
       event->dnd.context = current_dest_drag;
+      gdk_event_set_device (event, gdk_drag_context_get_device (current_dest_drag));
 
       hdrop = (HANDLE) msg->wParam;
       DragQueryPoint (hdrop, &pt);
@@ -1631,7 +1682,7 @@ static void
 local_send_leave (GdkDragContext *context,
 		  guint32         time)
 {
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
 
   GDK_NOTE (DND, g_print ("local_send_leave: context=%p current_dest_drag=%p\n",
 			  context,
@@ -1641,17 +1692,20 @@ local_send_leave (GdkDragContext *context,
       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
       (current_dest_drag->source_window == context->source_window))
     {
-      tmp_event.dnd.type = GDK_DRAG_LEAVE;
-      tmp_event.dnd.window = context->dest_window;
+      tmp_event = gdk_event_new (GDK_DRAG_LEAVE);
+
+      tmp_event->dnd.window = g_object_ref (context->dest_window);
       /* Pass ownership of context to the event */
-      tmp_event.dnd.send_event = FALSE;
-      tmp_event.dnd.context = current_dest_drag;
-      tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+      tmp_event->dnd.send_event = FALSE;
+      tmp_event->dnd.context = g_object_ref (current_dest_drag);
+      tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+      gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
 
       current_dest_drag = NULL;
 
-      GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-      gdk_event_put (&tmp_event);
+      GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+      gdk_event_put (tmp_event);
+      gdk_event_free (tmp_event);
     }
 }
 
@@ -1659,9 +1713,10 @@ static void
 local_send_enter (GdkDragContext *context,
 		  guint32         time)
 {
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
   GdkDragContextPrivateWin32 *private;
   GdkDragContext *new_context;
+  GdkDevice *device;
 
   GDK_NOTE (DND, g_print ("local_send_enter: context=%p current_dest_drag=%p\n",
 			  context,
@@ -1679,6 +1734,9 @@ local_send_enter (GdkDragContext *context,
   new_context->protocol = GDK_DRAG_PROTO_LOCAL;
   new_context->is_source = FALSE;
 
+  device = gdk_display_get_core_pointer (_gdk_display);
+  gdk_drag_context_set_device (new_context, device);
+
   new_context->source_window = context->source_window;
   g_object_ref (new_context->source_window);
 
@@ -1692,16 +1750,18 @@ local_send_enter (GdkDragContext *context,
 			 GDK_PROPERTY_CHANGE_MASK);
   new_context->actions = context->actions;
 
-  tmp_event.type = GDK_DRAG_ENTER;
-  tmp_event.dnd.window = context->dest_window;
-  tmp_event.dnd.send_event = FALSE;
-  tmp_event.dnd.context = new_context;
-  tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+  tmp_event = gdk_event_new (GDK_DRAG_ENTER);
+  tmp_event->dnd.window = g_object_ref (context->dest_window);
+  tmp_event->dnd.send_event = FALSE;
+  tmp_event->dnd.context = g_object_ref (new_context);
+  tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+  gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
 
   current_dest_drag = new_context;
 
-  GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-  gdk_event_put (&tmp_event);
+  GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+  gdk_event_put (tmp_event);
+  gdk_event_free (tmp_event);
 }
 
 static void
@@ -1711,7 +1771,7 @@ local_send_motion (GdkDragContext *context,
 		   GdkDragAction   action,
 		   guint32         time)
 {
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
 
   GDK_NOTE (DND, g_print ("local_send_motion: context=%p (%d,%d) current_dest_drag=%p\n",
 			  context, x_root, y_root,
@@ -1721,24 +1781,26 @@ local_send_motion (GdkDragContext *context,
       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
       (current_dest_drag->source_window == context->source_window))
     {
-      tmp_event.type = GDK_DRAG_MOTION;
-      tmp_event.dnd.window = current_dest_drag->dest_window;
-      tmp_event.dnd.send_event = FALSE;
-      tmp_event.dnd.context = current_dest_drag;
-      tmp_event.dnd.time = time;
+      tmp_event = gdk_event_new (GDK_DRAG_MOTION);
+      tmp_event->dnd.window = g_object_ref (current_dest_drag->dest_window);
+      tmp_event->dnd.send_event = FALSE;
+      tmp_event->dnd.context = g_object_ref (current_dest_drag);
+      tmp_event->dnd.time = time;
+      gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag));
 
       current_dest_drag->suggested_action = action;
 
-      tmp_event.dnd.x_root = x_root;
-      tmp_event.dnd.y_root = y_root;
+      tmp_event->dnd.x_root = x_root;
+      tmp_event->dnd.y_root = y_root;
 
       PRIVATE_DATA (current_dest_drag)->last_pt.x = x_root - _gdk_offset_x;
       PRIVATE_DATA (current_dest_drag)->last_pt.y = y_root - _gdk_offset_y;
 
       PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
 
-      GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-      gdk_event_put (&tmp_event);
+      GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+      gdk_event_put (tmp_event);
+      gdk_event_free (tmp_event);
     }
 }
 
@@ -1746,7 +1808,7 @@ static void
 local_send_drop (GdkDragContext *context,
 		 guint32         time)
 {
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
 
   GDK_NOTE (DND, g_print ("local_send_drop: context=%p current_dest_drag=%p\n",
 			  context,
@@ -1760,19 +1822,21 @@ local_send_drop (GdkDragContext *context,
       private = PRIVATE_DATA (current_dest_drag);
 
       /* Pass ownership of context to the event */
-      tmp_event.type = GDK_DROP_START;
-      tmp_event.dnd.window = current_dest_drag->dest_window;
-      tmp_event.dnd.send_event = FALSE;
-      tmp_event.dnd.context = current_dest_drag;
-      tmp_event.dnd.time = GDK_CURRENT_TIME;
+      tmp_event = gdk_event_new (GDK_DROP_START);
+      tmp_event->dnd.window = g_object_ref (current_dest_drag->dest_window);
+      tmp_event->dnd.send_event = FALSE;
+      tmp_event->dnd.context = g_object_ref (current_dest_drag);
+      tmp_event->dnd.time = GDK_CURRENT_TIME;
+      gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag));
 
-      tmp_event.dnd.x_root = private->last_pt.x + _gdk_offset_x;
-      tmp_event.dnd.y_root = private->last_pt.y + _gdk_offset_y;
+      tmp_event->dnd.x_root = private->last_pt.x + _gdk_offset_x;
+      tmp_event->dnd.y_root = private->last_pt.y + _gdk_offset_y;
 
       current_dest_drag = NULL;
 
-      GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-      gdk_event_put (&tmp_event);
+      GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+      gdk_event_put (tmp_event);
+      gdk_event_free (tmp_event);
     }
 
 }
@@ -1803,11 +1867,15 @@ gdk_drag_begin (GdkWindow *window,
   if (!use_ole2_dnd)
     {
       GdkDragContext *new_context;
+      GdkDevice *device;
 
       g_return_val_if_fail (window != NULL, NULL);
 
       new_context = gdk_drag_context_new ();
 
+      device = gdk_display_get_core_pointer (_gdk_display);
+      gdk_drag_context_set_device (new_context, device);
+
       new_context->is_source = TRUE;
 
       new_context->source_window = window;
@@ -2059,7 +2127,7 @@ gdk_drag_motion (GdkDragContext *context,
 	}
       else
 	{
-	  GdkEvent tmp_event;
+	  GdkEvent *tmp_event;
 
 	  /* Send a leave to the last destination */
 	  gdk_drag_do_leave (context, time);
@@ -2092,18 +2160,20 @@ gdk_drag_motion (GdkDragContext *context,
 	  /* Push a status event, to let the client know that
 	   * the drag changed
 	   */
-	  tmp_event.type = GDK_DRAG_STATUS;
-	  tmp_event.dnd.window = context->source_window;
+    tmp_event = gdk_event_new (GDK_DRAG_STATUS);
+	  tmp_event->dnd.window = g_object_ref (context->source_window);
 	  /* We use this to signal a synthetic status. Perhaps
 	   * we should use an extra field...
 	   */
-	  tmp_event.dnd.send_event = TRUE;
+	  tmp_event->dnd.send_event = TRUE;
 
-	  tmp_event.dnd.context = context;
-	  tmp_event.dnd.time = time;
+	  tmp_event->dnd.context = g_object_ref (context);
+	  tmp_event->dnd.time = time;
+    gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context));
 
-	  GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-	  gdk_event_put (&tmp_event);
+	  GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+	  gdk_event_put (tmp_event);
+    gdk_event_free (tmp_event);
 	}
 
       /* Send a drag-motion event */
@@ -2192,7 +2262,7 @@ gdk_drag_status (GdkDragContext *context,
 {
   GdkDragContextPrivateWin32 *private;
   GdkDragContext *src_context;
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
 
   g_return_if_fail (context != NULL);
 
@@ -2221,19 +2291,21 @@ gdk_drag_status (GdkDragContext *context,
 	  if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
 	    private->drag_status = GDK_DRAG_STATUS_DRAG;
 
-	  tmp_event.type = GDK_DRAG_STATUS;
-	  tmp_event.dnd.window = context->source_window;
-	  tmp_event.dnd.send_event = FALSE;
-	  tmp_event.dnd.context = src_context;
-	  tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+	  tmp_event = gdk_event_new (GDK_DRAG_STATUS);
+	  tmp_event->dnd.window = g_object_ref (context->source_window);
+	  tmp_event->dnd.send_event = FALSE;
+	  tmp_event->dnd.context = g_object_ref (src_context);
+	  tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+    gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context));
 
 	  if (action == GDK_ACTION_DEFAULT)
 	    action = 0;
 
 	  src_context->action = action;
 
-	  GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-	  gdk_event_put (&tmp_event);
+	  GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+	  gdk_event_put (tmp_event);
+    gdk_event_free (tmp_event);
 	}
     }
 }
@@ -2262,7 +2334,7 @@ gdk_drop_finish (GdkDragContext *context,
 {
   GdkDragContextPrivateWin32 *private;
   GdkDragContext *src_context;
-  GdkEvent tmp_event;
+  GdkEvent *tmp_event;
 
   g_return_if_fail (context != NULL);
 
@@ -2277,13 +2349,15 @@ gdk_drop_finish (GdkDragContext *context,
 					   context->dest_window);
       if (src_context)
 	{
-	  tmp_event.type = GDK_DROP_FINISHED;
-	  tmp_event.dnd.window = src_context->source_window;
-	  tmp_event.dnd.send_event = FALSE;
-	  tmp_event.dnd.context = src_context;
-
-	  GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
-	  gdk_event_put (&tmp_event);
+    tmp_event = gdk_event_new (GDK_DROP_FINISHED);
+	  tmp_event->dnd.window = g_object_ref (src_context->source_window);
+	  tmp_event->dnd.send_event = FALSE;
+	  tmp_event->dnd.context = g_object_ref (src_context);
+    gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context));
+
+	  GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event));
+	  gdk_event_put (tmp_event);
+    gdk_event_free (tmp_event);
 	}
     }
   else
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 3773e4d..17b445e 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -47,8 +47,10 @@
 
 #include "gdk.h"
 #include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
 #include "gdkkeysyms.h"
+#include "gdkdevicemanager-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevice-wintab.h"
 
 #include <windowsx.h>
 
@@ -101,6 +103,7 @@ static gboolean is_modally_blocked (GdkWindow   *window);
  */
 
 static GList *client_filters;	/* Filters for client messages */
+extern gint       _gdk_input_ignore_core;
 
 static HCURSOR p_grab_cursor;
 
@@ -199,31 +202,44 @@ _gdk_win32_get_next_tick (gulong suggested_tick)
 }
 
 static void
-generate_focus_event (GdkWindow *window,
-		      gboolean   in)
+generate_focus_event (GdkDeviceManager *device_manager,
+                      GdkWindow        *window,
+                      gboolean          in)
 {
+  GdkDevice *device;
   GdkEvent *event;
 
+  device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+
   event = gdk_event_new (GDK_FOCUS_CHANGE);
   event->focus_change.window = window;
   event->focus_change.in = in;
+  gdk_event_set_device (event, device);
 
   append_event (event);
 }
 
 static void
-generate_grab_broken_event (GdkWindow *window,
-			    gboolean   keyboard,
-			    GdkWindow *grab_window)
+generate_grab_broken_event (GdkDeviceManager *device_manager,
+                            GdkWindow        *window,
+                            gboolean          keyboard,
+                            GdkWindow        *grab_window)
 {
   GdkEvent *event = gdk_event_new (GDK_GRAB_BROKEN);
+  GdkDevice *device;
+
+  if (keyboard)
+    device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard;
+  else
+    device = GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer;
 
   event->grab_broken.window = window;
   event->grab_broken.send_event = 0;
   event->grab_broken.keyboard = keyboard;
   event->grab_broken.implicit = FALSE;
   event->grab_broken.grab_window = grab_window;
-	  
+  gdk_event_set_device (event, device);
+
   append_event (event);
 }
 
@@ -467,17 +483,19 @@ event_mask_string (GdkEventMask mask)
 #endif
 
 GdkGrabStatus
-_gdk_windowing_pointer_grab (GdkWindow    *window,
-			     GdkWindow    *native_window,
-			     gboolean	owner_events,
-			     GdkEventMask	event_mask,
-			     GdkWindow    *confine_to,
-			     GdkCursor    *cursor,
-			     guint32	time)
+_gdk_windowing_device_grab (GdkDevice    *device,
+                            GdkWindow    *window,
+                            GdkWindow    *native_window,
+                            gboolean      owner_events,
+                            GdkEventMask	event_mask,
+                            GdkWindow    *confine_to,
+                            GdkCursor    *cursor,
+                            guint32	      time)
 {
   HCURSOR hcursor;
   GdkCursorPrivate *cursor_private;
   gint return_val;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) native_window)->impl);
 
   g_return_val_if_fail (window != NULL, 0);
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
@@ -490,54 +508,53 @@ _gdk_windowing_pointer_grab (GdkWindow    *window,
   else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
     WIN32_API_FAILED ("CopyCursor");
 
-  return_val = _gdk_input_grab_pointer (native_window,
-					owner_events,
-					event_mask,
-					confine_to,
-					time);
+  return_val = GDK_DEVICE_GET_CLASS (device)->grab (device,
+                                                    native_window,
+                                                    owner_events,
+                                                    event_mask,
+                                                    confine_to,
+                                                    cursor,
+                                                    time);
 
-  if (return_val == GDK_GRAB_SUCCESS)
+  /* TODO_CSW: grab brokens, confine window, input_grab */
+  if (p_grab_cursor != NULL)
     {
-      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (((GdkWindowObject *) native_window)->impl);
-
-      SetCapture (GDK_WINDOW_HWND (native_window));
-      /* TODO_CSW: grab brokens, confine window, input_grab */
-      if (p_grab_cursor != NULL)
-	{
-	  if (GetCursor () == p_grab_cursor)
-	    SetCursor (NULL);
-	  DestroyCursor (p_grab_cursor);
-	}
-
-      p_grab_cursor = hcursor;
+      if (GetCursor () == p_grab_cursor)
+        SetCursor (NULL);
+      DestroyCursor (p_grab_cursor);
+    }
 
-      if (p_grab_cursor != NULL)
-	SetCursor (p_grab_cursor);
-      else if (impl->hcursor != NULL)
-	SetCursor (impl->hcursor);
-      else
-	SetCursor (LoadCursor (NULL, IDC_ARROW));
+  p_grab_cursor = hcursor;
 
-    }
+  if (p_grab_cursor != NULL)
+    SetCursor (p_grab_cursor);
+  else if (impl->hcursor != NULL)
+    SetCursor (impl->hcursor);
+  else
+    SetCursor (LoadCursor (NULL, IDC_ARROW));
 
   return return_val;
 }
 
 void
-gdk_display_pointer_ungrab (GdkDisplay *display,
-                            guint32     time)
+gdk_device_ungrab (GdkDevice *device,
+                   guint32    time)
 {
-  GdkPointerGrabInfo *info;
+  GdkDeviceGrabInfo *info;
+  GdkDisplay *display;
+
+  g_return_if_fail (GDK_IS_DEVICE (device));
+
+  display = gdk_device_get_display (device);
+  info = _gdk_display_get_last_device_grab (display, device);
 
-  info = _gdk_display_get_last_pointer_grab (display);
   if (info)
     {
       info->serial_end = 0;
-      ReleaseCapture ();
+      GDK_DEVICE_GET_CLASS (device)->ungrab (device, time);
     }
-  /* TODO_CSW: cursor, confines, etc */
 
-  _gdk_display_pointer_grab_update (display, 0);
+  _gdk_display_device_grab_update (display, device, 0);
 }
 
 
@@ -549,8 +566,11 @@ find_window_for_mouse_event (GdkWindow* reported_window,
   POINTS points;
   POINT pt;
   GdkWindow* other_window = NULL;
+  GdkDeviceManagerWin32 *device_manager;
+
+  device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (_gdk_display));
 
-  if (!_gdk_display_get_last_pointer_grab (_gdk_display))
+  if (!_gdk_display_get_last_device_grab (_gdk_display, device_manager->core_pointer))
     return reported_window;
 
   points = MAKEPOINTS (msg->lParam);
@@ -586,41 +606,6 @@ find_window_for_mouse_event (GdkWindow* reported_window,
   return other_window;
 }
 
-GdkGrabStatus
-gdk_keyboard_grab (GdkWindow *window,
-		   gboolean   owner_events,
-		   guint32    time)
-{
-  GdkDisplay *display;
-  GdkWindow  *toplevel;
-
-  g_return_val_if_fail (window != NULL, 0);
-  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-  
-  GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %p%s\n",
-			     GDK_WINDOW_HWND (window), owner_events ? " OWNER_EVENTS" : ""));
-
-  display = gdk_drawable_get_display (window);
-  toplevel = gdk_window_get_toplevel (window);
-
-  _gdk_display_set_has_keyboard_grab (display,
-				      window,
-				      toplevel,
-				      owner_events,
-				      0,
-				      time);
-
-  return GDK_GRAB_SUCCESS;
-}
-
-void
-gdk_display_keyboard_ungrab (GdkDisplay *display,
-                             guint32 time)
-{
-  GDK_NOTE (EVENTS, g_print ("gdk_display_keyboard_ungrab\n"));
-  _gdk_display_unset_has_keyboard_grab (display, FALSE);
-}
-
 void 
 gdk_display_add_client_message_filter (GdkDisplay   *display,
 				       GdkAtom       message_type,
@@ -1219,11 +1204,11 @@ do_show_window (GdkWindow *window, gboolean hide_window)
 }
 
 static void
-synthesize_enter_or_leave_event (GdkWindow    	*window,
-				 MSG          	*msg,
-				 GdkEventType 	 type,
-				 GdkCrossingMode mode,
-				 GdkNotifyType detail)
+synthesize_enter_or_leave_event (GdkWindow        *window,
+                                 MSG          	  *msg,
+                                 GdkEventType 	   type,
+                                 GdkCrossingMode   mode,
+                                 GdkNotifyType     detail)
 {
   GdkEvent *event;
   POINT pt;
@@ -1243,12 +1228,13 @@ synthesize_enter_or_leave_event (GdkWindow    	*window,
   event->crossing.detail = detail;
   event->crossing.focus = TRUE; /* FIXME: Set correctly */
   event->crossing.state = 0;	/* FIXME: Set correctly */
+  gdk_event_set_device (event, _gdk_display->core_pointer);
 
   append_event (event);
   
   if (type == GDK_ENTER_NOTIFY &&
       ((GdkWindowObject *) window)->extension_events != 0)
-    _gdk_input_enter_event (window);
+    _gdk_device_wintab_update_window_coords (window);
 }
 			 
 static void
@@ -1708,10 +1694,10 @@ handle_display_change (void)
 }
 
 static void
-generate_button_event (GdkEventType type,
-		       gint         button,
-		       GdkWindow   *window,
-		       MSG         *msg)
+generate_button_event (GdkEventType      type,
+                       gint              button,
+                       GdkWindow        *window,
+                       MSG              *msg)
 {
   GdkEvent *event = gdk_event_new (type);
 
@@ -1724,7 +1710,7 @@ generate_button_event (GdkEventType type,
   event->button.axes = NULL;
   event->button.state = build_pointer_event_state (msg);
   event->button.button = button;
-  event->button.device = _gdk_display->core_pointer;
+  gdk_event_set_device (event, _gdk_display->core_pointer);
 
   append_event (event);
 }
@@ -1892,7 +1878,10 @@ gdk_event_translate (MSG  *msg,
 
   GdkWindow *orig_window, *new_window, *toplevel;
 
-  GdkPointerGrabInfo *grab = NULL;
+  GdkDeviceManager *device_manager;
+
+  GdkDeviceGrabInfo *keyboard_grab = NULL;
+  GdkDeviceGrabInfo *pointer_grab = NULL;
   GdkWindow *grab_window = NULL;
 
   static gint update_colors_counter = 0;
@@ -1953,7 +1942,14 @@ gdk_event_translate (MSG  *msg,
 	}
       return FALSE;
     }
-  
+
+  device_manager = gdk_display_get_device_manager (_gdk_display);
+
+  keyboard_grab = _gdk_display_get_last_device_grab (_gdk_display,
+                                                     GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_keyboard);
+  pointer_grab = _gdk_display_get_last_device_grab (_gdk_display,
+                                                    GDK_DEVICE_MANAGER_WIN32 (device_manager)->core_pointer);
+
   g_object_ref (window);
 
   /* window's refcount has now been increased, so code below should
@@ -2071,7 +2067,7 @@ gdk_event_translate (MSG  *msg,
       /* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
        * the keyboard is grabbed.
        */
-      if (_gdk_display->keyboard_grab.window == NULL &&
+      if (!keyboard_grab &&
 	  (msg->wParam == VK_TAB ||
 	   msg->wParam == VK_SPACE ||
 	   msg->wParam == VK_F4))
@@ -2095,9 +2091,10 @@ gdk_event_translate (MSG  *msg,
 	  in_ime_composition)
 	break;
 
-      if (!propagate (&window, msg,
-		      _gdk_display->keyboard_grab.window,
-		      _gdk_display->keyboard_grab.owner_events,
+      if (keyboard_grab &&
+          !propagate (&window, msg,
+		      keyboard_grab->window,
+		      keyboard_grab->owner_events,
 		      GDK_ALL_EVENTS_MASK,
 		      doesnt_want_key, FALSE))
 	break;
@@ -2114,6 +2111,7 @@ 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);
       if (HIWORD (msg->lParam) & KF_EXTENDED)
 	{
 	  switch (msg->wParam)
@@ -2199,9 +2197,10 @@ gdk_event_translate (MSG  *msg,
       if (!(msg->lParam & GCS_RESULTSTR))
 	break;
 
-      if (!propagate (&window, msg,
-		      _gdk_display->keyboard_grab.window,
-		      _gdk_display->keyboard_grab.owner_events,
+      if (keyboard_grab &&
+          !propagate (&window, msg,
+		      keyboard_grab->window,
+		      keyboard_grab->owner_events,
 		      GDK_ALL_EVENTS_MASK,
 		      doesnt_want_char, FALSE))
 	break;
@@ -2225,6 +2224,7 @@ 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);
 	      build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
 
 	      append_event (event);
@@ -2235,6 +2235,7 @@ 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);
 	      build_wm_ime_composition_event (event, msg, wbuf[i], key_state);
 
 	      append_event (event);
@@ -2331,10 +2332,10 @@ gdk_event_translate (MSG  *msg,
 	      current_toplevel ? GDK_WINDOW_HWND (current_toplevel) : NULL, 
 	      toplevel ? GDK_WINDOW_HWND (toplevel) : NULL));
 	  if (current_toplevel)
-	    synthesize_enter_or_leave_event (current_toplevel, msg, 
-					     GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
-	  synthesize_enter_or_leave_event (toplevel, msg, 
-					   GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+	    synthesize_enter_or_leave_event (current_toplevel, msg,
+                                       GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+	  synthesize_enter_or_leave_event (toplevel, msg,
+                                     GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
 	  assign_object (&current_toplevel, toplevel);
 	  track_mouse_event (TME_LEAVE, GDK_WINDOW_HWND (toplevel));
 	}
@@ -2360,7 +2361,7 @@ gdk_event_translate (MSG  *msg,
       event->motion.axes = NULL;
       event->motion.state = build_pointer_event_state (msg);
       event->motion.is_hint = FALSE;
-      event->motion.device = _gdk_display->core_pointer;
+      gdk_event_set_device (event, _gdk_display->core_pointer);
 
       append_event (event);
 
@@ -2389,8 +2390,8 @@ gdk_event_translate (MSG  *msg,
 	{
 	  /* we are only interested if we don't know the new window */
 	  if (current_toplevel)
-	    synthesize_enter_or_leave_event (current_toplevel, msg, 
-					     GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
+	    synthesize_enter_or_leave_event (current_toplevel, msg,
+                                       GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, GDK_NOTIFY_ANCESTOR);
 	  assign_object (&current_toplevel, NULL);
 	}
       else
@@ -2436,7 +2437,7 @@ 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);
-      event->scroll.device = _gdk_display->core_pointer;
+      gdk_event_set_device (event, _gdk_display->core_pointer);
 
       append_event (event);
       
@@ -2536,16 +2537,16 @@ gdk_event_translate (MSG  *msg,
        break;
 
     case WM_KILLFOCUS:
-      if (_gdk_display->keyboard_grab.window != NULL &&
-	  !GDK_WINDOW_DESTROYED (_gdk_display->keyboard_grab.window))
+      if (keyboard_grab != NULL &&
+	  !GDK_WINDOW_DESTROYED (keyboard_grab->window))
 	{
-	  generate_grab_broken_event (_gdk_display->keyboard_grab.window, FALSE, NULL);
+	  generate_grab_broken_event (device_manager, keyboard_grab->window, FALSE, NULL);
 	}
 
       /* fallthrough */
     case WM_SETFOCUS:
-      if (_gdk_display->keyboard_grab.window != NULL &&
-	  !_gdk_display->keyboard_grab.owner_events)
+      if (keyboard_grab != NULL &&
+	  !keyboard_grab->owner_events)
 	break;
 
       if (!(((GdkWindowObject *) window)->event_mask & GDK_FOCUS_CHANGE_MASK))
@@ -2554,7 +2555,7 @@ gdk_event_translate (MSG  *msg,
       if (GDK_WINDOW_DESTROYED (window))
 	break;
 
-      generate_focus_event (window, (msg->message == WM_SETFOCUS));
+      generate_focus_event (device_manager, window, (msg->message == WM_SETFOCUS));
       return_val = TRUE;
       break;
 
@@ -2582,11 +2583,8 @@ gdk_event_translate (MSG  *msg,
       GDK_NOTE (EVENTS, g_print (" %#x %#x",
 				 LOWORD (msg->lParam), HIWORD (msg->lParam)));
 
-      grab = _gdk_display_get_last_pointer_grab (_gdk_display);
-      if (grab != NULL)
-	{
-	  grab_window = grab->window;
-	}
+      if (pointer_grab != NULL)
+        grab_window = pointer_grab->window;
 
       if (grab_window == NULL && LOWORD (msg->lParam) != HTCLIENT)
 	break;
@@ -2641,14 +2639,14 @@ gdk_event_translate (MSG  *msg,
 	      SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
 	    }
 
-	  grab = _gdk_display_get_last_pointer_grab (_gdk_display);
-	  if (grab != NULL)
+	  if (pointer_grab != NULL)
 	    {
-	      if (grab->window == window)
+	      if (pointer_grab->window == window)
 		gdk_pointer_ungrab (msg->time);
 	    }
 
-	  if (_gdk_display->keyboard_grab.window == window)
+	  if (keyboard_grab &&
+        keyboard_grab->window == window)
 	    gdk_keyboard_ungrab (msg->time);
 	}
 
@@ -2679,13 +2677,13 @@ gdk_event_translate (MSG  *msg,
       if (msg->wParam == SIZE_MINIMIZED)
 	{
 	  /* Don't generate any GDK event. This is *not* an UNMAP. */
-	  grab = _gdk_display_get_last_pointer_grab (_gdk_display);
-	  if (grab != NULL)
+	  if (pointer_grab != NULL)
 	    {
-	      if (grab->window == window)
+	      if (pointer_grab->window == window)
 		gdk_pointer_ungrab (msg->time);
 	    }
-	  if (_gdk_display->keyboard_grab.window == window)
+	  if (keyboard_grab &&
+        keyboard_grab->window == window)
 	    gdk_keyboard_ungrab (msg->time);
 
 	  gdk_synthesize_window_state (window,
@@ -2731,7 +2729,7 @@ gdk_event_translate (MSG  *msg,
 	    ((GdkWindowObject *) window)->resize_count -= 1;
 	  
 	  if (((GdkWindowObject *) window)->extension_events != 0)
-	    _gdk_input_configure_event (window);
+      _gdk_device_wintab_update_window_coords (window);
 
 	  return_val = TRUE;
 	}
@@ -3113,14 +3111,14 @@ gdk_event_translate (MSG  *msg,
       break;
 
     case WM_DESTROY:
-      grab = _gdk_display_get_last_pointer_grab (_gdk_display);
-      if (grab != NULL)
+      if (pointer_grab != NULL)
 	{
-	  if (grab->window == window)
+	  if (pointer_grab->window == window)
 	    gdk_pointer_ungrab (msg->time);
 	}
 
-      if (_gdk_display->keyboard_grab.window == window)
+      if (keyboard_grab &&
+          keyboard_grab->window == window)
 	gdk_keyboard_ungrab (msg->time);
 
       if ((window != NULL) && (msg->hwnd != GetDesktopWindow ()))
diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c
index ca8b33a..32de7fc 100644
--- a/gdk/win32/gdkinput.c
+++ b/gdk/win32/gdkinput.c
@@ -37,63 +37,13 @@
 #include "gdkinput.h"
 
 #include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
-
-static GdkDeviceAxis gdk_input_core_axes[] = {
-  { GDK_AXIS_X, 0, 0 },
-  { GDK_AXIS_Y, 0, 0 }
-};
-
-/* Global variables  */
+#include "gdkdevicemanager-win32.h"
 
 gint              _gdk_input_ignore_core;
 
 GList            *_gdk_input_devices;
 GList            *_gdk_input_windows;
 
-void
-_gdk_init_input_core (GdkDisplay *display)
-{
-  display->core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
-  
-  display->core_pointer->name = "Core Pointer";
-  display->core_pointer->source = GDK_SOURCE_MOUSE;
-  display->core_pointer->mode = GDK_MODE_SCREEN;
-  display->core_pointer->has_cursor = TRUE;
-  display->core_pointer->num_axes = 2;
-  display->core_pointer->axes = gdk_input_core_axes;
-  display->core_pointer->num_keys = 0;
-  display->core_pointer->keys = NULL;
-}
-
-GType
-gdk_device_get_type (void)
-{
-  static GType object_type = 0;
-
-  if (!object_type)
-    {
-      const GTypeInfo object_info =
-	{
-	  sizeof (GdkDeviceClass),
-	  (GBaseInitFunc) NULL,
-	  (GBaseFinalizeFunc) NULL,
-	  (GClassInitFunc) NULL,
-	  NULL,			/* class_finalize */
-	  NULL,			/* class_data */
-	  sizeof (GdkDevicePrivate),
-	  0,			/* n_preallocs */
-	  (GInstanceInitFunc) NULL,
-	};
-      
-      object_type = g_type_register_static (G_TYPE_OBJECT,
-                                            g_intern_static_string ("GdkDevice"),
-                                            &object_info, 0);
-    }
-  
-  return object_type;
-}
-
 GList *
 gdk_devices_list (void)
 {
@@ -105,126 +55,9 @@ gdk_display_list_devices (GdkDisplay *dpy)
 {
   g_return_val_if_fail (dpy == _gdk_display, NULL);
 
-  _gdk_input_wintab_init_check ();
   return _gdk_input_devices;
 }
 
-void
-gdk_device_set_source (GdkDevice      *device,
-		       GdkInputSource  source)
-{
-  g_return_if_fail (device != NULL);
-
-  device->source = source;
-}
-
-void
-gdk_device_set_key (GdkDevice      *device,
-		    guint           index,
-		    guint           keyval,
-		    GdkModifierType modifiers)
-{
-  g_return_if_fail (device != NULL);
-  g_return_if_fail (index < device->num_keys);
-
-  device->keys[index].keyval = keyval;
-  device->keys[index].modifiers = modifiers;
-}
-
-void
-gdk_device_set_axis_use (GdkDevice   *device,
-			 guint        index,
-			 GdkAxisUse   use)
-{
-  g_return_if_fail (device != NULL);
-  g_return_if_fail (index < device->num_axes);
-
-  device->axes[index].use = use;
-
-  switch (use)
-    {
-    case GDK_AXIS_X:
-    case GDK_AXIS_Y:
-      device->axes[index].min = 0.;
-      device->axes[index].max = 0.;
-      break;
-    case GDK_AXIS_XTILT:
-    case GDK_AXIS_YTILT:
-      device->axes[index].min = -1.;
-      device->axes[index].max = 1;
-      break;
-    default:
-      device->axes[index].min = 0.;
-      device->axes[index].max = 1;
-      break;
-    }
-}
-
-gboolean
-gdk_device_get_history  (GdkDevice         *device,
-			 GdkWindow         *window,
-			 guint32            start,
-			 guint32            stop,
-			 GdkTimeCoord    ***events,
-			 gint              *n_events)
-{
-  g_return_val_if_fail (window != NULL, FALSE);
-  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
-  g_return_val_if_fail (events != NULL, FALSE);
-  g_return_val_if_fail (n_events != NULL, FALSE);
-
-  if (n_events)
-    *n_events = 0;
-  if (events)
-    *events = NULL;
-
-  if (GDK_WINDOW_DESTROYED (window))
-    return FALSE;
-    
-  if (GDK_IS_CORE (device))
-    return FALSE;
-  else
-    return _gdk_device_get_history (device, window, start, stop, events, n_events);
-}
-
-GdkTimeCoord ** 
-_gdk_device_allocate_history (GdkDevice *device,
-			      gint       n_events)
-{
-  GdkTimeCoord **result = g_new (GdkTimeCoord *, n_events);
-  gint i;
-
-  for (i=0; i<n_events; i++)
-    result[i] = g_malloc (sizeof (GdkTimeCoord) -
-			  sizeof (double) * (GDK_MAX_TIMECOORD_AXES - device->num_axes));
-
-  return result;
-}
-
-void 
-gdk_device_free_history (GdkTimeCoord **events,
-			 gint           n_events)
-{
-  gint i;
-  
-  for (i=0; i<n_events; i++)
-    g_free (events[i]);
-
-  g_free (events);
-}
-
-GdkInputWindow *
-_gdk_input_window_find(GdkWindow *window)
-{
-  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
@@ -233,212 +66,60 @@ _gdk_input_window_find(GdkWindow *window)
 
 void
 gdk_input_set_extension_events (GdkWindow *window, gint mask,
-				GdkExtensionMode mode)
+                                GdkExtensionMode mode)
 {
+  GdkDeviceManager *device_manager;
   GdkWindowObject *window_private;
-  GList *tmp_list;
-  GdkInputWindow *iw;
+  GList *devices, *d;
 
-  g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
 
-  window_private = (GdkWindowObject*) window;
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
   if (mode == GDK_EXTENSION_EVENTS_NONE)
     mask = 0;
 
-  if (mask != 0)
-    {
-      _gdk_input_wintab_init_check ();
-
-      iw = g_new(GdkInputWindow,1);
-
-      iw->window = window;
-      iw->mode = mode;
-
-      iw->obscuring = NULL;
-      iw->num_obscuring = 0;
-      iw->grabbed = FALSE;
+  window_private = (GdkWindowObject *) window;
+  window_private->extension_events = mask;
 
-      _gdk_input_windows = g_list_append(_gdk_input_windows,iw);
-      window_private->extension_events = mask;
+  device_manager = gdk_display_get_device_manager (_gdk_display);
+  devices = gdk_device_manager_list_devices (device_manager,
+                                             GDK_DEVICE_TYPE_FLOATING);
 
-      /* 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
+  for (d = devices; d; d = d->next)
     {
-      iw = _gdk_input_window_find (window);
-      if (iw)
-	{
-	  _gdk_input_windows = g_list_remove(_gdk_input_windows,iw);
-	  g_free(iw);
-	}
+      GdkDevice *dev;
+      gint dev_mask;
 
-      window_private->extension_events = 0;
-    }
+      dev = d->data;
+      dev_mask = mask;
 
-  for (tmp_list = _gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
-    {
-      GdkDevicePrivate *gdkdev = tmp_list->data;
+      if (gdk_device_get_mode (dev) == GDK_MODE_DISABLED ||
+          (!gdk_device_get_has_cursor (dev) && mode == GDK_EXTENSION_EVENTS_CURSOR))
+        dev_mask = 0;
 
-      if (!GDK_IS_CORE (gdkdev))
-	{
-	  if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
-	      && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
-	    _gdk_input_enable_window (window,gdkdev);
-	  else
-	    _gdk_input_disable_window (window,gdkdev);
-	}
+      gdk_window_set_device_events (window, dev, mask);
     }
-}
-
-void
-_gdk_input_window_destroy (GdkWindow *window)
-{
-  GdkInputWindow *input_window;
-
-  input_window = _gdk_input_window_find (window);
-  g_return_if_fail (input_window != NULL);
 
-  _gdk_input_windows = g_list_remove (_gdk_input_windows,input_window);
-  g_free(input_window);
+  g_list_free (devices);
 }
 
 void
-_gdk_input_crossing_event (GdkWindow *window,
-			   gboolean enter)
+_gdk_input_init (GdkDisplay *display)
 {
-  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
-      input_window = priv->input_window;
-      if (input_window != NULL)
-	{
-	  _gdk_input_get_root_relative_geometry (window, &root_x, &root_y);
-	  input_window->root_x = root_x;
-	  input_window->root_y = root_y;
-	}
-#endif
-    }
-  else
-    _gdk_input_ignore_core = FALSE;
-}
+  GdkDeviceManagerWin32 *device_manager;
 
-void
-_gdk_input_exit (void)
-{
-  GList *tmp_list;
-  GdkDevicePrivate *gdkdev;
+  _gdk_input_ignore_core = FALSE;
 
-  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);
+  device_manager = g_object_new (GDK_TYPE_DEVICE_MANAGER_WIN32,
+                                 "display", display,
+                                 NULL);
+  display->device_manager = GDK_DEVICE_MANAGER (device_manager);
 
-	  g_free(gdkdev->info.name);
-	  g_free(gdkdev->axes);
-	  g_free(gdkdev->info.axes);
-	  g_free(gdkdev->info.keys);
-	  g_free(gdkdev);
-	}
-    }
-
-  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);
-}
-
-gboolean
-gdk_device_get_axis (GdkDevice  *device,
-		     gdouble    *axes,
-		     GdkAxisUse  use,
-		     gdouble    *value)
-{
-  gint i;
-  
-  g_return_val_if_fail (device != NULL, FALSE);
-
-  if (axes == NULL)
-    return FALSE;
-  
-  for (i=0; i<device->num_axes; i++)
-    if (device->axes[i].use == use)
-      {
-	if (value)
-	  *value = axes[i];
-	return TRUE;
-      }
-  
-  return FALSE;
-}
-
-gboolean
-gdk_device_set_mode (GdkDevice   *device,
-		     GdkInputMode mode)
-{
-  GList *tmp_list;
-  GdkDevicePrivate *gdkdev;
-  GdkInputMode old_mode;
-  GdkInputWindow *input_window;
-
-  if (GDK_IS_CORE (device))
-    return FALSE;
-
-  gdkdev = (GdkDevicePrivate *)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);
-	}
-    }
-  else if (mode == GDK_MODE_SCREEN)
-    {
-      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);
-	}
-    }
+  display->core_pointer = device_manager->core_pointer;
 
-  return TRUE;
+  _gdk_input_devices = g_list_append (NULL, display->core_pointer);
+  _gdk_input_devices = g_list_concat (_gdk_input_devices,
+                                      g_list_copy (device_manager->wintab_devices));
 }
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
index 94b7ac7..4ea4c8f 100644
--- a/gdk/win32/gdkmain-win32.c
+++ b/gdk/win32/gdkmain-win32.c
@@ -39,10 +39,11 @@
 #include "gdkinternals.h"
 #include "gdkintl.h"
 #include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
 
 #include <objbase.h>
 
+#include <windows.h>
+#include <wintab.h>
 #include <imm.h>
 
 static gboolean gdk_synchronize = FALSE;
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index 598d291..6ee0516 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -33,7 +33,8 @@
 #include "gdk.h"
 #include "gdkwindowimpl.h"
 #include "gdkprivate-win32.h"
-#include "gdkinput-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevicemanager-win32.h"
 #include "gdkenumtypes.h"
 
 static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable);
@@ -787,9 +788,6 @@ _gdk_win32_window_destroy (GdkWindow *window,
   GDK_NOTE (MISC, g_print ("_gdk_win32_window_destroy: %p\n",
 			   GDK_WINDOW_HWND (window)));
 
-  if (private->extension_events != 0)
-    _gdk_input_window_destroy (window);
-
   /* Remove ourself from the modal stack */
   _gdk_remove_modal_window (window);
 
@@ -1875,12 +1873,12 @@ gdk_win32_window_set_back_pixmap (GdkWindow *window,
 }
 
 static void
-gdk_win32_window_set_cursor (GdkWindow *window,
-			     GdkCursor *cursor)
+gdk_win32_window_set_device_cursor (GdkWindow *window,
+                                    GdkDevice *device,
+                                    GdkCursor *cursor)
 {
   GdkWindowImplWin32 *impl;
   GdkCursorPrivate *cursor_private;
-  GdkWindowObject *parent_window;
   HCURSOR hcursor;
   HCURSOR hprevcursor;
   
@@ -1905,6 +1903,8 @@ gdk_win32_window_set_cursor (GdkWindow *window,
    */
   hprevcursor = impl->hcursor;
 
+  GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
+
   if (hcursor == NULL)
     impl->hcursor = NULL;
   else
@@ -1921,62 +1921,10 @@ gdk_win32_window_set_cursor (GdkWindow *window,
 			       hcursor, impl->hcursor));
     }
 
-  if (impl->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 (impl->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.
-	   */
-	  GdkWindowObject *curr_window_obj = GDK_WINDOW_OBJECT (curr_window);
-	  while (curr_window_obj &&
-		 !GDK_WINDOW_IMPL_WIN32 (curr_window_obj->impl)->hcursor)
-	    {
-	      curr_window_obj = curr_window_obj->parent;
-	      if (curr_window_obj == GDK_WINDOW_OBJECT (window))
-		{
-	          SetCursor (impl->hcursor);
-		  break;
-		}
-	    }
-	}
-    }
-
-  /* Destroy 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.
-   */
+  /* Destroy the previous cursor */
   if (hprevcursor != NULL)
     {
-      if (GetCursor () == hprevcursor)
-	{
-	  /* Look for a suitable cursor to use instead */
-	  hcursor = NULL;
-          parent_window = GDK_WINDOW_OBJECT (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);
-        }
-
       GDK_NOTE (MISC, g_print ("... DestroyCursor (%p)\n", hprevcursor));
-      
       API_CALL (DestroyCursor, (hprevcursor));
     }
 }
@@ -2159,87 +2107,43 @@ gdk_window_get_frame_extents (GdkWindow    *window,
 			   r.left, r.top));
 }
 
-
-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 gboolean
-gdk_window_win32_get_pointer (GdkWindow       *window,
-			      gint            *x,
-			      gint            *y,
-			      GdkModifierType *mask)
+gdk_window_win32_get_device_state (GdkWindow       *window,
+                                   GdkDevice       *device,
+                                   gint            *x,
+                                   gint            *y,
+                                   GdkModifierType *mask)
 {
-  gboolean return_val;
-  POINT point;
-  HWND hwnd, hwndc;
+  GdkWindow *child;
 
   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), FALSE);
-  
-  return_val = TRUE;
-
-  hwnd = GDK_WINDOW_HWND (window);
-  GetCursorPos (&point);
-  ScreenToClient (hwnd, &point);
 
-  *x = point.x;
-  *y = point.y;
-
-  if (window == _gdk_root)
-    {
-      *x += _gdk_offset_x;
-      *y += _gdk_offset_y;
-    }
-
-  hwndc = ChildWindowFromPoint (hwnd, point);
-  if (hwndc != NULL && hwndc != hwnd &&
-      !gdk_win32_handle_table_lookup ((GdkNativeWindow) hwndc))
-    return_val = FALSE; /* Direct child unknown to gdk */
-
-  *mask = get_current_mask ();
-  
-  return return_val;
+  GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+                                              NULL, &child,
+                                              NULL, NULL,
+                                              x, y, mask);
+  return (child != NULL);
 }
 
 void
-_gdk_windowing_get_pointer (GdkDisplay       *display,
-			    GdkScreen       **screen,
-			    gint             *x,
-			    gint             *y,
-			    GdkModifierType  *mask)
+_gdk_windowing_get_device_state (GdkDisplay       *display,
+                                 GdkDevice        *device,
+                                 GdkScreen       **screen,
+                                 gint             *x,
+                                 gint             *y,
+                                 GdkModifierType  *mask)
 {
-  POINT point;
-
   g_return_if_fail (display == _gdk_display);
-  
-  *screen = _gdk_screen;
-  GetCursorPos (&point);
-  *x = point.x + _gdk_offset_x;
-  *y = point.y + _gdk_offset_y;
 
-  *mask = get_current_mask ();
+  if (screen)
+    *screen = _gdk_screen;
+
+  GDK_DEVICE_GET_CLASS (device)->query_state (device,
+                                              gdk_screen_get_root_window (_gdk_screen),
+                                              NULL, NULL,
+                                              x, y,
+                                              NULL, NULL,
+                                              mask);
 }
 
 void
@@ -2248,64 +2152,40 @@ gdk_display_warp_pointer (GdkDisplay *display,
 			  gint        x,
 			  gint        y)
 {
+  GdkDeviceManagerWin32 *device_manager;
+
   g_return_if_fail (display == _gdk_display);
   g_return_if_fail (screen == _gdk_screen);
 
-  SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
+  device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display));
+  GDK_DEVICE_GET_CLASS (device_manager->core_pointer)->warp (device_manager->core_pointer,
+                                                             screen, x, y);
 }
 
-GdkWindow*
-_gdk_windowing_window_at_pointer (GdkDisplay *display,
-				  gint       *win_x,
-				  gint       *win_y,
-				  GdkModifierType *mask,
-				  gboolean    get_toplevel)
+void
+gdk_display_warp_device (GdkDisplay *display,
+                         GdkDevice  *device,
+                         GdkScreen  *screen,
+                         gint        x,
+                         gint        y)
 {
-  GdkWindow *window;
-  POINT point, pointc;
-  HWND hwnd, hwndc;
-  RECT rect;
-
-  GetCursorPos (&pointc);
-  point = pointc;
-  hwnd = WindowFromPoint (point);
-
-  if (hwnd == NULL)
-    {
-      window = _gdk_root;
-      *win_x = pointc.x + _gdk_offset_x;
-      *win_y = pointc.y + _gdk_offset_y;
-      return window;
-    }
-      
-  ScreenToClient (hwnd, &point);
-
-  do {
-    if (get_toplevel &&
-	(window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd)) != NULL &&
-	GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
-      break;
-
-    hwndc = ChildWindowFromPoint (hwnd, point);
-    ClientToScreen (hwnd, &point);
-    ScreenToClient (hwndc, &point);
-  } while (hwndc != hwnd && (hwnd = hwndc, 1));
-
-  window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
-
-  if (window && (win_x || win_y))
-    {
-      GetClientRect (hwnd, &rect);
-      *win_x = point.x - rect.left;
-      *win_y = point.y - rect.top;
-    }
+  g_return_if_fail (display == _gdk_display);
+  g_return_if_fail (screen == _gdk_screen);
+  g_return_if_fail (GDK_IS_DEVICE (device));
+  g_return_if_fail (display == gdk_device_get_display (device));
 
-  GDK_NOTE (MISC, g_print ("_gdk_windowing_window_at_pointer: %+d%+d %p%s\n",
-			   *win_x, *win_y,
-			   hwnd,
-			   (window == NULL ? " NULL" : "")));
+  GDK_DEVICE_GET_CLASS (device)->warp (device, screen, x, y);
+}
 
-  return window;
+GdkWindow*
+_gdk_windowing_window_at_device_position (GdkDisplay      *display,
+                                          GdkDevice       *device,
+                                          gint            *win_x,
+                                          gint            *win_y,
+                                          GdkModifierType *mask,
+                                          gboolean         get_toplevel)
+{
+  return GDK_DEVICE_GET_CLASS (device)->window_at_position (device, win_x, win_y, mask, get_toplevel);
 }
 
 static GdkEventMask  
@@ -3531,9 +3411,9 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
   iface->set_background = gdk_win32_window_set_background;
   iface->set_back_pixmap = gdk_win32_window_set_back_pixmap;
   iface->reparent = gdk_win32_window_reparent;
-  iface->set_cursor = gdk_win32_window_set_cursor;
+  iface->set_device_cursor = gdk_win32_window_set_device_cursor;
   iface->get_geometry = gdk_win32_window_get_geometry;
-  iface->get_pointer = gdk_window_win32_get_pointer;
+  iface->get_device_state = gdk_window_win32_get_device_state;
   iface->get_root_coords = gdk_win32_window_get_root_coords;
   iface->shape_combine_region = gdk_win32_window_shape_combine_region;
   iface->input_shape_combine_region = gdk_win32_input_shape_combine_region;
@@ -3542,6 +3422,4 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
   iface->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
   iface->queue_translation = _gdk_win32_window_queue_translation;
   iface->destroy = _gdk_win32_window_destroy;
-  iface->input_window_destroy = _gdk_input_window_destroy;
-  iface->input_window_crossing = _gdk_input_crossing_event;
 }



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