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