[at-spi2-core] bus: Rewrite a11y bus management, don't fall back to session bus



commit ce599c14d58a2f1728637dbcb319ef4969460006
Author: Colin Walters <walters verbum org>
Date:   Tue Mar 15 17:00:35 2011 -0400

    bus: Rewrite a11y bus management, don't fall back to session bus
    
    First of all, there should *always* be an a11y bus; if I enable
    toolkit-accessibility, and apps pick that up but then libat-spi falls
    back to the session bus, that's broken.
    
    Fix this by rewriting the a11y bus launcher in C, making it a persistent
    session service, and giving it a DBus API (bus name: org.a11y.Bus).  It
    will start the bus process as a child dynamically; however if
    toolkit-accessibility is enabled, we start it on startup.  For more
    information, see the new file bus/README.
    
    Details:
    
    * Create a .service file so the session bus autostarts us if
      necessary
    * The .desktop file is changed to use --start-immediately
    * Remove the kill_accessibility_bus() hack in registryd; instead
      we chain at-spi-bus-launcher to the session bus lifecycle.
    * Change at-spi bus lookup to try both the new session bus API
      and the X11 root window property.
    * Create libregistry-internals.la which encapsulates a11y bus
      lookup logic, de-duplicating from atspi/ and registryd/.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=644851

 atspi/Makefile.am                 |    2 +
 atspi/atspi-misc.c                |   71 +-------
 bus/Makefile.am                   |   30 ++-
 bus/README                        |   10 +
 bus/accessibility.conf            |    2 -
 bus/at-spi-bus-launcher.c         |  395 +++++++++++++++++++++++++++++++++++++
 bus/at-spi-dbus-bus.desktop.in    |    2 +-
 bus/at-spi-dbus-bus.in            |   13 --
 bus/org.a11y.Bus.service.in       |    3 +
 configure.ac                      |    5 +-
 registryd/Makefile.am             |   10 +
 registryd/libregistry-internals.c |  176 ++++++++++++++++
 registryd/libregistry-internals.h |   35 ++++
 registryd/registry-main.c         |  132 +------------
 14 files changed, 660 insertions(+), 226 deletions(-)
---
diff --git a/atspi/Makefile.am b/atspi/Makefile.am
index 569c6ff..1a50538 100644
--- a/atspi/Makefile.am
+++ b/atspi/Makefile.am
@@ -4,10 +4,12 @@ libatspi_la_LDFLAGS = @LDFLAGS@ @LT_VERSION_INFO@ @LIBTOOL_EXPORT_OPTIONS@ -no-u
 
 libatspi_la_CFLAGS = $(DBUS_GLIB_CFLAGS) \
 		    $(DBIND_CFLAGS)     \
+		    -I$(top_srcdir)/registryd \
                     -I$(top_srcdir)
 
 libatspi_la_LIBADD = $(DBUS_GLIB_LIBS) \
 	$(X_LIBS) \
+	$(top_builddir)/registryd/libregistry-internals.la \
 	$(top_builddir)/dbind/libdbind.la
 
 libatspiincludedir = $(includedir)/at-spi-2.0/atspi
diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c
index 2adea05..a635272 100644
--- a/atspi/atspi-misc.c
+++ b/atspi/atspi-misc.c
@@ -29,6 +29,7 @@
  */
 
 #include "atspi-private.h"
+#include "libregistry-internals.h"
 #include "X11/Xlib.h"
 #include "dbus/dbus-glib.h"
 #include <stdio.h>
@@ -805,71 +806,6 @@ spi_display_name (void)
   return canonical_display_name;
 }
 
