]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkinput.c
Support added for building using a GNU toolchain on Win32,
[~andy/gtk] / gdk / win32 / gdkinput.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1999 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "config.h"
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <math.h>
33
34 #include <gdk/gdk.h>
35 #include "gdkx.h"
36 #include "gdkinput.h"
37
38 #ifndef M_PI
39 #define M_PI 3.14159265358979323846
40 #endif
41
42 /* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
43  * there are several?) as a system pointing device, i.e. it controls
44  * the normal Windows cursor. This seems much more natural.
45  */
46 #define USE_SYSCONTEXT 1        /* The code for the other choice is not
47                                  * good at all.
48                                  */
49
50 #define TWOPI (2.*M_PI)
51
52 #define PING() g_print("%s: %d\n",__FILE__,__LINE__)
53
54 /* Forward declarations */
55
56 static gint gdk_input_win32_set_mode (guint32      deviceid,
57                                       GdkInputMode mode);
58 static void gdk_input_win32_get_pointer (GdkWindow       *window,
59                                          guint32            deviceid,
60                                          gdouble         *x,
61                                          gdouble         *y,
62                                          gdouble         *pressure,
63                                          gdouble         *xtilt,
64                                          gdouble         *ytilt,
65                                          GdkModifierType *mask);
66 static void gdk_input_none_get_pointer (GdkWindow       *window,
67                                         guint32          deviceid,
68                                         gdouble         *x,
69                                         gdouble         *y,
70                                         gdouble         *pressure,
71                                         gdouble         *xtilt,
72                                         gdouble         *ytilt,
73                                         GdkModifierType *mask);
74 static gint gdk_input_win32_grab_pointer (GdkWindow *     window,
75                                           gint            owner_events,
76                                           GdkEventMask    event_mask,
77                                           GdkWindow      *confine_to,
78                                           guint32         time);
79 static void gdk_input_win32_ungrab_pointer (guint32 time);
80 static void gdk_input_win32_configure_event (GdkEventConfigure *event, 
81                                              GdkWindow         *window);
82 static void gdk_input_win32_enter_event (GdkEventCrossing  *xevent, 
83                                          GdkWindow         *window);
84 static gint gdk_input_win32_other_event (GdkEvent  *event, 
85                                          MSG       *xevent);
86 static gint gdk_input_win32_enable_window (GdkWindow        *window,
87                                            GdkDevicePrivate *gdkdev);
88 static gint gdk_input_win32_disable_window (GdkWindow        *window,
89                                             GdkDevicePrivate *gdkdev);
90
91 static GdkInputWindow *gdk_input_window_find (GdkWindow *window);
92 static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
93 static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid);
94 static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
95                                                       UINT id);
96
97 /* Local variables */
98
99 static GList     *gdk_input_devices;
100 static GList     *gdk_input_windows;
101 static GList     *wintab_contexts;
102
103 static gint gdk_input_root_width;
104 static gint gdk_input_root_height;
105
106 static GdkWindow *wintab_window;
107
108 static guint32 last_moved_cursor_id;
109
110 static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
111
112 static GdkDeviceInfo gdk_input_core_info =
113 {
114   GDK_CORE_POINTER,
115   "Core Pointer",
116   GDK_SOURCE_MOUSE,
117   GDK_MODE_SCREEN,
118   TRUE,
119   2,
120   gdk_input_core_axes
121 };
122
123 /* Global variables  */
124
125 GdkInputVTable    gdk_input_vtable;
126 gint              gdk_input_ignore_core;
127 gint              gdk_input_ignore_wintab = FALSE;
128
129 #if 0
130
131 static void
132 print_lc(LOGCONTEXT *lc)
133 {
134   g_print ("lcName = %s\n", lc->lcName);
135   g_print ("lcOptions =");
136   if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
137   if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
138   if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
139   if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
140   if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
141   if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
142   if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
143   g_print ("\n");
144   g_print ("lcStatus =");
145   if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
146   if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
147   if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
148   g_print ("\n");
149   g_print ("lcLocks =");
150   if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
151   if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
152   if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
153   if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
154   g_print ("\n");
155   g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
156           lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
157   g_print ("lcPktData =");
158   if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
159   if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
160   if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
161   if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
162   if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
163   if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
164   if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
165   if (lc->lcPktData & PK_X) g_print (" PK_X");
166   if (lc->lcPktData & PK_Y) g_print (" PK_Y");
167   if (lc->lcPktData & PK_Z) g_print (" PK_Z");
168   if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
169   if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
170   if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
171   if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
172   g_print ("\n");
173   g_print ("lcPktMode =");
174   if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
175   if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
176   if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
177   if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
178   if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
179   if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
180   if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
181   if (lc->lcPktMode & PK_X) g_print (" PK_X");
182   if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
183   if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
184   if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
185   if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
186   if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
187   if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
188   g_print ("\n");
189   g_print ("lcMoveMask =");
190   if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
191   if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
192   if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
193   if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
194   if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
195   if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
196   if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
197   if (lc->lcMoveMask & PK_X) g_print (" PK_X");
198   if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
199   if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
200   if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
201   if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
202   if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
203   if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
204   g_print ("\n");
205   g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
206           lc->lcBtnDnMask, lc->lcBtnUpMask);
207   g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n",
208           lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
209   g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n",
210           lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
211   g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n",
212           lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
213   g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n",
214           lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
215   g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
216           lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
217   g_print ("lcSysMode = %d\n", lc->lcSysMode);
218   g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
219           lc->lcSysOrgX, lc->lcSysOrgY);
220   g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
221           lc->lcSysExtX, lc->lcSysExtY);
222   g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
223           lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
224 }
225
226 #endif
227
228 void 
229 gdk_input_init (void)
230 {
231   GdkDevicePrivate *gdkdev;
232   GdkWindowPrivate *window_private;
233   GdkWindowAttr wa;
234   WORD specversion;
235   LOGCONTEXT defcontext;
236   HCTX *hctx;
237   UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
238   AXIS axis_x, axis_y, axis_npressure, axis_orientation[3];
239   int i, j, k;
240   char devname[100], csrname[100];
241   guint32 deviceid_counter = 0;
242
243   gdk_input_devices = NULL;
244   wintab_contexts = NULL;
245
246   if (!gdk_input_ignore_wintab &&
247       WTInfo (0, 0, NULL))
248     {
249       WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
250
251 #if USE_SYSCONTEXT
252       WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
253 #else
254       WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
255 #endif
256 #if 0
257       g_print("DEFCONTEXT:\n"); print_lc(&defcontext);
258 #endif
259       WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
260       WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
261
262       /* Create a dummy window to receive wintab events */
263       wa.wclass = GDK_INPUT_OUTPUT;
264       wa.event_mask = GDK_ALL_EVENTS_MASK;
265       wa.width = 2;
266       wa.height = 2;
267       wa.x = -100;
268       wa.y = -100;
269       wa.window_type = GDK_WINDOW_TOPLEVEL;
270       if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
271         {
272           g_warning ("gdk_input_init: gdk_window_new failed");
273           return;
274         }
275       gdk_window_ref (wintab_window);
276       window_private = (GdkWindowPrivate *) wintab_window;
277       
278       for (i = 0; i < ndevices; i++)
279         {
280           LOGCONTEXT lc;
281
282           WTInfo (WTI_DEVICES + i, DVC_NAME, devname);
283       
284           WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes);
285           WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr);
286           WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware);
287           WTInfo (WTI_DEVICES + i, DVC_X, &axis_x);
288           WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y);
289           WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure);
290           WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation);
291
292           if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
293             {
294               WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName);
295               WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions);
296               lc.lcOptions |= CXO_MESSAGES;
297               lc.lcStatus = 0;
298               WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks);
299               lc.lcMsgBase = WT_DEFBASE;
300               lc.lcDevice = i;
301               lc.lcPktRate = 20;
302               lc.lcPktData = PACKETDATA;
303               lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
304               lc.lcMoveMask = PACKETDATA;
305               lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
306               WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX);
307               WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY);
308               WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ);
309               WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX);
310               WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY);
311               WTInfo (WTI_DDCTXS + i, CTX_INEXTZ, &lc.lcInExtZ);
312               lc.lcOutOrgX = axis_x.axMin;
313               lc.lcOutOrgY = axis_y.axMin;
314               lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
315               lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
316               lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
317               WTInfo (WTI_DDCTXS + i, CTX_SENSX, &lc.lcSensX);
318               WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY);
319               WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ);
320               WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode);
321               lc.lcSysOrgX = lc.lcSysOrgY = 0;
322               WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX);
323               WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY);
324               WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX);
325               WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY);
326             }
327           else
328             {
329               lc = defcontext;
330               lc.lcOptions |= CXO_MESSAGES;
331               lc.lcMsgBase = WT_DEFBASE;
332               lc.lcPktRate = 20; /* Slow down the packets a bit */
333               lc.lcPktData = PACKETDATA;
334               lc.lcPktMode = PACKETMODE;
335               lc.lcMoveMask = PACKETDATA;
336               lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
337 #if 0
338               lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
339 #else
340               lc.lcOutOrgX = axis_x.axMin;
341               lc.lcOutOrgY = axis_y.axMin;
342               lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
343               lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
344               lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
345 #endif
346             }
347 #if 0
348           g_print("context for device %d:\n", i); print_lc(&lc);
349 #endif
350           hctx = g_new (HCTX, 1);
351           if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL)
352             {
353               g_warning ("gdk_input_init: WTOpen failed");
354               return;
355             }
356           GDK_NOTE (MISC, g_print ("gdk_input_init: opened Wintab device %d %#x\n",
357                                    i, *hctx));
358
359           wintab_contexts = g_list_append (wintab_contexts, hctx);
360 #if 0
361           WTEnable (*hctx, TRUE);
362 #endif
363           WTOverlap (*hctx, TRUE);
364
365 #if 0
366           g_print("context for device %d after WTOpen:\n", i); print_lc(&lc);
367 #endif
368           for (j = firstcsr; j < firstcsr + ncsrtypes; j++)
369             {
370               gdkdev = g_new (GdkDevicePrivate, 1);
371               WTInfo (WTI_CURSORS + j, CSR_NAME, csrname);
372               gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
373               gdkdev->info.deviceid = deviceid_counter++;
374               gdkdev->info.source = GDK_SOURCE_PEN;
375               gdkdev->info.mode = GDK_MODE_SCREEN;
376 #if USE_SYSCONTEXT
377               gdkdev->info.has_cursor = TRUE;
378 #else
379               gdkdev->info.has_cursor = FALSE;
380 #endif
381               gdkdev->hctx = *hctx;
382               gdkdev->cursor = j;
383               WTInfo (WTI_CURSORS + j, CSR_PKTDATA, &gdkdev->pktdata);
384               gdkdev->info.num_axes = 0;
385               if (gdkdev->pktdata & PK_X)
386                 gdkdev->info.num_axes++;
387               if (gdkdev->pktdata & PK_Y)
388                 gdkdev->info.num_axes++;
389               if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
390                 gdkdev->info.num_axes++;
391               if (gdkdev->pktdata & PK_ORIENTATION)
392                 gdkdev->info.num_axes += 2; /* x and y tilt */
393               WTInfo (WTI_CURSORS + j, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
394               gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
395               gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes);
396               gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
397               
398               for (k = 0; k < GDK_AXIS_LAST; k++)
399                 gdkdev->axis_for_use[k] = -1;
400
401               k = 0;
402               if (gdkdev->pktdata & PK_X)
403                 {
404                   gdkdev->axes[k].xresolution =
405                     gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
406                   gdkdev->axes[k].xmin_value =
407                     gdkdev->axes[k].min_value = axis_x.axMin;
408                   gdkdev->axes[k].xmax_value =
409                     gdkdev->axes[k].max_value = axis_x.axMax;
410                   gdkdev->info.axes[k] = GDK_AXIS_X;
411                   gdkdev->axis_for_use[GDK_AXIS_X] = k;
412                   k++;
413                 }
414               if (gdkdev->pktdata & PK_Y)
415                 {
416                   gdkdev->axes[k].xresolution =
417                     gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
418                   gdkdev->axes[k].xmin_value =
419                     gdkdev->axes[k].min_value = axis_y.axMin;
420                   gdkdev->axes[k].xmax_value =
421                     gdkdev->axes[k].max_value = axis_y.axMax;
422                   gdkdev->info.axes[k] = GDK_AXIS_Y;
423                   gdkdev->axis_for_use[GDK_AXIS_Y] = k;
424                   k++;
425                 }
426               if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
427                 {
428                   gdkdev->axes[k].xresolution =
429                     gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
430                   gdkdev->axes[k].xmin_value =
431                     gdkdev->axes[k].min_value = axis_npressure.axMin;
432                   gdkdev->axes[k].xmax_value =
433                     gdkdev->axes[k].max_value = axis_npressure.axMax;
434                   gdkdev->info.axes[k] = GDK_AXIS_PRESSURE;
435                   gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k;
436                   k++;
437                 }
438               if (gdkdev->pktdata & PK_ORIENTATION)
439                 {
440                   GdkAxisUse axis;
441
442                   gdkdev->orientation_axes[0] = axis_orientation[0];
443                   gdkdev->orientation_axes[1] = axis_orientation[1];
444                   for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
445                     {
446                       gdkdev->axes[k].xresolution =
447                         gdkdev->axes[k].resolution = 1000;
448                       gdkdev->axes[k].xmin_value =
449                         gdkdev->axes[k].min_value = -1000;
450                       gdkdev->axes[k].xmax_value =
451                         gdkdev->axes[k].max_value = 1000;
452                       gdkdev->info.axes[k] = axis;
453                       gdkdev->axis_for_use[axis] = k;
454                       k++;
455                     }
456                 }
457               gdkdev->info.num_keys = 0;
458               gdkdev->info.keys = NULL;
459               GDK_NOTE (EVENTS,
460                         g_print ("gdk_input_init: device: %d axes: %d\n",
461                                  gdkdev->info.deviceid,
462                                  gdkdev->info.num_axes));
463               gdk_input_devices = g_list_append (gdk_input_devices,
464                                                  gdkdev);
465             }
466         }
467       gdk_input_vtable.set_mode           = gdk_input_win32_set_mode;
468       gdk_input_vtable.set_axes           = NULL;
469       gdk_input_vtable.set_key            = NULL;
470       gdk_input_vtable.motion_events      = NULL;
471       gdk_input_vtable.get_pointer        = gdk_input_win32_get_pointer;
472       gdk_input_vtable.grab_pointer       = gdk_input_win32_grab_pointer;
473       gdk_input_vtable.ungrab_pointer     = gdk_input_win32_ungrab_pointer;
474       gdk_input_vtable.configure_event    = gdk_input_win32_configure_event;
475       gdk_input_vtable.enter_event        = gdk_input_win32_enter_event;
476       gdk_input_vtable.other_event        = gdk_input_win32_other_event;
477       gdk_input_vtable.enable_window      = gdk_input_win32_enable_window;
478       gdk_input_vtable.disable_window     = gdk_input_win32_disable_window;
479
480       gdk_input_root_width = gdk_screen_width ();
481       gdk_input_root_height = gdk_screen_height ();
482       gdk_input_ignore_core = FALSE;
483     }
484   else
485     {
486       gdk_input_vtable.set_mode           = NULL;
487       gdk_input_vtable.set_axes           = NULL;
488       gdk_input_vtable.set_key            = NULL;
489       gdk_input_vtable.motion_events      = NULL;
490       gdk_input_vtable.get_pointer        = gdk_input_none_get_pointer;
491       gdk_input_vtable.grab_pointer       = NULL;
492       gdk_input_vtable.ungrab_pointer     = NULL;
493       gdk_input_vtable.configure_event    = NULL;
494       gdk_input_vtable.enter_event        = NULL;
495       gdk_input_vtable.other_event        = NULL;
496       gdk_input_vtable.enable_window      = NULL;
497       gdk_input_vtable.disable_window     = NULL;
498       gdk_input_ignore_core = FALSE;
499     }
500   
501   gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info);
502 }
503
504 static void
505 gdk_input_get_root_relative_geometry (HWND w,
506                                       int  *x_ret,
507                                       int  *y_ret)
508 {
509   RECT rect;
510
511   GetWindowRect (w, &rect);
512
513   if (x_ret)
514     *x_ret = rect.left;
515   if (y_ret)
516     *y_ret = rect.top;
517 }
518
519 static void
520 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
521                                  GdkInputWindow   *input_window,
522                                  gint             *axis_data,
523                                  gdouble          *x,
524                                  gdouble          *y,
525                                  gdouble          *pressure,
526                                  gdouble          *xtilt,
527                                  gdouble          *ytilt)
528 {
529   GdkWindowPrivate *window_private;
530   gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis;
531   gdouble device_width, device_height;
532   gdouble x_offset, y_offset, x_scale, y_scale;
533
534   window_private = (GdkWindowPrivate *) input_window->window;
535
536   x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
537   y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
538   pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE];
539   xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT];
540   ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT];
541
542   device_width = gdkdev->axes[x_axis].max_value - 
543                    gdkdev->axes[x_axis].min_value;
544   device_height = gdkdev->axes[y_axis].max_value - 
545                     gdkdev->axes[y_axis].min_value;
546
547   if (gdkdev->info.mode == GDK_MODE_SCREEN) 
548     {
549       x_scale = gdk_input_root_width / device_width;
550       y_scale = gdk_input_root_height / device_height;
551
552       x_offset = -input_window->root_x;
553       y_offset = -input_window->root_y;
554     }
555   else                          /* GDK_MODE_WINDOW */
556     {
557       double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
558         (device_width*gdkdev->axes[x_axis].resolution);
559
560       if (device_aspect * window_private->width >= window_private->height)
561         {
562           /* device taller than window */
563           x_scale = window_private->width / device_width;
564           y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
565             / gdkdev->axes[y_axis].resolution;
566
567           x_offset = 0;
568           y_offset = -(device_height * y_scale - 
569                                window_private->height)/2;
570         }
571       else
572         {
573           /* window taller than device */
574           y_scale = window_private->height / device_height;
575           x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
576             / gdkdev->axes[x_axis].resolution;
577
578           y_offset = 0;
579           x_offset = -(device_width * x_scale - window_private->width)/2;
580         }
581     }
582   
583   if (x)
584     *x = x_offset + x_scale*axis_data[x_axis];
585   if (y)
586     *y = y_offset + y_scale*axis_data[y_axis];
587
588   if (pressure)
589     {
590       if (pressure_axis != -1)
591         *pressure = ((double)axis_data[pressure_axis] 
592                      - gdkdev->axes[pressure_axis].min_value) 
593           / (gdkdev->axes[pressure_axis].max_value 
594              - gdkdev->axes[pressure_axis].min_value);
595       else
596         *pressure = 0.5;
597     }
598
599   if (xtilt)
600     {
601       if (xtilt_axis != -1)
602         {
603           *xtilt = 2. * (double)(axis_data[xtilt_axis] - 
604                                  (gdkdev->axes[xtilt_axis].min_value +
605                                   gdkdev->axes[xtilt_axis].max_value)/2) /
606             (gdkdev->axes[xtilt_axis].max_value -
607              gdkdev->axes[xtilt_axis].min_value);
608         }
609       else
610         *xtilt = 0;
611     }
612   
613   if (ytilt)
614     {
615       if (ytilt_axis != -1)
616         {
617           *ytilt = 2. * (double)(axis_data[ytilt_axis] - 
618                                  (gdkdev->axes[ytilt_axis].min_value +
619                                   gdkdev->axes[ytilt_axis].max_value)/2) /
620             (gdkdev->axes[ytilt_axis].max_value -
621              gdkdev->axes[ytilt_axis].min_value);
622         }
623       else
624         *ytilt = 0;
625     }
626 }
627
628 gint
629 gdk_input_set_mode (guint32      deviceid,
630                     GdkInputMode mode)
631 {
632   if (deviceid == GDK_CORE_POINTER)
633     return FALSE;
634
635   if (gdk_input_vtable.set_mode)
636     return gdk_input_vtable.set_mode (deviceid, mode);
637   else
638     return FALSE;
639 }
640
641 void
642 gdk_input_set_axes (guint32     deviceid,
643                     GdkAxisUse *axes)
644 {
645   int i;
646   GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
647   g_return_if_fail (gdkdev != NULL);
648
649   if (deviceid == GDK_CORE_POINTER)
650     return;
651
652   for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
653     {
654       gdkdev->axis_for_use[i] = -1;
655     }
656
657   for (i = 0; i < gdkdev->info.num_axes; i++)
658     {
659       gdkdev->info.axes[i] = axes[i];
660       gdkdev->axis_for_use[axes[i]] = i;
661     }
662 }
663
664 static void 
665 gdk_input_win32_get_pointer (GdkWindow       *window,
666                              guint32          deviceid,
667                              gdouble         *x,
668                              gdouble         *y,
669                              gdouble         *pressure,
670                              gdouble         *xtilt,
671                              gdouble         *ytilt,
672                              GdkModifierType *mask)
673 {
674   GdkDevicePrivate *gdkdev;
675   GdkInputWindow *input_window;
676   gint x_int, y_int;
677   gint i;
678
679   if (deviceid == GDK_CORE_POINTER)
680     {
681       gdk_window_get_pointer (window, &x_int, &y_int, mask);
682       if (x)
683         *x = x_int;
684       if (y)
685         *y = y_int;
686       if (pressure)
687         *pressure = 0.5;
688       if (xtilt)
689         *xtilt = 0;
690       if (ytilt)
691         *ytilt = 0;
692     }
693   else
694     {
695       if (mask)
696         gdk_window_get_pointer (window, NULL, NULL, mask);
697       
698       gdkdev = gdk_input_find_device (deviceid);
699       g_return_if_fail (gdkdev != NULL);
700
701       input_window = gdk_input_window_find (window);
702       g_return_if_fail (input_window != NULL);
703
704       gdk_input_translate_coordinates (gdkdev, input_window,
705                                        gdkdev->last_axis_data,
706                                        x, y, pressure,
707                                        xtilt, ytilt);
708       if (mask)
709         {
710           *mask &= 0xFF;
711           *mask |= ((gdkdev->last_buttons & 0x1F) << 8);
712         }
713     }
714 }
715
716 static void
717 gdk_input_none_get_pointer (GdkWindow       *window,
718                             guint32          deviceid,
719                             gdouble         *x,
720                             gdouble         *y,
721                             gdouble         *pressure,
722                             gdouble         *xtilt,
723                             gdouble         *ytilt,
724                             GdkModifierType *mask)
725 {
726   gint x_int, y_int;
727
728   gdk_window_get_pointer (window, &x_int, &y_int, mask);
729
730   if (x)
731     *x = x_int;
732   if (y)
733     *y = y_int;
734   if (pressure)
735     *pressure = 0.5;
736   if (xtilt)
737     *xtilt = 0;
738   if (ytilt)
739     *ytilt = 0;
740 }
741
742 static gint
743 gdk_input_win32_set_mode (guint32      deviceid,
744                           GdkInputMode mode)
745 {
746   GList *tmp_list;
747   GdkDevicePrivate *gdkdev;
748   GdkInputMode old_mode;
749   GdkInputWindow *input_window;
750
751   if (deviceid == GDK_CORE_POINTER)
752     return FALSE;
753
754   gdkdev = gdk_input_find_device (deviceid);
755   g_return_val_if_fail (gdkdev != NULL, FALSE);
756   old_mode = gdkdev->info.mode;
757
758   if (old_mode == mode)
759     return TRUE;
760
761   gdkdev->info.mode = mode;
762
763   if (mode == GDK_MODE_WINDOW)
764     {
765       gdkdev->info.has_cursor = FALSE;
766       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
767         {
768           input_window = (GdkInputWindow *)tmp_list->data;
769           if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
770             gdk_input_win32_enable_window (input_window->window, gdkdev);
771           else
772             if (old_mode != GDK_MODE_DISABLED)
773               gdk_input_win32_disable_window (input_window->window, gdkdev);
774         }
775     }
776   else if (mode == GDK_MODE_SCREEN)
777     {
778       gdkdev->info.has_cursor = TRUE;
779       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
780         gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window,
781                                        gdkdev);
782     }
783   else  /* mode == GDK_MODE_DISABLED */
784     {
785       for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
786         {
787           input_window = (GdkInputWindow *)tmp_list->data;
788           if (old_mode != GDK_MODE_WINDOW ||
789               input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
790             gdk_input_win32_disable_window (input_window->window, gdkdev);
791         }
792     }
793
794   return TRUE;
795 }
796
797 static void
798 gdk_input_win32_configure_event (GdkEventConfigure *event,
799                                  GdkWindow         *window)
800 {
801   GdkInputWindow *input_window;
802   gint root_x, root_y;
803
804   input_window = gdk_input_window_find (window);
805   g_return_if_fail (window != NULL);
806
807   gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
808                                         &root_x, &root_y);
809
810   input_window->root_x = root_x;
811   input_window->root_y = root_y;
812 }
813
814 static void 
815 gdk_input_win32_enter_event (GdkEventCrossing *event, 
816                              GdkWindow        *window)
817 {
818   GdkInputWindow *input_window;
819   gint root_x, root_y;
820
821   input_window = gdk_input_window_find (window);
822   g_return_if_fail (window != NULL);
823
824   gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
825                                         &root_x, &root_y);
826
827   input_window->root_x = root_x;
828   input_window->root_y = root_y;
829 }
830
831 static void
832 decode_tilt (gint   *axis_data,
833              AXIS   *axes,
834              PACKET *packet)
835 {
836   /* As I don't have a tilt-sensing tablet,
837    * I cannot test this code.
838    */
839   
840   double az, el;
841
842   az = TWOPI * packet->pkOrientation.orAzimuth /
843     (axes[0].axResolution / 65536.);
844   el = TWOPI * packet->pkOrientation.orAltitude /
845     (axes[1].axResolution / 65536.);
846   
847   /* X tilt */
848   axis_data[0] = cos (az) * cos (el) * 1000;
849   /* Y tilt */
850   axis_data[1] = sin (az) * cos (el) * 1000;
851 }
852
853 static gint 
854 gdk_input_win32_other_event (GdkEvent  *event,
855                              MSG       *xevent)
856 {
857   GdkWindow *current_window;
858   GdkInputWindow *input_window;
859   GdkWindow *window;
860   GdkWindowPrivate *window_private;
861   GdkDevicePrivate *gdkdev;
862   GdkEventMask masktest;
863   POINT pt;
864   PACKET packet;
865   gint return_val;
866   gint k;
867   gint x, y;
868
869   if (event->any.window != wintab_window)
870     g_warning ("gdk_input_win32_other_event: not wintab_window?");
871
872 #if USE_SYSCONTEXT
873   window = gdk_window_at_pointer (&x, &y);
874   if (window == NULL)
875     window = (GdkWindow *) &gdk_root_parent;
876
877   gdk_window_ref (window);
878
879   window_private = (GdkWindowPrivate *) window;
880
881   GDK_NOTE (EVENTS, g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", window_private->xwindow, x, y));
882   
883 #else
884   /* ??? This code is pretty bogus */
885   current_window = gdk_window_lookup (GetActiveWindow ());
886   if (current_window == NULL)
887     return FALSE;
888   
889   input_window = gdk_input_window_find_within (current_window);
890   if (input_window == NULL)
891     return FALSE;
892 #endif
893
894   if (xevent->message == WT_PACKET)
895     {
896       if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet))
897         return FALSE;
898     }
899
900   switch (xevent->message)
901     {
902     case WT_PACKET:
903       if (window_private == &gdk_root_parent)
904         {
905           GDK_NOTE (EVENTS, g_print ("...is root\n"));
906           return FALSE;
907         }
908
909       if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam,
910                                                  packet.pkCursor)) == NULL)
911         return FALSE;
912
913       if (gdkdev->info.mode == GDK_MODE_DISABLED)
914         return FALSE;
915       
916       k = 0;
917       if (gdkdev->pktdata & PK_X)
918         gdkdev->last_axis_data[k++] = packet.pkX;
919       if (gdkdev->pktdata & PK_Y)
920         gdkdev->last_axis_data[k++] = packet.pkY;
921       if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
922         gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
923       if (gdkdev->pktdata & PK_ORIENTATION)
924         {
925           decode_tilt (gdkdev->last_axis_data + k,
926                        gdkdev->orientation_axes, &packet);
927           k += 2;
928         }
929
930       g_assert (k == gdkdev->info.num_axes);
931
932       if (HIWORD (packet.pkButtons) != TBN_NONE)
933         {
934           /* Gdk buttons are numbered 1.. */
935           event->button.button = 1 + LOWORD (packet.pkButtons);
936
937           if (HIWORD (packet.pkButtons) == TBN_UP)
938             {
939               event->any.type = GDK_BUTTON_RELEASE;
940               masktest = GDK_BUTTON_RELEASE_MASK;
941               gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
942             }
943           else
944             {
945               event->any.type = GDK_BUTTON_PRESS;
946               masktest = GDK_BUTTON_PRESS_MASK;
947               gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
948             }
949         }
950       else
951         {
952           event->any.type = GDK_MOTION_NOTIFY;
953           masktest = GDK_POINTER_MOTION_MASK;
954           if (gdkdev->button_state & (1 << 0))
955             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
956           if (gdkdev->button_state & (1 << 1))
957             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
958           if (gdkdev->button_state & (1 << 2))
959             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
960         }
961
962       /* Now we can check if the window wants the event, and
963        * propagate if necessary.
964        */
965     dijkstra:
966       if (!window_private->extension_events_selected
967           || !(window_private->extension_events & masktest))
968         {
969           GDK_NOTE (EVENTS, g_print ("...not selected\n"));
970
971           if (window_private->parent == (GdkWindow *) &gdk_root_parent)
972             return FALSE;
973           
974           pt.x = x;
975           pt.y = y;
976           ClientToScreen (window_private->xwindow, &pt);
977           gdk_window_unref (window);
978           window = window_private->parent;
979           gdk_window_ref (window);
980           window_private = (GdkWindowPrivate *) window;
981           ScreenToClient (window_private->xwindow, &pt);
982           x = pt.x;
983           y = pt.y;
984           GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, x, y));
985           goto dijkstra;
986         }
987
988       input_window = gdk_input_window_find (window);
989
990       g_assert (input_window != NULL);
991
992       if (gdkdev->info.mode == GDK_MODE_WINDOW
993           && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
994         return FALSE;
995
996       event->any.window = window;
997
998       if (event->any.type == GDK_BUTTON_PRESS
999           || event->any.type == GDK_BUTTON_RELEASE)
1000         {
1001           event->button.time = xevent->time;
1002           event->button.source = gdkdev->info.source;
1003           last_moved_cursor_id = 
1004             event->button.deviceid = gdkdev->info.deviceid;
1005           
1006 #if 0
1007 #if USE_SYSCONTEXT
1008           /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
1009           if (event->button.button <= 3)
1010             return FALSE;
1011 #endif
1012 #endif
1013           gdk_input_translate_coordinates (gdkdev, input_window,
1014                                            gdkdev->last_axis_data,
1015                                            &event->button.x, &event->button.y,
1016                                            &event->button.pressure,
1017                                            &event->button.xtilt, 
1018                                            &event->button.ytilt);
1019
1020           event->button.state = ((gdkdev->button_state << 8)
1021                                  & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
1022                                     | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
1023                                     | GDK_BUTTON5_MASK));
1024           GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g\n",
1025                                      (event->button.type == GDK_BUTTON_PRESS ?
1026                                       "press" : "release"),
1027                                      event->button.deviceid,
1028                                      event->button.button,
1029                                      event->button.x, event->button.y,
1030                                      event->button.pressure));
1031         }
1032       else
1033         {
1034           event->motion.time = xevent->time;
1035           last_moved_cursor_id =
1036             event->motion.deviceid = gdkdev->info.deviceid;
1037           event->motion.is_hint = FALSE;
1038           event->motion.source = gdkdev->info.source;
1039
1040           gdk_input_translate_coordinates (gdkdev, input_window,
1041                                            gdkdev->last_axis_data,
1042                                            &event->motion.x, &event->motion.y,
1043                                            &event->motion.pressure,
1044                                            &event->motion.xtilt, 
1045                                            &event->motion.ytilt);
1046
1047           event->motion.state = ((gdkdev->button_state << 8)
1048                                  & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
1049                                     | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
1050                                     | GDK_BUTTON5_MASK));
1051
1052           GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g\n",
1053                                      event->motion.deviceid,
1054                                      event->motion.x, event->motion.y,
1055                                      event->motion.pressure));
1056
1057           /* Check for missing release or press events for the normal
1058            * pressure button. At least on my ArtPadII I sometimes miss a
1059            * release event?
1060            */
1061           if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
1062                && (event->motion.state & GDK_BUTTON1_MASK)
1063                && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2))
1064               || (gdkdev->pktdata & PK_NORMAL_PRESSURE
1065                   && !(event->motion.state & GDK_BUTTON1_MASK)
1066                   && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
1067             {
1068               GdkEvent *event2 = gdk_event_copy (event);
1069               if (event->motion.state & GDK_BUTTON1_MASK)
1070                 {
1071                   event2->button.type = GDK_BUTTON_RELEASE;
1072                   gdkdev->button_state &= ~1;
1073                 }
1074               else
1075                 {
1076                   event2->button.type = GDK_BUTTON_PRESS;
1077                   gdkdev->button_state |= 1;
1078                 }
1079               event2->button.state = ((gdkdev->button_state << 8)
1080                                       & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
1081                                          | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
1082                                          | GDK_BUTTON5_MASK));
1083               event2->button.button = 1;
1084               GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n",
1085                                          (event2->button.type == GDK_BUTTON_PRESS ?
1086                                           "press" : "release"),
1087                                          event2->button.deviceid,
1088                                          event2->button.button,
1089                                          event2->button.x, event2->button.y,
1090                                          event2->button.pressure));
1091               gdk_event_queue_append (event2);
1092             }
1093         }
1094       return TRUE;
1095
1096     case WT_PROXIMITY:
1097       if (LOWORD (xevent->lParam) == 0)
1098         {
1099           event->proximity.type = GDK_PROXIMITY_OUT;
1100           gdk_input_ignore_core = FALSE;
1101         }
1102       else
1103         {
1104           event->proximity.type = GDK_PROXIMITY_IN;
1105           gdk_input_ignore_core = TRUE;
1106         }
1107       event->proximity.time = xevent->time;
1108       event->proximity.source = GDK_SOURCE_PEN;
1109       event->proximity.deviceid = last_moved_cursor_id;
1110
1111       GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n",
1112                                  (event->proximity.type == GDK_PROXIMITY_IN ?
1113                                   "in" : "out"),
1114                                  event->proximity.deviceid));
1115       return TRUE;
1116     }
1117
1118   return FALSE;
1119 }
1120
1121 static gint
1122 gdk_input_win32_enable_window (GdkWindow        *window,
1123                                GdkDevicePrivate *gdkdev)
1124 {
1125   GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
1126
1127   window_private->extension_events_selected = TRUE;
1128   return TRUE;
1129 }
1130
1131 static gint
1132 gdk_input_win32_disable_window (GdkWindow        *window,
1133                                 GdkDevicePrivate *gdkdev)
1134 {
1135   GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
1136
1137   window_private->extension_events_selected = FALSE;
1138   return TRUE;
1139 }
1140
1141 static gint
1142 gdk_input_win32_grab_pointer (GdkWindow    *window,
1143                               gint          owner_events,
1144                               GdkEventMask  event_mask,
1145                               GdkWindow    *confine_to,
1146                               guint32       time)
1147 {
1148   GdkInputWindow *input_window, *new_window;
1149   gboolean need_ungrab;
1150   GdkDevicePrivate *gdkdev;
1151   GList *tmp_list;
1152   gint result;
1153
1154   tmp_list = gdk_input_windows;
1155   new_window = NULL;
1156   need_ungrab = FALSE;
1157
1158   GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n",
1159                            ((GdkWindowPrivate *) window)->xwindow,
1160                            owner_events,
1161                            (confine_to ?
1162                             ((GdkWindowPrivate *) confine_to)->xwindow :
1163                             0)));
1164
1165   while (tmp_list)
1166     {
1167       input_window = (GdkInputWindow *)tmp_list->data;
1168
1169       if (input_window->window == window)
1170         new_window = input_window;
1171       else if (input_window->grabbed)
1172         {
1173           input_window->grabbed = FALSE;
1174           need_ungrab = TRUE;
1175         }
1176
1177       tmp_list = tmp_list->next;
1178     }
1179
1180   if (new_window)
1181     {
1182       new_window->grabbed = TRUE;
1183       
1184       tmp_list = gdk_input_devices;
1185       while (tmp_list)
1186         {
1187           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1188           if (gdkdev->info.deviceid != GDK_CORE_POINTER)
1189             {
1190 #if 0         
1191               gdk_input_find_events (window, gdkdev,
1192                                      event_mask,
1193                                      event_classes, &num_classes);
1194               result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice,
1195                                     GDK_WINDOW_XWINDOW (window),
1196                                     owner_events, num_classes, event_classes,
1197                                     GrabModeAsync, GrabModeAsync, time);
1198               
1199               /* FIXME: if failure occurs on something other than the first
1200                  device, things will be badly inconsistent */
1201               if (result != Success)
1202                 return result;
1203 #endif
1204             }
1205           tmp_list = tmp_list->next;
1206         }
1207     }
1208   else
1209     { 
1210       tmp_list = gdk_input_devices;
1211       while (tmp_list)
1212         {
1213           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1214           if (gdkdev->info.deviceid != GDK_CORE_POINTER && 
1215               ((gdkdev->button_state != 0) || need_ungrab))
1216             {
1217 #if 0
1218               XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1219 #endif
1220               gdkdev->button_state = 0;
1221             }
1222           
1223           tmp_list = tmp_list->next;
1224         }
1225     }
1226
1227   return Success;
1228       
1229 }
1230
1231 static void 
1232 gdk_input_win32_ungrab_pointer (guint32 time)
1233 {
1234   GdkInputWindow *input_window;
1235   GdkDevicePrivate *gdkdev;
1236   GList *tmp_list;
1237
1238   GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n"));
1239
1240   tmp_list = gdk_input_windows;
1241   while (tmp_list)
1242     {
1243       input_window = (GdkInputWindow *)tmp_list->data;
1244       if (input_window->grabbed)
1245         break;
1246       tmp_list = tmp_list->next;
1247     }
1248
1249   if (tmp_list)                 /* we found a grabbed window */
1250     {
1251       input_window->grabbed = FALSE;
1252
1253       tmp_list = gdk_input_devices;
1254       while (tmp_list)
1255         {
1256           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1257 #if 0
1258           if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice)
1259             XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1260 #endif
1261           tmp_list = tmp_list->next;
1262         }
1263     }
1264 }
1265
1266 GList *
1267 gdk_input_list_devices (void)
1268 {
1269   return gdk_input_devices;
1270 }
1271
1272 void
1273 gdk_input_set_source (guint32        deviceid,
1274                       GdkInputSource source)
1275 {
1276   GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
1277   g_return_if_fail (gdkdev != NULL);
1278
1279   gdkdev->info.source = source;
1280 }
1281
1282 void gdk_input_set_key (guint32 deviceid,
1283                         guint   index,
1284                         guint   keyval,
1285                         GdkModifierType modifiers)
1286 {
1287   if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
1288     gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
1289 }
1290
1291 GdkTimeCoord *
1292 gdk_input_motion_events (GdkWindow *window,
1293                          guint32    deviceid,
1294                          guint32    start,
1295                          guint32    stop,
1296                          gint      *nevents_return)
1297 {
1298   GdkWindowPrivate *window_private;
1299   GdkTimeCoord *coords;
1300   int i;
1301
1302   g_return_val_if_fail (window != NULL, NULL);
1303   window_private = (GdkWindowPrivate *) window;
1304   if (window_private->destroyed)
1305     return NULL;
1306
1307   *nevents_return = 0;
1308   return NULL;          /* ??? */
1309 }
1310
1311 static GdkInputWindow *
1312 gdk_input_window_find (GdkWindow *window)
1313 {
1314   GList *tmp_list;
1315
1316   for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
1317     if (((GdkInputWindow *)(tmp_list->data))->window == window)
1318       return (GdkInputWindow *)(tmp_list->data);
1319
1320   return NULL;      /* Not found */
1321 }
1322
1323 static GdkInputWindow *
1324 gdk_input_window_find_within (GdkWindow *window)
1325 {
1326   GList *tmp_list;
1327   GdkWindowPrivate *window_private;
1328   GdkWindowPrivate *tmp_private;
1329   GdkInputWindow *candidate = NULL;
1330
1331   window_private = (GdkWindowPrivate *) window;
1332
1333   for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
1334     {
1335       (GdkWindowPrivate *) tmp_private =
1336         (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window);
1337       if (tmp_private == window_private
1338           || IsChild (window_private->xwindow, tmp_private->xwindow))
1339         {
1340           if (candidate)
1341             return NULL;                /* Multiple hits */
1342           candidate = (GdkInputWindow *)(tmp_list->data);
1343         }
1344     }
1345
1346   return candidate;
1347 }
1348
1349 /* FIXME: this routine currently needs to be called between creation
1350    and the corresponding configure event (because it doesn't get the
1351    root_relative_geometry).  This should work with
1352    gtk_window_set_extension_events, but will likely fail in other
1353    cases */
1354
1355 void
1356 gdk_input_set_extension_events (GdkWindow       *window,
1357                                 gint             mask,
1358                                 GdkExtensionMode mode)
1359 {
1360   GdkWindowPrivate *window_private;
1361   GList *tmp_list;
1362   GdkInputWindow *iw;
1363
1364   g_return_if_fail (window != NULL);
1365   window_private = (GdkWindowPrivate *) window;
1366   if (window_private->destroyed)
1367     return;
1368
1369   if (mode == GDK_EXTENSION_EVENTS_NONE)
1370     mask = 0;
1371
1372   if (mask != 0)
1373     {
1374       iw = g_new (GdkInputWindow,1);
1375
1376       iw->window = window;
1377       iw->mode = mode;
1378
1379       iw->grabbed = FALSE;
1380
1381       gdk_input_windows = g_list_append (gdk_input_windows, iw);
1382       window_private->extension_events = mask;
1383
1384       /* Add enter window events to the event mask */
1385       gdk_window_set_events (window,
1386                              gdk_window_get_events (window) | 
1387                              GDK_ENTER_NOTIFY_MASK);
1388     }
1389   else
1390     {
1391       iw = gdk_input_window_find (window);
1392       if (iw)
1393         {
1394           gdk_input_windows = g_list_remove (gdk_input_windows, iw);
1395           g_free (iw);
1396         }
1397
1398       window_private->extension_events = 0;
1399     }
1400
1401   for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
1402     {
1403       GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
1404
1405       if (gdkdev->info.deviceid != GDK_CORE_POINTER)
1406         {
1407           if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
1408               && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
1409             gdk_input_win32_enable_window (window, gdkdev);
1410           else
1411             gdk_input_win32_disable_window (window, gdkdev);
1412         }
1413     }
1414 }
1415
1416 void
1417 gdk_input_window_destroy (GdkWindow *window)
1418 {
1419   GdkInputWindow *input_window;
1420
1421   input_window = gdk_input_window_find (window);
1422   g_return_if_fail (input_window != NULL);
1423
1424   gdk_input_windows = g_list_remove (gdk_input_windows,input_window);
1425   g_free (input_window);
1426 }
1427
1428 void
1429 gdk_input_exit (void)
1430 {
1431   GList *tmp_list;
1432   GdkDevicePrivate *gdkdev;
1433
1434   for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
1435     {
1436       gdkdev = (GdkDevicePrivate *)(tmp_list->data);
1437       if (gdkdev->info.deviceid != GDK_CORE_POINTER)
1438         {
1439           gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED);
1440           g_free (gdkdev->info.name);
1441           g_free (gdkdev->last_axis_data);
1442           g_free (gdkdev->info.axes);
1443           g_free (gdkdev->info.keys);
1444           g_free (gdkdev->axes);
1445           g_free (gdkdev);
1446         }
1447     }
1448
1449   g_list_free (gdk_input_devices);
1450
1451   for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
1452     {
1453       g_free (tmp_list->data);
1454     }
1455   g_list_free (gdk_input_windows);
1456
1457 #if 1
1458   for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next)
1459     {
1460       HCTX *hctx = (HCTX *) tmp_list->data;
1461       BOOL result;
1462
1463 #ifdef _MSC_VER
1464       /* For some reason WTEnable and/or WTClose tend to crash here.
1465        * Protect with __try/__except to avoid a message box.
1466        */
1467       __try {
1468 #endif /* _MSC_VER */
1469 #if 0
1470         WTEnable (*hctx, FALSE);
1471 #endif
1472         result = WTClose (*hctx);
1473 #ifdef _MSC_VER
1474       }
1475       __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */
1476                 EXCEPTION_EXECUTE_HANDLER /*: 
1477                 EXCEPTION_CONTINUE_SEARCH */) {
1478         result = FALSE;
1479       }
1480 #endif /* _MSC_VER */
1481       if (!result)
1482         g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx);
1483       g_free (hctx);
1484     }
1485 #endif
1486   g_list_free (wintab_contexts);
1487 }
1488
1489 static GdkDevicePrivate *
1490 gdk_input_find_device (guint32 id)
1491 {
1492   GList *tmp_list = gdk_input_devices;
1493   GdkDevicePrivate *gdkdev;
1494
1495   while (tmp_list)
1496     {
1497       gdkdev = (GdkDevicePrivate *) (tmp_list->data);
1498       if (gdkdev->info.deviceid == id)
1499         return gdkdev;
1500       tmp_list = tmp_list->next;
1501     }
1502   return NULL;
1503 }
1504
1505 static GdkDevicePrivate *
1506 gdk_input_find_dev_from_ctx (HCTX hctx,
1507                              UINT cursor)
1508 {
1509   GList *tmp_list = gdk_input_devices;
1510   GdkDevicePrivate *gdkdev;
1511
1512   while (tmp_list)
1513     {
1514       gdkdev = (GdkDevicePrivate *) (tmp_list->data);
1515       if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
1516         return gdkdev;
1517       tmp_list = tmp_list->next;
1518     }
1519   return NULL;
1520 }
1521
1522 void
1523 gdk_input_window_get_pointer (GdkWindow       *window,
1524                               guint32          deviceid,
1525                               gdouble         *x,
1526                               gdouble         *y,
1527                               gdouble         *pressure,
1528                               gdouble         *xtilt,
1529                               gdouble         *ytilt,
1530                               GdkModifierType *mask)
1531 {
1532   if (gdk_input_vtable.get_pointer)
1533     gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
1534                                   xtilt, ytilt, mask);
1535 }