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