]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkinput-win32.c
Avoid spurious core pointer events when the tablet pen is lifted.
[~andy/gtk] / gdk / win32 / gdkinput-win32.c
index e6369c73e4d42205a9e7868c50ddf7421352cddc..c7bb9a3aa6ceb3ca276c949c3b2997c436ec6212 100644 (file)
 /* GDK - The GIMP Drawing Kit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1999 Tor Lillqvist
+ * Copyright (C) 1998-2002 Tor Lillqvist
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * 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.
  */
 
 /*
- * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 
-#include <gdk/gdk.h>
-#include "gdkx.h"
+#include "gdk.h"
 #include "gdkinput.h"
+#include "gdkinternals.h"
+#include "gdkprivate-win32.h"
+#include "gdkinput-win32.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
+#ifdef HAVE_WINTAB
 
-/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
- * there are several?) as a system pointing device, i.e. it controls
- * the normal Windows cursor. This seems much more natural.
- */
-#define USE_SYSCONTEXT 1       /* The code for the other choice is not
-                                * good at all.
-                                */
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y  | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+#define PACKETMODE (PK_BUTTONS)
+#include <pktdef.h>
+
+#define DEBUG_WINTAB 1         /* Verbose debug messages enabled */
+
+#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
+
+#endif
 
-#define TWOPI (2.*M_PI)
+#if defined(HAVE_WINTAB) || defined(HAVE_WHATEVER_OTHER)
+#define HAVE_SOME_XINPUT
+#endif
 
-#define PING() g_print("%s: %d\n",__FILE__,__LINE__)
+#define TWOPI (2.*G_PI)
 
 /* Forward declarations */
 
-static gint gdk_input_win32_set_mode (guint32      deviceid,
-                                     GdkInputMode mode);
-static void gdk_input_win32_get_pointer (GdkWindow       *window,
-                                        guint32            deviceid,
-                                        gdouble         *x,
-                                        gdouble         *y,
-                                        gdouble         *pressure,
-                                        gdouble         *xtilt,
-                                        gdouble         *ytilt,
-                                        GdkModifierType *mask);
-static void gdk_input_none_get_pointer (GdkWindow       *window,
-                                       guint32          deviceid,
-                                       gdouble         *x,
-                                       gdouble         *y,
-                                       gdouble         *pressure,
-                                       gdouble         *xtilt,
-                                       gdouble         *ytilt,
-                                       GdkModifierType *mask);
-static gint gdk_input_win32_grab_pointer (GdkWindow *     window,
-                                         gint            owner_events,
-                                         GdkEventMask    event_mask,
-                                         GdkWindow      *confine_to,
-                                         guint32         time);
-static void gdk_input_win32_ungrab_pointer (guint32 time);
-static void gdk_input_win32_configure_event (GdkEventConfigure *event, 
-                                            GdkWindow         *window);
-static void gdk_input_win32_enter_event (GdkEventCrossing  *xevent, 
-                                        GdkWindow         *window);
-static gint gdk_input_win32_other_event (GdkEvent  *event, 
-                                        MSG       *xevent);
-static gint gdk_input_win32_enable_window (GdkWindow        *window,
-                                          GdkDevicePrivate *gdkdev);
-static gint gdk_input_win32_disable_window (GdkWindow        *window,
-                                           GdkDevicePrivate *gdkdev);
-
-static GdkInputWindow *gdk_input_window_find (GdkWindow *window);
-static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
-static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid);
+#ifdef HAVE_WINTAB
+
 static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
                                                      UINT id);
+static GList     *wintab_contexts = NULL;
 
-/* Local variables */
+static GdkWindow *wintab_window = NULL;
 
-static GList     *gdk_input_devices;
-static GList     *gdk_input_windows;
-static GList     *wintab_contexts;
+#endif /* HAVE_WINTAB */
 
-static gint gdk_input_root_width;
-static gint gdk_input_root_height;
+#ifdef HAVE_SOME_XINPUT
 
-static GdkWindow *wintab_window;
+static GdkWindow *x_grab_window = NULL; /* Window that currently holds
+                                        * the extended inputs grab
+                                        */
+static GdkEventMask x_grab_mask;
+static gboolean x_grab_owner_events;
 
-static guint32 last_moved_cursor_id;
+#endif /* HAVE_SOME_XINPUT */
 
-static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
+#ifdef HAVE_WINTAB
 
-static GdkDeviceInfo gdk_input_core_info =
+static GdkDevicePrivate *
+gdk_input_find_dev_from_ctx (HCTX hctx,
+                            UINT cursor)
 {
-  GDK_CORE_POINTER,
-  "Core Pointer",
-  GDK_SOURCE_MOUSE,
-  GDK_MODE_SCREEN,
-  TRUE,
-  2,
-  gdk_input_core_axes
-};
-
-/* Global variables  */
+  GList *tmp_list = _gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
 
-GdkInputVTable    gdk_input_vtable;
-gint              gdk_input_ignore_core;
-gint             gdk_input_ignore_wintab = FALSE;
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
+      if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
 
-#if 0
+#if DEBUG_WINTAB
 
 static void
 print_lc(LOGCONTEXT *lc)
@@ -139,7 +109,6 @@ print_lc(LOGCONTEXT *lc)
   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");
-  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
   g_print ("\n");
   g_print ("lcStatus =");
   if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
@@ -203,14 +172,14 @@ print_lc(LOGCONTEXT *lc)
   if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
   g_print ("\n");
   g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
-         lc->lcBtnDnMask, lc->lcBtnUpMask);
-  g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\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 = %d, lcInExtY = %d, lcInExtZ = %d\n",
+  g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
          lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
-  g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n",
+  g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
          lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
-  g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n",
+  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.);
@@ -225,40 +194,41 @@ print_lc(LOGCONTEXT *lc)
 
 #endif
 
