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