2008-11-5 Mark Doffman <mark.doffman@codethink.co.uk>
authorMark Doffman <mdoff@silver-wind.(none)>
Tue, 4 Nov 2008 19:34:23 +0000 (19:34 +0000)
committerMark Doffman <mdoff@silver-wind.(none)>
Wed, 5 Nov 2008 21:11:12 +0000 (21:11 +0000)
        * atk-adaptor/bridge.c
          Rework for new registration scheme and refactor for readability.
        * atk-adaptor/event.c
        * atk-adaptor/tree.c
          Rework to send out signals for new registration scheme.

        * pyatspi/*
          New registration scheme. Add new ApplicationCache to keep track
          of registered applications.

12 files changed:
atk-adaptor/bridge.c
atk-adaptor/event.c
atk-adaptor/tree.c
pyatspi/accessiblecache.py
pyatspi/applicationcache.py
pyatspi/desktop.py
pyatspi/registry.py
registryd/registry.c
registryd/testregistry.py
tests/apps/test-application.c
xml/org.freedesktop.atspi.Registry.xml
xml/org.freedesktop.atspi.Tree.xml

index 9c37fe5..3e5fba4 100644 (file)
@@ -2,6 +2,7 @@
  * AT-SPI - Assistive Technology Service Provider Interface
  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
  *
+ * Copyright 2008             Codethink Ltd.
  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
  * Copyright 2001, 2002, 2003 Ximian, Inc.
  *
 #include "bridge.h"
 #include "atk-dbus.h"
 
-#undef SPI_BRIDGE_DEBUG
-
-#define DBG(a,b) if(_dbg>=(a))b
-
-int _dbg = 0;
-static const char *registry = NULL;
-SpiAppData *this_app = NULL;
-static gboolean registry_died = FALSE;
-static gint toplevels = 0;
-static gboolean exiting = FALSE;
-static AtkMisc *misc = NULL;
-static gboolean during_init_shutdown = TRUE;
-
-static const char *spi_atk_bridge_get_registry (void);
-static char *device_event_controller = NULL;
-static void     spi_atk_bridge_register_application    (const char *registry);
-static gchar   *spi_atk_bridge_get_registry_ior        (void);
-static gboolean spi_atk_bridge_do_registration         (void);
-static void     spi_atk_bridge_toplevel_added          (AtkObject             *object,
-                                                        guint                 index,
-                                                        AtkObject             *child);
-static void     spi_atk_bridge_toplevel_removed        (AtkObject             *object,
-                                                        guint                 index,
-                                                        AtkObject             *child);
-
-static void     spi_atk_bridge_exit_func               (void);
-static void     spi_atk_tidy_windows                   (void);
-static void     deregister_application                 (SpiAppData *app);
-static void reinit_register_vars (void);
-
-/* For automatic libgnome init */
-extern void gnome_accessibility_module_init     (void);
-extern void gnome_accessibility_module_shutdown (void);
-
-static int     atk_bridge_initialized = FALSE;
-static pid_t   atk_bridge_pid = 0;
+void spi_atk_register_event_listeners   (void);
+void spi_atk_deregister_event_listeners (void);
+void spi_atk_tidy_windows               (void);
 
-/*
- *   These exported symbols are hooked by gnome-program
- * to provide automatic module initialization and shutdown.
- */
-extern void gnome_accessibility_module_init     (void);
-extern void gnome_accessibility_module_shutdown (void);
-
-void
-spi_atk_register_event_listeners(void);
-
-void
-spi_atk_deregister_event_listeners (void);
-
-static gboolean
-post_init (gpointer data)
-{
-  during_init_shutdown = FALSE;
-  return FALSE;
-}
+/*---------------------------------------------------------------------------*/
 
-static DBusObjectPathVTable droute_vtable =
-{
-  NULL,
-  &droute_message,
-  NULL, NULL, NULL, NULL
-};
+SpiAppData *app_data = NULL;
 
-static gchar* atspi_dbus_name;
-static gboolean atspi_no_register; 
+static const AtkMisc *atk_misc = NULL;
 
-static GOptionEntry atspi_option_entries[] = 
-{
-  {"atspi-dbus-name", 0, 0, G_OPTION_ARG_STRING, &atspi_dbus_name, "D-Bus bus name to register as", NULL},
-  {"atspi-no-register", 0, 0, G_OPTION_ARG_NONE, &atspi_no_register, "Do not register with Registry Daemon", NULL},
-  {NULL}
-};
+/*static Display *bridge_display = NULL;*/
 
