From ce599c14d58a2f1728637dbcb319ef4969460006 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 15 Mar 2011 17:00:35 -0400 Subject: [PATCH] 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(-) create mode 100644 bus/README create mode 100644 bus/at-spi-bus-launcher.c delete mode 100644 bus/at-spi-dbus-bus.in create mode 100644 bus/org.a11y.Bus.service.in create mode 100644 registryd/libregistry-internals.c create mode 100644 registryd/libregistry-internals.h 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 @@ -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 @@ accessibility - - EXTERNAL 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 +#include +#include +#include +#include + +#include +#include +#include + +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[] = + "" + " " + " " + " " + " " + " " + ""; +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 + 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/at-spi-dbus-bus.in b/bus/at-spi-dbus-bus.in deleted file mode 100644 index af92d25..0000000 --- a/bus/at-spi-dbus-bus.in +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -prefix="@prefix@" -sysconfdir="@sysconfdir@" -dbusdaemon="@DBUS_DAEMON@" - -var=`gconftool-2 --get /desktop/gnome/interface/at-spi-corba` -if [ "$var" == "true" ]; then - exit 0 -fi - -address=`${dbusdaemon} --config-file=${sysconfdir}/at-spi2/accessibility.conf --print-address 1 --print-pid 2 2>$HOME/.at-spi-dbus-bus.pid` -xprop -root -f AT_SPI_BUS 8s -set AT_SPI_BUS ${address} 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 + +#include "libregistry-internals.h" +#include +#include +#include + +/* + * 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 +#include + +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; -- 2.7.4