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->keysym == grab->kd->keysym && (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
  gint grab_keycode;
224

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

            
227
  if (grab_has_active_duplicate (x11_device, grab))
228
    ret = TRUE;
229
  else
230
    {
231
      if (grab->kd->keysym != 0)
232
        grab_keycode = XKeysymToKeycode (priv->display, grab->kd->keysym);
233
      else
234
        grab_keycode = grab->kd->keycode;
235

            
236
      ret = grab_key (x11_device, priv->focused_window, grab_keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
237
    }
238
  grab->enabled = TRUE;
239
  grab->window = priv->focused_window;
240
  return ret;
241
}
242

            
243
static void
244
ungrab_key_aux (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
245
{
246
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
247
  XIGrabModifiers xi_modifiers;
248

            
249
  xi_modifiers.modifiers = modmask;
250
  xi_modifiers.status = 0;
251

            
252
  XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, window, 1, &xi_modifiers);
253
}
254

            
255
static void
256
ungrab_key (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask)
257
{
258
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
259

            
260
  ungrab_key_aux (x11_device, window, keycode, modmask);
261
  if (!(modmask & LockMask))
262
    ungrab_key_aux (x11_device, window, keycode, modmask | LockMask);
263
  if (!(modmask & priv->numlock_physical_mask))
264
    {
265
      ungrab_key_aux (x11_device, window, keycode, modmask | priv->numlock_physical_mask);
266
      if (!(modmask & LockMask))
267
        ungrab_key_aux (x11_device, window, keycode, modmask | LockMask | priv->numlock_physical_mask);
268
    }
269
}
270

            
271
static void
272
disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
273
{
274
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
275
  gint grab_keycode;
276

            
277
  g_return_if_fail (priv->display != NULL);
278

            
279
  if (!grab->enabled)
280
    return;
281

            
282
  grab->enabled = FALSE;
283

            
284
  if (grab_has_active_duplicate (x11_device, grab))
285
    return;
286

            
287
  if (grab->kd->keysym != 0)
288
    grab_keycode = XKeysymToKeycode (priv->display, grab->kd->keysym);
289
  else
290
    grab_keycode = grab->kd->keycode;
291
  ungrab_key (x11_device, grab->window, grab_keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
292
}
293

            
294
static void
295
refresh_key_grabs (AtspiDeviceX11 *x11_device)
296
{
297
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
298
  GSList *l;
299
  int focus_revert;
300

            
301
  XGetInputFocus (priv->display, &priv->focused_window, &focus_revert);
302

            
303
  for (l = priv->key_grabs; l; l = l->next)
304
    {
305
      AtspiX11KeyGrab *grab = l->data;
306
      if (grab->window != priv->focused_window)
307
        disable_key_grab (x11_device, grab);
308
    }
309

            
310
  for (l = priv->key_grabs; l; l = l->next)
311
    {
312
      AtspiX11KeyGrab *grab = l->data;
313
      gboolean new_enabled = grab_should_be_enabled (x11_device, grab);
314
      if (new_enabled && !grab->enabled)
315
        enable_key_grab (x11_device, grab);
316
      else if (grab->enabled && !new_enabled)
317
        disable_key_grab (x11_device, grab);
318
    }
319
}
320

            
321
static void
322
set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled)
323
{
324
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
325
  guint modifier = find_virtual_mapping (x11_device, keycode);
326

            
327
  if (!modifier)
328
    return;
329

            
330
  if (enabled)
331
    {
332
      if (priv->virtual_mods_enabled & modifier)
333
        return;
334
      priv->virtual_mods_enabled |= modifier;
335
    }
336
  else
337
    {
338
      if (!(priv->virtual_mods_enabled & modifier))
339
        return;
340
      priv->virtual_mods_enabled &= ~modifier;
341
    }
342

            
343
  refresh_key_grabs (x11_device);
344
}
345

            
346
static gboolean
347
do_event_dispatch (gpointer user_data)
348
{
349
  AtspiDeviceX11 *device = user_data;
350
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
351
  Display *display = priv->display;
352
  XEvent xevent;
353
  char text[10];
354
  KeySym keysym;
355
  XComposeStatus status;
356
  guint modifiers;
357

            
358
  g_object_ref (device);
359
  while (XPending (display))
360
    {
361
      XNextEvent (display, &xevent);
362
      XEvent keyevent;
363

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

            
414
  g_object_unref (device);
415
  return TRUE;
416
}
417

            
418
static gboolean
419
event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
420
{
421
  if (callback)
422
    callback (user_data);
423
  return G_SOURCE_CONTINUE;
424
}
425

            
426
static GSourceFuncs event_funcs = {
427
  event_prepare,
428
  event_check,
429
  event_dispatch,
430
  NULL
431
};
432

            
433
static GSource *
434
display_source_new (Display *display)
435
{
436
  GSource *source = g_source_new (&event_funcs, sizeof (DisplaySource));
437
  DisplaySource *display_source = (DisplaySource *) source;
438
  g_source_set_name (source, "[at-spi2-core] display_source_funcs");
439

            
440
  display_source->display = display;
441

            
442
  return source;
443
}
444

            
445
static void
446
create_event_source (AtspiDeviceX11 *device)
447
{
448
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
449
  DisplaySource *display_source;
450

            
451
  int connection_number = ConnectionNumber (priv->display);
452

            
453
  priv->source = display_source_new (priv->display);
454
  display_source = (DisplaySource *) priv->source;
455

            
456
  g_source_set_priority (priv->source, G_PRIORITY_DEFAULT);
457

            
458
  display_source->event_poll_fd.fd = connection_number;
459
  display_source->event_poll_fd.events = G_IO_IN;
460

            
461
  g_source_add_poll (priv->source, &display_source->event_poll_fd);
462
  g_source_set_can_recurse (priv->source, TRUE);
463
  g_source_set_callback (priv->source, do_event_dispatch, device, NULL);
464
  g_source_attach (priv->source, NULL);
465
}
466

            
467
static gboolean
468
check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier)
469
{
470
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
471
  GSList *l;
472

            
473
  if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK))
