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