-static SpiAppData *
-spi_app_init (AtkObject *root, gint *argc, gchar **argv[])
-{
-  GOptionContext *opt;
-  SpiAppData *ad = g_new0(SpiAppData, 1);
-  GError *err = NULL;
-  DBusError error;
-  int i;
+/*---------------------------------------------------------------------------*/
 
-  opt = g_option_context_new(NULL);
-  g_option_context_add_main_entries(opt, atspi_option_entries, NULL);
-  g_option_context_set_ignore_unknown_options(opt, TRUE);
-  if (!g_option_context_parse(opt, argc, argv, &err))
-      g_warning("Option parsing failed: %s\n", err->message);
-
-  dbus_error_init(&error);
-  ad->root = root;
-  ad->droute.bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
-  g_print("D-Bus unique name is : %s\n", dbus_bus_get_unique_name(ad->droute.bus));
-
-  if (!ad->droute.bus)
-  {
-    g_warning("Couldn't connect to dbus: %s\n", error.message);
-    free(ad);
-    return NULL;
-  }
-  if (atspi_dbus_name != NULL && dbus_bus_request_name(ad->droute.bus, 
-                                                      atspi_dbus_name,
-                                                      0,
-                                                      &error))
-  {
-    g_print("\nRecieved D-Bus name - %s\n", atspi_dbus_name);
-  }
-  spi_register_tree_object(ad->droute.bus, &ad->droute, "/org/freedesktop/atspi/tree");
-  if (!dbus_connection_try_register_fallback (ad->droute.bus, 
-                                             "/org/freedesktop/atspi/accessible", 
-                                             &droute_vtable, 
-                                             &ad->droute, 
-                                             &error))
-  {
-    g_warning("Couldn't register droute.\n");
-    free(ad);
-    return NULL;
-  }
-
-  dbus_connection_setup_with_g_main(ad->droute.bus, g_main_context_default());
-
-  atk_dbus_initialize (&ad->droute);
-  return ad;
-}
-
-static int
-atk_bridge_init (gint *argc, gchar **argv[])
-{
-  const char *debug_env_string = g_getenv ("AT_SPI_DEBUG");
-  gchar *fname;
-  gboolean success = FALSE;
-
-  if (atk_bridge_initialized)
-    {
-      return 0;
-    }
-  atk_bridge_initialized = TRUE;
-  atk_bridge_pid = getpid ();
-
-  misc = atk_misc_get_instance();
-
-  if (g_getenv ("ATK_BRIDGE_REDIRECT_LOG"))
-    {
-      fname = g_strconcat ("/tmp/", g_get_prgname (), ".at-spi-log", NULL);
-      /* make sure we're not being redirected - security issue */
-      if (!g_file_test (fname, G_FILE_TEST_IS_SYMLINK))
-         freopen (fname, "w", stderr);
-      g_free (fname);
-    }
-
-  if (debug_env_string) 
-      _dbg = (int) g_ascii_strtod (debug_env_string, NULL);
-
-  /* Connect to dbus */
-  this_app = spi_app_init (atk_get_root (), argc, argv);
-
-  /*
-   * We only want to enable the bridge for top level
-   * applications, we detect bonobo components by seeing
-   * if they were activated with the intention of extracting
-   * an impl. by IID - very solid.
-   */
-#ifdef WITH_BONOBO
-  // TODO: Figure out if this is still needed
-  if (bonobo_activation_iid_get ())
-#else
-  if (0)
-#endif
-    {
-      DBG (1, g_message ("Found Bonobo component\n"));
-      g_signal_connect (atk_get_root (), 
-                        "children-changed::add",
-                        (GCallback) spi_atk_bridge_toplevel_added, 
-                        NULL);
-      g_signal_connect (atk_get_root (), 
-                        "children-changed::remove",
-                        (GCallback) spi_atk_bridge_toplevel_removed, 
-                        NULL);
-      /* in this case we redefine 'success' to mean 'registry is present' */
-      success = (spi_atk_bridge_get_registry () != NULL);
-    }
-  else
-    {
-      success = spi_atk_bridge_do_registration ();
-    }
-  /*
-   * we must emit events even if we are not registered as a
-   * full-fledged app; See bugzilla #400709.
-   */
-  if (success) 
-    {
-      spi_atk_register_event_listeners ();
-    }
-  else
-    {
-      atk_bridge_initialized = FALSE;
-    }
-  g_idle_add (post_init, NULL);
-
-  return 0;
-}
-
-static gboolean
-spi_atk_bridge_do_registration (void)
-{
-  if (spi_atk_bridge_get_registry () == NULL)
-    {
-      g_warning ("Could not locate registry");
-      return FALSE;
-    }
-
-  /* Create the accessible application server object */
-  if (this_app == NULL)
-    this_app = spi_app_init (atk_get_root (), 0, NULL);
-
-  DBG (1, g_message ("About to register application\n"));
-
-  spi_atk_bridge_register_application (spi_atk_bridge_get_registry ());
-  
-  g_atexit (spi_atk_bridge_exit_func);
-
-  DBG (1, g_message ("Application registered & listening\n"));
-  return TRUE;
-}
-
-static void
-spi_atk_bridge_toplevel_added (AtkObject *object,
-                               guint     index,
-                               AtkObject *child)
-{
-  if (toplevels == 0)
-    {
-      spi_atk_bridge_do_registration ();
-    }
-  toplevels++;
-}
-
-static void
-spi_atk_bridge_toplevel_removed (AtkObject *object,
-                                 guint     index,
-                                 AtkObject *child)
-{
-  toplevels--;
-  if (toplevels == 0)
-    {
-      deregister_application (this_app);
-      reinit_register_vars ();
-    }
-  if (toplevels < 0)
-    {
-      g_warning ("More toplevels removed than added\n");
-      toplevels = 0;
-    }
-}
-
-static void
-spi_atk_bridge_register_application (const char *registry)
-{
-  DBusMessage *message, *reply;
-  DBusError error;
-
-  message = dbus_message_new_signal (SPI_DBUS_PATH_REGISTRY, SPI_DBUS_INTERFACE_TREE, "registerApplication");
-  dbus_error_init (&error);
-  dbus_connection_send (this_app->droute.bus, message, NULL);
-  if (error.message) g_print (error.message);
-  if (message) dbus_message_unref (message);
-}
-
-/* 
+/*
  * Returns a 'canonicalized' value for DISPLAY,
  * with the screen number stripped off if present.
+ *
+ * Not currently used in D-Bus version but may be
+ * useful in future if we make use of XAtom.
  */
+#if 0
 static const gchar*
 spi_display_name (void)
 {
@@ -317,37 +68,44 @@ spi_display_name (void)
     if (!canonical_display_name)
       {
         const gchar *display_env = g_getenv ("AT_SPI_DISPLAY");
-       if (!display_env)
-         {
-           display_env = g_getenv ("DISPLAY");
-           if (!display_env || !display_env[0]) 
-               canonical_display_name = ":0";
-           else
-             {
-               gchar *display_p, *screen_p;
-               canonical_display_name = g_strdup (display_env);
-               display_p = strrchr (canonical_display_name, ':');
-               screen_p = strrchr (canonical_display_name, '.');
-               if (screen_p && display_p && (screen_p > display_p))
-                 {
-                   *screen_p = '\0';
-                 }
-             }
-         }
-       else
-         {
-           canonical_display_name = display_env;
-         }
+        if (!display_env)
+          {
+            display_env = g_getenv ("DISPLAY");
+            if (!display_env || !display_env[0]) 
+                canonical_display_name = ":0";
+            else
+              {
+                gchar *display_p, *screen_p;
+                canonical_display_name = g_strdup (display_env);
+                display_p = strrchr (canonical_display_name, ':');
+                screen_p = strrchr (canonical_display_name, '.');
+                if (screen_p && display_p && (screen_p > display_p))
+                  {
+                    *screen_p = '\0';
+                  }
+              }
+          }
+        else
+          {
+            canonical_display_name = display_env;
+          }
       }
     return canonical_display_name;
 }
+#endif
 
-static     Display *bridge_display = NULL;
+/*---------------------------------------------------------------------------*/
 
