1
/*
2
 * AT-SPI - Assistive Technology Service Provider Interface
3
 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4
 *
5
 * Copyright 2020 SUSE LLC.
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the
19
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

            
23
#include "atspi-device-x11.h"
24
#include "atspi-private.h"
25

            
26
#include <X11/XKBlib.h>
27
#include <X11/Xlib.h>
28
#include <X11/Xutil.h>
29
#include <X11/extensions/XInput2.h>
30

            
31
#define ATSPI_VIRTUAL_MODIFIER_MASK 0x0000f000
32

            
33
typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private;
34
struct _AtspiDeviceX11Private
35
{
36
  Display *display;
37
  Window root_window;
38
  Window focused_window;
39
  GSource *source;
40
  int xi_opcode;
41
  GSList *modifiers;
42
  GSList *key_grabs;
43
  guint virtual_mods_enabled;
44
  gboolean keyboard_grabbed;
45
  unsigned int numlock_physical_mask;
46
  AtspiEventListener *event_listener;
47
};
48

            
49
GObjectClass *device_x11_parent_class;
50

            
51
typedef struct _DisplaySource
52
{
53
  GSource source;
54

            
55
  Display *display;
56
  GPollFD event_poll_fd;
57
} DisplaySource;
58

            
59
typedef struct
60
{
61
  guint keycode;
62
  guint modifier;
63
} AtspiX11KeyModifier;
64

            
65
typedef struct
66
{
67
  AtspiKeyDefinition *kd;
68
  gboolean enabled;
69
  Window window;
70
} AtspiX11KeyGrab;
71

            
72
static gboolean
73
event_prepare (GSource *source, gint *timeout)
74
{
75
  Display *display = ((DisplaySource *) source)->display;
76
  gboolean retval;
77

            
78
  *timeout = -1;
79
  retval = XPending (display);
80

            
81
  return retval;
82
}
83

            
84
static gboolean
85
event_check (GSource *source)
86
{
87
  DisplaySource *display_source = (DisplaySource *) source;
88
  gboolean retval;
89

            
90
  if (display_source->event_poll_fd.revents & G_IO_IN)
91
    retval = XPending (display_source->display);
92
  else
93
    retval = FALSE;
94

            
95
  return retval;
96
}
97

            
98
static void
99
xi2keyevent (XIDeviceEvent *xievent, XEvent *xkeyevent)
100
{
101
  memset (xkeyevent, 0, sizeof (*xkeyevent));
102

            
103
  switch (xievent->evtype)
104
    {
105
    case XI_KeyPress:
106
      xkeyevent->type = KeyPress;
107
      break;
108
    case XI_KeyRelease:
109
      xkeyevent->type = KeyRelease;
110
      break;
111
    default:
112
      break;
113
    }
114
  xkeyevent->xkey.serial = xievent->serial;
115
  xkeyevent->xkey.send_event = xievent->send_event;
116
  xkeyevent->xkey.display = xievent->display;
117
  xkeyevent->xkey.window = xievent->event;
118
  xkeyevent->xkey.root = xievent->root;
119
  xkeyevent->xkey.subwindow = xievent->child;
120
  xkeyevent->xkey.time = xievent->time;
121
  xkeyevent->xkey.x = xievent->event_x;
122
  xkeyevent->xkey.y = xievent->event_y;
123
  xkeyevent->xkey.x_root = xievent->root_x;
124
  xkeyevent->xkey.y_root = xievent->root_y;
125
  xkeyevent->xkey.state = xievent->mods.effective;
126
  xkeyevent->xkey.keycode = xievent->detail;
127
  xkeyevent->xkey.same_screen = 1;
128
}
129

            
130
G_DEFINE_TYPE_WITH_CODE (AtspiDeviceX11, atspi_device_x11, ATSPI_TYPE_DEVICE, G_ADD_PRIVATE (AtspiDeviceX11))
131

            
132
static guint
133
find_virtual_mapping (AtspiDeviceX11 *x11_device, gint keycode)
134
{
135
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
136
  GSList *l;
137

            
138
  for (l = priv->modifiers; l; l = l->next)
139
    {
140
      AtspiX11KeyModifier *entry = l->data;
141
      if (entry->keycode == keycode)
142
        return entry->modifier;
143
    }
144

            
145
  return 0;
146
}
147

            
148
static gboolean
149
grab_should_be_enabled (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
150
{
151
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
152

            
153
  /* If the whole keyboard is grabbed, then all keys are grabbed elsewhere */
