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