+/*
+ * Gets the IOR from the XDisplay.
+ * Not currently used in D-Bus version, but something similar
+ * may be employed in the future for accessing the registry daemon
+ * bus name.
+ */
+#if 0
 static gchar *
 spi_atk_bridge_get_registry_ior (void)
 {
-     
      Atom AT_SPI_IOR;
      Atom actual_type;
      int actual_format;
@@ -359,124 +117,197 @@ spi_atk_bridge_get_registry_ior (void)
 
      AT_SPI_IOR = XInternAtom (bridge_display, "AT_SPI_IOR", False); 
      XGetWindowProperty(bridge_display, 
-                       XDefaultRootWindow (bridge_display),
-                       AT_SPI_IOR, 0L, 
-                       (long)BUFSIZ, False, 
-                       (Atom) 31, &actual_type, &actual_format,
-                       &nitems, &leftover, &data);
+                        XDefaultRootWindow (bridge_display),
+                        AT_SPI_IOR, 0L,
+                        (long)BUFSIZ, False,
+                        (Atom) 31, &actual_type, &actual_format,
+                        &nitems, &leftover, &data);
      if (data == NULL)
-         g_warning (_("AT_SPI_REGISTRY was not started at session startup."));
-     
+         g_warning (_("AT_SPI_REGISTRY was not started at session startup."));
      return (gchar *) data;
-     
 }
+#endif
 
-static const char *
-spi_atk_bridge_get_registry (void)
-{
-  // TODO: check for registry dying, as the old code attempted to do
-  return "org.freedesktop.atspi.registry";
-}
+/*---------------------------------------------------------------------------*/
 
-static const char *
-spi_atk_bridge_get_dec (void)
+static void
+register_application (SpiAppData *app)
 {
-  return "/dec";
-}
+  DBusMessage *message;
+  DBusMessageIter iter;
+  DBusError error;
+  const char *uname;
 
-int
-gtk_module_init (gint *argc, gchar **argv[])
-{
-       //printf("Pointer to argc %x %x\n", (short) ((argc && 0xffff0000) >> 16), (short) (argc && 0xffff));
-       return atk_bridge_init (argc, argv);
+  dbus_error_init (&error);
+
+  message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+                                          SPI_DBUS_PATH_REGISTRY,
+                                          SPI_DBUS_INTERFACE_REGISTRY,
+                                          "registerApplication");
+  dbus_message_set_no_reply (message, TRUE);
+
+  uname = dbus_bus_get_unique_name(app->droute.bus);
+
+  dbus_message_iter_init_append(message, &iter);
+  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uname);
+  dbus_connection_send (app->droute.bus, message, NULL);
+  if (message) dbus_message_unref (message);
 }
 
+/*---------------------------------------------------------------------------*/
+
 static void
 deregister_application (SpiAppData *app)
 {
-  const char *registry = spi_atk_bridge_get_registry ();
-  // todo: deregister
+  DBusMessage *message;
+  DBusMessageIter iter;
+  DBusError error;
+  const char *uname;
+
+  dbus_error_init (&error);
+
+  message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+                                          SPI_DBUS_PATH_REGISTRY,
+                                          SPI_DBUS_INTERFACE_REGISTRY,
+                                          "deregisterApplication");
+  dbus_message_set_no_reply (message, TRUE);
+
+  uname = dbus_bus_get_unique_name(app->droute.bus);
+
+  dbus_message_iter_init_append(message, &iter);
+  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uname);
+  dbus_connection_send (app->droute.bus, message, NULL);
+  if (message) dbus_message_unref (message);
 }
 
+/*---------------------------------------------------------------------------*/
+
 static void
-spi_atk_bridge_exit_func (void)
+exit_func (void)
 {
-  SpiAppData *app = (SpiAppData *) this_app;
-
-  DBG (1, g_message ("exiting bridge\n"));
-
-  if (!app)
+  if (!app_data)
     {
       return;
     }
-  if (atk_bridge_pid != getpid ())
-    {
-      _exit (0);
-    }
 
-  during_init_shutdown = TRUE;
-  exiting = TRUE;
-  /*
-   * Check whether we still have windows which have not been deleted.
-   */
   spi_atk_tidy_windows ();
-  /*
-   *  FIXME: this may be incorrect for apps that do their own bonobo
-   *  shutdown, until we can explicitly shutdown to get the ordering
-   *  right.
-   */
-  if (!registry_died)
-    deregister_application (this_app);
-  this_app = NULL;
-  DBG (1, g_message ("bridge exit func complete.\n"));
-
-  if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
-    {
-    }
+  spi_atk_deregister_event_listeners();
+  deregister_application (app_data);
+
+  g_free(app_data);
+  app_data = NULL;
+
+  /* Not currently creating an XDisplay */
+#if 0
   if (bridge_display)
     XCloseDisplay (bridge_display);
+#endif
 }
 
-void
-gnome_accessibility_module_init (void)
+/*---------------------------------------------------------------------------*/
+
+static DBusObjectPathVTable droute_vtable =
 {
-  atk_bridge_init (0, NULL);
+  NULL,
+  &droute_message,
+  NULL, NULL, NULL, NULL
+};
 
-  if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
-    {
-       g_print("Atk Accessibility bridge initialized\n");
-    }
-}
+static gchar *atspi_dbus_name;
+static gboolean atspi_no_register;
 
-void
-gnome_accessibility_module_shutdown (void)
+static GOptionEntry atspi_option_entries[] =
 {
-  int     i;
-  
-  if (!atk_bridge_initialized)
-    {
-      return;
-    }
-  during_init_shutdown = TRUE;
-  atk_bridge_initialized = FALSE;
+  {"atspi-dbus-name", 0, 0, G_OPTION_ARG_STRING, &atspi_dbus_name, "D-Bus bus name to register as", NULL},
+  {"atspi-no-register", 0, 0, G_OPTION_ARG_NONE, &atspi_no_register, "Do not register with Registry Daemon", NULL},
+  {NULL}
+};
 
