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