2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001, 2002 Sun Microsystems Inc.,
6 * Copyright 2001, 2002 Ximian, Inc.
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.
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.
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.
24 /* registry.c: the main accessibility service registry implementation */
26 #undef SPI_LISTENER_DEBUG
28 #undef SPI_QUEUE_DEBUG
35 #include <spi-common/spi-dbus.h>
38 #include "dbus/dbus-glib-lowlevel.h"
40 /* Our parent GObject type */
41 #define PARENT_TYPE G_OBJECT_TYPE
57 const char *event_name;
58 EventTypeCategory type_cat;
59 GQuark major; /* from string segment[1] */
60 GQuark minor; /* from string segment[1]+segment[2] */
61 GQuark detail; /* from string segment[3] (not concatenated) */
64 G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT)
67 spi_registry_set_debug (const char *debug_flag_string)
69 if (debug_flag_string)
70 _dbg = (int) g_ascii_strtod (debug_flag_string, NULL);
73 static void emit(SpiRegistry *registry, const char *name, int first_type, ...)
77 va_start(arg, first_type);
78 spi_dbus_emit_valist(registry->droute.bus, SPI_DBUS_PATH_DESKTOP, SPI_DBUS_INTERFACE_REGISTRY, name, first_type, arg);
83 desktop_add_application (SpiDesktop *desktop,
84 guint index, gpointer data)
86 SpiRegistry *registry = SPI_REGISTRY (data);
87 const SpiDesktopApplication *app = g_list_nth_data(desktop->applications, index);
89 emit(registry, "applicationAdd", DBUS_TYPE_UINT32, &index, DBUS_TYPE_STRING, &app->bus_name, DBUS_TYPE_INVALID);
95 desktop_remove_application (SpiDesktop *desktop,
96 guint index, gpointer data)
98 SpiRegistry *registry = SPI_REGISTRY (data);
99 SpiDesktopApplication *app = g_list_nth_data(desktop->applications, index);
101 spi_dbus_remove_disconnect_match (registry->droute.bus, app->bus_name);
102 emit(registry, "applicationRemove", DBUS_TYPE_UINT32, &index, DBUS_TYPE_STRING, &app->bus_name, DBUS_TYPE_INVALID);
107 spi_registry_object_finalize (GObject *object)
109 DBG (1, g_warning ("spi_registry_object_finalize called\n"));
110 g_object_unref (SPI_REGISTRY (object)->de_controller);
112 G_OBJECT_CLASS (spi_registry_parent_class)->finalize (object);
116 * registerApplication:
117 * @application: a reference to the requesting @Application
118 * return values: void
120 * Register a new application with the accessibility broker.
124 impl_accessibility_registry_register_application (DBusConnection *bus, DBusMessage *message, void *user_data)
126 SpiRegistry *registry = SPI_REGISTRY (user_data);
127 const char *application = dbus_message_get_sender (message);
130 fprintf (stderr, "registering app %s\n", application);
132 spi_desktop_add_application (registry->desktop, application);
134 spi_dbus_add_disconnect_match (registry->droute.bus, application);
137 * TODO: change the implementation below to a WM-aware one;
138 * e.g. don't add all apps to the SpiDesktop
140 return dbus_message_new_method_return (message);
144 * deregisterApplication:
145 * @application: a reference to the @Application
146 * to be deregistered.
147 * return values: void
149 * De-register an application previously registered with the broker.
153 impl_accessibility_registry_deregister_application (DBusConnection *bus, DBusMessage *message, void *user_data)
155 SpiRegistry *registry = SPI_REGISTRY (user_data);
156 const char *application = dbus_message_get_sender (message);
158 spi_desktop_remove_application (registry->desktop, application);
161 fprintf (stderr, "de-registered app %s\n", application);
163 return dbus_message_new_method_return (message);
168 * return values: a short integer indicating the current number of
171 * Get the current number of desktops.
175 impl_accessibility_registry_get_desktop_count (DBusConnection *bus, DBusMessage *message, void *user_data)
177 dbus_int16_t n_desktops = 1;
180 /* TODO: implement support for multiple virtual desktops */
181 reply = dbus_message_new_method_return (message);
184 dbus_message_append_args (reply, DBUS_TYPE_INT16, &n_desktops, DBUS_TYPE_INVALID);
191 * @n: the index of the requested @Desktop.
192 * return values: a reference to the requested @Desktop.
194 * Get the nth accessible desktop.
198 impl_accessibility_registry_get_desktop (DBusConnection *bus, DBusMessage *message, void *user_data)
205 /* TODO: implement support for multiple virtual desktops */
206 dbus_error_init (&error);
207 if (!dbus_message_get_args (message, &error, DBUS_TYPE_INT16, &n, DBUS_TYPE_INVALID))
209 return spi_dbus_general_error (message);
211 path = (n == 0? SPI_DBUS_PATH_DESKTOP: "/");
212 reply = dbus_message_new_method_return (message);
215 dbus_message_append_args (reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
223 * return values: a sequence containing references to
226 * Get a list of accessible desktops.
230 impl_accessibility_registry_get_desktop_list (DBusConnection *bus, DBusMessage *message, void *user_data)
233 DBusMessageIter iter, iter_array;
234 const char *path = SPI_DBUS_PATH_DESKTOP;
236 reply = dbus_message_new_method_return (message);
237 if (!reply) return NULL;
238 dbus_message_iter_init_append(reply, &iter);
239 if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
240 dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
241 if (!dbus_message_iter_close_container (&iter, &iter_array)) goto oom;
244 // TODO: handle out-of-memory
250 impl_accessibility_registry_get_device_event_controller (DBusConnection *bus, DBusMessage *message, void *user_data)
253 const char *path = SPI_DBUS_PATH_DEC;
255 reply = dbus_message_new_method_return (message);
258 dbus_message_append_args (reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
265 spi_registry_class_init (SpiRegistryClass *klass)
267 GObjectClass * object_class = (GObjectClass *) klass;
269 spi_registry_parent_class = g_type_class_ref (G_TYPE_OBJECT);
271 object_class->finalize = spi_registry_object_finalize;
274 static DBusObjectPathVTable droute_vtable =
278 NULL, NULL, NULL, NULL
282 disconnect_watch (DBusConnection *bus, DBusMessage *message, void *user_data)
284 SpiRegistry *registry = SPI_REGISTRY (user_data);
285 const char *name, *old, *new;
287 if (!dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
289 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
291 if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID))
293 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
295 if (*old != '\0' && *new == '\0')
297 spi_desktop_remove_application (registry->desktop, old);
298 spi_remove_device_listeners (registry->de_controller, old);
300 return DBUS_HANDLER_RESULT_HANDLED;
304 spi_registry_init (SpiRegistry *registry)
308 spi_registry_set_debug (g_getenv ("AT_SPI_DEBUG"));
310 * TODO: FIXME, this module makes the foolish assumptions that
311 * registryd uses the same display as the apps, and that the
312 * DISPLAY environment variable is set.
314 gdk_init (NULL, NULL);
316 registry->exit_notify_timeout = 200;
317 registry->queue_handler_id = 0;
319 dbus_error_init (&error);
320 registry->droute.bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
321 if (!registry->droute.bus)
323 g_warning("Couldn't connect to dbus: %s\n", error.message);
326 registry->droute.user_data = registry;
327 spi_registry_initialize_registry_interface (®istry->droute);
328 spi_registry_initialize_desktop_interface (®istry->droute);
329 spi_registry_initialize_dec_interface (®istry->droute);
330 // todo: initialize accessible and component interfaces, for desktop?
331 if (!dbus_connection_try_register_fallback (registry->droute.bus, "/org/freedesktop/atspi", &droute_vtable, ®istry->droute, &error))
333 g_warning("Couldn't register droute.\n");
335 dbus_connection_setup_with_g_main(registry->droute.bus, g_main_context_default());
337 // TODO: decide whether focus_object is still relevant
338 registry->desktop = spi_desktop_new ();
339 /* Register callback notification for application addition and removal */
340 g_signal_connect (G_OBJECT (registry->desktop),
342 G_CALLBACK (desktop_add_application),
345 g_signal_connect (G_OBJECT (registry->desktop),
346 "application_removed",
347 G_CALLBACK (desktop_remove_application),
350 registry->de_controller = spi_device_event_controller_new (registry);
352 dbus_connection_add_filter (registry->droute.bus, disconnect_watch, registry, NULL);
356 spi_registry_new (void)
358 SpiRegistry *retval = g_object_new (SPI_REGISTRY_TYPE, NULL);
362 static DRouteMethod methods[] =
364 { impl_accessibility_registry_register_application , "registerApplication" },
365 { impl_accessibility_registry_deregister_application, "deregisterApplication" },
366 { impl_accessibility_registry_get_desktop_count, "getDesktopCount" },
367 { impl_accessibility_registry_get_desktop, "getDesktop" },
368 { impl_accessibility_registry_get_desktop_list, "getDesktopList" },
369 { impl_accessibility_registry_get_device_event_controller, "getDeviceEventController" },
374 spi_registry_initialize_registry_interface (DRouteData * data)
376 droute_add_interface (data, "org.freedesktop.atspi.Registry", methods,