154
  if (priv->keyboard_grabbed)
155
    return FALSE;
156

            
157
  guint virtual_mods_used = grab->kd->modifiers & ATSPI_VIRTUAL_MODIFIER_MASK;
158
  return ((priv->virtual_mods_enabled & virtual_mods_used) == virtual_mods_used);
159
}
160

            
161
static gboolean
162
grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
163
{
164
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
165
  GSList *l;
166

            
167
  for (l = priv->key_grabs; l; l = l->next)
168
    {
169
      AtspiX11KeyGrab *other = l->data;
170
      if (other != grab && other->enabled && other->kd->keycode == grab->kd->keycode && (other->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK) == (grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK))
171
        return TRUE;
172
    }
173
  return FALSE;
174
}
175

            
176
static gboolean
177
grab_key_aux (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
178
{
179
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
180
  XIGrabModifiers xi_modifiers;
181
  XIEventMask eventmask;
182
  unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
183
  int ret;
184

            
185
  xi_modifiers.modifiers = modmask;
186
  xi_modifiers.status = 0;
187

            
188
  eventmask.deviceid = XIAllDevices;
189
  eventmask.mask_len = sizeof (mask);
190
  eventmask.mask = mask;
191

            
192
  XISetMask (mask, XI_KeyPress);
193
  XISetMask (mask, XI_KeyRelease);
194

            
195
  ret = XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers);
196
  return (ret == 0);
197
}
198

            
199
static gboolean
200
grab_key (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
201
{
202
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
203
  gboolean include_numlock = !_atspi_key_is_on_keypad (keycode);
204
  gboolean ret = FALSE;
205

            
206
  ret |= grab_key_aux (x11_device, window, keycode, modmask);
207
  if (!(modmask & LockMask))
208
    ret |= grab_key_aux (x11_device, window, keycode, modmask | LockMask);
209
  if (include_numlock && !(modmask & priv->numlock_physical_mask))
210
    {
211
      ret |= grab_key_aux (x11_device, window, keycode, modmask | priv->numlock_physical_mask);
212
      if (!(modmask & LockMask))
213
        ret |= grab_key_aux (x11_device, window, keycode, modmask | LockMask | priv->numlock_physical_mask);
214
    }
215
  return ret;
216
}
217

            
218
static gboolean
219
enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
220
{
221
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
222
  gboolean ret;
223

            
224
  g_return_val_if_fail (priv->display != NULL, FALSE);
225

            
226
  if (grab_has_active_duplicate (x11_device, grab))
227
    ret = TRUE;
228
  else
229
    ret = grab_key (x11_device, priv->focused_window, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
230
  grab->enabled = TRUE;
231
  grab->window = priv->focused_window;
232
  return ret;
233
}
234

            
235
static void
236
ungrab_key_aux (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
237
{
238
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
239
  XIGrabModifiers xi_modifiers;
240

            
241
  xi_modifiers.modifiers = modmask;
242
  xi_modifiers.status = 0;
243

            
244
  XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, window, 1, &xi_modifiers);
245
}
246

            
247
static void
248
ungrab_key (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
249
{
250
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
251

            
252
  ungrab_key_aux (x11_device, window, keycode, modmask);
253
  if (!(modmask & LockMask))
254
    ungrab_key_aux (x11_device, window, keycode, modmask | LockMask);
255
  if (!(modmask & priv->numlock_physical_mask))
256
    {
257
      ungrab_key_aux (x11_device, window, keycode, modmask | priv->numlock_physical_mask);
258
      if (!(modmask & LockMask))
259
        ungrab_key_aux (x11_device, window, keycode, modmask | LockMask | priv->numlock_physical_mask);
260
    }
261
}
262

            
263
static void
264
disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
265
{
266
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
267

            
268
  g_return_if_fail (priv->display != NULL);
269

            
270
  if (!grab->enabled)
271
    return;
272

            
273
  grab->enabled = FALSE;
274

            
275
  if (grab_has_active_duplicate (x11_device, grab))
276
    return;
277

            
278
  ungrab_key (x11_device, grab->window, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
279
}
280

            
281
static void
282
refresh_key_grabs (AtspiDeviceX11 *x11_device)
283
{
284
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
285
  GSList *l;
286
  int focus_revert;
287

            
288
  XGetInputFocus (priv->display, &priv->focused_window, &focus_revert);
289

            
290
  for (l = priv->key_grabs; l; l = l->next)
291
    {
292
      AtspiX11KeyGrab *grab = l->data;
293
      if (grab->window != priv->focused_window)
294
        disable_key_grab (x11_device, grab);
295
    }
296

            
297
  for (l = priv->key_grabs; l; l = l->next)
298
    {
299
      AtspiX11KeyGrab *grab = l->data;
300
      gboolean new_enabled = grab_should_be_enabled (x11_device, grab);
301
      if (new_enabled && !grab->enabled)
302
        enable_key_grab (x11_device, grab);
303
      else if (grab->enabled && !new_enabled)
304
        disable_key_grab (x11_device, grab);
305
    }
306
}
307

            
308
static void
309
set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled)
310
{
311
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
312
  guint modifier = find_virtual_mapping (x11_device, keycode);
313

            
314
  if (!modifier)
315
    return;
316

            
317
  if (enabled)
318
    {
319
      if (priv->virtual_mods_enabled & modifier)
320
        return;
321
      priv->virtual_mods_enabled |= modifier;
322
    }
323
  else
324
    {
325
      if (!(priv->virtual_mods_enabled & modifier))
326
        return;
327
      priv->virtual_mods_enabled &= ~modifier;
328
    }
329

            
330
  refresh_key_grabs (x11_device);
331
}
332

            
333
static gboolean
334
do_event_dispatch (gpointer user_data)
335
{
336
  AtspiDeviceX11 *device = user_data;
337
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
338
  Display *display = priv->display;
339
  XEvent xevent;
340
  char text[10];
341
  KeySym keysym;
342
  XComposeStatus status;
343
  guint modifiers;
344

            
345
  g_object_ref (device);
346
  while (XPending (display))
347
    {
348
      XNextEvent (display, &xevent);
349
      XEvent keyevent;
350

            
351
      switch (xevent.type)
352
        {
353
        case KeyPress:
354
        case KeyRelease:
355
          XLookupString (&xevent.xkey, text, sizeof (text), &keysym, &status);
356
          modifiers = xevent.xkey.state | priv->virtual_mods_enabled;
357
          if (modifiers & priv->numlock_physical_mask)
358
            {
359
              modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
360
              modifiers &= ~priv->numlock_physical_mask;
361
            }
362
          atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, modifiers, text);
363
          break;
364
        case FocusIn:
365
          refresh_key_grabs (device);
366
          break;
367
        case GenericEvent:
368
          if (xevent.xcookie.extension == priv->xi_opcode)
369
            {
370
              XGetEventData (priv->display, &xevent.xcookie);
371
              XIRawEvent *xiRawEv = (XIRawEvent *) xevent.xcookie.data;
372
              XIDeviceEvent *xiDevEv = (XIDeviceEvent *) xevent.xcookie.data;
373
              switch (xevent.xcookie.evtype)
374
                {
375
                case XI_KeyPress:
376
                case XI_KeyRelease:
377
                  xi2keyevent (xiDevEv, &keyevent);
378
                  XLookupString ((XKeyEvent *) &keyevent, text, sizeof (text), &keysym, &status);
379
                  if (text[0] < ' ')
380
                    text[0] = '\0';
381
                  set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress);
382
                  modifiers = keyevent.xkey.state | priv->virtual_mods_enabled;
383
                  if (modifiers & priv->numlock_physical_mask)
384
                    modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
385
                  if (xiDevEv->deviceid == xiDevEv->sourceid)
386
                    atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, modifiers, text);
387
                  /* otherwise it's probably a duplicate event from a key grab */
388
                  XFreeEventData (priv->display, &xevent.xcookie);
389
                  break;
390
                case FocusIn:
391
                  refresh_key_grabs (device);
392
                  break;
393
                }
394
            }
395
        default:
396
          if (XFilterEvent (&xevent, None))
397
            continue;
398
        }
399
    }
400

            
401
  g_object_unref (device);
402
  return TRUE;
403
}
404

            
405
static gboolean
406
event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
407
{
408
  if (callback)
409
    callback (user_data);
410
  return G_SOURCE_CONTINUE;
411
}
412

            
413
static GSourceFuncs event_funcs = {
414
  event_prepare,
415
  event_check,
416
  event_dispatch,
417
  NULL
418
};
419

            
420
static GSource *
421
display_source_new (Display *display)
422
{
423
  GSource *source = g_source_new (&event_funcs, sizeof (DisplaySource));
424
  DisplaySource *display_source = (DisplaySource *) source;
425
  g_source_set_name (source, "[at-spi2-core] display_source_funcs");
426

            
427
  display_source->display = display;
428

            
429
  return source;
430
}
431

            
432
static void
433
create_event_source (AtspiDeviceX11 *device)
434
{
435
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
436
  DisplaySource *display_source;
437

            
438
  int connection_number = ConnectionNumber (priv->display);
439

            
440
  priv->source = display_source_new (priv->display);
441
  display_source = (DisplaySource *) priv->source;
442

            
443
  g_source_set_priority (priv->source, G_PRIORITY_DEFAULT);
444

            
445
  display_source->event_poll_fd.fd = connection_number;
446
  display_source->event_poll_fd.events = G_IO_IN;
447

            
448
  g_source_add_poll (priv->source, &display_source->event_poll_fd);
449
  g_source_set_can_recurse (priv->source, TRUE);
450
  g_source_set_callback (priv->source, do_event_dispatch, device, NULL);
451
  g_source_attach (priv->source, NULL);
452
}
453

            
454
static gboolean
455
check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier)
456
{
457
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
458
  GSList *l;
459

            
460
  if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK))