-  if (g_getenv ("AT_BRIDGE_SHUTDOWN"))
-    {
-       g_print("Atk Accessibility bridge shutdown\n");
-    }
+/*
+ * spi_app_init
+ *
+ * The following needs to be initialized.
+ *
+ * - DRoute for routing message to their accessible objects.
+ * - Event handlers for emmitting signals on specific ATK events.
+ * - Application registration with the AT-SPI registry.
+ *
+ */
+static int
+adaptor_init (gint *argc, gchar **argv[])
+{
+  GOptionContext *opt;
+  GError *err = NULL;
+  DBusError error;
 
-  spi_atk_deregister_event_listeners();
+  if (app_data != NULL)
+     return 0;
+
+  /* Parse command line options */
+  opt = g_option_context_new(NULL);
+  g_option_context_add_main_entries(opt, atspi_option_entries, NULL);
+  g_option_context_set_ignore_unknown_options(opt, TRUE);
+  if (!g_option_context_parse(opt, argc, argv, &err))
+      g_warning("AT-SPI Option parsing failed: %s\n", err->message);
+
+  /* Allocate global data and do ATK initializations */
+  app_data = g_new0 (SpiAppData, 1);
+  atk_misc = atk_misc_get_instance ();
+
+  /* Get D-Bus connection, register D-Bus name*/
+  dbus_error_init (&error);
+  app_data->root = atk_get_root();
+  app_data->droute.bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+  if (!app_data->droute.bus)
+  {
+    g_warning ("AT-SPI Couldn't connect to D-Bus: %s\n", error.message);
+    g_free(app_data);
+    app_data = NULL;
+    return 0;
+  }
+  if (atspi_dbus_name != NULL &&
+      dbus_bus_request_name(app_data->droute.bus, atspi_dbus_name, 0, &error))
+  {
+    g_print("AT-SPI Recieved D-Bus name - %s\n", atspi_dbus_name);
+  }
 
-  deregister_application (this_app);
-  this_app = NULL;
+  /* Finish setting up D-Bus */
+  dbus_connection_setup_with_g_main(app_data->droute.bus, g_main_context_default());
 
-  misc = NULL;
+  /* Register droute for routing AT-SPI messages */
+  spi_register_tree_object(app_data->droute.bus, &app_data->droute, "/org/freedesktop/atspi/tree");
+
+  if (!dbus_connection_register_fallback (app_data->droute.bus,
+                                          "/org/freedesktop/atspi/accessible",
+                                          &droute_vtable,
+                                          &app_data->droute))
+  {
+    g_warning("AT-SPI Couldn't register droute.\n");
+    g_free(app_data);
+    app_data = NULL;
+    return 0;
+  }
+
+  /* Register all interfaces with droute and set up application accessible db */
+  atk_dbus_initialize (&app_data->droute);
+
+  /* Register methods to send D-Bus signals on certain ATK events */
+  spi_atk_register_event_listeners ();
+
+  /* Register this app by sending a signal out to AT-SPI registry daemon */
+  register_application (app_data);
+
+  g_atexit (exit_func);
+
+  return 0;
 }
 
-static void
-reinit_register_vars (void)
+/*---------------------------------------------------------------------------*/
+
+int
+gtk_module_init (gint *argc, gchar **argv[])
 {
-  registry = NULL;
-  device_event_controller = NULL;
-  this_app = NULL;
+  return adaptor_init (argc, argv);
 }
+
+/*END------------------------------------------------------------------------*/
index a4cbd9d..ddc3536 100644 (file)
@@ -28,7 +28,7 @@
 #include "bridge.h"
 #include "atk-dbus.h"
 
-extern SpiAppData *this_app;
+extern SpiAppData *app_data;
 
 static GArray *listener_ids = NULL;
 