-void 
-gdk_input_init (void)
+void
+_gdk_input_wintab_init_check (void)
 {
+  static gboolean wintab_initialized = FALSE;
   GdkDevicePrivate *gdkdev;
-  GdkWindowPrivate *window_private;
   GdkWindowAttr wa;
   WORD specversion;
-  LOGCONTEXT defcontext;
   HCTX *hctx;
   UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
-  AXIS axis_x, axis_y, axis_npressure, axis_orientation[3];
-  int i, j, k;
+  BOOL active;
+  AXIS axis_x, axis_y, axis_npressure, axis_or[3];
+  int i, k;
+  int devix, cursorix;
   char devname[100], csrname[100];
-  guint32 deviceid_counter = 0;
+  BOOL defcontext_done;
 
-  gdk_input_devices = NULL;
+  if (wintab_initialized)
+    return;
+  
+  wintab_initialized = TRUE;
+  
   wintab_contexts = NULL;
 
-  if (!gdk_input_ignore_wintab &&
+  if (!_gdk_input_ignore_wintab &&
       WTInfo (0, 0, NULL))
     {
       WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
-
-#if USE_SYSCONTEXT
-      WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
-#else
-      WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
-#endif
-#if 0
-      g_print("DEFCONTEXT:\n"); print_lc(&defcontext);
-#endif
+      GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
+                              HIBYTE (specversion), LOBYTE (specversion)));
       WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
       WTInfo (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;
@@ -269,92 +239,75 @@ gdk_input_init (void)
       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_init: gdk_window_new failed");
+         g_warning ("gdk_input_wintab_init: gdk_window_new failed");
          return;
        }
-      gdk_window_ref (wintab_window);
-      window_private = (GdkWindowPrivate *) wintab_window;
+      g_object_ref (wintab_window);
       
-      for (i = 0; i < ndevices; i++)
+      for (devix = 0; devix < ndevices; devix++)
        {
          LOGCONTEXT lc;
+         
+         /* We open the Wintab device (hmm, what if there are several?) as a
+          * system pointing device, i.e. it controls the normal Windows
+          * cursor. This seems much more natural.
+          */
 
-         WTInfo (WTI_DEVICES + i, DVC_NAME, devname);
+         WTInfo (WTI_DEVICES + devix, DVC_NAME, devname);
       
-         WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes);
-         WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr);
-         WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware);
-         WTInfo (WTI_DEVICES + i, DVC_X, &axis_x);
-         WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y);
-         WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure);
-         WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation);
-
+         WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
+         WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
+         WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
+         WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x);
+         WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y);
+         WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
+         WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
+
+         defcontext_done = FALSE;
          if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
            {
-             WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName);
-             WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions);
-             lc.lcOptions |= CXO_MESSAGES;
-             lc.lcStatus = 0;
-             WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks);
-             lc.lcMsgBase = WT_DEFBASE;
-             lc.lcDevice = i;
-             lc.lcPktRate = 20;
-             lc.lcPktData = PACKETDATA;
-             lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
-             lc.lcMoveMask = PACKETDATA;
-             lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
-             WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX);
-             WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY);
-             WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ);
-             WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX);
-             WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY);
-             WTInfo (WTI_DDCTXS + i, CTX_INEXTZ, &lc.lcInExtZ);
-             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 */
-             WTInfo (WTI_DDCTXS + i, CTX_SENSX, &lc.lcSensX);
-             WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY);
-             WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ);
-             WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode);
-             lc.lcSysOrgX = lc.lcSysOrgY = 0;
-             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX);
-             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY);
-             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX);
-             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY);
-           }
-         else
-           {
-             lc = defcontext;
-             lc.lcOptions |= CXO_MESSAGES;
-             lc.lcMsgBase = WT_DEFBASE;
-             lc.lcPktRate = 20; /* Slow down the packets a bit */
-             lc.lcPktData = PACKETDATA;
-             lc.lcPktMode = PACKETMODE;
-             lc.lcMoveMask = PACKETDATA;
-             lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
-#if 0
-             lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
-#else
-             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 */
+             /* Try to get device-specific default context */
+             /* Some drivers, e.g. Aiptek, don't provide this info */
+             if (WTInfo (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 0
-         g_print("context for device %d:\n", i); print_lc(&lc);
+
+         if (!defcontext_done)
+           WTInfo (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 = 50;
+         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 = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL)
+          if ((*hctx = WTOpen (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
            {
-             g_warning ("gdk_input_init: WTOpen failed");
+             g_warning ("gdk_input_wintab_init: WTOpen failed");
              return;
            }
-         GDK_NOTE (MISC, g_print ("gdk_input_init: opened Wintab device %d %#x\n",
-                                  i, *hctx));
+         GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
+                                  devix, *hctx));
 
          wintab_contexts = g_list_append (wintab_contexts, hctx);
 #if 0
@@ -362,25 +315,39 @@ gdk_input_init (void)
 #endif
          WTOverlap (*hctx, TRUE);
 
-#if 0
-         g_print("context for device %d after WTOpen:\n", i); print_lc(&lc);
+#if DEBUG_WINTAB
+         GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
+                          print_lc(&lc)));
 #endif
-         for (j = firstcsr; j < firstcsr + ncsrtypes; j++)
+         /* 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 = 128; i >= 1; i >>= 1)
+           {
+             if (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++)
            {
-             gdkdev = g_new (GdkDevicePrivate, 1);
-             WTInfo (WTI_CURSORS + j, CSR_NAME, csrname);
+             active = FALSE;
+             WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
+             if (!active)
+               continue;
+             gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
+             WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname);
              gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
-             gdkdev->info.deviceid = deviceid_counter++;
              gdkdev->info.source = GDK_SOURCE_PEN;
              gdkdev->info.mode = GDK_MODE_SCREEN;
-#if USE_SYSCONTEXT
              gdkdev->info.has_cursor = TRUE;
-#else
-             gdkdev->info.has_cursor = FALSE;
-#endif
              gdkdev->hctx = *hctx;
-             gdkdev->cursor = j;
-             WTInfo (WTI_CURSORS + j, CSR_PKTDATA, &gdkdev->pktdata);
+             gdkdev->cursor = cursorix;
+             WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata);
              gdkdev->info.num_axes = 0;
              if (gdkdev->pktdata & PK_X)
                gdkdev->info.num_axes++;
@@ -388,16 +355,22 @@ gdk_input_init (void)
                gdkdev->info.num_axes++;
              if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
                gdkdev->info.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 ((gdkdev->pktdata & PK_ORIENTATION)
+                 && axis_or[0].axResolution == 0)
+               gdkdev->pktdata &= ~PK_ORIENTATION;
+
              if (gdkdev->pktdata & PK_ORIENTATION)
                gdkdev->info.num_axes += 2; /* x and y tilt */
-             WTInfo (WTI_CURSORS + j, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
+             WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
+             gdkdev->info.axes = g_new (GdkDeviceAxis, gdkdev->info.num_axes);
              gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
-             gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes);
              gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
              
-             for (k = 0; k < GDK_AXIS_LAST; k++)
-               gdkdev->axis_for_use[k] = -1;
-
              k = 0;
              if (gdkdev->pktdata & PK_X)
                {
@@ -407,8 +380,9 @@ gdk_input_init (void)
                    gdkdev->axes[k].min_value = axis_x.axMin;
                  gdkdev->axes[k].xmax_value =
                    gdkdev->axes[k].max_value = axis_x.axMax;
-                 gdkdev->info.axes[k] = GDK_AXIS_X;
-                 gdkdev->axis_for_use[GDK_AXIS_X] = k;
+                 gdkdev->info.axes[k].use = GDK_AXIS_X;
+                 gdkdev->info.axes[k].min = axis_x.axMin;
+                 gdkdev->info.axes[k].max = axis_x.axMax;
                  k++;
                }
              if (gdkdev->pktdata & PK_Y)
@@ -419,8 +393,9 @@ gdk_input_init (void)
                    gdkdev->axes[k].min_value = axis_y.axMin;
                  gdkdev->axes[k].xmax_value =
                    gdkdev->axes[k].max_value = axis_y.axMax;
-                 gdkdev->info.axes[k] = GDK_AXIS_Y;
-                 gdkdev->axis_for_use[GDK_AXIS_Y] = k;
+                 gdkdev->info.axes[k].use = GDK_AXIS_Y;
+                 gdkdev->info.axes[k].min = axis_y.axMin;
+                 gdkdev->info.axes[k].max = axis_y.axMax;
                  k++;
                }
              if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
@@ -431,114 +406,117 @@ gdk_input_init (void)
                    gdkdev->axes[k].min_value = axis_npressure.axMin;
                  gdkdev->axes[k].xmax_value =
                    gdkdev->axes[k].max_value = axis_npressure.axMax;
-                 gdkdev->info.axes[k] = GDK_AXIS_PRESSURE;
-                 gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k;
+                 gdkdev->info.axes[k].use = GDK_AXIS_PRESSURE;
+                 /* GIMP seems to expect values in the range 0-1 */
+                 gdkdev->info.axes[k].min = 0.0; /*axis_npressure.axMin;*/
+                 gdkdev->info.axes[k].max = 1.0; /*axis_npressure.axMax;*/
                  k++;
                }
              if (gdkdev->pktdata & PK_ORIENTATION)
                {
                  GdkAxisUse axis;
 
-                 gdkdev->orientation_axes[0] = axis_orientation[0];
-                 gdkdev->orientation_axes[1] = axis_orientation[1];
+                 gdkdev->orientation_axes[0] = axis_or[0];
+                 gdkdev->orientation_axes[1] = axis_or[1];
                  for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
                    {
+                     /* Wintab gives us aximuth and altitude, which
+                      * we convert to x and y tilt in the -1000..1000 range
+                      */
                      gdkdev->axes[k].xresolution =
                        gdkdev->axes[k].resolution = 1000;
                      gdkdev->axes[k].xmin_value =
                        gdkdev->axes[k].min_value = -1000;
                      gdkdev->axes[k].xmax_value =
                        gdkdev->axes[k].max_value = 1000;
-                     gdkdev->info.axes[k] = axis;
-                     gdkdev->axis_for_use[axis] = k;
+                     gdkdev->info.axes[k].use = axis;
+                     gdkdev->info.axes[k].min = -1000;
+                     gdkdev->info.axes[k].max = 1000;
                      k++;
                    }
                }
              gdkdev->info.num_keys = 0;
              gdkdev->info.keys = NULL;
