]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkinput-x11.c
Remove selection for DeviceButtonRelease, we no longer need it now that
[~andy/gtk] / gdk / x11 / gdkinput-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gdkinputprivate.h"
28 #include "gdkinternals.h"
29 #include "gdkx.h"
30 #include "gdk.h"                /* For gdk_error_trap_push()/pop() */
31 #include "gdkdisplay-x11.h"
32
33 #include <string.h>
34
35 /* Forward declarations */
36 static GdkDevicePrivate *gdk_input_device_new            (GdkDisplay       *display,
37                                                           XDeviceInfo      *device,
38                                                           gint              include_core);
39 static void              gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
40                                                           GdkInputWindow   *input_window,
41                                                           gint             *axis_data,
42                                                           gdouble          *axis_out,
43                                                           gdouble          *x_out,
44                                                           gdouble          *y_out);
45 static guint             gdk_input_translate_state       (guint             state,
46                                                           guint             device_state);
47
48 GdkDevicePrivate *
49 _gdk_input_find_device (GdkDisplay *display,
50                         guint32     id)
51 {
52   GList *tmp_list = GDK_DISPLAY_X11 (display)->input_devices;
53   GdkDevicePrivate *gdkdev;
54   while (tmp_list)
55     {
56       gdkdev = (GdkDevicePrivate *)(tmp_list->data);
57       if (gdkdev->deviceid == id)
58         return gdkdev;
59       tmp_list = tmp_list->next;
60     }
61   return NULL;
62 }
63
64 void
65 _gdk_input_get_root_relative_geometry(Display *display, Window w, int *x_ret, int *y_ret,
66                                       int *width_ret, int *height_ret)
67 {
68   Window root, parent, child;
69   Window *children;
70   guint nchildren;
71   gint x,y;
72   guint width, height;
73   guint border_widthc, depthc;
74    
75   XQueryTree (display, w, &root, &parent, &children, &nchildren);
76   if (children)
77     XFree(children);
78   
79   XGetGeometry (display, w, &root, &x, &y, &width, &height, &border_widthc, &depthc);
80
81   XTranslateCoordinates (display, w, root, 0, 0, &x, &y, &child);
82  
83   if (x_ret)
84     *x_ret = x;
85   if (y_ret)
86     *y_ret = y;
87   if (width_ret)
88     *width_ret = width;
89   if (height_ret)
90     *height_ret = height;
91 }
92
93 static GdkDevicePrivate *
94 gdk_input_device_new (GdkDisplay  *display,
95                       XDeviceInfo *device, 
96                       gint         include_core)
97 {
98   GdkDevicePrivate *gdkdev;
99   gchar *tmp_name;
100   XAnyClassPtr class;
101   gint i,j;
102
103   gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
104
105   gdkdev->deviceid = device->id;
106   gdkdev->display = display;
107
108   if (device->name[0])
109     gdkdev->info.name = g_strdup (device->name);
110  else
111    /* XFree86 3.2 gives an empty name to the default core devices,
112       (fixed in 3.2A) */
113    gdkdev->info.name = g_strdup ("pointer");
114
115   gdkdev->info.mode = GDK_MODE_DISABLED;
116
117   /* Try to figure out what kind of device this is by its name -
118      could invite a very, very, long list... Lowercase name
119      for comparison purposes */
120
121   tmp_name = g_ascii_strdown (gdkdev->info.name, -1);
122   
123   if (!strcmp (tmp_name, "pointer"))
124     gdkdev->info.source = GDK_SOURCE_MOUSE;
125   else if (!strcmp (tmp_name, "wacom") ||
126            !strcmp (tmp_name, "pen"))
127     gdkdev->info.source = GDK_SOURCE_PEN;
128   else if (!strcmp (tmp_name, "eraser"))
129     gdkdev->info.source = GDK_SOURCE_ERASER;
130   else if (!strcmp (tmp_name, "cursor"))
131     gdkdev->info.source = GDK_SOURCE_CURSOR;
132   else
133     gdkdev->info.source = GDK_SOURCE_PEN;
134
135   g_free(tmp_name);
136
137   gdkdev->xdevice = NULL;
138
139   /* step through the classes */
140
141   gdkdev->info.num_axes = 0;
142   gdkdev->info.num_keys = 0;
143   gdkdev->info.axes = NULL;
144   gdkdev->info.keys = NULL;
145   gdkdev->axes = 0;
146   gdkdev->info.has_cursor = 0;
147   gdkdev->needs_update = FALSE;
148   gdkdev->claimed = FALSE;
149   gdkdev->button_state = 0;
150
151   class = device->inputclassinfo;
152   for (i=0;i<device->num_classes;i++) 
153     {
154       switch (class->class) {
155       case ButtonClass:
156         break;
157       case KeyClass:
158         {
159           XKeyInfo *xki = (XKeyInfo *)class;
160           /* Hack to catch XFree86 3.3.1 bug. Other devices better
161            * not have exactly 25 keys... 
162            */
163           if ((xki->min_keycode == 8) && (xki->max_keycode == 32))
164             {
165               gdkdev->info.num_keys = 32;
166               gdkdev->min_keycode = 1;
167             }
168           else
169             {
170               gdkdev->info.num_keys = xki->max_keycode - xki->min_keycode + 1;
171               gdkdev->min_keycode = xki->min_keycode;
172             }
173           gdkdev->info.keys = g_new (GdkDeviceKey, gdkdev->info.num_keys);
174
175           for (j=0; j<gdkdev->info.num_keys; j++)
176             {
177               gdkdev->info.keys[j].keyval = 0;
178               gdkdev->info.keys[j].modifiers = 0;
179             }
180
181           break;
182         }
183       case ValuatorClass:
184         {
185           XValuatorInfo *xvi = (XValuatorInfo *)class;
186           gdkdev->info.num_axes = xvi->num_axes;
187           gdkdev->axes = g_new (GdkAxisInfo, xvi->num_axes);
188           gdkdev->info.axes = g_new0 (GdkDeviceAxis, xvi->num_axes);
189           for (j=0;j<xvi->num_axes;j++)
190             {
191               gdkdev->axes[j].resolution = 
192                 gdkdev->axes[j].xresolution = xvi->axes[j].resolution;
193               gdkdev->axes[j].min_value =
194                 gdkdev->axes[j].xmin_value = xvi->axes[j].min_value;
195               gdkdev->axes[j].max_value =
196                 gdkdev->axes[j].xmax_value = xvi->axes[j].max_value;
197               gdkdev->info.axes[j].use = GDK_AXIS_IGNORE;
198             }
199           j=0;
200           if (j<xvi->num_axes)
201             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_X);
202           if (j<xvi->num_axes)
203             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_Y);
204           if (j<xvi->num_axes)
205             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_PRESSURE);
206           if (j<xvi->num_axes)
207             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_XTILT);
208           if (j<xvi->num_axes)
209             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_YTILT);
210           if (j<xvi->num_axes)
211             gdk_device_set_axis_use (&gdkdev->info, j++, GDK_AXIS_WHEEL);
212                        
213           break;
214         }
215       }
216       class = (XAnyClassPtr)(((char *)class) + class->length);
217     }
218   /* return NULL if no axes */
219   if (!gdkdev->info.num_axes || !gdkdev->axes ||
220       (!include_core && device->use == IsXPointer))
221     goto error;
222
223   if (device->use != IsXPointer)
224     {
225       gdk_error_trap_push ();
226       gdkdev->xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (display),
227                                      gdkdev->deviceid);
228
229       /* return NULL if device is not ready */
230       if (gdk_error_trap_pop ())
231         goto error;
232     }
233
234   gdkdev->buttonpress_type = 0;
235   gdkdev->buttonrelease_type = 0;
236   gdkdev->keypress_type = 0;
237   gdkdev->keyrelease_type = 0;
238   gdkdev->motionnotify_type = 0;
239   gdkdev->proximityin_type = 0;
240   gdkdev->proximityout_type = 0;
241   gdkdev->changenotify_type = 0;
242
243   return gdkdev;
244
245  error:
246
247   g_free (gdkdev->info.name);
248   if (gdkdev->axes)
249     g_free (gdkdev->axes);
250   if (gdkdev->info.keys)
251     g_free (gdkdev->info.keys);
252   if (gdkdev->info.axes)
253     g_free (gdkdev->info.axes);
254   g_object_unref (gdkdev);
255   
256   return NULL;
257 }
258
259 void
260 _gdk_input_common_find_events(GdkWindow *window,
261                               GdkDevicePrivate *gdkdev,
262                               gint mask,
263                               XEventClass *classes,
264                               int *num_classes)
265 {
266   gint i;
267   XEventClass class;
268   
269   i = 0;
270   if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK)
271     {
272       DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type,
273                              class);
274       if (class != 0)
275           classes[i++] = class;
276       DeviceButtonPressGrab (gdkdev->xdevice, 0, class);
277       if (class != 0)
278           classes[i++] = class;
279     }
280   if (mask & GDK_POINTER_MOTION_MASK)
281     {
282       DeviceMotionNotify  (gdkdev->xdevice, gdkdev->motionnotify_type, class);
283       if (class != 0)
284           classes[i++] = class;
285     }
286   else
287     if (mask & (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
288                 GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_MOTION_MASK |
289                 GDK_POINTER_MOTION_HINT_MASK))
290       {
291         /* Make sure gdkdev->motionnotify_type is set */
292         DeviceMotionNotify  (gdkdev->xdevice, gdkdev->motionnotify_type, class);
293       }
294   if (mask & GDK_BUTTON1_MOTION_MASK)
295     {
296       DeviceButton1Motion  (gdkdev->xdevice, 0, class);
297       if (class != 0)
298           classes[i++] = class;
299     }
300   if (mask & GDK_BUTTON2_MOTION_MASK)
301     {
302       DeviceButton2Motion  (gdkdev->xdevice, 0, class);
303       if (class != 0)
304           classes[i++] = class;
305     }
306   if (mask & GDK_BUTTON3_MOTION_MASK)
307     {
308       DeviceButton3Motion  (gdkdev->xdevice, 0, class);
309       if (class != 0)
310           classes[i++] = class;
311     }
312   if (mask & GDK_BUTTON_MOTION_MASK)
313     {
314       DeviceButtonMotion  (gdkdev->xdevice, 0, class);
315       if (class != 0)
316           classes[i++] = class;
317     }
318   if (mask & GDK_POINTER_MOTION_HINT_MASK)
319     {
320       /* We'll get into trouble if the macros change, but at least we'll
321          know about it, and we avoid warnings now */
322       DevicePointerMotionHint (gdkdev->xdevice, 0, class);
323       if (class != 0)
324           classes[i++] = class;
325     }
326   if (mask & GDK_KEY_PRESS_MASK)
327     {
328       DeviceKeyPress (gdkdev->xdevice, gdkdev->keypress_type, class);
329       if (class != 0)
330           classes[i++] = class;
331     }
332   if (mask & GDK_KEY_RELEASE_MASK)
333     {
334       DeviceKeyRelease (gdkdev->xdevice, gdkdev->keyrelease_type, class);
335       if (class != 0)
336           classes[i++] = class;
337     }
338   if (mask & GDK_PROXIMITY_IN_MASK)
339     {
340       ProximityIn   (gdkdev->xdevice, gdkdev->proximityin_type, class);
341       if (class != 0)
342           classes[i++] = class;
343     }
344   if (mask & GDK_PROXIMITY_OUT_MASK)
345     {
346       ProximityOut  (gdkdev->xdevice, gdkdev->proximityout_type, class);
347       if (class != 0)
348           classes[i++] = class;
349     }
350
351   *num_classes = i;
352 }
353
354 void
355 _gdk_input_common_select_events(GdkWindow *window,
356                                 GdkDevicePrivate *gdkdev)
357 {
358   XEventClass classes[GDK_MAX_DEVICE_CLASSES];
359   gint num_classes;
360
361   if (gdkdev->info.mode == GDK_MODE_DISABLED)
362     _gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes);
363   else
364     _gdk_input_common_find_events(window, gdkdev, 
365                                   ((GdkWindowObject *)window)->extension_events,
366                                   classes, &num_classes);
367   
368   XSelectExtensionEvent (GDK_WINDOW_XDISPLAY (window),
369                          GDK_WINDOW_XWINDOW (window),
370                          classes, num_classes);
371 }
372
373 gint 
374 _gdk_input_common_init (GdkDisplay *display,
375                         gint        include_core)
376 {
377   char **extensions;
378   XDeviceInfo   *devices;
379   int num_devices;
380   int num_extensions, loop;
381   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
382
383   /* Init XInput extension */
384   
385   extensions = XListExtensions(display_x11->xdisplay, &num_extensions);
386   for (loop = 0; loop < num_extensions &&
387          (strcmp(extensions[loop], "XInputExtension") != 0); loop++);
388   XFreeExtensionList(extensions);
389   display_x11->input_devices = NULL;
390   if (loop < num_extensions)
391     {
392       /* XInput extension found */
393
394       devices = XListInputDevices(display_x11->xdisplay, &num_devices);
395   
396       for(loop=0; loop<num_devices; loop++)
397         {
398           GdkDevicePrivate *gdkdev = gdk_input_device_new(display,
399                                                           &devices[loop],
400                                                           include_core);
401           if (gdkdev)
402             display_x11->input_devices = g_list_append(display_x11->input_devices, gdkdev);
403         }
404       XFreeDeviceList(devices);
405     }
406
407   display_x11->input_devices = g_list_append (display_x11->input_devices, display->core_pointer);
408
409   return TRUE;
410 }
411
412 static void
413 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
414                                  GdkInputWindow   *input_window,
415                                  gint             *axis_data,
416                                  gdouble          *axis_out,
417                                  gdouble          *x_out,
418                                  gdouble          *y_out)
419 {
420   GdkWindowImplX11 *impl;
421   int i;
422   int x_axis = 0;
423   int y_axis = 0;
424
425   double device_width, device_height;
426   double x_offset, y_offset, x_scale, y_scale;
427
428   impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *) input_window->window)->impl);
429
430   for (i=0; i<gdkdev->info.num_axes; i++)
431     {
432       switch (gdkdev->info.axes[i].use)
433         {
434         case GDK_AXIS_X:
435           x_axis = i;
436           break;
437         case GDK_AXIS_Y:
438           y_axis = i;
439           break;
440         default:
441           break;
442         }
443     }
444   
445   device_width = gdkdev->axes[x_axis].max_value - 
446                    gdkdev->axes[x_axis].min_value;
447   device_height = gdkdev->axes[y_axis].max_value - 
448                     gdkdev->axes[y_axis].min_value;
449
450   if (gdkdev->info.mode == GDK_MODE_SCREEN) 
451     {
452       x_scale = gdk_screen_get_width (gdk_drawable_get_screen (input_window->window)) / device_width;
453       y_scale = gdk_screen_get_height (gdk_drawable_get_screen (input_window->window)) / device_height;
454
455       x_offset = - input_window->root_x;
456       y_offset = - input_window->root_y;
457     }
458   else                          /* GDK_MODE_WINDOW */
459     {
460       double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
461         (device_width*gdkdev->axes[x_axis].resolution);
462
463       if (device_aspect * impl->width >= impl->height)
464         {
465           /* device taller than window */
466           x_scale = impl->width / device_width;
467           y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
468             / gdkdev->axes[y_axis].resolution;
469
470           x_offset = 0;
471           y_offset = -(device_height * y_scale - 
472                                impl->height)/2;
473         }
474       else
475         {
476           /* window taller than device */
477           y_scale = impl->height / device_height;
478           x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
479             / gdkdev->axes[x_axis].resolution;
480
481           y_offset = 0;
482           x_offset = - (device_width * x_scale - impl->width)/2;
483         }
484     }
485
486   for (i=0; i<gdkdev->info.num_axes; i++)
487     {
488       switch (gdkdev->info.axes[i].use)
489         {
490         case GDK_AXIS_X:
491           axis_out[i] = x_offset + x_scale*axis_data[x_axis];
492           if (x_out)
493             *x_out = axis_out[i];
494           break;
495         case GDK_AXIS_Y:
496           axis_out[i] = y_offset + y_scale*axis_data[y_axis];
497           if (y_out)
498             *y_out = axis_out[i];
499           break;
500         default:
501           axis_out[i] =
502             (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
503              gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
504             (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
505           break;
506         }
507     }
508 }
509
510 /* combine the state of the core device and the device state
511  * into one - for now we do this in a simple-minded manner -
512  * we just take the keyboard portion of the core device and
513  * the button portion (all of?) the device state.
514  * Any button remapping should go on here.
515  */
516 static guint
517 gdk_input_translate_state(guint state, guint device_state)
518 {
519   return device_state | (state & 0xFF);
520 }
521
522
523 gint 
524 _gdk_input_common_other_event (GdkEvent         *event,
525                                XEvent           *xevent,
526                                GdkInputWindow   *input_window,
527                                GdkDevicePrivate *gdkdev)
528 {
529   if ((xevent->type == gdkdev->buttonpress_type) ||
530       (xevent->type == gdkdev->buttonrelease_type)) 
531     {
532       XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent);
533
534       if (xdbe->type == gdkdev->buttonpress_type)
535         {
536           event->button.type = GDK_BUTTON_PRESS;
537           gdkdev->button_state |= 1 << xdbe->button;
538         }
539       else
540         {
541           event->button.type = GDK_BUTTON_RELEASE;
542           gdkdev->button_state &= ~(1 << xdbe->button);
543         }
544       event->button.device = &gdkdev->info;
545       event->button.window = input_window->window;
546       event->button.time = xdbe->time;
547
548       event->button.axes = g_new (gdouble, gdkdev->info.num_axes);
549       gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data,
550                                        event->button.axes, 
551                                        &event->button.x,&event->button.y);
552       event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state);
553       event->button.button = xdbe->button;
554
555       GDK_NOTE (EVENTS,
556         g_print ("button %s:\t\twindow: %ld  device: %ld  x,y: %f %f  button: %d\n",
557                  (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
558                  xdbe->window,
559                  xdbe->deviceid,
560                  event->button.x, event->button.y,
561                  xdbe->button));
562
563       return TRUE;
564   }
565
566   if ((xevent->type == gdkdev->keypress_type) ||
567       (xevent->type == gdkdev->keyrelease_type))
568     {
569       XDeviceKeyEvent *xdke = (XDeviceKeyEvent *)(xevent);
570
571       GDK_NOTE (EVENTS,
572         g_print ("device key %s:\twindow: %ld  device: %ld  keycode: %d\n",
573                  (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
574                  xdke->window,
575                  xdke->deviceid,
576                  xdke->keycode));
577
578       if (xdke->keycode < gdkdev->min_keycode ||
579           xdke->keycode >= gdkdev->min_keycode + gdkdev->info.num_keys)
580         {
581           g_warning ("Invalid device key code received");
582           return FALSE;
583         }
584       
585       event->key.keyval = gdkdev->info.keys[xdke->keycode - gdkdev->min_keycode].keyval;
586
587       if (event->key.keyval == 0) 
588         {
589           GDK_NOTE (EVENTS,
590             g_print ("\t\ttranslation - NONE\n"));
591           
592           return FALSE;
593         }
594
595       event->key.type = (xdke->type == gdkdev->keypress_type) ?
596         GDK_KEY_PRESS : GDK_KEY_RELEASE;
597
598       event->key.window = input_window->window;
599       event->key.time = xdke->time;
600
601       event->key.state = gdk_input_translate_state(xdke->state, xdke->device_state)
602         | gdkdev->info.keys[xdke->keycode - gdkdev->min_keycode].modifiers;
603
604       /* Add a string translation for the key event */
605       if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
606         {
607           event->key.length = 1;
608           event->key.string = g_new (gchar, 2);
609           event->key.string[0] = (gchar)event->key.keyval;
610           event->key.string[1] = 0;
611         }
612       else
613         {
614           event->key.length = 0;
615           event->key.string = g_new0 (gchar, 1);
616         }
617
618       GDK_NOTE (EVENTS,
619         g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
620                  event->key.keyval,
621                  event->key.state));
622
623       return TRUE;
624     }
625
626   if (xevent->type == gdkdev->motionnotify_type) 
627     {
628       XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent);
629
630       event->motion.device = &gdkdev->info;
631       
632       event->motion.axes = g_new (gdouble, gdkdev->info.num_axes);
633       gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data,
634                                       event->motion.axes,
635                                       &event->motion.x,&event->motion.y);
636
637       event->motion.type = GDK_MOTION_NOTIFY;
638       event->motion.window = input_window->window;
639       event->motion.time = xdme->time;
640       event->motion.state = gdk_input_translate_state(xdme->state,
641                                                       xdme->device_state);
642       event->motion.is_hint = xdme->is_hint;
643
644       GDK_NOTE (EVENTS,
645         g_print ("motion notify:\t\twindow: %ld  device: %ld  x,y: %f %f  state %#4x  hint: %s\n",
646                  xdme->window,
647                  xdme->deviceid,
648                  event->motion.x, event->motion.y,
649                  event->motion.state,
650                  (xdme->is_hint) ? "true" : "false"));
651       
652       
653       return TRUE;
654     }
655
656   if (xevent->type == gdkdev->proximityin_type ||
657       xevent->type == gdkdev->proximityout_type)
658     {
659       XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent);
660
661       event->proximity.device = &gdkdev->info;
662       event->proximity.type = (xevent->type == gdkdev->proximityin_type)?
663         GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT;
664       event->proximity.window = input_window->window;
665       event->proximity.time = xpne->time;
666       
667       return TRUE;
668   }
669
670   return -1;                    /* wasn't one of our event types */
671 }
672
673 gboolean
674 _gdk_device_get_history (GdkDevice         *device,
675                          GdkWindow         *window,
676                          guint32            start,
677                          guint32            stop,
678                          GdkTimeCoord    ***events,
679                          gint              *n_events)
680 {
681   GdkTimeCoord **coords;
682   XDeviceTimeCoord *device_coords;
683   GdkInputWindow *input_window;
684   GdkDevicePrivate *gdkdev;
685   gint mode_return;
686   gint axis_count_return;
687   gint i;
688
689   gdkdev = (GdkDevicePrivate *)device;
690   input_window = _gdk_input_window_find (window);
691
692   g_return_val_if_fail (input_window != NULL, FALSE);
693
694   device_coords = XGetDeviceMotionEvents (GDK_WINDOW_XDISPLAY (window),
695                                           gdkdev->xdevice,
696                                           start, stop,
697                                           n_events, &mode_return,
698                                           &axis_count_return);
699
700   if (device_coords)
701     {
702       coords = _gdk_device_allocate_history (device, *n_events);
703       
704       for (i=0; i<*n_events; i++)
705         gdk_input_translate_coordinates (gdkdev, input_window,
706                                          device_coords[i].data,
707                                          coords[i]->axes, NULL, NULL);
708       XFreeDeviceMotionEvents (device_coords);
709
710       *events = coords;
711
712       return TRUE;
713     }
714   else
715     return FALSE;
716 }
717
718 void 
719 gdk_device_get_state (GdkDevice       *device,
720                       GdkWindow       *window,
721                       gdouble         *axes,
722                       GdkModifierType *mask)
723 {
724   gint i;
725
726   g_return_if_fail (device != NULL);
727   g_return_if_fail (GDK_IS_WINDOW (window));
728
729   if (GDK_IS_CORE (device))
730     {
731       gint x_int, y_int;
732       
733       gdk_window_get_pointer (window, &x_int, &y_int, mask);
734
735       if (axes)
736         {
737           axes[0] = x_int;
738           axes[1] = y_int;
739         }
740     }
741   else
742     {
743       GdkDevicePrivate *gdkdev;
744       GdkInputWindow *input_window;
745       XDeviceState *state;
746       XInputClass *input_class;
747       
748       if (mask)
749         gdk_window_get_pointer (window, NULL, NULL, mask);
750       
751       gdkdev = (GdkDevicePrivate *)device;
752       input_window = _gdk_input_window_find (window);
753       g_return_if_fail (input_window != NULL);
754
755       state = XQueryDeviceState (GDK_WINDOW_XDISPLAY (window),
756                                  gdkdev->xdevice);
757       input_class = state->data;
758       for (i=0; i<state->num_classes; i++)
759         {
760           switch (input_class->class)
761             {
762             case ValuatorClass:
763               if (axes)
764                 gdk_input_translate_coordinates (gdkdev, input_window,
765                                                  ((XValuatorState *)input_class)->valuators,
766                                                  axes, NULL, NULL);
767               break;
768               
769             case ButtonClass:
770               if (mask)
771                 {
772                   *mask &= 0xFF;
773                   if (((XButtonState *)input_class)->num_buttons > 0)
774                     *mask |= ((XButtonState *)input_class)->buttons[0] << 7;
775                   /* GDK_BUTTON1_MASK = 1 << 8, and button n is stored
776                    * in bit 1<<(n%8) in byte n/8. n = 1,2,... */
777                 }
778               break;
779             }
780           input_class = (XInputClass *)(((char *)input_class)+input_class->length);
781         }
782       XFreeDeviceState (state);
783     }
784 }