]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdevicemanager-xi2.c
quartz: Null check title before setting it
[~andy/gtk] / gdk / x11 / gdkdevicemanager-xi2.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-xi2.h"
21 #include "gdkx11device-xi2.h"
22
23 #include "gdkdevicemanagerprivate-core.h"
24 #include "gdkdeviceprivate.h"
25 #include "gdkdisplayprivate.h"
26 #include "gdkeventtranslator.h"
27 #include "gdkprivate-x11.h"
28 #include "gdkintl.h"
29 #include "gdkkeysyms.h"
30 #include "gdkinternals.h"
31
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/XInput2.h>
35
36 #include <string.h>
37
38 struct _GdkX11DeviceManagerXI2
39 {
40   GdkX11DeviceManagerCore parent_object;
41
42   GHashTable *id_table;
43
44   GList *devices;
45
46   gint opcode;
47   gint major;
48   gint minor;
49 };
50
51 struct _GdkX11DeviceManagerXI2Class
52 {
53   GdkDeviceManagerClass parent_class;
54 };
55
56 static void     gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface);
57
58 G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI2, gdk_x11_device_manager_xi2, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
59                          G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
60                                                 gdk_x11_device_manager_xi2_event_translator_init))
61
62 static void    gdk_x11_device_manager_xi2_constructed  (GObject      *object);
63 static void    gdk_x11_device_manager_xi2_dispose      (GObject      *object);
64 static void    gdk_x11_device_manager_xi2_set_property (GObject      *object,
65                                                         guint         prop_id,
66                                                         const GValue *value,
67                                                         GParamSpec   *pspec);
68 static void    gdk_x11_device_manager_xi2_get_property (GObject      *object,
69                                                         guint         prop_id,
70                                                         GValue       *value,
71                                                         GParamSpec   *pspec);
72
73 static GList * gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
74                                                         GdkDeviceType     type);
75 static GdkDevice * gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager);
76
77 static gboolean gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
78                                                             GdkDisplay         *display,
79                                                             GdkEvent           *event,
80                                                             XEvent             *xevent);
81 static GdkEventMask gdk_x11_device_manager_xi2_get_handled_events   (GdkEventTranslator *translator);
82 static void         gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
83                                                                      Window              window,
84                                                                      GdkEventMask        event_mask);
85 static GdkWindow *  gdk_x11_device_manager_xi2_get_window           (GdkEventTranslator *translator,
86                                                                      XEvent             *xevent);
87
88 enum {
89   PROP_0,
90   PROP_OPCODE,
91   PROP_MAJOR,
92   PROP_MINOR
93 };
94
95 static void
96 gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass)
97 {
98   GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
99   GObjectClass *object_class = G_OBJECT_CLASS (klass);
100
101   object_class->constructed = gdk_x11_device_manager_xi2_constructed;
102   object_class->dispose = gdk_x11_device_manager_xi2_dispose;
103   object_class->set_property = gdk_x11_device_manager_xi2_set_property;
104   object_class->get_property = gdk_x11_device_manager_xi2_get_property;
105
106   device_manager_class->list_devices = gdk_x11_device_manager_xi2_list_devices;
107   device_manager_class->get_client_pointer = gdk_x11_device_manager_xi2_get_client_pointer;
108
109   g_object_class_install_property (object_class,
110                                    PROP_OPCODE,
111                                    g_param_spec_int ("opcode",
112                                                      P_("Opcode"),
113                                                      P_("Opcode for XInput2 requests"),
114                                                      0, G_MAXINT, 0,
115                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
116   g_object_class_install_property (object_class,
117                                    PROP_MAJOR,
118                                    g_param_spec_int ("major",
119                                                      P_("Major"),
120                                                      P_("Major version number"),
121                                                      0, G_MAXINT, 0,
122                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
123   g_object_class_install_property (object_class,
124                                    PROP_MINOR,
125                                    g_param_spec_int ("minor",
126                                                      P_("Minor"),
127                                                      P_("Minor version number"),
128                                                      0, G_MAXINT, 0,
129                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
130 }
131
132 static void
133 gdk_x11_device_manager_xi2_init (GdkX11DeviceManagerXI2 *device_manager)
134 {
135   device_manager->id_table = g_hash_table_new_full (g_direct_hash,
136                                                     g_direct_equal,
137                                                     NULL,
138                                                     (GDestroyNotify) g_object_unref);
139 }
140
141 static void
142 _gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
143                                            Window            xwindow,
144                                            XIEventMask      *event_mask)
145 {
146   GdkDisplay *display;
147   Display *xdisplay;
148
149   display = gdk_device_manager_get_display (device_manager);
150   xdisplay = GDK_DISPLAY_XDISPLAY (display);
151
152   XISelectEvents (xdisplay, xwindow, event_mask, 1);
153 }
154
155 static void
156 translate_valuator_class (GdkDisplay          *display,
157                           GdkDevice           *device,
158                           Atom                 valuator_label,
159                           gdouble              min,
160                           gdouble              max,
161                           gdouble              resolution)
162 {
163   static gboolean initialized = FALSE;
164   static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
165   GdkAxisUse use = GDK_AXIS_IGNORE;
166   GdkAtom label;
167   gint i;
168
169   if (!initialized)
170     {
171       label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
172       label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");
173       label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Pressure");
174       label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
175       label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
176       label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
177       initialized = TRUE;
178     }
179
180   for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
181     {
182       if (label_atoms[i] == valuator_label)
183         {
184           use = i;
185           break;
186         }
187     }
188
189   if (valuator_label != None)
190     label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
191   else
192     label = GDK_NONE;
193
194   _gdk_device_add_axis (device, label, use, min, max, resolution);
195 }
196
197 static void
198 translate_device_classes (GdkDisplay      *display,
199                           GdkDevice       *device,
200                           XIAnyClassInfo **classes,
201                           guint            n_classes)
202 {
203   gint i;
204
205   g_object_freeze_notify (G_OBJECT (device));
206
207   for (i = 0; i < n_classes; i++)
208     {
209       XIAnyClassInfo *class_info = classes[i];
210
211       switch (class_info->type)
212         {
213         case XIKeyClass:
214           {
215             XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
216             gint i;
217
218             _gdk_device_set_keys (device, key_info->num_keycodes);
219
220             for (i = 0; i < key_info->num_keycodes; i++)
221               gdk_device_set_key (device, i, key_info->keycodes[i], 0);
222           }
223           break;
224         case XIValuatorClass:
225           {
226             XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info;
227             translate_valuator_class (display, device,
228                                       valuator_info->label,
229                                       valuator_info->min,
230                                       valuator_info->max,
231                                       valuator_info->resolution);
232           }
233           break;
234 #ifdef XINPUT_2_2
235         case XIScrollClass:
236           {
237             XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
238             GdkScrollDirection direction;
239
240             if (scroll_info->scroll_type == XIScrollTypeVertical)
241               direction = GDK_SCROLL_DOWN;
242             else
243               direction = GDK_SCROLL_RIGHT;
244
245             GDK_NOTE (INPUT,
246                       g_message ("\n\tscroll valuator %d: %s, increment %f",
247                                  scroll_info->number,
248                                  scroll_info->scroll_type == XIScrollTypeVertical
249                                                 ? "vertical"
250                                                 : "horizontal",
251                                  scroll_info->increment));
252
253             _gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device),
254                                                      scroll_info->number,
255                                                      direction,
256                                                      scroll_info->increment);
257           }
258 #endif /* XINPUT_2_2 */
259         default:
260           /* Ignore */
261           break;
262         }
263     }
264
265   g_object_thaw_notify (G_OBJECT (device));
266 }
267
268 static gboolean
269 is_touch_device (XIAnyClassInfo **classes,
270                  guint            n_classes,
271                  GdkInputSource  *device_type,
272                  gint            *num_touches)
273 {
274 #ifdef XINPUT_2_2
275   guint i;
276
277   for (i = 0; i < n_classes; i++)
278     {
279       XITouchClassInfo *class = (XITouchClassInfo *) classes[i];
280
281       if (class->type != XITouchClass)
282         continue;
283
284       if (class->num_touches > 0)
285         {
286           if (class->mode == XIDirectTouch)
287             *device_type = GDK_SOURCE_TOUCHSCREEN;
288           else if (class->mode == XIDependentTouch)
289             *device_type = GDK_SOURCE_TOUCHPAD;
290           else
291             continue;
292
293           *num_touches = class->num_touches;
294
295           return TRUE;
296         }
297     }
298 #endif
299
300   return FALSE;
301 }
302
303 static GdkDevice *
304 create_device (GdkDeviceManager *device_manager,
305                GdkDisplay       *display,
306                XIDeviceInfo     *dev)
307 {
308   GdkInputSource input_source;
309   GdkInputSource touch_source;
310   GdkDeviceType type;
311   GdkDevice *device;
312   GdkInputMode mode;
313   gint num_touches = 0;
314
315   if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
316     input_source = GDK_SOURCE_KEYBOARD;
317   else if (dev->use == XISlavePointer &&
318            is_touch_device (dev->classes, dev->num_classes, &touch_source, &num_touches))
319     input_source = touch_source;
320   else
321     {
322       gchar *tmp_name;
323
324       tmp_name = g_ascii_strdown (dev->name, -1);
325
326       if (strstr (tmp_name, "eraser"))
327         input_source = GDK_SOURCE_ERASER;
328       else if (strstr (tmp_name, "cursor"))
329         input_source = GDK_SOURCE_CURSOR;
330       else if (strstr (tmp_name, "wacom") ||
331                strstr (tmp_name, "pen"))
332         input_source = GDK_SOURCE_PEN;
333       else
334         input_source = GDK_SOURCE_MOUSE;
335
336       g_free (tmp_name);
337     }
338
339   switch (dev->use)
340     {
341     case XIMasterKeyboard:
342     case XIMasterPointer:
343       type = GDK_DEVICE_TYPE_MASTER;
344       mode = GDK_MODE_SCREEN;
345       break;
346     case XISlaveKeyboard:
347     case XISlavePointer:
348       type = GDK_DEVICE_TYPE_SLAVE;
349       mode = GDK_MODE_DISABLED;
350       break;
351     case XIFloatingSlave:
352     default:
353       type = GDK_DEVICE_TYPE_FLOATING;
354       mode = GDK_MODE_DISABLED;
355       break;
356     }
357
358   GDK_NOTE (INPUT,
359             ({
360               const gchar *type_names[] = { "master", "slave", "floating" };
361               const gchar *source_names[] = { "mouse", "pen", "eraser", "cursor", "keyboard", "direct touch", "indirect touch" };
362               const gchar *mode_names[] = { "disabled", "screen", "window" };
363               g_message ("input device:\n\tname: %s\n\ttype: %s\n\tsource: %s\n\tmode: %s\n\thas cursor: %d\n\ttouches: %d",
364                          dev->name,
365                          type_names[type],
366                          source_names[input_source],
367                          mode_names[mode],
368                          dev->use == XIMasterPointer,
369                          num_touches);
370             }));
371
372   device = g_object_new (GDK_TYPE_X11_DEVICE_XI2,
373                          "name", dev->name,
374                          "type", type,
375                          "input-source", input_source,
376                          "input-mode", mode,
377                          "has-cursor", (dev->use == XIMasterPointer),
378                          "display", display,
379                          "device-manager", device_manager,
380                          "device-id", dev->deviceid,
381                          NULL);
382
383   translate_device_classes (display, device, dev->classes, dev->num_classes);
384
385   return device;
386 }
387
388 static GdkDevice *
389 add_device (GdkX11DeviceManagerXI2 *device_manager,
390             XIDeviceInfo           *dev,
391             gboolean                emit_signal)
392 {
393   GdkDisplay *display;
394   GdkDevice *device;
395
396   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
397   device = create_device (GDK_DEVICE_MANAGER (device_manager), display, dev);
398
399   g_hash_table_replace (device_manager->id_table,
400                         GINT_TO_POINTER (dev->deviceid),
401                         g_object_ref (device));
402
403   device_manager->devices = g_list_append (device_manager->devices, device);
404
405   if (emit_signal)
406     {
407       if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
408         {
409           GdkDevice *master;
410
411           /* The device manager is already constructed, then
412            * keep the hierarchy coherent for the added device.
413            */
414           master = g_hash_table_lookup (device_manager->id_table,
415                                         GINT_TO_POINTER (dev->attachment));
416
417           _gdk_device_set_associated_device (device, master);
418           _gdk_device_add_slave (master, device);
419         }
420
421       g_signal_emit_by_name (device_manager, "device-added", device);
422     }
423
424   return device;
425 }
426
427 static void
428 remove_device (GdkX11DeviceManagerXI2 *device_manager,
429                gint                    device_id)
430 {
431   GdkDevice *device;
432
433   device = g_hash_table_lookup (device_manager->id_table,
434                                 GINT_TO_POINTER (device_id));
435
436   if (device)
437     {
438       device_manager->devices = g_list_remove (device_manager->devices, device);
439
440       g_signal_emit_by_name (device_manager, "device-removed", device);
441
442       g_object_run_dispose (G_OBJECT (device));
443
444       g_hash_table_remove (device_manager->id_table,
445                            GINT_TO_POINTER (device_id));
446     }
447 }
448
449 static void
450 relate_masters (gpointer key,
451                 gpointer value,
452                 gpointer user_data)
453 {
454   GdkX11DeviceManagerXI2 *device_manager;
455   GdkDevice *device, *relative;
456
457   device_manager = user_data;
458   device = g_hash_table_lookup (device_manager->id_table, key);
459   relative = g_hash_table_lookup (device_manager->id_table, value);
460
461   _gdk_device_set_associated_device (device, relative);
462   _gdk_device_set_associated_device (relative, device);
463 }
464
465 static void
466 relate_slaves (gpointer key,
467                gpointer value,
468                gpointer user_data)
469 {
470   GdkX11DeviceManagerXI2 *device_manager;
471   GdkDevice *slave, *master;
472
473   device_manager = user_data;
474   slave = g_hash_table_lookup (device_manager->id_table, key);
475   master = g_hash_table_lookup (device_manager->id_table, value);
476
477   _gdk_device_set_associated_device (slave, master);
478   _gdk_device_add_slave (master, slave);
479 }
480
481 static void
482 gdk_x11_device_manager_xi2_constructed (GObject *object)
483 {
484   GdkX11DeviceManagerXI2 *device_manager;
485   GdkDisplay *display;
486   GdkScreen *screen;
487   GHashTable *masters, *slaves;
488   Display *xdisplay;
489   XIDeviceInfo *info, *dev;
490   int ndevices, i;
491   XIEventMask event_mask;
492   unsigned char mask[2] = { 0 };
493
494   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
495   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
496   xdisplay = GDK_DISPLAY_XDISPLAY (display);
497
498   g_assert (device_manager->major == 2);
499
500   masters = g_hash_table_new (NULL, NULL);
501   slaves = g_hash_table_new (NULL, NULL);
502
503   info = XIQueryDevice (xdisplay, XIAllDevices, &ndevices);
504
505   /* Initialize devices list */
506   for (i = 0; i < ndevices; i++)
507     {
508       dev = &info[i];
509
510       if (!dev->enabled)
511               continue;
512
513       add_device (device_manager, dev, FALSE);
514
515       if (dev->use == XIMasterPointer ||
516           dev->use == XIMasterKeyboard)
517         {
518           g_hash_table_insert (masters,
519                                GINT_TO_POINTER (dev->deviceid),
520                                GINT_TO_POINTER (dev->attachment));
521         }
522       else if (dev->use == XISlavePointer ||
523                dev->use == XISlaveKeyboard)
524         {
525           g_hash_table_insert (slaves,
526                                GINT_TO_POINTER (dev->deviceid),
527                                GINT_TO_POINTER (dev->attachment));
528         }
529     }
530
531   XIFreeDeviceInfo (info);
532
533   /* Stablish relationships between devices */
534   g_hash_table_foreach (masters, relate_masters, object);
535   g_hash_table_destroy (masters);
536
537   g_hash_table_foreach (slaves, relate_slaves, object);
538   g_hash_table_destroy (slaves);
539
540   /* Connect to hierarchy change events */
541   screen = gdk_display_get_default_screen (display);
542   XISetMask (mask, XI_HierarchyChanged);
543   XISetMask (mask, XI_DeviceChanged);
544
545   event_mask.deviceid = XIAllDevices;
546   event_mask.mask_len = sizeof (mask);
547   event_mask.mask = mask;
548
549   _gdk_x11_device_manager_xi2_select_events (GDK_DEVICE_MANAGER (object),
550                                              GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
551                                              &event_mask);
552 }
553
554 static void
555 gdk_x11_device_manager_xi2_dispose (GObject *object)
556 {
557   GdkX11DeviceManagerXI2 *device_manager;
558
559   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
560
561   g_list_free_full (device_manager->devices, g_object_unref);
562   device_manager->devices = NULL;
563
564   if (device_manager->id_table)
565     {
566       g_hash_table_destroy (device_manager->id_table);
567       device_manager->id_table = NULL;
568     }
569
570   G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->dispose (object);
571 }
572
573 static GList *
574 gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
575                                          GdkDeviceType     type)
576 {
577   GdkX11DeviceManagerXI2 *device_manager_xi2;
578   GList *cur, *list = NULL;
579
580   device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (device_manager);
581
582   for (cur = device_manager_xi2->devices; cur; cur = cur->next)
583     {
584       GdkDevice *dev = cur->data;
585
586       if (type == gdk_device_get_device_type (dev))
587         list = g_list_prepend (list, dev);
588     }
589
590   return list;
591 }
592
593 static GdkDevice *
594 gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager)
595 {
596   GdkX11DeviceManagerXI2 *device_manager_xi2;
597   GdkDisplay *display;
598   int device_id;
599
600   device_manager_xi2 = (GdkX11DeviceManagerXI2 *) device_manager;
601   display = gdk_device_manager_get_display (device_manager);
602
603   XIGetClientPointer (GDK_DISPLAY_XDISPLAY (display),
604                       None, &device_id);
605
606   return g_hash_table_lookup (device_manager_xi2->id_table,
607                               GINT_TO_POINTER (device_id));
608 }
609
610 static void
611 gdk_x11_device_manager_xi2_set_property (GObject      *object,
612                                          guint         prop_id,
613                                          const GValue *value,
614                                          GParamSpec   *pspec)
615 {
616   GdkX11DeviceManagerXI2 *device_manager;
617
618   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
619
620   switch (prop_id)
621     {
622     case PROP_OPCODE:
623       device_manager->opcode = g_value_get_int (value);
624       break;
625     case PROP_MAJOR:
626       device_manager->major = g_value_get_int (value);
627       break;
628     case PROP_MINOR:
629       device_manager->minor = g_value_get_int (value);
630       break;
631     default:
632       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
633       break;
634     }
635 }
636
637 static void
638 gdk_x11_device_manager_xi2_get_property (GObject    *object,
639                                          guint       prop_id,
640                                          GValue     *value,
641                                          GParamSpec *pspec)
642 {
643   GdkX11DeviceManagerXI2 *device_manager;
644
645   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
646
647   switch (prop_id)
648     {
649     case PROP_OPCODE:
650       g_value_set_int (value, device_manager->opcode);
651       break;
652     case PROP_MAJOR:
653       g_value_set_int (value, device_manager->major);
654       break;
655     case PROP_MINOR:
656       g_value_set_int (value, device_manager->minor);
657       break;
658     default:
659       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
660       break;
661     }
662 }
663
664 static void
665 gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface)
666 {
667   iface->translate_event = gdk_x11_device_manager_xi2_translate_event;
668   iface->get_handled_events = gdk_x11_device_manager_xi2_get_handled_events;
669   iface->select_window_events = gdk_x11_device_manager_xi2_select_window_events;
670   iface->get_window = gdk_x11_device_manager_xi2_get_window;
671 }
672
673 static void
674 handle_hierarchy_changed (GdkX11DeviceManagerXI2 *device_manager,
675                           XIHierarchyEvent       *ev)
676 {
677   GdkDisplay *display;
678   Display *xdisplay;
679   XIDeviceInfo *info;
680   int ndevices;
681   gint i;
682
683   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
684   xdisplay = GDK_DISPLAY_XDISPLAY (display);
685
686   for (i = 0; i < ev->num_info; i++)
687     {
688       if (ev->info[i].flags & XIDeviceEnabled)
689         {
690           gdk_x11_display_error_trap_push (display);
691           info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
692           gdk_x11_display_error_trap_pop_ignored (display);
693           if (info)
694             {
695               add_device (device_manager, &info[0], TRUE);
696               XIFreeDeviceInfo (info);
697             }
698         }
699       else if (ev->info[i].flags & XIDeviceDisabled)
700         remove_device (device_manager, ev->info[i].deviceid);
701       else if (ev->info[i].flags & XISlaveAttached ||
702                ev->info[i].flags & XISlaveDetached)
703         {
704           GdkDevice *master, *slave;
705
706           slave = g_hash_table_lookup (device_manager->id_table,
707                                        GINT_TO_POINTER (ev->info[i].deviceid));
708
709           if (!slave)
710             continue;
711
712           /* Remove old master info */
713           master = gdk_device_get_associated_device (slave);
714
715           if (master)
716             {
717               _gdk_device_remove_slave (master, slave);
718               _gdk_device_set_associated_device (slave, NULL);
719
720               g_signal_emit_by_name (device_manager, "device-changed", master);
721             }
722
723           /* Add new master if it's an attachment event */
724           if (ev->info[i].flags & XISlaveAttached)
725             {
726               gdk_x11_display_error_trap_push (display);
727               info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
728               gdk_x11_display_error_trap_pop_ignored (display);
729               if (info)
730                 {
731                   master = g_hash_table_lookup (device_manager->id_table,
732                                                 GINT_TO_POINTER (info->attachment));
733                   XIFreeDeviceInfo (info);
734                 }
735
736               if (master)
737                 {
738                   _gdk_device_set_associated_device (slave, master);
739                   _gdk_device_add_slave (master, slave);
740
741                   g_signal_emit_by_name (device_manager, "device-changed", master);
742                 }
743             }
744
745           g_signal_emit_by_name (device_manager, "device-changed", slave);
746         }
747     }
748 }
749
750 static void
751 handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
752                        XIDeviceChangedEvent   *ev)
753 {
754   GdkDisplay *display;
755   GdkDevice *device, *source_device;
756
757   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
758   device = g_hash_table_lookup (device_manager->id_table,
759                                 GUINT_TO_POINTER (ev->deviceid));
760   source_device = g_hash_table_lookup (device_manager->id_table,
761                                        GUINT_TO_POINTER (ev->sourceid));
762
763   if (device)
764     {
765       _gdk_device_reset_axes (device);
766       translate_device_classes (display, device, ev->classes, ev->num_classes);
767
768       g_signal_emit_by_name (G_OBJECT (device), "changed");
769     }
770
771   if (source_device)
772     _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
773 }
774
775 static GdkCrossingMode
776 translate_crossing_mode (gint mode)
777 {
778   switch (mode)
779     {
780     case NotifyNormal:
781       return GDK_CROSSING_NORMAL;
782     case NotifyGrab:
783       return GDK_CROSSING_GRAB;
784     case NotifyUngrab:
785       return GDK_CROSSING_UNGRAB;
786     default:
787       g_assert_not_reached ();
788     }
789 }
790
791 static GdkNotifyType
792 translate_notify_type (gint detail)
793 {
794   switch (detail)
795     {
796     case NotifyInferior:
797       return GDK_NOTIFY_INFERIOR;
798     case NotifyAncestor:
799       return GDK_NOTIFY_ANCESTOR;
800     case NotifyVirtual:
801       return GDK_NOTIFY_VIRTUAL;
802     case NotifyNonlinear:
803       return GDK_NOTIFY_NONLINEAR;
804     case NotifyNonlinearVirtual:
805       return GDK_NOTIFY_NONLINEAR_VIRTUAL;
806     default:
807       g_assert_not_reached ();
808     }
809 }
810
811 static gboolean
812 set_screen_from_root (GdkDisplay *display,
813                       GdkEvent   *event,
814                       Window      xrootwin)
815 {
816   GdkScreen *screen;
817
818   screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
819
820   if (screen)
821     {
822       gdk_event_set_screen (event, screen);
823
824       return TRUE;
825     }
826
827   return FALSE;
828 }
829
830 static void
831 set_user_time (GdkEvent *event)
832 {
833   GdkWindow *window;
834   guint32 time;
835
836   window = gdk_window_get_toplevel (event->any.window);
837   g_return_if_fail (GDK_IS_WINDOW (window));
838
839   time = gdk_event_get_time (event);
840
841   /* If an event doesn't have a valid timestamp, we shouldn't use it
842    * to update the latest user interaction time.
843    */
844   if (time != GDK_CURRENT_TIME)
845     gdk_x11_window_set_user_time (window, time);
846 }
847
848 static gdouble *
849 translate_axes (GdkDevice       *device,
850                 gdouble          x,
851                 gdouble          y,
852                 GdkWindow       *window,
853                 XIValuatorState *valuators)
854 {
855   guint n_axes, i;
856   gdouble *axes;
857   gdouble *vals;
858
859   g_object_get (device, "n-axes", &n_axes, NULL);
860
861   axes = g_new0 (gdouble, n_axes);
862   vals = valuators->values;
863
864   for (i = 0; i < valuators->mask_len * 8; i++)
865     {
866       GdkAxisUse use;
867       gdouble val;
868
869       if (!XIMaskIsSet (valuators->mask, i))
870         continue;
871
872       use = gdk_device_get_axis_use (device, i);
873       val = *vals++;
874
875       switch (use)
876         {
877         case GDK_AXIS_X:
878         case GDK_AXIS_Y:
879           if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
880             _gdk_device_translate_window_coord (device, window, i, val, &axes[i]);
881           else
882             {
883               if (use == GDK_AXIS_X)
884                 axes[i] = x;
885               else
886                 axes[i] = y;
887             }
888           break;
889         default:
890           _gdk_device_translate_axis (device, i, val, &axes[i]);
891           break;
892         }
893     }
894
895   return axes;
896 }
897
898 static gboolean
899 is_parent_of (GdkWindow *parent,
900               GdkWindow *child)
901 {
902   GdkWindow *w;
903
904   w = child;
905   while (w != NULL)
906     {
907       if (w == parent)
908         return TRUE;
909
910       w = gdk_window_get_parent (w);
911     }
912
913   return FALSE;
914 }
915
916 static gboolean
917 get_event_window (GdkEventTranslator *translator,
918                   XIEvent            *ev,
919                   GdkWindow         **window_p)
920 {
921   GdkDisplay *display;
922   GdkWindow *window = NULL;
923   gboolean should_have_window = TRUE;
924
925   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (translator));
926
927   switch (ev->evtype)
928     {
929     case XI_KeyPress:
930     case XI_KeyRelease:
931     case XI_ButtonPress:
932     case XI_ButtonRelease:
933     case XI_Motion:
934 #ifdef XINPUT_2_2
935     case XI_TouchUpdate:
936     case XI_TouchBegin:
937     case XI_TouchEnd:
938 #endif /* XINPUT_2_2 */
939       {
940         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
941
942         window = gdk_x11_window_lookup_for_display (display, xev->event);
943
944         /* Apply keyboard grabs to non-native windows */
945         if (ev->evtype == XI_KeyPress || ev->evtype == XI_KeyRelease)
946           {
947             GdkDeviceGrabInfo *info;
948             GdkDevice *device;
949             gulong serial;
950
951             device = g_hash_table_lookup (GDK_X11_DEVICE_MANAGER_XI2 (translator)->id_table,
952                                           GUINT_TO_POINTER (((XIDeviceEvent *) ev)->deviceid));
953
954             serial = _gdk_display_get_next_serial (display);
955             info = _gdk_display_has_device_grab (display, device, serial);
956
957             if (info &&
958                 (!is_parent_of (info->window, window) ||
959                  !info->owner_events))
960               {
961                 /* Report key event against grab window */
962                 window = info->window;
963               }
964           }
965       }
966       break;
967     case XI_Enter:
968     case XI_Leave:
969     case XI_FocusIn:
970     case XI_FocusOut:
971       {
972         XIEnterEvent *xev = (XIEnterEvent *) ev;
973
974         window = gdk_x11_window_lookup_for_display (display, xev->event);
975       }
976       break;
977     default:
978       should_have_window = FALSE;
979       break;
980     }
981
982   *window_p = window;
983
984   if (should_have_window && !window)
985     return FALSE;
986
987   return TRUE;
988 }
989
990 static gboolean
991 gdk_x11_device_manager_xi2_translate_core_event (GdkEventTranslator *translator,
992                                                  GdkDisplay         *display,
993                                                  GdkEvent           *event,
994                                                  XEvent             *xevent)
995 {
996   GdkEventTranslatorIface *parent_iface;
997   gboolean keyboard = FALSE;
998   GdkDevice *device;
999
1000   if ((xevent->type == KeyPress || xevent->type == KeyRelease) &&
1001       (xevent->xkey.keycode == 0 || xevent->xkey.serial == 0))
1002     {
1003       /* The X input methods (when triggered via XFilterEvent)
1004        * generate a core key press event with keycode 0 to signal the
1005        * end of a key sequence. We use the core translate_event
1006        * implementation to translate this event.
1007        *
1008        * Other less educated IM modules like to filter every keypress,
1009        * only to have these replaced by their own homegrown events,
1010        * these events oddly have serial=0, so we try to catch these.
1011        *
1012        * This is just a bandaid fix to keep xim working with a single
1013        * keyboard until XFilterEvent learns about XI2.
1014        */
1015       keyboard = TRUE;
1016     }
1017   else if (xevent->xany.send_event)
1018     {
1019       /* If another process sends us core events, process them; we
1020        * assume that it won't send us redundant core and XI2 events.
1021        * (At the moment, it's not possible to send XI2 events anyway.
1022        * In the future, an app that was trying to decide whether to
1023        * send core or XI2 events could look at the event mask on the
1024        * window to see which kind we are listening to.)
1025        */
1026       switch (xevent->type)
1027         {
1028         case KeyPress:
1029         case KeyRelease:
1030         case FocusIn:
1031         case FocusOut:
1032           keyboard = TRUE;
1033           break;
1034
1035         case ButtonPress:
1036         case ButtonRelease:
1037         case MotionNotify:
1038         case EnterNotify:
1039         case LeaveNotify:
1040           break;
1041
1042         default:
1043           return FALSE;
1044         }
1045     }
1046   else
1047     return FALSE;
1048
1049   parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
1050   if (!parent_iface->translate_event (translator, display, event, xevent))
1051     return FALSE;
1052
1053   /* The core device manager sets a core device on the event.
1054    * We need to override that with an XI2 device, since we are
1055    * using XI2.
1056    */
1057   device = gdk_x11_device_manager_xi2_get_client_pointer ((GdkDeviceManager *)translator);
1058   if (keyboard)
1059     device = gdk_device_get_associated_device (device);
1060   gdk_event_set_device (event, device);
1061
1062   return TRUE;
1063 }
1064
1065 static gboolean
1066 scroll_valuators_changed (GdkX11DeviceXI2 *device,
1067                           XIValuatorState *valuators,
1068                           gdouble         *dx,
1069                           gdouble         *dy)
1070 {
1071   gboolean has_scroll_valuators = FALSE;
1072   GdkScrollDirection direction;
1073   guint n_axes, i, n_val;
1074   gdouble *vals;
1075
1076   n_axes = gdk_device_get_n_axes (GDK_DEVICE (device));
1077   vals = valuators->values;
1078   *dx = *dy = 0;
1079   n_val = 0;
1080
1081   for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
1082     {
1083       gdouble delta;
1084
1085       if (!XIMaskIsSet (valuators->mask, i))
1086         continue;
1087
1088       if (_gdk_x11_device_xi2_get_scroll_delta (device, i, vals[n_val],
1089                                                 &direction, &delta))
1090         {
1091           has_scroll_valuators = TRUE;
1092
1093           if (direction == GDK_SCROLL_UP ||
1094               direction == GDK_SCROLL_DOWN)
1095             *dy = delta;
1096           else
1097             *dx = delta;
1098         }
1099
1100       n_val++;
1101     }
1102
1103   return has_scroll_valuators;
1104 }
1105
1106 static gboolean
1107 gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
1108                                             GdkDisplay         *display,
1109                                             GdkEvent           *event,
1110                                             XEvent             *xevent)
1111 {
1112   GdkX11DeviceManagerXI2 *device_manager;
1113   XGenericEventCookie *cookie;
1114   gboolean return_val = TRUE;
1115   GdkWindow *window;
1116   XIEvent *ev;
1117
1118   device_manager = (GdkX11DeviceManagerXI2 *) translator;
1119   cookie = &xevent->xcookie;
1120
1121   if (xevent->type != GenericEvent)
1122     return gdk_x11_device_manager_xi2_translate_core_event (translator, display, event, xevent);
1123   else if (cookie->extension != device_manager->opcode)
1124     return FALSE;
1125
1126   ev = (XIEvent *) cookie->data;
1127
1128   if (!ev)
1129     return FALSE;
1130
1131   if (!get_event_window (translator, ev, &window))
1132     return FALSE;
1133
1134   if (window && GDK_WINDOW_DESTROYED (window))
1135     return FALSE;
1136
1137   if (ev->evtype == XI_Motion ||
1138       ev->evtype == XI_ButtonRelease)
1139     {
1140       if (_gdk_x11_moveresize_handle_event (xevent))
1141         return FALSE;
1142     }
1143
1144   switch (ev->evtype)
1145     {
1146     case XI_HierarchyChanged:
1147       handle_hierarchy_changed (device_manager,
1148                                 (XIHierarchyEvent *) ev);
1149       return_val = FALSE;
1150       break;
1151     case XI_DeviceChanged:
1152       handle_device_changed (device_manager,
1153                              (XIDeviceChangedEvent *) ev);
1154       return_val = FALSE;
1155       break;
1156     case XI_KeyPress:
1157     case XI_KeyRelease:
1158       {
1159         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1160         GdkKeymap *keymap = gdk_keymap_get_for_display (display);
1161         GdkModifierType consumed, state;
1162         GdkDevice *device, *source_device;
1163
1164         event->key.type = xev->evtype == XI_KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
1165
1166         event->key.window = window;
1167
1168         event->key.time = xev->time;
1169         event->key.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1170         event->key.group = xev->group.effective;
1171
1172         event->key.hardware_keycode = xev->detail;
1173         event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
1174
1175         device = g_hash_table_lookup (device_manager->id_table,
1176                                       GUINT_TO_POINTER (xev->deviceid));
1177         gdk_event_set_device (event, device);
1178
1179         source_device = g_hash_table_lookup (device_manager->id_table,
1180                                              GUINT_TO_POINTER (xev->sourceid));
1181         gdk_event_set_source_device (event, source_device);
1182
1183         event->key.keyval = GDK_KEY_VoidSymbol;
1184
1185         gdk_keymap_translate_keyboard_state (keymap,
1186                                              event->key.hardware_keycode,
1187                                              event->key.state,
1188                                              event->key.group,
1189                                              &event->key.keyval,
1190                                              NULL, NULL, &consumed);
1191
1192         state = event->key.state & ~consumed;
1193         _gdk_x11_keymap_add_virt_mods (keymap, &state);
1194         event->key.state |= state;
1195
1196         _gdk_x11_event_translate_keyboard_string (&event->key);
1197
1198         if (ev->evtype == XI_KeyPress)
1199           set_user_time (event);
1200
1201         /* FIXME: emulate autorepeat on key
1202          * release? XI2 seems attached to Xkb.
1203          */
1204       }
1205
1206       break;
1207     case XI_ButtonPress:
1208     case XI_ButtonRelease:
1209       {
1210         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1211         GdkDevice *source_device;
1212
1213         if (ev->evtype == XI_ButtonRelease &&
1214             (xev->detail >= 4 && xev->detail <= 7))
1215           return FALSE;
1216         else if (ev->evtype == XI_ButtonPress &&
1217                  (xev->detail >= 4 && xev->detail <= 7))
1218           {
1219             /* Button presses of button 4-7 are scroll events */
1220             event->scroll.type = GDK_SCROLL;
1221
1222             if (xev->detail == 4)
1223               event->scroll.direction = GDK_SCROLL_UP;
1224             else if (xev->detail == 5)
1225               event->scroll.direction = GDK_SCROLL_DOWN;
1226             else if (xev->detail == 6)
1227               event->scroll.direction = GDK_SCROLL_LEFT;
1228             else
1229               event->scroll.direction = GDK_SCROLL_RIGHT;
1230
1231             event->scroll.window = window;
1232             event->scroll.time = xev->time;
1233             event->scroll.x = (gdouble) xev->event_x;
1234             event->scroll.y = (gdouble) xev->event_y;
1235             event->scroll.x_root = (gdouble) xev->root_x;
1236             event->scroll.y_root = (gdouble) xev->root_y;
1237             event->scroll.delta_x = 0;
1238             event->scroll.delta_y = 0;
1239
1240             event->scroll.device = g_hash_table_lookup (device_manager->id_table,
1241                                                         GUINT_TO_POINTER (xev->deviceid));
1242
1243             source_device = g_hash_table_lookup (device_manager->id_table,
1244                                                  GUINT_TO_POINTER (xev->sourceid));
1245             gdk_event_set_source_device (event, source_device);
1246
1247             event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1248
1249 #ifdef XINPUT_2_2
1250             if (xev->flags & XIPointerEmulated)
1251               _gdk_event_set_pointer_emulated (event, TRUE);
1252 #endif
1253           }
1254         else
1255           {
1256             event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
1257
1258             event->button.window = window;
1259             event->button.time = xev->time;
1260             event->button.x = (gdouble) xev->event_x;
1261             event->button.y = (gdouble) xev->event_y;
1262             event->button.x_root = (gdouble) xev->root_x;
1263             event->button.y_root = (gdouble) xev->root_y;
1264
1265             event->button.device = g_hash_table_lookup (device_manager->id_table,
1266                                                         GUINT_TO_POINTER (xev->deviceid));
1267
1268             source_device = g_hash_table_lookup (device_manager->id_table,
1269                                                  GUINT_TO_POINTER (xev->sourceid));
1270             gdk_event_set_source_device (event, source_device);
1271
1272             event->button.axes = translate_axes (event->button.device,
1273                                                  event->button.x,
1274                                                  event->button.y,
1275                                                  event->button.window,
1276                                                  &xev->valuators);
1277
1278             if (gdk_device_get_mode (event->button.device) == GDK_MODE_WINDOW)
1279               {
1280                 GdkDevice *device = event->button.device;
1281
1282                 /* Update event coordinates from axes */
1283                 gdk_device_get_axis (device, event->button.axes, GDK_AXIS_X, &event->button.x);
1284                 gdk_device_get_axis (device, event->button.axes, GDK_AXIS_Y, &event->button.y);
1285               }
1286
1287             event->button.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1288
1289             event->button.button = xev->detail;
1290           }
1291
1292 #ifdef XINPUT_2_2
1293         if (xev->flags & XIPointerEmulated)
1294           _gdk_event_set_pointer_emulated (event, TRUE);
1295 #endif
1296
1297         if (return_val == FALSE)
1298           break;
1299
1300         if (!set_screen_from_root (display, event, xev->root))
1301           {
1302             return_val = FALSE;
1303             break;
1304           }
1305
1306         if (ev->evtype == XI_ButtonPress)
1307           set_user_time (event);
1308
1309         break;
1310       }
1311
1312     case XI_Motion:
1313       {
1314         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1315         GdkDevice *source_device, *device;
1316         gdouble delta_x, delta_y;
1317
1318         source_device = g_hash_table_lookup (device_manager->id_table,
1319                                              GUINT_TO_POINTER (xev->sourceid));
1320         device = g_hash_table_lookup (device_manager->id_table,
1321                                       GUINT_TO_POINTER (xev->deviceid));
1322
1323         /* When scrolling, X might send events twice here; once with both the
1324          * device and the source device set to the physical device, and once
1325          * with the device set to the master device.
1326          * Since we are only interested in the latter, and
1327          * scroll_valuators_changed() updates the valuator cache for the
1328          * source device, we need to explicitly ignore the first event in
1329          * order to get the correct delta for the second.
1330          */
1331         if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_SLAVE &&
1332             scroll_valuators_changed (GDK_X11_DEVICE_XI2 (source_device),
1333                                       &xev->valuators, &delta_x, &delta_y))
1334           {
1335             event->scroll.type = GDK_SCROLL;
1336             event->scroll.direction = GDK_SCROLL_SMOOTH;
1337
1338             GDK_NOTE(EVENTS,
1339                      g_message ("smooth scroll: %s\n\tdevice: %u\n\tsource device: %u\n\twindow %ld\n\tdeltas: %f %f",
1340 #ifdef XINPUT_2_2
1341                                 (xev->flags & XIPointerEmulated) ? "emulated" : "",
1342 #else
1343                                  "",
1344 #endif
1345                                 xev->deviceid, xev->sourceid,
1346                                 xev->event, delta_x, delta_y));
1347
1348
1349             event->scroll.window = window;
1350             event->scroll.time = xev->time;
1351             event->scroll.x = (gdouble) xev->event_x;
1352             event->scroll.y = (gdouble) xev->event_y;
1353             event->scroll.x_root = (gdouble) xev->root_x;
1354             event->scroll.y_root = (gdouble) xev->root_y;
1355             event->scroll.delta_x = delta_x;
1356             event->scroll.delta_y = delta_y;
1357
1358             event->scroll.device = device;
1359             gdk_event_set_source_device (event, source_device);
1360
1361             event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1362             break;
1363           }
1364
1365         event->motion.type = GDK_MOTION_NOTIFY;
1366         event->motion.window = window;
1367         event->motion.time = xev->time;
1368         event->motion.x = (gdouble) xev->event_x;
1369         event->motion.y = (gdouble) xev->event_y;
1370         event->motion.x_root = (gdouble) xev->root_x;
1371         event->motion.y_root = (gdouble) xev->root_y;
1372
1373         event->motion.device = device;
1374         gdk_event_set_source_device (event, source_device);
1375
1376         event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1377
1378 #ifdef XINPUT_2_2
1379         if (xev->flags & XIPointerEmulated)
1380           _gdk_event_set_pointer_emulated (event, TRUE);
1381 #endif
1382
1383         /* There doesn't seem to be motion hints in XI */
1384         event->motion.is_hint = FALSE;
1385
1386         event->motion.axes = translate_axes (event->motion.device,
1387                                              event->motion.x,
1388                                              event->motion.y,
1389                                              event->motion.window,
1390                                              &xev->valuators);
1391
1392         if (gdk_device_get_mode (event->motion.device) == GDK_MODE_WINDOW)
1393           {
1394             GdkDevice *device = event->motion.device;
1395
1396             /* Update event coordinates from axes */
1397             gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_X, &event->motion.x);
1398             gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_Y, &event->motion.y);
1399           }
1400       }
1401       break;
1402
1403 #ifdef XINPUT_2_2
1404     case XI_TouchBegin:
1405     case XI_TouchEnd:
1406       {
1407         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1408         GdkDevice *source_device;
1409
1410         GDK_NOTE(EVENTS,
1411                  g_message ("touch %s:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %d",
1412                             ev->evtype == XI_TouchBegin ? "begin" : "end",
1413                             xev->event,
1414                             xev->detail,
1415                             xev->flags & XITouchEmulatingPointer));
1416
1417         if (ev->evtype == XI_TouchBegin)
1418           event->touch.type = GDK_TOUCH_BEGIN;
1419         else if (ev->evtype == XI_TouchEnd)
1420           event->touch.type = GDK_TOUCH_END;
1421
1422         event->touch.window = window;
1423         event->touch.time = xev->time;
1424         event->touch.x = (gdouble) xev->event_x;
1425         event->touch.y = (gdouble) xev->event_y;
1426         event->touch.x_root = (gdouble) xev->root_x;
1427         event->touch.y_root = (gdouble) xev->root_y;
1428
1429         event->touch.device = g_hash_table_lookup (device_manager->id_table,
1430                                                    GUINT_TO_POINTER (xev->deviceid));
1431
1432         source_device = g_hash_table_lookup (device_manager->id_table,
1433                                              GUINT_TO_POINTER (xev->sourceid));
1434         gdk_event_set_source_device (event, source_device);
1435
1436         event->touch.axes = translate_axes (event->touch.device,
1437                                             event->touch.x,
1438                                             event->touch.y,
1439                                             event->touch.window,
1440                                             &xev->valuators);
1441
1442         if (gdk_device_get_mode (event->touch.device) == GDK_MODE_WINDOW)
1443           {
1444             GdkDevice *device = event->touch.device;
1445
1446             /* Update event coordinates from axes */
1447             gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_X, &event->touch.x);
1448             gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_Y, &event->touch.y);
1449           }
1450
1451         event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1452
1453         if (ev->evtype == XI_TouchBegin)
1454           event->touch.state |= GDK_BUTTON1_MASK;
1455
1456         event->touch.sequence = GUINT_TO_POINTER (xev->detail);
1457
1458         if (xev->flags & XITouchEmulatingPointer)
1459           {
1460             event->touch.emulating_pointer = TRUE;
1461             _gdk_event_set_pointer_emulated (event, TRUE);
1462           }
1463
1464         if (return_val == FALSE)
1465           break;
1466
1467         if (!set_screen_from_root (display, event, xev->root))
1468           {
1469             return_val = FALSE;
1470             break;
1471           }
1472
1473         if (ev->evtype == XI_TouchBegin)
1474           set_user_time (event);
1475       }
1476       break;
1477
1478     case XI_TouchUpdate:
1479       {
1480         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1481         GdkDevice *source_device;
1482
1483         GDK_NOTE(EVENTS,
1484                  g_message ("touch update:\twindow %ld\n\ttouch id: %u\n\tpointer emulating: %d",
1485                             xev->event,
1486                             xev->detail,
1487                             xev->flags & XITouchEmulatingPointer));
1488
1489         event->touch.window = window;
1490         event->touch.sequence = GUINT_TO_POINTER (xev->detail);
1491         event->touch.type = GDK_TOUCH_UPDATE;
1492         event->touch.time = xev->time;
1493         event->touch.x = (gdouble) xev->event_x;
1494         event->touch.y = (gdouble) xev->event_y;
1495         event->touch.x_root = (gdouble) xev->root_x;
1496         event->touch.y_root = (gdouble) xev->root_y;
1497
1498         event->touch.device = g_hash_table_lookup (device_manager->id_table,
1499                                                    GINT_TO_POINTER (xev->deviceid));
1500
1501         source_device = g_hash_table_lookup (device_manager->id_table,
1502                                              GUINT_TO_POINTER (xev->sourceid));
1503         gdk_event_set_source_device (event, source_device);
1504
1505         event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1506
1507         event->touch.state |= GDK_BUTTON1_MASK;
1508
1509         if (xev->flags & XITouchEmulatingPointer)
1510           {
1511             event->touch.emulating_pointer = TRUE;
1512             _gdk_event_set_pointer_emulated (event, TRUE);
1513           }
1514
1515         event->touch.axes = translate_axes (event->touch.device,
1516                                             event->touch.x,
1517                                             event->touch.y,
1518                                             event->touch.window,
1519                                             &xev->valuators);
1520
1521         if (gdk_device_get_mode (event->touch.device) == GDK_MODE_WINDOW)
1522           {
1523             GdkDevice *device = event->touch.device;
1524
1525             /* Update event coordinates from axes */
1526             gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_X, &event->touch.x);
1527             gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_Y, &event->touch.y);
1528           }
1529       }
1530       break;
1531 #endif  /* XINPUT_2_2 */
1532
1533     case XI_Enter:
1534     case XI_Leave:
1535       {
1536         XIEnterEvent *xev = (XIEnterEvent *) ev;
1537         GdkDevice *device, *source_device;
1538
1539         event->crossing.type = (ev->evtype == XI_Enter) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
1540
1541         event->crossing.x = (gdouble) xev->event_x;
1542         event->crossing.y = (gdouble) xev->event_y;
1543         event->crossing.x_root = (gdouble) xev->root_x;
1544         event->crossing.y_root = (gdouble) xev->root_y;
1545         event->crossing.time = xev->time;
1546         event->crossing.focus = xev->focus;
1547
1548         event->crossing.window = window;
1549         event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xev->child);
1550
1551         device = g_hash_table_lookup (device_manager->id_table,
1552                                       GINT_TO_POINTER (xev->deviceid));
1553         gdk_event_set_device (event, device);
1554
1555         source_device = g_hash_table_lookup (device_manager->id_table,
1556                                              GUINT_TO_POINTER (xev->sourceid));
1557         gdk_event_set_source_device (event, source_device);
1558         _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
1559
1560         event->crossing.mode = translate_crossing_mode (xev->mode);
1561         event->crossing.detail = translate_notify_type (xev->detail);
1562         event->crossing.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
1563       }
1564       break;
1565     case XI_FocusIn:
1566     case XI_FocusOut:
1567       {
1568         if (window)
1569           {
1570             XIEnterEvent *xev = (XIEnterEvent *) ev;
1571             GdkDevice *device, *source_device;
1572
1573             device = g_hash_table_lookup (device_manager->id_table,
1574                                           GINT_TO_POINTER (xev->deviceid));
1575
1576             source_device = g_hash_table_lookup (device_manager->id_table,
1577                                                  GUINT_TO_POINTER (xev->sourceid));
1578
1579             _gdk_device_manager_core_handle_focus (window,
1580                                                    xev->event,
1581                                                    device,
1582                                                    source_device,
1583                                                    (ev->evtype == XI_FocusIn) ? TRUE : FALSE,
1584                                                    xev->detail,
1585                                                    xev->mode);
1586           }
1587
1588         return_val = FALSE;
1589       }
1590       break;
1591     default:
1592       return_val = FALSE;
1593       break;
1594     }
1595
1596   event->any.send_event = cookie->send_event;
1597
1598   if (return_val)
1599     {
1600       if (event->any.window)
1601         g_object_ref (event->any.window);
1602
1603       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1604            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1605           (event->crossing.subwindow != NULL))
1606         g_object_ref (event->crossing.subwindow);
1607     }
1608   else
1609     {
1610       /* Mark this event as having no resources to be freed */
1611       event->any.window = NULL;
1612       event->any.type = GDK_NOTHING;
1613     }
1614
1615   return return_val;
1616 }
1617
1618 static GdkEventMask
1619 gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
1620 {
1621   return (GDK_KEY_PRESS_MASK |
1622           GDK_KEY_RELEASE_MASK |
1623           GDK_BUTTON_PRESS_MASK |
1624           GDK_BUTTON_RELEASE_MASK |
1625           GDK_SCROLL_MASK |
1626           GDK_ENTER_NOTIFY_MASK |
1627           GDK_LEAVE_NOTIFY_MASK |
1628           GDK_POINTER_MOTION_MASK |
1629           GDK_POINTER_MOTION_HINT_MASK |
1630           GDK_BUTTON1_MOTION_MASK |
1631           GDK_BUTTON2_MOTION_MASK |
1632           GDK_BUTTON3_MOTION_MASK |
1633           GDK_BUTTON_MOTION_MASK |
1634           GDK_FOCUS_CHANGE_MASK |
1635           GDK_TOUCH_MASK);
1636 }
1637
1638 static void
1639 gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
1640                                                  Window              window,
1641                                                  GdkEventMask        evmask)
1642 {
1643   GdkDeviceManager *device_manager;
1644   XIEventMask event_mask;
1645
1646   device_manager = GDK_DEVICE_MANAGER (translator);
1647
1648   event_mask.deviceid = XIAllMasterDevices;
1649   event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (GDK_X11_DEVICE_MANAGER_XI2 (device_manager),
1650                                                               evmask,
1651                                                               &event_mask.mask_len);
1652
1653   _gdk_x11_device_manager_xi2_select_events (device_manager, window, &event_mask);
1654   g_free (event_mask.mask);
1655 }
1656
1657 static GdkWindow *
1658 gdk_x11_device_manager_xi2_get_window (GdkEventTranslator *translator,
1659                                        XEvent             *xevent)
1660 {
1661   GdkX11DeviceManagerXI2 *device_manager;
1662   XIEvent *ev;
1663   GdkWindow *window = NULL;
1664
1665   device_manager = (GdkX11DeviceManagerXI2 *) translator;
1666
1667   if (xevent->type != GenericEvent ||
1668       xevent->xcookie.extension != device_manager->opcode)
1669     return NULL;
1670
1671   ev = (XIEvent *) xevent->xcookie.data;
1672
1673   get_event_window (translator, ev, &window);
1674   return window;
1675 }
1676
1677 GdkDevice *
1678 _gdk_x11_device_manager_xi2_lookup (GdkX11DeviceManagerXI2 *device_manager_xi2,
1679                                     gint                    device_id)
1680 {
1681   return g_hash_table_lookup (device_manager_xi2->id_table,
1682                               GINT_TO_POINTER (device_id));
1683 }