gdkdevicemanager-xi2.c 74.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* GDK - The GIMP Drawing Kit
 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16
17
18
19
 */

#include "config.h"

20
21
#include "gdkx11devicemanager-xi2.h"
#include "gdkx11device-xi2.h"
22

23
#include "gdkdevicemanagerprivate-core.h"
24
#include "gdkdeviceprivate.h"
25
#include "gdkdevicetoolprivate.h"
26
#include "gdkdisplayprivate.h"
27
28
#include "gdkeventtranslator.h"
#include "gdkprivate-x11.h"
29
30
#include "gdkintl.h"
#include "gdkkeysyms.h"
Matthias Clasen's avatar
Matthias Clasen committed
31
#include "gdkinternals.h"
32
#include "gdkseatdefaultprivate.h"
33

34
35
36
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
37
#include <X11/Xatom.h>
38

39
40
#include <string.h>

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static const char *wacom_type_atoms[] = {
  "STYLUS",
  "CURSOR",
  "ERASER",
  "PAD",
  "TOUCH"
};
#define N_WACOM_TYPE_ATOMS G_N_ELEMENTS (wacom_type_atoms)

enum {
  WACOM_TYPE_STYLUS,
  WACOM_TYPE_CURSOR,
  WACOM_TYPE_ERASER,
  WACOM_TYPE_PAD,
  WACOM_TYPE_TOUCH,
};

58
59
struct _GdkX11DeviceManagerXI2
{
60
  GdkX11DeviceManagerCore parent_object;
61
62
63

  GHashTable *id_table;

64
  GList *devices;
65
66

  gint opcode;
67
68
  gint major;
  gint minor;
69
70
71
72
73
74
75
};

struct _GdkX11DeviceManagerXI2Class
{
  GdkDeviceManagerClass parent_class;
};

76
77
78
79
80
81
static void     gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface);

G_DEFINE_TYPE_WITH_CODE (GdkX11DeviceManagerXI2, gdk_x11_device_manager_xi2, GDK_TYPE_X11_DEVICE_MANAGER_CORE,
                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
                                                gdk_x11_device_manager_xi2_event_translator_init))

82
83
84
85
86
87
88
89
90
91
static void    gdk_x11_device_manager_xi2_constructed  (GObject      *object);
static void    gdk_x11_device_manager_xi2_dispose      (GObject      *object);
static void    gdk_x11_device_manager_xi2_set_property (GObject      *object,
                                                        guint         prop_id,
                                                        const GValue *value,
                                                        GParamSpec   *pspec);
static void    gdk_x11_device_manager_xi2_get_property (GObject      *object,
                                                        guint         prop_id,
                                                        GValue       *value,
                                                        GParamSpec   *pspec);
92

93
94
95
static GList * gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
                                                        GdkDeviceType     type);
static GdkDevice * gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager);
96

97
98
99
100
101
102
103
104
static gboolean gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
                                                            GdkDisplay         *display,
                                                            GdkEvent           *event,
                                                            XEvent             *xevent);
static GdkEventMask gdk_x11_device_manager_xi2_get_handled_events   (GdkEventTranslator *translator);
static void         gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
                                                                     Window              window,
                                                                     GdkEventMask        event_mask);
105
106
static GdkWindow *  gdk_x11_device_manager_xi2_get_window           (GdkEventTranslator *translator,
                                                                     XEvent             *xevent);
107

108
109
enum {
  PROP_0,
110
111
112
  PROP_OPCODE,
  PROP_MAJOR,
  PROP_MINOR
113
114
};

