]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkdevicemanager-xi2.c
Fix a warning
[~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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gdkx11devicemanager-xi2.h"
23 #include "gdkx11device-xi2.h"
24
25 #include "gdkdevicemanagerprivate.h"
26 #include "gdkdeviceprivate.h"
27 #include "gdkdisplayprivate.h"
28 #include "gdkeventtranslator.h"
29 #include "gdkprivate-x11.h"
30 #include "gdkintl.h"
31 #include "gdkkeysyms.h"
32
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/extensions/XInput2.h>
36
37 #include <string.h>
38
39 struct _GdkX11DeviceManagerXI2
40 {
41   GdkDeviceManager parent_object;
42
43   GHashTable *id_table;
44
45   GList *devices;
46
47   gint opcode;
48 };
49
50 struct _GdkX11DeviceManagerXI2Class
51 {
52   GdkDeviceManagerClass parent_class;
53 };
54
55 #define HAS_FOCUS(toplevel) ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
56
57
58 static void    gdk_x11_device_manager_xi2_constructed  (GObject      *object);
59 static void    gdk_x11_device_manager_xi2_dispose      (GObject      *object);
60 static void    gdk_x11_device_manager_xi2_set_property (GObject      *object,
61                                                         guint         prop_id,
62                                                         const GValue *value,
63                                                         GParamSpec   *pspec);
64 static void    gdk_x11_device_manager_xi2_get_property (GObject      *object,
65                                                         guint         prop_id,
66                                                         GValue       *value,
67                                                         GParamSpec   *pspec);
68
69 static GList * gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
70                                                         GdkDeviceType     type);
71 static GdkDevice * gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager);
72
73 static void     gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface);
74
75 static gboolean gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
76                                                             GdkDisplay         *display,
77                                                             GdkEvent           *event,
78                                                             XEvent             *xevent);
79 static GdkEventMask gdk_x11_device_manager_xi2_get_handled_events   (GdkEventTranslator *translator);
80 static void         gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
81                                                                      Window              window,
82                                                                      GdkEventMask        event_mask);
83
84
85 G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI2, gdk_x11_device_manager_xi2, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
86                          G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
87                                                 gdk_x11_device_manager_xi2_event_translator_init))
88
89
90 enum {
91   PROP_0,
92   PROP_OPCODE
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 }
117
118 static void
119 gdk_x11_device_manager_xi2_init (GdkX11DeviceManagerXI2 *device_manager)
120 {
121   device_manager->id_table = g_hash_table_new_full (g_direct_hash,
122                                                     g_direct_equal,
123                                                     NULL,
124                                                     (GDestroyNotify) g_object_unref);
125 }
126
127 static void
128 _gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
129                                            Window            xwindow,
130                                            XIEventMask      *event_mask)
131 {
132   GdkDisplay *display;
133   Display *xdisplay;
134
135   display = gdk_device_manager_get_display (device_manager);
136   xdisplay = GDK_DISPLAY_XDISPLAY (display);
137
138   XISelectEvents (xdisplay, xwindow, event_mask, 1);
139 }
140
141 static void
142 translate_valuator_class (GdkDisplay          *display,
143                           GdkDevice           *device,
144                           XIValuatorClassInfo *info,
145                           gint                 n_valuator)
146 {
147   static gboolean initialized = FALSE;
148   static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
149   GdkAxisUse use = GDK_AXIS_IGNORE;
150   GdkAtom label;
151   gint i;
152
153   if (!initialized)
154     {
155       label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
156       label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");
157       label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Pressure");
158       label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
159       label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
160       label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
161       initialized = TRUE;
162     }
163
164   for (i = GDK_AXIS_IGNORE; i <= GDK_AXIS_LAST; i++)
165     {
166       if (label_atoms[i] == info->label)
167         {
168           use = i;
169           break;
170         }
171     }
172
173   if (info->label != None)
174     label = gdk_x11_xatom_to_atom_for_display (display, info->label);
175   else
176     label = GDK_NONE;
177
178   _gdk_device_add_axis (device,
179                         label,
180                         use,
181                         info->min,
182                         info->max,
183                         info->resolution);
184 }
185
186 static void
187 translate_device_classes (GdkDisplay      *display,
188                           GdkDevice       *device,
189                           XIAnyClassInfo **classes,
190                           guint            n_classes)
191 {
192   gint i, n_valuator = 0;
193
194   g_object_freeze_notify (G_OBJECT (device));
195
196   for (i = 0; i < n_classes; i++)
197     {
198       XIAnyClassInfo *class_info = classes[i];
199
200       switch (class_info->type)
201         {
202         case XIKeyClass:
203           {
204             XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
205             gint i;
206
207             _gdk_device_set_keys (device, key_info->num_keycodes);
208
209             for (i = 0; i < key_info->num_keycodes; i++)
210               gdk_device_set_key (device, i, key_info->keycodes[i], 0);
211           }
212           break;
213         case XIValuatorClass:
214           translate_valuator_class (display, device,
215                                     (XIValuatorClassInfo *) class_info,
216                                     n_valuator);
217           n_valuator++;
218           break;
219         default:
220           /* Ignore */
221           break;
222         }
223     }
224
225   g_object_thaw_notify (G_OBJECT (device));
226 }
227
228 static GdkDevice *
229 create_device (GdkDeviceManager *device_manager,
230                GdkDisplay       *display,
231                XIDeviceInfo     *dev)
232 {
233   GdkInputSource input_source;
234   GdkDeviceType type;
235   GdkDevice *device;
236   GdkInputMode mode;
237
238   if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
239     input_source = GDK_SOURCE_KEYBOARD;
240   else
241     {
242       gchar *tmp_name;
243
244       tmp_name = g_ascii_strdown (dev->name, -1);
245
246       if (strstr (tmp_name, "eraser"))
247         input_source = GDK_SOURCE_ERASER;
248       else if (strstr (tmp_name, "cursor"))
249         input_source = GDK_SOURCE_CURSOR;
250       else if (strstr (tmp_name, "wacom") ||
251                strstr (tmp_name, "pen"))
252         input_source = GDK_SOURCE_PEN;
253       else
254         input_source = GDK_SOURCE_MOUSE;
255
256       g_free (tmp_name);
257     }
258
259   switch (dev->use)
260     {
261     case XIMasterKeyboard:
262     case XIMasterPointer:
263       type = GDK_DEVICE_TYPE_MASTER;
264       mode = GDK_MODE_SCREEN;
265       break;
266     case XISlaveKeyboard:
267     case XISlavePointer:
268       type = GDK_DEVICE_TYPE_SLAVE;
269       mode = GDK_MODE_DISABLED;
270       break;
271     case XIFloatingSlave:
272     default:
273       type = GDK_DEVICE_TYPE_FLOATING;
274       mode = GDK_MODE_DISABLED;
275       break;
276     }
277
278   device = g_object_new (GDK_TYPE_X11_DEVICE_XI2,
279                          "name", dev->name,
280                          "type", type,
281                          "input-source", input_source,
282                          "input-mode", mode,
283                          "has-cursor", (dev->use == XIMasterPointer),
284                          "display", display,
285                          "device-manager", device_manager,
286                          "device-id", dev->deviceid,
287                          NULL);
288
289   translate_device_classes (display, device, dev->classes, dev->num_classes);
290
291   return device;
292 }
293
294 static GdkDevice *
295 add_device (GdkX11DeviceManagerXI2 *device_manager,
296             XIDeviceInfo           *dev,
297             gboolean                emit_signal)
298 {
299   GdkDisplay *display;
300   GdkDevice *device;
301
302   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
303   device = create_device (GDK_DEVICE_MANAGER (device_manager), display, dev);
304
305   g_hash_table_replace (device_manager->id_table,
306                         GINT_TO_POINTER (dev->deviceid),
307                         g_object_ref (device));
308
309   device_manager->devices = g_list_append (device_manager->devices, device);
310
311   if (emit_signal)
312     {
313       if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
314         {
315           GdkDevice *master;
316
317           /* The device manager is already constructed, then
318            * keep the hierarchy coherent for the added device.
319            */
320           master = g_hash_table_lookup (device_manager->id_table,
321                                         GINT_TO_POINTER (dev->attachment));
322
323           _gdk_device_set_associated_device (device, master);
324           _gdk_device_add_slave (master, device);
325         }
326
327       g_signal_emit_by_name (device_manager, "device-added", device);
328     }
329
330   return device;
331 }
332
333 static void
334 remove_device (GdkX11DeviceManagerXI2 *device_manager,
335                gint                    device_id)
336 {
337   GdkDevice *device;
338
339   device = g_hash_table_lookup (device_manager->id_table,
340                                 GINT_TO_POINTER (device_id));
341
342   if (device)
343     {
344       device_manager->devices = g_list_remove (device_manager->devices, device);
345
346       g_signal_emit_by_name (device_manager, "device-removed", device);
347
348       g_object_run_dispose (G_OBJECT (device));
349
350       g_hash_table_remove (device_manager->id_table,
351                            GINT_TO_POINTER (device_id));
352     }
353 }
354
355 static void
356 relate_masters (gpointer key,
357                 gpointer value,
358                 gpointer user_data)
359 {
360   GdkX11DeviceManagerXI2 *device_manager;
361   GdkDevice *device, *relative;
362
363   device_manager = user_data;
364   device = g_hash_table_lookup (device_manager->id_table, key);
365   relative = g_hash_table_lookup (device_manager->id_table, value);
366
367   _gdk_device_set_associated_device (device, relative);
368   _gdk_device_set_associated_device (relative, device);
369 }
370
371 static void
372 relate_slaves (gpointer key,
373                gpointer value,
374                gpointer user_data)
375 {
376   GdkX11DeviceManagerXI2 *device_manager;
377   GdkDevice *slave, *master;
378
379   device_manager = user_data;
380   slave = g_hash_table_lookup (device_manager->id_table, key);
381   master = g_hash_table_lookup (device_manager->id_table, value);
382
383   _gdk_device_set_associated_device (slave, master);
384   _gdk_device_add_slave (master, slave);
385 }
386
387 static void
388 gdk_x11_device_manager_xi2_constructed (GObject *object)
389 {
390   GdkX11DeviceManagerXI2 *device_manager;
391   GdkDisplay *display;
392   GdkScreen *screen;
393   GHashTable *masters, *slaves;
394   Display *xdisplay;
395   XIDeviceInfo *info, *dev;
396   int ndevices, i;
397   XIEventMask event_mask;
398   unsigned char mask[2] = { 0 };
399
400   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
401   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
402   xdisplay = GDK_DISPLAY_XDISPLAY (display);
403
404   masters = g_hash_table_new (NULL, NULL);
405   slaves = g_hash_table_new (NULL, NULL);
406
407   info = XIQueryDevice (xdisplay, XIAllDevices, &ndevices);
408
409   /* Initialize devices list */
410   for (i = 0; i < ndevices; i++)
411     {
412       dev = &info[i];
413       add_device (device_manager, dev, FALSE);
414
415       if (dev->use == XIMasterPointer ||
416           dev->use == XIMasterKeyboard)
417         {
418           g_hash_table_insert (masters,
419                                GINT_TO_POINTER (dev->deviceid),
420                                GINT_TO_POINTER (dev->attachment));
421         }
422       else if (dev->use == XISlavePointer ||
423                dev->use == XISlaveKeyboard)
424         {
425           g_hash_table_insert (slaves,
426                                GINT_TO_POINTER (dev->deviceid),
427                                GINT_TO_POINTER (dev->attachment));
428         }
429     }
430
431   XIFreeDeviceInfo (info);
432
433   /* Stablish relationships between devices */
434   g_hash_table_foreach (masters, relate_masters, object);
435   g_hash_table_destroy (masters);
436
437   g_hash_table_foreach (slaves, relate_slaves, object);
438   g_hash_table_destroy (slaves);
439
440   /* Connect to hierarchy change events */
441   screen = gdk_display_get_default_screen (display);
442   XISetMask (mask, XI_HierarchyChanged);
443   XISetMask (mask, XI_DeviceChanged);
444
445   event_mask.deviceid = XIAllDevices;
446   event_mask.mask_len = sizeof (mask);
447   event_mask.mask = mask;
448
449   _gdk_x11_device_manager_xi2_select_events (GDK_DEVICE_MANAGER (object),
450                                              GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
451                                              &event_mask);
452 }
453
454 static void
455 gdk_x11_device_manager_xi2_dispose (GObject *object)
456 {
457   GdkX11DeviceManagerXI2 *device_manager;
458
459   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
460
461   g_list_free_full (device_manager->devices, g_object_unref);
462   device_manager->devices = NULL;
463
464   if (device_manager->id_table)
465     {
466       g_hash_table_destroy (device_manager->id_table);
467       device_manager->id_table = NULL;
468     }
469
470   G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->dispose (object);
471 }
472
473 static GList *
474 gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
475                                          GdkDeviceType     type)
476 {
477   GdkX11DeviceManagerXI2 *device_manager_xi2;
478   GList *cur, *list = NULL;
479
480   device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (device_manager);
481
482   for (cur = device_manager_xi2->devices; cur; cur = cur->next)
483     {
484       GdkDevice *dev = cur->data;
485
486       if (type == gdk_device_get_device_type (dev))
487         list = g_list_prepend (list, dev);
488     }
489
490   return list;
491 }
492
493 static GdkDevice *
494 gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager)
495 {
496   GdkX11DeviceManagerXI2 *device_manager_xi2;
497   GdkDisplay *display;
498   int device_id;
499
500   device_manager_xi2 = (GdkX11DeviceManagerXI2 *) device_manager;
501   display = gdk_device_manager_get_display (device_manager);
502
503   XIGetClientPointer (GDK_DISPLAY_XDISPLAY (display),
504                       None, &device_id);
505
506   return g_hash_table_lookup (device_manager_xi2->id_table,
507                               GINT_TO_POINTER (device_id));
508 }
509
510 static void
511 gdk_x11_device_manager_xi2_set_property (GObject      *object,
512                                          guint         prop_id,
513                                          const GValue *value,
514                                          GParamSpec   *pspec)
515 {
516   GdkX11DeviceManagerXI2 *device_manager;
517
518   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
519
520   switch (prop_id)
521     {
522     case PROP_OPCODE:
523       device_manager->opcode = g_value_get_int (value);
524       break;
525     default:
526       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527       break;
528     }
529 }
530
531 static void
532 gdk_x11_device_manager_xi2_get_property (GObject    *object,
533                                          guint       prop_id,
534                                          GValue     *value,
535                                          GParamSpec *pspec)
536 {
537   GdkX11DeviceManagerXI2 *device_manager;
538
539   device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
540
541   switch (prop_id)
542     {
543     case PROP_OPCODE:
544       g_value_set_int (value, device_manager->opcode);
545       break;
546     default:
547       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
548       break;
549     }
550 }
551
552 static void
553 gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface)
554 {
555   iface->translate_event = gdk_x11_device_manager_xi2_translate_event;
556   iface->get_handled_events = gdk_x11_device_manager_xi2_get_handled_events;
557   iface->select_window_events = gdk_x11_device_manager_xi2_select_window_events;
558 }
559
560 static void
561 handle_hierarchy_changed (GdkX11DeviceManagerXI2 *device_manager,
562                           XIHierarchyEvent       *ev)
563 {
564   GdkDisplay *display;
565   Display *xdisplay;
566   XIDeviceInfo *info;
567   int ndevices;
568   gint i;
569
570   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
571   xdisplay = GDK_DISPLAY_XDISPLAY (display);
572
573   for (i = 0; i < ev->num_info; i++)
574     {
575       if (ev->info[i].flags & XIDeviceEnabled)
576         {
577           info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
578           add_device (device_manager, &info[0], TRUE);
579           XIFreeDeviceInfo (info);
580         }
581       else if (ev->info[i].flags & XIDeviceDisabled)
582         remove_device (device_manager, ev->info[i].deviceid);
583       else if (ev->info[i].flags & XISlaveAttached ||
584                ev->info[i].flags & XISlaveDetached)
585         {
586           GdkDevice *master, *slave;
587
588           slave = g_hash_table_lookup (device_manager->id_table,
589                                        GINT_TO_POINTER (ev->info[i].deviceid));
590
591           /* Remove old master info */
592           master = gdk_device_get_associated_device (slave);
593
594           if (master)
595             {
596               _gdk_device_remove_slave (master, slave);
597               _gdk_device_set_associated_device (slave, NULL);
598
599               g_signal_emit_by_name (device_manager, "device-changed", master);
600             }
601
602           /* Add new master if it's an attachment event */
603           if (ev->info[i].flags & XISlaveAttached)
604             {
605               info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
606
607               master = g_hash_table_lookup (device_manager->id_table,
608                                             GINT_TO_POINTER (info->attachment));
609
610               _gdk_device_set_associated_device (slave, master);
611               _gdk_device_add_slave (master, slave);
612
613               g_signal_emit_by_name (device_manager, "device-changed", master);
614             }
615
616           g_signal_emit_by_name (device_manager, "device-changed", slave);
617         }
618     }
619 }
620
621 static void
622 handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
623                        XIDeviceChangedEvent   *ev)
624 {
625   GdkDisplay *display;
626   GdkDevice *device;
627
628   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
629   device = g_hash_table_lookup (device_manager->id_table,
630                                 GUINT_TO_POINTER (ev->deviceid));
631
632   _gdk_device_reset_axes (device);
633   translate_device_classes (display, device, ev->classes, ev->num_classes);
634
635   g_signal_emit_by_name (G_OBJECT (device), "changed");
636 }
637
638 static GdkCrossingMode
639 translate_crossing_mode (gint mode)
640 {
641   switch (mode)
642     {
643     case NotifyNormal:
644       return GDK_CROSSING_NORMAL;
645     case NotifyGrab:
646       return GDK_CROSSING_GRAB;
647     case NotifyUngrab:
648       return GDK_CROSSING_UNGRAB;
649     default:
650       g_assert_not_reached ();
651     }
652 }
653
654 static GdkNotifyType
655 translate_notify_type (gint detail)
656 {
657   switch (detail)
658     {
659     case NotifyInferior:
660       return GDK_NOTIFY_INFERIOR;
661     case NotifyAncestor:
662       return GDK_NOTIFY_ANCESTOR;
663     case NotifyVirtual:
664       return GDK_NOTIFY_VIRTUAL;
665     case NotifyNonlinear:
666       return GDK_NOTIFY_NONLINEAR;
667     case NotifyNonlinearVirtual:
668       return GDK_NOTIFY_NONLINEAR_VIRTUAL;
669     default:
670       g_assert_not_reached ();
671     }
672 }
673
674 static gboolean
675 set_screen_from_root (GdkDisplay *display,
676                       GdkEvent   *event,
677                       Window      xrootwin)
678 {
679   GdkScreen *screen;
680
681   screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
682
683   if (screen)
684     {
685       gdk_event_set_screen (event, screen);
686
687       return TRUE;
688     }
689
690   return FALSE;
691 }
692
693 static void
694 set_user_time (GdkEvent *event)
695 {
696   GdkWindow *window;
697   guint32 time;
698
699   window = gdk_window_get_toplevel (event->any.window);
700   g_return_if_fail (GDK_IS_WINDOW (window));
701
702   time = gdk_event_get_time (event);
703
704   /* If an event doesn't have a valid timestamp, we shouldn't use it
705    * to update the latest user interaction time.
706    */
707   if (time != GDK_CURRENT_TIME)
708     gdk_x11_window_set_user_time (window, time);
709 }
710
711 static void
712 translate_keyboard_string (GdkEventKey *event)
713 {
714   gunichar c = 0;
715   gchar buf[7];
716
717   /* Fill in event->string crudely, since various programs
718    * depend on it.
719    */
720   event->string = NULL;
721
722   if (event->keyval != GDK_KEY_VoidSymbol)
723     c = gdk_keyval_to_unicode (event->keyval);
724
725   if (c)
726     {
727       gsize bytes_written;
728       gint len;
729
730       /* Apply the control key - Taken from Xlib
731        */
732       if (event->state & GDK_CONTROL_MASK)
733         {
734           if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
735           else if (c == '2')
736             {
737               event->string = g_memdup ("\0\0", 2);
738               event->length = 1;
739               buf[0] = '\0';
740               return;
741             }
742           else if (c >= '3' && c <= '7') c -= ('3' - '\033');
743           else if (c == '8') c = '\177';
744           else if (c == '/') c = '_' & 0x1F;
745         }
746
747       len = g_unichar_to_utf8 (c, buf);
748       buf[len] = '\0';
749
750       event->string = g_locale_from_utf8 (buf, len,
751                                           NULL, &bytes_written,
752                                           NULL);
753       if (event->string)
754         event->length = bytes_written;
755     }
756   else if (event->keyval == GDK_KEY_Escape)
757     {
758       event->length = 1;
759       event->string = g_strdup ("\033");
760     }
761   else if (event->keyval == GDK_KEY_Return ||
762           event->keyval == GDK_KEY_KP_Enter)
763     {
764       event->length = 1;
765       event->string = g_strdup ("\r");
766     }
767
768   if (!event->string)
769     {
770       event->length = 0;
771       event->string = g_strdup ("");
772     }
773 }
774
775 static void
776 generate_focus_event (GdkWindow *window,
777                       GdkDevice *device,
778                       GdkDevice *source_device,
779                       gboolean   in)
780 {
781   GdkEvent *event;
782
783   event = gdk_event_new (GDK_FOCUS_CHANGE);
784   event->focus_change.window = g_object_ref (window);
785   event->focus_change.send_event = FALSE;
786   event->focus_change.in = in;
787   gdk_event_set_device (event, device);
788   gdk_event_set_source_device (event, source_device);
789
790   gdk_event_put (event);
791   gdk_event_free (event);
792 }
793
794 static void
795 handle_focus_change (GdkWindow *window,
796                      GdkDevice *device,
797                      GdkDevice *source_device,
798                      gint       detail,
799                      gint       mode,
800                      gboolean   in)
801 {
802   GdkToplevelX11 *toplevel;
803   gboolean had_focus;
804
805   toplevel = _gdk_x11_window_get_toplevel (window);
806
807   if (!toplevel)
808     return;
809
810   had_focus = HAS_FOCUS (toplevel);
811
812   switch (detail)
813     {
814     case NotifyAncestor:
815     case NotifyVirtual:
816       /* When the focus moves from an ancestor of the window to
817        * the window or a descendent of the window, *and* the
818        * pointer is inside the window, then we were previously
819        * receiving keystroke events in the has_pointer_focus
820        * case and are now receiving them in the
821        * has_focus_window case.
822        */
823       if (toplevel->has_pointer &&
824           mode != NotifyGrab &&
825           mode != NotifyUngrab)
826         toplevel->has_pointer_focus = (in) ? FALSE : TRUE;
827
828       /* fall through */
829     case NotifyNonlinear:
830     case NotifyNonlinearVirtual:
831       if (mode != NotifyGrab &&
832           mode != NotifyUngrab)
833         toplevel->has_focus_window = (in) ? TRUE : FALSE;
834       /* We pretend that the focus moves to the grab
835        * window, so we pay attention to NotifyGrab
836        * NotifyUngrab, and ignore NotifyWhileGrabbed
837        */
838       if (mode != NotifyWhileGrabbed)
839         toplevel->has_focus = (in) ? TRUE : FALSE;
840       break;
841     case NotifyPointer:
842       /* The X server sends NotifyPointer/NotifyGrab,
843        * but the pointer focus is ignored while a
844        * grab is in effect
845        */
846       if (mode != NotifyGrab &&
847           mode != NotifyUngrab)
848         toplevel->has_pointer_focus = (in) ? TRUE :FALSE;
849       break;
850     case NotifyInferior:
851     case NotifyPointerRoot:
852     case NotifyDetailNone:
853       break;
854     }
855
856   if (HAS_FOCUS (toplevel) != had_focus)
857     generate_focus_event (window, device, source_device, (in) ? TRUE : FALSE);
858 }
859
860 static gdouble *
861 translate_axes (GdkDevice       *device,
862                 gdouble          x,
863                 gdouble          y,
864                 GdkWindow       *window,
865                 XIValuatorState *valuators)
866 {
867   guint n_axes, i;
868   gdouble *axes;
869   gdouble *vals;
870
871   g_object_get (device, "n-axes", &n_axes, NULL);
872
873   axes = g_new0 (gdouble, n_axes);
874   vals = valuators->values;
875
876   for (i = 0; i < valuators->mask_len * 8; i++)
877     {
878       GdkAxisUse use;
879       gdouble val;
880
881       if (!XIMaskIsSet (valuators->mask, i))
882         continue;
883
884       use = _gdk_device_get_axis_use (device, i);
885       val = *vals++;
886
887       switch (use)
888         {
889         case GDK_AXIS_X:
890         case GDK_AXIS_Y:
891           if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
892             _gdk_device_translate_window_coord (device, window, i, val, &axes[i]);
893           else
894             {
895               if (use == GDK_AXIS_X)
896                 axes[i] = x;
897               else
898                 axes[i] = y;
899             }
900           break;
901         default:
902           _gdk_device_translate_axis (device, i, val, &axes[i]);
903           break;
904         }
905     }
906
907   return axes;
908 }
909
910 static gboolean
911 is_parent_of (GdkWindow *parent,
912               GdkWindow *child)
913 {
914   GdkWindow *w;
915
916   w = child;
917   while (w != NULL)
918     {
919       if (w == parent)
920         return TRUE;
921
922       w = gdk_window_get_parent (w);
923     }
924
925   return FALSE;
926 }
927
928 static GdkWindow *
929 get_event_window (GdkEventTranslator *translator,
930                   XIEvent            *ev)
931 {
932   GdkDisplay *display;
933   GdkWindow *window = NULL;
934
935   display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (translator));
936
937   switch (ev->evtype)
938     {
939     case XI_KeyPress:
940     case XI_KeyRelease:
941     case XI_ButtonPress:
942     case XI_ButtonRelease:
943     case XI_Motion:
944       {
945         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
946
947         window = gdk_x11_window_lookup_for_display (display, xev->event);
948
949         /* Apply keyboard grabs to non-native windows */
950         if (ev->evtype == XI_KeyPress || ev->evtype == XI_KeyRelease)
951           {
952             GdkDeviceGrabInfo *info;
953             GdkDevice *device;
954             gulong serial;
955
956             device = g_hash_table_lookup (GDK_X11_DEVICE_MANAGER_XI2 (translator)->id_table,
957                                           GUINT_TO_POINTER (((XIDeviceEvent *) ev)->deviceid));
958
959             serial = _gdk_display_get_next_serial (display);
960             info = _gdk_display_has_device_grab (display, device, serial);
961
962             if (info &&
963                 (!is_parent_of (info->window, window) ||
964                  !info->owner_events))
965               {
966                 /* Report key event against grab window */
967                 window = info->window;
968               }
969           }
970       }
971       break;
972     case XI_Enter:
973     case XI_Leave:
974     case XI_FocusIn:
975     case XI_FocusOut:
976       {
977         XIEnterEvent *xev = (XIEnterEvent *) ev;
978
979         window = gdk_x11_window_lookup_for_display (display, xev->event);
980       }
981       break;
982     }
983
984   return window;
985 }
986
987 static gboolean
988 gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
989                                             GdkDisplay         *display,
990                                             GdkEvent           *event,
991                                             XEvent             *xevent)
992 {
993   GdkX11DeviceManagerXI2 *device_manager;
994   GdkEventTranslatorIface *parent_iface;
995   XGenericEventCookie *cookie;
996   gboolean return_val = TRUE;
997   GdkWindow *window;
998   XIEvent *ev;
999   Display *dpy;
1000
1001   dpy = GDK_DISPLAY_XDISPLAY (display);
1002   device_manager = (GdkX11DeviceManagerXI2 *) translator;
1003   cookie = &xevent->xcookie;
1004
1005   parent_iface = g_type_interface_peek_parent (GDK_EVENT_TRANSLATOR_GET_IFACE (translator));
1006
1007   /* The X input methods (when triggered via XFilterEvent) generate
1008    * a core key press event with keycode 0 to signal the end of a
1009    * key sequence. We use the core translate_event implementation
1010    * to translate this event.
1011    *
1012    * This is just a bandaid fix to keep xim working with a single
1013    * keyboard until XFilterEvent learns about XI2.
1014    */
1015   if (xevent->type == KeyPress && xevent->xkey.keycode == 0 &&
1016       parent_iface->translate_event (translator, display, event, xevent))
1017     {
1018       GdkDevice *device;
1019
1020       /* The core device manager sets a core device on the event.
1021        * We need to override that with an XI2 device, since we are
1022        * using XI2.
1023        */
1024       device = gdk_x11_device_manager_xi2_get_client_pointer ((GdkDeviceManager *)device_manager);
1025       gdk_event_set_device (event, gdk_device_get_associated_device (device));
1026
1027       return TRUE;
1028     }
1029
1030   if (!XGetEventData (dpy, cookie))
1031     return FALSE;
1032
1033   if (cookie->type != GenericEvent ||
1034       cookie->extension != device_manager->opcode)
1035     {
1036       XFreeEventData (dpy, cookie);
1037       return FALSE;
1038     }
1039
1040   ev = (XIEvent *) cookie->data;
1041
1042   window = get_event_window (translator, ev);
1043
1044   if (window && GDK_WINDOW_DESTROYED (window))
1045     {
1046       XFreeEventData (dpy, cookie);
1047       return FALSE;
1048     }
1049
1050   if (ev->evtype == XI_Motion ||
1051       ev->evtype == XI_ButtonRelease)
1052     {
1053       if (_gdk_x11_moveresize_handle_event (xevent))
1054         {
1055           XFreeEventData (dpy, cookie);
1056           return FALSE;
1057         }
1058     }
1059
1060   switch (ev->evtype)
1061     {
1062     case XI_HierarchyChanged:
1063       handle_hierarchy_changed (device_manager,
1064                                 (XIHierarchyEvent *) ev);
1065       return_val = FALSE;
1066       break;
1067     case XI_DeviceChanged:
1068       handle_device_changed (device_manager,
1069                              (XIDeviceChangedEvent *) ev);
1070       return_val = FALSE;
1071       break;
1072     case XI_KeyPress:
1073     case XI_KeyRelease:
1074       {
1075         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1076         GdkKeymap *keymap = gdk_keymap_get_for_display (display);
1077         GdkModifierType consumed, state;
1078         GdkDevice *device, *source_device;
1079
1080         event->key.type = xev->evtype == XI_KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
1081
1082         event->key.window = window;
1083
1084         event->key.time = xev->time;
1085         event->key.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons);
1086         event->key.group = _gdk_x11_get_group_for_state (display, event->key.state);
1087
1088         event->key.hardware_keycode = xev->detail;
1089         event->key.is_modifier = _gdk_x11_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
1090
1091         device = g_hash_table_lookup (device_manager->id_table,
1092                                       GUINT_TO_POINTER (xev->deviceid));
1093         gdk_event_set_device (event, device);
1094
1095         source_device = g_hash_table_lookup (device_manager->id_table,
1096                                              GUINT_TO_POINTER (xev->sourceid));
1097         gdk_event_set_source_device (event, source_device);
1098
1099         event->key.keyval = GDK_KEY_VoidSymbol;
1100
1101         gdk_keymap_translate_keyboard_state (keymap,
1102                                              event->key.hardware_keycode,
1103                                              event->key.state,
1104                                              event->key.group,
1105                                              &event->key.keyval,
1106                                              NULL, NULL, &consumed);
1107
1108         state = event->key.state & ~consumed;
1109         _gdk_x11_keymap_add_virt_mods (keymap, &state);
1110         event->key.state |= state;
1111
1112         translate_keyboard_string ((GdkEventKey *) event);
1113
1114         if (ev->evtype == XI_KeyPress)
1115           set_user_time (event);
1116
1117         /* FIXME: emulate autorepeat on key
1118          * release? XI2 seems attached to Xkb.
1119          */
1120       }
1121
1122       break;
1123     case XI_ButtonPress:
1124     case XI_ButtonRelease:
1125       {
1126         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1127         GdkDevice *source_device;
1128
1129         switch (xev->detail)
1130           {
1131           case 4:
1132           case 5:
1133           case 6:
1134           case 7:
1135             event->scroll.type = GDK_SCROLL;
1136
1137             if (xev->detail == 4)
1138               event->scroll.direction = GDK_SCROLL_UP;
1139             else if (xev->detail == 5)
1140               event->scroll.direction = GDK_SCROLL_DOWN;
1141             else if (xev->detail == 6)
1142               event->scroll.direction = GDK_SCROLL_LEFT;
1143             else
1144               event->scroll.direction = GDK_SCROLL_RIGHT;
1145
1146             event->scroll.window = window;
1147             event->scroll.time = xev->time;
1148             event->scroll.x = (gdouble) xev->event_x;
1149             event->scroll.y = (gdouble) xev->event_y;
1150             event->scroll.x_root = (gdouble) xev->root_x;
1151             event->scroll.y_root = (gdouble) xev->root_y;
1152
1153             event->scroll.device = g_hash_table_lookup (device_manager->id_table,
1154                                                         GUINT_TO_POINTER (xev->deviceid));
1155
1156             source_device = g_hash_table_lookup (device_manager->id_table,
1157                                                  GUINT_TO_POINTER (xev->sourceid));
1158             gdk_event_set_source_device (event, source_device);
1159
1160             event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons);
1161             break;
1162           default:
1163             event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
1164
1165             event->button.window = window;
1166             event->button.time = xev->time;
1167             event->button.x = (gdouble) xev->event_x;
1168             event->button.y = (gdouble) xev->event_y;
1169             event->button.x_root = (gdouble) xev->root_x;
1170             event->button.y_root = (gdouble) xev->root_y;
1171
1172             event->button.device = g_hash_table_lookup (device_manager->id_table,
1173                                                         GUINT_TO_POINTER (xev->deviceid));
1174
1175             source_device = g_hash_table_lookup (device_manager->id_table,
1176                                                  GUINT_TO_POINTER (xev->sourceid));
1177             gdk_event_set_source_device (event, source_device);
1178
1179             event->button.axes = translate_axes (event->button.device,
1180                                                  event->button.x,
1181                                                  event->button.y,
1182                                                  event->button.window,
1183                                                  &xev->valuators);
1184
1185             if (gdk_device_get_mode (event->button.device) == GDK_MODE_WINDOW)
1186               {
1187                 GdkDevice *device = event->button.device;
1188
1189                 /* Update event coordinates from axes */
1190                 gdk_device_get_axis (device, event->button.axes, GDK_AXIS_X, &event->button.x);
1191                 gdk_device_get_axis (device, event->button.axes, GDK_AXIS_Y, &event->button.y);
1192               }
1193
1194             event->button.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons);
1195             event->button.button = xev->detail;
1196           }
1197
1198         if (!set_screen_from_root (display, event, xev->root))
1199           {
1200             return_val = FALSE;
1201             break;
1202           }
1203
1204         set_user_time (event);
1205
1206         break;
1207       }
1208     case XI_Motion:
1209       {
1210         XIDeviceEvent *xev = (XIDeviceEvent *) ev;
1211         GdkDevice *source_device;
1212
1213         event->motion.type = GDK_MOTION_NOTIFY;
1214
1215         event->motion.window = window;
1216
1217         event->motion.time = xev->time;
1218         event->motion.x = (gdouble) xev->event_x;
1219         event->motion.y = (gdouble) xev->event_y;
1220         event->motion.x_root = (gdouble) xev->root_x;
1221         event->motion.y_root = (gdouble) xev->root_y;
1222
1223         event->motion.device = g_hash_table_lookup (device_manager->id_table,
1224                                                     GINT_TO_POINTER (xev->deviceid));
1225
1226         source_device = g_hash_table_lookup (device_manager->id_table,
1227                                              GUINT_TO_POINTER (xev->sourceid));
1228         gdk_event_set_source_device (event, source_device);
1229
1230         event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons);
1231
1232         /* There doesn't seem to be motion hints in XI */
1233         event->motion.is_hint = FALSE;
1234
1235         event->motion.axes = translate_axes (event->motion.device,
1236                                              event->motion.x,
1237                                              event->motion.y,
1238                                              event->motion.window,
1239                                              &xev->valuators);
1240
1241         if (gdk_device_get_mode (event->motion.device) == GDK_MODE_WINDOW)
1242           {
1243             GdkDevice *device = event->motion.device;
1244
1245             /* Update event coordinates from axes */
1246             gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_X, &event->motion.x);
1247             gdk_device_get_axis (device, event->motion.axes, GDK_AXIS_Y, &event->motion.y);
1248           }
1249       }
1250       break;
1251     case XI_Enter:
1252     case XI_Leave:
1253       {
1254         XIEnterEvent *xev = (XIEnterEvent *) ev;
1255         GdkDevice *device, *source_device;
1256
1257         event->crossing.type = (ev->evtype == XI_Enter) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
1258
1259         event->crossing.x = (gdouble) xev->event_x;
1260         event->crossing.y = (gdouble) xev->event_y;
1261         event->crossing.x_root = (gdouble) xev->root_x;
1262         event->crossing.y_root = (gdouble) xev->root_y;
1263         event->crossing.time = xev->time;
1264         event->crossing.focus = xev->focus;
1265
1266         event->crossing.window = window;
1267         event->crossing.subwindow = gdk_x11_window_lookup_for_display (display, xev->child);
1268
1269         device = g_hash_table_lookup (device_manager->id_table,
1270                                       GINT_TO_POINTER (xev->deviceid));
1271         gdk_event_set_device (event, device);
1272
1273         source_device = g_hash_table_lookup (device_manager->id_table,
1274                                              GUINT_TO_POINTER (xev->sourceid));
1275         gdk_event_set_source_device (event, source_device);
1276
1277         event->crossing.mode = translate_crossing_mode (xev->mode);
1278         event->crossing.detail = translate_notify_type (xev->detail);
1279         event->crossing.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons);
1280       }
1281       break;
1282     case XI_FocusIn:
1283     case XI_FocusOut:
1284       {
1285         XIEnterEvent *xev = (XIEnterEvent *) ev;
1286         GdkDevice *device, *source_device;
1287
1288         device = g_hash_table_lookup (device_manager->id_table,
1289                                       GINT_TO_POINTER (xev->deviceid));
1290
1291         source_device = g_hash_table_lookup (device_manager->id_table,
1292                                              GUINT_TO_POINTER (xev->sourceid));
1293
1294         handle_focus_change (window, device, source_device,
1295                              xev->detail, xev->mode,
1296                              (ev->evtype == XI_FocusIn) ? TRUE : FALSE);
1297
1298         return_val = FALSE;
1299       }
1300     default:
1301       return_val = FALSE;
1302       break;
1303     }
1304
1305   event->any.send_event = cookie->send_event;
1306
1307   if (return_val)
1308     {
1309       if (event->any.window)
1310         g_object_ref (event->any.window);
1311
1312       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1313            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1314           (event->crossing.subwindow != NULL))
1315         g_object_ref (event->crossing.subwindow);
1316     }
1317   else
1318     {
1319       /* Mark this event as having no resources to be freed */
1320       event->any.window = NULL;
1321       event->any.type = GDK_NOTHING;
1322     }
1323
1324   XFreeEventData (dpy, cookie);
1325
1326   return return_val;
1327 }
1328
1329 static GdkEventMask
1330 gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
1331 {
1332   return (GDK_KEY_PRESS_MASK |
1333           GDK_KEY_RELEASE_MASK |
1334           GDK_BUTTON_PRESS_MASK |
1335           GDK_BUTTON_RELEASE_MASK |
1336           GDK_SCROLL_MASK |
1337           GDK_ENTER_NOTIFY_MASK |
1338           GDK_LEAVE_NOTIFY_MASK |
1339           GDK_POINTER_MOTION_MASK |
1340           GDK_POINTER_MOTION_HINT_MASK |
1341           GDK_BUTTON1_MOTION_MASK |
1342           GDK_BUTTON2_MOTION_MASK |
1343           GDK_BUTTON3_MOTION_MASK |
1344           GDK_BUTTON_MOTION_MASK |
1345           GDK_FOCUS_CHANGE_MASK);
1346 }
1347
1348 static void
1349 gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
1350                                                  Window              window,
1351                                                  GdkEventMask        evmask)
1352 {
1353   GdkDeviceManager *device_manager;
1354   XIEventMask event_mask;
1355
1356   device_manager = GDK_DEVICE_MANAGER (translator);
1357
1358   event_mask.deviceid = XIAllMasterDevices;
1359   event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
1360
1361   _gdk_x11_device_manager_xi2_select_events (device_manager, window, &event_mask);
1362   g_free (event_mask.mask);
1363 }