-             GDK_NOTE (EVENTS,
-                       g_print ("gdk_input_init: device: %d axes: %d\n",
-                                gdkdev->info.deviceid,
+             GDK_NOTE (INPUT,
+                       g_print ("device: (%d) %s axes: %d\n",
+                                cursorix,
+                                gdkdev->info.name,
                                 gdkdev->info.num_axes));
-             gdk_input_devices = g_list_append (gdk_input_devices,
+             for (i = 0; i < gdkdev->info.num_axes; i++)
+               GDK_NOTE (INPUT,
+                         g_print ("... axis %d: %d--%d@%d (%d--%d@%d)\n",
+                                  i,
+                                  gdkdev->axes[i].xmin_value, 
+                                  gdkdev->axes[i].xmax_value, 
+                                  gdkdev->axes[i].xresolution, 
+                                  gdkdev->axes[i].min_value, 
+                                  gdkdev->axes[i].max_value, 
+                                  gdkdev->axes[i].resolution));
+             _gdk_input_devices = g_list_append (_gdk_input_devices,
                                                 gdkdev);
            }
        }
-      gdk_input_vtable.set_mode           = gdk_input_win32_set_mode;
-      gdk_input_vtable.set_axes           = NULL;
-      gdk_input_vtable.set_key            = NULL;
-      gdk_input_vtable.motion_events      = NULL;
-      gdk_input_vtable.get_pointer       = gdk_input_win32_get_pointer;
-      gdk_input_vtable.grab_pointer      = gdk_input_win32_grab_pointer;
-      gdk_input_vtable.ungrab_pointer     = gdk_input_win32_ungrab_pointer;
-      gdk_input_vtable.configure_event    = gdk_input_win32_configure_event;
-      gdk_input_vtable.enter_event        = gdk_input_win32_enter_event;
-      gdk_input_vtable.other_event        = gdk_input_win32_other_event;
-      gdk_input_vtable.enable_window      = gdk_input_win32_enable_window;
-      gdk_input_vtable.disable_window     = gdk_input_win32_disable_window;
-
-      gdk_input_root_width = gdk_screen_width ();
-      gdk_input_root_height = gdk_screen_height ();
-      gdk_input_ignore_core = FALSE;
-    }
-  else
-    {
-      gdk_input_vtable.set_mode           = NULL;
-      gdk_input_vtable.set_axes           = NULL;
-      gdk_input_vtable.set_key            = NULL;
-      gdk_input_vtable.motion_events      = NULL;
-      gdk_input_vtable.get_pointer       = gdk_input_none_get_pointer;
-      gdk_input_vtable.grab_pointer      = NULL;
-      gdk_input_vtable.ungrab_pointer     = NULL;
-      gdk_input_vtable.configure_event    = NULL;
-      gdk_input_vtable.enter_event        = NULL;
-      gdk_input_vtable.other_event        = NULL;
-      gdk_input_vtable.enable_window      = NULL;
-      gdk_input_vtable.disable_window     = NULL;
-      gdk_input_ignore_core = FALSE;
     }
-  
-  gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info);
 }
 
 static void
-gdk_input_get_root_relative_geometry (HWND w,
-                                     int  *x_ret,
-                                     int  *y_ret)
+decode_tilt (gint   *axis_data,
+            AXIS   *axes,
+            PACKET *packet)
 {
-  RECT rect;
-
-  GetWindowRect (w, &rect);
+  /* As I don't have a tilt-sensing tablet,
+   * I cannot test this code.
+   */
+  
+  double az, el;
 
-  if (x_ret)
-    *x_ret = rect.left;
-  if (y_ret)
-    *y_ret = rect.top;
+  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;
 }
 
+#endif /* HAVE_WINTAB */
+
 static void
 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
                                 GdkInputWindow   *input_window,
                                 gint             *axis_data,
-                                gdouble          *x,
-                                gdouble          *y,
-                                gdouble          *pressure,
-                                gdouble          *xtilt,
-                                gdouble          *ytilt)
+                                gdouble          *axis_out,
+                                gdouble          *x_out,
+                                gdouble          *y_out)
 {
-  GdkWindowPrivate *window_private;
-  gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis;
-  gdouble device_width, device_height;
-  gdouble x_offset, y_offset, x_scale, y_scale;
+  GdkWindowImplWin32 *impl, *root_impl;
 
-  window_private = (GdkWindowPrivate *) input_window->window;
+  int i;
+  int x_axis = 0;
+  int y_axis = 0;
 
-  x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
-  y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
-  pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE];
-  xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT];
-  ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT];
+  double device_width, device_height;
+  double x_offset, y_offset, x_scale, y_scale;
 
+  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (input_window->window)->impl);
+
+  for (i=0; i<gdkdev->info.num_axes; i++)
+    {
+      switch (gdkdev->info.axes[i].use)
+       {
+       case GDK_AXIS_X:
+         x_axis = i;
+         break;
+       case GDK_AXIS_Y:
+         y_axis = i;
+         break;
+       default:
+         break;
+       }
+    }
+  
   device_width = gdkdev->axes[x_axis].max_value - 
                   gdkdev->axes[x_axis].min_value;
   device_height = gdkdev->axes[y_axis].max_value - 
