bf512409a9b136b76926fe5da8e8e2308ca15afe
[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, 2003 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         key_event.event_string = CORBA_string_dup ("Tab");
1253         break;
1254       case XK_BackSpace:
1255         key_event.event_string = CORBA_string_dup ("Backspace");
1256         break;
1257       case XK_Return:
1258         key_event.event_string = CORBA_string_dup ("Return");
1259         break;
1260       case XK_Home:
1261         key_event.event_string = CORBA_string_dup ("Home");
1262         break;
1263       case XK_Page_Down:
1264         key_event.event_string = CORBA_string_dup ("Page_Down");
1265         break;
1266       case XK_Page_Up:
1267         key_event.event_string = CORBA_string_dup ("Page_Up");
1268         break;
1269       case XK_F1:
1270         key_event.event_string = CORBA_string_dup ("F1");
1271         break;
1272       case XK_F2:
1273         key_event.event_string = CORBA_string_dup ("F2");
1274         break;
1275       case XK_F3:
1276         key_event.event_string = CORBA_string_dup ("F3");
1277         break;
1278       case XK_F4:
1279         key_event.event_string = CORBA_string_dup ("F4");
1280         break;
1281       case XK_F5:
1282         key_event.event_string = CORBA_string_dup ("F5");
1283         break;
1284       case XK_F6:
1285         key_event.event_string = CORBA_string_dup ("F6");
1286         break;
1287       case XK_F7:
1288         key_event.event_string = CORBA_string_dup ("F7");
1289         break;
1290       case XK_F8:
1291         key_event.event_string = CORBA_string_dup ("F8");
1292         break;
1293       case XK_F9:
1294         key_event.event_string = CORBA_string_dup ("F9");
1295         break;
1296       case XK_F10:
1297         key_event.event_string = CORBA_string_dup ("F10");
1298         break;
1299       case XK_F11:
1300         key_event.event_string = CORBA_string_dup ("F11");
1301         break;
1302       case XK_F12:
1303         key_event.event_string = CORBA_string_dup ("F12");
1304         break;
1305       case XK_End:
1306         key_event.event_string = CORBA_string_dup ("End");
1307         break;
1308       case XK_Escape:
1309         key_event.event_string = CORBA_string_dup ("Escape");
1310         break;
1311       case XK_Up:
1312         key_event.event_string = CORBA_string_dup ("Up");
1313         break;
1314       case XK_Down:
1315         key_event.event_string = CORBA_string_dup ("Down");
1316         break;
1317       case XK_Left:
1318         key_event.event_string = CORBA_string_dup ("Left");
1319         break;
1320       case XK_Right:
1321         key_event.event_string = CORBA_string_dup ("Right");
1322         break;
1323       default:
1324         if (nbytes > 0)
1325           {
1326             gunichar c;
1327             cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
1328             key_event.event_string = CORBA_string_dup (cbuf);
1329             c = g_utf8_get_char_validated (cbuf, nbytes);
1330             if ((c > 0) && g_unichar_isprint (c))
1331               {
1332                 key_event.is_text = CORBA_TRUE; 
1333                 /* incorrect for some composed chars? */
1334               }
1335           }
1336         else
1337           {
1338             key_event.event_string = CORBA_string_dup ("");
1339           }
1340     }
1341
1342   key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
1343 #ifdef SPI_KEYEVENT_DEBUG
1344   fprintf (stderr,
1345            "Key %lu pressed (%c), modifiers %d; string=%s [%x] %s\n",
1346            (unsigned long) keysym,
1347            keysym ? (int) keysym : '*',
1348            (int) x_key_event->state,
1349            key_event.event_string,
1350            key_event.event_string[0],
1351            (key_event.is_text == CORBA_TRUE) ? "(text)" : "(not text)");
1352 #endif
1353 #ifdef SPI_DEBUG
1354   fprintf (stderr, "%s%c",
1355      (x_key_event->state & Mod1Mask)?"Alt-":"",
1356      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
1357      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
1358 #endif /* SPI_DEBUG */
1359   return key_event;     
1360 }
1361
1362 static gboolean
1363 spi_controller_update_key_grabs (SpiDEController           *controller,
1364                                  Accessibility_DeviceEvent *recv)
1365 {
1366   GList *l, *next;
1367   gboolean   update_failed = FALSE;
1368   
1369   g_return_val_if_fail (controller != NULL, FALSE);
1370
1371   /*
1372    * masks known to work with default RH 7.1+:
1373    * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
1374    * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
1375    * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
1376    * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
1377    *
1378    * ControlMask grabs are broken, must be in use already
1379    */
1380   for (l = controller->keygrabs_list; l; l = next)
1381     {
1382       gboolean do_remove;
1383       gboolean re_issue_grab;
1384       DEControllerGrabMask *grab_mask = l->data;
1385
1386       next = l->next;
1387
1388       re_issue_grab = recv &&
1389 /*            (recv->type == Accessibility_KEY_RELEASED) && - (?) */
1390               (recv->modifiers & grab_mask->mod_mask) &&
1391               (grab_mask->key_val == keycode_for_keysym (recv->id));
1392
1393 #ifdef SPI_DEBUG
1394       fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
1395                (long int) grab_mask->key_val,
1396                (long int) grab_mask->mod_mask,
1397                grab_mask->pending_add ? '+' : '.',
1398                grab_mask->pending_remove ? '-' : '.',
1399                re_issue_grab ? "re-issue": "");
1400 #endif
1401
1402       do_remove = FALSE;
1403
1404       if (grab_mask->pending_add && grab_mask->pending_remove)
1405         {
1406           do_remove = TRUE;
1407         }
1408       else if (grab_mask->pending_remove)
1409         {
1410 #ifdef SPI_DEBUG
1411       fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1412 #endif
1413           XUngrabKey (spi_get_display (),
1414                       grab_mask->key_val,
1415                       grab_mask->mod_mask,
1416                       gdk_x11_get_default_root_xwindow ());
1417
1418           do_remove = TRUE;
1419         }
1420       else if (grab_mask->pending_add || re_issue_grab)
1421         {
1422
1423 #ifdef SPI_DEBUG
1424           fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1425 #endif
1426           XGrabKey (spi_get_display (),
1427                     grab_mask->key_val,
1428                     grab_mask->mod_mask,
1429                     gdk_x11_get_default_root_xwindow (),
1430                     True,
1431                     GrabModeSync,
1432                     GrabModeSync);
1433           XSync (spi_get_display (), False);
1434           update_failed = spi_clear_error_state ();
1435           if (update_failed) {
1436                   while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1437                   do_remove = TRUE;
1438           }
1439         }
1440
1441       grab_mask->pending_add = FALSE;
1442       grab_mask->pending_remove = FALSE;
1443
1444       if (do_remove)
1445         {
1446           g_assert (grab_mask->ref_count <= 0);
1447
1448           controller->keygrabs_list = g_list_delete_link (
1449             controller->keygrabs_list, l);
1450
1451           spi_grab_mask_free (grab_mask);
1452         }
1453
1454     } 
1455
1456   return ! update_failed;
1457 }
1458
1459 /*
1460  * Implemented GObject::finalize
1461  */
1462 static void
1463 spi_device_event_controller_object_finalize (GObject *object)
1464 {
1465   SpiDEController *controller;
1466   DEControllerPrivateData *private;
1467   controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1468
1469 #ifdef SPI_DEBUG
1470   fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1471 #endif
1472   /* disconnect any special listeners, get rid of outstanding keygrabs */
1473   XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1474
1475   private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
1476   if (private->xkb_desc)
1477           XkbFreeKeyboard (private->xkb_desc, 0, True);
1478   g_free (private);
1479   spi_device_event_controller_parent_class->finalize (object);
1480 }
1481
1482 /*
1483  * CORBA Accessibility::DEController::registerKeystrokeListener
1484  *     method implementation
1485  */
1486 static CORBA_boolean
1487 impl_register_keystroke_listener (PortableServer_Servant                  servant,
1488                                   const Accessibility_DeviceEventListener l,
1489                                   const Accessibility_KeySet             *keys,
1490                                   const Accessibility_ControllerEventMask mask,
1491                                   const Accessibility_EventTypeSeq       *type,
1492                                   const Accessibility_EventListenerMode  *mode,
1493                                   CORBA_Environment                      *ev)
1494 {
1495   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1496           bonobo_object_from_servant (servant));
1497   DEControllerKeyListener *dec_listener;
1498 #ifdef SPI_DEBUG
1499   fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1500            (void *) l, (unsigned long) mask);
1501 #endif
1502   dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1503   return spi_controller_register_device_listener (
1504           controller, (DEControllerListener *) dec_listener, ev);
1505 }
1506
1507
1508 /*
1509  * CORBA Accessibility::DEController::registerDeviceEventListener
1510  *     method implementation
1511  */
1512 static CORBA_boolean
1513 impl_register_device_listener (PortableServer_Servant                  servant,
1514                                const Accessibility_DeviceEventListener l,
1515                                const Accessibility_EventTypeSeq       *event_types,
1516                                CORBA_Environment                      *ev)
1517 {
1518   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1519           bonobo_object_from_servant (servant));
1520   DEControllerListener *dec_listener;
1521
1522   dec_listener = spi_dec_listener_new (l, event_types, ev);
1523   return spi_controller_register_device_listener (
1524           controller, (DEControllerListener *) dec_listener, ev);
1525 }
1526
1527 typedef struct {
1528         CORBA_Environment       *ev;
1529         DEControllerListener    *listener;
1530 } RemoveListenerClosure;
1531
1532 static SpiReEntrantContinue
1533 remove_listener_cb (GList * const *list,
1534                     gpointer       user_data)
1535 {
1536   DEControllerListener  *listener = (*list)->data;
1537   RemoveListenerClosure *ctx = user_data;
1538
1539   if (CORBA_Object_is_equivalent (ctx->listener->object,
1540                                   listener->object, ctx->ev))
1541     {
1542       spi_re_entrant_list_delete_link (list);
1543       spi_dec_listener_free (listener, ctx->ev);
1544     }
1545
1546   return SPI_RE_ENTRANT_CONTINUE;
1547 }
1548
1549 static SpiReEntrantContinue
1550 copy_key_listener_cb (GList * const *list,
1551                       gpointer       user_data)
1552 {
1553   DEControllerKeyListener  *key_listener = (*list)->data;
1554   RemoveListenerClosure    *ctx = user_data;
1555
1556   if (CORBA_Object_is_equivalent (ctx->listener->object,
1557                                   key_listener->listener.object, ctx->ev))
1558     {
1559       /* TODO: FIXME aggregate keys in case the listener is registered twice */
1560       DEControllerKeyListener *ctx_key_listener = 
1561         (DEControllerKeyListener *) ctx->listener; 
1562       CORBA_free (ctx_key_listener->keys);          
1563       ctx_key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1564     }
1565
1566   return SPI_RE_ENTRANT_CONTINUE;
1567 }
1568
1569 static void
1570 spi_deregister_controller_device_listener (SpiDEController            *controller,
1571                                            DEControllerListener *listener,
1572                                            CORBA_Environment          *ev)
1573 {
1574   RemoveListenerClosure  ctx;
1575
1576   ctx.ev = ev;
1577   ctx.listener = listener;
1578
1579   spi_re_entrant_list_foreach (&controller->mouse_listeners,
1580                                remove_listener_cb, &ctx);
1581 }
1582
1583 static void
1584 spi_deregister_controller_key_listener (SpiDEController            *controller,
1585                                         DEControllerKeyListener    *key_listener,
1586                                         CORBA_Environment          *ev)
1587 {
1588   RemoveListenerClosure  ctx;
1589
1590   ctx.ev = ev;
1591   ctx.listener = (DEControllerListener *) key_listener;
1592
1593   /* special case, copy keyset from existing controller list entry */
1594   if (key_listener->keys->_length == 0) 
1595     {
1596       spi_re_entrant_list_foreach (&controller->key_listeners,
1597                                   copy_key_listener_cb, &ctx);
1598     }
1599   
1600   spi_controller_deregister_global_keygrabs (controller, key_listener);
1601
1602   spi_re_entrant_list_foreach (&controller->key_listeners,
1603                                 remove_listener_cb, &ctx);
1604
1605 }
1606
1607 /*
1608  * CORBA Accessibility::DEController::deregisterKeystrokeListener
1609  *     method implementation
1610  */
1611 static void
1612 impl_deregister_keystroke_listener (PortableServer_Servant                  servant,
1613                                     const Accessibility_DeviceEventListener l,
1614                                     const Accessibility_KeySet             *keys,
1615                                     const Accessibility_ControllerEventMask mask,
1616                                     const Accessibility_EventTypeSeq       *type,
1617                                     CORBA_Environment                      *ev)
1618 {
1619   DEControllerKeyListener  *key_listener;
1620   SpiDEController *controller;
1621
1622   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1623
1624   key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1625
1626 #ifdef SPI_DEREGISTER_DEBUG
1627   fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1628            (void *) l, (unsigned long) mask->value);
1629 #endif
1630
1631   spi_deregister_controller_key_listener (controller, key_listener, ev);
1632
1633   spi_dec_listener_free ((DEControllerListener *) key_listener, ev);
1634 }
1635
1636 /*
1637  * CORBA Accessibility::DEController::deregisterDeviceEventListener
1638  *     method implementation
1639  */
1640 static void
1641 impl_deregister_device_listener (PortableServer_Servant                  servant,
1642                                  const Accessibility_DeviceEventListener l,
1643                                  const Accessibility_EventTypeSeq       *event_types,
1644                                  CORBA_Environment                      *ev)
1645 {
1646   SpiDEController *controller;
1647   DEControllerListener *listener = 
1648           spi_dec_listener_new (l, event_types, ev);
1649
1650   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1651
1652   spi_deregister_controller_device_listener (controller, listener, ev);
1653
1654   spi_dec_listener_free (listener, ev);
1655 }
1656
1657 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1658 {
1659   unsigned int retval = 0;
1660   DEControllerPrivateData *priv = (DEControllerPrivateData *)
1661           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1662 #ifdef HAVE_XKB
1663 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY      
1664   retval = XkbGetSlowKeysDelay (spi_get_display (),
1665                                 XkbUseCoreKbd, &bounce_delay);
1666 #else
1667   if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1668     {
1669       Status s = XkbGetControls (spi_get_display (),
1670                                  XkbAllControlsMask, priv->xkb_desc);
1671       if (s == Success)
1672         {
1673          if (priv->xkb_desc->ctrls->enabled_ctrls & XkbSlowKeysMask)
1674                  retval = priv->xkb_desc->ctrls->slow_keys_delay;
1675         }
1676     }
1677 #endif
1678 #endif
1679 #ifdef SPI_XKB_DEBUG
1680         fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1681 #endif
1682         return retval;
1683 }
1684
1685 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1686 {
1687   unsigned int retval = 0;
1688   DEControllerPrivateData *priv = (DEControllerPrivateData *)
1689           g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
1690 #ifdef HAVE_XKB
1691 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY    
1692   retval = XkbGetBounceKeysDelay (spi_get_display (),
1693                                   XkbUseCoreKbd, &bounce_delay);
1694 #else
1695   if (!(priv->xkb_desc == (XkbDescPtr) BadAlloc || priv->xkb_desc == NULL))
1696     {
1697       Status s = XkbGetControls (spi_get_display (),
1698                                  XkbAllControlsMask, priv->xkb_desc);
1699       if (s == Success)
1700         {
1701           if (priv->xkb_desc->ctrls->enabled_ctrls & XkbBounceKeysMask)
1702                   retval = priv->xkb_desc->ctrls->debounce_delay;
1703         }
1704     }
1705 #endif
1706 #endif
1707 #ifdef SPI_XKB_DEBUG
1708   fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1709 #endif
1710   return retval;
1711 }
1712
1713 static gboolean
1714 dec_synth_keycode_press (SpiDEController *controller,
1715                          unsigned int keycode)
1716 {
1717         unsigned int time = CurrentTime;
1718         unsigned int bounce_delay;
1719         unsigned int elapsed_msec;
1720         struct timeval tv;
1721         DEControllerPrivateData *priv =
1722                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1723                                                                 spi_dec_private_quark);
1724         if (keycode == priv->last_release_keycode)
1725         {
1726                 bounce_delay = dec_xkb_get_bouncekeys_delay (controller); 
1727                 if (bounce_delay)
1728                 {
1729                         gettimeofday (&tv, NULL);
1730                         elapsed_msec =
1731                                 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1732                                 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1733 #ifdef SPI_XKB_DEBUG                    
1734                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1735                                  (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1736 #endif
1737 #ifdef THIS_IS_BROKEN
1738                         if (elapsed_msec < bounce_delay)
1739                                 time = bounce_delay - elapsed_msec + 1;
1740 #else
1741                         time = bounce_delay + 10;
1742                         /* fudge for broken XTest */
1743 #endif
1744 #ifdef SPI_XKB_DEBUG                    
1745                         fprintf (stderr, "waiting %d ms\n", time);
1746 #endif
1747                 }
1748         }
1749         XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1750         priv->last_press_keycode = keycode;
1751         XSync (spi_get_display (), False);
1752         gettimeofday (&priv->last_press_time, NULL);
1753         return TRUE;
1754 }
1755
1756 static gboolean
1757 dec_synth_keycode_release (SpiDEController *controller,
1758                            unsigned int keycode)
1759 {
1760         unsigned int time = CurrentTime;
1761         unsigned int slow_delay;
1762         unsigned int elapsed_msec;
1763         struct timeval tv;
1764         DEControllerPrivateData *priv =
1765                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1766                                                                 spi_dec_private_quark);
1767         if (keycode == priv->last_press_keycode)
1768         {
1769                 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1770                 if (slow_delay)
1771                 {
1772                         gettimeofday (&tv, NULL);
1773                         elapsed_msec =
1774                                 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1775                                 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1776 #ifdef SPI_XKB_DEBUG                    
1777                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1778                                  (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1779 #endif
1780 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1781                         if (elapsed_msec < slow_delay)
1782                                 time = slow_delay - elapsed_msec + 1;
1783 #else
1784                         time = slow_delay + 10;
1785                         /* our XTest seems broken, we have to add slop as above */
1786 #endif
1787 #ifdef SPI_XKB_DEBUG                    
1788                         fprintf (stderr, "waiting %d ms\n", time);
1789 #endif
1790                 }
1791         }
1792         XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1793         priv->last_release_keycode = keycode;
1794         XSync (spi_get_display (), False);
1795         gettimeofday (&priv->last_release_time, NULL);
1796         return TRUE;
1797 }
1798
1799 /*
1800  * CORBA Accessibility::DEController::registerKeystrokeListener
1801  *     method implementation
1802  */
1803 static void
1804 impl_generate_keyboard_event (PortableServer_Servant           servant,
1805                               const CORBA_long                 keycode,
1806                               const CORBA_char                *keystring,
1807                               const Accessibility_KeySynthType synth_type,
1808                               CORBA_Environment               *ev)
1809 {
1810   SpiDEController *controller =
1811         SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1812   long key_synth_code;
1813   KeySym keysym;
1814
1815 #ifdef SPI_DEBUG
1816         fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1817                  (long) keycode, (int) synth_type);
1818 #endif
1819   /* TODO: hide/wrap/remove X dependency */
1820
1821   /*
1822    * TODO: when initializing, query for XTest extension before using,
1823    * and fall back to XSendEvent() if XTest is not available.
1824    */
1825   
1826   /* TODO: implement keystring mode also */
1827   gdk_error_trap_push ();
1828   key_synth_code = keycode;
1829
1830   switch (synth_type)
1831     {
1832       case Accessibility_KEY_PRESS:
1833               dec_synth_keycode_press (controller, keycode);
1834               break;
1835       case Accessibility_KEY_PRESSRELEASE:
1836               dec_synth_keycode_press (controller, keycode);
1837       case Accessibility_KEY_RELEASE:
1838               dec_synth_keycode_release (controller, keycode);
1839               break;
1840       case Accessibility_KEY_SYM:
1841 #ifdef SPI_XKB_DEBUG          
1842               fprintf (stderr, "KeySym synthesis\n");
1843 #endif
1844               key_synth_code = keycode_for_keysym (keycode);
1845               dec_synth_keycode_press (controller, key_synth_code);
1846               dec_synth_keycode_release (controller, key_synth_code);
1847               break;
1848       case Accessibility_KEY_STRING:
1849               fprintf (stderr, "Not yet implemented\n");
1850               break;
1851     }
1852   if (gdk_error_trap_pop ())
1853     {
1854       DBG (-1, g_warning ("Error emitting keystroke"));
1855     }
1856   if (synth_type == Accessibility_KEY_SYM) {
1857     keysym = keycode;
1858   }
1859   else {
1860     keysym = XkbKeycodeToKeysym (spi_get_display (), keycode, 0, 0);
1861   }
1862   if (XkbKeysymToModifiers (spi_get_display (), keysym) == 0) 
1863     {
1864       spi_dec_clear_unlatch_pending (controller);
1865     }
1866 }
1867
1868 /* Accessibility::DEController::generateMouseEvent */
1869 static void
1870 impl_generate_mouse_event (PortableServer_Servant servant,
1871                            const CORBA_long       x,
1872                            const CORBA_long       y,
1873                            const CORBA_char      *eventName,
1874                            CORBA_Environment     *ev)
1875 {
1876   int button = 0;
1877   gboolean error = FALSE;
1878   Display *display = spi_get_display ();
1879 #ifdef SPI_DEBUG
1880   fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1881            eventName, (long int) x, (long int) y);
1882 #endif
1883   switch (eventName[0])
1884     {
1885       case 'b':
1886         switch (eventName[1])
1887           {
1888           /* TODO: check number of buttons before parsing */
1889           case '1':
1890                     button = 1;
1891                     break;
1892           case '2':
1893                   button = 2;
1894                   break;
1895           case '3':
1896                   button = 3;
1897                   break;
1898           case '4':
1899                   button = 4;
1900                   break;
1901           case '5':
1902                   button = 5;
1903                   break;
1904           default:
1905                   error = TRUE;
1906           }
1907         if (!error)
1908           {
1909             if (x != -1 && y != -1)
1910               {
1911                 XTestFakeMotionEvent (display, DefaultScreen (display),
1912                                       x, y, 0);
1913               }
1914             XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1915             if (eventName[2] == 'c')
1916               XTestFakeButtonEvent (display, button, FALSE, 1);
1917             else if (eventName[2] == 'd')
1918               {
1919               XTestFakeButtonEvent (display, button, FALSE, 1);
1920               XTestFakeButtonEvent (display, button, TRUE, 2);
1921               XTestFakeButtonEvent (display, button, FALSE, 3);
1922               }
1923           }
1924         break;
1925       case 'r': /* relative motion */ 
1926         XTestFakeRelativeMotionEvent (display, x, y, 0);
1927         break;
1928       case 'a': /* absolute motion */
1929         XTestFakeMotionEvent (display, DefaultScreen (display),
1930                               x, y, 0);
1931         break;
1932     }
1933 }
1934
1935 /* Accessibility::DEController::notifyListenersSync */
1936 static CORBA_boolean
1937 impl_notify_listeners_sync (PortableServer_Servant           servant,
1938                             const Accessibility_DeviceEvent *event,
1939                             CORBA_Environment               *ev)
1940 {
1941   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1942     bonobo_object_from_servant (servant));
1943 #ifdef SPI_DEBUG
1944   g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1945            controller, (int) event->id);
1946 #endif
1947   return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1948           CORBA_TRUE : CORBA_FALSE; 
1949 }
1950
1951 /* Accessibility::DEController::notifyListenersAsync */
1952 static void
1953 impl_notify_listeners_async (PortableServer_Servant           servant,
1954                              const Accessibility_DeviceEvent *event,
1955                              CORBA_Environment               *ev)
1956 {
1957   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1958     bonobo_object_from_servant (servant));
1959 #ifdef SPI_DEBUG
1960   fprintf (stderr, "notifying listeners asynchronously\n");
1961 #endif
1962   spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev); 
1963 }
1964
1965 static void
1966 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1967 {
1968   GObjectClass * object_class = (GObjectClass *) klass;
1969   POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1970
1971   spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1972   
1973   object_class->finalize = spi_device_event_controller_object_finalize;
1974         
1975   epv->registerKeystrokeListener   = impl_register_keystroke_listener;
1976   epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1977   epv->registerDeviceEventListener = impl_register_device_listener;
1978   epv->deregisterDeviceEventListener = impl_deregister_device_listener;
1979   epv->generateKeyboardEvent       = impl_generate_keyboard_event;
1980   epv->generateMouseEvent          = impl_generate_mouse_event;
1981   epv->notifyListenersSync         = impl_notify_listeners_sync;
1982   epv->notifyListenersAsync        = impl_notify_listeners_async;
1983
1984   if (!spi_dec_private_quark)
1985           spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1986 }
1987
1988 static void
1989 spi_device_event_controller_init (SpiDEController *device_event_controller)
1990 {
1991   DEControllerPrivateData *private;     
1992   device_event_controller->key_listeners   = NULL;
1993   device_event_controller->mouse_listeners = NULL;
1994   device_event_controller->keygrabs_list   = NULL;
1995
1996   private = g_new0 (DEControllerPrivateData, 1);
1997   gettimeofday (&private->last_press_time, NULL);
1998   gettimeofday (&private->last_release_time, NULL);
1999   g_object_set_qdata (G_OBJECT (device_event_controller),
2000                       spi_dec_private_quark,
2001                       private);
2002   spi_controller_register_with_devices (device_event_controller);
2003 }
2004
2005 static void
2006 spi_device_event_controller_forward_key_event (SpiDEController *controller,
2007                                                const XEvent    *event)
2008 {
2009   gboolean is_consumed = FALSE;
2010   CORBA_Environment ev;
2011   Accessibility_DeviceEvent key_event;
2012
2013   g_assert (event->type == KeyPress || event->type == KeyRelease);
2014
2015   CORBA_exception_init (&ev);
2016
2017   key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
2018
2019   spi_controller_update_key_grabs (controller, &key_event);
2020
2021   /* relay to listeners, and decide whether to consume it or not */
2022   is_consumed = spi_controller_notify_keylisteners (
2023           controller, &key_event, CORBA_TRUE, &ev);
2024
2025   if (is_consumed)
2026     {
2027       XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
2028     }
2029   else
2030     {
2031       XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
2032     }
2033 }
2034
2035 SpiDEController *
2036 spi_device_event_controller_new (SpiRegistry *registry)
2037 {
2038   SpiDEController *retval = g_object_new (
2039     SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
2040   
2041   retval->registry = SPI_REGISTRY (bonobo_object_ref (
2042           BONOBO_OBJECT (registry)));
2043
2044   spi_dec_init_mouse_listener (registry);
2045   /* TODO: kill mouse listener on finalize */  
2046   return retval;
2047 }
2048
2049 BONOBO_TYPE_FUNC_FULL (SpiDEController,
2050                        Accessibility_DeviceEventController,
2051                        PARENT_TYPE,
2052                        spi_device_event_controller);