-/* TODO: Avoid having duplicate functions for this here and in at-spi2-atk */
-static DBusConnection *
-get_accessibility_bus ()
-{
-  Atom AT_SPI_BUS;
-  Atom actual_type;
-  Display *bridge_display;
-  int actual_format;
-  unsigned char *data = NULL;
-  unsigned long nitems;
-  unsigned long leftover;
-
-  DBusConnection *bus = NULL;
-  DBusError error;
-
-  bridge_display = XOpenDisplay (spi_display_name ());
-  if (!bridge_display)
-    {
-      g_warning (_("AT-SPI: Could not get the display\n"));
-      return NULL;
-    }
-
-  AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
-  XGetWindowProperty (bridge_display,
-                      XDefaultRootWindow (bridge_display),
-                      AT_SPI_BUS, 0L,
-                      (long) BUFSIZ, False,
-                      (Atom) 31, &actual_type, &actual_format,
-                      &nitems, &leftover, &data);
-  XCloseDisplay (bridge_display);
-
-  dbus_error_init (&error);
-
-  if (data == NULL)
-    {
-      g_warning
-        (_("AT-SPI: Accessibility bus not found - Using session bus.\n"));
-      bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
-      if (!bus)
-        {
-          g_warning (_("AT-SPI: Couldn't connect to bus: %s\n"), error.message);
-          return NULL;
-        }
-    }
-  else
-    {
-      bus = dbus_connection_open (data, &error);
-      if (!bus)
-        {
-          g_warning (_("AT-SPI: Couldn't connect to bus: %s\n"), error.message);
-          return NULL;
-        }
-      else
-        {
-          if (!dbus_bus_register (bus, &error))
-            {
-              g_warning (_("AT-SPI: Couldn't register with bus: %s\n"), error.message);
-              return NULL;
-            }
-        }
-    }
-
-  return bus;
-}
-
 /**
  * atspi_init:
  *
@@ -895,12 +831,9 @@ atspi_init (void)
   get_live_refs();
 
   dbus_error_init (&error);
-  bus = get_accessibility_bus ();
+  bus = _libregistry_get_a11y_bus ();
   if (!bus)
-  {
-    g_warning ("Couldn't get session bus");
     return 2;
-  }
   dbus_bus_register (bus, &error);
   dbus_connection_setup_with_g_main(bus, g_main_context_default());
   dbus_connection_add_filter (bus, atspi_dbus_filter, NULL, NULL);
diff --git a/bus/Makefile.am b/bus/Makefile.am
index 1f5a7d1..009d15a 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -1,20 +1,30 @@
+EXTRA_DIST=accessibility.conf
+CLEANFILES=
+
 busconfigdir = $(sysconfdir)/at-spi2
 busconfig_DATA = accessibility.conf
 
-atspidbusdir = $(libexecdir)
-atspidbus_SCRIPTS = at-spi-dbus-bus
+libexec_PROGRAMS = at-spi-bus-launcher
+at_spi_bus_launcher_SOURCES = at-spi-bus-launcher.c
+at_spi_bus_launcher_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \
+                               -DDBUS_DAEMON=\"$(DBUS_DAEMON)\"
+at_spi_bus_launcher_CFLAGS = $(GIO_CFLAGS)
+at_spi_bus_launcher_LDADD = $(GIO_LIBS) $(X_LIBS)
 
 default_sessiondir = $(sysconfdir)/xdg/autostart
 default_session_DATA = at-spi-dbus-bus.desktop
 
+substitutions = "s,@libexecdir[ ],$(libexecdir),"
 at-spi-dbus-bus.desktop: at-spi-dbus-bus.desktop.in
-	sed -e "s,@libexecdir[ ],$(libexecdir)," $< > $  tmp && mv $  tmp $@
+	sed -e$ $(substitutions)  $< > $  tmp && mv $  tmp $@
+EXTRA_DIST += at-spi-dbus-bus.desktop.in
+CLEANFILES += at-spi-dbus-bus.desktop
+
+dbusservicedir=$(datadir)/dbus-1/services
+dbusservice_DATA = org.a11y.Bus.service
 
-EXTRA_DIST= \
-	accessibility.conf \
-	at-spi-dbus-bus.in \
-	at-spi-dbus-bus.desktop.in
+org.a11y.Bus.service: org.a11y.Bus.service.in
+	sed -e $(substitutions) $< > $  tmp && mv $  tmp $@
+EXTRA_DIST += org.a11y.Bus.service.in
+CLEANFILES += org.a11y.Bus.service
 
-CLEANFILES= \
-	at-spi-dbus-bus.desktop \
-	at-spi-dbus-bus
diff --git a/bus/README b/bus/README
new file mode 100644
index 0000000..40b9ad6
--- /dev/null
+++ b/bus/README
@@ -0,0 +1,10 @@
+The a11y bus is accessed via two mechanisms:
+
+1) The DBus session bus, service "org.a11y.Bus", method "GetAddress")
+2) The X11 root window property AT_SPI_BUS
+
+If the "toolkit-accessibility" variable is set, the bus is launched
+immediately (and will be accessible immediately via the X11 property).
+Otherwise, it will be spawned dynamically.
+
+
diff --git a/bus/accessibility.conf b/bus/accessibility.conf
index d9703e0..b9367d0 100644
--- a/bus/accessibility.conf
+++ b/bus/accessibility.conf
@@ -3,8 +3,6 @@
 
   <type>accessibility</type>
 
-  <fork/>
-
   <standard_session_servicedirs/>
 
   <auth>EXTERNAL</auth>
diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c
new file mode 100644
index 0000000..37ad60f
--- /dev/null
+++ b/bus/at-spi-bus-launcher.c
@@ -0,0 +1,395 @@
+/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+ * 
+ * at-spi-bus-launcher: Manage the a11y bus as a child process 
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <gio/gio.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+typedef enum {
+  A11Y_BUS_STATE_IDLE = 0,
+  A11Y_BUS_STATE_READING_ADDRESS,
+  A11Y_BUS_STATE_RUNNING,
+  A11Y_BUS_STATE_ERROR
+} A11yBusState;
+
+typedef struct {
+  GMainLoop *loop;
+  gboolean launch_immediately;
+  GDBusConnection *session_bus;
+
+  A11yBusState state;
+  /* -1 == error, 0 == pending, > 0 == running */
+  int a11y_bus_pid;
+  char *a11y_bus_address;
+  int pipefd[2];
+  char *a11y_launch_error_message;
+} A11yBusLauncher;
+
+static A11yBusLauncher *_global_app = NULL;
+
+static const gchar introspection_xml[] =
+  "<node>"
+  "  <interface name='org.a11y.Bus'>"
+  "    <method name='GetAddress'>"
+  "      <arg type='s' name='address' direction='out'/>"
+  "    </method>"
+  "  </interface>"
+  "</node>";
+static GDBusNodeInfo *introspection_data = NULL;
+
+static void
+setup_bus_child (gpointer data)
+{
+  A11yBusLauncher *app = data;
+  (void) app;
+
+  close (app->pipefd[0]);
+  dup2 (app->pipefd[1], 3);
+  close (app->pipefd[1]);
+
+  /* On Linux, tell the bus process to exit if this process goes away */
+#ifdef __linux
+#include <sys/prctl.h>
+  prctl (PR_SET_PDEATHSIG, 15);
+#endif  
+}
+
+/**
+ * unix_read_all_fd_to_string:
+ *
+ * Read all data from a file descriptor to a C string buffer.
+ */
+static gboolean
+unix_read_all_fd_to_string (int      fd,
+                            char    *buf,
+                            ssize_t  max_bytes)
+{
+  ssize_t bytes_read;
+
+  while (max_bytes > 1 && (bytes_read = read (fd, buf, MAX (4096, max_bytes - 1))))
+    {
+      if (bytes_read < 0)
+        return FALSE;
+      buf += bytes_read;
+      max_bytes -= bytes_read;
+    }
+  *buf = '\0';
+  return TRUE;
+}
+
+static void
+on_bus_exited (GPid     pid,
+               gint     status,
+               gpointer data)
+{
+  A11yBusLauncher *app = data;
+  
+  app->a11y_bus_pid = -1;
+  app->state = A11Y_BUS_STATE_ERROR;
+  if (app->a11y_launch_error_message == NULL)
+    {
+      if (WIFEXITED (status))
+        app->a11y_launch_error_message = g_strdup_printf ("Bus exited with code %d", WEXITSTATUS (status));
+      else if (WIFSIGNALED (status))
+        app->a11y_launch_error_message = g_strdup_printf ("Bus killed by signal %d", WTERMSIG (status));
+      else if (WIFSTOPPED (status))
+        app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status));
+    }
+  g_main_loop_quit (app->loop);
+} 
+
+static void
+ensure_a11y_bus (A11yBusLauncher *app)
+{
+  GPid pid;
+  char *argv[] = { DBUS_DAEMON, NULL, "--nofork", "--print-address", "3", NULL };
+  char addr_buf[2048];
+  GError *error = NULL;
+
+  if (app->a11y_bus_pid != 0)
+    return;
+  
+  argv[1] = g_strdup_printf ("--config-file=%s/at-spi2/accessibility.conf", SYSCONFDIR);
+
+  if (pipe (app->pipefd) < 0)
+    g_error ("Failed to create pipe: %s", strerror (errno));
+  
+  if (!g_spawn_async (NULL,
+                      argv,
+                      NULL,
+                      G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                      setup_bus_child,
+                      app,
+                      &pid,
+                      &error))
+    {
+      app->a11y_bus_pid = -1;
+      app->a11y_launch_error_message = g_strdup (error->message);
+      g_clear_error (&error);
+      goto error;
+    }
+
+  close (app->pipefd[1]);
+  app->pipefd[1] = -1;
+
+  g_child_watch_add (pid, on_bus_exited, app);
+
+  app->state = A11Y_BUS_STATE_READING_ADDRESS;
+  app->a11y_bus_pid = pid;
+  g_debug ("Launched a11y bus, child is %ld", (long) pid);
+  if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf)))
+    {
+      app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno));
+      kill (app->a11y_bus_pid, SIGTERM);
+      goto error;
+    }
+  close (app->pipefd[0]);
+  app->pipefd[0] = -1;
+  app->state = A11Y_BUS_STATE_RUNNING;
+
+  /* Trim the trailing newline */
+  app->a11y_bus_address = g_strchomp (g_strdup (addr_buf));
+  g_debug ("a11y bus address: %s", app->a11y_bus_address);
+
+  {
+    Display *display = XOpenDisplay (NULL);
+    if (display)
+      {
+        Atom bus_address_atom = XInternAtom (display, "AT_SPI_BUS", False);
+        XChangeProperty (display,
+                         XDefaultRootWindow (display),
+                         bus_address_atom,
+                         XA_STRING, 8, PropModeReplace,
+                         (guchar *) app->a11y_bus_address, strlen (app->a11y_bus_address));
+      }
+    XFlush (display);
+    XCloseDisplay (display);
+  }
+
+  return;
+  
+ error:
+  close (app->pipefd[0]);
+  close (app->pipefd[1]);
+  app->state = A11Y_BUS_STATE_ERROR;
+}
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+  A11yBusLauncher *app = user_data;
+
+  if (g_strcmp0 (method_name, "GetAddress") == 0)
+    {
+      ensure_a11y_bus (app);
+      if (app->a11y_bus_pid > 0)
+        g_dbus_method_invocation_return_value (invocation,
+                                               g_variant_new ("(s)", app->a11y_bus_address));
+      else
+        g_dbus_method_invocation_return_dbus_error (invocation,
+                                                    "org.a11y.Bus.Error",
+                                                    app->a11y_launch_error_message);
+    }
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+  handle_method_call,
+  NULL,
+  NULL  /* handle_set_property */
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar     *name,
+                 gpointer         user_data)
+{
+  A11yBusLauncher *app = user_data;
+  GError *error;
+  guint registration_id;
+  
+  if (connection == NULL)
+    {
+      g_main_loop_quit (app->loop);
+      return;
+    }
+  app->session_bus = connection;
+
+  if (app->launch_immediately)
+    {
+      ensure_a11y_bus (app);
+      if (app->state == A11Y_BUS_STATE_ERROR)
+        {
+          g_main_loop_quit (app->loop);
+          return;
+        }
+    }
+
+  error = NULL;
+  registration_id = g_dbus_connection_register_object (connection,
+                                                       "/org/a11y/bus",
+                                                       introspection_data->interfaces[0],
+                                                       &interface_vtable,
+                                                       _global_app,
+                                                       NULL,
+                                                       &error);
+  if (registration_id == 0)
+    g_error ("%s", error->message);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar     *name,
+              gpointer         user_data)
+{
+  A11yBusLauncher *app = user_data;
+  if (app->session_bus == NULL
+      && connection == NULL
+      && app->a11y_launch_error_message == NULL)
+    app->a11y_launch_error_message = g_strdup ("Failed to connect to session bus");
+  g_main_loop_quit (app->loop);
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+  A11yBusLauncher *app = user_data;
+  (void) app;
+}
+
+static int sigterm_pipefd[2];
+
+static void
+sigterm_handler (int signum)
+{
+  write (sigterm_pipefd[1], "X", 1);
+}
+
+static gboolean
+on_sigterm_pipe (GIOChannel  *channel,
+                 GIOCondition condition,
+                 gpointer     data)
+{
+  A11yBusLauncher *app = data;
+  
+  g_main_loop_quit (app->loop);
+
+  return FALSE;
+}
+
+static void
+init_sigterm_handling (A11yBusLauncher *app)
+{
+  GIOChannel *sigterm_channel;
+
+  if (pipe (sigterm_pipefd) < 0)
+    g_error ("Failed to create pipe: %s", strerror (errno));
+  signal (SIGTERM, sigterm_handler);
+
+  sigterm_channel = g_io_channel_unix_new (sigterm_pipefd[0]);
+  g_io_add_watch (sigterm_channel,
+                  G_IO_IN | G_IO_ERR | G_IO_HUP,
+                  on_sigterm_pipe,
+                  app);
+}
+
+static gboolean
+is_a11y_using_corba (void)
+{
+  char *gconf_argv[] = { "gconftool-2", "--get", "/desktop/gnome/interface/at-spi-corba", NULL };
+  char *stdout = NULL;
+  int estatus;
+  gboolean result = FALSE;
+
+  if (!g_spawn_sync (NULL, gconf_argv, NULL,
+                     G_SPAWN_SEARCH_PATH, NULL, NULL, &stdout, NULL, &estatus, NULL))
+    goto out;
+  if (estatus != 0)
+    goto out;
+  if (g_str_has_prefix (stdout, "true"))
+    result = TRUE;
+ out:
+  g_free (stdout);
+  return result;
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  GError *error = NULL;
+  GMainLoop *loop;
+  GDBusConnection *session_bus;
+  int name_owner_id;
+
+  g_type_init ();
+
+  if (is_a11y_using_corba ())
+    return 0;
+
+  _global_app = g_slice_new0 (A11yBusLauncher);
+  _global_app->loop = g_main_loop_new (NULL, FALSE);
+  _global_app->launch_immediately = (argc == 2 && strcmp (argv[1], "--launch-immediately") == 0);
+
+  init_sigterm_handling (_global_app);
+
+  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+  g_assert (introspection_data != NULL);
+
+  name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                                  "org.a11y.Bus",
+                                  G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+                                  on_bus_acquired,
+                                  on_name_acquired,
+                                  on_name_lost,
+                                  _global_app,
+                                  NULL);
+
+  g_main_loop_run (_global_app->loop);
+
+  if (_global_app->a11y_bus_pid > 0)
+    kill (_global_app->a11y_bus_pid, SIGTERM);
+    
+  if (_global_app->a11y_launch_error_message)
+    {
+      g_printerr ("Failed to launch bus: %s", _global_app->a11y_launch_error_message);
+      return 1;
+    }
+  return 0;
+}
diff --git a/bus/at-spi-dbus-bus.desktop.in b/bus/at-spi-dbus-bus.desktop.in
index 8290478..0d25fda 100644
--- a/bus/at-spi-dbus-bus.desktop.in
+++ b/bus/at-spi-dbus-bus.desktop.in
@@ -1,7 +1,7 @@
 [Desktop Entry]
 Type=Application
 Name=AT SPI D-Bus Bus