@@ -546,367 +524,237 @@ gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
 
   if (gdkdev->info.mode == GDK_MODE_SCREEN) 
     {
-      x_scale = gdk_input_root_width / device_width;
-      y_scale = gdk_input_root_height / device_height;
+      root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl);
+      x_scale = root_impl->width / device_width;
+      y_scale = root_impl->height / device_height;
 
-      x_offset = -input_window->root_x;
-      y_offset = -input_window->root_y;
+      x_offset = - input_window->root_x;
+      y_offset = - input_window->root_y;
     }
   else                         /* GDK_MODE_WINDOW */
     {
       double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
        (device_width*gdkdev->axes[x_axis].resolution);
 
-      if (device_aspect * window_private->width >= window_private->height)
+      if (device_aspect * impl->width >= impl->height)
        {
          /* device taller than window */
-         x_scale = window_private->width / device_width;
+         x_scale = impl->width / device_width;
          y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
            / gdkdev->axes[y_axis].resolution;
 
          x_offset = 0;
          y_offset = -(device_height * y_scale - 
-                              window_private->height)/2;
+                              impl->height)/2;
        }
       else
        {
          /* window taller than device */
-         y_scale = window_private->height / device_height;
+         y_scale = impl->height / device_height;
          x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
            / gdkdev->axes[x_axis].resolution;
 
          y_offset = 0;
-         x_offset = -(device_width * x_scale - window_private->width)/2;
+         x_offset = - (device_width * x_scale - impl->width)/2;
        }
     }
-  
-  if (x)
-    *x = x_offset + x_scale*axis_data[x_axis];
-  if (y)
-    *y = y_offset + y_scale*axis_data[y_axis];
-
-  if (pressure)
-    {
-      if (pressure_axis != -1)
-       *pressure = ((double)axis_data[pressure_axis] 
-                    - gdkdev->axes[pressure_axis].min_value) 
-         / (gdkdev->axes[pressure_axis].max_value 
-            - gdkdev->axes[pressure_axis].min_value);
-      else
-       *pressure = 0.5;
-    }
 
-  if (xtilt)
-    {
-      if (xtilt_axis != -1)
-       {
-         *xtilt = 2. * (double)(axis_data[xtilt_axis] - 
-                                (gdkdev->axes[xtilt_axis].min_value +
-                                 gdkdev->axes[xtilt_axis].max_value)/2) /
-           (gdkdev->axes[xtilt_axis].max_value -
-            gdkdev->axes[xtilt_axis].min_value);
-       }
-      else
-       *xtilt = 0;
-    }
-  
-  if (ytilt)
-    {
-      if (ytilt_axis != -1)
-       {
-         *ytilt = 2. * (double)(axis_data[ytilt_axis] - 
-                                (gdkdev->axes[ytilt_axis].min_value +
-                                 gdkdev->axes[ytilt_axis].max_value)/2) /
-           (gdkdev->axes[ytilt_axis].max_value -
-            gdkdev->axes[ytilt_axis].min_value);
-       }
-      else
-       *ytilt = 0;
-    }
-}
-
-gint
-gdk_input_set_mode (guint32      deviceid,
-                   GdkInputMode mode)
-{
-  if (deviceid == GDK_CORE_POINTER)
-    return FALSE;
-
-  if (gdk_input_vtable.set_mode)
-    return gdk_input_vtable.set_mode (deviceid, mode);
-  else
-    return FALSE;
-}
-
-void
-gdk_input_set_axes (guint32     deviceid,
-                   GdkAxisUse *axes)
-{
-  int i;
-  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
-  g_return_if_fail (gdkdev != NULL);
-
-  if (deviceid == GDK_CORE_POINTER)
-    return;
-
-  for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
-    {
-      gdkdev->axis_for_use[i] = -1;
-    }
-
-  for (i = 0; i < gdkdev->info.num_axes; i++)
-    {
-      gdkdev->info.axes[i] = axes[i];
-      gdkdev->axis_for_use[axes[i]] = i;
-    }
-}
-
-static void 
-gdk_input_win32_get_pointer (GdkWindow       *window,
-                            guint32          deviceid,
-                            gdouble         *x,
-                            gdouble         *y,
-                            gdouble         *pressure,
-                            gdouble         *xtilt,
-                            gdouble         *ytilt,
-                            GdkModifierType *mask)
-{
-  GdkDevicePrivate *gdkdev;
-  GdkInputWindow *input_window;
-  gint x_int, y_int;
-  gint i;
-
-  if (deviceid == GDK_CORE_POINTER)
-    {
-      gdk_window_get_pointer (window, &x_int, &y_int, mask);
-      if (x)
-       *x = x_int;
-      if (y)
-       *y = y_int;
-      if (pressure)
-       *pressure = 0.5;
-      if (xtilt)
-       *xtilt = 0;
-      if (ytilt)
-       *ytilt = 0;
-    }
-  else
+  for (i=0; i<gdkdev->info.num_axes; i++)
     {
-      if (mask)
-       gdk_window_get_pointer (window, NULL, NULL, mask);
-      
-      gdkdev = gdk_input_find_device (deviceid);
-      g_return_if_fail (gdkdev != NULL);
-
-      input_window = gdk_input_window_find (window);
-      g_return_if_fail (input_window != NULL);
-
-      gdk_input_translate_coordinates (gdkdev, input_window,
-                                      gdkdev->last_axis_data,
-                                      x, y, pressure,
-                                      xtilt, ytilt);
-      if (mask)
+      switch (gdkdev->info.axes[i].use)
        {
-         *mask &= 0xFF;
-         *mask |= ((gdkdev->last_buttons & 0x1F) << 8);
+       case GDK_AXIS_X:
+         axis_out[i] = x_offset + x_scale*axis_data[x_axis];
+         if (x_out)
+           *x_out = axis_out[i];
+         break;
+       case GDK_AXIS_Y:
+         axis_out[i] = y_offset + y_scale*axis_data[y_axis];
+         if (y_out)
+           *y_out = axis_out[i];
+         break;
+       default:
+         axis_out[i] =
+           (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
+            gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
+           (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
+         break;
        }
     }
 }
 
 static void
-gdk_input_none_get_pointer (GdkWindow       *window,
-                           guint32          deviceid,
-                           gdouble         *x,
-                           gdouble         *y,
-                           gdouble         *pressure,
-                           gdouble         *xtilt,
-                           gdouble         *ytilt,
-                           GdkModifierType *mask)
-{
-  gint x_int, y_int;
-
-  gdk_window_get_pointer (window, &x_int, &y_int, mask);
-
-  if (x)
-    *x = x_int;
-  if (y)
-    *y = y_int;
-  if (pressure)
-    *pressure = 0.5;
-  if (xtilt)
-    *xtilt = 0;
-  if (ytilt)
-    *ytilt = 0;
-}
-
-static gint
-gdk_input_win32_set_mode (guint32      deviceid,
-                         GdkInputMode mode)
+gdk_input_get_root_relative_geometry (HWND w,
+                                     int  *x_ret,
+                                     int  *y_ret)
 {
-  GList *tmp_list;
-  GdkDevicePrivate *gdkdev;
-  GdkInputMode old_mode;
-  GdkInputWindow *input_window;
-
-  if (deviceid == GDK_CORE_POINTER)
-    return FALSE;
-
-  gdkdev = gdk_input_find_device (deviceid);
-  g_return_val_if_fail (gdkdev != NULL, FALSE);
-  old_mode = gdkdev->info.mode;
-
-  if (old_mode == mode)
-    return TRUE;
-
-  gdkdev->info.mode = mode;
+  RECT rect;
 
-  if (mode == GDK_MODE_WINDOW)
-    {
-      gdkdev->info.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_win32_enable_window (input_window->window, gdkdev);
-         else
-           if (old_mode != GDK_MODE_DISABLED)
-             gdk_input_win32_disable_window (input_window->window, gdkdev);
-       }
-    }
-  else if (mode == GDK_MODE_SCREEN)
-    {
-      gdkdev->info.has_cursor = TRUE;
-      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
-       gdk_input_win32_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_win32_disable_window (input_window->window, gdkdev);
-       }
-    }
+  GetWindowRect (w, &rect);
 
-  return TRUE;
+  if (x_ret)
+    *x_ret = rect.left + _gdk_offset_x;
+  if (y_ret)
+    *y_ret = rect.top + _gdk_offset_y;
 }
 
