2002-10-23 Vitaly Tishkov <tvv@sparc.spb.su>
[platform/upstream/at-spi2-core.git] / registryd / deviceeventcontroller.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /* deviceeventcontroller.c: implement the DeviceEventController interface */
25
26 #include <config.h>
27
28 #undef  SPI_XKB_DEBUG
29 #undef  SPI_DEBUG
30 #undef  SPI_KEYEVENT_DEBUG
31
32 #include <string.h>
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <bonobo/bonobo-exception.h>
36
37 #include <X11/Xlib.h>
38 #include <X11/extensions/XTest.h>
39 #include <X11/XKBlib.h>
40 #define XK_MISCELLANY
41 #include <X11/keysymdef.h>
42 #include <gdk/gdk.h>
43 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
44 #include <gdk/gdkkeysyms.h>
45 #include <gdk/gdkwindow.h>
46
47 #include "../libspi/spi-private.h"
48 #include "deviceeventcontroller.h"
49
50 /* Our parent Gtk object type */
51 #define PARENT_TYPE BONOBO_TYPE_OBJECT
52
53 /* A pointer to our parent object class */
54 static GObjectClass *spi_device_event_controller_parent_class;
55 static int spi_error_code = 0;
56 static GdkPoint *last_mouse_pos = NULL; 
57 static unsigned int mouse_mask_state = 0;
58 static unsigned int mouse_button_mask =
59   Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
60 static unsigned int key_modifier_mask =
61   Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
62
63 static GQuark spi_dec_private_quark = 0;
64
65 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
66
67 typedef enum {
68   SPI_DEVICE_TYPE_KBD,
69   SPI_DEVICE_TYPE_MOUSE,
70   SPI_DEVICE_TYPE_LAST_DEFINED
71 } SpiDeviceTypeCategory;
72
73 typedef struct {
74   guint                             ref_count : 30;
75   guint                             pending_add : 1;
76   guint                             pending_remove : 1;
77
78   Accessibility_ControllerEventMask mod_mask;
79   CORBA_unsigned_long               key_val;  /* KeyCode */
80 } DEControllerGrabMask;
81
82 typedef struct {
83   CORBA_Object          object;
84   SpiDeviceTypeCategory type;
85 } DEControllerListener;
86
87 typedef struct {
88   DEControllerListener listener;
89
90   Accessibility_KeySet             *keys;
91   Accessibility_ControllerEventMask mask;
92   Accessibility_KeyEventTypeSeq    *typeseq;
93   Accessibility_EventListenerMode  *mode;       
94 } DEControllerKeyListener;
95
96 typedef struct {
97         unsigned int last_press_keycode;
98         unsigned int last_release_keycode;
99         struct timeval last_press_time;
100         struct timeval last_release_time;
101 } DEControllerPrivateData;
102
103 static void     spi_controller_register_with_devices          (SpiDEController           *controller);
104 static gboolean spi_controller_update_key_grabs               (SpiDEController           *controller,
105                                                                Accessibility_DeviceEvent *recv);
106 static gboolean spi_controller_register_device_listener       (SpiDEController           *controller,
107                                                                DEControllerListener      *l,
108                                                                CORBA_Environment         *ev);
109 static void     spi_device_event_controller_forward_key_event (SpiDEController           *controller,
110                                                                const XEvent              *event);
111 static void     spi_deregister_controller_key_listener (SpiDEController         *controller,
112                                                         DEControllerKeyListener *key_listener,
113                                                         CORBA_Environment       *ev);
114
115 static gboolean spi_clear_error_state (void);
116 static gboolean spi_dec_poll_mouse_moved (gpointer data);
117 static gboolean spi_dec_poll_mouse_moving (gpointer data);
118 static gboolean spi_dec_poll_mouse_idle (gpointer data);
119
120 #define spi_get_display() GDK_DISPLAY()
121
122 /* Private methods */
123
124 static KeyCode
125 keycode_for_keysym (long keysym)
126 {
127   return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
128 }
129
130 static DEControllerGrabMask *
131 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
132 {
133   DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
134
135   memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
136
137   clone->ref_count = 1;
138   clone->pending_add = TRUE;
139   clone->pending_remove = FALSE;
140
141   return clone;
142 }
143
144 static void
145 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
146 {
147   g_free (grab_mask);
148 }
149
150 static gint
151 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
152 {
153   DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
154   DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
155
156   if (p1 == p2)
157     {
158       return 0;
159     }
160   else
161     { 
162       return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
163     }
164 }
165
166 static gint poll_count = 0;
167
168 static gboolean
169 spi_dec_poll_mouse_moved (gpointer data)
170 {
171   SpiRegistry *registry = SPI_REGISTRY (data);
172   CORBA_Environment ev;
173   Accessibility_Event e;
174   Window root_return, child_return;
175   int win_x_return,win_y_return;
176   int x, y;
177   int poll_count_modulus = 10;
178   unsigned int mask_return;
179   gchar event_name[24];
180   Display *display = spi_get_display ();
181
182   if (display != NULL)
183           XQueryPointer(display, DefaultRootWindow (display),
184                 &root_return, &child_return,
185                 &x, &y,
186                 &win_x_return, &win_y_return, &mask_return);
187
188   if (mask_return != mouse_mask_state) {
189           if ((mask_return & mouse_button_mask) !=
190               (mouse_mask_state & mouse_button_mask)) {
191                   int button_number = 0;
192                   if (!(mask_return & Button1Mask) &&
193                       (mouse_mask_state & Button1Mask)) {
194                           button_number = 1;
195                   } else if (!(mask_return & Button2Mask) &&
196                              (mouse_mask_state & Button2Mask)) {
197                           button_number = 2;
198                   } else if (!(mask_return & Button3Mask) &&
199                              (mouse_mask_state & Button3Mask)) {
200                           button_number = 3;
201                   } else if (!(mask_return & Button4Mask) &&
202                              (mouse_mask_state & Button1Mask)) {
203                           button_number = 4;
204                   } else if (!(mask_return & Button5Mask) &&
205                              (mouse_mask_state & Button5Mask)) {
206                           button_number = 5;
207                   }
208                   if (button_number) {
209 #ifdef SPI_DEBUG                  
210                           fprintf (stderr, "Button %d Released\n",
211                                    button_number);
212 #endif
213                           snprintf (event_name, 22, "mouse:button:%dr", button_number);
214                           e.type = event_name;
215                           e.source = BONOBO_OBJREF (registry->desktop);
216                           e.detail1 = last_mouse_pos->x;
217                           e.detail2 = last_mouse_pos->y;
218                           CORBA_exception_init (&ev);
219                           Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
220                                                               &e,
221                                                               &ev);
222                   }
223           }
224           if ((mask_return & key_modifier_mask) !=
225               (mouse_mask_state & key_modifier_mask)) {
226 #ifdef SPI_DEBUG
227                   fprintf (stderr, "MODIFIER CHANGE EVENT!\n");
228 #endif
229                   e.type = "keyboard:modifiers";  
230                   e.source = BONOBO_OBJREF (registry->desktop);
231                   e.detail1 = mouse_mask_state;
232                   e.detail2 = mask_return;
233                   CORBA_exception_init (&ev);
234                   Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
235                                                       &e,
236                                                       &ev);
237           }
238           mouse_mask_state = mask_return;
239   }
240   if (last_mouse_pos == NULL) {
241           last_mouse_pos = g_new0 (GdkPoint, 1);
242           last_mouse_pos->x = 0;
243           last_mouse_pos->y = 0;
244   }
245   if (poll_count++ == poll_count_modulus) {
246           poll_count = 0;
247           e.type = "mouse:abs";  
248           e.source = BONOBO_OBJREF (registry->desktop);
249           e.detail1 = x;
250           e.detail2 = y;
251           CORBA_exception_init (&ev);
252           Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
253                                               &e,
254                                               &ev);
255   }
256   if (x != last_mouse_pos->x || y != last_mouse_pos->y) {
257           e.type = "mouse:rel";  
258           e.source = BONOBO_OBJREF (registry->desktop);
259           e.detail1 = x - last_mouse_pos->x;
260           e.detail2 = y - last_mouse_pos->y;
261           CORBA_exception_init (&ev);
262           last_mouse_pos->x = x;
263           last_mouse_pos->y = y;
264           Accessibility_Registry_notifyEvent (BONOBO_OBJREF (registry),
265                                               &e,
266                                               &ev);
267           return TRUE;
268   }
269   return FALSE;
270 }
271
272 static gboolean
273 spi_dec_poll_mouse_idle (gpointer data)
274 {
275   if (! spi_dec_poll_mouse_moved (data)) 
276     return TRUE;
277   else
278     {
279       g_timeout_add (20, spi_dec_poll_mouse_moving, data);          
280       return FALSE;         
281     }
282 }
283
284 static gboolean
285 spi_dec_poll_mouse_moving (gpointer data)
286 {
287   if (spi_dec_poll_mouse_moved (data))
288     return TRUE;
289   else
290     {
291       g_timeout_add (100, spi_dec_poll_mouse_idle, data);           
292       return FALSE;
293     }
294 }
295
296 static int
297 spi_dec_ungrab_mouse (gpointer data)
298 {
299         Display *display = spi_get_display ();
300         fprintf (stderr, "mouse ungrab : display = %p\n", display);
301         if (display)
302           {
303             XUngrabButton (spi_get_display (), AnyButton, AnyModifier,
304                            XDefaultRootWindow (spi_get_display ()));
305             fprintf (stderr, "mouse grab released\n");
306           }
307         return FALSE;
308 }
309
310 static void
311 spi_dec_init_mouse_listener (SpiRegistry *registry)
312 {
313   Display *display = spi_get_display ();
314   g_timeout_add (100, spi_dec_poll_mouse_idle, registry);
315
316   if (display)
317     {
318       XGrabButton (display, AnyButton, 0,
319                    gdk_x11_get_default_root_xwindow (),
320                    True, ButtonPressMask | ButtonReleaseMask,
321                    GrabModeSync, GrabModeAsync, None, None);
322       XSync (display, False);
323 #ifdef SPI_DEBUG
324       fprintf (stderr, "mouse buttons grabbed\n");
325 #endif
326     }
327 }
328
329 static DEControllerKeyListener *
330 spi_dec_key_listener_new (CORBA_Object                            l,
331                           const Accessibility_KeySet             *keys,
332                           const Accessibility_ControllerEventMask mask,
333                           const Accessibility_KeyEventTypeSeq    *typeseq,
334                           const Accessibility_EventListenerMode  *mode,
335                           CORBA_Environment                      *ev)
336 {
337   DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
338   key_listener->listener.object = bonobo_object_dup_ref (l, ev);
339   key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
340   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
341   key_listener->mask = mask;
342   key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
343   if (mode)
344     key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
345   else
346     key_listener->mode = NULL;
347
348 #ifdef SPI_DEBUG
349   g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
350            (unsigned int) key_listener->mask,
351            (int) (mode ? mode->global : 0),
352            (void *) key_listener->keys,
353            (int) (key_listener->keys ? key_listener->keys->_length : 0));
354 #endif
355
356   return key_listener;  
357 }
358
359 static DEControllerKeyListener *
360 spi_key_listener_clone (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
361 {
362   DEControllerKeyListener *clone = g_new0 (DEControllerKeyListener, 1);
363   clone->listener.object =
364           CORBA_Object_duplicate (key_listener->listener.object, ev);
365   clone->listener.type = SPI_DEVICE_TYPE_KBD;
366   clone->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
367   clone->mask = key_listener->mask;
368   clone->typeseq = ORBit_copy_value (key_listener->typeseq, TC_Accessibility_KeyEventTypeSeq);
369   if (key_listener->mode)
370     clone->mode = ORBit_copy_value (key_listener->mode, TC_Accessibility_EventListenerMode);
371   else
372     clone->mode = NULL;
373   return clone;
374 }
375
376 static void
377 spi_key_listener_data_free (DEControllerKeyListener *key_listener, CORBA_Environment *ev)
378 {
379   CORBA_free (key_listener->typeseq);
380   CORBA_free (key_listener->keys);
381   g_free (key_listener);
382 }
383
384 static void
385 spi_key_listener_clone_free (DEControllerKeyListener *clone, CORBA_Environment *ev)
386 {
387   CORBA_Object_release (clone->listener.object, ev);
388   spi_key_listener_data_free (clone, ev);
389 }
390
391 static void
392 spi_dec_key_listener_free (DEControllerKeyListener *key_listener,
393                            CORBA_Environment       *ev)
394 {
395   bonobo_object_release_unref (key_listener->listener.object, ev);
396   spi_key_listener_data_free (key_listener, ev);
397 }
398
399 static void
400 _register_keygrab (SpiDEController      *controller,
401                    DEControllerGrabMask *grab_mask)
402 {
403   GList *l;
404
405   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
406                           spi_grab_mask_compare_values);
407   if (l)
408     {
409       DEControllerGrabMask *cur_mask = l->data;
410
411       cur_mask->ref_count++;
412       if (cur_mask->pending_remove)
413         {
414           cur_mask->pending_remove = FALSE;
415         }
416     }
417   else
418     {
419       controller->keygrabs_list =
420         g_list_prepend (controller->keygrabs_list,
421                         spi_grab_mask_clone (grab_mask));
422     }
423 }
424
425 static void
426 _deregister_keygrab (SpiDEController      *controller,
427                      DEControllerGrabMask *grab_mask)
428 {
429   GList *l;
430
431   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
432                           spi_grab_mask_compare_values);
433
434   if (l)
435     {
436       DEControllerGrabMask *cur_mask = l->data;
437
438       cur_mask->ref_count--;
439       if (cur_mask->ref_count <= 0)
440         {
441           cur_mask->pending_remove = TRUE;
442         }
443     }
444   else
445     {
446       g_warning ("De-registering non-existant grab");
447     }
448 }
449
450 static void
451 handle_keygrab (SpiDEController         *controller,
452                 DEControllerKeyListener *key_listener,
453                 void                   (*process_cb) (SpiDEController *controller,
454                                                       DEControllerGrabMask *grab_mask))
455 {
456   DEControllerGrabMask grab_mask = { 0 };
457
458   grab_mask.mod_mask = key_listener->mask;
459   if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
460     {
461       grab_mask.key_val = AnyKey;
462 #ifdef SPI_DEBUG
463       fprintf (stderr, "AnyKey grab!");
464 #endif
465       process_cb (controller, &grab_mask);
466     }
467   else
468     {
469       int i;
470
471       for (i = 0; i < key_listener->keys->_length; ++i)
472         {
473           Accessibility_KeyDefinition keydef = key_listener->keys->_buffer[i];  
474           long int key_val = keydef.keysym;
475           /* X Grabs require keycodes, not keysyms */
476           if (keydef.keystring && keydef.keystring[0])
477             {
478               key_val = XStringToKeysym(keydef.keystring);                  
479             }
480           if (key_val > 0)
481             {
482               key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
483             }
484           else
485             {
486               key_val = keydef.keycode;
487             }
488           grab_mask.key_val = key_val;
489           process_cb (controller, &grab_mask);
490         }
491     }
492 }
493
494 static gboolean
495 spi_controller_register_global_keygrabs (SpiDEController         *controller,
496                                          DEControllerKeyListener *key_listener)
497 {
498   handle_keygrab (controller, key_listener, _register_keygrab);
499   return spi_controller_update_key_grabs (controller, NULL);
500 }
501
502 static void
503 spi_controller_deregister_global_keygrabs (SpiDEController         *controller,
504                                            DEControllerKeyListener *key_listener)
505 {
506   handle_keygrab (controller, key_listener, _deregister_keygrab);
507   spi_controller_update_key_grabs (controller, NULL);
508 }
509
510 static gboolean
511 spi_controller_register_device_listener (SpiDEController      *controller,
512                                          DEControllerListener *listener,
513                                          CORBA_Environment    *ev)
514 {
515   DEControllerKeyListener *key_listener;
516   
517   switch (listener->type) {
518   case SPI_DEVICE_TYPE_KBD:
519       key_listener = (DEControllerKeyListener *) listener;
520
521       controller->key_listeners = g_list_prepend (controller->key_listeners,
522                                                   key_listener);
523       if (key_listener->mode->global)
524         {
525           return spi_controller_register_global_keygrabs (controller, key_listener);    
526         }
527       else
528               return TRUE;
529       break;
530     default:
531       break;
532   }
533   return FALSE; 
534 }
535
536 static void
537 spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
538                                                  XEvent *xevent)
539 {
540   Accessibility_Event e;
541   CORBA_Environment ev;
542   gchar event_name[24];
543   int button = ((XButtonEvent *) xevent)->button;
544   
545   unsigned int mouse_button_state = ((XButtonEvent *) xevent)->state;
546
547   switch (button)
548     {
549     case 1:
550             mouse_button_state |= Button1Mask;
551             break;
552     case 2:
553             mouse_button_state |= Button2Mask;
554             break;
555     case 3:
556             mouse_button_state |= Button3Mask;
557             break;
558     case 4:
559             mouse_button_state |= Button4Mask;
560             break;
561     case 5:
562             mouse_button_state |= Button5Mask;
563             break;
564     }
565   last_mouse_pos->x = ((XButtonEvent *) xevent)->x_root;
566   last_mouse_pos->y = ((XButtonEvent *) xevent)->y_root;
567
568 #ifdef SPI_DEBUG  
569   fprintf (stderr, "mouse button %d %s (%x)\n",
570            ((XButtonEvent *) xevent)->button, 
571            (xevent->type == ButtonPress) ? "Press" : "Release",
572            mouse_button_state);
573 #endif
574   snprintf (event_name, 22, "mouse:button:%d%c", button,
575             (xevent->type == ButtonPress) ? 'p' : 'r');
576
577   e.type = CORBA_string_dup (event_name);
578   e.source = BONOBO_OBJREF (controller->registry->desktop);
579   e.detail1 = last_mouse_pos->x;
580   e.detail2 = last_mouse_pos->y;
581   CORBA_exception_init (&ev);
582   Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
583                                       &e,
584                                       &ev);
585   
586   XAllowEvents (spi_get_display (), ReplayPointer, CurrentTime);
587 }
588
589 static GdkFilterReturn
590 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
591 {
592   XEvent *xevent = gdk_xevent;
593   SpiDEController *controller;
594
595   if (xevent->type == KeyPress || xevent->type == KeyRelease)
596     {
597       controller = SPI_DEVICE_EVENT_CONTROLLER (data);
598       spi_device_event_controller_forward_key_event (controller, xevent);
599       /* FIXME: is this right ? */
600       return GDK_FILTER_CONTINUE;
601     }
602   if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
603     {
604       controller = SPI_DEVICE_EVENT_CONTROLLER (data);
605       spi_device_event_controller_forward_mouse_event (controller, xevent);
606     }
607   
608   return GDK_FILTER_CONTINUE;
609 }
610
611 int
612 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
613 {
614   if (error->error_code == BadAccess) 
615     {  
616       g_message ("Could not complete key grab: grab already in use.\n");
617       spi_error_code = BadAccess;
618       return 0;
619     }
620   else 
621     {
622       return (*x_default_error_handler) (display, error);
623     }
624 }
625
626 static void
627 spi_controller_register_with_devices (SpiDEController *controller)
628 {
629   /* calls to device-specific implementations and routines go here */
630   /* register with: keyboard hardware code handler */
631   /* register with: (translated) keystroke handler */
632
633   gdk_window_add_filter (NULL, global_filter_fn, controller);
634
635   gdk_window_set_events (gdk_get_default_root_window (),
636                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
637
638   x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
639 }
640
641 static gboolean
642 spi_key_set_contains_key (Accessibility_KeySet            *key_set,
643                           const Accessibility_DeviceEvent *key_event)
644 {
645   gint i;
646   gint len;
647
648   if (!key_set)
649     {
650       g_print ("null key set!");
651       return TRUE;
652     }
653
654   len = key_set->_length;
655   
656   if (len == 0) /* special case, means "all keys/any key" */
657     {
658       g_print ("anykey\n");         
659       return TRUE;
660     }
661
662   for (i = 0; i < len; ++i)
663     {
664 #ifdef SPI_KEYEVENT_DEBUG           
665       g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
666                 i, (int) key_set->_buffer[i].keycode,
667                (int) key_event->id, (int) key_event->hw_code,
668                key_event->event_string); 
669 #endif
670       if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
671         {
672           return TRUE;
673         }
674       if (key_set->_buffer[i].keycode == (CORBA_long) key_event->hw_code)
675         {
676           return TRUE;
677         }
678       if (key_event->event_string && key_event->event_string[0] &&
679           !strcmp (key_set->_buffer[i].keystring, key_event->event_string))
680         {
681           return TRUE;
682         }
683     }
684   
685   return FALSE;
686 }
687
688 static gboolean
689 spi_key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq   *type_seq,
690                                       const Accessibility_DeviceEvent *key_event)
691 {
692   gint i;
693   gint len;
694
695
696   if (!type_seq)
697     {
698       g_print ("null type seq!");
699       return TRUE;
700     }
701
702   len = type_seq->_length;
703   
704   if (len == 0) /* special case, means "all events/any event" */
705     {
706       return TRUE;
707     }
708
709   for (i = 0; i < len; ++i)
710     {
711 #ifdef SPI_DEBUG            
712       g_print ("type_seq[%d] = %d; key event type = %d\n", i,
713                (int) type_seq->_buffer[i], (int) key_event->type);
714 #endif      
715       if (type_seq->_buffer[i] == (CORBA_long) key_event->type)
716         {
717           return TRUE;
718         }
719     }
720   
721   return FALSE;
722 }
723
724 static gboolean
725 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
726                                 DEControllerKeyListener         *listener,
727                                 CORBA_boolean                    is_system_global)
728 {
729   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
730        spi_key_set_contains_key (listener->keys, key_event) &&
731        spi_key_eventtype_seq_contains_event (listener->typeseq, key_event) && 
732       (is_system_global == listener->mode->global))
733     {
734       return TRUE;
735     }
736   else
737     {
738       return FALSE;
739     }
740 }
741
742 static gboolean
743 spi_controller_notify_keylisteners (SpiDEController                 *controller,
744                                     const Accessibility_DeviceEvent *key_event,
745                                     CORBA_boolean                    is_system_global,
746                                     CORBA_Environment               *ev)
747 {
748   GList   *l;
749   GSList  *notify = NULL, *l2;
750   GList  **key_listeners = &controller->key_listeners;
751   gboolean is_consumed;
752
753   if (!key_listeners)
754     {
755       return FALSE;
756     }
757
758   for (l = *key_listeners; l; l = l->next)
759     {
760        DEControllerKeyListener *key_listener = l->data;
761
762        if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
763          {
764            Accessibility_DeviceEventListener ls = key_listener->listener.object;
765
766            if (ls != CORBA_OBJECT_NIL)
767              {
768                /* we clone (don't dup) the listener, to avoid refcount inc. */
769                notify = g_slist_prepend (notify,
770                                          spi_key_listener_clone (key_listener, ev));
771              }
772          }
773     }
774
775 #ifdef SPI_KEYEVENT_DEBUG
776   if (!notify)
777     {
778       g_print ("no match for event\n");
779     }
780 #endif
781
782   is_consumed = FALSE;
783   for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
784     {
785       DEControllerKeyListener *key_listener = l2->data;     
786       Accessibility_DeviceEventListener ls = key_listener->listener.object;
787
788       is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
789
790       if (BONOBO_EX (ev))
791         {
792           is_consumed = FALSE;
793           spi_deregister_controller_key_listener (controller, key_listener,
794                                                   ev);
795           CORBA_exception_free (ev);
796         }
797
798       CORBA_Object_release (ls, ev);
799     }
800
801   for (; l2; l2 = l2->next)
802     {
803       DEControllerKeyListener *key_listener = l2->data;     
804       spi_key_listener_clone_free (key_listener, ev);
805       /* clone doesn't have its own ref, so don't use spi_key_listener_free */
806     }
807
808   g_slist_free (notify);
809
810 #ifdef SPI_DEBUG
811   if (is_consumed) g_message ("consumed\n");
812 #endif
813   return is_consumed;
814 }
815
816 static gboolean
817 spi_clear_error_state ()
818 {
819         gboolean retval = spi_error_code != 0;
820         spi_error_code = 0;
821         return retval;
822 }
823
824 static Accessibility_DeviceEvent
825 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
826 {
827   Accessibility_DeviceEvent key_event;
828   KeySym keysym;
829   const int cbuf_bytes = 20;
830   char cbuf [cbuf_bytes];
831   
832   keysym = XLookupKeysym (x_key_event, 0);
833   key_event.id = (CORBA_long)(keysym);
834   key_event.hw_code = (CORBA_short) x_key_event->keycode;
835   if (((XEvent *) x_key_event)->type == KeyPress)
836     {
837       key_event.type = Accessibility_KEY_PRESSED;
838     }
839   else
840     {
841       key_event.type = Accessibility_KEY_RELEASED;
842     } 
843   key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
844   key_event.is_text = CORBA_FALSE;
845   switch (keysym)
846     {
847       case ' ':
848         key_event.event_string = CORBA_string_dup ("space");
849         break;
850       case XK_Tab:
851 #ifdef SPI_KEYEVENT_DEBUG
852         fprintf(stderr, "Tab\n");
853 #endif
854         key_event.event_string = CORBA_string_dup ("Tab");
855         break;
856       case XK_BackSpace:
857         key_event.event_string = CORBA_string_dup ("Backspace");
858         break;
859       case XK_Return:
860         key_event.event_string = CORBA_string_dup ("Return");
861         break;
862       case XK_Home:
863         key_event.event_string = CORBA_string_dup ("Home");
864         break;
865       case XK_Page_Down:
866         key_event.event_string = CORBA_string_dup ("Page_Down");
867         break;
868       case XK_Page_Up:
869         key_event.event_string = CORBA_string_dup ("Page_Up");
870         break;
871       case XK_F1:
872         key_event.event_string = CORBA_string_dup ("F1");
873         break;
874       case XK_F2:
875         key_event.event_string = CORBA_string_dup ("F2");
876         break;
877       case XK_F3:
878         key_event.event_string = CORBA_string_dup ("F3");
879         break;
880       case XK_F4:
881         key_event.event_string = CORBA_string_dup ("F4");
882         break;
883       case XK_F5:
884         key_event.event_string = CORBA_string_dup ("F5");
885         break;
886       case XK_F6:
887         key_event.event_string = CORBA_string_dup ("F6");
888         break;
889       case XK_F7:
890         key_event.event_string = CORBA_string_dup ("F7");
891         break;
892       case XK_F8:
893         key_event.event_string = CORBA_string_dup ("F8");
894         break;
895       case XK_F9:
896         key_event.event_string = CORBA_string_dup ("F9");
897         break;
898       case XK_F10:
899         key_event.event_string = CORBA_string_dup ("F10");
900         break;
901       case XK_F11:
902         key_event.event_string = CORBA_string_dup ("F11");
903         break;
904       case XK_F12:
905         key_event.event_string = CORBA_string_dup ("F12");
906         break;
907       case XK_End:
908         key_event.event_string = CORBA_string_dup ("End");
909         break;
910       case XK_Escape:
911         key_event.event_string = CORBA_string_dup ("Escape");
912         break;
913       case XK_Up:
914         key_event.event_string = CORBA_string_dup ("Up");
915         break;
916       case XK_Down:
917         key_event.event_string = CORBA_string_dup ("Down");
918         break;
919       case XK_Left:
920         key_event.event_string = CORBA_string_dup ("Left");
921         break;
922       case XK_Right:
923         key_event.event_string = CORBA_string_dup ("Right");
924         break;
925       default:
926         if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
927           {
928             key_event.event_string = CORBA_string_dup (cbuf);
929             if (isgraph (keysym))
930               {
931                 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
932               }
933           }
934         else
935           {
936             key_event.event_string = CORBA_string_dup ("");
937           }
938     }
939
940   key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
941 #ifdef SPI_KEYEVENT_DEBUG
942   fprintf (stderr,
943      "Key %lu pressed (%c), modifiers %d\n",
944      (unsigned long) keysym,
945      keysym ? (int) keysym : '*',
946      (int) x_key_event->state);
947 #endif
948 #ifdef SPI_DEBUG
949   fprintf (stderr, "%s%c",
950      (x_key_event->state & Mod1Mask)?"Alt-":"",
951      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
952      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
953 #endif /* SPI_DEBUG */
954   return key_event;     
955 }
956
957 static gboolean
958 spi_controller_update_key_grabs (SpiDEController           *controller,
959                                  Accessibility_DeviceEvent *recv)
960 {
961   GList *l, *next;
962   gboolean   update_failed = FALSE;
963   
964   g_return_val_if_fail (controller != NULL, FALSE);
965
966   /*
967    * masks known to work with default RH 7.1+:
968    * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
969    * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
970    * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
971    * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
972    *
973    * ControlMask grabs are broken, must be in use already
974    */
975   for (l = controller->keygrabs_list; l; l = next)
976     {
977       gboolean do_remove;
978       gboolean re_issue_grab;
979       DEControllerGrabMask *grab_mask = l->data;
980
981       next = l->next;
982
983       re_issue_grab = recv &&
984 /*            (recv->type == Accessibility_KEY_RELEASED) && - (?) */
985               (recv->modifiers & grab_mask->mod_mask) &&
986               (grab_mask->key_val == keycode_for_keysym (recv->id));
987
988 #ifdef SPI_DEBUG
989       fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
990                (long int) grab_mask->key_val,
991                (long int) grab_mask->mod_mask,
992                grab_mask->pending_add ? '+' : '.',
993                grab_mask->pending_remove ? '-' : '.',
994                re_issue_grab ? "re-issue": "");
995 #endif
996
997       do_remove = FALSE;
998
999       if (grab_mask->pending_add && grab_mask->pending_remove)
1000         {
1001           do_remove = TRUE;
1002         }
1003       else if (grab_mask->pending_remove)
1004         {
1005 #ifdef SPI_DEBUG
1006       fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
1007 #endif
1008           XUngrabKey (spi_get_display (),
1009                       grab_mask->key_val,
1010                       grab_mask->mod_mask,
1011                       gdk_x11_get_default_root_xwindow ());
1012
1013           do_remove = TRUE;
1014         }
1015       else if (grab_mask->pending_add || re_issue_grab)
1016         {
1017
1018 #ifdef SPI_DEBUG
1019           fprintf (stderr, "grab %d with mask %x\n", grab_mask->key_val, grab_mask->mod_mask);
1020 #endif
1021           XGrabKey (spi_get_display (),
1022                     grab_mask->key_val,
1023                     grab_mask->mod_mask,
1024                     gdk_x11_get_default_root_xwindow (),
1025                     True,
1026                     GrabModeSync,
1027                     GrabModeSync);
1028           XSync (spi_get_display (), False);
1029           update_failed = spi_clear_error_state ();
1030           if (update_failed) {
1031                   while (grab_mask->ref_count > 0) --grab_mask->ref_count;
1032                   do_remove = TRUE;
1033           }
1034         }
1035
1036       grab_mask->pending_add = FALSE;
1037       grab_mask->pending_remove = FALSE;
1038
1039       if (do_remove)
1040         {
1041           g_assert (grab_mask->ref_count <= 0);
1042
1043           controller->keygrabs_list = g_list_delete_link (
1044             controller->keygrabs_list, l);
1045
1046           spi_grab_mask_free (grab_mask);
1047         }
1048
1049     } 
1050
1051   return ! update_failed;
1052 }
1053
1054 /*
1055  * Implemented GObject::finalize
1056  */
1057 static void
1058 spi_device_event_controller_object_finalize (GObject *object)
1059 {
1060   SpiDEController *controller;
1061
1062   controller = SPI_DEVICE_EVENT_CONTROLLER (object);
1063
1064 #ifdef SPI_DEBUG
1065   fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
1066 #endif
1067   /* disconnect any special listeners, get rid of outstanding keygrabs */
1068   XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
1069
1070   g_free (g_object_get_data (G_OBJECT (controller), "spi-dec-private"));
1071   spi_device_event_controller_parent_class->finalize (object);
1072 }
1073
1074 /*
1075  * CORBA Accessibility::DEController::registerKeystrokeListener
1076  *     method implementation
1077  */
1078 static CORBA_boolean
1079 impl_register_keystroke_listener (PortableServer_Servant                  servant,
1080                                   const Accessibility_DeviceEventListener l,
1081                                   const Accessibility_KeySet             *keys,
1082                                   const Accessibility_ControllerEventMask mask,
1083                                   const Accessibility_KeyEventTypeSeq    *type,
1084                                   const Accessibility_EventListenerMode  *mode,
1085                                   CORBA_Environment                      *ev)
1086 {
1087   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1088           bonobo_object_from_servant (servant));
1089   DEControllerKeyListener *dec_listener;
1090 #ifdef SPI_DEBUG
1091   fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
1092            (void *) l, (unsigned long) mask);
1093 #endif
1094   dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
1095   return spi_controller_register_device_listener (
1096           controller, (DEControllerListener *) dec_listener, ev);
1097 }
1098
1099
1100 typedef struct {
1101         CORBA_Environment       *ev;
1102         DEControllerKeyListener *key_listener;
1103 } RemoveKeyListenerClosure;
1104
1105 static SpiReEntrantContinue
1106 remove_key_listener_cb (GList * const *list,
1107                         gpointer       user_data)
1108 {
1109   DEControllerKeyListener  *key_listener = (*list)->data;
1110   RemoveKeyListenerClosure *ctx = user_data;
1111
1112   if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
1113                                   key_listener->listener.object, ctx->ev))
1114     {
1115       spi_re_entrant_list_delete_link (list);
1116       spi_dec_key_listener_free (key_listener, ctx->ev);
1117     }
1118
1119   return SPI_RE_ENTRANT_CONTINUE;
1120 }
1121
1122 static SpiReEntrantContinue
1123 copy_key_listener_cb (GList * const *list,
1124                       gpointer       user_data)
1125 {
1126   DEControllerKeyListener  *key_listener = (*list)->data;
1127   RemoveKeyListenerClosure *ctx = user_data;
1128
1129   if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
1130                                   key_listener->listener.object, ctx->ev))
1131     {
1132       /* TODO: FIXME aggregate keys in case the listener is registered twice */
1133       CORBA_free (ctx->key_listener->keys);         
1134       ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
1135     }
1136
1137   return SPI_RE_ENTRANT_CONTINUE;
1138 }
1139
1140
1141 static void
1142 spi_deregister_controller_key_listener (SpiDEController            *controller,
1143                                         DEControllerKeyListener    *key_listener,
1144                                         CORBA_Environment          *ev)
1145 {
1146   RemoveKeyListenerClosure  ctx;
1147
1148   ctx.ev = ev;
1149   ctx.key_listener = key_listener;
1150
1151   /* special case, copy keyset from existing controller list entry */
1152   if (key_listener->keys->_length == 0) 
1153     {
1154       spi_re_entrant_list_foreach (&controller->key_listeners,
1155                                   copy_key_listener_cb, &ctx);
1156     }
1157   
1158   spi_controller_deregister_global_keygrabs (controller, key_listener);
1159
1160   spi_re_entrant_list_foreach (&controller->key_listeners,
1161                                 remove_key_listener_cb, &ctx);
1162
1163 }
1164
1165 /*
1166  * CORBA Accessibility::DEController::deregisterKeystrokeListener
1167  *     method implementation
1168  */
1169 static void
1170 impl_deregister_keystroke_listener (PortableServer_Servant                  servant,
1171                                     const Accessibility_DeviceEventListener l,
1172                                     const Accessibility_KeySet             *keys,
1173                                     const Accessibility_ControllerEventMask mask,
1174                                     const Accessibility_KeyEventTypeSeq    *type,
1175                                     CORBA_Environment                      *ev)
1176 {
1177   DEControllerKeyListener  *key_listener;
1178   SpiDEController *controller;
1179
1180   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1181
1182   key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
1183
1184 #ifdef SPI_DEREGISTER_DEBUG
1185   fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
1186            (void *) l, (unsigned long) mask->value);
1187 #endif
1188
1189   spi_deregister_controller_key_listener (controller, key_listener, ev);
1190
1191   spi_dec_key_listener_free (key_listener, ev);
1192 }
1193
1194 static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
1195 {
1196         unsigned int retval = 0;
1197 #ifdef HAVE_XKB
1198 #ifdef XKB_HAS_GET_SLOW_KEYS_DELAY      
1199         retval = XkbGetSlowKeysDelay (spi_get_display (),
1200                                       XkbUseCoreKbd, &bounce_delay);
1201 #else
1202         XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1203         if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
1204         {
1205                 Status s = XkbGetControls (spi_get_display (),
1206                                            XkbAllControlsMask, xkb);
1207                 if (s == Success)
1208                 {
1209                         if (xkb->ctrls->enabled_ctrls & XkbSlowKeysMask)
1210                                 retval = xkb->ctrls->slow_keys_delay;
1211                 }
1212                 XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
1213         }
1214 #endif
1215 #endif
1216 #ifdef SPI_XKB_DEBUG
1217         fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
1218 #endif
1219         return retval;
1220 }
1221
1222 static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
1223 {
1224         unsigned int retval = 0;
1225 #ifdef HAVE_XKB
1226 #ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY    
1227         retval = XkbGetBounceKeysDelay (spi_get_display (),
1228                                         XkbUseCoreKbd, &bounce_delay);
1229 #else
1230         XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
1231         if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
1232         {
1233                 Status s = XkbGetControls (spi_get_display (),
1234                                            XkbAllControlsMask, xkb);
1235                 if (s == Success)
1236                 {
1237                         if (xkb->ctrls->enabled_ctrls & XkbBounceKeysMask)
1238                                 retval = xkb->ctrls->debounce_delay;
1239                 }
1240                 XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
1241         }
1242 #endif
1243 #endif
1244 #ifdef SPI_XKB_DEBUG
1245         fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
1246 #endif
1247         return retval;
1248 }
1249
1250 static gboolean
1251 dec_synth_keycode_press (SpiDEController *controller,
1252                          unsigned int keycode)
1253 {
1254         unsigned int time = CurrentTime;
1255         unsigned int bounce_delay;
1256         unsigned int elapsed_msec;
1257         struct timeval tv;
1258         DEControllerPrivateData *priv =
1259                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1260                                                                 spi_dec_private_quark);
1261         if (keycode == priv->last_release_keycode)
1262         {
1263                 bounce_delay = dec_xkb_get_bouncekeys_delay (controller); 
1264                 if (bounce_delay)
1265                 {
1266                         gettimeofday (&tv, NULL);
1267                         elapsed_msec =
1268                                 (tv.tv_sec - priv->last_release_time.tv_sec) * 1000
1269                                 + (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
1270 #ifdef SPI_XKB_DEBUG                    
1271                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1272                                  (long) (tv.tv_usec - priv->last_release_time.tv_usec));
1273 #endif
1274 #ifdef THIS_IS_BROKEN
1275                         if (elapsed_msec < bounce_delay)
1276                                 time = bounce_delay - elapsed_msec + 1;
1277 #else
1278                         time = bounce_delay + 10;
1279                         /* fudge for broken XTest */
1280 #endif
1281 #ifdef SPI_XKB_DEBUG                    
1282                         fprintf (stderr, "waiting %d ms\n", time);
1283 #endif
1284                 }
1285         }
1286         fprintf (stderr, "press %d\n", (int) keycode);
1287         XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
1288         priv->last_press_keycode = keycode;
1289         XSync (spi_get_display (), False);
1290         gettimeofday (&priv->last_press_time, NULL);
1291         return TRUE;
1292 }
1293
1294 static gboolean
1295 dec_synth_keycode_release (SpiDEController *controller,
1296                            unsigned int keycode)
1297 {
1298         unsigned int time = CurrentTime;
1299         unsigned int slow_delay;
1300         unsigned int elapsed_msec;
1301         struct timeval tv;
1302         DEControllerPrivateData *priv =
1303                 (DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
1304                                                                 spi_dec_private_quark);
1305         if (keycode == priv->last_press_keycode)
1306         {
1307                 slow_delay = dec_xkb_get_slowkeys_delay (controller);
1308                 if (slow_delay)
1309                 {
1310                         gettimeofday (&tv, NULL);
1311                         elapsed_msec =
1312                                 (tv.tv_sec - priv->last_press_time.tv_sec) * 1000
1313                                 + (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
1314 #ifdef SPI_XKB_DEBUG                    
1315                         fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
1316                                  (long) (tv.tv_usec - priv->last_press_time.tv_usec));
1317 #endif
1318 #ifdef THIS_IS_BROKEN_DUNNO_WHY
1319                         if (elapsed_msec < slow_delay)
1320                                 time = slow_delay - elapsed_msec + 1;
1321 #else
1322                         time = slow_delay + 10;
1323                         /* our XTest seems broken, we have to add slop as above */
1324 #endif
1325 #ifdef SPI_XKB_DEBUG                    
1326                         fprintf (stderr, "waiting %d ms\n", time);
1327 #endif
1328                 }
1329         }
1330         fprintf (stderr, "release %d\n", (int) keycode);
1331         XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
1332         priv->last_release_keycode = keycode;
1333         XSync (spi_get_display (), False);
1334         gettimeofday (&priv->last_release_time, NULL);
1335         return TRUE;
1336 }
1337
1338 /*
1339  * CORBA Accessibility::DEController::registerKeystrokeListener
1340  *     method implementation
1341  */
1342 static void
1343 impl_generate_keyboard_event (PortableServer_Servant           servant,
1344                               const CORBA_long                 keycode,
1345                               const CORBA_char                *keystring,
1346                               const Accessibility_KeySynthType synth_type,
1347                               CORBA_Environment               *ev)
1348 {
1349   SpiDEController *controller =
1350         SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
1351   long key_synth_code;
1352   unsigned int slow_keys_delay;
1353   unsigned int press_time;
1354   unsigned int release_time;
1355
1356 #ifdef SPI_DEBUG
1357         fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
1358                  (long) keycode, (int) synth_type);
1359 #endif
1360   /* TODO: hide/wrap/remove X dependency */
1361
1362   /*
1363    * TODO: when initializing, query for XTest extension before using,
1364    * and fall back to XSendEvent() if XTest is not available.
1365    */
1366   
1367   /* TODO: implement keystring mode also */
1368   gdk_error_trap_push ();
1369   
1370   switch (synth_type)
1371     {
1372       case Accessibility_KEY_PRESS:
1373               dec_synth_keycode_press (controller, keycode);
1374               break;
1375       case Accessibility_KEY_PRESSRELEASE:
1376               dec_synth_keycode_press (controller, keycode);
1377       case Accessibility_KEY_RELEASE:
1378               dec_synth_keycode_release (controller, keycode);
1379               break;
1380       case Accessibility_KEY_SYM:
1381 #ifdef SPI_XKB_DEBUG          
1382               fprintf (stderr, "KeySym synthesis\n");
1383 #endif
1384               key_synth_code = keycode_for_keysym (keycode);
1385               dec_synth_keycode_press (controller, key_synth_code);
1386               dec_synth_keycode_release (controller, key_synth_code);
1387               break;
1388       case Accessibility_KEY_STRING:
1389               fprintf (stderr, "Not yet implemented\n");
1390               break;
1391     }
1392   if (gdk_error_trap_pop ())
1393     {
1394       g_warning ("Error emitting keystroke");
1395     }
1396 }
1397
1398 /* Accessibility::DEController::generateMouseEvent */
1399 static void
1400 impl_generate_mouse_event (PortableServer_Servant servant,
1401                            const CORBA_long       x,
1402                            const CORBA_long       y,
1403                            const CORBA_char      *eventName,
1404                            CORBA_Environment     *ev)
1405 {
1406   int button;
1407   gboolean error = FALSE;
1408   Display *display = spi_get_display ();
1409 #ifdef SPI_DEBUG
1410   fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
1411            eventName, (long int) x, (long int) y);
1412 #endif
1413   g_message ("mouse event synthesis\n");
1414   switch (eventName[0])
1415     {
1416       case 'b':
1417         switch (eventName[1])
1418           {
1419           /* TODO: check number of buttons before parsing */
1420           case '1':
1421                     button = 1;
1422                     break;
1423           case '2':
1424                   button = 2;
1425                   break;
1426           case '3':
1427                   button = 3;
1428                   break;
1429           default:
1430                   error = TRUE;
1431           }
1432         if (!error)
1433           {
1434             if (x != -1 && y != -1)
1435               {
1436                 XTestFakeMotionEvent (display, DefaultScreen (display),
1437                                       x, y, 0);
1438               }
1439             XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
1440             if (eventName[2] == 'c')
1441               XTestFakeButtonEvent (display, button, FALSE, 1);
1442             else if (eventName[2] == 'd')
1443               {
1444               XTestFakeButtonEvent (display, button, FALSE, 1);
1445               XTestFakeButtonEvent (display, button, TRUE, 2);
1446               XTestFakeButtonEvent (display, button, FALSE, 3);
1447               }
1448           }
1449         break;
1450       case 'r': /* relative motion */ 
1451         XTestFakeRelativeMotionEvent (display, x, y, 0);
1452         break;
1453       case 'a': /* absolute motion */
1454         XTestFakeMotionEvent (display, DefaultScreen (display),
1455                               x, y, 0);
1456         break;
1457     }
1458 }
1459
1460 /* Accessibility::DEController::notifyListenersSync */
1461 static CORBA_boolean
1462 impl_notify_listeners_sync (PortableServer_Servant           servant,
1463                             const Accessibility_DeviceEvent *event,
1464                             CORBA_Environment               *ev)
1465 {
1466   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1467     bonobo_object_from_servant (servant));
1468 #ifdef SPI_DEBUG
1469   g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
1470            controller, (int) event->id);
1471 #endif
1472   return spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev) ?
1473           CORBA_TRUE : CORBA_FALSE; 
1474 }
1475
1476 /* Accessibility::DEController::notifyListenersAsync */
1477 static void
1478 impl_notify_listeners_async (PortableServer_Servant           servant,
1479                              const Accessibility_DeviceEvent *event,
1480                              CORBA_Environment               *ev)
1481 {
1482   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
1483     bonobo_object_from_servant (servant));
1484 #ifdef SPI_DEBUG
1485   fprintf (stderr, "notifying listeners asynchronously\n");
1486 #endif
1487   spi_controller_notify_keylisteners (controller, event, CORBA_FALSE, ev); 
1488 }
1489
1490 static void
1491 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
1492 {
1493   GObjectClass * object_class = (GObjectClass *) klass;
1494   POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
1495
1496   spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
1497   
1498   object_class->finalize = spi_device_event_controller_object_finalize;
1499         
1500   epv->registerKeystrokeListener   = impl_register_keystroke_listener;
1501   epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
1502   epv->generateKeyboardEvent       = impl_generate_keyboard_event;
1503   epv->generateMouseEvent          = impl_generate_mouse_event;
1504   epv->notifyListenersSync         = impl_notify_listeners_sync;
1505   epv->notifyListenersAsync        = impl_notify_listeners_async;
1506 }
1507
1508 static void
1509 spi_device_event_controller_init (SpiDEController *device_event_controller)
1510 {
1511   device_event_controller->key_listeners   = NULL;
1512   device_event_controller->mouse_listeners = NULL;
1513   device_event_controller->keygrabs_list   = NULL;
1514
1515   /*
1516    * TODO: fixme, this module makes the foolish assumptions that
1517    * registryd uses the same display as the apps, and that the
1518    * DISPLAY environment variable is set.
1519    */
1520   gdk_init (NULL, NULL);
1521   
1522   spi_controller_register_with_devices (device_event_controller);
1523 }
1524
1525 static void
1526 spi_device_event_controller_forward_key_event (SpiDEController *controller,
1527                                                const XEvent    *event)
1528 {
1529   gboolean is_consumed = FALSE;
1530   CORBA_Environment ev;
1531   Accessibility_DeviceEvent key_event;
1532
1533   g_assert (event->type == KeyPress || event->type == KeyRelease);
1534
1535   CORBA_exception_init (&ev);
1536
1537   key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
1538
1539   spi_controller_update_key_grabs (controller, &key_event);
1540
1541   /* relay to listeners, and decide whether to consume it or not */
1542   is_consumed = spi_controller_notify_keylisteners (
1543           controller, &key_event, CORBA_TRUE, &ev);
1544
1545   CORBA_exception_free (&ev);
1546
1547   if (is_consumed)
1548     {
1549       XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
1550     }
1551   else
1552     {
1553       XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
1554     }
1555 }
1556
1557 SpiDEController *
1558 spi_device_event_controller_new (SpiRegistry *registry)
1559 {
1560   SpiDEController *retval = g_object_new (
1561     SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
1562   DEControllerPrivateData *private;
1563   
1564   retval->registry = SPI_REGISTRY (bonobo_object_ref (
1565           BONOBO_OBJECT (registry)));
1566
1567   private = g_new0 (DEControllerPrivateData, 1);
1568   gettimeofday (&private->last_press_time, NULL);
1569   gettimeofday (&private->last_release_time, NULL);
1570   if (!spi_dec_private_quark)
1571           spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
1572   g_object_set_qdata (G_OBJECT (retval),
1573                       spi_dec_private_quark,
1574                       private);
1575   spi_dec_init_mouse_listener (registry);
1576   /* TODO: kill mouse listener on finalize */  
1577   return retval;
1578 }
1579
1580 BONOBO_TYPE_FUNC_FULL (SpiDEController,
1581                        Accessibility_DeviceEventController,
1582                        PARENT_TYPE,
1583                        spi_device_event_controller);