@@ -61,7 +61,7 @@ Accessibility_DeviceEventController_notifyListenersSync(const Accessibility_Devi
   dbus_error_init(&error);
   if (spi_dbus_marshal_deviceEvent(message, key_event))
   {
-    DBusMessage *reply = dbus_connection_send_with_reply_and_block(this_app->droute.bus, message, 1000, &error);
+    DBusMessage *reply = dbus_connection_send_with_reply_and_block(app_data->droute.bus, message, 1000, &error);
     if (reply)
     {
       DBusError error;
@@ -226,7 +226,7 @@ emit(AtkObject  *accessible,
   dbus_message_iter_append_basic(&sub, (int) *type, &val);
   dbus_message_iter_close_container(&iter, &sub);
 
-  dbus_connection_send(this_app->droute.bus, sig, NULL);
+  dbus_connection_send(app_data->droute.bus, sig, NULL);
   dbus_message_unref(sig);
 }
 
@@ -279,7 +279,7 @@ emit_rect(AtkObject  *accessible,
     dbus_message_iter_close_container (&variant, &sub);
   dbus_message_iter_close_container (&iter, &variant);
 
-  dbus_connection_send(this_app->droute.bus, sig, NULL);
+  dbus_connection_send(app_data->droute.bus, sig, NULL);
 }
 
 /*---------------------------------------------------------------------------*/
index 00ec003..8652f77 100644 (file)
@@ -28,7 +28,7 @@
 #include "accessible.h"
 #include "bridge.h"
 
-extern SpiAppData *this_app;
+extern SpiAppData *app_data;
 static gboolean update_pending = FALSE;
 
 /*---------------------------------------------------------------------------*/
@@ -58,7 +58,7 @@ append_accessible(gpointer ref, gpointer obj_data, gpointer iter)
 
   obj = ATK_OBJECT(obj_data);
   iter_array = (DBusMessageIter *) iter;
-  data = &(this_app->droute);
+  data = &(app_data->droute);
 
   dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct);
     {
@@ -163,7 +163,7 @@ send_cache_update(gpointer d)
   DBusMessageIter iter_array;
   DRouteData *data;
 
-  data = &(this_app->droute);
+  data = &(app_data->droute);
 
   message = dbus_message_new_signal ("/org/freedesktop/atspi/tree", SPI_DBUS_INTERFACE_TREE, "updateTree");
 
index 8b2bde9..5729f71 100644 (file)
@@ -43,6 +43,20 @@ class _CacheData(object):
 
 #------------------------------------------------------------------------------
 
+def _list_items_added_removed (l1, l2):
+        """
+        Returns a tuple (boolean, boolean).
+        The first value indicates if, when
+        moving from l1 to l2, any items have been added.
+        The second value indicates whether any items have
+        been removed.
+        """
+        l1notl2 = [item for item in l1 if item not in l2]
+        l2notl1 = [item for item in l2 if item not in l1]
+        return ((len(l1notl2) > 0), (len(l2notl1) > 0))
+
+#------------------------------------------------------------------------------
+
 class AccessibleCache(object):
         """
         There is one accessible cache per application.
@@ -93,28 +107,17 @@ class AccessibleCache(object):
         def __contains__(self, key):
                 return key in self._objects
 
-        def _update_cache_dispatch_events(self, cachedata, data):
-                (path,
-                 parent,
-                 children,
-                 interfaces,
-                 name,
-                 role,
-                 description) = data
-
-                # TODO The 'self._registry._cache' statement makes me think
-                # I have serious modularization FAIL here. 
-
-                if name != cachedata.name:
+        def _dispatch_event(self, olddata, newdata):
+                if olddata.name != newdata.name:
                         event = _Event(self._registry._cache,
                                        path,
                                        self._bus_name,
                                        "org.freedesktop.atspi.Event.Object",
                                        "property-change",
-                                       ("name", 0, 0, name))
+                                       ("name", 0, 0, newdata.name))
                         self._registry._notifyNameChange(event)
 
-                if description != cachedata.description:
+                if olddata.description != newdata.description:
                         event = _Event(self._registry._cache,
                                        path,
                                        self._bus_name,
@@ -123,7 +126,7 @@ class AccessibleCache(object):
                                        ("description", 0, 0, description))
                         self._registry._notifyDescriptionChange(event)
 
-                if parent != cachedata.parent:
+                if olddata.parent != newdata.parent:
                         event = _Event(self._registry._cache,
                                        path,
                                        self._bus_name,
@@ -132,30 +135,44 @@ class AccessibleCache(object):
                                        ("parent", 0, 0, ""))
                         self._registry._notifyParentChange(event)
 
-                if children != cachedata.children:
+                added, removed = _list_items_added_removed (olddata.children, newdata.children):
+
+                if added:
                         event = _Event(self._registry._cache,
                                        path,
                                        self._bus_name,
                                        "org.freedesktop.atspi.Event.Object",
                                        "children-changed",
-                                       ("", 0, 0, ""))
+                                       ("add", 0, 0, ""))
                         self._registry._notifyChildrenChange(event)
 
-                cachedata._update(data)
+                if removed:
+                        event = _Event(self._registry._cache,
+                                       path,
+                                       self._bus_name,
+                                       "org.freedesktop.atspi.Event.Object",
+                                       "children-changed",
+                                       ("remove", 0, 0, ""))
+                        self._registry._notifyChildrenChange(event)
 
         def _update_handler(self, update, remove):
                 self._remove_objects(remove)
                 self._update_objects(update)
 
         def _update_objects(self, objects):
+                cache_update_objects = []
                 for data in objects:
                         #First element is the object path.
                         path = data[0]
                         if path in self._objects:
-                                cachedata = self._objects[path]
-                                self._update_cache_dispatch_events(cachedata, data)
+                                olddata = self._objects[path]
+                                newdata = _CacheData(data)
+                                cache_update_objects.append((olddata, newdata))
+                                self._objects[path] = newdata
                         else:
                                 self._objects[path] = _CacheData(data)
+                for old, new in cache_update_objects:
+                        self._dispatch_event(old, new)
 
         def _remove_objects(self, paths):
                 for path in paths:
index b6676d2..ada9dbb 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
+import dbus
+
 from accessiblecache import AccessibleCache
 from desktop import Desktop
 from factory import accessible_factory
+from event import Event as _Event
 
 import interfaces
 
 __all__ = [
-
+           "ApplicationCache",
            "TestApplicationCache",
           ]
 
@@ -92,4 +95,123 @@ class TestApplicationCache(object):
                 """
                 return self._connection
 
+#------------------------------------------------------------------------------
+
+class ApplicationCache(object):
+        """
+        Test application store, accesses a single application.
+
+        The store object acts as a central class for creating accessible objects.
+        It interfaces with the ATSPI registry to keep account of all accessible
+        applications. It contains the accessible cache objects from each application.
+
+        @registry:   Each accessible cache object must have a reference to the registry
+                     object to send update events.
+
+        @connection: D-Bus connection used to access applications.
+
+        @bus_name:   The test store only accesses one accessible application, this is its
+                     D-Bus path.
+        """
+
+        _REGISTRY_PATH = '/org/freedesktop/atspi/registry'
+        _REGISTRY_INTERFACE = 'org.freedesktop.atspi.Registry'
+        _REGISTRY_NAME = 'org.freedesktop.atspi.Registry'
+
+        # An accessible path of '/' implies the desktop object, whatever the application name.
+        _DESKTOP_PATH = '/'
+
+        _APPLICATIONS_ADD = 1
+        _APPLICATIONS_REMOVE = 0
+
+        def __init__(self, registry, connection):
+                self._connection = connection
+                self._registry = registry
+
+                self.application_list = []
+                self.application_cache = {}
+
+                self._regsig = connection.add_signal_receiver(self.update_handler,
+                                                              dbus_interface=ApplicationCache._REGISTRY_INTERFACE,
+                                                              signal_name="updateApplications")
+
+                obj = connection.get_object(ApplicationCache._REGISTRY_NAME,
+                                            ApplicationCache._REGISTRY_PATH,
+                                            introspect=False)
+                self._app_register = dbus.Interface(obj, ApplicationCache._REGISTRY_INTERFACE)
+
+                self.application_list.extend(self._app_register.getApplications())
+                for bus_name in self.application_list:
+                        self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
+
+        def update_handler (self, update_type, bus_name):
+                if update_type == ApplicationCache._APPLICATIONS_ADD:
+                        #TODO Check that app does not already exist
+                        self.application_list.append(bus_name)
+                        self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
+                        event = _Event(self,
+                                       ApplicationCache._DESKTOP_PATH,
+                                       ApplicationCache._REGISTRY_NAME,
+                                       "org.freedesktop.atspi.Event.Object",
+                                       "children-changed",
+                                       ("add", 0, 0, ""))
+                elif update_type == ApplicationCache._APPLICATIONS_REMOVE:
+                        #TODO Fail safely if app does not exist
+                        self.application_list.remove(bus_name)
+                        del(self.application_cache[bus_name])
+                        event = _Event(self,
+                                       ApplicationCache._DESKTOP_PATH,
+                                       ApplicationCache._REGISTRY_NAME,
+                                       "org.freedesktop.atspi.Event.Object",
+                                       "children-changed",
+                                       ("remove", 0, 0, ""))
+
+                self._registry._notifyChildrenChange(event)
+
+        def get_cache_data(self, app_name, acc_path):
+                """
+                Returns the cache tuple for the given application and accessible
+                object path. Throws an IndexError if the cache data is not found.
+                """
+                return self.application_cache[app_name][acc_path]
+
+        def create_application(self, app_name):
+                """
+                Creates an accessible object for the root of the application
+                available at the given D-Bus name.
+                """
+                if app_name == ApplicationCache._REGISTRY_NAME:
+                        return Desktop(self)
+                else:
+                        cls = accessible_factory.get_accessible_class(interfaces.ATSPI_APPLICATION)
+                        return cls(app_name, self.application_cache[app_name].root, self, interfaces.ATSPI_APPLICATION)
+
+        def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
+                """
+                Creates an accessible object.
+
+                @app_name: D-Bus name of the application where the accessible object resides.
+
+                @acc_path: D-Bus path of the object within the application.
+
+                @interface: D-Bus interface of the requested object. A different accessible object
+                            class will be created depending on this. Making the function much like 
+                            an accessible object factory.
+
+                @dbus_object: If a D-Bus object already exists for the accessible object it can be
+                              provided here so that another one is not created.
+                """
+                if acc_path == ApplicationCache._DESKTOP_PATH:
+                        return Desktop(self)
+                else:
+                        cls = accessible_factory.get_accessible_class(interface)
+                        return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
+
+        @property
+        def connection(self):
+                """
+                D-Bus connection used by the store.
+                """
+                return self._connection
+
 #END----------------------------------------------------------------------------
index a75cf92..0a2e0e2 100644 (file)
@@ -166,6 +166,12 @@ class Desktop(object):
                 self._app_name = ':'
                 self._acc_path = '/'
 
+        def __str__(self):
+                    try:
+                              return '[%s | %s]' % (self.getRoleName(), self.name)
+                    except Exception:
+                              return '[DEAD]'
+
         def __nonzero__(self):
                         return True
 
index 0c40fcf..477f932 100644 (file)
@@ -27,7 +27,7 @@ from base import Enum as _Enum
 from desktop import Desktop as _Desktop
 from event import EventType as _EventType
 from event import event_type_to_signal_reciever as _event_type_to_signal_reciever
-from applicationcache import TestApplicationCache
+from applicationcache import TestApplicationCache, ApplicationCache
 
 from dbus.mainloop.glib import DBusGMainLoop as _DBusGMainLoop
 _DBusGMainLoop(set_as_default=True)
@@ -123,8 +123,6 @@ class _Registry(object):
         @type observers: dictionary
         """
 
-        _REGISTRY_NAME = 'org.freedesktop.atspi.Registry'
-
         def __init__(self):
                 """
                 Stores a reference to the AT-SPI registry. Gets and stores a reference
@@ -141,6 +139,8 @@ class _Registry(object):
                 if app_name:
                         self._app_name = app_name
                         self._appcache = TestApplicationCache(self, self._bus, app_name)
+                else:
+                        self._appcache = ApplicationCache(self, self._bus)
 
                 self._event_listeners = {}
 
@@ -220,7 +220,7 @@ class _Registry(object):
         def _notifyParentChange(self, event):
                 self._callClients(self._parent_listeners, event)
 
-        def _notifyChildenChange(self, event):
+        def _notifyChildrenChange(self, event):
                 self._callClients(self._children_changed_listeners, event)
 
         def _registerFake(self, type, register, client, *names):
index b5610fe..240554d 100644 (file)
 
 #include "registry.h"
 
+enum
+{
+  REGISTRY_APPLICATION_REMOVE = 0,
+  REGISTRY_APPLICATION_ADD = 1
+};
+
 /*---------------------------------------------------------------------------*/
 
 G_DEFINE_TYPE(SpiRegistry, spi_registry, G_TYPE_OBJECT)
@@ -59,57 +65,38 @@ static void emit(SpiRegistry *reg, const char *itf, const char *name, int ftype,
 
 /*---------------------------------------------------------------------------*/
 
-static void
-add_bus_name_cb (gpointer item, gpointer data)
+static gint
+data_str_cmp (gpointer a, gpointer b, gpointer data)
 {
-  DBusMessageIter *iter_array = (DBusMessageIter *) data;
-
-  dbus_message_iter_append_basic (iter_array, DBUS_TYPE_STRING, (gchar **) &item);
+  return g_strcmp0(a, b);
 }
 
-static DBusMessage *
-impl_getApplications (DBusConnection *bus, DBusMessage *message, void *user_data)
+static gboolean
+seq_add_string (GSequence *seq, gchar *str)
 {
-  DBusMessage *reply;
-  DBusMessageIter iter, iter_array;
-  SpiRegistry *reg = SPI_REGISTRY (user_data);
-
-  reply = dbus_message_new_method_return (message);
-
-  dbus_message_iter_init_append (reply, &iter);
-  dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iter_array);
-  g_sequence_foreach (reg->apps, add_bus_name_cb, &iter_array);
-  dbus_message_iter_close_container(&iter, &iter_array);
-  return reply;
-}
+  GSequenceIter *iter;
+  gchar *item;
+  gboolean res = FALSE;
 
-static DBusHandlerResult
-message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
-{
-  DBusMessage *reply = NULL;
+  iter = g_sequence_search (seq, str, (GCompareDataFunc) data_str_cmp, NULL);
+  iter = g_sequence_iter_prev (iter);
 
-  if (dbus_message_is_method_call (message, SPI_DBUS_INTERFACE_REGISTRY, "getApplications"))
+  if (!g_sequence_iter_is_end (iter))
     {
-      reply = impl_getApplications (bus, message, user_data);
-      if (reply)
+      item = g_sequence_get (iter);
+      if (g_strcmp0 (item, str))
         {
-          dbus_connection_send (bus, reply, NULL);
-          dbus_message_unref (reply);
+          g_sequence_insert_sorted (seq, g_strdup(str), (GCompareDataFunc) data_str_cmp, NULL);
+          res = TRUE;
         }
-      return DBUS_HANDLER_RESULT_HANDLED;
     }
   else
     {
-      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      g_sequence_insert_sorted (seq, g_strdup(str), (GCompareDataFunc) data_str_cmp, NULL);
+      res = TRUE;
     }
-}
-
-/*---------------------------------------------------------------------------*/
 
-static gint
-data_str_cmp (gpointer a, gpointer b, gpointer data)
-{
-  return g_strcmp0(a, b);
+  return res;
 }
 
 static gboolean
@@ -135,75 +122,157 @@ seq_remove_string (GSequence *seq, gchar *str)
 }
 
 static void
-handle_register_application (SpiRegistry *reg, DBusMessage *message)
+add_application (DBusConnection *bus, SpiRegistry *reg, gchar *app)
+{
+  guint add = REGISTRY_APPLICATION_ADD;
+
+  if (seq_add_string (reg->apps, app))
+    {
+      emit (reg,
+            SPI_DBUS_INTERFACE_REGISTRY,
+            "updateApplications",
+            DBUS_TYPE_INT32,
+            &add,
+            DBUS_TYPE_STRING,
+            &app,
+            DBUS_TYPE_INVALID);
+    }
+}
+
+static void
+remove_application (DBusConnection *bus, SpiRegistry *reg, gchar *app)
+{
+  guint remove = REGISTRY_APPLICATION_REMOVE;
+
+  if (seq_remove_string (reg->apps, app))
+    {
+      /*TODO spi_remove_device_listeners (registry->de_controller, old);*/
+      emit (reg,
+            SPI_DBUS_INTERFACE_REGISTRY,
+            "updateApplications",
+            DBUS_TYPE_INT32,
+            &remove,
+            DBUS_TYPE_STRING,
+            &app,
+            DBUS_TYPE_INVALID);
+    }
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+add_bus_name_cb (gpointer item, gpointer data)
+{
+  DBusMessageIter *iter_array = (DBusMessageIter *) data;
+
+  dbus_message_iter_append_basic (iter_array, DBUS_TYPE_STRING, (gchar **) &item);
+}
+
+static DBusMessage *
+impl_getApplications (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+  DBusMessage *reply;
+  DBusMessageIter iter, iter_array;
+  SpiRegistry *reg = SPI_REGISTRY (user_data);
+
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+  dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iter_array);
+  g_sequence_foreach (reg->apps, add_bus_name_cb, &iter_array);
+  dbus_message_iter_close_container(&iter, &iter_array);
+  return reply;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+impl_registerApplication (DBusConnection *bus, DBusMessage *message, void *user_data)
 {
   gchar *app_name;
+  SpiRegistry *reg = SPI_REGISTRY (user_data);
 
   if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &app_name, DBUS_TYPE_INVALID))
-      g_sequence_insert_sorted (reg->apps, app_name, (GCompareDataFunc) data_str_cmp, NULL);
+      add_application(bus, reg, app_name);
 }
 
 static void
-handle_deregister_application (SpiRegistry *reg, DBusMessage *message)
+impl_deregisterApplication (DBusConnection *bus, DBusMessage *message, void *user_data)
 {
   gchar *app_name;
+  SpiRegistry *reg = SPI_REGISTRY (user_data);
 
   if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &app_name, DBUS_TYPE_INVALID))