-static void
-gdk_input_win32_configure_event (GdkEventConfigure *event,
-                                GdkWindow         *window)
+void
+_gdk_input_configure_event (GdkWindow         *window)
 {
   GdkInputWindow *input_window;
-  gint root_x, root_y;
+  int root_x, root_y;
 
-  input_window = gdk_input_window_find (window);
+  input_window = _gdk_input_window_find (window);
   g_return_if_fail (window != NULL);
 
-  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
                                        &root_x, &root_y);
 
   input_window->root_x = root_x;
   input_window->root_y = root_y;
 }
 
-static void 
-gdk_input_win32_enter_event (GdkEventCrossing *event, 
-                            GdkWindow        *window)
+void 
+_gdk_input_enter_event (GdkWindow        *window)
 {
   GdkInputWindow *input_window;
-  gint root_x, root_y;
+  int root_x, root_y;
 
-  input_window = gdk_input_window_find (window);
+  input_window = _gdk_input_window_find (window);
   g_return_if_fail (window != NULL);
 
-  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
-                                       &root_x, &root_y);
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
 
   input_window->root_x = root_x;
   input_window->root_y = root_y;
 }
 
-static void
-decode_tilt (gint   *axis_data,
-            AXIS   *axes,
-            PACKET *packet)
+/*
+ * 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)
 {
-  /* As I don't have a tilt-sensing tablet,
-   * I cannot test this code.
-   */
+  guint state;
   
-  double az, el;
+  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;
+}
 
-  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;
+#ifdef HAVE_WINTAB
+
+static guint ignore_core_timer = 0;
+
+static gboolean
+ignore_core_timefunc (gpointer data)
+{
+  /* The delay has passed */
+  _gdk_input_ignore_core = FALSE;
+  ignore_core_timer = 0;
+
+  return FALSE; /* remove timeout */
 }
 
-static gint 
-gdk_input_win32_other_event (GdkEvent  *event,
-                            MSG       *xevent)
+/*
+ * 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)
 {
-  GdkWindow *current_window;
+  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 = g_timeout_add (PROXIMITY_OUT_DELAY,
+                                        ignore_core_timefunc, NULL);
+}
+#endif /* HAVE_WINTAB */
+
+gboolean 
+_gdk_input_other_event (GdkEvent  *event,
+                       MSG       *msg,
+                       GdkWindow *window)
+{
+#ifdef HAVE_WINTAB
+  GdkDisplay *display;
+  GdkWindowObject *obj, *grab_obj;
   GdkInputWindow *input_window;
-  GdkWindow *window;
-  GdkWindowPrivate *window_private;
-  GdkDevicePrivate *gdkdev;
+  GdkDevicePrivate *gdkdev = NULL;
   GdkEventMask masktest;
+  guint key_state;
   POINT pt;
+
   PACKET packet;
-  gint return_val;
   gint k;
   gint x, y;
 
   if (event->any.window != wintab_window)
-    g_warning ("gdk_input_win32_other_event: not wintab_window?");
+    {
+      g_warning ("_gdk_input_other_event: not wintab_window?");
+      return FALSE;
+    }
 
-#if USE_SYSCONTEXT
   window = gdk_window_at_pointer (&x, &y);
   if (window == NULL)
-    window = (GdkWindow *) &gdk_root_parent;
-
-  gdk_window_ref (window);
+    window = _gdk_root;
 
-  window_private = (GdkWindowPrivate *) window;
+  g_object_ref (window);
+  display = gdk_drawable_get_display (window);
 
-  GDK_NOTE (EVENTS, g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", window_private->xwindow, x, y));
+  GDK_NOTE (EVENTS_OR_INPUT,
+           g_print ("gdk_input_win32_other_event: window=%p %+d%+d\n",
+                    GDK_WINDOW_HWND (window), x, y));
   
-#else
-  /* ??? This code is pretty bogus */
-  current_window = gdk_window_lookup (GetActiveWindow ());
-  if (current_window == NULL)
-    return FALSE;
-  
-  input_window = gdk_input_window_find_within (current_window);
-  if (input_window == NULL)
-    return FALSE;
-#endif
-
-  if (xevent->message == WT_PACKET)
+  if (msg->message == WT_PACKET)
     {
-      if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet))
+      if (!WTPacket ((HCTX) msg->lParam, msg->wParam, &packet))
        return FALSE;
     }
 
-  switch (xevent->message)
+  obj = GDK_WINDOW_OBJECT (window);
+
+  switch (msg->message)
     {
     case WT_PACKET:
-      if (window_private == &gdk_root_parent)
+      /* Don't produce any button or motion events while a window is being
+       * moved or resized, see bug #151090. */
+      if (_sizemove_in_progress)
        {
-         GDK_NOTE (EVENTS, g_print ("...is root\n"));
+         GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
+         return FALSE;
+       }
+      if (window == _gdk_root && x_grab_window == NULL)
+       {
+         GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
          return FALSE;
        }
 
-      if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam,
+      if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
                                                 packet.pkCursor)) == NULL)
        return FALSE;
 
@@ -959,33 +807,63 @@ gdk_input_win32_other_event (GdkEvent  *event,
            masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
        }
 
+      /* See if input is grabbed */
+      /* FIXME: x_grab_owner_events should probably be handled somehow */
+      if (x_grab_window != NULL)
+       {
+         grab_obj = GDK_WINDOW_OBJECT (x_grab_window);
+         if (!GDK_WINDOW_IMPL_WIN32 (grab_obj->impl)->extension_events_selected
+             || !(grab_obj->extension_events & masktest)
+             || !(x_grab_mask && masktest))
+           {
+             GDK_NOTE (EVENTS_OR_INPUT, 
+                       g_print ("... grabber doesn't want it\n"));
+             return FALSE;
+           }
+         GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
+
+         g_object_ref(x_grab_window);
+         g_object_unref(window);
+         window = x_grab_window;
+         obj = grab_obj;
+       }
       /* Now we can check if the window wants the event, and
        * propagate if necessary.
        */
     dijkstra:
