Bugfix for keygrab regression (registryd was holding keygrabs after they should have...
[platform/core/uifw/at-spi2-atk.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 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /* deviceeventcontroler.c: implement the DeviceEventController interface */
24
25 #include <config.h>
26
27 #undef SPI_DEBUG
28
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <bonobo/bonobo-exception.h>
33
34 #include <X11/Xlib.h>
35 #include <X11/extensions/XTest.h>
36 #define XK_MISCELLANY
37 #include <X11/keysymdef.h>
38 #include <gdk/gdk.h>
39 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
40 #include <gdk/gdkkeysyms.h>
41 #include <gdk/gdkwindow.h>
42
43 #include "../libspi/spi-private.h"
44 #include "deviceeventcontroller.h"
45
46 /* Our parent Gtk object type */
47 #define PARENT_TYPE BONOBO_TYPE_OBJECT
48
49 /* A pointer to our parent object class */
50 static GObjectClass *spi_device_event_controller_parent_class;
51
52 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
53
54 typedef enum {
55   SPI_DEVICE_TYPE_KBD,
56   SPI_DEVICE_TYPE_MOUSE,
57   SPI_DEVICE_TYPE_LAST_DEFINED
58 } SpiDeviceTypeCategory;
59
60 typedef struct {
61   guint                             ref_count : 30;
62   guint                             pending_add : 1;
63   guint                             pending_remove : 1;
64
65   Accessibility_ControllerEventMask mod_mask;
66   CORBA_unsigned_long               key_val;  /* KeyCode */
67 } DEControllerGrabMask;
68
69 typedef struct {
70   CORBA_Object          object;
71   SpiDeviceTypeCategory type;
72 } DEControllerListener;
73
74 typedef struct {
75   DEControllerListener listener;
76
77   Accessibility_KeySet             *keys;
78   Accessibility_ControllerEventMask mask;
79   Accessibility_KeyEventTypeSeq    *typeseq;
80   Accessibility_EventListenerMode  *mode;       
81 } DEControllerKeyListener;
82
83 static void     spi_controller_register_with_devices          (SpiDEController           *controller);
84 static gboolean spi_controller_update_key_grabs               (SpiDEController           *controller,
85                                                                Accessibility_DeviceEvent *recv);
86 static void     spi_controller_register_device_listener       (SpiDEController           *controller,
87                                                                DEControllerListener      *l,
88                                                                CORBA_Environment         *ev);
89 static void     spi_device_event_controller_forward_key_event (SpiDEController           *controller,
90                                                                const XEvent              *event);
91
92 /* Private methods */
93
94 static KeyCode
95 keycode_for_keysym (long keysym)
96 {
97   return XKeysymToKeycode (GDK_DISPLAY (), (KeySym) keysym);
98 }
99
100 static DEControllerGrabMask *
101 spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
102 {
103   DEControllerGrabMask *clone = g_new (DEControllerGrabMask, 1);
104
105   memcpy (clone, grab_mask, sizeof (DEControllerGrabMask));
106
107   clone->ref_count = 1;
108   clone->pending_add = TRUE;
109   clone->pending_remove = FALSE;
110
111   return clone;
112 }
113
114 static void
115 spi_grab_mask_free (DEControllerGrabMask *grab_mask)
116 {
117   g_free (grab_mask);
118 }
119
120 static gint
121 spi_grab_mask_compare_values (gconstpointer p1, gconstpointer p2)
122 {
123   DEControllerGrabMask *l1 = (DEControllerGrabMask *) p1;
124   DEControllerGrabMask *l2 = (DEControllerGrabMask *) p2;
125
126   if (p1 == p2)
127     {
128       return 0;
129     }
130   else
131     { 
132       return ((l1->mod_mask != l2->mod_mask) || (l1->key_val != l2->key_val));
133     }
134 }
135
136 static DEControllerKeyListener *
137 spi_dec_key_listener_new (CORBA_Object                            l,
138                           const Accessibility_KeySet             *keys,
139                           const Accessibility_ControllerEventMask mask,
140                           const Accessibility_KeyEventTypeSeq    *typeseq,
141                           const Accessibility_EventListenerMode  *mode,
142                           CORBA_Environment                      *ev)
143 {
144   DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
145   key_listener->listener.object = bonobo_object_dup_ref (l, ev);
146   key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
147   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
148   key_listener->mask = mask;
149   key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
150   if (mode)
151     key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
152   else
153     key_listener->mode = NULL;
154
155 #ifdef SPI_DEBUG
156   g_print ("new listener, with mask %x, is_global %d, keys %p (%d)\n",
157            (unsigned int) key_listener->mask,
158            (int) (mode ? mode->global : 0),
159            (void *) key_listener->keys,
160            (int) (key_listener->keys ? key_listener->keys->_length : 0));
161 #endif
162
163   return key_listener;  
164 }
165
166 static void
167 spi_dec_key_listener_free (DEControllerKeyListener *key_listener,
168                            CORBA_Environment       *ev)
169 {
170   bonobo_object_release_unref (key_listener->listener.object, ev);
171   CORBA_free (key_listener->typeseq);
172   CORBA_free (key_listener->keys);
173   g_free (key_listener);
174 }
175
176 static void
177 _register_keygrab (SpiDEController      *controller,
178                    DEControllerGrabMask *grab_mask)
179 {
180   GList *l;
181
182   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
183                           spi_grab_mask_compare_values);
184   if (l)
185     {
186       DEControllerGrabMask *cur_mask = l->data;
187
188       cur_mask->ref_count++;
189       if (cur_mask->pending_remove)
190         {
191           cur_mask->pending_remove = FALSE;
192         }
193     }
194   else
195     {
196       controller->keygrabs_list =
197         g_list_prepend (controller->keygrabs_list,
198                         spi_grab_mask_clone (grab_mask));
199     }
200 }
201
202 static void
203 _deregister_keygrab (SpiDEController      *controller,
204                      DEControllerGrabMask *grab_mask)
205 {
206   GList *l;
207
208   l = g_list_find_custom (controller->keygrabs_list, grab_mask,
209                           spi_grab_mask_compare_values);
210
211   if (l)
212     {
213       DEControllerGrabMask *cur_mask = l->data;
214
215       cur_mask->ref_count--;
216       cur_mask->pending_remove = TRUE;
217     }
218   else
219     {
220       g_warning ("De-registering non-existant grab");
221     }
222 }
223
224 static void
225 handle_keygrab (SpiDEController         *controller,
226                 DEControllerKeyListener *key_listener,
227                 void                   (*process_cb) (SpiDEController *controller,
228                                                       DEControllerGrabMask *grab_mask))
229 {
230   DEControllerGrabMask grab_mask = { 0 };
231
232   grab_mask.mod_mask = key_listener->mask;
233   if (key_listener->keys->_length == 0) /* special case means AnyKey/AllKeys */
234     {
235       grab_mask.key_val = AnyKey;
236       process_cb (controller, &grab_mask);
237     }
238   else
239     {
240       int i;
241
242       for (i = 0; i < key_listener->keys->_length; ++i)
243         {
244           long int key_val = key_listener->keys->_buffer[i];
245           /* X Grabs require keycodes, not keysyms */
246           if (key_val >= 0)
247             {
248               key_val = XKeysymToKeycode (GDK_DISPLAY (), (KeySym) key_val);
249             }
250           grab_mask.key_val = key_val;
251
252           process_cb (controller, &grab_mask);
253         }
254     }
255 }
256
257 static void
258 spi_controller_register_global_keygrabs (SpiDEController         *controller,
259                                          DEControllerKeyListener *key_listener)
260 {
261   handle_keygrab (controller, key_listener, _register_keygrab);
262   spi_controller_update_key_grabs (controller, NULL);
263 }
264
265 static void
266 spi_controller_deregister_global_keygrabs (SpiDEController         *controller,
267                                            DEControllerKeyListener *key_listener)
268 {
269   handle_keygrab (controller, key_listener, _deregister_keygrab);
270   spi_controller_update_key_grabs (controller, NULL);
271 }
272
273 static void
274 spi_controller_register_device_listener (SpiDEController      *controller,
275                                          DEControllerListener *listener,
276                                          CORBA_Environment    *ev)
277 {
278   DEControllerKeyListener *key_listener;
279   
280   switch (listener->type) {
281   case SPI_DEVICE_TYPE_KBD:
282       key_listener = (DEControllerKeyListener *) listener;
283
284       controller->key_listeners = g_list_prepend (controller->key_listeners,
285                                                   key_listener);
286       if (key_listener->mode->global)
287         {
288           spi_controller_register_global_keygrabs (controller, key_listener);   
289         }
290       break;
291     default:
292       break;
293   }
294 }
295
296 static GdkFilterReturn
297 global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
298 {
299   XEvent *xevent = gdk_xevent;
300   SpiDEController *controller;
301
302   if (xevent->type != KeyPress && xevent->type != KeyRelease)
303     {
304       return GDK_FILTER_CONTINUE;
305     }
306
307   controller = SPI_DEVICE_EVENT_CONTROLLER (data);
308
309   spi_device_event_controller_forward_key_event (controller, xevent);
310
311   /* FIXME: is this right ? */
312   return GDK_FILTER_CONTINUE;
313 }
314
315 int
316 _spi_controller_device_error_handler (Display *display, XErrorEvent *error)
317 {
318   if (error->error_code == BadAccess) 
319     {  
320       g_message ("Could not complete key grab: grab already in use.\n");
321     }
322   else 
323     {
324       (*x_default_error_handler) (display, error);
325     }
326 }
327
328 static void
329 spi_controller_register_with_devices (SpiDEController *controller)
330 {
331   /* calls to device-specific implementations and routines go here */
332   /* register with: keyboard hardware code handler */
333   /* register with: (translated) keystroke handler */
334
335   gdk_window_add_filter (NULL, global_filter_fn, controller);
336
337   gdk_window_set_events (gdk_get_default_root_window (),
338                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
339
340   x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
341
342   XSelectInput (GDK_DISPLAY (),
343                 DefaultRootWindow (GDK_DISPLAY ()),
344                 KeyPressMask | KeyReleaseMask);
345 }
346
347 static gboolean
348 spi_key_set_contains_key (Accessibility_KeySet            *key_set,
349                           const Accessibility_DeviceEvent *key_event)
350 {
351   gint i;
352   gint len;
353
354   if (!key_set)
355     {
356       g_print ("null key set!");
357       return TRUE;
358     }
359
360   len = key_set->_length;
361   
362   if (len == 0) /* special case, means "all keys/any key" */
363     {
364       g_print ("anykey\n");         
365       return TRUE;
366     }
367
368   for (i = 0; i < len; ++i)
369     {
370 #ifdef SPI_KEYEVENT_DEBUG           
371       g_print ("key_set[%d] = %d; key_event %d, code %d\n",
372                 i, (int) key_set->_buffer[i],
373                (int) key_event->id, (int) key_event->hw_code); 
374 #endif
375       if (key_set->_buffer[i] == (CORBA_long) key_event->id)
376         {
377           return TRUE;
378         }
379       if (key_set->_buffer[i] == (CORBA_long) -key_event->hw_code)
380         {
381           return TRUE;
382         }
383     }
384   
385   return FALSE;
386 }
387
388 static gboolean
389 spi_key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq   *type_seq,
390                                       const Accessibility_DeviceEvent *key_event)
391 {
392   gint i;
393   gint len;
394
395
396   if (!type_seq)
397     {
398       g_print ("null type seq!");
399       return TRUE;
400     }
401
402   len = type_seq->_length;
403   
404   if (len == 0) /* special case, means "all events/any event" */
405     {
406       return TRUE;
407     }
408
409   for (i = 0; i < len; ++i)
410     {
411 #ifdef SPI_DEBUG            
412       g_print ("type_seq[%d] = %d; key event type = %d\n", i,
413                (int) type_seq->_buffer[i], (int) key_event->type);
414 #endif      
415       if (type_seq->_buffer[i] == (CORBA_long) key_event->type)
416         {
417           return TRUE;
418         }
419     }
420   
421   return FALSE;
422 }
423
424 static gboolean
425 spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
426                                 DEControllerKeyListener         *listener,
427                                 CORBA_boolean                    is_system_global)
428 {
429   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
430        spi_key_set_contains_key (listener->keys, key_event) &&
431        spi_key_eventtype_seq_contains_event (listener->typeseq, key_event) && 
432       (is_system_global == listener->mode->global))
433     {
434       return TRUE;
435     }
436   else
437     {
438       return FALSE;
439     }
440 }
441
442 static gboolean
443 spi_notify_keylisteners (GList                          **key_listeners,
444                          const Accessibility_DeviceEvent *key_event,
445                          CORBA_boolean                    is_system_global,
446                          CORBA_Environment               *ev)
447 {
448   GList   *l;
449   GSList  *notify = NULL, *l2;
450   gboolean is_consumed;
451
452   if (!key_listeners)
453     {
454       return FALSE;
455     }
456
457   for (l = *key_listeners; l; l = l->next)
458     {
459        DEControllerKeyListener *key_listener = l->data;
460
461        if (spi_key_event_matches_listener (key_event, key_listener, is_system_global))
462          {
463            Accessibility_DeviceEventListener ls = key_listener->listener.object;
464
465            if (ls != CORBA_OBJECT_NIL)
466              {
467                notify = g_slist_prepend (notify, CORBA_Object_duplicate (ls, ev));
468              }
469          }
470     }
471
472 #ifdef SPI_KEYEVENT_DEBUG
473   if (!notify)
474     {
475       g_print ("no match for listener %d\n", i);
476     }
477 #endif
478
479   is_consumed = FALSE;
480   for (l2 = notify; l2 && !is_consumed; l2 = l2->next)
481     {
482       Accessibility_DeviceEventListener ls = l2->data;
483
484       is_consumed = Accessibility_DeviceEventListener_notifyEvent (ls, key_event, ev);
485
486       if (BONOBO_EX (ev))
487         {
488           is_consumed = FALSE;
489           CORBA_exception_free (ev);
490         }
491
492       CORBA_Object_release (ls, ev);
493     }
494
495   for (; l2; l2 = l2->next)
496     {
497       CORBA_Object_release (l2->data, ev);
498     }
499
500   g_slist_free (notify);
501   
502   return is_consumed;
503 }
504
505 static Accessibility_DeviceEvent
506 spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
507 {
508   Accessibility_DeviceEvent key_event;
509   KeySym keysym;
510   const int cbuf_bytes = 20;
511   char cbuf [cbuf_bytes];
512   
513   keysym = XLookupKeysym (x_key_event, 0);
514   key_event.id = (CORBA_long)(keysym);
515   key_event.hw_code = (CORBA_short) x_key_event->keycode;
516   if (((XEvent *) x_key_event)->type == KeyPress)
517     {
518       key_event.type = Accessibility_KEY_PRESSED;
519     }
520   else
521     {
522       key_event.type = Accessibility_KEY_RELEASED;
523     } 
524   key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
525   key_event.is_text = CORBA_FALSE;
526   switch (keysym)
527     {
528       case ' ':
529         key_event.event_string = CORBA_string_dup ("space");
530         break;
531       case XK_Tab:
532         key_event.event_string = CORBA_string_dup ("Tab");
533         break;
534       case XK_BackSpace:
535         key_event.event_string = CORBA_string_dup ("Backspace");
536         break;
537       case XK_Return:
538         key_event.event_string = CORBA_string_dup ("Return");
539         break;
540       default:
541         if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
542           {
543             key_event.event_string = CORBA_string_dup (cbuf);
544             if (isgraph (keysym))
545               {
546                 key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
547               }
548           }
549         else
550           {
551             key_event.event_string = CORBA_string_dup ("");
552           }
553     }
554
555   key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
556 #ifdef SPI_KEYEVENT_DEBUG
557   fprintf (stderr,
558      "Key %lu pressed (%c), modifiers %d\n",
559      (unsigned long) keysym,
560      keysym ? (int) keysym : '*',
561      (int) x_key_event->state);
562 #endif
563 #ifdef SPI_DEBUG
564   fprintf (stderr, "%s%c",
565      (x_key_event->state & Mod1Mask)?"Alt-":"",
566      ((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
567      g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
568 #endif /* SPI_DEBUG */
569   return key_event;     
570 }
571
572 static gboolean
573 spi_controller_update_key_grabs (SpiDEController           *controller,
574                                  Accessibility_DeviceEvent *recv)
575 {
576   GList *l, *next;
577
578   g_return_val_if_fail (controller != NULL, FALSE);
579
580   /*
581    * masks known to work with default RH 7.1+:
582    * 0 (no mods), LockMask, Mod1Mask, Mod2Mask, ShiftMask,
583    * ShiftMask|LockMask, Mod1Mask|LockMask, Mod2Mask|LockMask,
584    * ShiftMask|Mod1Mask, ShiftMask|Mod2Mask, Mod1Mask|Mod2Mask,
585    * ShiftMask|LockMask|Mod1Mask, ShiftMask|LockMask|Mod2Mask,
586    *
587    * ControlMask grabs are broken, must be in use already
588    */
589   for (l = controller->keygrabs_list; l; l = next)
590     {
591       gboolean do_remove;
592       gboolean re_issue_grab;
593       DEControllerGrabMask *grab_mask = l->data;
594
595       next = l->next;
596
597       re_issue_grab = recv &&
598               (recv->modifiers & grab_mask->mod_mask) &&
599               (grab_mask->key_val == keycode_for_keysym (recv->id));
600
601 #ifdef SPI_DEBUG
602       fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
603                (long int) grab_mask->key_val,
604                (long int) grab_mask->mod_mask,
605                grab_mask->pending_add ? '+' : '.',
606                grab_mask->pending_remove ? '-' : '.',
607                re_issue_grab ? "re-issue": "");
608 #endif
609
610       do_remove = FALSE;
611
612       if (grab_mask->pending_add && grab_mask->pending_remove)
613         {
614           do_remove = TRUE;
615         }
616       else if (grab_mask->pending_remove)
617         {
618 #ifdef SPI_DEBUG
619       fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
620 #endif
621           XUngrabKey (GDK_DISPLAY (),
622                       grab_mask->key_val,
623                       grab_mask->mod_mask,
624                       gdk_x11_get_default_root_xwindow ());
625
626           do_remove = TRUE;
627         }
628       else if (grab_mask->pending_add || re_issue_grab)
629         {
630
631 #ifdef SPI_DEBUG
632           fprintf (stderr, "grab with mask %x\n", grab_mask->mod_mask);
633 #endif
634           XGrabKey (GDK_DISPLAY (),
635                     grab_mask->key_val,
636                     grab_mask->mod_mask,
637                     gdk_x11_get_default_root_xwindow (),
638                     True,
639                     GrabModeAsync,
640                     GrabModeAsync);
641         }
642
643       grab_mask->pending_add = FALSE;
644       grab_mask->pending_remove = FALSE;
645
646       if (do_remove)
647         {
648           g_assert (grab_mask->ref_count <= 0);
649
650           controller->keygrabs_list = g_list_delete_link (
651             controller->keygrabs_list, l);
652
653           spi_grab_mask_free (grab_mask);
654         }
655
656       /* TODO: check calls for errors and return FALSE if error occurs */
657     } 
658
659   return TRUE;
660 }
661
662 /*
663  * Implemented GObject::finalize
664  */
665 static void
666 spi_device_event_controller_object_finalize (GObject *object)
667 {
668   SpiDEController *controller;
669
670   controller = SPI_DEVICE_EVENT_CONTROLLER (object);
671
672 #ifdef SPI_DEBUG
673   fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
674 #endif
675   /* disconnect any special listeners, get rid of outstanding keygrabs */
676   XUngrabKey (GDK_DISPLAY (), AnyKey, AnyModifier, DefaultRootWindow (GDK_DISPLAY ()));
677         
678   spi_device_event_controller_parent_class->finalize (object);
679 }
680
681 /*
682  * CORBA Accessibility::DEController::registerKeystrokeListener
683  *     method implementation
684  */
685 static void
686 impl_register_keystroke_listener (PortableServer_Servant                  servant,
687                                   const Accessibility_DeviceEventListener l,
688                                   const Accessibility_KeySet             *keys,
689                                   const Accessibility_ControllerEventMask mask,
690                                   const Accessibility_KeyEventTypeSeq    *type,
691                                   const Accessibility_EventListenerMode  *mode,
692                                   CORBA_Environment                      *ev)
693 {
694   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
695           bonobo_object_from_servant (servant));
696   DEControllerKeyListener *dec_listener;
697 #ifdef SPI_DEBUG
698   fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
699            (void *) l, (unsigned long) mask);
700 #endif
701   dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
702   spi_controller_register_device_listener (
703     controller, (DEControllerListener *) dec_listener, ev);
704 }
705
706
707 typedef struct {
708         CORBA_Environment       *ev;
709         DEControllerKeyListener *key_listener;
710 } RemoveKeyListenerClosure;
711
712 static SpiReEntrantContinue
713 remove_key_listener_cb (GList * const *list,
714                         gpointer       user_data)
715 {
716   DEControllerKeyListener  *key_listener = (*list)->data;
717   RemoveKeyListenerClosure *ctx = user_data;
718
719   if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
720                                   key_listener->listener.object, ctx->ev))
721     {
722       spi_re_entrant_list_delete_link (list);
723       spi_dec_key_listener_free (key_listener, ctx->ev);
724     }
725
726   return SPI_RE_ENTRANT_CONTINUE;
727 }
728
729 static SpiReEntrantContinue
730 copy_key_listener_cb (GList * const *list,
731                       gpointer       user_data)
732 {
733   DEControllerKeyListener  *key_listener = (*list)->data;
734   RemoveKeyListenerClosure *ctx = user_data;
735
736   if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
737                                   key_listener->listener.object, ctx->ev))
738     {
739       /* TODO: FIXME aggregate keys in case the listener is registered twice */
740       CORBA_free (ctx->key_listener->keys);         
741       ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
742     }
743
744   return SPI_RE_ENTRANT_CONTINUE;
745 }
746
747 /*
748  * CORBA Accessibility::DEController::deregisterKeystrokeListener
749  *     method implementation
750  */
751 static void
752 impl_deregister_keystroke_listener (PortableServer_Servant                  servant,
753                                     const Accessibility_DeviceEventListener l,
754                                     const Accessibility_KeySet             *keys,
755                                     const Accessibility_ControllerEventMask mask,
756                                     const Accessibility_KeyEventTypeSeq    *type,
757                                     CORBA_Environment                      *ev)
758 {
759   DEControllerKeyListener  *key_listener;
760   RemoveKeyListenerClosure  ctx;
761   SpiDEController *controller;
762
763   controller = SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
764
765   key_listener = spi_dec_key_listener_new (l, keys, mask, type, NULL, ev);
766
767 #ifdef SPI_DEREGISTER_DEBUG
768   fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
769            (void *) l, (unsigned long) mask->value);
770 #endif
771
772   ctx.ev = ev;
773   ctx.key_listener = key_listener;
774
775   /* special case, copy keyset from existing controller list entry */
776   if (keys->_length == 0) 
777     {
778       spi_re_entrant_list_foreach (&controller->key_listeners,
779                                   copy_key_listener_cb, &ctx);
780     }
781   
782   spi_controller_deregister_global_keygrabs (controller, key_listener);
783
784   spi_re_entrant_list_foreach (&controller->key_listeners,
785                                 remove_key_listener_cb, &ctx);
786
787   spi_dec_key_listener_free (key_listener, ev);
788 }
789
790 /*
791  * CORBA Accessibility::DEController::registerKeystrokeListener
792  *     method implementation
793  */
794 static void
795 impl_generate_keyboard_event (PortableServer_Servant           servant,
796                               const CORBA_long                 keycode,
797                               const CORBA_char                *keystring,
798                               const Accessibility_KeySynthType synth_type,
799                               CORBA_Environment               *ev)
800 {
801   long key_synth_code;
802
803 #ifdef SPI_DEBUG
804   fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
805            (long) keycode, (int) synth_type);
806 #endif
807   /* TODO: hide/wrap/remove X dependency */
808
809   /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
810         
811   /*
812    * TODO: when initializing, query for XTest extension before using,
813    * and fall back to XSendEvent() if XTest is not available.
814    */
815   
816   /* TODO: implement keystring mode also */
817   gdk_error_trap_push ();
818
819   switch (synth_type)
820     {
821       case Accessibility_KEY_PRESS:
822         XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
823         break;
824       case Accessibility_KEY_PRESSRELEASE:
825         XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
826       case Accessibility_KEY_RELEASE:
827         XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, False, CurrentTime);
828         break;
829       case Accessibility_KEY_SYM:
830         key_synth_code = keycode_for_keysym (keycode);
831         XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, True, CurrentTime);
832         XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, False, CurrentTime);
833         break;
834       case Accessibility_KEY_STRING:
835         fprintf (stderr, "Not yet implemented\n");
836         break;
837     }
838   if (gdk_error_trap_pop ())
839     {
840       g_warning ("Error emitting keystroke");
841     }
842 }
843
844 /* Accessibility::DEController::generateMouseEvent */
845 static void
846 impl_generate_mouse_event (PortableServer_Servant servant,
847                            const CORBA_long       x,
848                            const CORBA_long       y,
849                            const CORBA_char      *eventName,
850                            CORBA_Environment     *ev)
851 {
852 #ifdef SPI_DEBUG
853   fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
854            eventName, (long int) x, (long int) y);
855 #endif
856   g_warning ("not yet implemented");
857 }
858
859 /* Accessibility::DEController::notifyListenersSync */
860 static CORBA_boolean
861 impl_notify_listeners_sync (PortableServer_Servant           servant,
862                             const Accessibility_DeviceEvent *event,
863                             CORBA_Environment               *ev)
864 {
865   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
866     bonobo_object_from_servant (servant));
867 #ifdef SPI_DEBUG
868   g_print ("notifylistening listeners synchronously: controller %p, event id %d\n",
869            controller, (int) event->id);
870 #endif
871   return spi_notify_keylisteners (&controller->key_listeners, event, CORBA_FALSE, ev) ?
872           CORBA_TRUE : CORBA_FALSE; 
873 }
874
875 /* Accessibility::DEController::notifyListenersAsync */
876 static void
877 impl_notify_listeners_async (PortableServer_Servant           servant,
878                              const Accessibility_DeviceEvent *event,
879                              CORBA_Environment               *ev)
880 {
881   SpiDEController *controller = SPI_DEVICE_EVENT_CONTROLLER (
882     bonobo_object_from_servant (servant));
883 #ifdef SPI_DEBUG
884   fprintf (stderr, "notifying listeners asynchronously\n");
885 #endif
886   spi_notify_keylisteners (&controller->key_listeners, event, CORBA_FALSE, ev); 
887 }
888
889 static void
890 spi_device_event_controller_class_init (SpiDEControllerClass *klass)
891 {
892   GObjectClass * object_class = (GObjectClass *) klass;
893   POA_Accessibility_DeviceEventController__epv *epv = &klass->epv;
894
895   spi_device_event_controller_parent_class = g_type_class_peek_parent (klass);
896   
897   object_class->finalize = spi_device_event_controller_object_finalize;
898         
899   epv->registerKeystrokeListener   = impl_register_keystroke_listener;
900   epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
901   epv->generateKeyboardEvent       = impl_generate_keyboard_event;
902   epv->generateMouseEvent          = impl_generate_mouse_event;
903   epv->notifyListenersSync         = impl_notify_listeners_sync;
904   epv->notifyListenersAsync        = impl_notify_listeners_async;
905 }
906
907 static void
908 spi_device_event_controller_init (SpiDEController *device_event_controller)
909 {
910   device_event_controller->key_listeners   = NULL;
911   device_event_controller->mouse_listeners = NULL;
912   device_event_controller->keygrabs_list   = NULL;
913
914   /*
915    * TODO: fixme, this module makes the foolish assumptions that
916    * registryd uses the same display as the apps, and that the
917    * DISPLAY environment variable is set.
918    */
919   gdk_init (NULL, NULL);
920   
921   spi_controller_register_with_devices (device_event_controller);
922 }
923
924 static void
925 spi_device_event_controller_forward_key_event (SpiDEController *controller,
926                                                const XEvent    *event)
927 {
928   gboolean is_consumed = FALSE;
929   CORBA_Environment ev;
930   Accessibility_DeviceEvent key_event;
931
932   g_assert (event->type == KeyPress || event->type == KeyRelease);
933
934   CORBA_exception_init (&ev);
935
936   key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
937   /* relay to listeners, and decide whether to consume it or not */
938   is_consumed = spi_notify_keylisteners (
939     &controller->key_listeners, &key_event, CORBA_TRUE, &ev);
940
941   CORBA_exception_free (&ev);
942
943   if (is_consumed)
944     {
945       XAllowEvents (GDK_DISPLAY (), AsyncKeyboard, CurrentTime);
946     }
947   else
948     {
949       XAllowEvents (GDK_DISPLAY (), ReplayKeyboard, CurrentTime);
950     }
951
952   spi_controller_update_key_grabs (controller, &key_event);
953 }
954
955 SpiDEController *
956 spi_device_event_controller_new (SpiRegistry *registry)
957 {
958   SpiDEController *retval = g_object_new (
959     SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
960
961   retval->registry = SPI_REGISTRY (bonobo_object_ref (
962           BONOBO_OBJECT (registry)));
963
964   return retval;
965 }
966
967 BONOBO_TYPE_FUNC_FULL (SpiDEController,
968                        Accessibility_DeviceEventController,
969                        PARENT_TYPE,
970                        spi_device_event_controller);