-Exec= libexecdir@/at-spi-dbus-bus
+Exec= libexecdir@/at-spi-bus-launcher --launch-immediately
 OnlyShowIn=GNOME;
 NoDisplay=true
 AutostartCondition=GSETTINGS org.gnome.desktop.interface toolkit-accessibility
diff --git a/bus/org.a11y.Bus.service.in b/bus/org.a11y.Bus.service.in
new file mode 100644
index 0000000..60edc28
--- /dev/null
+++ b/bus/org.a11y.Bus.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.a11y.Bus
+Exec= libexecdir@/at-spi-bus-launcher
diff --git a/configure.ac b/configure.ac
index f5a581e..aee668c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,10 @@ PKG_CHECK_MODULES(GOBJ, [gobject-2.0 >= 2.0.0])
 AC_SUBST(GOBJ_LIBS)
 AC_SUBST(GOBJ_CFLAGS)
 
+PKG_CHECK_MODULES(GIO, [gio-2.0 >= 2.28])
+AC_SUBST(GIO_LIBS)
+AC_SUBST(GIO_CFLAGS)
+
 # --------------------------------------------------------------------
 # Find DL functionality
 
@@ -192,7 +196,6 @@ AC_CONFIG_FILES([Makefile po/Makefile.in
 dbind/dbind-config.h
 	atspi/Makefile
 	registryd/Makefile
-	bus/at-spi-dbus-bus
 	bus/Makefile
 doc/Makefile
 doc/libatspi/Makefile
diff --git a/registryd/Makefile.am b/registryd/Makefile.am
index b4f929f..0d6a651 100644
--- a/registryd/Makefile.am
+++ b/registryd/Makefile.am
@@ -1,4 +1,5 @@
 libexec_PROGRAMS = at-spi2-registryd
+noinst_LTLIBRARIES = libregistry-internals.la
 
 at_spi2_registryd_CFLAGS =	\
 	$(GLIB_CFLAGS)		\
@@ -8,7 +9,16 @@ at_spi2_registryd_CFLAGS =	\
 	-I$(top_srcdir)		\
 	-DATSPI_INTROSPECTION_PATH=\"$(pkgdatadir)/$(DEFAULT_ATSPI_INTROSPECTION_PATH)\"
 
+libregistry_internals_la_SOURCES = \
+	libregistry-internals.h \
+	libregistry-internals.c
+
+libregistry_internals_la_CFLAGS = $(DBUS_GLIB_CFLAGS)
+libregistry_internals_la_LIBADD = $(DBUS_GLIB_LIBS) $(X_LIBS)
+
+
 at_spi2_registryd_LDADD =	\
+	libregistry-internals.la \
 	$(GLIB_LIBS)		\
 	$(DBUS_GLIB_LIBS)	\
 	$(GOBJ_CFLAGS)		\
diff --git a/registryd/libregistry-internals.c b/registryd/libregistry-internals.c
new file mode 100644
index 0000000..722766c
--- /dev/null
+++ b/registryd/libregistry-internals.c
@@ -0,0 +1,176 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "libregistry-internals.h"
+#include <X11/Xlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Returns a 'canonicalized' value for DISPLAY,
+ * with the screen number stripped off if present.
+ *
+ */
+static const gchar*
+spi_display_name (void)
+{
+    static const char *canonical_display_name = NULL;
+    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;
+          }
+      }
+    return canonical_display_name;
+}
+
+/*
+ * Gets the IOR from the XDisplay.
+ */
+static char *
+get_accessibility_bus_address_x11 (void)
+{
+  Atom AT_SPI_BUS;
+  Atom actual_type;
+  Display *bridge_display;
+  int actual_format;
+  unsigned char *data = NULL;
+  unsigned long nitems;
+  unsigned long leftover;
+
+  bridge_display = XOpenDisplay (spi_display_name ());
+  if (!bridge_display)
+    {
+      g_warning ("Could not open X display");
+      return NULL;
+    }
+      
+  AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
+  XGetWindowProperty (bridge_display,
+		      XDefaultRootWindow (bridge_display),
+		      AT_SPI_BUS, 0L,
+		      (long) BUFSIZ, False,
+		      (Atom) 31, &actual_type, &actual_format,
+		      &nitems, &leftover, &data);
+  XCloseDisplay (bridge_display);
+
+  return g_strdup (data);
+}
+
+static char *
+get_accessibility_bus_address_dbus (void)
+{
+  DBusConnection *session_bus = NULL;
+  DBusMessage *message;
+  DBusMessage *reply;
+  char *address = NULL;
+
+  session_bus = dbus_bus_get (DBUS_BUS_SESSION, NULL);
+  if (!session_bus)
+    return NULL;
+
+  message = dbus_message_new_method_call ("org.a11y.Bus",
+					  "/org/a11y/bus",
+					  "org.a11y.Bus",
+					  "GetAddress");
+
+  reply = dbus_connection_send_with_reply_and_block (session_bus,
+						     message,
+						     -1,
+						     NULL);
+  dbus_message_unref (message);
+
+  if (!reply)
+    return NULL;
+  
+  {
+    const char *tmp_address;
+    if (!dbus_message_get_args (reply,
+				NULL,
+				DBUS_TYPE_STRING,
+				&tmp_address,
+				DBUS_TYPE_INVALID))
+      {
+	dbus_message_unref (reply);
+	return NULL;
+      }
+    address = g_strdup (tmp_address);
+    dbus_message_unref (reply);
+  }
+  
+  return address;
+}
+
+DBusConnection *
+_libregistry_get_a11y_bus (void)
+{
+  DBusConnection *bus = NULL;
+  DBusError error;
+  char *address;
+
+  address = get_accessibility_bus_address_x11 ();
+  if (!address)
+    address = get_accessibility_bus_address_dbus ();
+  if (!address)
+    return NULL;
+
+  dbus_error_init (&error);
+  bus = dbus_connection_open (address, &error);
+  if (!bus)
+    {
+      g_warning ("Couldn't connect to accessibility bus: %s", error.message);
+      return NULL;
+    }
+  else
+    {
+      if (!dbus_bus_register (bus, &error))
+	{
+	  g_warning ("Couldn't register with accessibility bus: %s", error.message);
+	  return NULL;
+	}
+    }
+  
+  return bus;
+}
diff --git a/registryd/libregistry-internals.h b/registryd/libregistry-internals.h
new file mode 100644
index 0000000..66184f8
--- /dev/null
+++ b/registryd/libregistry-internals.h
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LIBREGISTRY_INTERNALS_H__
+#define __LIBREGISTRY_INTERNALS_H__ 
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+DBusConnection *_libregistry_get_a11y_bus (void);
+
+G_END_DECLS
+
+#endif /* __LIBREGISTRY_INTERNALS_H__ */
diff --git a/registryd/registry-main.c b/registryd/registry-main.c
index 083de19..d35475b 100644
--- a/registryd/registry-main.c
+++ b/registryd/registry-main.c
@@ -34,6 +34,7 @@
 #include "paths.h"
 #include "registry.h"
 #include "deviceeventcontroller.h"
