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