115
static void
116
gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass)
117
118
119
120
{
  GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

121
122
  object_class->constructed = gdk_x11_device_manager_xi2_constructed;
  object_class->dispose = gdk_x11_device_manager_xi2_dispose;
123
124
  object_class->set_property = gdk_x11_device_manager_xi2_set_property;
  object_class->get_property = gdk_x11_device_manager_xi2_get_property;
125

126
127
  device_manager_class->list_devices = gdk_x11_device_manager_xi2_list_devices;
  device_manager_class->get_client_pointer = gdk_x11_device_manager_xi2_get_client_pointer;
128
129
130
131
132
133
134
135

  g_object_class_install_property (object_class,
                                   PROP_OPCODE,
                                   g_param_spec_int ("opcode",
                                                     P_("Opcode"),
                                                     P_("Opcode for XInput2 requests"),
                                                     0, G_MAXINT, 0,
                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  g_object_class_install_property (object_class,
                                   PROP_MAJOR,
                                   g_param_spec_int ("major",
                                                     P_("Major"),
                                                     P_("Major version number"),
                                                     0, G_MAXINT, 0,
                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
  g_object_class_install_property (object_class,
                                   PROP_MINOR,
                                   g_param_spec_int ("minor",
                                                     P_("Minor"),
                                                     P_("Minor version number"),
                                                     0, G_MAXINT, 0,
                                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
150
151
152
}

static void
153
gdk_x11_device_manager_xi2_init (GdkX11DeviceManagerXI2 *device_manager)
154
155
156
157
158
159
160
161
{
  device_manager->id_table = g_hash_table_new_full (g_direct_hash,
                                                    g_direct_equal,
                                                    NULL,
                                                    (GDestroyNotify) g_object_unref);
}

static void
162
163
164
_gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
                                           Window            xwindow,
                                           XIEventMask      *event_mask)
165
166
167
168
169
170
171
172
173
174
175
176
177
{
  GdkDisplay *display;
  Display *xdisplay;

  display = gdk_device_manager_get_display (device_manager);
  xdisplay = GDK_DISPLAY_XDISPLAY (display);

  XISelectEvents (xdisplay, xwindow, event_mask, 1);
}

static void
translate_valuator_class (GdkDisplay          *display,
                          GdkDevice           *device,
Matthias Clasen's avatar
Matthias Clasen committed
178
179
180
181
                          Atom                 valuator_label,
                          gdouble              min,
                          gdouble              max,
                          gdouble              resolution)
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
{
  static gboolean initialized = FALSE;
  static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
  GdkAxisUse use = GDK_AXIS_IGNORE;
  GdkAtom label;
  gint i;

  if (!initialized)
    {
      label_atoms [GDK_AXIS_X] = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
      label_atoms [GDK_AXIS_Y] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");
      label_atoms [GDK_AXIS_PRESSURE] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Pressure");
      label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
      label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
      label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
      initialized = TRUE;
    }

Matthias Clasen's avatar
Matthias Clasen committed
200
  for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
201
    {
Matthias Clasen's avatar
Matthias Clasen committed
202
      if (label_atoms[i] == valuator_label)
203
204
205
206
207
208
        {
          use = i;
          break;
        }
    }

Matthias Clasen's avatar
Matthias Clasen committed
209
210
  if (valuator_label != None)
    label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
211
212
213
  else
    label = GDK_NONE;

Matthias Clasen's avatar
Matthias Clasen committed
214
  _gdk_device_add_axis (device, label, use, min, max, resolution);
215
  GDK_NOTE (INPUT, g_message ("\n\taxis: %s %s", gdk_atom_name (label), use == GDK_AXIS_IGNORE ? "(ignored)" : "(used)"));
216
217
218
219
220
221
222
223
}

static void
translate_device_classes (GdkDisplay      *display,
                          GdkDevice       *device,
                          XIAnyClassInfo **classes,
                          guint            n_classes)
{
Matthias Clasen's avatar
Matthias Clasen committed
224
  gint i;
225
226
227
228
229
230
231
232
233
234
235
236

  g_object_freeze_notify (G_OBJECT (device));

  for (i = 0; i < n_classes; i++)
    {
      XIAnyClassInfo *class_info = classes[i];

      switch (class_info->type)
        {
        case XIKeyClass:
          {
            XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
237
            gint j;
238
239
240

            _gdk_device_set_keys (device, key_info->num_keycodes);

241
242
            for (j = 0; j < key_info->num_keycodes; j++)
              gdk_device_set_key (device, j, key_info->keycodes[j], 0);
243
244
245
          }
          break;
        case XIValuatorClass:
Matthias Clasen's avatar
Matthias Clasen committed
246
247
248
249
250
251
252
253
          {
            XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info;
            translate_valuator_class (display, device,
                                      valuator_info->label,
                                      valuator_info->min,
                                      valuator_info->max,
                                      valuator_info->resolution);
          }
254
          break;
255
256
257
258
259
260
261
262
263
264
265
#ifdef XINPUT_2_2
        case XIScrollClass:
          {
            XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
            GdkScrollDirection direction;

            if (scroll_info->scroll_type == XIScrollTypeVertical)
              direction = GDK_SCROLL_DOWN;
            else
              direction = GDK_SCROLL_RIGHT;

266
            GDK_NOTE (INPUT,
Matthias Clasen's avatar
Matthias Clasen committed
267
                      g_message ("\n\tscroll valuator %d: %s, increment %f",
268
269
270
                                 scroll_info->number,
                                 scroll_info->scroll_type == XIScrollTypeVertical
                                                ? "vertical"
Matthias Clasen's avatar
Matthias Clasen committed
271
272
                                                : "horizontal",
                                 scroll_info->increment));
273

274
275
            _gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device),
                                                     scroll_info->number,
Matthias Clasen's avatar
Matthias Clasen committed
276
277
                                                     direction,
                                                     scroll_info->increment);
278
279
          }
#endif /* XINPUT_2_2 */
280
281
282
283
284
285
286
287
288
        default:
          /* Ignore */
          break;
        }
    }

  g_object_thaw_notify (G_OBJECT (device));
}

289
290
291
static gboolean
is_touch_device (XIAnyClassInfo **classes,
                 guint            n_classes,
292
293
                 GdkInputSource  *device_type,
                 gint            *num_touches)
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
{
#ifdef XINPUT_2_2
  guint i;

  for (i = 0; i < n_classes; i++)
    {
      XITouchClassInfo *class = (XITouchClassInfo *) classes[i];

      if (class->type != XITouchClass)
        continue;

      if (class->num_touches > 0)
        {
          if (class->mode == XIDirectTouch)
            *device_type = GDK_SOURCE_TOUCHSCREEN;
          else if (class->mode == XIDependentTouch)
            *device_type = GDK_SOURCE_TOUCHPAD;
          else
            continue;

314
315
          *num_touches = class->num_touches;

316
317
318
319
320
321
322
323
          return TRUE;
        }
    }
#endif

  return FALSE;
}

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
static gboolean
has_abs_axes (GdkDisplay      *display,
              XIAnyClassInfo **classes,
              guint            n_classes)
{
  gboolean has_x = FALSE, has_y = FALSE;
  Atom abs_x, abs_y;
  guint i;

  abs_x = gdk_x11_get_xatom_by_name_for_display (display, "Abs X");
  abs_y = gdk_x11_get_xatom_by_name_for_display (display, "Abs Y");

  for (i = 0; i < n_classes; i++)
    {
      XIValuatorClassInfo *class = (XIValuatorClassInfo *) classes[i];

      if (class->type != XIValuatorClass)
        continue;
      if (class->mode != XIModeAbsolute)
        continue;

      if (class->label == abs_x)
        has_x = TRUE;
      else if (class->label == abs_y)
        has_y = TRUE;

      if (has_x && has_y)
        break;
    }

  return (has_x && has_y);
}

357
358
359
360
361
362
363
364
365
static gboolean
get_device_ids (GdkDisplay    *display,
                XIDeviceInfo  *info,
                gchar        **vendor_id,
                gchar        **product_id)
{
  gulong nitems, bytes_after;
  guint32 *data;
  int rc, format;
366
  Atom prop, type;
367
368
369

  gdk_x11_display_error_trap_push (display);

370
371
372
  prop = XInternAtom (GDK_DISPLAY_XDISPLAY (display), "Device Product ID", True);

  if (prop == None)
Matthias Clasen's avatar
Matthias Clasen committed
373
374
375
376
    {
      gdk_x11_display_error_trap_pop_ignored (display);
      return 0;
    }
377

378
  rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
379
                      info->deviceid, prop,
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
                      0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after,
                      (guchar **) &data);
  gdk_x11_display_error_trap_pop_ignored (display);

  if (rc != Success || type != XA_INTEGER || format != 32 || nitems != 2)
    return FALSE;

  if (vendor_id)
    *vendor_id = g_strdup_printf ("%.4x", data[0]);
  if (product_id)
    *product_id = g_strdup_printf ("%.4x", data[1]);

  XFree (data);

  return TRUE;
}

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
static gboolean
is_touchpad_device (GdkDisplay   *display,
                    XIDeviceInfo *info)
{
  gulong nitems, bytes_after;
  guint32 *data;
  int rc, format;
  Atom type;

  gdk_x11_display_error_trap_push (display);

  rc = XIGetProperty (GDK_DISPLAY_XDISPLAY (display),
                      info->deviceid,
                      gdk_x11_get_xatom_by_name_for_display (display, "libinput Tapping Enabled"),
                      0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after,
                      (guchar **) &data);
  gdk_x11_display_error_trap_pop_ignored (display);

  if (rc != Success || type != XA_INTEGER || format != 8 || nitems != 1)
    return FALSE;

  XFree (data);

  return TRUE;
}

423
424
425
426
427
428
static GdkDevice *
create_device (GdkDeviceManager *device_manager,
               GdkDisplay       *display,
               XIDeviceInfo     *dev)
{
  GdkInputSource input_source;
429
  GdkInputSource touch_source;
430
431
432
  GdkDeviceType type;
  GdkDevice *device;
  GdkInputMode mode;
433
  gint num_touches = 0;
434
  gchar *vendor_id = NULL, *product_id = NULL;
435
436
437

  if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
    input_source = GDK_SOURCE_KEYBOARD;
438
439
  else if (is_touchpad_device (display, dev))
    input_source = GDK_SOURCE_TOUCHPAD;
440
  else if (dev->use == XISlavePointer &&
441
           is_touch_device (dev->classes, dev->num_classes, &touch_source, &num_touches))
442
    input_source = touch_source;
443
444
445
446
447
448
449
450
451
452
  else
    {
      gchar *tmp_name;

      tmp_name = g_ascii_strdown (dev->name, -1);

      if (strstr (tmp_name, "eraser"))
        input_source = GDK_SOURCE_ERASER;
      else if (strstr (tmp_name, "cursor"))
        input_source = GDK_SOURCE_CURSOR;
453
454
      else if (strstr (tmp_name, " pad"))
        input_source = GDK_SOURCE_TABLET_PAD;
455
      else if (strstr (tmp_name, "wacom") ||
456
457
               strstr (tmp_name, "pen") ||
               strstr (tmp_name, "stylus"))
458
        input_source = GDK_SOURCE_PEN;
459
      else if (!strstr (tmp_name, "mouse") &&
460
               !strstr (tmp_name, "pointer") &&
461
               !strstr (tmp_name, "qemu usb tablet") &&
462
               !strstr (tmp_name, "spice vdagent tablet") &&
463
               !strstr (tmp_name, "virtualbox usb tablet") &&
464
               has_abs_axes (display, dev->classes, dev->num_classes))
465
        input_source = GDK_SOURCE_TOUCHSCREEN;
466
467
468
      else if (strstr (tmp_name, "trackpoint") ||
               strstr (tmp_name, "dualpoint stick"))
        input_source = GDK_SOURCE_TRACKPOINT;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
      else
        input_source = GDK_SOURCE_MOUSE;

      g_free (tmp_name);
    }

  switch (dev->use)
    {
    case XIMasterKeyboard:
    case XIMasterPointer:
      type = GDK_DEVICE_TYPE_MASTER;
      mode = GDK_MODE_SCREEN;
      break;
    case XISlaveKeyboard:
    case XISlavePointer:
      type = GDK_DEVICE_TYPE_SLAVE;
      mode = GDK_MODE_DISABLED;
      break;
    case XIFloatingSlave:
    default:
      type = GDK_DEVICE_TYPE_FLOATING;
      mode = GDK_MODE_DISABLED;
      break;
    }

494
495
496
  GDK_NOTE (INPUT,
            ({
              const gchar *type_names[] = { "master", "slave", "floating" };
497
              const gchar *source_names[] = { "mouse", "pen", "eraser", "cursor", "keyboard", "direct touch", "indirect touch", "trackpoint", "pad" };
498
499
500
501
502
503
504
505
506
507
              const gchar *mode_names[] = { "disabled", "screen", "window" };
              g_message ("input device:\n\tname: %s\n\ttype: %s\n\tsource: %s\n\tmode: %s\n\thas cursor: %d\n\ttouches: %d",
                         dev->name,
                         type_names[type],
                         source_names[input_source],
                         mode_names[mode],
                         dev->use == XIMasterPointer,
                         num_touches);
            }));

508
509
510
511
  if (dev->use != XIMasterKeyboard &&
      dev->use != XIMasterPointer)
    get_device_ids (display, dev, &vendor_id, &product_id);

512
  device = g_object_new (GDK_TYPE_X11_DEVICE_XI2,
513
514
515
516
517
518
519
520
                         "name", dev->name,
                         "type", type,
                         "input-source", input_source,
                         "input-mode", mode,
                         "has-cursor", (dev->use == XIMasterPointer),
                         "display", display,
                         "device-manager", device_manager,
                         "device-id", dev->deviceid,
521
522
                         "vendor-id", vendor_id,
                         "product-id", product_id,
523
                         "num-touches", num_touches,
524
525
526
                         NULL);

  translate_device_classes (display, device, dev->classes, dev->num_classes);
527
528
  g_free (vendor_id);
  g_free (product_id);
529
530
531
532

  return device;
}

533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
static void
ensure_seat_for_device_pair (GdkX11DeviceManagerXI2 *device_manager,
                             GdkDevice              *device1,
                             GdkDevice              *device2)
{
  GdkDevice *pointer, *keyboard;
  GdkDisplay *display;
  GdkSeat *seat;

  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
  seat = gdk_device_get_seat (device1);

  if (!seat)
    {
      if (gdk_device_get_source (device1) == GDK_SOURCE_KEYBOARD)
        {
          keyboard = device1;
          pointer = device2;
        }
      else
        {
          pointer = device1;
          keyboard = device2;
        }

      seat = gdk_seat_default_new_for_master_pair (pointer, keyboard);
      gdk_display_add_seat (display, seat);
      g_object_unref (seat);
    }
}

564
static GdkDevice *
565
566
567
add_device (GdkX11DeviceManagerXI2 *device_manager,
            XIDeviceInfo           *dev,
            gboolean                emit_signal)
568
569
570
571
572
573
574
575
576
{
  GdkDisplay *display;
  GdkDevice *device;

  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
  device = create_device (GDK_DEVICE_MANAGER (device_manager), display, dev);

  g_hash_table_replace (device_manager->id_table,
                        GINT_TO_POINTER (dev->deviceid),
577
                        g_object_ref (device));
578

579
  device_manager->devices = g_list_append (device_manager->devices, device);
580
581

  if (emit_signal)
582
583
584
585
    {
      if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
        {
          GdkDevice *master;
586
          GdkSeat *seat;
587
588
589
590
591
592
593
594
595

          /* The device manager is already constructed, then
           * keep the hierarchy coherent for the added device.
           */
          master = g_hash_table_lookup (device_manager->id_table,
                                        GINT_TO_POINTER (dev->attachment));

          _gdk_device_set_associated_device (device, master);
          _gdk_device_add_slave (master, device);
596
597
598

          seat = gdk_device_get_seat (master);
          gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), device);
599
        }
600
601
602
      else if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
        {
          GdkDevice *relative;
603

604
605
606
607
608
609
610
611
612
613
          relative = g_hash_table_lookup (device_manager->id_table,
                                          GINT_TO_POINTER (dev->attachment));

          if (relative)
            {
              _gdk_device_set_associated_device (device, relative);
              _gdk_device_set_associated_device (relative, device);
              ensure_seat_for_device_pair (device_manager, device, relative);
            }
        }
614
    }
615

616
617
    g_signal_emit_by_name (device_manager, "device-added", device);

618
619
620
  return device;
}

