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