474
    return TRUE;
475

            
476
  for (l = priv->modifiers; l; l = l->next)
477
    {
478
      AtspiX11KeyModifier *entry = l->data;
479
      if (entry->modifier == modifier)
480
        return TRUE;
481
    }
482

            
483
  return FALSE;
484
}
485

            
486
static guint
487
get_unused_virtual_modifier (AtspiDeviceX11 *x11_device)
488
{
489
  guint ret = 0x1000;
490

            
491
  while (ret < 0x10000)
492
    {
493
      if (!check_virtual_modifier (x11_device, ret))
494
        return ret;
495
      ret <<= 1;
496
    }
497

            
498
  return 0;
499
}
500

            
501
static guint
502
atspi_device_x11_map_modifier (AtspiDevice *device, gint keycode)
503
{
504
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
505
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
506
  XkbDescPtr desc;
507
  guint ret;
508
  AtspiX11KeyModifier *entry;
509

            
510
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
511

            
512
  if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
513
    {
514
      XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
515
      g_warning ("Passed invalid keycode %d", keycode);
516
      return 0;
517
    }
518

            
519
  ret = desc->map->modmap[keycode];
520
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
521
  if (ret & (ShiftMask | ControlMask))
522
    return ret;
523

            
524
  ret = find_virtual_mapping (x11_device, keycode);
525
  if (ret)
526
    return ret;
527

            
528
  ret = get_unused_virtual_modifier (x11_device);
529

            
530
  entry = g_new (AtspiX11KeyModifier, 1);
531
  entry->keycode = keycode;
532
  entry->modifier = ret;
533
  priv->modifiers = g_slist_append (priv->modifiers, entry);
534

            
535
  return ret;
536
}
537

            
538
static void
539
atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode)
540
{
541
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
542
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
543
  GSList *l;
544

            
545
  for (l = priv->modifiers; l; l = l->next)
546
    {
547
      AtspiX11KeyModifier *entry = l->data;
548
      if (entry->keycode == keycode)
549
        {
550
          priv->modifiers = g_slist_remove (priv->modifiers, entry);
551
          g_free (entry);
552
          return;
553
        }
554
    }
555
}
556

            
557
static guint
558
atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode)
559
{
560
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
561
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
562
  XkbDescPtr desc;
563
  guint ret;
564

            
565
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
566

            
567
  if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
568
    {
569
      XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
570
      g_warning ("Passed invalid keycode %d", keycode);
571
      return 0;
572
    }
573

            
574
  ret = desc->map->modmap[keycode];
575
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
576
  if (ret)
577
    return ret;
578

            
579
  return find_virtual_mapping (x11_device, keycode);
580
}
581

            
582
static void
583
event_listener_cb (AtspiEvent *event, void *user_data)
584
{
585
  AtspiDeviceX11 *x11_device = user_data;
586

            
587
  refresh_key_grabs (x11_device);
588
  g_boxed_free (ATSPI_TYPE_EVENT, event);
589
}
590

            
591
static void
592
atspi_device_x11_init (AtspiDeviceX11 *device)
593
{
594
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
595
  int first_event, first_error;
596
  int focus_revert;
597

            
598
  priv->display = XOpenDisplay ("");
599
  g_return_if_fail (priv->display != NULL);
600
  priv->root_window = DefaultRootWindow (priv->display);
601
  XGetInputFocus (priv->display, &priv->focused_window, &focus_revert);
602

            
603
  if (XQueryExtension (priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error))
604
    {
605
      int major = 2;
606
      int minor = 1;
607
      if (XIQueryVersion (priv->display, &major, &minor) != BadRequest)
608
        {
609
          XIEventMask eventmask;
610
          unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
611

            
612
          eventmask.deviceid = XIAllDevices;
613
          eventmask.mask_len = sizeof (mask);
614
          eventmask.mask = mask;
615

            
616
          XISetMask (mask, XI_KeyPress);
617
          XISetMask (mask, XI_KeyRelease);
618
          XISetMask (mask, XI_ButtonPress);
619
          XISetMask (mask, XI_ButtonRelease);
620
          XISetMask (mask, XI_Motion);
621
          XISelectEvents (priv->display, priv->root_window, &eventmask, 1);
622
          XSelectInput (priv->display, priv->root_window, FocusChangeMask);
623
          create_event_source (device);
624
        }
625
    }
626

            
627
  priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display,
628
                                                      XK_Num_Lock);