621
622
623
624
625
626
627
628
629
630
631
632
633
634
static void
detach_from_seat (GdkDevice *device)
{
  GdkSeat *seat = gdk_device_get_seat (device);

  if (!seat)
    return;

  if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER)
    gdk_display_remove_seat (gdk_device_get_display (device), seat);
  else if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_SLAVE)
    gdk_seat_default_remove_slave (GDK_SEAT_DEFAULT (seat), device);
}

635
static void
636
637
remove_device (GdkX11DeviceManagerXI2 *device_manager,
               gint                    device_id)
638
639
640
641
642
643
644
645
{
  GdkDevice *device;

  device = g_hash_table_lookup (device_manager->id_table,
                                GINT_TO_POINTER (device_id));

  if (device)
    {
646
      detach_from_seat (device);
647
648
649

      g_hash_table_remove (device_manager->id_table,
                           GINT_TO_POINTER (device_id));
650
651
652
653
654

      device_manager->devices = g_list_remove (device_manager->devices, device);
      g_signal_emit_by_name (device_manager, "device-removed", device);
      g_object_run_dispose (G_OBJECT (device));
      g_object_unref (device);
655
656
657
658
    }
}

static void
659
relate_masters (gpointer key,
660
661
662
                gpointer value,
                gpointer user_data)
{
663
  GdkX11DeviceManagerXI2 *device_manager;
664
665
666
667
668
669
670
671
  GdkDevice *device, *relative;

  device_manager = user_data;
  device = g_hash_table_lookup (device_manager->id_table, key);
  relative = g_hash_table_lookup (device_manager->id_table, value);

  _gdk_device_set_associated_device (device, relative);
  _gdk_device_set_associated_device (relative, device);
672
  ensure_seat_for_device_pair (device_manager, device, relative);
673
674
}