+#include "libregistry-internals.h"
 
 #define CORBA_GCONF_KEY  "/desktop/gnome/interface/at-spi-corba"
 
@@ -88,36 +89,8 @@ session_manager_connect (void)
 }
 
 static void
-kill_accessibility_bus ()
-{
-  FILE *fp;
-  const char *home;
-  char *name;
-  int pid;
-
-  home = getenv ("HOME");
-  if (!home)
-    return;
-  name = g_strconcat (home, "/", ".atspi-dbus-bus.pid", NULL);
-  if (!name)
-    return;
-
-  fp = fopen (name, "r");
-  if (fp)
-  {
-    if (fscanf (fp, "%d", &pid) == 1)
-    {
-      kill (&pid, SIGTERM);
-    }
-    fclose (fp);
-  }
-  g_free (name);
-}
-
-static void
 stop_cb (gpointer data)
 {
-        kill_accessibility_bus ();
         g_main_loop_quit (mainloop);
 }
 
@@ -151,7 +124,6 @@ query_end_session_cb (guint flags, gpointer data)
 static void
 end_session_cb (guint flags, gpointer data)
 {
-        kill_accessibility_bus ();
         end_session_response (TRUE, NULL);
         g_main_loop_quit (mainloop);
 }
@@ -205,105 +177,6 @@ register_client (void)
 
 /*---------------------------------------------------------------------------*/
 