-      if (!window_private->extension_events_selected
-         || !(window_private->extension_events & masktest))
+      if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
+         || !(obj->extension_events & masktest))
        {
-         GDK_NOTE (EVENTS, g_print ("...not selected\n"));
+         GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
 
-         if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+         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 (window_private->xwindow, &pt);
-         gdk_window_unref (window);
-         window = window_private->parent;
-         gdk_window_ref (window);
-         window_private = (GdkWindowPrivate *) window;
-         ScreenToClient (window_private->xwindow, &pt);
+         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, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, x, y));
+         GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
+                                             GDK_WINDOW_HWND (window), x, y));
          goto dijkstra;
        }
 
-      input_window = gdk_input_window_find (window);
+      input_window = _gdk_input_window_find (window);
 
       g_assert (input_window != NULL);
 
@@ -994,65 +872,66 @@ gdk_input_win32_other_event (GdkEvent  *event,
        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 = xevent->time;
-         event->button.source = gdkdev->info.source;
-         last_moved_cursor_id = 
-           event->button.deviceid = gdkdev->info.deviceid;
+         event->button.time = _gdk_win32_get_next_tick (msg->time);
+         event->button.device = &gdkdev->info;
          
-#if 0
-#if USE_SYSCONTEXT
-         /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
-         if (event->button.button <= 3)
-           return FALSE;
-#endif
-#endif
+         event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
+
          gdk_input_translate_coordinates (gdkdev, input_window,
                                           gdkdev->last_axis_data,
-                                          &event->button.x, &event->button.y,
-                                          &event->button.pressure,
-                                          &event->button.xtilt, 
-                                          &event->button.ytilt);
+                                          event->button.axes,
+                                          &event->button.x, 
+                                          &event->button.y);
+
+         /* Also calculate root coordinates. Note that input_window->root_x
+            is in GDK root coordinates. */
+         event->button.x_root = event->button.x + input_window->root_x;
+         event->button.y_root = event->button.y + input_window->root_y;
 
          event->button.state = ((gdkdev->button_state << 8)
                                 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
                                    | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
-                                   | GDK_BUTTON5_MASK));
-         GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g\n",
-                                    (event->button.type == GDK_BUTTON_PRESS ?
-                                     "press" : "release"),
-                                    event->button.deviceid,
-                                    event->button.button,
-                                    event->button.x, event->button.y,
-                                    event->button.pressure));
+                                   | GDK_BUTTON5_MASK))
+                               | key_state;
+         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 = xevent->time;
-         last_moved_cursor_id =
-           event->motion.deviceid = gdkdev->info.deviceid;
+         event->motion.time = _gdk_win32_get_next_tick (msg->time);
          event->motion.is_hint = FALSE;
-         event->motion.source = gdkdev->info.source;
+         event->motion.device = &gdkdev->info;
+
+         event->motion.axes = g_new(gdouble, gdkdev->info.num_axes);
 
          gdk_input_translate_coordinates (gdkdev, input_window,
                                           gdkdev->last_axis_data,
-                                          &event->motion.x, &event->motion.y,
-                                          &event->motion.pressure,
-                                          &event->motion.xtilt, 
-                                          &event->motion.ytilt);
+                                          event->motion.axes,
+                                          &event->motion.x, 
+                                          &event->motion.y);
+
+         /* Also calculate root coordinates. Note that input_window->root_x
+            is in GDK root coordinates. */
+         event->motion.x_root = event->motion.x + input_window->root_x;
+         event->motion.y_root = event->motion.y + input_window->root_y;
 
          event->motion.state = ((gdkdev->button_state << 8)
                                 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
                                    | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
-                                   | GDK_BUTTON5_MASK));
+                                   | GDK_BUTTON5_MASK))
+                               | key_state;
 
-         GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g\n",
-                                    event->motion.deviceid,
-                                    event->motion.x, event->motion.y,
-                                    event->motion.pressure));
+         GDK_NOTE (EVENTS_OR_INPUT,
+                   g_print ("WINTAB motion: %g,%g\n",
+                            event->motion.x, event->motion.y));
 
          /* Check for missing release or press events for the normal
           * pressure button. At least on my ArtPadII I sometimes miss a
@@ -1060,7 +939,7 @@ gdk_input_win32_other_event (GdkEvent  *event,
           */
          if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
               && (event->motion.state & GDK_BUTTON1_MASK)
-              && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2))
+              && packet.pkNormalPressure <= MAX (0, (gint) gdkdev->npbtnmarks[0] - 2))
              || (gdkdev->pktdata & PK_NORMAL_PRESSURE
                  && !(event->motion.state & GDK_BUTTON1_MASK)
                  && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
@@ -1079,88 +958,92 @@ gdk_input_win32_other_event (GdkEvent  *event,
              event2->button.state = ((gdkdev->button_state << 8)
                                      & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
                                         | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
-                                        | GDK_BUTTON5_MASK));
+                                        | GDK_BUTTON5_MASK))
+                                    | key_state;
              event2->button.button = 1;
-             GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n",
-                                        (event2->button.type == GDK_BUTTON_PRESS ?
-                                         "press" : "release"),
-                                        event2->button.deviceid,
-                                        event2->button.button,
-                                        event2->button.x, event2->button.y,
-                                        event2->button.pressure));
-             gdk_event_queue_append (event2);
+             GDK_NOTE (EVENTS_OR_INPUT,
+                       g_print ("WINTAB synthesized button %s: %d %g,%gg\n",
+                                (event2->button.type == GDK_BUTTON_PRESS ?
+                                 "press" : "release"),
+                                event2->button.button,
+                                event2->button.x,
+                                event2->button.y));
+             _gdk_event_queue_append (display, event2);
            }
        }
       return TRUE;
 
     case WT_PROXIMITY:
-      if (LOWORD (xevent->lParam) == 0)
+      if (LOWORD (msg->lParam) == 0)
        {
          event->proximity.type = GDK_PROXIMITY_OUT;
-         gdk_input_ignore_core = FALSE;
+         set_ignore_core (FALSE);
        }
       else
        {
          event->proximity.type = GDK_PROXIMITY_IN;
-         gdk_input_ignore_core = TRUE;
+         set_ignore_core (TRUE);
        }
-      event->proximity.time = xevent->time;
-      event->proximity.source = GDK_SOURCE_PEN;
-      event->proximity.deviceid = last_moved_cursor_id;
-
-      GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n",
-                                (event->proximity.type == GDK_PROXIMITY_IN ?
-                                 "in" : "out"),
-                                event->proximity.deviceid));
+      event->proximity.time = _gdk_win32_get_next_tick (msg->time);
+      event->proximity.device = &gdkdev->info;
+
+      GDK_NOTE (EVENTS_OR_INPUT,
+               g_print ("WINTAB proximity %s\n",
+                        (event->proximity.type == GDK_PROXIMITY_IN ?
+                         "in" : "out")));
       return TRUE;
     }
-
+#endif
   return FALSE;
 }
 
