54aa07f428192a3042201fa62503e2f09192900a
[platform/upstream/at-spi2-core.git] / bus / at-spi-bus-launcher.c
1 /* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * 
3  * at-spi-bus-launcher: Manage the a11y bus as a child process 
4  *
5  * Copyright 2011 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24
25 #include <unistd.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <stdio.h>
31
32 #include <gio/gio.h>
33 #ifdef HAVE_X11
34 #include <X11/Xlib.h>
35 #include <X11/Xatom.h>
36 #endif
37
38 typedef enum {
39   A11Y_BUS_STATE_IDLE = 0,
40   A11Y_BUS_STATE_READING_ADDRESS,
41   A11Y_BUS_STATE_RUNNING,
42   A11Y_BUS_STATE_ERROR
43 } A11yBusState;
44
45 typedef struct {
46   GMainLoop *loop;
47   gboolean launch_immediately;
48   gboolean a11y_enabled;
49   gboolean screen_reader_enabled;
50   GDBusConnection *session_bus;
51   GSettings *a11y_schema;
52   GSettings *interface_schema;
53
54   GDBusProxy *client_proxy;
55
56   A11yBusState state;
57   /* -1 == error, 0 == pending, > 0 == running */
58   int a11y_bus_pid;
59   char *a11y_bus_address;
60   int pipefd[2];
61   char *a11y_launch_error_message;
62 } A11yBusLauncher;
63
64 static A11yBusLauncher *_global_app = NULL;
65
66 static const gchar introspection_xml[] =
67   "<node>"
68   "  <interface name='org.a11y.Bus'>"
69   "    <method name='GetAddress'>"
70   "      <arg type='s' name='address' direction='out'/>"
71   "    </method>"
72   "  </interface>"
73   "<interface name='org.a11y.Status'>"
74   "<property name='IsEnabled' type='b' access='readwrite'/>"
75   "<property name='ScreenReaderEnabled' type='b' access='readwrite'/>"
76   "</interface>"
77   "</node>";
78 static GDBusNodeInfo *introspection_data = NULL;
79
80 static void
81 respond_to_end_session (GDBusProxy *proxy)
82 {
83   GVariant *parameters;
84
85   parameters = g_variant_new ("(bs)", TRUE, "");
86
87   g_dbus_proxy_call (proxy,
88                      "EndSessionResponse", parameters,
89                      G_DBUS_CALL_FLAGS_NONE,
90                      -1, NULL, NULL, NULL);
91 }
92
93 static void
94 g_signal_cb (GDBusProxy *proxy,
95              gchar      *sender_name,
96              gchar      *signal_name,
97              GVariant   *parameters,
98              gpointer    user_data)
99 {
100   A11yBusLauncher *app = user_data;
101
102   if (g_strcmp0 (signal_name, "QueryEndSession") == 0)
103     respond_to_end_session (proxy);
104   else if (g_strcmp0 (signal_name, "EndSession") == 0)
105     respond_to_end_session (proxy);
106   else if (g_strcmp0 (signal_name, "Stop") == 0)
107     g_main_loop_quit (app->loop);
108 }
109
110 static void
111 client_proxy_ready_cb (GObject      *source_object,
112                        GAsyncResult *res,
113                        gpointer      user_data)
114 {
115   A11yBusLauncher *app = user_data;
116   GError *error = NULL;
117
118   app->client_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
119
120   if (error != NULL)
121     {
122       g_warning ("Failed to get a client proxy: %s", error->message);
123       g_error_free (error);
124
125       return;
126     }
127
128   g_signal_connect (app->client_proxy, "g-signal",
129                     G_CALLBACK (g_signal_cb), app);
130 }
131
132 static void
133 register_client (A11yBusLauncher *app)
134 {
135   GDBusProxyFlags flags;
136   GDBusProxy *sm_proxy;
137   GError *error;
138   const gchar *app_id;
139   const gchar *autostart_id;
140   gchar *client_startup_id;
141   GVariant *parameters;
142   GVariant *variant;
143   gchar *object_path;
144
145   flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
146           G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS;
147
148   error = NULL;
149   sm_proxy = g_dbus_proxy_new_sync (app->session_bus, flags, NULL,
150                                     "org.gnome.SessionManager",
151                                     "/org/gnome/SessionManager",
152                                     "org.gnome.SessionManager",
153                                     NULL, &error);
154
155   if (error != NULL)
156     {
157       g_warning ("Failed to get session manager proxy: %s", error->message);
158       g_error_free (error);
159
160       return;
161     }
162
163   app_id = "at-spi-bus-launcher";
164   autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
165
166   if (autostart_id != NULL)
167     {
168       client_startup_id = g_strdup (autostart_id);
169       g_unsetenv ("DESKTOP_AUTOSTART_ID");
170     }
171   else
172     {
173       client_startup_id = g_strdup ("");
174     }
175
176   parameters = g_variant_new ("(ss)", app_id, client_startup_id);
177   g_free (client_startup_id);
178
179   error = NULL;
180   variant = g_dbus_proxy_call_sync (sm_proxy,
181                                     "RegisterClient", parameters,
182                                     G_DBUS_CALL_FLAGS_NONE,
183                                     -1, NULL, &error);
184
185   g_object_unref (sm_proxy);
186
187   if (error != NULL)
188     {
189       g_warning ("Failed to register client: %s", error->message);
190       g_error_free (error);
191
192       return;
193     }
194
195   g_variant_get (variant, "(o)", &object_path);
196   g_variant_unref (variant);
197
198   flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
199   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, flags, NULL,
200                             "org.gnome.SessionManager", object_path,
201                             "org.gnome.SessionManager.ClientPrivate",
202                             NULL, client_proxy_ready_cb, app);
203
204   g_free (object_path);
205 }
206
207 static void
208 setup_bus_child (gpointer data)
209 {
210   A11yBusLauncher *app = data;
211   (void) app;
212
213   close (app->pipefd[0]);
214   dup2 (app->pipefd[1], 3);
215   close (app->pipefd[1]);
216
217   /* On Linux, tell the bus process to exit if this process goes away */
218 #ifdef __linux
219 #include <sys/prctl.h>
220   prctl (PR_SET_PDEATHSIG, 15);
221 #endif  
222 }
223
224 /**
225  * unix_read_all_fd_to_string:
226  *
227  * Read all data from a file descriptor to a C string buffer.
228  */
229 static gboolean
230 unix_read_all_fd_to_string (int      fd,
231                             char    *buf,
232                             ssize_t  max_bytes)
233 {
234   ssize_t bytes_read;
235
236   while (max_bytes > 1 && (bytes_read = read (fd, buf, MAX (4096, max_bytes - 1))))
237     {
238       if (bytes_read < 0)
239         return FALSE;
240       buf += bytes_read;
241       max_bytes -= bytes_read;
242     }
243   *buf = '\0';
244   return TRUE;
245 }
246
247 static void
248 on_bus_exited (GPid     pid,
249                gint     status,
250                gpointer data)
251 {
252   A11yBusLauncher *app = data;
253   
254   app->a11y_bus_pid = -1;
255   app->state = A11Y_BUS_STATE_ERROR;
256   if (app->a11y_launch_error_message == NULL)
257     {
258       if (WIFEXITED (status))
259         app->a11y_launch_error_message = g_strdup_printf ("Bus exited with code %d", WEXITSTATUS (status));
260       else if (WIFSIGNALED (status))
261         app->a11y_launch_error_message = g_strdup_printf ("Bus killed by signal %d", WTERMSIG (status));
262       else if (WIFSTOPPED (status))
263         app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status));
264     }
265   g_main_loop_quit (app->loop);
266
267
268 static gboolean
269 ensure_a11y_bus (A11yBusLauncher *app)
270 {
271   GPid pid;
272   char *argv[] = { DBUS_DAEMON, NULL, "--nofork", "--print-address", "3", NULL };
273   char addr_buf[2048];
274   GError *error = NULL;
275   const char *config_path = NULL;
276
277   if (app->a11y_bus_pid != 0)
278     return FALSE;
279
280   if (g_file_test (SYSCONFDIR"/at-spi2/accessibility.conf", G_FILE_TEST_EXISTS))
281       config_path = "--config-file="SYSCONFDIR"/at-spi2/accessibility.conf";
282   else
283       config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf";
284
285   argv[1] = config_path;
286
287   if (pipe (app->pipefd) < 0)
288     g_error ("Failed to create pipe: %s", strerror (errno));
289   
290   if (!g_spawn_async (NULL,
291                       argv,
292                       NULL,
293                       G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
294                       setup_bus_child,
295                       app,
296                       &pid,
297                       &error))
298     {
299       app->a11y_bus_pid = -1;
300       app->a11y_launch_error_message = g_strdup (error->message);
301       g_clear_error (&error);
302       goto error;
303     }
304
305   close (app->pipefd[1]);
306   app->pipefd[1] = -1;
307
308   g_child_watch_add (pid, on_bus_exited, app);
309
310   app->state = A11Y_BUS_STATE_READING_ADDRESS;
311   app->a11y_bus_pid = pid;
312   g_debug ("Launched a11y bus, child is %ld", (long) pid);
313   if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf)))
314     {
315       app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno));
316       kill (app->a11y_bus_pid, SIGTERM);
317       goto error;
318     }
319   close (app->pipefd[0]);
320   app->pipefd[0] = -1;
321   app->state = A11Y_BUS_STATE_RUNNING;
322
323   /* Trim the trailing newline */
324   app->a11y_bus_address = g_strchomp (g_strdup (addr_buf));
325   g_debug ("a11y bus address: %s", app->a11y_bus_address);
326
327 #ifdef HAVE_X11
328   {
329     Display *display = XOpenDisplay (NULL);
330     if (display)
331       {
332         Atom bus_address_atom = XInternAtom (display, "AT_SPI_BUS", False);
333         XChangeProperty (display,
334                          XDefaultRootWindow (display),
335                          bus_address_atom,
336                          XA_STRING, 8, PropModeReplace,
337                          (guchar *) app->a11y_bus_address, strlen (app->a11y_bus_address));
338         XFlush (display);
339         XCloseDisplay (display);
340       }
341   }
342 #endif
343
344   return TRUE;
345   
346  error:
347   close (app->pipefd[0]);
348   close (app->pipefd[1]);
349   app->state = A11Y_BUS_STATE_ERROR;
350
351   return FALSE;
352 }
353
354 static void
355 handle_method_call (GDBusConnection       *connection,
356                     const gchar           *sender,
357                     const gchar           *object_path,
358                     const gchar           *interface_name,
359                     const gchar           *method_name,
360                     GVariant              *parameters,
361                     GDBusMethodInvocation *invocation,
362                     gpointer               user_data)
363 {
364   A11yBusLauncher *app = user_data;
365
366   if (g_strcmp0 (method_name, "GetAddress") == 0)
367     {
368       ensure_a11y_bus (app);
369       if (app->a11y_bus_pid > 0)
370         g_dbus_method_invocation_return_value (invocation,
371                                                g_variant_new ("(s)", app->a11y_bus_address));
372       else
373         g_dbus_method_invocation_return_dbus_error (invocation,
374                                                     "org.a11y.Bus.Error",
375                                                     app->a11y_launch_error_message);
376     }
377 }
378
379 static GVariant *
380 handle_get_property  (GDBusConnection       *connection,
381                       const gchar           *sender,
382                       const gchar           *object_path,
383                       const gchar           *interface_name,
384                       const gchar           *property_name,
385                     GError **error,
386                     gpointer               user_data)
387 {
388   A11yBusLauncher *app = user_data;
389
390   if (g_strcmp0 (property_name, "IsEnabled") == 0)
391     return g_variant_new ("b", app->a11y_enabled);
392   else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0)
393     return g_variant_new ("b", app->screen_reader_enabled);
394   else
395     return NULL;
396 }
397
398 static void
399 handle_a11y_enabled_change (A11yBusLauncher *app, gboolean enabled,
400                                gboolean notify_gsettings)
401 {
402   GVariantBuilder builder;
403   GVariantBuilder invalidated_builder;
404
405   if (enabled == app->a11y_enabled)
406     return;
407
408   app->a11y_enabled = enabled;
409
410   if (notify_gsettings && app->interface_schema)
411     {
412       g_settings_set_boolean (app->interface_schema, "toolkit-accessibility",
413                               enabled);
414       g_settings_sync ();
415     }
416
417   g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
418   g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
419   g_variant_builder_add (&builder, "{sv}", "IsEnabled",
420                          g_variant_new_boolean (enabled));
421
422   g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus",
423                                  "org.freedesktop.DBus.Properties",
424                                  "PropertiesChanged",
425                                  g_variant_new ("(sa{sv}as)", "org.a11y.Status",
426                                                 &builder,
427                                                 &invalidated_builder),
428                                  NULL);
429 }
430
431 static void
432 handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled,
433                                gboolean notify_gsettings)
434 {
435   GVariantBuilder builder;
436   GVariantBuilder invalidated_builder;
437
438   if (enabled == app->screen_reader_enabled)
439     return;
440
441   /* If the screen reader is being enabled, we should enable accessibility
442    * if it isn't enabled already */
443   if (enabled)
444     handle_a11y_enabled_change (app, enabled, notify_gsettings);
445
446   app->screen_reader_enabled = enabled;
447
448   if (notify_gsettings && app->a11y_schema)
449     {
450       g_settings_set_boolean (app->a11y_schema, "screen-reader-enabled",
451                               enabled);
452       g_settings_sync ();
453     }
454
455   g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
456   g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
457   g_variant_builder_add (&builder, "{sv}", "ScreenReaderEnabled",
458                          g_variant_new_boolean (enabled));
459
460   g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus",
461                                  "org.freedesktop.DBus.Properties",
462                                  "PropertiesChanged",
463                                  g_variant_new ("(sa{sv}as)", "org.a11y.Status",
464                                                 &builder,
465                                                 &invalidated_builder),
466                                  NULL);
467 }
468
469 static gboolean
470 handle_set_property  (GDBusConnection       *connection,
471                       const gchar           *sender,
472                       const gchar           *object_path,
473                       const gchar           *interface_name,
474                       const gchar           *property_name,
475                       GVariant *value,
476                     GError **error,
477                     gpointer               user_data)
478 {
479   A11yBusLauncher *app = user_data;
480   const gchar *type = g_variant_get_type_string (value);
481   gboolean enabled;
482   
483   if (g_strcmp0 (type, "b") != 0)
484     {
485       g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
486                        "org.a11y.Status.%s expects a boolean but got %s", property_name, type);
487       return FALSE;
488     }
489
490   enabled = g_variant_get_boolean (value);
491
492   if (g_strcmp0 (property_name, "IsEnabled") == 0)
493     {
494       handle_a11y_enabled_change (app, enabled, TRUE);
495       return TRUE;
496     }
497   else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0)
498     {
499       handle_screen_reader_enabled_change (app, enabled, TRUE);
500       return TRUE;
501     }
502   else
503     {
504       g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
505                        "Unknown property '%s'", property_name);
506       return FALSE;
507     }
508 }
509
510 static const GDBusInterfaceVTable bus_vtable =
511 {
512   handle_method_call,
513   NULL, /* handle_get_property, */
514   NULL  /* handle_set_property */
515 };
516
517 static const GDBusInterfaceVTable status_vtable =
518 {
519   NULL, /* handle_method_call */
520   handle_get_property,
521   handle_set_property
522 };
523
524 static void
525 on_bus_acquired (GDBusConnection *connection,
526                  const gchar     *name,
527                  gpointer         user_data)
528 {
529   A11yBusLauncher *app = user_data;
530   GError *error;
531   guint registration_id;
532   
533   if (connection == NULL)
534     {
535       g_main_loop_quit (app->loop);
536       return;
537     }
538   app->session_bus = connection;
539
540   if (app->launch_immediately)
541     {
542       ensure_a11y_bus (app);
543       if (app->state == A11Y_BUS_STATE_ERROR)
544         {
545           g_main_loop_quit (app->loop);
546           return;
547         }
548     }
549
550   error = NULL;
551   registration_id = g_dbus_connection_register_object (connection,
552                                                        "/org/a11y/bus",
553                                                        introspection_data->interfaces[0],
554                                                        &bus_vtable,
555                                                        _global_app,
556                                                        NULL,
557                                                        &error);
558   if (registration_id == 0)
559     {
560       g_error ("%s", error->message);
561       g_clear_error (&error);
562     }
563
564   g_dbus_connection_register_object (connection,
565                                      "/org/a11y/bus",
566                                      introspection_data->interfaces[1],
567                                      &status_vtable,
568                                      _global_app,
569                                      NULL,
570                                      NULL);
571 }
572
573 static void
574 on_name_lost (GDBusConnection *connection,
575               const gchar     *name,
576               gpointer         user_data)
577 {
578   A11yBusLauncher *app = user_data;
579   if (app->session_bus == NULL
580       && connection == NULL
581       && app->a11y_launch_error_message == NULL)
582     app->a11y_launch_error_message = g_strdup ("Failed to connect to session bus");
583   g_main_loop_quit (app->loop);
584 }
585
586 static void
587 on_name_acquired (GDBusConnection *connection,
588                   const gchar     *name,
589                   gpointer         user_data)
590 {
591   A11yBusLauncher *app = user_data;
592
593   register_client (app);
594 }
595
596 static int sigterm_pipefd[2];
597
598 static void
599 sigterm_handler (int signum)
600 {
601   write (sigterm_pipefd[1], "X", 1);
602 }
603
604 static gboolean
605 on_sigterm_pipe (GIOChannel  *channel,
606                  GIOCondition condition,
607                  gpointer     data)
608 {
609   A11yBusLauncher *app = data;
610   
611   g_main_loop_quit (app->loop);
612
613   return FALSE;
614 }
615
616 static void
617 init_sigterm_handling (A11yBusLauncher *app)
618 {
619   GIOChannel *sigterm_channel;
620
621   if (pipe (sigterm_pipefd) < 0)
622     g_error ("Failed to create pipe: %s", strerror (errno));
623   signal (SIGTERM, sigterm_handler);
624
625   sigterm_channel = g_io_channel_unix_new (sigterm_pipefd[0]);
626   g_io_add_watch (sigterm_channel,
627                   G_IO_IN | G_IO_ERR | G_IO_HUP,
628                   on_sigterm_pipe,
629                   app);
630 }
631
632 static gboolean
633 already_running ()
634 {
635 #ifdef HAVE_X11
636   Atom AT_SPI_BUS;
637   Atom actual_type;
638   Display *bridge_display;
639   int actual_format;
640   unsigned char *data = NULL;
641   unsigned long nitems;
642   unsigned long leftover;
643   gboolean result = FALSE;
644
645   bridge_display = XOpenDisplay (NULL);
646   if (!bridge_display)
647               return FALSE;
648       
649   AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
650   XGetWindowProperty (bridge_display,
651                       XDefaultRootWindow (bridge_display),
652                       AT_SPI_BUS, 0L,
653                       (long) BUFSIZ, False,
654                       (Atom) 31, &actual_type, &actual_format,
655                       &nitems, &leftover, &data);
656
657   if (data)
658   {
659     GDBusConnection *bus;
660     bus = g_dbus_connection_new_for_address_sync ((const gchar *)data, 0,
661                                                   NULL, NULL, NULL);
662     if (bus != NULL)
663       {
664         result = TRUE;
665         g_object_unref (bus);
666       }
667   }
668
669   XCloseDisplay (bridge_display);
670   return result;
671 #else
672   return FALSE;
673 #endif
674 }
675
676 static GSettings *
677 get_schema (const gchar *name)
678 {
679   const char * const *schemas = NULL;
680   gint i;
681
682   schemas = g_settings_list_schemas ();
683   for (i = 0; schemas[i]; i++)
684   {
685     if (!strcmp (schemas[i], name))
686       return g_settings_new (schemas[i]);
687   }
688
689   return NULL;
690 }
691
692 static void
693 gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data)
694 {
695   gboolean new_val = g_settings_get_boolean (gsettings, key);
696   A11yBusLauncher *app = user_data;
697
698   if (!strcmp (key, "toolkit-accessibility"))
699     handle_a11y_enabled_change (_global_app, new_val, FALSE);
700   else if (!strcmp (key, "screen-reader-enabled"))
701     handle_screen_reader_enabled_change (_global_app, new_val, FALSE);
702 }
703
704 int
705 main (int    argc,
706       char **argv)
707 {
708   GError *error = NULL;
709   GMainLoop *loop;
710   GDBusConnection *session_bus;
711   int name_owner_id;
712   gboolean a11y_set = FALSE;
713   gboolean screen_reader_set = FALSE;
714   gint i;
715
716   if (already_running ())
717     return 0;
718
719   _global_app = g_slice_new0 (A11yBusLauncher);
720   _global_app->loop = g_main_loop_new (NULL, FALSE);
721
722   for (i = 1; i < argc; i++)
723     {
724       if (!strcmp (argv[i], "--launch-immediately"))
725         _global_app->launch_immediately = TRUE;
726       else if (sscanf (argv[i], "--a11y=%d", &_global_app->a11y_enabled) == 1)
727         a11y_set = TRUE;
728       else if (sscanf (argv[i], "--screen-reader=%d",
729                        &_global_app->screen_reader_enabled) == 1)
730         screen_reader_set = TRUE;
731     else
732       g_error ("usage: %s [--launch-immediately] [--a11y=0|1] [--screen-reader=0|1]", argv[0]);
733     }
734
735   _global_app->interface_schema = get_schema ("org.gnome.desktop.interface");
736   _global_app->a11y_schema = get_schema ("org.gnome.desktop.a11y.applications");
737
738   if (!a11y_set)
739     {
740       _global_app->a11y_enabled = _global_app->interface_schema
741                                   ? g_settings_get_boolean (_global_app->interface_schema, "toolkit-accessibility")
742                                   : _global_app->launch_immediately;
743     }
744
745   if (!screen_reader_set)
746     {
747       _global_app->screen_reader_enabled = _global_app->a11y_schema
748                                   ? g_settings_get_boolean (_global_app->a11y_schema, "screen-reader-enabled")
749                                   : FALSE;
750     }
751
752   if (_global_app->interface_schema)
753     g_signal_connect (_global_app->interface_schema,
754                       "changed::toolkit-accessibility",
755                       G_CALLBACK (gsettings_key_changed), _global_app);
756
757   if (_global_app->a11y_schema)
758     g_signal_connect (_global_app->a11y_schema,
759                       "changed::screen-reader-enabled",
760                       G_CALLBACK (gsettings_key_changed), _global_app);
761
762   init_sigterm_handling (_global_app);
763
764   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
765   g_assert (introspection_data != NULL);
766
767   name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
768                                   "org.a11y.Bus",
769                                   G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
770                                   on_bus_acquired,
771                                   on_name_acquired,
772                                   on_name_lost,
773                                   _global_app,
774                                   NULL);
775
776   g_main_loop_run (_global_app->loop);
777
778   if (_global_app->a11y_bus_pid > 0)
779     kill (_global_app->a11y_bus_pid, SIGTERM);
780
781   /* Clear the X property if our bus is gone; in the case where e.g. 
782    * GDM is launching a login on an X server it was using before,
783    * we don't want early login processes to pick up the stale address.
784    */
785 #ifdef HAVE_X11
786   {
787     Display *display = XOpenDisplay (NULL);
788     if (display)
789       {
790         Atom bus_address_atom = XInternAtom (display, "AT_SPI_BUS", False);
791         XDeleteProperty (display,
792                          XDefaultRootWindow (display),
793                          bus_address_atom);
794
795         XFlush (display);
796         XCloseDisplay (display);
797       }
798   }
799 #endif
800
801   if (_global_app->a11y_launch_error_message)
802     {
803       g_printerr ("Failed to launch bus: %s", _global_app->a11y_launch_error_message);
804       return 1;
805     }
806   return 0;
807 }