Fix for 107988, tweak to deviceeventcontroller.c to be less aggressive
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
1 /* AT-SPI - Assistive Technology Service Provider Interface
2  *
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* deviceeventcontroller.c: implement the DeviceEventController interface */
25
26 #include <config.h>
27
28 #undef  SPI_XKB_DEBUG
29 #undef  SPI_DEBUG
30 #define  SPI_KEYEVENT_DEBUG
31
32 #include <string.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <sys/time.h>
36 #include <bonobo/bonobo-exception.h>
37
38 #include <X11/Xlib.h>
39 #include <X11/extensions/XTest.h>
40 #include <X11/XKBlib.h>
41 #define XK_MISCELLANY
42 #include <X11/keysymdef.h>
43 #include <gdk/gdk.h>
44 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
45 #include <gdk/gdkkeysyms.h>
46 #include <gdk/gdkwindow.h>
47
48 #include "../libspi/spi-private.h"
49 #include "deviceeventcontroller.h"
50
51 /* Our parent Gtk object type */
52 #define PARENT_TYPE BONOBO_TYPE_OBJECT
53
54 /* A pointer to our parent object class */
55 static GObjectClass *spi_device_event_controller_parent_class;
56 static int spi_error_code = 0;
57 static GdkPoint last_mouse_pos_static = {0, 0}; 
58 static GdkPoint *last_mouse_pos = &last_mouse_pos_static;
59 static unsigned int mouse_mask_state = 0;
60 static unsigned int mouse_button_mask =
61   Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
62 static unsigned int key_modifier_mask =
63   Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
64
65 static GQuark spi_dec_private_quark = 0;
66
67 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
68
69 typedef enum {
70   SPI_DEVICE_TYPE_KBD,
71   SPI_DEVICE_TYPE_MOUSE,
72   SPI_DEVICE_TYPE_LAST_DEFINED
73 } SpiDeviceTypeCategory;
74
75 typedef struct {
76   guint                             ref_count : 30;
77   guint                             pending_add : 1;
78   guint                             pending_remove : 1;
79
80   Accessibility_ControllerEventMask mod_mask;
81   CORBA_unsigned_long               key_val;  /* KeyCode */
82 } DEControllerGrabMask;
83
84 typedef struct {
85   CORBA_Object          object;
86   SpiDeviceTypeCategory type;
87   Accessibility_EventTypeSeq    *typeseq;
88 } DEControllerListener;
89
90 typedef struct {
91   DEControllerListener listener;
92
93   Accessibility_KeySet             *keys;
94   Accessibility_ControllerEventMask mask;
95   Accessibility_EventListenerMode  *mode;       
96 } DEControllerKeyListener;
97
98 typedef struct {
99   unsigned int last_press_keycode;
100   unsigned int last_release_keycode;
101   struct timeval last_press_time;
102   struct timeval last_release_time;
103   int have_xkb;
104   int xkb_major_extension_opcode;
105   int xkb_base_event_code;
106   int xkb_base_error_code;
107   unsigned int xkb_latch_mask;
108   unsigned int pending_xkb_mod_relatch_mask;
109   XkbDescPtr xkb_desc;
110 } DEControllerPrivateData;
111
112 static void     spi_controller_register_with_devices          (SpiDEController           *controller);
113 static gboolean spi_controller_update_key_grabs               (SpiDEController           *controller,
114                                                                Accessibility_DeviceEvent *recv);
115 static gboolean spi_controller_register_device_listener       (SpiDEController           *controller,
116                                                                DEControllerListener      *l,
117                                                                CORBA_Environment         *ev);
118 static void     spi_device_event_controller_forward_key_event (SpiDEController           *controller,
119                                                                const XEvent              *event);
120 static void     spi_deregister_controller_device_listener (SpiDEController            *controller,
121                                                            DEControllerListener *listener,
122                                                            CORBA_Environment          *ev);
123 static void     spi_deregister_controller_key_listener (SpiDEController         *controller,
124                                                         DEControllerKeyListener *key_listener,
125                                                         CORBA_Environment       *ev);
126 static gboolean spi_controller_notify_mouselisteners (SpiDEController                 *controller,
127                                                       const Accessibility_DeviceEvent *event,
128                                                       CORBA_Environment               *ev);
129
130 static gboolean spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq      *type_seq,
131                                                   const Accessibility_DeviceEvent *event);
132 static gboolean spi_clear_error_state (void);
133 static gboolean spi_dec_poll_mouse_moved (gpointer data);
134 static gboolean spi_dec_poll_mouse_moving (gpointer data);
135 static gboolean spi_dec_poll_mouse_idle (gpointer data);
136
137 #define spi_get_display() GDK_DISPLAY()
138
139 /* Private methods */
140
141 static KeyCode
142 keycode_for_keysym (long keysym)
143 {
144   return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
145 }
146
147 static DEControllerGrabMask *
148 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
149 {
150   DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
151
152   memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
153
154   clone->ref_count = 1;
155   clone->pending_add = TRUE;
156   clone->pending_remove = FALSE;
157
158   return clone;
159 }
160
161 static void
162 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
163 {
164   g_free (grab_mask);
165 }
166
167 static gint
168 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
169 {
170   DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
171   DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
172
173   if (p1 == p2)
174     {
175       return 0;
176     }
177   else
178     { 
179       return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
180     }
181 }
182
183 static void
184 spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask)
185 {
186   DEControllerPrivateData *priv = 
187     g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
188 #ifdef SPI_XKB_DEBUG
189   if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", 
190                                      priv->xkb_latch_mask);
191 #endif
192   priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask; 
193 }
194  
195 static void
196 spi_dec_clear_unlatch_pending (SpiDEController *controller)
197 {
198   DEControllerPrivateData *priv = 
199     g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
200   priv->xkb_latch_mask = 0; 
201 }
202  
203 static gboolean
204 spi_dec_button_update_and_emit (SpiDEController *controller, 
205                                 guint mask_return)
206 {
207   CORBA_Environment ev;
208   Accessibility_Event e;
209   Accessibility_DeviceEvent mouse_e;
210   gchar event_name[24];
211   gboolean is_consumed = FALSE;
212
213   if ((mask_return & mouse_button_mask) !=
214       (mouse_mask_state & mouse_button_mask)) 
215     {
216       int button_number = 0;
217       gboolean is_down = False;
218       
219       if (!(mask_return & Button1Mask) &&
220           (mouse_mask_state & Button1Mask)) 
221         {
222           mouse_mask_state &= ~Button1Mask;
223           button_number = 1;
224         } 
225       else if ((mask_return & Button1Mask) &&
226                !(mouse_mask_state & Button1Mask)) 
227         {
228           mouse_mask_state |= Button1Mask;
229           button_number = 1;
230           is_down = True;
231         } 
232       else if (!(mask_return & Button2Mask) &&
233                (mouse_mask_state & Button2Mask)) 
234         {
235           mouse_mask_state &= ~Button2Mask;
236           button_number = 2;
237         } 
238       else if ((mask_return & Button2Mask) &&
239                !(mouse_mask_state & Button2Mask)) 
240         {
241           mouse_mask_state |= Button2Mask;
242           button_number = 2;
243           is_down = True;
244         } 
245       else if (!(mask_return & Button3Mask) &&
246                (mouse_mask_state & Button3Mask)) 
247         {
248           mouse_mask_state &= ~Button3Mask;
249           button_number = 3;
250         } 
251       else if ((mask_return & Button3Mask) &&
252                !(mouse_mask_state & Button3Mask)) 
253         {
254           mouse_mask_state |= Button3Mask;
255           button_number = 3;
256           is_down = True;
257         } 
258       else if (!(mask_return & Button4Mask) &&
259                (mouse_mask_state & Button4Mask)) 
260         {
261           mouse_mask_state &= ~Button4Mask;
262           button_number = 4;
263         } 
264       else if ((mask_return & Button4Mask) &&
265                !(mouse_mask_state & Button4Mask)) 
266         {
267           mouse_mask_state |= Button4Mask;
268           button_number = 4;
269           is_down = True;
270         } 
271       else if (!(mask_return & Button5Mask) &&
272                (mouse_mask_state & Button5Mask)) 
273         {
274           mouse_mask_state &= ~Button5Mask;
275           button_number = 5;
276         }
277       else if ((mask_return & Button5Mask) &&
278                !(mouse_mask_state & Button5Mask)) 
279         {
280           mouse_mask_state |= Button5Mask;
281           button_number = 5;
282           is_down = True;
283         }
284       if (button_number) {
285 #ifdef SPI_DEBUG                  
286         fprintf (stderr, "Button %d %s\n",
287                  button_number, (is_down) ? "Pressed" : "Released");
288 #endif
289         snprintf (event_name, 22, "mouse:button:%d%c", button_number,
290                   (is_down) ? 'p' : 'r');
291         /* TODO: distinguish between physical and 
292          * logical buttons 
293          */
294         mouse_e.type      = (is_down) ? 
295           Accessibility_BUTTON_PRESSED_EVENT :
296           Accessibility_BUTTON_RELEASED_EVENT;
297         mouse_e.id        = button_number;
298         mouse_e.hw_code   = button_number;
299         mouse_e.modifiers = (CORBA_unsigned_short) mouse_mask_state; 
300         mouse_e.timestamp = 0;
301         mouse_e.event_string = "";
302         mouse_e.is_text   = CORBA_FALSE;
303         is_consumed = 
304           spi_controller_notify_mouselisteners (controller, 
305                                                 &mouse_e, 
306                                                 &ev);
307         e.type = event_name;
308         e.source = BONOBO_OBJREF (controller->registry->desktop);
309         e.detail1 = last_mouse_pos->x;
310         e.detail2 = last_mouse_pos->y;
311         spi_init_any_nil (&e.any_data);
312         CORBA_exception_init (&ev);
313         if (!is_consumed)
314           {
315             Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
316                                                 &e,
317                                                 &ev);  
318           }
319         else
320           spi_dec_set_unlatch_pending (controller, mask_return);
321       }
322       return TRUE;
323     }
324   else
325     {
326       return FALSE;
327     }
328 }
329
330
331 static guint
332 spi_dec_mouse_check (SpiDEController *controller, 
333                      int *x, int *y, gboolean *moved)
334 {
335   Accessibility_Event e;
336   CORBA_Environment ev;
337   int win_x_return,win_y_return;
338   unsigned int mask_return;
339   Window root_return, child_return;
340   Display *display = spi_get_display ();
341
342   if (display != NULL)
343     XQueryPointer(display, DefaultRootWindow (display),
344                   &root_return, &child_return,
345                   x, y,
346                   &win_x_return, &win_y_return, &mask_return);
347   /* 
348    * Since many clients grab the pointer, and X goes an automatic
349    * pointer grab on mouse-down, we often must detect mouse button events
350    * by polling rather than via a button grab. 
351    * The while loop (rather than if) is used since it's possible that 
352    * multiple buttons have changed state since we last checked.
353    */
354   if (mask_return != mouse_mask_state) 
355     {
356       while (spi_dec_button_update_and_emit (controller, mask_return));
357     }
358
359   if (*x != last_mouse_pos->x || *y != last_mouse_pos->y) 
360     {
361       e.type = "mouse:abs";  
362       e.source = BONOBO_OBJREF (controller->registry->desktop);
363       e.detail1 = *x;
364       e.detail2 = *y;
365       spi_init_any_nil (&e.any_data);
366       CORBA_exception_init (&ev);
367       Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
368                                           &e,
369                                           &ev);
370       e.type = "mouse:rel";  
371       e.source = BONOBO_OBJREF (controller->registry->desktop);
372       e.detail1 = *x - last_mouse_pos->x;
373       e.detail2 = *y - last_mouse_pos->y;
374       spi_init_any_nil (&e.any_data);
375       CORBA_exception_init (&ev);
376       last_mouse_pos->x = *x;
377       last_mouse_pos->y = *y;
378       Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
379                                           &e,
380                                           &ev);
381       *moved = True;
382     }
383   else
384     {
385       *moved = False;
386     }
387
388   return mask_return;
389 }
390
391 static void
392 spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask, 
393                              guint current_mask)
394 {
395   Accessibility_Event e;
396   CORBA_Environment ev;
397
398 #ifdef SPI_XKB_DEBUG
399   fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n", 
400            prev_mask, current_mask);
401 #endif
402   e.type = "keyboard:modifiers";  
403   e.source = BONOBO_OBJREF (controller->registry->desktop);
404   e.detail1 = prev_mask & key_modifier_mask;
405   e.detail2 = current_mask & key_modifier_mask;
406   spi_init_any_nil (&e.any_data);
407   CORBA_exception_init (&ev);
408   Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
409                                       &e,
410                                       &ev);
411 }
412
413 static gboolean
414 spi_dec_poll_mouse_moved (gpointer data)
415 {
416   SpiRegistry *registry = SPI_REGISTRY (data);
417   SpiDEController *controller = registry->de_controller;
418   int x, y;  
419   gboolean moved;
420   guint mask_return;
421
422   mask_return = spi_dec_mouse_check (controller, &x, &y, &moved);
423   
424   if ((mask_return & key_modifier_mask) !=
425       (mouse_mask_state & key_modifier_mask)) 
426     {
427       spi_dec_emit_modifier_event (controller, mouse_mask_state, mask_return);
428       mouse_mask_state = mask_return;
429     }
430
431   return moved;
432 }
433
434 static gboolean
435 spi_dec_poll_mouse_idle (gpointer data)
436 {
437   if (! spi_dec_poll_mouse_moved (data)) 
438     return TRUE;
439   else
440     {
441       g_timeout_add (20, spi_dec_poll_mouse_moving, data);          
442       return FALSE;         
443     }
444 }
445
446 static gboolean
447 spi_dec_poll_mouse_moving (gpointer data)
448 {
449   if (spi_dec_poll_mouse_moved (data))
450     return TRUE;
451   else
452     {
453       g_timeout_add (100, spi_dec_poll_mouse_idle, data);           
454       return FALSE;
455     }
456 }
457
458 #ifdef WE_NEED_UGRAB_MOUSE
459 static int
460 spi_dec_ungrab_mouse (gpointer data)
461 {
462         Display *display = spi_get_display ();
463         if (display)
464           {
465             XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
466                            XDefaultRootWindow (spi_get_display ()));
467           }
468         return FALSE;
469 }
470 #endif
471
472 static void
473 spi_dec_init_mouse_listener (SpiRegistry *registry)
474 {
475   Display *display = spi_get_display ();
476   g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
477
478   if (display)
479     {
480       if (XGrabButton (display, AnyButton, AnyModifier,
481                    gdk_x11_get_default_root_xwindow (),
482                    True, ButtonPressMask | ButtonReleaseMask,
483                    GrabModeSync, GrabModeAsync, None, None) != Success)
484         fprintf (stderr, "WARNING: could not grab mouse buttons!\n");
485       XSync (display, False);
486 #ifdef SPI_DEBUG
487       fprintf (stderr, "mouse buttons grabbed\n");
488 #endif
489     }
490 }
491
492 static DEControllerKeyListener *
493 spi_dec_key_listener_new (CORBA_Object                            l,
494                           const Accessibility_KeySet             *keys,
495                           const Accessibility_ControllerEventMask mask,
496                           const Accessibility_EventTypeSeq    *typeseq,
497                           const Accessibility_EventListenerMode  *mode,
498                           CORBA_Environment                      *ev)
499 {
500   DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
501   key_listener->listener.object = bonobo_object_dup_ref (l, ev);
502   key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
503   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
504   key_listener->mask = mask;
505   key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
506   if (mode)
507     key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
508   else
509     key_listener->mode = NULL;
510
511 #ifdef SPI_DEBUG
512   g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
513            (unsigned int) key_listener->mask,
514            (int) (mode ? mode->global : 0),
515            (void *) key_listener->keys,
516            (int) (key_listener->keys ? key_listener->keys->_length : 0));
517 #endif
518
519   return key_listener;  
520 }
521
522 static DEControllerListener *
523 spi_dec_listener_new (CORBA_Object                            l,
524                       const Accessibility_EventTypeSeq    *typeseq,
525                       CORBA_Environment                      *ev)
526 {
527   DEControllerListener *listener = g_new0 (DEControllerListener, 1);
528   listener->object = bonobo_object_dup_ref (l, ev);
529   listener->type = SPI_DEVICE_TYPE_MOUSE;
530   listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
531   return listener;      
532 }
533
534 static DEControllerListener *
535 spi_listener_clone (DEControllerListener *listener, CORBA_Environment *ev)
536 {
537   DEControllerListener *clone = g_new0 (DEControllerListener, 1);
538   clone->object =
539           CORBA_Object_duplicate (listener->object, ev);
540   clone->type = listener->type;
541   clone->typeseq = ORBit_copy_value (listener->typeseq, TC_Accessibility_EventTypeSeq);
542   return clone;
543 }
544
545 static DEControllerKeyListener *
546 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
547 {
548   DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
549   clone->listener.object =
550           CORBA_Object_duplicate (key_listener->listener.object, ev);
551   clone->listener.type = SPI_DEVICE_TYPE_KBD;
552   clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
553   clone->mask = key_listener->mask;
554   clone->listener.typeseq = ORBit_copy_value (key_listener->listener.typeseq, TC_Accessibility_EventTypeSeq);
555   if (key_listener->mode)
556     clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
557   else
558     clone->mode = NULL;
559   return clone;
560 }
561
562 static void
563 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
564 {
565   CORBA_free (key_listener->listener.typeseq);
566   CORBA_free (key_listener->keys);
567   g_free (key_listener);
568 }
569
570 static void
571 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
572 {
573   CORBA_Object_release (clone->listener.object, ev);
574   spi_key_listener_data_free (clone, ev);
575 }
576
577 static void
578 spi_listener_clone_free (DEControllerListener *clone, CORBA_Environment *ev)
579 {
580   CORBA_Object_release (clone->object, ev);
581   CORBA_free (clone->typeseq);
582   g_free (clone);
583 }
584
585 static void
586 spi_dec_listener_free (DEControllerListener    *listener,
587                        CORBA_Environment       *ev)
588 {
589   bonobo_object_release_unref (listener->object, ev);
590   if (listener->type == SPI_DEVICE_TYPE_KBD) 
591     spi_key_listener_data_free ((DEControllerKeyListener *) listener, ev);
592 }
593
594 static void
595 _register_keygrab (SpiDEController      *controller,
596                    DEControllerGrabMask *grab_mask)
597 {
598   GList *l;
599
600   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
601                           spi_grab_mask_compare_values);
602   if (l)
603     {
604       DEControllerGrabMask *cur_mask = l->data;
605
606       cur_mask->ref_count++;
607       if (cur_mask->pending_remove)
608         {
609           cur_mask->pending_remove = FALSE;
610         }
611     }
612   else
613     {
614       controller->keygrabs_list =
615         g_list_prepend (controller->keygrabs_list,
616                         spi_grab_mask_clone (grab_mask));
617     }
618 }
619
620 static void
621 _deregister_keygrab (SpiDEController      *controller,
622                      DEControllerGrabMask *grab_mask)
623 {
624   GList *l;
625
626   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
627                           spi_grab_mask_compare_values);
628
629   if (l)
630     {
631       DEControllerGrabMask *cur_mask = l->data;
632
633       cur_mask->ref_count--;
634       if (cur_mask->ref_count <= 0)
635         {
636           cur_mask->pending_remove = TRUE;
637         }
638     }
639   else
640     {
641       DBG (1, g_warning ("De-registering non-existant grab"));
642     }
643 }
644
645 static void
646 handle_keygrab (SpiDEController         *controller,
647                 DEControllerKeyListener *key_listener,
648                 void                   (*process_cb) (SpiDEController *controller,
649                                                       DEControllerGrabMask *grab_mask))
650 {
651   DEControllerGrabMask grab_mask = { 0 };
652
653   grab_mask.mod_mask = key_listener->mask;
654   if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
655     {
656       grab_mask.key_val = AnyKey;
657 #ifdef SPI_DEBUG
658       fprintf (stderr, "AnyKey grab!");
659 #endif
660       process_cb (controller, &grab_mask);
661     }
662   else
663     {
664       int i;
665
666       for (i = 0; i < key_listener->keys->_length; ++i)
667         {
668           Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];  
669           long int key_val = keydef.keysym;
670           /* X Grabs require keycodes, not keysyms */
671           if (keydef.keystring && keydef.keystring[0])
672             {
673               key_val = XStringToKeysym(keydef.keystring);                  
674             }
675           if (key_val > 0)
676             {
677               key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
678             }
679           else
680             {
681               key_val = keydef.keycode;
682             }
683           grab_mask.key_val = key_val;
684           process_cb (controller, &grab_mask);
685         }
686     }
687 }
688
689 static gboolean
690 spi_controller_register_global_keygrabs (SpiDEController         *controller,
691                                          DEControllerKeyListener *key_listener)
692 {
693   handle_keygrab (controller, key_listener, _register_keygrab);
694   return spi_controller_update_key_grabs (controller, NULL);
695 }
696
697 static void
698 spi_controller_deregister_global_keygrabs (SpiDEController         *controller,
699                                            DEControllerKeyListener *key_listener)
700 {
701   handle_keygrab (controller, key_listener, _deregister_keygrab);
702   spi_controller_update_key_grabs (controller, NULL);
703 }
704
705 static gboolean
706 spi_controller_register_device_listener (SpiDEController      *controller,
707                                          DEControllerListener *listener,
708                                          CORBA_Environment    *ev)
709 {
710   DEControllerKeyListener *key_listener;
711   
712   switch (listener->type) {
713   case SPI_DEVICE_TYPE_KBD:
714       key_listener = (DEControllerKeyListener *) listener;
715
716       controller->key_listeners = g_list_prepend (controller->key_listeners,
717                                                   key_listener);
718       if (key_listener->mode->global)
719         {
720           return spi_controller_register_global_keygrabs (controller, key_listener);    
721         }
722       else
723               return TRUE;
724       break;
725   case SPI_DEVICE_TYPE_MOUSE:
726       controller->mouse_listeners = g_list_prepend (controller->mouse_listeners, listener);
727       break;
728   default:
729       DBG (1, g_warning ("listener registration for unknown device type.\n"));
730       break;
731   }
732   return FALSE; 
733 }
734
735 static gboolean
736 spi_controller_notify_mouselisteners (SpiDEController                 *controller,
737                                       const Accessibility_DeviceEvent *event,
738                                       CORBA_Environment               *ev)
739 {
740   GList   *l;
741   GSList  *notify = NULL, *l2;
742   GList  **listeners = &controller->mouse_listeners;
743   gboolean is_consumed;
744
745   if (!listeners)
746     {
747       return FALSE;
748     }
749
750   for (l = *listeners; l; l = l->next)
751     {
752        DEControllerListener *listener = l->data;
753
754        if (spi_eventtype_seq_contains_event (listener->typeseq, event))
755          {
756            Accessibility_DeviceEventListener ls = listener->object;
757
758            if (ls != CORBA_OBJECT_NIL)
759              {
760                /* we clone (don't dup) the listener, to avoid refcount inc. */
761                notify = g_slist_prepend (notify,
762                                          spi_listener_clone (listener, ev));
763              }
764          }
765     }
766
767 #ifdef SPI_KEYEVENT_DEBUG
768   if (!notify)
769     {
770       g_print ("no match for event\n");
771     }
772 #endif
773
774   is_consumed = FALSE;
775   for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
776     {
777       DEControllerListener *listener = l2->data;            
778       Accessibility_DeviceEventListener ls = listener->object;
779
780       CORBA_exception_init (ev);
781       is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, event, ev);
782       if (BONOBO_EX (ev))
783         {
784           is_consumed = FALSE;
785           DBG (2, g_warning ("error notifying listener, removing it\n"));
786           spi_deregister_controller_device_listener (controller, listener,
787                                                      ev);
788           CORBA_exception_free (ev);
789         }
790       
791       spi_listener_clone_free ((DEControllerListener *) l2->data, ev);
792     }
793
794   for (; l2; l2 = l2->next)
795     {
796       DEControllerListener *listener = l2->data;            
797       spi_listener_clone_free (listener, ev);
798       /* clone doesn't have its own ref, so don't use spi_device_listener_free */
799     }
800
801   g_slist_free (notify);
802
803 #ifdef SPI_DEBUG
804   if (is_consumed) g_message ("consumed\n");
805 #endif
806   return is_consumed;
807 }
808
809 static void
810 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
811                                                  XEvent *xevent)
812 {
813   Accessibility_Event e;
814   Accessibility_DeviceEvent mouse_e;
815   CORBA_Environment ev;
816   gchar event_name[24];
817   gboolean is_consumed = FALSE;
818   gboolean xkb_mod_unlatch_occurred;
819   XButtonEvent *xbutton_event = (XButtonEvent *) xevent;
820
821   int button = xbutton_event->button;
822   
823   unsigned int mouse_button_state = xbutton_event->state;
824
825   switch (button)
826     {
827     case 1:
828             mouse_button_state |= Button1Mask;
829             break;
830     case 2:
831             mouse_button_state |= Button2Mask;
832             break;
833     case 3:
834             mouse_button_state |= Button3Mask;
835             break;
836     case 4:
837             mouse_button_state |= Button4Mask;
838             break;
839     case 5:
840             mouse_button_state |= Button5Mask;
841             break;
842     }
843
844   last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
845   last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
846
847 #ifdef SPI_DEBUG  
848   fprintf (stderr, "mouse button %d %s (%x)\n",
849            xbutton_event->button, 
850            (xevent->type == ButtonPress) ? "Press" : "Release",
851            mouse_button_state);
852 #endif
853   snprintf (event_name, 22, "mouse:button:%d%c", button,
854             (xevent->type == ButtonPress) ? 'p' : 'r');
855
856   /* TODO: distinguish between physical and logical buttons */
857   mouse_e.type      = (xevent->type == ButtonPress) ? 
858                       Accessibility_BUTTON_PRESSED_EVENT :
859                       Accessibility_BUTTON_RELEASED_EVENT;
860   mouse_e.id        = button;
861   mouse_e.hw_code   = button;
862   mouse_e.modifiers = (CORBA_unsigned_short) xbutton_event->state;
863   mouse_e.timestamp = (CORBA_unsigned_long) xbutton_event->time;
864   mouse_e.event_string = "";
865   mouse_e.is_text   = CORBA_FALSE;
866   if ((mouse_button_state & mouse_button_mask) != 
867        (mouse_mask_state & mouse_button_mask))
868     { 
869       if ((mouse_mask_state & key_modifier_mask) !=
870           (mouse_button_state & key_modifier_mask))
871         spi_dec_emit_modifier_event (controller, 
872                                      mouse_mask_state, mouse_button_state);
873       mouse_mask_state = mouse_button_state;
874       is_consumed = 
875         spi_controller_notify_mouselisteners (controller, &mouse_e, &ev);
876       e.type = CORBA_string_dup (event_name);
877       e.source = BONOBO_OBJREF (controller->registry->desktop);
878       e.detail1 = last_mouse_pos->x;
879       e.detail2 = last_mouse_pos->y;
880       spi_init_any_nil (&e.any_data);
881       CORBA_exception_init (&ev);
882       
883       Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
884                                           &e,
885                                           &ev);
886     }
887
888   xkb_mod_unlatch_occurred = (xevent->type == ButtonPress ||
889                               xevent->type == ButtonRelease);
890   
891   /* if client wants to consume this event, and XKB latch state was
892    *   unset by this button event, we reset it
893    */
894   if (is_consumed && xkb_mod_unlatch_occurred)
895     spi_dec_set_unlatch_pending (controller, mouse_mask_state);
896   
897   XAllowEvents (spi_get_display (),
898                 (is_consumed) ? SyncPointer : ReplayPointer,
899                 CurrentTime);
900 }
901
902 static GdkFilterReturn
903 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
904 {
905   XEvent *xevent = gdk_xevent;
906   SpiDEController *controller;
907   DEControllerPrivateData *priv;
908   Display *display = spi_get_display ();
909   controller = SPI_DEVICE_EVENT_CONTROLLER (data);
910   priv = (DEControllerPrivateData *)
911           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);  
912
913   if (xevent->type == KeyPress || xevent->type == KeyRelease)
914     {
915       spi_device_event_controller_forward_key_event (controller, xevent);
916       return GDK_FILTER_CONTINUE;
917     }
918   if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
919     {
920       spi_device_event_controller_forward_mouse_event (controller, xevent);
921     }
922   if (xevent->type == priv->xkb_base_event_code)
923     {
924       XkbAnyEvent * xkb_ev = (XkbAnyEvent *) xevent;
925       /* ugly but probably necessary...*/
926       XSynchronize (spi_get_display (), TRUE);
927
928       if (xkb_ev->xkb_type == XkbStateNotify)
929         {
930           XkbStateNotifyEvent *xkb_snev =
931                   (XkbStateNotifyEvent *) xkb_ev;
932           /* check the mouse, to catch mouse events grabbed by
933            * another client; in case we should revert this XKB delatch 
934            */
935           if (!priv->pending_xkb_mod_relatch_mask)
936             {
937               int x, y;
938               gboolean moved;
939               spi_dec_mouse_check (controller, &x, &y, &moved);
940             }
941           /* we check again, since the previous call may have 
942              changed this flag */
943           if (priv->pending_xkb_mod_relatch_mask)
944             {
945               unsigned int feedback_mask;
946 #ifdef SPI_XKB_DEBUG
947               fprintf (stderr, "relatching %x\n",
948                        priv->pending_xkb_mod_relatch_mask);
949 #endif
950               /* temporarily turn off the latch bell, if it's on */
951               XkbGetControls (display,
952                               XkbAccessXFeedbackMask,
953                               priv->xkb_desc);
954               feedback_mask = priv->xkb_desc->ctrls->ax_options;
955               if (feedback_mask & XkbAX_StickyKeysFBMask)
956               {
957                 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
958                                                  0, False};      
959                 priv->xkb_desc->ctrls->ax_options
960                               &= ~(XkbAX_StickyKeysFBMask);
961                 XkbChangeControls (display, priv->xkb_desc, &changes);
962               }
963               /* TODO: account for lock as well as latch */
964               XkbLatchModifiers (display,
965                                  XkbUseCoreKbd,
966                                  priv->pending_xkb_mod_relatch_mask,
967                                  priv->pending_xkb_mod_relatch_mask);
968               if (feedback_mask & XkbAX_StickyKeysFBMask)
969               { 
970                 XkbControlsChangesRec changes = {XkbAccessXFeedbackMask,
971                                                  0, False};      
972                 priv->xkb_desc->ctrls->ax_options = feedback_mask;
973                 XkbChangeControls (display, priv->xkb_desc, &changes);
974               }
975 #ifdef SPI_XKB_DEBUG
976               fprintf (stderr, "relatched %x\n",
977                        priv->pending_xkb_mod_relatch_mask);
978 #endif
979               priv->pending_xkb_mod_relatch_mask = 0;
980             }
981           else
982             {
983               priv->xkb_latch_mask = xkb_snev->latched_mods;
984             }
985         }
986         else
987                DBG (2, g_warning ("XKB event %d\n", xkb_ev->xkb_type));
988       XSynchronize (spi_get_display (), FALSE);
989     }
990   
991   return GDK_FILTER_CONTINUE;
992 }
993
994 int
995 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
996 {
997   if (error->error_code == BadAccess) 
998     {  
999       g_message ("Could not complete key grab: grab already in use.\n");
1000       spi_error_code = BadAccess;
1001       return 0;
1002     }
1003   else 
1004     {
1005       return (*x_default_error_handler) (display, error);
1006     }
1007 }
1008
1009 static void
1010 spi_controller_register_with_devices (SpiDEController *controller)
1011 {
1012   DEControllerPrivateData *priv = (DEControllerPrivateData *) 
1013           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);     
1014   /* FIXME: should check for extension first! */
1015   XTestGrabControl (spi_get_display (), True);
1016
1017   /* calls to device-specific implementations and routines go here */
1018   /* register with: keyboard hardware code handler */
1019   /* register with: (translated) keystroke handler */
1020
1021   priv->have_xkb = XkbQueryExtension (spi_get_display (),
1022                                       &priv->xkb_major_extension_opcode,
1023                                       &priv->xkb_base_event_code,
1024                                       &priv->xkb_base_error_code, NULL, NULL);
1025   if (priv->have_xkb)
1026     {
1027       priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1028       XkbSelectEvents (spi_get_display (),
1029                        XkbUseCoreKbd,
1030                        XkbStateNotifyMask, XkbStateNotifyMask);     
1031     }   
1032
1033   gdk_window_add_filter (NULL, global_filter_fn, controller);
1034
1035   gdk_window_set_events (gdk_get_default_root_window (),
1036                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
1037
1038   x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
1039 }
1040
1041 static gboolean
1042 spi_key_set_contains_key (Accessibility_KeySet            *key_set,
1043                           const Accessibility_DeviceEvent *key_event)
1044 {
1045   gint i;
1046   gint len;
1047
1048   if (!key_set)
1049     {
1050       g_print ("null key set!");
1051       return TRUE;
1052     }
1053
1054   len = key_set->_length;
1055   
1056   if (len == 0) /* special case, means "all keys/any key" */
1057     {
1058       g_print ("anykey\n");         
1059       return TRUE;
1060     }
1061
1062   for (i = 0; i < len; ++i)
1063     {
1064 #ifdef SPI_KEYEVENT_DEBUG           
1065       g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
1066                 i, (int) key_set->_buffer[i].keycode,
1067                (int) key_event->id, (int) key_event->hw_code,
1068                key_event->event_string); 
1069 #endif
1070       if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
1071         {
1072           return TRUE;
1073         }
1074       if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
1075         {
1076           return TRUE;
1077         }
1078       if (key_event->event_string && key_event->event_string[0] &&
1079           !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
1080         {
1081           return TRUE;
1082         }
1083     }
1084   
1085   return FALSE;
1086 }
1087
1088 static gboolean
1089 spi_eventtype_seq_contains_event (Accessibility_EventTypeSeq      *type_seq,
1090                                   const Accessibility_DeviceEvent *event)
1091 {
1092   gint i;
1093   gint len;
1094
1095
1096   if (!type_seq)
1097     {
1098       g_print ("null type seq!");
1099       return TRUE;
1100     }
1101
1102   len = type_seq->_length;
1103   
1104   if (len == 0) /* special case, means "all events/any event" */
1105     {
1106       return TRUE;
1107     }
1108
1109   for (i = 0; i < len; ++i)
1110     {
1111 #ifdef SPI_DEBUG            
1112       g_print ("type_seq[%d] = %d; event type = %d\n", i,
1113                (int) type_seq->_buffer[i], (int) event->type);
1114 #endif      
1115       if (type_seq->_buffer[i] == (CORBA_long) event->type)
1116         {
1117           return TRUE;
1118         }
1119     }
1120   
1121   return FALSE;
1122 }
1123
1124 static gboolean
1125 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
1126                                 DEControllerKeyListener         *listener,
1127                                 CORBA_boolean                    is_system_global)
1128 {
1129   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
1130        spi_key_set_contains_key (listener->keys, key_event) &&
1131        spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) && 
1132       (is_system_global == listener->mode->global))
1133     {
1134       return TRUE;
1135     }
1136   else
1137     {
1138       return FALSE;
1139     }
1140 }
1141
1142 static gboolean
1143 spi_controller_notify_keylisteners (SpiDEController                 *controller,
1144                                     const Accessibility_DeviceEvent *key_event,
1145                                     CORBA_boolean                    is_system_global,
1146                                     CORBA_Environment               *ev)
1147 {
1148   GList   *l;
1149   GSList  *notify = NULL, *l2;
1150   GList  **key_listeners = &controller->key_listeners;
1151   gboolean is_consumed;
1152
1153   if (!key_listeners)
1154     {
1155       return FALSE;
1156     }
1157
1158   for (l = *key_listeners; l; l = l->next)
1159     {
1160        DEControllerKeyListener *key_listener = l->data;
1161
1162        if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
1163          {
1164            Accessibility_DeviceEventListener ls = key_listener->listener.object;
1165
1166            if (ls != CORBA_OBJECT_NIL)
1167              {
1168                /* we clone (don't dup) the listener, to avoid refcount inc. */
1169                notify = g_slist_prepend (notify,
1170                                          spi_key_listener_clone (key_listener, ev));
1171              }
1172          }
1173     }
1174
1175 #ifdef SPI_KEYEVENT_DEBUG
1176   if (!notify)
1177     {
1178       g_print ("no match for event\n");
1179     }
1180 #endif
1181
1182   is_consumed = FALSE;
1183   for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
1184     {
1185       DEControllerKeyListener *key_listener = l2->data;     
1186       Accessibility_DeviceEventListener ls = key_listener->listener.object;
1187
1188       is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
1189
1190       if (BONOBO_EX (ev))
1191         {
1192           is_consumed = FALSE;
1193           spi_deregister_controller_key_listener (controller, key_listener,
1194                                                   ev);
1195           CORBA_exception_free (ev);
1196         }
1197
1198       spi_key_listener_clone_free (key_listener, ev);
1199     }
1200
1201   for (; l2; l2 = l2->next)
1202     {
1203       DEControllerKeyListener *key_listener = l2->data;     
1204       spi_key_listener_clone_free (key_listener, ev);
1205       /* clone doesn't have its own ref, so don't use spi_dec_listener_free */
1206     }
1207
1208   g_slist_free (notify);
1209
1210 #ifdef SPI_DEBUG
1211   if (is_consumed) g_message ("consumed\n");
1212 #endif
1213   return is_consumed;
1214 }
1215
1216 static gboolean
1217 spi_clear_error_state ()
1218 {
1219         gboolean retval = spi_error_code != 0;
1220         spi_error_code = 0;
1221         return retval;
1222 }
1223
1224 static Accessibility_DeviceEvent
1225 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
1226 {
1227   Accessibility_DeviceEvent key_event;
1228   KeySym keysym;
1229   const int cbuf_bytes = 20;
1230   char cbuf [cbuf_bytes+1];
1231   int nbytes;
1232
1233   nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);  
1234   key_event.id = (CORBA_long)(keysym);
1235   key_event.hw_code = (CORBA_short) x_key_event->keycode;
1236   if (((XEvent *) x_key_event)->type == KeyPress)
1237     {
1238       key_event.type = Accessibility_KEY_PRESSED;
1239     }
1240   else
1241     {
1242       key_event.type = Accessibility_KEY_RELEASED;
1243     } 
1244   key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
1245   key_event.is_text = CORBA_FALSE;
1246   switch (keysym)
1247     {
1248       case ' ':
1249         key_event.event_string = CORBA_string_dup ("space");
1250         break;
1251       case XK_Tab:
1252 #ifdef SPI_KEYEVENT_DEBUG
1253         fprintf(stderr, "Tab\n");
1254 #endif
1255         key_event.event_string = CORBA_string_dup ("Tab");
1256         break;
1257       case XK_BackSpace:
1258         key_event.event_string = CORBA_string_dup ("Backspace");
1259         break;
1260       case XK_Return:
1261         key_event.event_string = CORBA_string_dup ("Return");
1262         break;
1263       case XK_Home:
1264         key_event.event_string = CORBA_string_dup ("Home");
1265         break;
1266       case XK_Page_Down:
1267         key_event.event_string = CORBA_string_dup ("Page_Down");
1268         break;
1269       case XK_Page_Up:
1270         key_event.event_string = CORBA_string_dup ("Page_Up");
1271         break;
1272       case XK_F1:
1273         key_event.event_string = CORBA_string_dup ("F1");
1274         break;
1275       case XK_F2:
1276         key_event.event_string = CORBA_string_dup ("F2");
1277         break;
1278       case XK_F3:
1279         key_event.event_string = CORBA_string_dup ("F3");
1280         break;
1281       case XK_F4:
1282         key_event.event_string = CORBA_string_dup ("F4");
1283         break;
1284       case XK_F5:
1285         key_event.event_string = CORBA_string_dup ("F5");
1286         break;
1287       case XK_F6:
1288         key_event.event_string = CORBA_string_dup ("F6");
1289         break;
1290       case XK_F7:
1291         key_event.event_string = CORBA_string_dup ("F7");
1292         break;
1293       case XK_F8:
1294         key_event.event_string = CORBA_string_dup ("F8");
1295         break;
1296       case XK_F9:
1297         key_event.event_string = CORBA_string_dup ("F9");
1298         break;
1299       case XK_F10:
1300         key_event.event_string = CORBA_string_dup ("F10");
1301         break;
1302       case XK_F11:
1303         key_event.event_string = CORBA_string_dup ("F11");
1304         break;
1305       case XK_F12:
1306         key_event.event_string = CORBA_string_dup ("F12");
1307         break;
1308       case XK_End:
1309         key_event.event_string = CORBA_string_dup ("End");
1310         break;
1311       case XK_Escape:
1312         key_event.event_string = CORBA_string_dup ("Escape");
1313         break;
1314       case XK_Up:
1315         key_event.event_string = CORBA_string_dup ("Up");
1316         break;
1317       case XK_Down:
1318         key_event.event_string = CORBA_string_dup ("Down");
1319         break;
1320       case XK_Left:
1321         key_event.event_string = CORBA_string_dup ("Left");
1322         break;
1323       case XK_Right:
1324         key_event.event_string = CORBA_string_dup ("Right");
1325         break;
1326       default:
1327         if (nbytes > 0)
1328           {
1329             cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
1330             key_event.event_string = CORBA_string_dup (cbuf);
1331             if ((keysym && g_ascii_isprint (keysym)) || (nbytes == 1))
1332               {
1333                 key_event.is_text = CORBA_TRUE; 
1334                 /* FIXME: incorrect for some composed chars, unicode chars? */
1335               }
1336           }
1337         else
1338           {
1339             key_event.event_string = CORBA_string_dup ("");
1340           }
1341     }
1342
1343   key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1344 #ifdef SPI_KEYEVENT_DEBUG
1345   fprintf (stderr,
1346      "Key %lu pressed (%c), modifiers %d\n",
1347      (unsigned long) keysym,
1348      keysym ? (int) keysym : '*',
1349      (int) x_key_event->state);
1350 #endif
1351 #ifdef SPI_DEBUG
1352   fprintf (stderr, "%s%c",
1353      (x_key_event->state & Mod1Mask)?"Alt-":"",
1354      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1355      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1356 #endif /* SPI_DEBUG */
1357   return key_event;     
1358 }
1359
1360 static gboolean
1361 spi_controller_update_key_grabs (SpiDEController           *controller,
1362                                  Accessibility_DeviceEvent *recv)
1363 {
1364   GList *l, *next;
1365   gboolean   update_failed = FALSE;
1366   
1367   g_return_val_if_fail (controller != NULL, FALSE);
1368
1369   /*
1370    * masks known to work with default RH 7.1+:
1371    * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1372    * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1373    * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1374    * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1375    *
1376    * ControlMask grabs are broken, must be in use already
1377    */
1378   for (l = controller->keygrabs_list; l; l = next)
1379     {
1380       gboolean do_remove;
1381       gboolean re_issue_grab;
1382       DEControllerGrabMask *grab_mask = l->data;
1383
1384       next = l->next;
1385
1386       re_issue_grab = recv &&
1387 /*            (recv->type == Accessibility_KEY_RELEASED) && - (?) */
1388               (recv->modifiers & grab_mask->mod_mask) &&
1389               (grab_mask->key_val == keycode_for_keysym (recv->id));
1390
1391 #ifdef SPI_DEBUG
1392       fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1393                (long int) grab_mask->key_val,
1394                (long int) grab_mask->mod_mask,
1395                grab_mask->pending_add ? '+' : '.',
1396                grab_mask->pending_remove ? '-' : '.',
1397                re_issue_grab ? "re-issue": "");
1398 #endif
1399
1400       do_remove = FALSE;
1401
1402       if (grab_mask->pending_add && grab_mask->pending_remove)
1403         {
1404           do_remove = TRUE;
1405         }
1406       else if (grab_mask->pending_remove)
1407         {
1408 #ifdef SPI_DEBUG
1409       fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1410 #endif
1411           XUngrabKey (spi_get_display (),
1412                       grab_mask->key_val,
1413                       grab_mask->mod_mask,
1414                       gdk_x11_get_default_root_xwindow ());
1415
1416           do_remove = TRUE;
1417         }
1418       else if (grab_mask->pending_add || re_issue_grab)
1419         {
1420
1421 #ifdef SPI_DEBUG
1422           fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1423 #endif
1424           XGrabKey (spi_get_display (),
1425                     grab_mask->key_val,
1426                     grab_mask->mod_mask,
1427                     gdk_x11_get_default_root_xwindow (),
1428                     True,
1429                     GrabModeSync,
1430                     GrabModeSync);
1431           XSync (spi_get_display (), False);
1432           update_failed = spi_clear_error_state ();
1433           if (update_failed) {
1434                   while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1435                   do_remove = TRUE;
1436           }
1437         }
1438
1439       grab_mask->pending_add = FALSE;
1440       grab_mask->pending_remove = FALSE;
1441
1442       if (do_remove)
1443         {
1444           g_assert (grab_mask->ref_count <= 0);
1445
1446           controller->keygrabs_list = g_list_delete_link (
1447             controller->keygrabs_list, l);
1448
1449           spi_grab_mask_free (grab_mask);
1450         }
1451
1452     } 
1453
1454   return ! update_failed;
1455 }
1456
1457 /*
1458  * Implemented GObject::finalize
1459  */
1460 static void
1461 spi_device_event_controller_object_finalize (GObject *object)
1462 {
1463   SpiDEController *controller;
1464   DEControllerPrivateData *private;
1465   controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1466
1467 #ifdef SPI_DEBUG
1468   fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1469 #endif
1470   /* disconnect any special listeners, get rid of outstanding keygrabs */
1471   XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1472
1473   private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1474   if (private->xkb_desc)
1475           XkbFreeKeyboard (private->xkb_desc, 0, True);
1476   g_free (private);
1477   spi_device_event_controller_parent_class->finalize (object);
1478 }
1479
1480 /*
1481  * CORBA Accessibility::DEController::registerKeystrokeListener
1482  *     method implementation
1483  */
1484 static CORBA_boolean
1485 impl_register_keystroke_listener (PortableServer_Servant                  servant,
1486                                   const Accessibility_DeviceEventListener l,
1487                                   const Accessibility_KeySet             *keys,
1488                                   const Accessibility_ControllerEventMask mask,
1489                                   const Accessibility_EventTypeSeq       *type,
1490                                   const Accessibility_EventListenerMode  *mode,
1491                                   CORBA_Environment                      *ev)
1492 {
1493   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1494           bonobo_object_from_servant (servant));
1495   DEControllerKeyListener *dec_listener;
1496 #ifdef SPI_DEBUG
1497   fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1498            (void *) l, (unsigned long) mask);
1499 #endif
1500   dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1501   return spi_controller_register_device_listener (
1502           controller, (DEControllerListener *) dec_listener, ev);
1503 }
1504
1505
1506 /*
1507  * CORBA Accessibility::DEController::registerDeviceEventListener
1508  *     method implementation
1509  */
1510 static CORBA_boolean
1511 impl_register_device_listener (PortableServer_Servant                  servant,
1512                                const Accessibility_DeviceEventListener l,
1513                                const Accessibility_EventTypeSeq       *event_types,
1514                                CORBA_Environment                      *ev)
1515 {
1516   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1517           bonobo_object_from_servant (servant));
1518   DEControllerListener *dec_listener;
1519
1520   dec_listener = spi_dec_listener_new (l, event_types, ev);
1521   return spi_controller_register_device_listener (
1522           controller, (DEControllerListener *) dec_listener, ev);
1523 }
1524
1525 typedef struct {
1526         CORBA_Environment       *ev;
1527         DEControllerListener    *listener;
1528 } RemoveListenerClosure;
1529
1530 static SpiReEntrantContinue
1531 remove_listener_cb (GList * const *list,
1532                     gpointer       user_data)
1533 {
1534   DEControllerListener  *listener = (*list)->data;
1535   RemoveListenerClosure *ctx = user_data;
1536
1537   if (CORBA_Object_is_equivalent (ctx->listener->object,
1538                                   listener->object, ctx->ev))
1539     {
1540       spi_re_entrant_list_delete_link (list);
1541       spi_dec_listener_free (listener, ctx->ev);
1542     }
1543
1544   return SPI_RE_ENTRANT_CONTINUE;
1545 }
1546
1547 static SpiReEntrantContinue
1548 copy_key_listener_cb (GList * const *list,
1549                       gpointer       user_data)
1550 {
1551   DEControllerKeyListener  *key_listener = (*list)->data;
1552   RemoveListenerClosure    *ctx = user_data;
1553
1554   if (CORBA_Object_is_equivalent (ctx->listener->object,
1555                                   key_listener->listener.object, ctx->ev))
1556     {
1557       /* TODO: FIXME aggregate keys in case the listener is registered twice */
1558       DEControllerKeyListener *ctx_key_listener = 
1559         (DEControllerKeyListener *) ctx->listener; 
1560       CORBA_free (ctx_key_listener->keys);          
1561       ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1562     }
1563
1564   return SPI_RE_ENTRANT_CONTINUE;
1565 }
1566
1567 static void
1568 spi_deregister_controller_device_listener (SpiDEController            *controller,
1569                                            DEControllerListener *listener,
1570                                            CORBA_Environment          *ev)
1571 {
1572   RemoveListenerClosure  ctx;
1573
1574   ctx.ev = ev;
1575   ctx.listener = listener;
1576
1577   spi_re_entrant_list_foreach (&controller->mouse_listeners,
1578                                remove_listener_cb, &ctx);
1579 }
1580
1581 static void
1582 spi_deregister_controller_key_listener (SpiDEController            *controller,
1583                                         DEControllerKeyListener    *key_listener,
1584                                         CORBA_Environment          *ev)
1585 {
1586   RemoveListenerClosure  ctx;
1587
1588   ctx.ev = ev;
1589   ctx.listener = (DEControllerListener *) key_listener;
1590
1591   /* special case, copy keyset from existing controller list entry */
1592   if (key_listener->keys->_length == 0) 
1593     {
1594       spi_re_entrant_list_foreach (&controller->key_listeners,
1595                                   copy_key_listener_cb, &ctx);
1596     }
1597   
1598   spi_controller_deregister_global_keygrabs (controller, key_listener);
1599
1600   spi_re_entrant_list_foreach (&controller->key_listeners,
1601                                 remove_listener_cb, &ctx);
1602
1603 }
1604
1605 /*
1606  * CORBA Accessibility::DEController::deregisterKeystrokeListener
1607  *     method implementation
1608  */
1609 static void
1610 impl_deregister_keystroke_listener (PortableServer_Servant                  servant,
1611                                     const Accessibility_DeviceEventListener l,
1612                                     const Accessibility_KeySet             *keys,
1613                                     const Accessibility_ControllerEventMask mask,
1614                                     const Accessibility_EventTypeSeq       *type,
1615                                     CORBA_Environment                      *ev)
1616 {
1617   DEControllerKeyListener  *key_listener;
1618   SpiDEController *controller;
1619
1620   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1621
1622   key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1623
1624 #ifdef SPI_DEREGISTER_DEBUG
1625   fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1626            (void *) l, (unsigned long) mask->value);
1627 #endif
1628
1629   spi_deregister_controller_key_listener (controller, key_listener, ev);
1630
1631   spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1632 }
1633
1634 /*
1635  * CORBA Accessibility::DEController::deregisterDeviceEventListener
1636  *     method implementation
1637  */
1638 static void
1639 impl_deregister_device_listener (PortableServer_Servant                  servant,
1640                                  const Accessibility_DeviceEventListener l,
1641                                  const Accessibility_EventTypeSeq       *event_types,
1642                                  CORBA_Environment                      *ev)
1643 {
1644   SpiDEController *controller;
1645   DEControllerListener *listener = 
1646           spi_dec_listener_new (l, event_types, ev);
1647
1648   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1649
1650   spi_deregister_controller_device_listener (controller, listener, ev);
1651
1652   spi_dec_listener_free (listener, ev);
1653 }
1654
1655 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1656 {
1657   unsigned int retval = 0;
1658   DEControllerPrivateData *priv = (DEControllerPrivateData *)
1659           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1660 #ifdef HAVE_XKB
1661 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY      
1662   retval = XkbGetSlowKeysDelay (spi_get_display (),
1663                                 XkbUseCoreKbd, &bounce_delay);
1664 #else
1665   if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1666     {
1667       Status s = XkbGetControls (spi_get_display (),
1668                                  XkbAllControlsMask, priv->xkb_desc);
1669       if (s == Success)
1670         {
1671          if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1672                  retval = priv->xkb_desc->ctrls->slow_keys_delay;
1673         }
1674     }
1675 #endif
1676 #endif
1677 #ifdef SPI_XKB_DEBUG
1678         fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1679 #endif
1680         return retval;
1681 }
1682
1683 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1684 {
1685   unsigned int retval = 0;
1686   DEControllerPrivateData *priv = (DEControllerPrivateData *)
1687           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1688 #ifdef HAVE_XKB
1689 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY    
1690   retval = XkbGetBounceKeysDelay (spi_get_display (),
1691                                   XkbUseCoreKbd, &bounce_delay);
1692 #else
1693   if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1694     {
1695       Status s = XkbGetControls (spi_get_display (),
1696                                  XkbAllControlsMask, priv->xkb_desc);
1697       if (s == Success)
1698         {
1699           if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1700                   retval = priv->xkb_desc->ctrls->debounce_delay;
1701         }
1702     }
1703 #endif
1704 #endif
1705 #ifdef SPI_XKB_DEBUG
1706   fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1707 #endif
1708   return retval;
1709 }
1710
1711 static gboolean
1712 dec_synth_keycode_press (SpiDEController *controller,
1713                          unsigned int keycode)
1714 {
1715         unsigned int time = CurrentTime;
1716         unsigned int bounce_delay;
1717         unsigned int elapsed_msec;
1718         struct timeval tv;
1719         DEControllerPrivateData *priv =
1720                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1721                                                                 spi_dec_private_quark);
1722         if (keycode == priv->last_release_keycode)
1723         {
1724                 bounce_delay = dec_xkb_get_bouncekeys_delay (controller); 
1725                 if (bounce_delay)
1726                 {
1727                         gettimeofday (&tv, NULL);
1728                         elapsed_msec =
1729                                 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1730                                 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1731 #ifdef SPI_XKB_DEBUG                    
1732                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1733                                  (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1734 #endif
1735 #ifdef THIS_IS_BROKEN
1736                         if (elapsed_msec < bounce_delay)
1737                                 time = bounce_delay - elapsed_msec + 1;
1738 #else
1739                         time = bounce_delay + 10;
1740                         /* fudge for broken XTest */
1741 #endif
1742 #ifdef SPI_XKB_DEBUG                    
1743                         fprintf (stderr, "waiting %d ms\n", time);
1744 #endif
1745                 }
1746         }
1747         XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1748         priv->last_press_keycode = keycode;
1749         XSync (spi_get_display (), False);
1750         gettimeofday (&priv->last_press_time, NULL);
1751         return TRUE;
1752 }
1753
1754 static gboolean
1755 dec_synth_keycode_release (SpiDEController *controller,
1756                            unsigned int keycode)
1757 {
1758         unsigned int time = CurrentTime;
1759         unsigned int slow_delay;
1760         unsigned int elapsed_msec;
1761         struct timeval tv;
1762         DEControllerPrivateData *priv =
1763                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1764                                                                 spi_dec_private_quark);
1765         if (keycode == priv->last_press_keycode)
1766         {
1767                 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1768                 if (slow_delay)
1769                 {
1770                         gettimeofday (&tv, NULL);
1771                         elapsed_msec =
1772                                 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1773                                 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1774 #ifdef SPI_XKB_DEBUG                    
1775                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1776                                  (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1777 #endif
1778 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1779                         if (elapsed_msec < slow_delay)
1780                                 time = slow_delay - elapsed_msec + 1;
1781 #else
1782                         time = slow_delay + 10;
1783                         /* our XTest seems broken, we have to add slop as above */
1784 #endif
1785 #ifdef SPI_XKB_DEBUG                    
1786                         fprintf (stderr, "waiting %d ms\n", time);
1787 #endif
1788                 }
1789         }
1790         XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1791         priv->last_release_keycode = keycode;
1792         XSync (spi_get_display (), False);
1793         gettimeofday (&priv->last_release_time, NULL);
1794         return TRUE;
1795 }
1796
1797 /*
1798  * CORBA Accessibility::DEController::registerKeystrokeListener
1799  *     method implementation
1800  */
1801 static void
1802 impl_generate_keyboard_event (PortableServer_Servant           servant,
1803                               const CORBA_long                 keycode,
1804                               const CORBA_char                *keystring,
1805                               const Accessibility_KeySynthType synth_type,
1806                               CORBA_Environment               *ev)
1807 {
1808   SpiDEController *controller =
1809         SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1810   long key_synth_code;
1811   KeySym keysym;
1812
1813 #ifdef SPI_DEBUG
1814         fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1815                  (long) keycode, (int) synth_type);
1816 #endif
1817   /* TODO: hide/wrap/remove X dependency */
1818
1819   /*
1820    * TODO: when initializing, query for XTest extension before using,
1821    * and fall back to XSendEvent() if XTest is not available.
1822    */
1823   
1824   /* TODO: implement keystring mode also */
1825   gdk_error_trap_push ();
1826   key_synth_code = keycode;
1827
1828   switch (synth_type)
1829     {
1830       case Accessibility_KEY_PRESS:
1831               dec_synth_keycode_press (controller, keycode);
1832               break;
1833       case Accessibility_KEY_PRESSRELEASE:
1834               dec_synth_keycode_press (controller, keycode);
1835       case Accessibility_KEY_RELEASE:
1836               dec_synth_keycode_release (controller, keycode);
1837               break;
1838       case Accessibility_KEY_SYM:
1839 #ifdef SPI_XKB_DEBUG          
1840               fprintf (stderr, "KeySym synthesis\n");
1841 #endif
1842               key_synth_code = keycode_for_keysym (keycode);
1843               dec_synth_keycode_press (controller, key_synth_code);
1844               dec_synth_keycode_release (controller, key_synth_code);
1845               break;
1846       case Accessibility_KEY_STRING:
1847               fprintf (stderr, "Not yet implemented\n");
1848               break;
1849     }
1850   if (gdk_error_trap_pop ())
1851     {
1852       DBG (-1, g_warning ("Error emitting keystroke"));
1853     }
1854   if (synth_type == Accessibility_KEY_SYM) {
1855     keysym = keycode;
1856   }
1857   else {
1858     keysym = XkbKeycodeToKeysym (spi_get_display (), keycode, 0, 0);
1859   }
1860   if (XkbKeysymToModifiers (spi_get_display (), keysym) == 0) 
1861     {
1862       spi_dec_clear_unlatch_pending (controller);
1863     }
1864 }
1865
1866 /* Accessibility::DEController::generateMouseEvent */
1867 static void
1868 impl_generate_mouse_event (PortableServer_Servant servant,
1869                            const CORBA_long       x,
1870                            const CORBA_long       y,
1871                            const CORBA_char      *eventName,
1872                            CORBA_Environment     *ev)
1873 {
1874   int button = 0;
1875   gboolean error = FALSE;
1876   Display *display = spi_get_display ();
1877 #ifdef SPI_DEBUG
1878   fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1879            eventName, (long int) x, (long int) y);
1880 #endif
1881   switch (eventName[0])
1882     {
1883       case 'b':
1884         switch (eventName[1])
1885           {
1886           /* TODO: check number of buttons before parsing */
1887           case '1':
1888                     button = 1;
1889                     break;
1890           case '2':
1891                   button = 2;
1892                   break;
1893           case '3':
1894                   button = 3;
1895                   break;
1896           case '4':
1897                   button = 4;
1898                   break;
1899           case '5':
1900                   button = 5;
1901                   break;
1902           default:
1903                   error = TRUE;
1904           }
1905         if (!error)
1906           {
1907             if (x != -1 && y != -1)
1908               {
1909                 XTestFakeMotionEvent (display, DefaultScreen (display),
1910                                       x, y, 0);
1911               }
1912             XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1913             if (eventName[2] == 'c')
1914               XTestFakeButtonEvent (display, button, FALSE, 1);
1915             else if (eventName[2] == 'd')
1916               {
1917               XTestFakeButtonEvent (display, button, FALSE, 1);
1918               XTestFakeButtonEvent (display, button, TRUE, 2);
1919               XTestFakeButtonEvent (display, button, FALSE, 3);
1920               }
1921           }
1922         break;
1923       case 'r': /* relative motion */ 
1924         XTestFakeRelativeMotionEvent (display, x, y, 0);
1925         break;
1926       case 'a': /* absolute motion */
1927         XTestFakeMotionEvent (display, DefaultScreen (display),
1928                               x, y, 0);
1929         break;
1930     }
1931 }
1932
1933 /* Accessibility::DEController::notifyListenersSync */
1934 static CORBA_boolean
1935 impl_notify_listeners_sync (PortableServer_Servant           servant,
1936                             const Accessibility_DeviceEvent *event,
1937                             CORBA_Environment               *ev)
1938 {
1939   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1940     bonobo_object_from_servant (servant));
1941 #ifdef SPI_DEBUG
1942   g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1943            controller, (int) event->id);
1944 #endif
1945   return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1946           CORBA_TRUE : CORBA_FALSE; 
1947 }
1948
1949 /* Accessibility::DEController::notifyListenersAsync */
1950 static void
1951 impl_notify_listeners_async (PortableServer_Servant           servant,
1952                              const Accessibility_DeviceEvent *event,
1953                              CORBA_Environment               *ev)
1954 {
1955   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1956     bonobo_object_from_servant (servant));
1957 #ifdef SPI_DEBUG
1958   fprintf (stderr, "notifying listeners asynchronously\n");
1959 #endif
1960   spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev); 
1961 }
1962
1963 static void
1964 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1965 {
1966   GObjectClass * object_class = (GObjectClass *) klass;
1967   POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1968
1969   spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1970   
1971   object_class->finalize = spi_device_event_controller_object_finalize;
1972         
1973   epv->registerKeystrokeListener   = impl_register_keystroke_listener;
1974   epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1975   epv->registerDeviceEventListener = impl_register_device_listener;
1976   epv->deregisterDeviceEventListener = impl_deregister_device_listener;
1977   epv->generateKeyboardEvent       = impl_generate_keyboard_event;
1978   epv->generateMouseEvent          = impl_generate_mouse_event;
1979   epv->notifyListenersSync         = impl_notify_listeners_sync;
1980   epv->notifyListenersAsync        = impl_notify_listeners_async;
1981
1982   if (!spi_dec_private_quark)
1983           spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1984 }
1985
1986 static void
1987 spi_device_event_controller_init (SpiDEController *device_event_controller)
1988 {
1989   DEControllerPrivateData *private;     
1990   device_event_controller->key_listeners   = NULL;
1991   device_event_controller->mouse_listeners = NULL;
1992   device_event_controller->keygrabs_list   = NULL;
1993
1994   private = g_new0 (DEControllerPrivateData, 1);
1995   gettimeofday (&private->last_press_time, NULL);
1996   gettimeofday (&private->last_release_time, NULL);
1997   g_object_set_qdata (G_OBJECT (device_event_controller),
1998                       spi_dec_private_quark,
1999                       private);
2000   spi_controller_register_with_devices (device_event_controller);
2001 }
2002
2003 static void
2004 spi_device_event_controller_forward_key_event (SpiDEController *controller,
2005                                                const XEvent    *event)
2006 {
2007   gboolean is_consumed = FALSE;
2008   CORBA_Environment ev;
2009   Accessibility_DeviceEvent key_event;
2010
2011   g_assert (event->type == KeyPress || event->type == KeyRelease);
2012
2013   CORBA_exception_init (&ev);
2014
2015   key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
2016
2017   spi_controller_update_key_grabs (controller, &key_event);
2018
2019   /* relay to listeners, and decide whether to consume it or not */
2020   is_consumed = spi_controller_notify_keylisteners (
2021           controller, &key_event, CORBA_TRUE, &ev);
2022
2023   if (is_consumed)
2024     {
2025       XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
2026     }
2027   else
2028     {
2029       XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
2030     }
2031 }
2032
2033 SpiDEController *
2034 spi_device_event_controller_new (SpiRegistry *registry)
2035 {
2036   SpiDEController *retval = g_object_new (
2037     SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
2038   
2039   retval->registry = SPI_REGISTRY (bonobo_object_ref (
2040           BONOBO_OBJECT (registry)));
2041
2042   spi_dec_init_mouse_listener (registry);
2043   /* TODO: kill mouse listener on finalize */  
2044   return retval;
2045 }
2046
2047 BONOBO_TYPE_FUNC_FULL (SpiDEController,
2048                        Accessibility_DeviceEventController,
2049                        PARENT_TYPE,
2050                        spi_device_event_controller);