Protecting against potential NULL pointer dereference
[platform/upstream/at-spi2-core.git] / atspi / atspi-device-x11.c
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-private.h"
24 #include "atspi-device-x11.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/extensions/XInput2.h>
29 #include <X11/XKBlib.h>
30
31
32 #define ATSPI_VIRTUAL_MODIFIER_MASK 0x0000f000
33
34 typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private;
35 struct _AtspiDeviceX11Private
36 {
37   Display *display;
38   Window window;
39   GSource *source;
40   int xi_opcode;
41   int device_id;
42   int device_id_alt;
43   GSList *modifiers;
44   GSList *key_grabs;
45   guint virtual_mods_enabled;
46   gboolean keyboard_grabbed;
47   unsigned int numlock_physical_mask;
48 };
49
50 GObjectClass *device_x11_parent_class;
51
52 typedef struct _DisplaySource
53 {
54   GSource source;
55   
56   Display *display;
57   GPollFD  event_poll_fd;
58 } DisplaySource;
59
60 typedef struct
61 {
62   guint keycode;
63   guint modifier;
64 } AtspiX11KeyModifier;
65
66 typedef struct
67 {
68   AtspiKeyDefinition *kd;
69   gboolean enabled;
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,
131                           ATSPI_TYPE_DEVICE,
132                           G_ADD_PRIVATE (AtspiDeviceX11))
133
134
135 static guint
136 find_virtual_mapping (AtspiDeviceX11 *x11_device, gint keycode)
137 {
138   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
139   GSList *l;
140
141   for (l = priv->modifiers; l; l = l->next)
142   {
143     AtspiX11KeyModifier *entry = l->data;
144     if (entry->keycode == keycode)
145       return entry->modifier;
146   }
147
148   return 0;
149 }
150
151 static gboolean
152 grab_should_be_enabled (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
153 {
154   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
155
156   /* If the whole keyboard is grabbed, then all keys are grabbed elsewhere */
157   if (priv->keyboard_grabbed)
158     return FALSE;
159
160   guint virtual_mods_used = grab->kd->modifiers & ATSPI_VIRTUAL_MODIFIER_MASK;
161   return ((priv->virtual_mods_enabled & virtual_mods_used) == virtual_mods_used);
162 }
163
164 static gboolean
165 grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
166 {
167   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
168   GSList *l;
169
170   for (l = priv->key_grabs; l; l = l->next)
171   {
172     AtspiX11KeyGrab *other = l->data;
173     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))
174       return TRUE;
175   }
176   return FALSE;
177 }
178
179 static void
180 grab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask)
181 {
182   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
183   XIGrabModifiers xi_modifiers;
184   XIEventMask eventmask;
185                         unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
186
187   xi_modifiers.modifiers = modmask;
188   xi_modifiers.status = 0;
189
190                         eventmask.deviceid = XIAllDevices;
191                         eventmask.mask_len = sizeof(mask);
192                         eventmask.mask = mask;
193
194                         XISetMask (mask, XI_KeyPress);
195                         XISetMask (mask, XI_KeyRelease);
196
197   XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers);
198 }
199
200 static void
201 grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask)
202 {
203   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
204
205   grab_key_aux (x11_device, keycode, modmask);
206   if (!(modmask & LockMask))
207     grab_key_aux (x11_device, keycode, modmask | LockMask);
208   if (!(modmask & priv->numlock_physical_mask))
209   {
210     grab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask);
211     if (!(modmask & LockMask))
212       grab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask);
213   }
214 }
215
216 static void
217 enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
218 {
219   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
220
221   g_return_if_fail (priv->display != NULL);
222
223   if (!grab_has_active_duplicate (x11_device, grab))
224     grab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
225   grab->enabled = TRUE;
226 }
227
228 static void
229 ungrab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask)
230 {
231   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
232   XIGrabModifiers xi_modifiers;
233
234   xi_modifiers.modifiers = modmask;
235   xi_modifiers.status = 0;
236
237   XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, sizeof(xi_modifiers), &xi_modifiers);
238 }
239
240 static void
241 ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask)
242 {
243   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
244
245   ungrab_key_aux (x11_device, keycode, modmask);
246   if (!(modmask & LockMask))
247     ungrab_key_aux (x11_device, keycode, modmask | LockMask);
248   if (!(modmask & priv->numlock_physical_mask))
249   {
250     ungrab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask);
251     if (!(modmask & LockMask))
252       ungrab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask);
253   }
254 }
255
256 static void
257 disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab)
258 {
259   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
260
261   g_return_if_fail (priv->display != NULL);
262
263   if (!grab->enabled)
264     return;
265
266   grab->enabled = FALSE;
267
268   if (grab_has_active_duplicate (x11_device, grab))
269     return;
270
271   ungrab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK);
272 }
273
274 static void
275 refresh_key_grabs (AtspiDeviceX11 *x11_device)
276 {
277   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
278   GSList *l;
279
280   for (l = priv->key_grabs; l; l = l->next)
281   {
282     AtspiX11KeyGrab *grab = l->data;
283     gboolean new_enabled = grab_should_be_enabled (x11_device, grab);
284     if (new_enabled && !grab->enabled)
285       enable_key_grab (x11_device, grab);
286     else if (grab->enabled && !new_enabled)
287       disable_key_grab (x11_device, grab);
288   }
289 }
290
291 static void
292 set_virtual_modifier (AtspiDeviceX11 *x11_device, gint keycode, gboolean enabled)
293 {
294   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
295   guint modifier = find_virtual_mapping (x11_device, keycode);
296
297   if (!modifier)
298     return;
299
300   if (enabled)
301   {
302     if (priv->virtual_mods_enabled & modifier)
303       return;
304     priv->virtual_mods_enabled |= modifier;
305   }
306   else
307   {
308     if (!(priv->virtual_mods_enabled & modifier))
309       return;
310     priv->virtual_mods_enabled &= ~modifier;
311   }
312
313   refresh_key_grabs (x11_device);
314 }
315
316 static gboolean
317 do_event_dispatch (gpointer user_data)
318 {
319   AtspiDeviceX11 *device = user_data;
320   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
321   Display *display = priv->display;
322   XEvent xevent;
323   char text[10];
324   KeySym keysym;
325   XComposeStatus status;
326   guint modifiers;
327  
328   while (XPending (display))
329   {
330     XNextEvent (display, &xevent);
331   XEvent keyevent;
332
333     switch (xevent.type)
334     {
335     case KeyPress:
336     case KeyRelease:
337       XLookupString(&xevent.xkey, text, sizeof (text), &keysym, &status);
338       modifiers = xevent.xkey.state | priv->virtual_mods_enabled;
339       if (modifiers & priv->numlock_physical_mask)
340       {
341         modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
342         modifiers &= ~priv->numlock_physical_mask;
343       }
344       atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, modifiers, text);
345       break;
346     case GenericEvent:
347       if (xevent.xcookie.extension == priv->xi_opcode)
348       {
349         XGetEventData(priv->display, &xevent.xcookie);
350         XIRawEvent *xiRawEv = (XIRawEvent *) xevent.xcookie.data;
351         XIDeviceEvent *xiDevEv = (XIDeviceEvent *) xevent.xcookie.data;
352         switch (xevent.xcookie.evtype)
353         {
354         case XI_KeyPress:
355         case XI_KeyRelease:
356           xi2keyevent (xiDevEv, &keyevent);
357           XLookupString((XKeyEvent *)&keyevent, text, sizeof (text), &keysym, &status);
358           if (text[0] < ' ')
359             text[0] = '\0';
360           /* The deviceid can change. Would be nice to find a better way of
361              handling this */
362           if (priv->device_id && priv->device_id_alt && xiDevEv->deviceid != priv->device_id && xiDevEv->deviceid != priv->device_id_alt)
363             priv->device_id = priv->device_id_alt = 0;
364           else if (priv->device_id && !priv->device_id_alt && xiDevEv->deviceid != priv->device_id)
365             priv->device_id_alt = xiDevEv->deviceid;
366           if (!priv->device_id)
367             priv->device_id = xiDevEv->deviceid;
368           set_virtual_modifier (device, xiRawEv->detail, xevent.xcookie.evtype == XI_KeyPress);
369           modifiers = keyevent.xkey.state | priv->virtual_mods_enabled;
370           if (modifiers & priv->numlock_physical_mask)
371             modifiers |= (1 << ATSPI_MODIFIER_NUMLOCK);
372           if (xiDevEv->deviceid == priv->device_id)
373             atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.xcookie.evtype == XI_KeyPress), xiRawEv->detail, keysym, modifiers, text);
374           /* otherwise it's probably a duplicate event from a key grab */
375           XFreeEventData (priv->display, &xevent.xcookie);
376           break;
377         }
378       }
379     default:
380       if (XFilterEvent (&xevent, None))
381         continue;
382     }
383   }
384   return TRUE;
385 }
386
387 static gboolean  
388 event_dispatch (GSource *source, GSourceFunc callback, gpointer  user_data)
389 {
390   if (callback)
391     callback (user_data);
392   return G_SOURCE_CONTINUE;
393 }
394
395 static GSourceFuncs event_funcs = {
396   event_prepare,
397   event_check,
398   event_dispatch,
399   NULL
400 };
401
402 static GSource *
403 display_source_new (Display *display)
404 {
405   GSource *source = g_source_new (&event_funcs, sizeof (DisplaySource));
406   DisplaySource *display_source = (DisplaySource *) source;
407   g_source_set_name (source, "[at-spi2-core] display_source_funcs");
408   
409   display_source->display = display;
410   
411   return source;
412 }
413
414 static void 
415 create_event_source (AtspiDeviceX11 *device)
416 {
417   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
418   DisplaySource *display_source;
419
420   int connection_number = ConnectionNumber (priv->display);
421
422   priv->source = display_source_new (priv->display);
423   display_source = (DisplaySource *)priv->source;
424
425   g_source_set_priority (priv->source, G_PRIORITY_DEFAULT);
426   
427   display_source->event_poll_fd.fd = connection_number;
428   display_source->event_poll_fd.events = G_IO_IN;
429   
430   g_source_add_poll (priv->source, &display_source->event_poll_fd);
431   g_source_set_can_recurse (priv->source, TRUE);
432   g_source_set_callback (priv->source, do_event_dispatch, device, NULL);
433   g_source_attach (priv->source, NULL);
434 }
435
436 static gboolean
437 check_virtual_modifier (AtspiDeviceX11 *x11_device, guint modifier)
438 {
439   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
440   GSList *l;
441
442   if (modifier == (1 << ATSPI_MODIFIER_NUMLOCK))
443     return TRUE;
444
445   for (l = priv->modifiers; l; l = l->next)
446   {
447     AtspiX11KeyModifier *entry = l->data;
448     if (entry->modifier == modifier)
449       return TRUE;
450   }
451
452   return FALSE;
453 }
454
455 static guint
456 get_unused_virtual_modifier (AtspiDeviceX11 *x11_device)
457 {
458   guint ret = 0x1000;
459
460   while (ret < 0x10000)
461   {
462     if (!check_virtual_modifier (x11_device, ret))
463       return ret;
464     ret <<= 1;
465   }
466
467   return 0;
468 }
469
470 static guint
471 atspi_device_x11_map_modifier (AtspiDevice *device, gint keycode)
472 {
473   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
474   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
475   XkbDescPtr desc;
476   guint ret;
477   AtspiX11KeyModifier *entry;
478
479   desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
480
481   if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
482   {
483     XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
484     g_warning ("Passed invalid keycode %d", keycode);
485     return 0;
486   }
487
488   ret = desc->map->modmap[keycode];
489   XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
490   if (ret & (ShiftMask | ControlMask))
491     return ret;
492
493   ret = find_virtual_mapping (x11_device, keycode);
494   if (ret)
495     return ret;
496
497   ret = get_unused_virtual_modifier (x11_device);
498
499   entry = g_new (AtspiX11KeyModifier, 1);
500   entry->keycode = keycode;
501   entry->modifier = ret;
502   priv->modifiers = g_slist_append (priv->modifiers, entry);
503
504   return ret;
505 }
506
507 static void
508 atspi_device_x11_unmap_modifier (AtspiDevice *device, gint keycode)
509 {
510   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
511   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
512   GSList *l;
513
514   for (l = priv->modifiers; l; l = l->next)
515   {
516     AtspiX11KeyModifier *entry = l->data;
517     if (entry->keycode == keycode)
518     {
519       priv->modifiers = g_slist_remove (priv->modifiers, entry);
520       g_free (entry);
521       return;
522     }
523   }
524 }
525
526 static guint
527 atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode)
528 {
529   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
530   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
531   XkbDescPtr desc;
532   guint ret;
533
534   desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
535
536   if (keycode < desc->min_key_code || keycode >= desc->max_key_code)
537   {
538     XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
539     g_warning ("Passed invalid keycode %d", keycode);
540     return 0;
541   }
542
543   ret = desc->map->modmap[keycode];
544   XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
545   if (ret)
546     return ret;
547
548   return find_virtual_mapping (x11_device, keycode);
549 }
550
551 static void
552 atspi_device_x11_init (AtspiDeviceX11 *device)
553 {
554   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
555   int first_event, first_error;
556
557   priv->display=XOpenDisplay("");
558   g_return_if_fail (priv->display != NULL);
559   priv->window = DefaultRootWindow(priv->display);
560
561   if (XQueryExtension(priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error)) 
562   {
563     int major = 2;
564     int minor = 1;
565     if (XIQueryVersion(priv->display, &major, &minor) != BadRequest)
566     {
567       XIEventMask eventmask;
568       unsigned char mask[XIMaskLen (XI_LASTEVENT)] = { 0 };
569
570       eventmask.deviceid = XIAllDevices;
571       eventmask.mask_len = sizeof(mask);
572       eventmask.mask = mask;
573
574       XISetMask (mask, XI_KeyPress);
575       XISetMask (mask, XI_KeyRelease);
576       XISetMask (mask, XI_ButtonPress);
577       XISetMask (mask, XI_ButtonRelease);
578       XISetMask (mask, XI_Motion);
579       XISelectEvents (priv->display, priv->window, &eventmask, 1);
580       create_event_source (device);
581     }
582   }
583
584   priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display,
585                                                       XK_Num_Lock);
586 }
587
588 static void
589 atspi_device_x11_finalize (GObject *object)
590 {
591   AtspiDeviceX11 *device = ATSPI_DEVICE_X11 (object);
592   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device);
593   GSList *l;
594
595   for (l = priv->key_grabs; l; l = l->next)
596   {
597     AtspiX11KeyGrab *grab = l->data;
598     disable_key_grab (device, grab);
599     g_boxed_free (ATSPI_TYPE_KEY_DEFINITION, grab->kd);
600     g_free (grab);
601   }
602   g_slist_free (priv->key_grabs);
603   priv->key_grabs = NULL;
604
605   g_slist_free_full (priv->modifiers, g_free);
606   priv->modifiers = NULL;
607
608   if (priv->source)
609   {
610     g_source_destroy ((GSource *) priv->source);
611     g_source_unref ((GSource *) priv->source);
612     priv->source = NULL;
613     }
614
615   device_x11_parent_class->finalize (object);
616 }
617
618
619 static void
620 atspi_device_x11_add_key_grab (AtspiDevice *device, AtspiKeyDefinition *kd)
621 {
622   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
623   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
624   AtspiX11KeyGrab *grab;
625
626   grab = g_new (AtspiX11KeyGrab, 1);
627   grab->kd = g_boxed_copy (ATSPI_TYPE_KEY_DEFINITION, kd);
628   grab->enabled = FALSE;
629   priv->key_grabs = g_slist_append (priv->key_grabs, grab);
630   if (grab_should_be_enabled (x11_device, grab))
631     enable_key_grab (x11_device, grab);
632 }
633
634 static void
635 atspi_device_x11_remove_key_grab (AtspiDevice *device, guint id)
636 {
637   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
638   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
639   AtspiKeyDefinition *kd;
640   GSList *l;
641
642   kd = atspi_device_get_grab_by_id (device, id);
643
644   for (l = priv->key_grabs; l; l = g_slist_next (l))
645   {
646     AtspiX11KeyGrab *other = l->data;
647     if (other->kd->keycode == kd->keycode && other->kd->modifiers == kd->modifiers)
648     {
649       disable_key_grab (x11_device, other);
650       priv->key_grabs = g_slist_remove (priv->key_grabs, other);
651       return;
652     }
653   }
654 }
655
656 static guint
657 atspi_device_x11_get_locked_modifiers (AtspiDevice *device)
658 {
659   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
660   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
661   XkbStateRec state_rec;
662
663   memset (&state_rec, 0, sizeof (state_rec));
664   XkbGetState (priv->display, XkbUseCoreKbd, &state_rec);
665   return state_rec.locked_mods;
666 }
667
668 static void
669 get_keycode_range (AtspiDeviceX11 *x11_device, int *min, int *max)
670 {
671   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
672   XkbDescPtr desc;
673
674   desc = XkbGetMap (priv->display, XkbModifierMapMask, XkbUseCoreKbd);
675   *min = desc->min_key_code;
676   *max = desc->max_key_code;
677   XkbFreeKeyboard (desc, XkbModifierMapMask, TRUE);
678 }
679
680 static gboolean
681 atspi_device_x11_grab_keyboard (AtspiDevice *device)
682 {
683   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
684   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
685   int min, max;
686   gint i;
687
688   g_return_val_if_fail (priv->display != NULL, FALSE);
689 #if 0
690   /* THis seems like the right thing to do, but it fails for me */
691   return (XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0;
692 #else
693   if (priv->keyboard_grabbed)
694     return TRUE;
695   priv->keyboard_grabbed = TRUE;
696   refresh_key_grabs (x11_device);
697
698   get_keycode_range (x11_device, &min, &max);
699   for (i = min; i < max; i++)
700     grab_key (x11_device, i, 0);
701   return TRUE;
702 #endif
703 }
704
705 static void
706 atspi_device_x11_ungrab_keyboard (AtspiDevice *device)
707 {
708   AtspiDeviceX11 *x11_device = ATSPI_DEVICE_X11 (device);
709   AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device);
710   int min, max;
711   gint i;
712
713   g_return_if_fail (priv->display != NULL);
714 #if 0
715   XUngrabKeyboard (priv->display, CurrentTime);
716 #else
717   if (!priv->keyboard_grabbed)
718     return;
719   priv->keyboard_grabbed = FALSE;
720
721   get_keycode_range (x11_device, &min, &max);
722   for (i = min; i < max; i++)
723     ungrab_key (x11_device, i, 0);
724
725   refresh_key_grabs (x11_device);
726 #endif
727 }
728
729 static void
730 atspi_device_x11_class_init (AtspiDeviceX11Class *klass)
731 {
732   AtspiDeviceClass *device_class = ATSPI_DEVICE_CLASS (klass);
733   GObjectClass *object_class = (GObjectClass *) klass;
734
735   device_x11_parent_class = g_type_class_peek_parent (klass);
736   device_class->add_key_grab = atspi_device_x11_add_key_grab;
737   device_class->map_modifier = atspi_device_x11_map_modifier;
738   device_class->unmap_modifier = atspi_device_x11_unmap_modifier;
739   device_class->get_modifier = atspi_device_x11_get_modifier;
740   device_class->remove_key_grab = atspi_device_x11_remove_key_grab;
741   device_class->get_locked_modifiers = atspi_device_x11_get_locked_modifiers;
742   device_class->grab_keyboard = atspi_device_x11_grab_keyboard;
743   device_class->ungrab_keyboard = atspi_device_x11_ungrab_keyboard;
744   object_class->finalize = atspi_device_x11_finalize;
745 }
746
747 /**
748  * atspi_device_x11_new:
749  *
750  * Creates a new #AtspiDeviceX11.
751  *
752  * Returns: (transfer full): a pointer to a newly-created #AtspiDeviceX11.
753  *
754  **/
755 AtspiDeviceX11 *
756 atspi_device_x11_new ()
757 {
758   AtspiDeviceX11 *device = g_object_new (atspi_device_x11_get_type (), NULL);
759
760   return device;
761 }