2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001 Sun Microsystems Inc.
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.
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.
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.
23 /* registry.c: the main accessibility service registry implementation */
25 #undef SPI_LISTENER_DEBUG
34 /* Our parent GObject type */
35 #define PARENT_TYPE SPI_LISTENER_TYPE
37 /* A pointer to our parent object class */
38 static SpiListenerClass *spi_registry_parent_class;
53 EventTypeCategory type_cat;
54 GQuark major; /* from string segment[1] */
55 GQuark minor; /* from string segment[1]+segment[2] */
56 GQuark detail; /* from string segment[3] (not concatenated) */
60 Accessibility_EventListener listener;
61 GQuark event_type_quark;
62 EventTypeCategory event_type_cat;
65 /* static function prototypes */
66 static void _registry_notify_listeners (GList *listeners,
67 const Accessibility_Event *e,
68 CORBA_Environment *ev);
70 static long _get_unique_id();
72 static gboolean _device_event_controller_hook (gpointer source);
75 spi_listener_struct_new (Accessibility_EventListener listener, CORBA_Environment *ev)
77 SpiListenerStruct *retval = g_malloc (sizeof (SpiListenerStruct));
78 retval->listener = bonobo_object_dup_ref (listener, ev);
83 spi_listener_struct_free (SpiListenerStruct *ls, CORBA_Environment *ev)
85 bonobo_object_release_unref (ls->listener, ev);
89 /* GObject::finalize */
91 spi_registry_object_finalize (GObject *object)
93 SpiRegistry *registry = SPI_REGISTRY (object);
95 printf("spi_registry_object_finalize called\n");
96 /* TODO: unref deviceeventcontroller, which disconnects key listener */
97 G_OBJECT_CLASS (spi_registry_parent_class)->finalize (object);
101 * registerApplication:
102 * @application: a reference to the requesting @Application
103 * return values: void
105 * Register a new application with the accessibility broker.
109 impl_accessibility_registry_register_application (PortableServer_Servant servant,
110 const Accessibility_Application application,
111 CORBA_Environment * ev)
113 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
116 fprintf (stderr, "registering app %p\n", application);
118 spi_desktop_add_application (registry->desktop, application);
120 Accessibility_Application__set_id (application, _get_unique_id(), ev);
123 * TODO: change the implementation below to a WM-aware one;
124 * e.g. don't add all apps to the SpiDesktop
129 compare_corba_objects (gconstpointer p1, gconstpointer p2)
131 CORBA_Environment ev;
135 fprintf (stderr, "comparing %p to %p\n",
139 retval = !CORBA_Object_is_equivalent ((CORBA_Object) p1, (CORBA_Object) p2, &ev);
144 register_with_toolkits (SpiRegistry *spi_registry_bonobo_object, EventTypeStruct *etype, CORBA_Environment *ev)
149 Accessibility_Desktop desktop;
150 Accessibility_Application app;
151 Accessibility_Registry registry;
152 registry = BONOBO_OBJREF (spi_registry_bonobo_object);
154 /* for each app in each desktop, call ...Application_registerToolkitEventListener */
156 n_desktops = Accessibility_Registry_getDesktopCount (registry, ev);
158 for (i=0; i<n_desktops; ++i)
160 desktop = Accessibility_Registry_getDesktop (registry, i, ev);
161 n_apps = Accessibility_Desktop__get_childCount (desktop, ev);
162 for (j=0; j<n_apps; ++j)
164 app = (Accessibility_Application) Accessibility_Desktop_getChildAtIndex (desktop,
167 Accessibility_Application_registerToolkitEventListener (app,
169 CORBA_string_dup (etype->event_name),
177 compare_listener_quarks (gconstpointer p1, gconstpointer p2)
179 return (!((SpiListenerStruct *)p2)->event_type_quark == ((SpiListenerStruct *)p1)->event_type_quark);
183 compare_listener_corbaref (gconstpointer p1, gconstpointer p2)
185 return compare_corba_objects (((SpiListenerStruct *)p2)->listener,
186 ((SpiListenerStruct *)p1)->listener);
190 parse_event_type (EventTypeStruct *etype, char *event_name)
192 gchar **split_string;
195 split_string = g_strsplit(event_name, ":", 4);
196 etype->event_name = g_strndup(event_name, 255);
198 if (!g_ascii_strncasecmp (event_name, "focus:", 6))
200 etype->type_cat = ETYPE_FOCUS;
202 else if (!g_ascii_strncasecmp (event_name, "object:", 7))
204 etype->type_cat = ETYPE_OBJECT;
206 else if (!g_ascii_strncasecmp (event_name, "window:", 7))
208 etype->type_cat = ETYPE_WINDOW;
212 etype->type_cat = ETYPE_TOOLKIT;
219 etype->minor = g_quark_from_string (s = g_strconcat (split_string[1], split_string[2], NULL));
223 etype->detail = g_quark_from_string (split_string[3]);
224 s = g_strconcat (split_string[1], split_string[2], split_string[3], NULL);
225 etype->major = g_quark_from_string (s);
230 etype->detail = g_quark_from_static_string ("");
231 s = g_strconcat (split_string[1], split_string[2], NULL);
232 etype->major = g_quark_from_string (s);
238 etype->major = g_quark_from_string (split_string[1]);
239 etype->minor = etype->major;
240 etype->detail = etype->major;
245 etype->major = g_quark_from_static_string ("");
246 etype->minor = etype->major;
247 etype->detail = etype->major;
250 g_strfreev (split_string);
254 * deregisterApplication:
255 * @application: a reference to the @Application
256 * to be deregistered.
257 * return values: void
259 * De-register an application previously registered with the broker.
263 impl_accessibility_registry_deregister_application (PortableServer_Servant servant,
264 const Accessibility_Application application,
265 CORBA_Environment * ev)
267 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
269 spi_desktop_remove_application (registry->desktop, application);
272 fprintf (stderr, "de-registered app %p\n", application);
277 * CORBA Accessibility::Registry::registerGlobalEventListener method implementation
280 impl_accessibility_registry_register_global_event_listener (
281 PortableServer_Servant servant,
282 Accessibility_EventListener listener,
283 const CORBA_char *event_name,
284 CORBA_Environment *ev)
286 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
287 SpiListenerStruct *ls = spi_listener_struct_new (listener, ev);
288 EventTypeStruct etype;
290 fprintf(stderr, "registering for events of type %s\n", event_name);
292 /* parse, check major event type and add listener accordingly */
293 parse_event_type (&etype, (char*) event_name);
294 ls->event_type_quark = etype.major;
295 ls->event_type_cat = etype.type_cat;
297 switch (etype.type_cat)
300 case (ETYPE_OBJECT) :
301 case (ETYPE_PROPERTY) :
302 registry->object_listeners =
303 g_list_append (registry->object_listeners, ls);
305 case (ETYPE_WINDOW) :
306 /* Support for Window Manager Events is not yet implemented */
307 spi_listener_struct_free (ls, ev);
309 case (ETYPE_TOOLKIT) :
310 registry->toolkit_listeners =
311 g_list_append (registry->toolkit_listeners, ls);
312 register_with_toolkits (registry, &etype, ev);
315 spi_listener_struct_free (ls, ev);
321 * CORBA Accessibility::Registry::deregisterGlobalEventListenerAll method implementation
324 impl_accessibility_registry_deregister_global_event_listener_all (
325 PortableServer_Servant servant,
326 Accessibility_EventListener listener,
327 CORBA_Environment *ev)
329 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
330 SpiListenerStruct *ls = spi_listener_struct_new (listener, ev);
332 list = g_list_find_custom (registry->object_listeners, ls,
333 compare_listener_corbaref);
336 * TODO : de-register with toolkit if the last instance of a listener
337 * to a particular toolkit event type has been deregistered.
342 spi_listener_struct_free ((SpiListenerStruct *) list->data, ev);
343 registry->object_listeners = g_list_delete_link (registry->object_listeners, list);
344 list = g_list_find_custom (registry->object_listeners, ls, compare_listener_corbaref);
346 list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
349 spi_listener_struct_free ((SpiListenerStruct *) list->data, ev);
350 registry->toolkit_listeners = g_list_delete_link (registry->toolkit_listeners, list);
351 list = g_list_find_custom (registry->toolkit_listeners, ls, compare_listener_corbaref);
353 spi_listener_struct_free (ls, ev);
357 * CORBA Accessibility::Registry::deregisterGlobalEventListener method implementation
360 impl_accessibility_registry_deregister_global_event_listener (
361 PortableServer_Servant servant,
362 Accessibility_EventListener listener,
363 const CORBA_char * event_name,
364 CORBA_Environment *ev)
366 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
367 SpiListenerStruct ls;
368 EventTypeStruct etype;
372 parse_event_type (&etype, (char *) event_name);
373 switch (etype.type_cat)
375 case (ETYPE_OBJECT) :
376 case (ETYPE_PROPERTY) :
378 listeners = ®istry->object_listeners;
380 case (ETYPE_WINDOW) :
381 /* Support for Window Manager Events is not yet implemented */
384 case (ETYPE_TOOLKIT) :
385 listeners = ®istry->toolkit_listeners;
395 ls.event_type_quark = etype.major;
396 list = g_list_find_custom (*listeners, &ls, compare_listener_quarks);
400 spi_listener_struct_free ((SpiListenerStruct *) list->data, ev);
401 *listeners = g_list_delete_link (*listeners, list);
402 list = g_list_find_custom (*listeners, &ls, compare_listener_quarks);
409 * return values: a short integer indicating the current number of
412 * Get the current number of desktops.
416 impl_accessibility_registry_get_desktop_count (PortableServer_Servant servant,
417 CORBA_Environment * ev)
419 /* TODO: implement support for multiple virtual desktops */
420 CORBA_short n_desktops;
421 n_desktops = (CORBA_short) 1;
427 * @n: the index of the requested @Desktop.
428 * return values: a reference to the requested @Desktop.
430 * Get the nth accessible desktop.
433 static Accessibility_Desktop
434 impl_accessibility_registry_get_desktop (PortableServer_Servant servant,
436 CORBA_Environment * ev)
438 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
440 /* TODO: implement support for multiple virtual desktops */
443 return (Accessibility_Desktop)
444 bonobo_object_dup_ref (BONOBO_OBJREF (registry->desktop), ev);
448 return (Accessibility_Desktop) CORBA_OBJECT_NIL;
454 * return values: a sequence containing references to
457 * Get a list of accessible desktops.
460 static Accessibility_DesktopSeq *
461 impl_accessibility_registry_get_desktop_list (PortableServer_Servant servant,
462 CORBA_Environment * ev)
464 /* TODO: implement support for multiple virtual desktops */
465 return (Accessibility_DesktopSeq *) NULL;
468 static Accessibility_DeviceEventController
469 impl_accessibility_registry_get_device_event_controller (PortableServer_Servant servant,
470 CORBA_Environment * ev)
472 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
473 if (!registry->device_event_controller)
474 registry->device_event_controller = spi_device_event_controller_new (registry);
476 return bonobo_object_dup_ref (BONOBO_OBJREF (registry->device_event_controller), ev);
480 impl_registry_notify_event (PortableServer_Servant servant,
481 const Accessibility_Event *e,
482 CORBA_Environment *ev)
484 SpiRegistry *registry = SPI_REGISTRY (bonobo_object_from_servant (servant));
485 EventTypeStruct etype;
487 parse_event_type (&etype, e->type);
489 switch (etype.type_cat)
491 case (ETYPE_OBJECT) :
492 case (ETYPE_PROPERTY) :
494 _registry_notify_listeners (registry->object_listeners, e, ev);
496 case (ETYPE_WINDOW) :
497 _registry_notify_listeners (registry->window_listeners, e, ev);
499 case (ETYPE_TOOLKIT) :
500 _registry_notify_listeners (registry->toolkit_listeners, e, ev);
502 case (ETYPE_KEYBOARD) :
506 if (e->source != CORBA_OBJECT_NIL)
508 Accessibility_Accessible_unref (e->source, ev);
520 _registry_notify_listeners (GList *listeners,
521 const Accessibility_Event *e_in,
522 CORBA_Environment *ev)
525 Accessibility_Event e_out;
526 SpiListenerStruct *ls;
527 EventTypeStruct etype;
533 parse_event_type (&etype, e_in->type);
535 for (l = listeners; l; l = l->next)
537 ls = (SpiListenerStruct *) l->data;
539 #ifdef SPI_LISTENER_DEBUG
540 fprintf (stderr, "event quarks: %lx %lx %lx\n", ls->event_type_quark, etype.major, etype.minor);
541 fprintf (stderr, "event name: %s\n", etype.event_name);
544 if ((ls->event_type_quark == etype.major) || (ls->event_type_quark == etype.minor))
547 fprintf (stderr, "notifying listener %d\n", g_list_index (listeners, l->data));
548 s = Accessibility_Accessible__get_name (e_in->source, ev);
549 fprintf (stderr, "event source name %s\n", s);
552 e_out.source = bonobo_object_dup_ref (e_in->source, ev);
553 Accessibility_EventListener_notifyEvent ((Accessibility_EventListener) ls->listener,
556 if (ev->_major != CORBA_NO_EXCEPTION)
558 g_warning ("Accessibility app error: exception during event notification: %s\n",
559 CORBA_exception_id (ev));
566 _device_event_controller_hook (gpointer p)
568 SpiRegistry *registry = (SpiRegistry *)p;
569 SpiDeviceEventController *controller = registry->device_event_controller;
571 spi_device_event_controller_check_key_event (controller);
576 spi_registry_class_init (SpiRegistryClass *klass)
578 GObjectClass * object_class = (GObjectClass *) klass;
579 POA_Accessibility_Registry__epv *epv = &klass->epv;
581 spi_registry_parent_class = g_type_class_ref (SPI_LISTENER_TYPE);
583 object_class->finalize = spi_registry_object_finalize;
585 epv->registerApplication = impl_accessibility_registry_register_application;
586 epv->deregisterApplication = impl_accessibility_registry_deregister_application;
587 epv->registerGlobalEventListener = impl_accessibility_registry_register_global_event_listener;
588 epv->deregisterGlobalEventListener = impl_accessibility_registry_deregister_global_event_listener;
589 epv->deregisterGlobalEventListenerAll = impl_accessibility_registry_deregister_global_event_listener_all;
590 epv->getDeviceEventController = impl_accessibility_registry_get_device_event_controller;
591 epv->getDesktopCount = impl_accessibility_registry_get_desktop_count;
592 epv->getDesktop = impl_accessibility_registry_get_desktop;
593 epv->getDesktopList = impl_accessibility_registry_get_desktop_list;
595 ((SpiListenerClass *) klass)->epv.notifyEvent = impl_registry_notify_event;
599 spi_registry_init (SpiRegistry *registry)
601 registry->object_listeners = NULL;
602 registry->window_listeners = NULL;
603 registry->toolkit_listeners = NULL;
604 registry->desktop = spi_desktop_new();
605 registry->device_event_controller = NULL;
606 registry->kbd_event_hook = _device_event_controller_hook;
609 BONOBO_TYPE_FUNC_FULL (SpiRegistry,
610 Accessibility_Registry,
615 spi_registry_new (void)
617 SpiRegistry *retval = g_object_new (SPI_REGISTRY_TYPE, NULL);
618 bonobo_object_set_immortal (BONOBO_OBJECT (retval), TRUE);