-static gint
-gdk_input_win32_enable_window (GdkWindow        *window,
-                              GdkDevicePrivate *gdkdev)
+gboolean
+_gdk_input_enable_window (GdkWindow        *window,
+                         GdkDevicePrivate *gdkdev)
 {
-  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+#ifdef HAVE_SOME_XINPUT
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+  impl->extension_events_selected = TRUE;
+#endif
 
-  window_private->extension_events_selected = TRUE;
   return TRUE;
 }
 
-static gint
-gdk_input_win32_disable_window (GdkWindow        *window,
-                               GdkDevicePrivate *gdkdev)
+gboolean
+_gdk_input_disable_window (GdkWindow        *window,
+                          GdkDevicePrivate *gdkdev)
 {
-  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+#ifdef HAVE_SOME_XINPUT
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+  impl->extension_events_selected = FALSE;
+#endif
 
-  window_private->extension_events_selected = FALSE;
   return TRUE;
 }
 
-static gint
-gdk_input_win32_grab_pointer (GdkWindow    *window,
-                             gint          owner_events,
-                             GdkEventMask  event_mask,
-                             GdkWindow    *confine_to,
-                             guint32       time)
+gint
+_gdk_input_grab_pointer (GdkWindow    *window,
+                        gint          owner_events,
+                        GdkEventMask  event_mask,
+                        GdkWindow    *confine_to,
+                        guint32       time)
 {
+#ifdef HAVE_SOME_XINPUT
   GdkInputWindow *input_window, *new_window;
   gboolean need_ungrab;
   GdkDevicePrivate *gdkdev;
   GList *tmp_list;
-  gint result;
 
-  tmp_list = gdk_input_windows;
+  tmp_list = _gdk_input_windows;
   new_window = NULL;
   need_ungrab = FALSE;
 
-  GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n",
-                          ((GdkWindowPrivate *) window)->xwindow,
+  GDK_NOTE (INPUT, g_print ("gdk_input_win32_grab_pointer: %p %d %p\n",
+                          GDK_WINDOW_HWND (window),
                           owner_events,
-                          (confine_to ?
-                           ((GdkWindowPrivate *) confine_to)->xwindow :
-                           0)));
+                          (confine_to ? GDK_WINDOW_HWND (confine_to) : 0)));
 
   while (tmp_list)
     {
@@ -1180,18 +1063,25 @@ gdk_input_win32_grab_pointer (GdkWindow    *window,
   if (new_window)
     {
       new_window->grabbed = TRUE;
+      x_grab_window = window;
+      x_grab_mask = event_mask;
+      x_grab_owner_events = owner_events;
+
+      /* FIXME: Do we need to handle confine_to and time? */
       
-      tmp_list = gdk_input_devices;
+      tmp_list = _gdk_input_devices;
       while (tmp_list)
        {
          gdkdev = (GdkDevicePrivate *)tmp_list->data;
-         if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+         if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
            {
 #if 0        
-             gdk_input_find_events (window, gdkdev,
-                                    event_mask,
-                                    event_classes, &num_classes);
-             result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice,
+             /* XXX */
+             gdk_input_common_find_events (window, gdkdev,
+                                           event_mask,
+                                           event_classes, &num_classes);
+             
+             result = XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
                                    GDK_WINDOW_XWINDOW (window),
                                    owner_events, num_classes, event_classes,
                                    GrabModeAsync, GrabModeAsync, time);
@@ -1207,14 +1097,16 @@ gdk_input_win32_grab_pointer (GdkWindow    *window,
     }
   else
     { 
-      tmp_list = gdk_input_devices;
+      x_grab_window = NULL;
+      tmp_list = _gdk_input_devices;
       while (tmp_list)
        {
          gdkdev = (GdkDevicePrivate *)tmp_list->data;
-         if (gdkdev->info.deviceid != GDK_CORE_POINTER && 
+         if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
              ((gdkdev->button_state != 0) || need_ungrab))
            {
 #if 0
+             /* XXX */
              XUngrabDevice (gdk_display, gdkdev->xdevice, time);
 #endif
              gdkdev->button_state = 0;
@@ -1223,21 +1115,22 @@ gdk_input_win32_grab_pointer (GdkWindow    *window,
          tmp_list = tmp_list->next;
        }
     }
+#endif
 
-  return Success;
-      
+  return GDK_GRAB_SUCCESS;
 }
 
-static void 
-gdk_input_win32_ungrab_pointer (guint32 time)
+void 
+_gdk_input_ungrab_pointer (guint32 time)
 {
+#ifdef HAVE_SOME_XINPUT
   GdkInputWindow *input_window;
   GdkDevicePrivate *gdkdev;
   GList *tmp_list;
 
-  GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n"));
+  GDK_NOTE (INPUT, g_print ("gdk_input_win32_ungrab_pointer\n"));
 
-  tmp_list = gdk_input_windows;
+  tmp_list = _gdk_input_windows;
   while (tmp_list)
     {
       input_window = (GdkInputWindow *)tmp_list->data;
@@ -1250,282 +1143,126 @@ gdk_input_win32_ungrab_pointer (guint32 time)
     {
       input_window->grabbed = FALSE;
 
-      tmp_list = gdk_input_devices;
+      tmp_list = _gdk_input_devices;
       while (tmp_list)
        {
          gdkdev = (GdkDevicePrivate *)tmp_list->data;
 #if 0
-         if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice)
+         /* XXX */
+         if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
            XUngrabDevice (gdk_display, gdkdev->xdevice, time);
 #endif
          tmp_list = tmp_list->next;
        }
     }
+  x_grab_window = NULL;
+#endif
 }
 
-GList *
-gdk_input_list_devices (void)
-{
-  return gdk_input_devices;
-}
-
-void
-gdk_input_set_source (guint32        deviceid,
-                     GdkInputSource source)
-{
-  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
-  g_return_if_fail (gdkdev != NULL);
-
-  gdkdev->info.source = source;
-}
-
-void gdk_input_set_key (guint32 deviceid,
-                       guint   index,
-                       guint   keyval,
-                       GdkModifierType modifiers)
-{
-  if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
-    gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
-}
-
-GdkTimeCoord *
-gdk_input_motion_events (GdkWindow *window,
-                        guint32    deviceid,
-                        guint32    start,
-                        guint32    stop,
-                        gint      *nevents_return)
-{
-  GdkWindowPrivate *window_private;
-  GdkTimeCoord *coords;
-  int i;
-
-  g_return_val_if_fail (window != NULL, NULL);
-  window_private = (GdkWindowPrivate *) window;
-  if (window_private->destroyed)
-    return NULL;
-
-  *nevents_return = 0;
-  return NULL;         /* ??? */
-}
-
-static 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 */
-}
-
-static GdkInputWindow *
-gdk_input_window_find_within (GdkWindow *window)
+gboolean
+_gdk_device_get_history (GdkDevice         *device,
+                        GdkWindow         *window,
+                        guint32            start,
+                        guint32            stop,
+                        GdkTimeCoord    ***events,
+                        gint              *n_events)
 {
-  GList *tmp_list;
-  GdkWindowPrivate *window_private;
-  GdkWindowPrivate *tmp_private;
-  GdkInputWindow *candidate = NULL;
-
-  window_private = (GdkWindowPrivate *) window;
-
-  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
-    {
-      (GdkWindowPrivate *) tmp_private =
-       (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window);
-      if (tmp_private == window_private
-         || IsChild (window_private->xwindow, tmp_private->xwindow))
-       {
-         if (candidate)
-           return NULL;                /* Multiple hits */
-         candidate = (GdkInputWindow *)(tmp_list->data);
-       }
-    }
-
-  return candidate;
+  return FALSE;
 }
 
-/* FIXME: this routine currently needs to be called between creation
-   and the corresponding configure event (because it doesn't get the
-   root_relative_geometry).  This should work with
-   gtk_window_set_extension_events, but will likely fail in other
-   cases */
-
-void
-gdk_input_set_extension_events (GdkWindow       *window,
-                               gint             mask,
-                               GdkExtensionMode mode)
+void 
+gdk_device_get_state (GdkDevice       *device,
+                     GdkWindow       *window,
+                     gdouble         *axes,
+                     GdkModifierType *mask)
 {
-  GdkWindowPrivate *window_private;
-  GList *tmp_list;
-  GdkInputWindow *iw;
+  g_return_if_fail (device != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
 
-  g_return_if_fail (window != NULL);
-  window_private = (GdkWindowPrivate *) window;
-  if (window_private->destroyed)
-    return;
-
-  if (mode == GDK_EXTENSION_EVENTS_NONE)
-    mask = 0;
-
-  if (mask != 0)
+  if (GDK_IS_CORE (device))
     {
-      iw = g_new (GdkInputWindow,1);
-
-      iw->window = window;
-      iw->mode = mode;
-
-      iw->grabbed = FALSE;
-
-      gdk_input_windows = g_list_append (gdk_input_windows, iw);
-      window_private->extension_events = mask;
+      gint x_int, y_int;
+      
+      gdk_window_get_pointer (window, &x_int, &y_int, mask);
 
-      /* Add enter window events to the event mask */
-      gdk_window_set_events (window,
-                            gdk_window_get_events (window) | 
-                            GDK_ENTER_NOTIFY_MASK);
-    }
-  else
-    {
-      iw = gdk_input_window_find (window);
-      if (iw)
+      if (axes)
        {
-         gdk_input_windows = g_list_remove (gdk_input_windows, iw);
-         g_free (iw);
+         axes[0] = x_int;
+         axes[1] = y_int;
        }
-
-      window_private->extension_events = 0;
     }
-
-  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+  else
     {
-      GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
-
-      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+      GdkDevicePrivate *gdkdev;
+      GdkInputWindow *input_window;
+      
+      gdkdev = (GdkDevicePrivate *)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)
        {
-         if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
-             && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
-           gdk_input_win32_enable_window (window, gdkdev);
-         else
-           gdk_input_win32_disable_window (window, gdkdev);
+         gdk_window_get_pointer (window, NULL, NULL, mask);
+         *mask &= 0xFF; /* Mask away core pointer buttons */
+         *mask |= ((gdkdev->button_state << 8)
+                   & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                      | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                      | GDK_BUTTON5_MASK));
        }
+      input_window = _gdk_input_window_find (window);
+      g_return_if_fail (input_window != NULL);
+      /* For some reason, input_window is sometimes NULL when I use The GIMP 2
+       * (bug #141543?). Avoid crashing if debugging is disabled. */
+      if (axes && gdkdev->last_axis_data && input_window)
+       gdk_input_translate_coordinates (gdkdev, input_window,
+                                        gdkdev->last_axis_data,
+                                        axes, NULL, NULL);
     }
 }
 
+#ifdef HAVE_WINTAB
 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);
-}
-
-void
-gdk_input_exit (void)
+_gdk_input_set_tablet_active (void)
 {
   GList *tmp_list;
-  GdkDevicePrivate *gdkdev;
-
-  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
-    {
-      gdkdev = (GdkDevicePrivate *)(tmp_list->data);
-      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
-       {
-         gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED);
-         g_free (gdkdev->info.name);
-         g_free (gdkdev->last_axis_data);
-         g_free (gdkdev->info.axes);
-         g_free (gdkdev->info.keys);
-         g_free (gdkdev->axes);
-         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);
-
-#if 1
-  for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next)
-    {
-      HCTX *hctx = (HCTX *) tmp_list->data;
-      BOOL result;
-
-      /* For some reason WTEnable and/or WTClose tend to crash here.
-       * Protect with __try/__except to avoid a message box.
-       */
-      __try {
-#if 0
-        WTEnable (*hctx, FALSE);
-#endif
-       result = WTClose (*hctx);
-      }
-      __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */
-                EXCEPTION_EXECUTE_HANDLER /*: 
-                EXCEPTION_CONTINUE_SEARCH */) {
-       result = FALSE;
-      }
-      if (!result)
-       g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx);
-      g_free (hctx);
-    }
-#endif
-  g_list_free (wintab_contexts);
-}
+  HCTX *hctx;
 