461
    return TRUE;
462

            
463
  for (l = priv->modifiers; l; l = l->next)
464
    {
465
      AtspiX11KeyModifier *entry = l->data;
466
      if (entry->modifier == modifier)
467
        return TRUE;
468
    }
469

            
470
  return FALSE;
471
}
472

            
473
static guint
474
get_unused_virtual_modifier (AtspiDeviceX11 *x11_device)
475
{
476
  guint ret = 0x1000;
477

            
478
  while (ret < 0x10000)
479
    {
480
      if (!check_virtual_modifier (x11_device, ret))
481
        return ret;
482
      ret <<= 1;
483
    }
484

            
485
  return 0;
486
}
487

            
488
static guint
489
atspi_device_x11_map_modifier (AtspiDevice *device, gint keycode)
490
{
491
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
492
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
493
  XkbDescPtr desc;
494
  guint ret;
495
  AtspiX11KeyModifier *entry;
496

            
497
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
498

            
499
  if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
500
    {
501
      XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
502
      g_warning ("Passed invalid keycode %d", keycode);
503
      return 0;
504
    }
505

            
506
  ret = desc->map->modmap[keycode];
507
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
508
  if (ret & (ShiftMask | ControlMask))
509
    return ret;
510

            
511
  ret = find_virtual_mapping (x11_device, keycode);
512
  if (ret)
513
    return ret;
514

            
515
  ret = get_unused_virtual_modifier (x11_device);
516

            
517
  entry = g_new (AtspiX11KeyModifier, 1);
518
  entry->keycode = keycode;
519
  entry->modifier = ret;
520
  priv->modifiers = g_slist_append (priv->modifiers, entry);
521

            
522
  return ret;
523
}
524

            
525
static void
526
atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode)
527
{
528
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
529
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
530
  GSList *l;
531

            
532
  for (l = priv->modifiers; l; l = l->next)
533
    {
534
      AtspiX11KeyModifier *entry = l->data;
535
      if (entry->keycode == keycode)
536
        {
537
          priv->modifiers = g_slist_remove (priv->modifiers, entry);
538
          g_free (entry);
539
          return;
540
        }
541
    }
542
}
543

            
544
static guint
545
atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode)
546
{
547
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
548
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
549
  XkbDescPtr desc;
550
  guint ret;
551

            
552
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
553

            
554
  if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
555
    {
556
      XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
557
      g_warning ("Passed invalid keycode %d", keycode);
558
      return 0;
559
    }
560

            
561
  ret = desc->map->modmap[keycode];
562
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
563
  if (ret)
564
    return ret;
565

            
566
  return find_virtual_mapping (x11_device, keycode);
567
}
568

            
569
static void
570
event_listener_cb (AtspiEvent *event, void *user_data)
571
{
572
  AtspiDeviceX11 *x11_device = user_data;
573

            
574
  refresh_key_grabs (x11_device);
575
  g_boxed_free (ATSPI_TYPE_EVENT, event);
576
}
577

            
578
static void
579
atspi_device_x11_init (AtspiDeviceX11 *device)
580
{
581
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
582
  int first_event, first_error;
583
  int focus_revert;
584

            
585
  priv->display = XOpenDisplay ("");
586
  g_return_if_fail (priv->display != NULL);
587
  priv->root_window = DefaultRootWindow (priv->display);
588
  XGetInputFocus (priv->display, &priv->focused_window, &focus_revert);
589

            
590
  if (XQueryExtension (priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error))
591
    {
592
      int major = 2;
593
      int minor = 1;
594
      if (XIQueryVersion (priv->display, &major, &minor) != BadRequest)
595
        {
596
          XIEventMask eventmask;
597
          unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
598

            
599
          eventmask.deviceid = XIAllDevices;
600
          eventmask.mask_len = sizeof (mask);
601
          eventmask.mask = mask;
602

            
603
          XISetMask (mask, XI_KeyPress);
604
          XISetMask (mask, XI_KeyRelease);
605
          XISetMask (mask, XI_ButtonPress);
606
          XISetMask (mask, XI_ButtonRelease);
607
          XISetMask (mask, XI_Motion);
608
          XISelectEvents (priv->display, priv->root_window, &eventmask, 1);
609
          XSelectInput (priv->display, priv->root_window, FocusChangeMask);
610
          create_event_source (device);
611
        }
612
    }
613

            
614
  priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display,
615
                                                      XK_Num_Lock);