-      seq_remove_string (reg->apps, app_name);
+      remove_application(bus, reg, app_name);
 }
 
+/*---------------------------------------------------------------------------*/
+
 static void
-handle_disconnection (SpiRegistry *reg, DBusMessage *message)
+handle_disconnection (DBusConnection *bus, DBusMessage *message, void *user_data)
 {
   char *name, *old, *new;
+  SpiRegistry *reg = SPI_REGISTRY (user_data);
 
   if (dbus_message_get_args (message, NULL,
                              DBUS_TYPE_STRING, &name,
                              DBUS_TYPE_STRING, &old,
                              DBUS_TYPE_STRING, &new,
                              DBUS_TYPE_INVALID))
-  {
-    if (*old != '\0' && *new == '\0')
     {
-      if (seq_remove_string (reg->apps, old))
+      if (*old != '\0' && *new == '\0')
         {
-          /*Emit deregistered signal here*/
-          emit (reg, SPI_DBUS_INTERFACE_TREE, "deregisterApplication", DBUS_TYPE_STRING, old);
-          /*TODO spi_remove_device_listeners (registry->de_controller, old);*/
+          remove_application(bus, reg, old);
         }
     }
-  }
 }
 
+/*---------------------------------------------------------------------------*/
+
 static DBusHandlerResult
