]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkinput-win32.c
Generate gtk/makefile.mingw.
[~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 "gdkinput.h"
35 #include "gdkinternals.h"
36 #include "gdkprivate-win32.h"
37 #include "gdkinput-win32.h"
38
39 #ifdef HAVE_WINTAB
40
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
45 /* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
46  * there are several?) as a system pointing device, i.e. it controls
47  * the normal Windows cursor. This seems much more natural.
48  */
49 #define USE_SYSCONTEXT 1        /* The code for the other choice is not
50                                  * good at all.
51                                  */
52
53 #define DEBUG_WINTAB 1          /* Verbose debug messages enabled */
54
55 #endif
56
57 #if defined(HAVE_WINTAB) || defined(HAVE_WHATEVER_OTHER)
58 #define HAVE_SOME_XINPUT
59 #endif
60
61 #define TWOPI (2.*G_PI)
62
63 /* Forward declarations */
64
65 #if !USE_SYSCONTEXT
66 static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
67 #endif
68
69 #ifdef HAVE_WINTAB
70
71 static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
72                                                       UINT id);
73 static GList     *wintab_contexts;
74
75 static GdkWindow *wintab_window;
76
77 #endif /* HAVE_WINTAB */
78
79 gboolean
80 gdk_device_get_history  (GdkDevice         *device,
81                          GdkWindow         *window,
82                          guint32            start,
83                          guint32            stop,
84                          GdkTimeCoord    ***events,
85                          gint              *n_events)
86 {
87   GdkTimeCoord **coords;
88   int i;
89
90   g_return_val_if_fail (window != NULL, FALSE);
91   g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
92   g_return_val_if_fail (events != NULL, FALSE);
93   g_return_val_if_fail (n_events != NULL, FALSE);
94
95   *n_events = 0;
96   *events = NULL;
97
98   if (GDK_WINDOW_DESTROYED (window))
99     return FALSE;
100     
101   if (GDK_IS_CORE (device))
102     return FALSE;
103   else
104     return _gdk_device_get_history (device, window, start, stop, events, n_events);
105 }
106
107 #ifdef HAVE_WINTAB
108
109 static GdkDevicePrivate *
110 gdk_input_find_dev_from_ctx (HCTX hctx,
111                              UINT cursor)
112 {
113   GList *tmp_list = gdk_input_devices;
114   GdkDevicePrivate *gdkdev;
115
116   while (tmp_list)
117     {
118       gdkdev = (GdkDevicePrivate *) (tmp_list->data);
119       if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
120         return gdkdev;
121       tmp_list = tmp_list->next;
122     }
123   return NULL;
124 }
125
126 #if DEBUG_WINTAB
127
128 static void
129 print_lc(LOGCONTEXT *lc)
130 {
131   g_print ("lcName = %s\n", lc->lcName);
132   g_print ("lcOptions =");
133   if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
134   if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
135   if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
136   if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
137   if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
138   if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
139   if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
140   g_print ("\n");
141   g_print ("lcStatus =");
142   if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
143   if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
144   if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
145   g_print ("\n");
146   g_print ("lcLocks =");
147   if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
148   if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
149   if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
150   if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
151   g_print ("\n");
152   g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
153           lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
154   g_print ("lcPktData =");
155   if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
156   if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
157   if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
158   if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
159   if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
160   if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
161   if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
162   if (lc->lcPktData & PK_X) g_print (" PK_X");
163   if (lc->lcPktData & PK_Y) g_print (" PK_Y");
164   if (lc->lcPktData & PK_Z) g_print (" PK_Z");
165   if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
166   if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
167   if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
168   if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
169   g_print ("\n");
170   g_print ("lcPktMode =");
171   if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
172   if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
173   if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
174   if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
175   if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
176   if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
177   if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
178   if (lc->lcPktMode & PK_X) g_print (" PK_X");
179   if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
180   if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
181   if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
182   if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
183   if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
184   if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
185   g_print ("\n");
186   g_print ("lcMoveMask =");
187   if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
188   if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
189   if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
190   if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
191   if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
192   if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
193   if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
194   if (lc->lcMoveMask & PK_X) g_print (" PK_X");
195   if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
196   if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
197   if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
198   if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
199   if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
200   if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
201   g_print ("\n");
202   g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
203           lc->lcBtnDnMask, lc->lcBtnUpMask);
204   g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n",
205           lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
206   g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n",
207           lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
208   g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n",
209           lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
210   g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n",
211           lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
212   g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
213           lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
214   g_print ("lcSysMode = %d\n", lc->lcSysMode);
215   g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
216           lc->lcSysOrgX, lc->lcSysOrgY);
217   g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
218           lc->lcSysExtX, lc->lcSysExtY);
219   g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
220           lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
221 }
222
223 #endif
224
225 static void
226 gdk_input_wintab_init (void)
227 {
228   GdkDevicePrivate *gdkdev;
229   GdkWindowAttr wa;
230   WORD specversion;
231   LOGCONTEXT defcontext;
232   HCTX *hctx;
233   UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
234   BOOL active;
235   AXIS axis_x, axis_y, axis_npressure, axis_or[3];
236   int i, j, k;
237   int devix, cursorix;
238   char devname[100], csrname[100];
239
240   gdk_input_devices = NULL;
241   wintab_contexts = NULL;
242
243   if (!gdk_input_ignore_wintab &&
244       WTInfo (0, 0, NULL))
245     {
246       WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
247       GDK_NOTE (MISC, g_print ("Wintab interface version %d.%d\n",
248                                HIBYTE (specversion), LOBYTE (specversion)));
249 #if USE_SYSCONTEXT
250       WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
251 #if DEBUG_WINTAB
252       GDK_NOTE (MISC, (g_print("DEFSYSCTX:\n"), print_lc(&defcontext)));
253 #endif
254 #else
255       WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
256 #if DEBUG_WINTAB
257       GDK_NOTE (MISC, (g_print("DEFCONTEXT:\n"), print_lc(&defcontext)));
258 #endif
259 #endif
260       WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
261       WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
262 #if DEBUG_WINTAB
263       GDK_NOTE (MISC, g_print ("NDEVICES: %d, NCURSORS: %d\n",
264                                ndevices, ncursors));
265 #endif
266       /* Create a dummy window to receive wintab events */
267       wa.wclass = GDK_INPUT_OUTPUT;
268       wa.event_mask = GDK_ALL_EVENTS_MASK;
269       wa.width = 2;
270       wa.height = 2;
271       wa.x = -100;
272       wa.y = -100;
273       wa.window_type = GDK_WINDOW_TOPLEVEL;
274       if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
275         {
276           g_warning ("gdk_input_init: gdk_window_new failed");
277           return;
278         }
279       gdk_drawable_ref (wintab_window);
280       
281       for (devix = 0; devix < ndevices; devix++)
282         {
283           LOGCONTEXT lc;
284
285           WTInfo (WTI_DEVICES + devix, DVC_NAME, devname);
286       
287           WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
288           WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
289           WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
290           WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x);
291           WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y);
292           WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
293           WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
294
295           if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
296             {
297               WTInfo (WTI_DDCTXS + devix, CTX_NAME, lc.lcName);
298               WTInfo (WTI_DDCTXS + devix, CTX_OPTIONS, &lc.lcOptions);
299               lc.lcOptions |= CXO_MESSAGES;
300 #if USE_SYSCONTEXT
301               lc.lcOptions |= CXO_SYSTEM;
302 #endif
303               lc.lcStatus = 0;
304               WTInfo (WTI_DDCTXS + devix, CTX_LOCKS, &lc.lcLocks);
305               lc.lcMsgBase = WT_DEFBASE;
306               lc.lcDevice = devix;
307               lc.lcPktRate = 50;
308               lc.lcPktData = PACKETDATA;
309               lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
310               lc.lcMoveMask = PACKETDATA;
311               lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
312               WTInfo (WTI_DDCTXS + devix, CTX_INORGX, &lc.lcInOrgX);
313               WTInfo (WTI_DDCTXS + devix, CTX_INORGY, &lc.lcInOrgY);
314               WTInfo (WTI_DDCTXS + devix, CTX_INORGZ, &lc.lcInOrgZ);
315               WTInfo (WTI_DDCTXS + devix, CTX_INEXTX, &lc.lcInExtX);
316               WTInfo (WTI_DDCTXS + devix, CTX_INEXTY, &lc.lcInExtY);
317               WTInfo (WTI_DDCTXS + devix, CTX_INEXTZ, &lc.lcInExtZ);
318               lc.lcOutOrgX = axis_x.axMin;
319               lc.lcOutOrgY = axis_y.axMin;
320               lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
321               lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
322               lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
323               WTInfo (WTI_DDCTXS + devix, CTX_SENSX, &lc.lcSensX);
324               WTInfo (WTI_DDCTXS + devix, CTX_SENSY, &lc.lcSensY);
325               WTInfo (WTI_DDCTXS + devix, CTX_SENSZ, &lc.lcSensZ);
326               WTInfo (WTI_DDCTXS + devix, CTX_SYSMODE, &lc.lcSysMode);
327               lc.lcSysOrgX = lc.lcSysOrgY = 0;
328               WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTX, &lc.lcSysExtX);
329               WTInfo (WTI_DDCTXS + devix, CTX_SYSEXTY, &lc.lcSysExtY);
330               WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSX, &lc.lcSysSensX);
331               WTInfo (WTI_DDCTXS + devix, CTX_SYSSENSY, &lc.lcSysSensY);
332             }
333           else
334             {
335               lc = defcontext;
336               lc.lcOptions |= CXO_MESSAGES;
337               lc.lcMsgBase = WT_DEFBASE;
338               lc.lcPktRate = 50;
339               lc.lcPktData = PACKETDATA;
340               lc.lcPktMode = PACKETMODE;
341               lc.lcMoveMask = PACKETDATA;
342               lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
343 #if 0
344               lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
345 #else
346               lc.lcOutOrgX = axis_x.axMin;
347               lc.lcOutOrgY = axis_y.axMin;
348               lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
349               lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
350               lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
351 #endif
352             }
353 #if DEBUG_WINTAB
354           GDK_NOTE (MISC, (g_print("context for device %d:\n", devix),
355                            print_lc(&lc)));
356 #endif
357           hctx = g_new (HCTX, 1);
358           if ((*hctx = WTOpen (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
359             {
360               g_warning ("gdk_input_init: WTOpen failed");
361               return;
362             }
363           GDK_NOTE (MISC, g_print ("opened Wintab device %d %#x\n",
364                                    devix, *hctx));
365
366           wintab_contexts = g_list_append (wintab_contexts, hctx);
367 #if 0
368           WTEnable (*hctx, TRUE);
369 #endif
370           WTOverlap (*hctx, TRUE);
371
372 #if DEBUG_WINTAB
373           GDK_NOTE (MISC, (g_print("context for device %d after WTOpen:\n", devix),
374                            print_lc(&lc)));
375 #endif
376           for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
377             {
378               active = FALSE;
379               WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
380               if (!active)
381                 continue;
382               gdkdev = g_new (GdkDevicePrivate, 1);
383               WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname);
384               gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
385               gdkdev->info.source = GDK_SOURCE_PEN;
386               gdkdev->info.mode = GDK_MODE_SCREEN;
387 #if USE_SYSCONTEXT
388               gdkdev->info.has_cursor = TRUE;
389 #else
390               gdkdev->info.has_cursor = FALSE;
391 #endif
392               gdkdev->hctx = *hctx;
393               gdkdev->cursor = cursorix;
394               WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata);
395               gdkdev->info.num_axes = 0;
396               if (gdkdev->pktdata & PK_X)
397                 gdkdev->info.num_axes++;
398               if (gdkdev->pktdata & PK_Y)
399                 gdkdev->info.num_axes++;
400               if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
401                 gdkdev->info.num_axes++;
402               /* The wintab driver for the Wacom ArtPad II reports
403                * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't
404                * actually sense tilt. Catch this by noticing that the
405                * orientation axis's azimuth resolution is zero.
406                */
407               if ((gdkdev->pktdata & PK_ORIENTATION)
408                   && axis_or[0].axResolution == 0)
409                 gdkdev->pktdata &= ~PK_ORIENTATION;
410
411               if (gdkdev->pktdata & PK_ORIENTATION)
412                 gdkdev->info.num_axes += 2; /* x and y tilt */
413               WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
414               gdkdev->info.axes = g_new (GdkDeviceAxis, gdkdev->info.num_axes);
415               gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
416               gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
417               
418               k = 0;
419               if (gdkdev->pktdata & PK_X)
420                 {
421                   gdkdev->axes[k].xresolution =
422                     gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
423                   gdkdev->axes[k].xmin_value =
424                     gdkdev->axes[k].min_value = axis_x.axMin;
425                   gdkdev->axes[k].xmax_value =
426                     gdkdev->axes[k].max_value = axis_x.axMax;
427                   gdkdev->info.axes[k].use = GDK_AXIS_X;
428                   gdkdev->info.axes[k].min = axis_x.axMin;
429                   gdkdev->info.axes[k].min = axis_x.axMax;
430                   k++;
431                 }
432               if (gdkdev->pktdata & PK_Y)
433                 {
434                   gdkdev->axes[k].xresolution =
435                     gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
436                   gdkdev->axes[k].xmin_value =
437                     gdkdev->axes[k].min_value = axis_y.axMin;
438                   gdkdev->axes[k].xmax_value =
439                     gdkdev->axes[k].max_value = axis_y.axMax;
440                   gdkdev->info.axes[k].use = GDK_AXIS_Y;
441                   gdkdev->info.axes[k].min = axis_y.axMin;
442                   gdkdev->info.axes[k].min = axis_y.axMax;
443                   k++;
444                 }
445               if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
446                 {
447                   gdkdev->axes[k].xresolution =
448                     gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
449                   gdkdev->axes[k].xmin_value =
450                     gdkdev->axes[k].min_value = axis_npressure.axMin;
451                   gdkdev->axes[k].xmax_value =
452                     gdkdev->axes[k].max_value = axis_npressure.axMax;
453                   gdkdev->info.axes[k].use = GDK_AXIS_PRESSURE;
454                   gdkdev->info.axes[k].min = axis_npressure.axMin;
455                   gdkdev->info.axes[k].min = axis_npressure.axMax;
456                   k++;
457                 }
458               if (gdkdev->pktdata & PK_ORIENTATION)
459                 {
460                   GdkAxisUse axis;
461
462                   gdkdev->orientation_axes[0] = axis_or[0];
463                   gdkdev->orientation_axes[1] = axis_or[1];
464                   for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
465                     {
466                       /* Wintab gives us aximuth and altitude, which
467                        * we convert to x and y tilt in the -1000..1000 range
468                        */
469                       gdkdev->axes[k].xresolution =
470                         gdkdev->axes[k].resolution = 1000;
471                       gdkdev->axes[k].xmin_value =
472                         gdkdev->axes[k].min_value = -1000;
473                       gdkdev->axes[k].xmax_value =
474                         gdkdev->axes[k].max_value = 1000;
475                       gdkdev->info.axes[k].use = axis;
476                       gdkdev->info.axes[k].min = -1000;
477                       gdkdev->info.axes[k].min = 1000;
478                       k++;
479                     }
480                 }
481               gdkdev->info.num_keys = 0;
482               gdkdev->info.keys = NULL;
483               GDK_NOTE (EVENTS,
484                         g_print ("device: (%d) %s axes: %d\n",
485                                  cursorix,
486                                  gdkdev->info.name,
487                                  gdkdev->info.num_axes));
488               for (i = 0; i < gdkdev->info.num_axes; i++)
489                 GDK_NOTE (EVENTS,
490                           g_print ("...axis %d: %d--%d@%d (%d--%d@%d)\n",
491                                    i,
492                                    gdkdev->axes[i].xmin_value, 
493                                    gdkdev->axes[i].xmax_value, 
494                                    gdkdev->axes[i].xresolution, 
495                                    gdkdev->axes[i].min_value, 
496                                    gdkdev->axes[i].max_value, 
497                                    gdkdev->axes[i].resolution));
498               gdk_input_devices = g_list_append (gdk_input_devices,
499                                                  gdkdev);
500             }
501         }
502     }
503 }
504
505 static void
506 decode_tilt (gint   *axis_data,
507              AXIS   *axes,
508              PACKET *packet)
509 {
510   /* As I don't have a tilt-sensing tablet,
511    * I cannot test this code.
512    */
513   
514   double az, el;
515
516   az = TWOPI * packet->pkOrientation.orAzimuth /
517     (axes[0].axResolution / 65536.);
518   el = TWOPI * packet->pkOrientation.orAltitude /
519     (axes[1].axResolution / 65536.);
520   
521   /* X tilt */
522   axis_data[0] = cos (az) * cos (el) * 1000;
523   /* Y tilt */
524   axis_data[1] = sin (az) * cos (el) * 1000;
525 }
526
527 #if !USE_SYSCONTEXT
528
529 static GdkInputWindow *
530 gdk_input_window_find_within (GdkWindow *window)
531 {
532   GList *list;
533   GdkWindow *tmpw;
534   GdkInputWindow *candidate = NULL;
535
536   for (list = gdk_input_windows; list != NULL; list = list->next)
537     {
538       tmpw = ((GdkInputWindow *) (tmp_list->data))->window;
539       if (tmpw == window
540           || IsChild (GDK_WINDOW_HWND (window), GDK_WINDOW_HWND (tmpw)))
541         {
542           if (candidate)
543             return NULL;                /* Multiple hits */
544           candidate = (GdkInputWindow *) (list->data);
545         }
546     }
547
548   return candidate;
549 }
550
551 #endif /* USE_SYSCONTEXT */
552
553 #endif /* HAVE_WINTAB */
554
555 static void
556 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
557                                  GdkInputWindow   *input_window,
558                                  gint             *axis_data,
559                                  gdouble          *axis_out,
560                                  gdouble          *x_out,
561                                  gdouble          *y_out)
562 {
563   GdkWindowImplWin32 *impl;
564
565   int i;
566   int x_axis = 0;
567   int y_axis = 0;
568
569   double device_width, device_height;
570   double x_offset, y_offset, x_scale, y_scale;
571
572   impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (input_window->window)->impl);
573
574   for (i=0; i<gdkdev->info.num_axes; i++)
575     {
576       switch (gdkdev->info.axes[i].use)
577         {
578         case GDK_AXIS_X:
579           x_axis = i;
580           break;
581         case GDK_AXIS_Y:
582           y_axis = i;
583           break;
584         default:
585           break;
586         }
587     }
588   
589   device_width = gdkdev->axes[x_axis].max_value - 
590                    gdkdev->axes[x_axis].min_value;
591   device_height = gdkdev->axes[y_axis].max_value - 
592                     gdkdev->axes[y_axis].min_value;
593
594   if (gdkdev->info.mode == GDK_MODE_SCREEN) 
595     {
596       x_scale = gdk_screen_width() / device_width;
597       y_scale = gdk_screen_height() / device_height;
598
599       x_offset = - input_window->root_x;
600       y_offset = - input_window->root_y;
601     }
602   else                          /* GDK_MODE_WINDOW */
603     {
604       double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
605         (device_width*gdkdev->axes[x_axis].resolution);
606
607       if (device_aspect * impl->width >= impl->height)
608         {
609           /* device taller than window */
610           x_scale = impl->width / device_width;
611           y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
612             / gdkdev->axes[y_axis].resolution;
613
614           x_offset = 0;
615           y_offset = -(device_height * y_scale - 
616                                impl->height)/2;
617         }
618       else
619         {
620           /* window taller than device */
621           y_scale = impl->height / device_height;
622           x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
623             / gdkdev->axes[x_axis].resolution;
624
625           y_offset = 0;
626           x_offset = - (device_width * x_scale - impl->width)/2;
627         }
628     }
629
630   for (i=0; i<gdkdev->info.num_axes; i++)
631     {
632       switch (gdkdev->info.axes[i].use)
633         {
634         case GDK_AXIS_X:
635           axis_out[i] = x_offset + x_scale*axis_data[x_axis];
636           if (x_out)
637             *x_out = axis_out[i];
638           break;
639         case GDK_AXIS_Y:
640           axis_out[i] = y_offset + y_scale*axis_data[y_axis];
641           if (y_out)
642             *y_out = axis_out[i];
643           break;
644         default:
645           axis_out[i] =
646             (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
647              gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
648             (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
649           break;
650         }
651     }
652 }
653
654 static void
655 gdk_input_get_root_relative_geometry (HWND w,
656                                       int  *x_ret,
657                                       int  *y_ret)
658 {
659   RECT rect;
660
661   GetWindowRect (w, &rect);
662
663   if (x_ret)
664     *x_ret = rect.left;
665   if (y_ret)
666     *y_ret = rect.top;
667 }
668
669 GdkTimeCoord *
670 gdk_input_motion_events (GdkWindow *window,
671                          guint32    deviceid,
672                          guint32    start,
673                          guint32    stop,
674                          gint      *nevents_return)
675 {
676   g_return_val_if_fail (window != NULL, NULL);
677   if (GDK_WINDOW_DESTROYED (window))
678     return NULL;
679
680   *nevents_return = 0;
681   return NULL;          /* ??? */
682 }
683
684 void
685 _gdk_input_configure_event (GdkEventConfigure *event,
686                             GdkWindow         *window)
687 {
688   GdkInputWindow *input_window;
689   int root_x, root_y;
690
691   input_window = gdk_input_window_find (window);
692   g_return_if_fail (window != NULL);
693
694   gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
695                                         &root_x, &root_y);
696
697   input_window->root_x = root_x;
698   input_window->root_y = root_y;
699 }
700
701 void 
702 _gdk_input_enter_event (GdkEventCrossing *event, 
703                         GdkWindow        *window)
704 {
705   GdkInputWindow *input_window;
706   int root_x, root_y;
707
708   input_window = gdk_input_window_find (window);
709   g_return_if_fail (window != NULL);
710
711   gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
712
713   input_window->root_x = root_x;
714   input_window->root_y = root_y;
715 }
716
717 gint 
718 _gdk_input_other_event (GdkEvent  *event,
719                         MSG       *msg,
720                         GdkWindow *window)
721 {
722 #ifdef HAVE_WINTAB
723   GdkWindow *current_window;
724   GdkWindowObject *obj;
725   GdkWindowImplWin32 *impl;
726   GdkInputWindow *input_window;
727   GdkDevicePrivate *gdkdev;
728   GdkEventMask masktest;
729   POINT pt;
730
731   PACKET packet;
732   gint return_val;
733   gint k;
734   gint x, y;
735
736   if (event->any.window != wintab_window)
737     {
738       g_warning ("_gdk_input_other_event: not wintab_window?");
739       return FALSE;
740     }
741
742 #if USE_SYSCONTEXT
743   window = gdk_window_at_pointer (&x, &y);
744   if (window == NULL)
745     window = gdk_parent_root;
746
747   gdk_drawable_ref (window);
748
749   GDK_NOTE (EVENTS,
750             g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n",
751                      GDK_WINDOW_HWND (window), x, y));
752   
753 #else
754   /* ??? This code is pretty bogus */
755   current_window = gdk_win32_handle_table_lookup (GetActiveWindow ());
756   if (current_window == NULL)
757     return FALSE;
758   
759   input_window = gdk_input_window_find_within (current_window);
760   if (input_window == NULL)
761     return FALSE;
762 #endif
763
764   if (msg->message == WT_PACKET)
765     {
766       if (!WTPacket ((HCTX) msg->lParam, msg->wParam, &packet))
767         return FALSE;
768     }
769
770   obj = GDK_WINDOW_OBJECT (window);
771   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
772
773   switch (msg->message)
774     {
775     case WT_PACKET:
776       if (window == gdk_parent_root)
777         {
778           GDK_NOTE (EVENTS, g_print ("...is root\n"));
779           return FALSE;
780         }
781
782       if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
783                                                  packet.pkCursor)) == NULL)
784         return FALSE;
785
786       if (gdkdev->info.mode == GDK_MODE_DISABLED)
787         return FALSE;
788       
789       k = 0;
790       if (gdkdev->pktdata & PK_X)
791         gdkdev->last_axis_data[k++] = packet.pkX;
792       if (gdkdev->pktdata & PK_Y)
793         gdkdev->last_axis_data[k++] = packet.pkY;
794       if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
795         gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
796       if (gdkdev->pktdata & PK_ORIENTATION)
797         {
798           decode_tilt (gdkdev->last_axis_data + k,
799                        gdkdev->orientation_axes, &packet);
800           k += 2;
801         }
802
803       g_assert (k == gdkdev->info.num_axes);
804
805       if (HIWORD (packet.pkButtons) != TBN_NONE)
806         {
807           /* Gdk buttons are numbered 1.. */
808           event->button.button = 1 + LOWORD (packet.pkButtons);
809
810           if (HIWORD (packet.pkButtons) == TBN_UP)
811             {
812               event->any.type = GDK_BUTTON_RELEASE;
813               masktest = GDK_BUTTON_RELEASE_MASK;
814               gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
815             }
816           else
817             {
818               event->any.type = GDK_BUTTON_PRESS;
819               masktest = GDK_BUTTON_PRESS_MASK;
820               gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
821             }
822         }
823       else
824         {
825           event->any.type = GDK_MOTION_NOTIFY;
826           masktest = GDK_POINTER_MOTION_MASK;
827           if (gdkdev->button_state & (1 << 0))
828             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
829           if (gdkdev->button_state & (1 << 1))
830             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
831           if (gdkdev->button_state & (1 << 2))
832             masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
833         }
834
835       /* Now we can check if the window wants the event, and
836        * propagate if necessary.
837        */
838     dijkstra:
839       if (!impl->extension_events_selected
840           || !(obj->extension_events & masktest))
841         {
842           GDK_NOTE (EVENTS, g_print ("...not selected\n"));
843
844           if (obj->parent == GDK_WINDOW_OBJECT (gdk_parent_root))
845             return FALSE;
846           
847           pt.x = x;
848           pt.y = y;
849           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
850           gdk_drawable_unref (window);
851           window = (GdkWindow *) obj->parent;
852           obj = GDK_WINDOW_OBJECT (window);
853           gdk_drawable_ref (window);
854           ScreenToClient (GDK_WINDOW_HWND (window), &pt);
855           x = pt.x;
856           y = pt.y;
857           GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n",
858                                      GDK_WINDOW_HWND (window), x, y));
859           goto dijkstra;
860         }
861
862       input_window = gdk_input_window_find (window);
863
864       g_assert (input_window != NULL);
865
866       if (gdkdev->info.mode == GDK_MODE_WINDOW
867           && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
868         return FALSE;
869
870       event->any.window = window;
871
872       if (event->any.type == GDK_BUTTON_PRESS
873           || event->any.type == GDK_BUTTON_RELEASE)
874         {
875           event->button.time = msg->time;
876           event->button.device = &gdkdev->info;
877           
878 #if 0
879 #if USE_SYSCONTEXT
880           /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
881           if (event->button.button <= 3)
882             return FALSE;
883 #endif
884 #endif
885           gdk_input_translate_coordinates (gdkdev, input_window,
886                                            gdkdev->last_axis_data,
887                                            event->button.axes,
888                                            &event->button.x, 
889                                            &event->button.y);
890
891           event->button.state = ((gdkdev->button_state << 8)
892                                  & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
893                                     | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
894                                     | GDK_BUTTON5_MASK));
895           GDK_NOTE (EVENTS, g_print ("WINTAB button %s:%d %g,%g %g %g,%g\n",
896                                      (event->button.type == GDK_BUTTON_PRESS ?
897                                       "press" : "release"),
898                                      event->button.button,
899                                      event->button.x, event->button.y));
900         }
901       else
902         {
903           event->motion.time = msg->time;
904           event->motion.is_hint = FALSE;
905           event->motion.device = &gdkdev->info;
906
907           gdk_input_translate_coordinates (gdkdev, input_window,
908                                            gdkdev->last_axis_data,
909                                            event->motion.axes,
910                                            &event->motion.x, 
911                                            &event->motion.y);
912
913           event->motion.state = ((gdkdev->button_state << 8)
914                                  & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
915                                     | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
916                                     | GDK_BUTTON5_MASK));
917
918           GDK_NOTE (EVENTS, g_print ("WINTAB motion: %g,%g\n",
919                                      event->motion.x, event->motion.y));
920
921           /* Check for missing release or press events for the normal
922            * pressure button. At least on my ArtPadII I sometimes miss a
923            * release event?
924            */
925           if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
926                && (event->motion.state & GDK_BUTTON1_MASK)
927                && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2))
928               || (gdkdev->pktdata & PK_NORMAL_PRESSURE
929                   && !(event->motion.state & GDK_BUTTON1_MASK)
930                   && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
931             {
932               GdkEvent *event2 = gdk_event_copy (event);
933               if (event->motion.state & GDK_BUTTON1_MASK)
934                 {
935                   event2->button.type = GDK_BUTTON_RELEASE;
936                   gdkdev->button_state &= ~1;
937                 }
938               else
939                 {
940                   event2->button.type = GDK_BUTTON_PRESS;
941                   gdkdev->button_state |= 1;
942                 }
943               event2->button.state = ((gdkdev->button_state << 8)
944                                       & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
945                                          | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
946                                          | GDK_BUTTON5_MASK));
947               event2->button.button = 1;
948               GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %g,%gg\n",
949                                          (event2->button.type == GDK_BUTTON_PRESS ?
950                                           "press" : "release"),
951                                          event2->button.button,
952                                          event2->button.x,
953                                          event2->button.y));
954               gdk_event_queue_append (event2);
955             }
956         }
957       return TRUE;
958
959     case WT_PROXIMITY:
960       if (LOWORD (msg->lParam) == 0)
961         {
962           event->proximity.type = GDK_PROXIMITY_OUT;
963           gdk_input_ignore_core = FALSE;
964         }
965       else
966         {
967           event->proximity.type = GDK_PROXIMITY_IN;
968           gdk_input_ignore_core = TRUE;
969         }
970       event->proximity.time = msg->time;
971       event->proximity.device = &gdkdev->info;
972
973       GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s\n",
974                                  (event->proximity.type == GDK_PROXIMITY_IN ?
975                                   "in" : "out")));
976       return TRUE;
977     }
978 #endif
979   return -1;
980 }
981
982 gboolean
983 _gdk_input_enable_window (GdkWindow        *window,
984                           GdkDevicePrivate *gdkdev)
985 {
986 #ifdef HAVE_SOME_XINPUT
987   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
988
989   impl->extension_events_selected = TRUE;
990 #endif
991
992   return TRUE;
993 }
994
995 gboolean
996 _gdk_input_disable_window (GdkWindow        *window,
997                            GdkDevicePrivate *gdkdev)
998 {
999 #ifdef HAVE_SOME_XINPUT
1000   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
1001
1002   impl->extension_events_selected = FALSE;
1003 #endif
1004
1005   return TRUE;
1006 }
1007
1008 gint
1009 _gdk_input_grab_pointer (GdkWindow    *window,
1010                          gint          owner_events,
1011                          GdkEventMask  event_mask,
1012                          GdkWindow    *confine_to,
1013                          guint32       time)
1014 {
1015 #ifdef HAVE_SOME_XINPUT
1016   GdkInputWindow *input_window, *new_window;
1017   gboolean need_ungrab;
1018   GdkDevicePrivate *gdkdev;
1019   GList *tmp_list;
1020   gint result;
1021
1022   tmp_list = gdk_input_windows;
1023   new_window = NULL;
1024   need_ungrab = FALSE;
1025
1026   GDK_NOTE (MISC, g_print ("gdk_input_win32_grab_pointer: %#x %d %#x\n",
1027                            GDK_WINDOW_HWND (window),
1028                            owner_events,
1029                            (confine_to ? GDK_WINDOW_HWND (confine_to) : 0)));
1030
1031   while (tmp_list)
1032     {
1033       input_window = (GdkInputWindow *)tmp_list->data;
1034
1035       if (input_window->window == window)
1036         new_window = input_window;
1037       else if (input_window->grabbed)
1038         {
1039           input_window->grabbed = FALSE;
1040           need_ungrab = TRUE;
1041         }
1042
1043       tmp_list = tmp_list->next;
1044     }
1045
1046   if (new_window)
1047     {
1048       new_window->grabbed = TRUE;
1049       
1050       tmp_list = gdk_input_devices;
1051       while (tmp_list)
1052         {
1053           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1054           if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
1055             {
1056 #if 0         
1057               /* XXX */
1058               gdk_input_common_find_events (window, gdkdev,
1059                                             event_mask,
1060                                             event_classes, &num_classes);
1061               
1062               result = XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
1063                                     GDK_WINDOW_XWINDOW (window),
1064                                     owner_events, num_classes, event_classes,
1065                                     GrabModeAsync, GrabModeAsync, time);
1066               
1067               /* FIXME: if failure occurs on something other than the first
1068                  device, things will be badly inconsistent */
1069               if (result != Success)
1070                 return result;
1071 #endif
1072             }
1073           tmp_list = tmp_list->next;
1074         }
1075     }
1076   else
1077     { 
1078       tmp_list = gdk_input_devices;
1079       while (tmp_list)
1080         {
1081           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1082           if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
1083               ((gdkdev->button_state != 0) || need_ungrab))
1084             {
1085 #if 0
1086               /* XXX */
1087               XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1088 #endif
1089               gdkdev->button_state = 0;
1090             }
1091           
1092           tmp_list = tmp_list->next;
1093         }
1094     }
1095 #endif
1096
1097   return GDK_GRAB_SUCCESS;
1098 }
1099
1100 void 
1101 _gdk_input_ungrab_pointer (guint32 time)
1102 {
1103 #ifdef HAVE_SOME_XINPUT
1104   GdkInputWindow *input_window;
1105   GdkDevicePrivate *gdkdev;
1106   GList *tmp_list;
1107
1108   GDK_NOTE (MISC, g_print ("gdk_input_win32_ungrab_pointer\n"));
1109
1110   tmp_list = gdk_input_windows;
1111   while (tmp_list)
1112     {
1113       input_window = (GdkInputWindow *)tmp_list->data;
1114       if (input_window->grabbed)
1115         break;
1116       tmp_list = tmp_list->next;
1117     }
1118
1119   if (tmp_list)                 /* we found a grabbed window */
1120     {
1121       input_window->grabbed = FALSE;
1122
1123       tmp_list = gdk_input_devices;
1124       while (tmp_list)
1125         {
1126           gdkdev = (GdkDevicePrivate *)tmp_list->data;
1127 #if 0
1128           /* XXX */
1129           if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
1130             XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1131 #endif
1132           tmp_list = tmp_list->next;
1133         }
1134     }
1135 #endif
1136 }
1137
1138 gint 
1139 _gdk_input_window_none_event (GdkEvent *event,
1140                               MSG      *msg)
1141 {
1142   return -1;
1143 }
1144
1145 gboolean
1146 _gdk_device_get_history (GdkDevice         *device,
1147                          GdkWindow         *window,
1148                          guint32            start,
1149                          guint32            stop,
1150                          GdkTimeCoord    ***events,
1151                          gint              *n_events)
1152 {
1153   return FALSE;
1154 }
1155
1156 void 
1157 gdk_input_init (void)
1158 {
1159   gdk_input_ignore_core = FALSE;
1160   gdk_input_devices = NULL;
1161
1162 #ifdef HAVE_WINTAB
1163   gdk_input_wintab_init ();
1164 #endif /* HAVE_WINTAB */
1165
1166   gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info);
1167 }
1168