-static GdkDevicePrivate *
-gdk_input_find_device (guint32 id)
-{
-  GList *tmp_list = gdk_input_devices;
-  GdkDevicePrivate *gdkdev;
+  /* 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)
     {
-      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
-      if (gdkdev->info.deviceid == id)
-       return gdkdev;
+      hctx = (HCTX *) (tmp_list->data);
+      WTOverlap (*hctx, TRUE);
       tmp_list = tmp_list->next;
     }
-  return NULL;
 }
+#endif /* HAVE_WINTAB */
 
-static GdkDevicePrivate *
-gdk_input_find_dev_from_ctx (HCTX hctx,
-                            UINT cursor)
+void 
+_gdk_input_init (GdkDisplay *display)
 {
-  GList *tmp_list = gdk_input_devices;
-  GdkDevicePrivate *gdkdev;
+  _gdk_input_ignore_core = FALSE;
+  _gdk_input_devices = NULL;
+
+  _gdk_init_input_core (display);
+#ifdef HAVE_WINTAB
+#ifdef WINTAB_NO_LAZY_INIT
+  /* Normally, Wintab is only initialized when the application performs
+   * an action that requires it, such as enabling extended input events
+   * for a window or enumerating the devices.
+   */
+  _gdk_input_wintab_init_check ();
+#endif /* WINTAB_NO_LAZY_INIT */
+#endif /* HAVE_WINTAB */
 
-  while (tmp_list)
-    {
-      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
-      if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
-       return gdkdev;
-      tmp_list = tmp_list->next;
-    }
-  return NULL;
+  _gdk_input_devices = g_list_append (_gdk_input_devices, display->core_pointer);
 }
 
-void
-gdk_input_window_get_pointer (GdkWindow       *window,
-                             guint32          deviceid,
-                             gdouble         *x,
-                             gdouble         *y,
-                             gdouble         *pressure,
-                             gdouble         *xtilt,
-                             gdouble         *ytilt,
-                             GdkModifierType *mask)
-{
-  if (gdk_input_vtable.get_pointer)
-    gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
-                                 xtilt, ytilt, mask);
-}