-/*
- * Returns a 'canonicalized' value for DISPLAY,
- * with the screen number stripped off if present.
- *
- */
-static const gchar*
-spi_display_name (void)
-{
-    static const char *canonical_display_name = NULL;
-    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;
-          }
-      }
-    return canonical_display_name;
-}
-
-/*---------------------------------------------------------------------------*/
-
-/*
- * 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.
- */
-
-static DBusConnection *
-spi_get_bus (void)
-{
-     Atom AT_SPI_BUS;
-     Atom actual_type;
-     Display *bridge_display;
-     int actual_format;
-     unsigned char *data = NULL;  
-     unsigned long nitems;
-     unsigned long leftover;
-
-     DBusConnection *bus = NULL;
-     DBusError       error;
-
-     bridge_display = XOpenDisplay (spi_display_name ());
-     if (!bridge_display)
-	g_error ("AT_SPI: Could not get the display");
-
-     AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", FALSE); 
-     XGetWindowProperty(bridge_display, 
-                        XDefaultRootWindow (bridge_display),
-                        AT_SPI_BUS, 0L,
-                        (long)BUFSIZ, False,
-                        (Atom) 31, &actual_type, &actual_format,
-                        &nitems, &leftover, &data);
-
-     dbus_error_init (&error);
-
-     if (data == NULL)
-     {
-         g_warning ("AT-SPI: Accessibility bus bus not found - Using session bus.\n");
-         bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
-         if (!bus)
-             g_error ("AT-SPI: Couldn't connect to bus: %s\n", error.message);
-     }
-     else
-     {
-	 bus = dbus_connection_open (data, &error);
-	 XFree (data);
-         if (!bus)
-         {
-             g_error ("AT-SPI: Couldn't connect to bus: %s\n", error.message);
-         }
-	 else
-         {
-	     if (!dbus_bus_register (bus, &error))
-	         g_error ("AT-SPI: Couldn't register with bus: %s\n", error.message);
-         } 
-     }
-
-  XCloseDisplay (bridge_display);
-     return bus;
-}
 
 /*---------------------------------------------------------------------------*/
 
@@ -340,8 +213,7 @@ main (int argc, char **argv)
       dbus_name = SPI_DBUS_NAME_REGISTRY;
 
   dbus_error_init (&error);
-  bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
-  bus = spi_get_bus ();
+  bus = _libregistry_get_a11y_bus ();
   if (!bus)
   {
     return 0;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]