-signal_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
+message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
 {
-  SpiRegistry *registry = SPI_REGISTRY (user_data);
+  DBusMessage *reply = NULL;
   guint res = DBUS_HANDLER_RESULT_HANDLED;
-  const char *iface = dbus_message_get_interface (message);
-  const char *member = dbus_message_get_member (message);
 
-  g_print ("\n%s", iface);
-  g_print ("\n%d", dbus_message_get_type (message));
-  g_print ("\n%s\n", member);
-
-#if 0
-  if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
-      handle_disconnection (registry, message);
-  else if (dbus_message_is_signal (message, SPI_DBUS_INTERFACE_TREE, "registerApplication"))
-      handle_register_application (registry, message);
-  else if (dbus_message_is_signal (message, SPI_DBUS_INTERFACE_TREE, "deregisterApplication"))
-      handle_deregister_application (registry, message);
+
+  int mtype;
+  const char *itf;
+  const char *name;
+
+  mtype = dbus_message_get_type (message);
+  itf = dbus_message_get_interface (message);
+  name = dbus_message_get_member (message);
+
+  if (dbus_message_is_method_call (message, SPI_DBUS_INTERFACE_REGISTRY, "getApplications"))
+      reply = impl_getApplications (bus, message, user_data);
+  else if (dbus_message_is_method_call (message, SPI_DBUS_INTERFACE_REGISTRY, "registerApplication"))
+      impl_registerApplication (bus, message, user_data);
+  else if (dbus_message_is_method_call (message, SPI_DBUS_INTERFACE_REGISTRY, "deregisterApplication"))
+      impl_deregisterApplication (bus, message, user_data);
   else
       res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-#endif
+
+  if (reply)
+    {
+      dbus_connection_send (bus, reply, NULL);
+      dbus_message_unref (reply);
+    }
+  return res;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+  SpiRegistry *registry = SPI_REGISTRY (user_data);
+  guint res = DBUS_HANDLER_RESULT_HANDLED;
+  const char *iface = dbus_message_get_interface (message);
+  const char *member = dbus_message_get_member (message);
 
   if (!g_strcmp0(iface, DBUS_INTERFACE_DBUS) && !g_strcmp0(member, "NameOwnerChanged"))
-      handle_disconnection (registry, message);
-  else if (!g_strcmp0(iface, SPI_DBUS_INTERFACE_TREE) && !g_strcmp0(member, "registerApplication"))
-      handle_register_application (registry, message);
-  else if (!g_strcmp0(iface, SPI_DBUS_INTERFACE_TREE) && !g_strcmp0(member, "deregisterApplication"))
-      handle_deregister_application (registry, message);
+      handle_disconnection (bus, message, user_data);
   else
       res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -212,10 +281,8 @@ signal_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
 
 /*---------------------------------------------------------------------------*/
 
-static gchar *app_reg_sig_match = "type='signal', interface='org.freedesktop.atspi.Tree', member='registerApplication'";
-static gchar *app_dereg_sig_match = "type='signal', interface='org.freedesktop.atspi.Tree', member='deregisterApplication'";
-
-static gchar *app_sig_match_blank = "";
+static gchar *app_sig_match_name_owner =
+       "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged'";
 
 static DBusObjectPathVTable reg_vtable =
 {
@@ -233,10 +300,10 @@ spi_registry_new (DBusConnection *bus)
 
   dbus_connection_register_object_path(bus, SPI_DBUS_PATH_REGISTRY, &reg_vtable, reg);
 
-  //dbus_bus_add_match (bus, app_reg_sig_match, NULL);
-  //dbus_bus_add_match (bus, app_dereg_sig_match, NULL);
-  dbus_bus_add_match (bus, app_sig_match_blank, NULL);
-  dbus_connection_add_filter (bus, signal_handler, reg, NULL);
+  dbus_bus_add_match (bus, app_sig_match_name_owner, NULL);
+  dbus_connection_add_filter (bus, signal_filter, reg, NULL);
 
   return reg;
 }
+
+/*END------------------------------------------------------------------------*/
index 2bb684f..86be32a 100644 (file)
@@ -9,18 +9,6 @@ from dbus.mainloop.glib import DBusGMainLoop
 
 DBusGMainLoop(set_as_default=True)
 
-class Emitter (dbus.service.Object):
-       def __init__(self, bus, object_path):
-               dbus.service.Object.__init__(self, bus, object_path)
-
-       @dbus.service.signal(dbus_interface='org.freedesktop.atspi.Tree', signature='s')
-       def registerApplication(self, app_name):
-               pass
-
-       @dbus.service.signal(dbus_interface='org.freedesktop.atspi.Tree', signature='s')
-       def deregisterApplication(self, app_name):
-               pass
-
 class IdleStateM (object):
        def __init__(self, bus, loop):
                self._bus = bus
@@ -34,14 +22,15 @@ class IdleStateM (object):
                return True
 
        def setup(self):
-               self.emit = Emitter(self._bus, "/org/freedesktop/atspi/tree")
-               self.obj = self._bus.get_object("org.freedesktop.atspi.Registry", "/org/freedesktop/atspi/registry")
+               self.obj = self._bus.get_object("org.freedesktop.atspi.Registry",
+                                                "/org/freedesktop/atspi/registry",
+                                                introspect=False)
                self.itf = dbus.Interface(self.obj, dbus_interface="org.freedesktop.atspi.Registry")
-               return self.emit_registers
+               return self.register_apps
 
-       def emit_registers(self):
-               self.emit.registerApplication(":R123")
-               self.emit.registerApplication(":R456")
+       def register_apps(self):
+               #self.itf.registerApplication(":R456", ignore_reply=True)
+               #self.itf.registerApplication(":R123", ignore_reply=True)
                return self.print_applications
 
        def print_applications(self):
index 550f810..487dd26 100644 (file)
@@ -93,7 +93,7 @@ load_atspi_module(const char *path, int *argc, char **argv[])
 
   bridge = g_module_open(path, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
   if (!bridge)
-    g_error("Couldn't load atk-bridge module : %s\n", path);
+    g_error("Couldn't load atk-bridge module : %s\n", g_module_error());
 
   if (!g_module_symbol(bridge, "gtk_module_init", &init))
     g_error("Couldn't load symbol \"gtk_module_init\"\n");
index 416a4f0..9abced1 100644 (file)
@@ -9,11 +9,11 @@
       interact with those applications.  </p>
 
     <p>The Registry service provides four basic functions to Assistive Technology (AT) clients:
-           <ol>
-                   <li>It provides a list of the applications who have registered with the
-                           AT-SPI framework, thereby announcing their participation in the AT-SPI framework.</li>
-                   <li>It gives access to system device events via the associated DeviceEventController interface.</li>
-           </ol>
+        <ol>
+            <li>It provides a list of the applications who have registered with the
+                AT-SPI framework, thereby announcing their participation in the AT-SPI framework.</li>
+            <li>It gives access to system device events via the associated DeviceEventController interface.</li>
+        </ol>
     </p>
 
     <p>From the point of view of accessible applications (i.e. AT-SPI service producers), 
       illustrating the relationship between applications, Registry, and AT is shown at:
       http://developer.gnome.org/projects/gap/tech-docs/SPIBlockDiagram.png  </p>
   </tp:docstring>
+
   <method name="getApplications">
     <tp:docstring>
-           Gets all the currently registered applications.
+        Gets all the currently registered applications.
     </tp:docstring>
     <arg direction="out" name="applications" type="as">
-       <tp:docstring>
-               A list of strings containing the D-Bus bus names of the applications.
-       </tp:docstring>
+        <tp:docstring>
+            A list of strings containing the D-Bus bus names of the applications.
+        </tp:docstring>
     </arg>
   </method>
+
+  <signal name="updateApplications">
+    <tp:docstring>
+        Updates an AT about recently added or removed applications.
+    </tp:docstring>
+    <arg direction="out" name="app" type="is">
+        <tp:docstring>
+                Unique bus name of the application that has been removed or added.
+                The integer is an enumeration:
+                           0 : The application has been removed.
+                           1 : The application has been added.
+        </tp:docstring>
+    </arg>
+  </signal>
+
+  <method name="registerApplication">
+    <tp:docstring>
+      Register a new application with the accessibility registry.
+   </tp:docstring>
+   <arg direction="in" name="app" type="s" tp:type="Application">
+      <tp:docstring>
+         D-Bus Bus name of the application that wishes to be made accessible.
+      </tp:docstring>
+   </arg>
+  </method>
+
+  <method name="deregisterApplication">
+   <tp:docstring>
+      De-register an application from accessibility registry.
+   </tp:docstring>
+   <arg direction="in" name="app" type="s" tp:type="Application">
+      <tp:docstring>
+         D-Bus Bus name of the application that wishes to be made accessible.
+      </tp:docstring>
+   </arg>
+  </method>
+
 </interface>
 </node>
index b6746cc..23ddb35 100644 (file)
                                </tp:docstring>
                        </arg>
                </signal>
-               <signal name="registerApplication">
-                       <tp:docstring>
-                               Register a new application with the accessibility registry.
-                       </tp:docstring>
-                       <arg direction="out" name="app" type="s" tp:type="Application">
-                               <tp:docstring>
-                                       D-Bus Bus name of the application that wishes to be made accessible.
-                               </tp:docstring>
-                       </arg>
-               </method>
-               <signal name="deregisterApplication">
-                       <tp:docstring>
-                               De-register an application from accessibility registry.
-                       </tp:docstring>
-                       <arg direction="out" name="app" type="s" tp:type="Application">
-                               <tp:docstring>
-                                       D-Bus Bus name of the application that wishes to be made accessible.
-                               </tp:docstring>
-                       </arg>
-               </method>
        </interface>
 </node>