616

            
617
  priv->event_listener = atspi_event_listener_new (event_listener_cb, device, NULL);
618
  atspi_event_listener_register (priv->event_listener, "window:activate", NULL);
619
  atspi_event_listener_register (priv->event_listener, "window:deactivate", NULL);
620
}
621

            
622
static void
623
atspi_device_x11_finalize (GObject *object)
624
{
625
  AtspiDeviceX11 *device = ATSPI_DEVICE_X11 (object);
626
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
627

            
628
  while (priv->key_grabs)
629
    {
630
      AtspiX11KeyGrab *grab = priv->key_grabs->data;
631
      disable_key_grab (device, grab);
632
      g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
633
      g_free (grab);
634
      priv->key_grabs = g_slist_remove (priv->key_grabs, grab);
635
    }
636

            
637
  g_slist_free_full (priv->modifiers, g_free);
638
  priv->modifiers = NULL;
639

            
640
  if (priv->source)
641
    {
642
      g_source_destroy ((GSource *) priv->source);
643
      g_source_unref ((GSource *) priv->source);
644
      priv->source = NULL;
645
    }
646

            
647
  /* TODO: deregister event listeners automatically when the listener is finalized */
648
  atspi_event_listener_deregister (priv->event_listener, "window:deactivate", NULL);
649
  atspi_event_listener_deregister (priv->event_listener, "window:activate", NULL);
650
  g_object_unref (priv->event_listener);
651

            
652
  device_x11_parent_class->finalize (object);
653
}
654

            
655
static gboolean
656
atspi_device_x11_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd)
657
{
658
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
659
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
660
  AtspiX11KeyGrab *grab;
661
  gboolean ret;
662

            
663
  grab = g_new0 (AtspiX11KeyGrab, 1);
664
  grab->kd = g_boxed_copy (ATSPI_TYPE_KEY_DEFINITION, kd);
665
  grab->enabled = FALSE;
666
  if (grab_should_be_enabled (x11_device, grab))
667
    ret = enable_key_grab (x11_device, grab);
668
  else
669
    ret = TRUE;
670

            
671
  if (ret)
672
    priv->key_grabs = g_slist_append (priv->key_grabs, grab);
673
  else
674
    {
675
      g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
676
      g_free (grab);
677
    }
678

            
679
  return ret;
680
}
681

            
682
static void
683
atspi_device_x11_remove_key_grab (AtspiDevice *device, guint id)
684
{
685
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
686
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
687
  AtspiKeyDefinition *kd;
688
  GSList *l;
689

            
690
  kd = atspi_device_get_grab_by_id (device, id);
691

            
692
  for (l = priv->key_grabs; l; l = g_slist_next (l))
693
    {
694
      AtspiX11KeyGrab *other = l->data;
695
      if (other->kd->keycode == kd->keycode && other->kd->modifiers == kd->modifiers)
696
        {
697
          disable_key_grab (x11_device, other);
698
          priv->key_grabs = g_slist_remove (priv->key_grabs, other);
699
          return;
700
        }
701
    }
702
}
703

            
704
static guint
705
atspi_device_x11_get_locked_modifiers (AtspiDevice *device)
706
{
707
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
708
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
709
  XkbStateRec state_rec;
710

            
711
  memset (&state_rec, 0, sizeof (state_rec));
712
  XkbGetState (priv->display, XkbUseCoreKbd, &state_rec);
713
  return state_rec.locked_mods;
714
}
715

            
716
static void
717
get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max)
718
{
719
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
720
  XkbDescPtr desc;
721

            
722
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
723
  *min = desc->min_key_code;
724
  *max = desc->max_key_code;
725
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
726
}
727

            
728
static gboolean
729
atspi_device_x11_grab_keyboard (AtspiDevice *device)
730
{
731
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
732
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
733
  int min, max;
734
  gint i;
735

            
736
  g_return_val_if_fail (priv->display != NULL, FALSE);
737
#if 0
738
  /* THis seems like the right thing to do, but it fails for me */
739
  return (XGrabKeyboard (priv->display, priv->focused_window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0;
740
#else
741
  if (priv->keyboard_grabbed)
742
    return TRUE;
743
  priv->keyboard_grabbed = TRUE;
744
  refresh_key_grabs (x11_device);
745

            
746
  get_keycode_range (x11_device, &min, &max);
747
  for (i = min; i < max; i++)
748
    grab_key (x11_device, priv->focused_window, i, 0);
749
  return TRUE;
750
#endif
751
}
752

            
753
static void
754
atspi_device_x11_ungrab_keyboard (AtspiDevice *device)
755
{
756
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
757
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
758
  int min, max;
759
  gint i;
760

            
761
  g_return_if_fail (priv->display != NULL);
762
#if 0
763
  XUngrabKeyboard (priv->display, CurrentTime);
764
#else
765
  if (!priv->keyboard_grabbed)
766
    return;
767
  priv->keyboard_grabbed = FALSE;
768

            
769
  get_keycode_range (x11_device, &min, &max);
770
  for (i = min; i < max; i++)
771
    ungrab_key (x11_device, priv->focused_window, i, 0);
772

            
773
  refresh_key_grabs (x11_device);
774
#endif
775
}
776

            
777
static void
778
atspi_device_x11_generate_mouse_event (AtspiDevice *device, AtspiAccessible *obj, gint x, gint y, const gchar *name, GError **error)
779
{
780
  AtspiPoint *p;
781

            
782
  p = atspi_component_get_position (ATSPI_COMPONENT (obj), ATSPI_COORD_TYPE_SCREEN, error);
783
  if (p->y == -1 && atspi_accessible_get_role (obj, NULL) == ATSPI_ROLE_APPLICATION)
784
    {
785
      g_clear_error (error);
786
      g_free (p);
787
      AtspiAccessible *child = atspi_accessible_get_child_at_index (obj, 0, NULL);
788
      if (child)
789
        {
790
          p = atspi_component_get_position (ATSPI_COMPONENT (child), ATSPI_COORD_TYPE_SCREEN, error);
791
          g_object_unref (child);
792
        }
793
    }
794

            
795
  if (p->y == -1 || p->x == -1)
796
    return;
797

            
798
  x += p->x;
799
  y += p->y;
800
  g_free (p);
801

            
802
  /* TODO: do this in process */
803
  atspi_generate_mouse_event (x, y, name, error);
804
}
805

            
806
static void
807
atspi_device_x11_class_init (AtspiDeviceX11Class *klass)
808
{
809
  AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass);
810
  GObjectClass *object_class = (GObjectClass *) klass;
811

            
812
  device_x11_parent_class = g_type_class_peek_parent (klass);
813
  device_class->add_key_grab = atspi_device_x11_add_key_grab;
814
  device_class->map_modifier = atspi_device_x11_map_modifier;
815
  device_class->unmap_modifier = atspi_device_x11_unmap_modifier;
816
  device_class->get_modifier = atspi_device_x11_get_modifier;
817
  device_class->remove_key_grab = atspi_device_x11_remove_key_grab;
818
  device_class->get_locked_modifiers = atspi_device_x11_get_locked_modifiers;
819
  device_class->grab_keyboard = atspi_device_x11_grab_keyboard;
820
  device_class->ungrab_keyboard = atspi_device_x11_ungrab_keyboard;
821
  device_class->generate_mouse_event = atspi_device_x11_generate_mouse_event;
822
  object_class->finalize = atspi_device_x11_finalize;
823
}
824

            
825
/**
826
 * atspi_device_x11_new:
827
 *
828
 * Creates a new #AtspiDeviceX11.
829
 *
830
 * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceX11.
831
 *
832
 **/
833
AtspiDeviceX11 *
834
atspi_device_x11_new ()
835
{
836
  AtspiDeviceX11 *device = g_object_new (atspi_device_x11_get_type (), NULL);
837

            
838
  return device;
839
}