675
676
677
678
679
static void
relate_slaves (gpointer key,
               gpointer value,
               gpointer user_data)
{
680
  GdkX11DeviceManagerXI2 *device_manager;
681
  GdkDevice *slave, *master;
682
  GdkSeat *seat;
683
684
685
686
687
688
689

  device_manager = user_data;
  slave = g_hash_table_lookup (device_manager->id_table, key);
  master = g_hash_table_lookup (device_manager->id_table, value);

  _gdk_device_set_associated_device (slave, master);
  _gdk_device_add_slave (master, slave);
690
691
692

  seat = gdk_device_get_seat (master);
  gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), slave);
693
694
}

695
static void
696
gdk_x11_device_manager_xi2_constructed (GObject *object)
697
{
698
  GdkX11DeviceManagerXI2 *device_manager;
699
700
  GdkDisplay *display;
  GdkScreen *screen;
701
  GHashTable *masters, *slaves;
702
703
704
705
706
707
  Display *xdisplay;
  XIDeviceInfo *info, *dev;
  int ndevices, i;
  XIEventMask event_mask;
  unsigned char mask[2] = { 0 };

708
709
  G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->constructed (object);

710
  device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
711
712
  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
713

714
715
  g_assert (device_manager->major == 2);

716
717
  masters = g_hash_table_new (NULL, NULL);
  slaves = g_hash_table_new (NULL, NULL);
718

719
  info = XIQueryDevice (xdisplay, XIAllDevices, &ndevices);
720
721
722
723
724

  /* Initialize devices list */
  for (i = 0; i < ndevices; i++)
    {
      dev = &info[i];
725
726
727
728

      if (!dev->enabled)
	      continue;

Matthias Clasen's avatar
Matthias Clasen committed
729
      add_device (device_manager, dev, FALSE);
730
731
732
733

      if (dev->use == XIMasterPointer ||
          dev->use == XIMasterKeyboard)
        {
734
735
736
737
738
739
740
741
          g_hash_table_insert (masters,
                               GINT_TO_POINTER (dev->deviceid),
                               GINT_TO_POINTER (dev->attachment));
        }
      else if (dev->use == XISlavePointer ||
               dev->use == XISlaveKeyboard)
        {
          g_hash_table_insert (slaves,
742
743
744
745
746
                               GINT_TO_POINTER (dev->deviceid),
                               GINT_TO_POINTER (dev->attachment));
        }
    }

747
  XIFreeDeviceInfo (info);
748
749

  /* Stablish relationships between devices */
750
751
752
753
754
  g_hash_table_foreach (masters, relate_masters, object);
  g_hash_table_destroy (masters);

  g_hash_table_foreach (slaves, relate_slaves, object);
  g_hash_table_destroy (slaves);
755
756
757
758
759

  /* Connect to hierarchy change events */
  screen = gdk_display_get_default_screen (display);
  XISetMask (mask, XI_HierarchyChanged);
  XISetMask (mask, XI_DeviceChanged);
760
  XISetMask (mask, XI_PropertyEvent);
761
762
763
764
765

  event_mask.deviceid = XIAllDevices;
  event_mask.mask_len = sizeof (mask);
  event_mask.mask = mask;

766
767
768
  _gdk_x11_device_manager_xi2_select_events (GDK_DEVICE_MANAGER (object),
                                             GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
                                             &event_mask);
769
770
771
}

