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