]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdevicemanager-xi.c
a0ba46726d14f58fc4c46ba8f2c8ac08dd6478c1
[~andy/gtk] / gdk / x11 / gdkdevicemanager-xi.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
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 #include "config.h"
21
22 #include "gdkx11devicemanager-xi.h"
23 #include "gdkdevicemanagerprivate-core.h"
24 #include "gdkdeviceprivate-xi.h"
25
26 #include "gdkdevicemanagerprivate.h"
27 #include "gdkeventtranslator.h"
28 #include "gdkintl.h"
29 #include "gdkprivate-x11.h"
30
31 #ifdef XINPUT_XFREE
32
33 #include <X11/extensions/XInput.h>
34
35 #endif /* XINPUT_XFREE */
36
37 struct _GdkX11DeviceManagerXI
38 {
39   GdkX11DeviceManagerCore parent_object;
40
41   GHashTable *id_table;
42   gint event_base;
43   GList *devices;
44   gboolean ignore_core_events;
45 };
46
47 struct _GdkX11DeviceManagerXIClass
48 {
49   GdkX11DeviceManagerCoreClass parent_class;
50 };
51
52 static void     gdk_x11_device_manager_xi_event_translator_init  (GdkEventTranslatorIface *iface);
53
54 G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI, gdk_x11_device_manager_xi, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
55                          G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
56                                                 gdk_x11_device_manager_xi_event_translator_init))
57
58 #ifdef XINPUT_XFREE
59
60 static void gdk_x11_device_manager_xi_constructed  (GObject      *object);
61 static void gdk_x11_device_manager_xi_dispose      (GObject      *object);
62 static void gdk_x11_device_manager_xi_set_property (GObject      *object,
63                                                     guint         prop_id,
64                                                     const GValue *value,
65                                                     GParamSpec   *pspec);
66 static void gdk_x11_device_manager_xi_get_property (GObject      *object,
67                                                     guint         prop_id,
68                                                     GValue       *value,
69                                                     GParamSpec   *pspec);
70
71 static gboolean gdk_x11_device_manager_xi_translate_event (GdkEventTranslator *translator,
72                                                            GdkDisplay         *display,
73                                                            GdkEvent           *event,
74                                                            XEvent             *xevent);
75 static GList *  gdk_x11_device_manager_xi_list_devices    (GdkDeviceManager  *device_manager,
76                                                            GdkDeviceType      type);
77
78
79 enum {
80   PROP_0,
81   PROP_EVENT_BASE
82 };
83
84 static void
85 gdk_x11_device_manager_xi_class_init (GdkX11DeviceManagerXIClass *klass)
86 {
87   GObjectClass *object_class = G_OBJECT_CLASS (klass);
88   GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
89
90   object_class->constructed = gdk_x11_device_manager_xi_constructed;
91   object_class->dispose = gdk_x11_device_manager_xi_dispose;
92   object_class->set_property = gdk_x11_device_manager_xi_set_property;
93   object_class->get_property = gdk_x11_device_manager_xi_get_property;
94
95   device_manager_class->list_devices = gdk_x11_device_manager_xi_list_devices;
96
97   g_object_class_install_property (object_class,
98                                    PROP_EVENT_BASE,
99                                    g_param_spec_int ("event-base",
100                                                      P_("Event base"),
101                                                      P_("Event base for XInput events"),
102                                                      0, G_MAXINT, 0,
103                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
104 }
105
106 static GdkFilterReturn
107 window_input_info_filter (GdkXEvent *xevent,
108                           GdkEvent  *event,
109                           gpointer   user_data)
110 {
111   GdkDeviceManager *device_manager;
112   GdkDisplay *display;
113   GdkWindow *window;
114   XEvent *xev;
115
116   device_manager = user_data;
117   xev = (XEvent *) xevent;
118
119   display = gdk_device_manager_get_display (device_manager);
120   window = gdk_x11_window_lookup_for_display (display, xev->xany.window);
121
122   if (window && xev->type == ConfigureNotify)
123     _gdk_x11_device_xi_update_window_info (window);
124
125   return GDK_FILTER_CONTINUE;
126 }
127
128 static void
129 gdk_x11_device_manager_xi_init (GdkX11DeviceManagerXI *device_manager)
130 {
131   device_manager->id_table = g_hash_table_new_full (NULL, NULL, NULL,
132                                                    (GDestroyNotify) g_object_unref);
133
134   gdk_window_add_filter (NULL, window_input_info_filter, device_manager);
135 }
136
137 static void
138 translate_class_info (GdkDevice   *device,
139                       XDeviceInfo *info)
140 {
141   GdkX11DeviceXI *device_xi;
142   XAnyClassPtr class;
143   gint i, j;
144
145   device_xi = GDK_X11_DEVICE_XI (device);
146   class = info->inputclassinfo;
147
148   for (i = 0; i < info->num_classes; i++)
149     {
150       switch (class->class)
151         {
152         case ButtonClass:
153           break;
154         case KeyClass:
155           {
156             XKeyInfo *xki = (XKeyInfo *)class;
157             guint num_keys;
158
159             num_keys = xki->max_keycode - xki->min_keycode + 1;
160             _gdk_device_set_keys (device, num_keys);
161
162             device_xi->min_keycode = xki->min_keycode;
163
164             break;
165           }
166         case ValuatorClass:
167           {
168             XValuatorInfo *xvi = (XValuatorInfo *)class;
169
170             for (j = 0; j < xvi->num_axes; j++)
171               {
172                 GdkAxisUse use;
173
174                 switch (j)
175                   {
176                   case 0:
177                     use = GDK_AXIS_X;
178                     break;
179                   case 1:
180                     use = GDK_AXIS_Y;
181                     break;
182                   case 2:
183                     use = GDK_AXIS_PRESSURE;
184                     break;
185                   case 3:
186                     use = GDK_AXIS_XTILT;
187                     break;
188                   case 4:
189                     use = GDK_AXIS_YTILT;
190                     break;
191                   case 5:
192                     use = GDK_AXIS_WHEEL;
193                     break;
194                   default:
195                     use = GDK_AXIS_IGNORE;
196                   }
197
198                 _gdk_device_add_axis (device,
199                                       GDK_NONE,
200                                       use,
201                                       xvi->axes[j].min_value,
202                                       xvi->axes[j].max_value,
203                                       xvi->axes[j].resolution);
204               }
205
206             break;
207           }
208       }
209
210       class = (XAnyClassPtr) (((char *) class) + class->length);
211     }
212 }
213
214 /* old versions of XI.h don't define these */
215 #ifndef IsXExtensionKeyboard
216 #define IsXExtensionKeyboard 3
217 #define IsXExtensionPointer  4
218 #endif
219
220 static GdkDevice *
221 create_device (GdkDeviceManager *device_manager,
222                GdkDisplay       *display,
223                XDeviceInfo      *info)
224 {
225   GdkInputSource input_source;
226   GdkDevice *device;
227
228   if (info->use != IsXExtensionPointer &&
229       info->use != IsXExtensionKeyboard)
230     return NULL;
231
232   if (info->use == IsXExtensionKeyboard)
233     input_source = GDK_SOURCE_KEYBOARD;
234   else
235     {
236       gchar *tmp_name;
237
238       tmp_name = g_ascii_strdown (info->name, -1);
239
240       if (strstr (tmp_name, "eraser"))
241         input_source = GDK_SOURCE_ERASER;
242       else if (strstr (tmp_name, "cursor"))
243         input_source = GDK_SOURCE_CURSOR;
244       else if (strstr (tmp_name, "wacom") ||
245                strstr (tmp_name, "pen"))
246         input_source = GDK_SOURCE_PEN;
247       else
248         input_source = GDK_SOURCE_MOUSE;
249
250       g_free (tmp_name);
251     }
252
253   device = g_object_new (GDK_TYPE_X11_DEVICE_XI,
254                          "name", info->name,
255                          "type", GDK_DEVICE_TYPE_FLOATING,
256                          "input-source", input_source,
257                          "input-mode", GDK_MODE_DISABLED,
258                          "has-cursor", FALSE,
259                          "display", display,
260                          "device-manager", device_manager,
261                          "device-id", info->id,
262                          NULL);
263   translate_class_info (device, info);
264
265   return device;
266 }
267
268 static void
269 gdk_x11_device_manager_xi_constructed (GObject *object)
270 {
271   GdkX11DeviceManagerXI *device_manager;
272   XDeviceInfo *devices;
273   gint i, num_devices;
274   GdkDisplay *display;
275
276   device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
277   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
278   devices = XListInputDevices (GDK_DISPLAY_XDISPLAY (display), &num_devices);
279
280   for(i = 0; i < num_devices; i++)
281     {
282       GdkDevice *device;
283
284       device = create_device (GDK_DEVICE_MANAGER (object),
285                               display, &devices[i]);
286       if (device)
287         {
288           device_manager->devices = g_list_prepend (device_manager->devices, device);
289           g_hash_table_insert (device_manager->id_table,
290                                GINT_TO_POINTER (devices[i].id),
291                                g_object_ref (device));
292         }
293     }
294
295   XFreeDeviceList (devices);
296
297   gdk_x11_register_standard_event_type (display,
298                                         device_manager->event_base,
299                                         15 /* Number of events */);
300
301   if (G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->constructed)
302     G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->constructed (object);
303 }
304
305 static void
306 gdk_x11_device_manager_xi_dispose (GObject *object)
307 {
308   GdkX11DeviceManagerXI *device_manager;
309
310   device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
311   g_list_foreach (device_manager->devices, (GFunc) g_object_unref, NULL);
312   g_list_free (device_manager->devices);
313   device_manager->devices = NULL;
314
315   if (device_manager->id_table != NULL)
316     {
317       g_hash_table_destroy (device_manager->id_table);
318       device_manager->id_table = NULL;
319     }
320
321   gdk_window_remove_filter (NULL, window_input_info_filter, object);
322
323   G_OBJECT_CLASS (gdk_x11_device_manager_xi_parent_class)->dispose (object);
324 }
325
326 static void
327 gdk_x11_device_manager_xi_set_property (GObject      *object,
328                                         guint         prop_id,
329                                         const GValue *value,
330                                         GParamSpec   *pspec)
331 {
332   GdkX11DeviceManagerXI *device_manager;
333
334   device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
335
336   switch (prop_id)
337     {
338     case PROP_EVENT_BASE:
339       device_manager->event_base = g_value_get_int (value);
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343       break;
344     }
345 }
346
347 static void
348 gdk_x11_device_manager_xi_get_property (GObject    *object,
349                                         guint       prop_id,
350                                         GValue     *value,
351                                         GParamSpec *pspec)
352 {
353   GdkX11DeviceManagerXI *device_manager;
354
355   device_manager = GDK_X11_DEVICE_MANAGER_XI (object);
356
357   switch (prop_id)
358     {
359     case PROP_EVENT_BASE:
360       g_value_set_int (value, device_manager->event_base);
361       break;
362     default:
363       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
364       break;
365     }
366 }
367
368 static void
369 gdk_x11_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
370 {
371   iface->translate_event = gdk_x11_device_manager_xi_translate_event;
372 }
373
374 /* combine the state of the core device and the device state
375  * into one - for now we do this in a simple-minded manner -
376  * we just take the keyboard portion of the core device and
377  * the button portion (all of?) the device state.
378  * Any button remapping should go on here.
379  */
380 static guint
381 translate_state (guint state, guint device_state)
382 {
383   return device_state | (state & 0xFF);
384 }
385
386 static GdkDevice *
387 lookup_device (GdkX11DeviceManagerXI *manager,
388                XEvent                *xevent)
389 {
390   GdkX11DeviceManagerXI *device_manager;
391   guint32 device_id;
392
393   device_manager = GDK_X11_DEVICE_MANAGER_XI (manager);
394
395   /* This is a sort of a hack, as there isn't any XDeviceAnyEvent -
396      but it's potentially faster than scanning through the types of
397      every device. If we were deceived, then it won't match any of
398      the types for the device anyways */
399   device_id = ((XDeviceButtonEvent *)xevent)->deviceid;
400
401   return g_hash_table_lookup (device_manager->id_table, GINT_TO_POINTER (device_id));
402 }
403
404 static gboolean
405 gdk_x11_device_manager_xi_translate_event (GdkEventTranslator *translator,
406                                            GdkDisplay         *display,
407                                            GdkEvent           *event,
408                                            XEvent             *xevent)
409 {
410   GdkX11DeviceManagerXI *device_manager;
411   GdkEventTranslatorIface *parent_iface;
412   GdkX11DeviceXI *device_xi;
413   GdkDevice *device;
414   GdkWindow *window;
415
416   parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
417   device_manager = GDK_X11_DEVICE_MANAGER_XI (translator);
418
419   if (!device_manager->ignore_core_events &&
420       parent_iface->translate_event (translator, display, event, xevent))
421     return TRUE;
422
423   device = lookup_device (device_manager, xevent);
424   device_xi = GDK_X11_DEVICE_XI (device);
425
426   if (!device)
427     return FALSE;
428
429   window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
430
431   if (!window)
432     return FALSE;
433
434   if ((xevent->type == device_xi->button_press_type) ||
435       (xevent->type == device_xi->button_release_type))
436     {
437       XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
438
439       event->button.type = (xdbe->type == device_xi->button_press_type) ?
440         GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
441
442       event->button.device = device;
443       event->button.window = g_object_ref (window);
444       event->button.time = xdbe->time;
445
446       event->button.x_root = (gdouble) xdbe->x_root;
447       event->button.y_root = (gdouble) xdbe->y_root;
448
449       event->button.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
450       _gdk_x11_device_xi_update_axes (device, xdbe->axes_count,
451                                       xdbe->first_axis, xdbe->axis_data);
452       _gdk_x11_device_xi_translate_axes (device, window,
453                                          device_xi->axis_data,
454                                          event->button.axes,
455                                          &event->button.x,
456                                          &event->button.y);
457
458       event->button.state = translate_state (xdbe->state, xdbe->device_state);
459       event->button.button = xdbe->button;
460
461       if (event->button.type == GDK_BUTTON_PRESS)
462         _gdk_event_button_generate (gdk_window_get_display (event->button.window),
463                                     event);
464
465       GDK_NOTE (EVENTS,
466         g_print ("button %s:\t\twindow: %ld  device: %ld  x,y: %f %f  button: %d\n",
467                  (event->button.type == GDK_BUTTON_PRESS) ? "press" : "release",
468                  xdbe->window,
469                  xdbe->deviceid,
470                  event->button.x, event->button.y,
471                  xdbe->button));
472
473       /* Update the timestamp of the latest user interaction, if the event has
474        * a valid timestamp.
475        */
476       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
477         gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
478                                       gdk_event_get_time (event));
479       return TRUE;
480     }
481
482   if ((xevent->type == device_xi->key_press_type) ||
483       (xevent->type == device_xi->key_release_type))
484     {
485       XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
486
487       GDK_NOTE (EVENTS,
488         g_print ("device key %s:\twindow: %ld  device: %ld  keycode: %d\n",
489                  (event->key.type == GDK_KEY_PRESS) ? "press" : "release",
490                  xdke->window,
491                  xdke->deviceid,
492                  xdke->keycode));
493
494       if (xdke->keycode < device_xi->min_keycode ||
495           xdke->keycode >= device_xi->min_keycode + gdk_device_get_n_keys (device))
496         {
497           g_warning ("Invalid device key code received");
498           return FALSE;
499         }
500
501       gdk_device_get_key (device, xdke->keycode - device_xi->min_keycode,
502                           &event->key.keyval,
503                           &event->key.state);
504
505       if (event->key.keyval == 0)
506         {
507           GDK_NOTE (EVENTS,
508             g_print ("\t\ttranslation - NONE\n"));
509
510           return FALSE;
511         }
512
513       event->key.type = (xdke->type == device_xi->key_press_type) ?
514         GDK_KEY_PRESS : GDK_KEY_RELEASE;
515
516       event->key.window = g_object_ref (window);
517       event->key.time = xdke->time;
518
519       event->key.state |= translate_state (xdke->state, xdke->device_state);
520
521       /* Add a string translation for the key event */
522       if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xFF))
523         {
524           event->key.length = 1;
525           event->key.string = g_new (gchar, 2);
526           event->key.string[0] = (gchar) event->key.keyval;
527           event->key.string[1] = 0;
528         }
529       else
530         {
531           event->key.length = 0;
532           event->key.string = g_new0 (gchar, 1);
533         }
534
535       GDK_NOTE (EVENTS,
536         g_print ("\t\ttranslation - keyval: %d modifiers: %#x\n",
537                  event->key.keyval,
538                  event->key.state));
539
540       /* Update the timestamp of the latest user interaction, if the event has
541        * a valid timestamp.
542        */
543       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
544         gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
545                                       gdk_event_get_time (event));
546       return TRUE;
547     }
548
549   if (xevent->type == device_xi->motion_notify_type)
550     {
551       XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
552
553       event->motion.device = device;
554
555       if (device_xi->in_proximity)
556         device_manager->ignore_core_events = TRUE;
557
558       event->motion.x_root = (gdouble) xdme->x_root;
559       event->motion.y_root = (gdouble) xdme->y_root;
560
561       event->motion.axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
562       _gdk_x11_device_xi_update_axes (device, xdme->axes_count,
563                                       xdme->first_axis, xdme->axis_data);
564       _gdk_x11_device_xi_translate_axes (device, window,
565                                          device_xi->axis_data,
566                                          event->motion.axes,
567                                          &event->motion.x,
568                                          &event->motion.y);
569
570       event->motion.type = GDK_MOTION_NOTIFY;
571       event->motion.window = g_object_ref (window);
572       event->motion.time = xdme->time;
573       event->motion.state = translate_state (xdme->state,
574                                              xdme->device_state);
575       event->motion.is_hint = xdme->is_hint;
576
577       GDK_NOTE (EVENTS,
578         g_print ("motion notify:\t\twindow: %ld  device: %ld  x,y: %f %f  state %#4x  hint: %s\n",
579                  xdme->window,
580                  xdme->deviceid,
581                  event->motion.x, event->motion.y,
582                  event->motion.state,
583                  (xdme->is_hint) ? "true" : "false"));
584
585
586       /* Update the timestamp of the latest user interaction, if the event has
587        * a valid timestamp.
588        */
589       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
590         gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
591                                       gdk_event_get_time (event));
592       return TRUE;
593     }
594
595   if (xevent->type == device_xi->proximity_in_type ||
596       xevent->type == device_xi->proximity_out_type)
597     {
598       XProximityNotifyEvent *xpne = (XProximityNotifyEvent *) xevent;
599
600       if (xevent->type == device_xi->proximity_in_type)
601         {
602           event->proximity.type = GDK_PROXIMITY_IN;
603           device_xi->in_proximity = TRUE;
604           device_manager->ignore_core_events = TRUE;
605         }
606       else
607         {
608           event->proximity.type = GDK_PROXIMITY_OUT;
609           device_xi->in_proximity = FALSE;
610           device_manager->ignore_core_events = FALSE;
611         }
612
613       event->proximity.device = device;
614       event->proximity.window = g_object_ref (window);
615       event->proximity.time = xpne->time;
616
617       /* Update the timestamp of the latest user interaction, if the event has
618        * a valid timestamp.
619        */
620       if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
621         gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
622                                       gdk_event_get_time (event));
623       return TRUE;
624     }
625
626   if (xevent->type == device_xi->state_notify_type)
627     {
628       XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
629       XInputClass *input_class = (XInputClass *) xdse->data;
630       int i;
631
632       for (i = 0; i < xdse->num_classes; i++)
633         {
634           if (input_class->class == ValuatorClass)
635             _gdk_x11_device_xi_update_axes (device, gdk_device_get_n_axes (device), 0,
636                                             ((XValuatorState *)input_class)->valuators);
637
638           input_class = (XInputClass *)(((char *)input_class)+input_class->length);
639         }
640
641       GDK_NOTE (EVENTS,
642                 g_print ("device state notify:\t\twindow: %ld  device: %ld\n",
643                          xdse->window,
644                          xdse->deviceid));
645
646       return FALSE;
647     }
648
649   return FALSE;
650 }
651
652 static GList *
653 gdk_x11_device_manager_xi_list_devices (GdkDeviceManager *manager,
654                                         GdkDeviceType     type)
655 {
656   GdkX11DeviceManagerXI *device_manager;
657
658   device_manager = GDK_X11_DEVICE_MANAGER_XI (manager);
659
660   if (type == GDK_DEVICE_TYPE_MASTER)
661     return GDK_DEVICE_MANAGER_CLASS (gdk_x11_device_manager_xi_parent_class)->list_devices (manager, type);
662   else if (type == GDK_DEVICE_TYPE_FLOATING)
663     {
664       return g_list_copy (device_manager->devices);
665     }
666   else
667     return NULL;
668 }
669
670 #else /* XINPUT_XFREE */
671
672 static void
673 gdk_x11_device_manager_xi_class_init (GdkX11DeviceManagerXIClass *klass)
674 {
675 }
676
677 static void
678 gdk_x11_device_manager_xi_init (GdkX11DeviceManagerXI *device_manager)
679 {
680 }
681
682 static void
683 gdk_x11_device_manager_xi_event_translator_init (GdkEventTranslatorIface *iface)
684 {
685 }
686
687 #endif /* XINPUT_XFREE */