static void
772
gdk_x11_device_manager_xi2_dispose (GObject *object)
773
{
774
  GdkX11DeviceManagerXI2 *device_manager;
775

776
  device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);
777

778
779
  g_list_free_full (device_manager->devices, g_object_unref);
  device_manager->devices = NULL;
780

781
  if (device_manager->id_table)
782
    {
783
784
      g_hash_table_destroy (device_manager->id_table);
      device_manager->id_table = NULL;
785
    }
786

787
  G_OBJECT_CLASS (gdk_x11_device_manager_xi2_parent_class)->dispose (object);
788
789
790
}

static GList *
791
792
gdk_x11_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
                                         GdkDeviceType     type)
793
{
794
  GdkX11DeviceManagerXI2 *device_manager_xi2;
795
  GList *cur, *list = NULL;
796

797
  device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (device_manager);
798

799
  for (cur = device_manager_xi2->devices; cur; cur = cur->next)
800
    {
801
      GdkDevice *dev = cur->data;
802

803
804
      if (type == gdk_device_get_device_type (dev))
        list = g_list_prepend (list, dev);
805
806
    }

807
  return list;
808
809
}

810
static GdkDevice *
811
gdk_x11_device_manager_xi2_get_client_pointer (GdkDeviceManager *device_manager)
812
{
813
  GdkX11DeviceManagerXI2 *device_manager_xi2;
814
815
816
  GdkDisplay *display;
  int device_id;

817
  device_manager_xi2 = (GdkX11DeviceManagerXI2 *) device_manager;
818
819
820
821
822
823
824
825
826
  display = gdk_device_manager_get_display (device_manager);

  XIGetClientPointer (GDK_DISPLAY_XDISPLAY (display),
                      None, &device_id);

  return g_hash_table_lookup (device_manager_xi2->id_table,
                              GINT_TO_POINTER (device_id));
}