629

            
630
  priv->event_listener = atspi_event_listener_new (event_listener_cb, device, NULL);
631
  atspi_event_listener_register (priv->event_listener, "window:activate", NULL);
632
  atspi_event_listener_register (priv->event_listener, "window:deactivate", NULL);
633
}
634

            
635
static void
636
atspi_device_x11_finalize (GObject *object)
637
{
638
  AtspiDeviceX11 *device = ATSPI_DEVICE_X11 (object);
639
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
640

            
641
  while (priv->key_grabs)
642
    {
643
      AtspiX11KeyGrab *grab = priv->key_grabs->data;
644
      disable_key_grab (device, grab);
645
      g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
646
      g_free (grab);
647
      priv->key_grabs = g_slist_remove (priv->key_grabs, grab);
648
    }
649

            
650
  g_slist_free_full (priv->modifiers, g_free);
651
  priv->modifiers = NULL;
652

            
653
  if (priv->source)
654
    {
655
      g_source_destroy ((GSource *) priv->source);
656
      g_source_unref ((GSource *) priv->source);
657
      priv->source = NULL;
658
    }
659

            
660
  /* TODO: deregister event listeners automatically when the listener is finalized */
661
  atspi_event_listener_deregister (priv->event_listener, "window:deactivate", NULL);
662
  atspi_event_listener_deregister (priv->event_listener, "window:activate", NULL);
663
  g_object_unref (priv->event_listener);
664

            
665
  device_x11_parent_class->finalize (object);
666
}
667

            
668
static gboolean
669
atspi_device_x11_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd)
670
{
671
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
672
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
673
  AtspiX11KeyGrab *grab;
674
  gboolean ret;
675

            
676
  grab = g_new0 (AtspiX11KeyGrab, 1);
677
  grab->kd = g_boxed_copy (ATSPI_TYPE_KEY_DEFINITION, kd);
678
  grab->enabled = FALSE;
679
  if (grab_should_be_enabled (x11_device, grab))
680
    ret = enable_key_grab (x11_device, grab);
681
  else
682
    ret = TRUE;
683

            
684
  if (ret)
685
    priv->key_grabs = g_slist_append (priv->key_grabs, grab);
686
  else
687
    {
688
      g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
689
      g_free (grab);
690
    }
691

            
692
  return ret;
693
}
694

            
695
static void
696
atspi_device_x11_remove_key_grab (AtspiDevice *device, guint id)
697
{
698
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
699
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
700
  AtspiKeyDefinition *kd;
701
  GSList *l;
702

            
703
  kd = atspi_device_get_grab_by_id (device, id);
704

            
705
  for (l = priv->key_grabs; l; l = g_slist_next (l))
706
    {
707
      AtspiX11KeyGrab *other = l->data;
708
      if (((kd->keycode && other->kd->keycode == kd->keycode) || (kd->keysym && other->kd->keysym == kd->keysym)) && other->kd->modifiers == kd->modifiers)
709
        {
710
          disable_key_grab (x11_device, other);
711
          priv->key_grabs = g_slist_remove (priv->key_grabs, other);
712
          return;
713
        }
714
    }
715
}
716

            
717
static guint
718
atspi_device_x11_get_locked_modifiers (AtspiDevice *device)
719
{
720
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
721
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
722
  XkbStateRec state_rec;
723

            
724
  memset (&state_rec, 0, sizeof (state_rec));
725
  XkbGetState (priv->display, XkbUseCoreKbd, &state_rec);
726
  return state_rec.locked_mods;
727
}
728

            
729
static void
730
get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max)
731
{
732
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
733
  XkbDescPtr desc;
734

            
735
  desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
736
  *min = desc->min_key_code;
737
  *max = desc->max_key_code;
738
  XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
739
}
740

            
741
static gboolean
742
atspi_device_x11_grab_keyboard (AtspiDevice *device)
743
{
744
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
745
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
746
  int min, max;
747
  gint i;
748

            
749
  g_return_val_if_fail (priv->display != NULL, FALSE);
750
#if 0
751
  /* THis seems like the right thing to do, but it fails for me */
752
  return (XGrabKeyboard (priv->display, priv->focused_window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0;
753
#else
754
  if (priv->keyboard_grabbed)
755
    return TRUE;
756
  priv->keyboard_grabbed = TRUE;
757
  refresh_key_grabs (x11_device);
758

            
759
  get_keycode_range (x11_device, &min, &max);
760
  for (i = min; i < max; i++)
761
    grab_key (x11_device, priv->focused_window, i, 0);
762
  return TRUE;
763
#endif
764
}
765

            
766
static void
767
atspi_device_x11_ungrab_keyboard (AtspiDevice *device)
768
{
769
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
770
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
771
  int min, max;
772
  gint i;
773

            
774
  g_return_if_fail (priv->display != NULL);
775
#if 0
776
  XUngrabKeyboard (priv->display, CurrentTime);
777
#else
778
  if (!priv->keyboard_grabbed)
779
    return;
780
  priv->keyboard_grabbed = FALSE;
781

            
782
  get_keycode_range (x11_device, &min, &max);
783
  for (i = min; i < max; i++)
784
    ungrab_key (x11_device, priv->focused_window, i, 0);
785

            
786
  refresh_key_grabs (x11_device);
787
#endif
788
}
789

            
790
static void
791
atspi_device_x11_generate_mouse_event (AtspiDevice *device, AtspiAccessible *obj, gint x, gint y, const gchar *name, GError **error)
792
{
793
  AtspiPoint *p;
794

            
795
  p = atspi_component_get_position (ATSPI_COMPONENT (obj), ATSPI_COORD_TYPE_SCREEN, error);
796
  if (p->y == -1 && atspi_accessible_get_role (obj, NULL) == ATSPI_ROLE_APPLICATION)
797
    {
798
      g_clear_error (error);
799
      g_free (p);
800
      AtspiAccessible *child = atspi_accessible_get_child_at_index (obj, 0, NULL);
801
      if (child)
802
        {
803
          p = atspi_component_get_position (ATSPI_COMPONENT (child), ATSPI_COORD_TYPE_SCREEN, error);
804
          g_object_unref (child);
805
        }
806
    }
807

            
808
  if (p->y == -1 || p->x == -1)
809
    return;
810

            
811
  x += p->x;
812
  y += p->y;
813
  g_free (p);
814

            
815
  /* TODO: do this in process */
816
  atspi_generate_mouse_event (x, y, name, error);
817
}
818

            
819
static guint
820
atspi_device_x11_map_keysym_modifier (AtspiDevice *device, guint keysym)
821
{
822
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
823
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
824

            
825
  gint keycode = XKeysymToKeycode (priv->display, keysym);
826
  return atspi_device_x11_map_modifier (device, keycode);
827
}
828

            
829
static void
830
atspi_device_x11_unmap_keysym_modifier (AtspiDevice *device, guint keysym)
831
{
832
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
833
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
834

            
835
  gint keycode = XKeysymToKeycode (priv->display, keysym);
836
  atspi_device_x11_unmap_modifier (device, keycode);
837
}
838

            
839
static guint
840
atspi_device_x11_get_keysym_modifier (AtspiDevice *device, guint keysym)
841
{
842
  AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
843
  AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
844

            
845
  gint keycode = XKeysymToKeycode (priv->display, keysym);
846
  return atspi_device_x11_get_modifier (device, keycode);
847
}
848

            
849
static void
850
atspi_device_x11_class_init (AtspiDeviceX11Class *klass)
851
{
852
  AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass);
853
  GObjectClass *object_class = (GObjectClass *) klass;
854

            
855
  device_x11_parent_class = g_type_class_peek_parent (klass);
856
  device_class->add_key_grab = atspi_device_x11_add_key_grab;
857
  device_class->map_modifier = atspi_device_x11_map_modifier;
858
  device_class->unmap_modifier = atspi_device_x11_unmap_modifier;
859
  device_class->get_modifier = atspi_device_x11_get_modifier;
860
  device_class->remove_key_grab = atspi_device_x11_remove_key_grab;
861
  device_class->get_locked_modifiers = atspi_device_x11_get_locked_modifiers;
862
  device_class->grab_keyboard = atspi_device_x11_grab_keyboard;
863
  device_class->ungrab_keyboard = atspi_device_x11_ungrab_keyboard;
864
  device_class->generate_mouse_event = atspi_device_x11_generate_mouse_event;
865
  device_class->map_keysym_modifier = atspi_device_x11_map_keysym_modifier;
866
  device_class->unmap_keysym_modifier = atspi_device_x11_unmap_keysym_modifier;
867
  device_class->get_keysym_modifier = atspi_device_x11_get_keysym_modifier;
868
  object_class->finalize = atspi_device_x11_finalize;
869
}
870

            
871
/**
872
 * atspi_device_x11_new:
873
 *
874
 * Creates a new #AtspiDeviceX11.
875
 *
876
 * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceX11.
877
 *
878
 **/
879
AtspiDeviceX11 *
880
atspi_device_x11_new ()
881
{
882
  AtspiDeviceX11 *device = g_object_new (atspi_device_x11_get_type (), NULL);
883

            
884
  return device;
885
}