827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
static void
gdk_x11_device_manager_xi2_set_property (GObject      *object,
                                         guint         prop_id,
                                         const GValue *value,
                                         GParamSpec   *pspec)
{
  GdkX11DeviceManagerXI2 *device_manager;

  device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);

  switch (prop_id)
    {
    case PROP_OPCODE:
      device_manager->opcode = g_value_get_int (value);
      break;
842
843
844
845
846
847
    case PROP_MAJOR:
      device_manager->major = g_value_get_int (value);
      break;
    case PROP_MINOR:
      device_manager->minor = g_value_get_int (value);
      break;
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gdk_x11_device_manager_xi2_get_property (GObject    *object,
                                         guint       prop_id,
                                         GValue     *value,
                                         GParamSpec *pspec)
{
  GdkX11DeviceManagerXI2 *device_manager;

  device_manager = GDK_X11_DEVICE_MANAGER_XI2 (object);

  switch (prop_id)
    {
    case PROP_OPCODE:
      g_value_set_int (value, device_manager->opcode);
      break;
869
870
871
872
873
874
    case PROP_MAJOR:
      g_value_set_int (value, device_manager->major);
      break;
    case PROP_MINOR:
      g_value_set_int (value, device_manager->minor);
      break;
875
876
877
878
879
880
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

881
static void
882
gdk_x11_device_manager_xi2_event_translator_init (GdkEventTranslatorIface *iface)
883
{
884
885
886
  iface->translate_event = gdk_x11_device_manager_xi2_translate_event;
  iface->get_handled_events = gdk_x11_device_manager_xi2_get_handled_events;
  iface->select_window_events = gdk_x11_device_manager_xi2_select_window_events;
887
  iface->get_window = gdk_x11_device_manager_xi2_get_window;
888
889
890
}

static void
891
892
handle_hierarchy_changed (GdkX11DeviceManagerXI2 *device_manager,
                          XIHierarchyEvent       *ev)
893
{
894
895
896
897
  GdkDisplay *display;
  Display *xdisplay;
  XIDeviceInfo *info;
  int ndevices;
898
899
  gint i;

900
901
  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
902
903
904
905
906

  for (i = 0; i < ev->num_info; i++)
    {
      if (ev->info[i].flags & XIDeviceEnabled)
        {
907
          gdk_x11_display_error_trap_push (display);
908
          info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
909
910
911
912
913
914
          gdk_x11_display_error_trap_pop_ignored (display);
          if (info)
            {
              add_device (device_manager, &info[0], TRUE);
              XIFreeDeviceInfo (info);
            }
915
916
917
        }
      else if (ev->info[i].flags & XIDeviceDisabled)
        remove_device (device_manager, ev->info[i].deviceid);
918
919
920
921
      else if (ev->info[i].flags & XISlaveAttached ||
               ev->info[i].flags & XISlaveDetached)
        {
          GdkDevice *master, *slave;
922
          GdkSeat *seat;
923
924
925
926

          slave = g_hash_table_lookup (device_manager->id_table,
                                       GINT_TO_POINTER (ev->info[i].deviceid));

927
928
929
          if (!slave)
            continue;

930
931
932
933
934
935
936
937
938
          /* Remove old master info */
          master = gdk_device_get_associated_device (slave);

          if (master)
            {
              _gdk_device_remove_slave (master, slave);
              _gdk_device_set_associated_device (slave, NULL);

              g_signal_emit_by_name (device_manager, "device-changed", master);
939
940
941

              seat = gdk_device_get_seat (master);
              gdk_seat_default_remove_slave (GDK_SEAT_DEFAULT (seat), slave);
942
943
944
945
946
            }

          /* Add new master if it's an attachment event */
          if (ev->info[i].flags & XISlaveAttached)
            {
947
              gdk_x11_display_error_trap_push (display);
948
              info = XIQueryDevice (xdisplay, ev->info[i].deviceid, &ndevices);
949
950
951
952
953
954
              gdk_x11_display_error_trap_pop_ignored (display);
              if (info)
                {
                  master = g_hash_table_lookup (device_manager->id_table,
                                                GINT_TO_POINTER (info->attachment));
                  XIFreeDeviceInfo (info);
955
                }
956

957
958
              if (master)
                {
959
960
961
                  _gdk_device_set_associated_device (slave, master);
                  _gdk_device_add_slave (master, slave);

962
963
964
                  seat = gdk_device_get_seat (master);
                  gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), slave);

965
966
                  g_signal_emit_by_name (device_manager, "device-changed", master);
                }
967
968
969
970
            }

          g_signal_emit_by_name (device_manager, "device-changed", slave);
        }
971
972
973
974
    }
}

static void
975
976
handle_device_changed (GdkX11DeviceManagerXI2 *device_manager,
                       XIDeviceChangedEvent   *ev)
977
978
{
  GdkDisplay *display;
979
  GdkDevice *device, *source_device;
980
981
982
983

  display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
  device = g_hash_table_lookup (device_manager->id_table,
                                GUINT_TO_POINTER (ev->deviceid));
984
985
  source_device = g_hash_table_lookup (device_manager->id_table,
                                       GUINT_TO_POINTER (ev->sourceid));
986

987
988
989
  if (device)
    {
      _gdk_device_reset_axes (device);
990
      _gdk_device_xi2_unset_scroll_valuators ((GdkX11DeviceXI2 *) device);
991
      gdk_x11_device_xi2_store_axes (GDK_X11_DEVICE_XI2 (device), NULL, 0);
992
      translate_device_classes (display, device, ev->classes, ev->num_classes);
993

994
995
      g_signal_emit_by_name (G_OBJECT (device), "changed");
    }
996
997
998

  if (source_device)
    _gdk_device_xi2_reset_scroll_valuators (GDK_X11_DEVICE_XI2 (source_device));
999
1000
}

For faster browsing, not all history is shown. View entire blame