Add Nepali translation
[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 name_appeared_handler (GDBusConnection *connection,
209                        const gchar     *name,
210                        const gchar     *name_owner,
211                        gpointer         user_data)
212 {
213   A11yBusLauncher *app = user_data;
214
215   register_client (app);
216 }
217
218 static void
219 setup_bus_child (gpointer data)
220 {
221   A11yBusLauncher *app = data;
222   (void) app;
223
224   close (app->pipefd[0]);
225   dup2 (app->pipefd[1], 3);
226   close (app->pipefd[1]);
227
228   /* On Linux, tell the bus process to exit if this process goes away */
229 #ifdef __linux
230 #include <sys/prctl.h>
231   prctl (PR_SET_PDEATHSIG, 15);
232 #endif  
233 }
234
235 /**
236  * unix_read_all_fd_to_string:
237  *
238  * Read all data from a file descriptor to a C string buffer.
239  */
240 static gboolean
241 unix_read_all_fd_to_string (int      fd,
242                             char    *buf,
243                             ssize_t  max_bytes)
244 {
245   ssize_t bytes_read;
246
247   while (max_bytes > 1 && (bytes_read = read (fd, buf, MAX (4096, max_bytes - 1))))
248     {
249       if (bytes_read < 0)
250         return FALSE;
251       buf += bytes_read;
252       max_bytes -= bytes_read;
253     }
254   *buf = '\0';
255   return TRUE;
256 }
257
258 static void
259 on_bus_exited (GPid     pid,
260                gint     status,
261                gpointer data)
262 {
263   A11yBusLauncher *app = data;
264   
265   app->a11y_bus_pid = -1;
266   app->state = A11Y_BUS_STATE_ERROR;
267   if (app->a11y_launch_error_message == NULL)
268     {
269       if (WIFEXITED (status))
270         app->a11y_launch_error_message = g_strdup_printf ("Bus exited with code %d", WEXITSTATUS (status));
271       else if (WIFSIGNALED (status))
272         app->a11y_launch_error_message = g_strdup_printf ("Bus killed by signal %d", WTERMSIG (status));
273       else if (WIFSTOPPED (status))
274         app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status));
275     }
276   g_main_loop_quit (app->loop);
277
278
279 static gboolean
280 ensure_a11y_bus (A11yBusLauncher *app)
281 {
282   GPid pid;
283   char *argv[] = { DBUS_DAEMON, NULL, "--nofork", "--print-address", "3", NULL };
284   char addr_buf[2048];
285   GError *error = NULL;
286   const char *config_path = NULL;
287
288   if (app->a11y_bus_pid != 0)
289     return FALSE;
290
291   if (g_file_test (SYSCONFDIR"/at-spi2/accessibility.conf", G_FILE_TEST_EXISTS))
292       config_path = "--config-file="SYSCONFDIR"/at-spi2/accessibility.conf";
293   else
294       config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf";
295
296   argv[1] = config_path;
297
298   if (pipe (app->pipefd) < 0)
299     g_error ("Failed to create pipe: %s", strerror (errno));
300   
301   if (!g_spawn_async (NULL,
302                       argv,
303                       NULL,
304                       G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
305                       setup_bus_child,
306                       app,
307                       &pid,
308                       &error))
309     {
310       app->a11y_bus_pid = -1;
311       app->a11y_launch_error_message = g_strdup (error->message);
312       g_clear_error (&error);
313       goto error;
314     }
315
316   close (app->pipefd[1]);
317   app->pipefd[1] = -1;
318
319   g_child_watch_add (pid, on_bus_exited, app);
320
321   app->state = A11Y_BUS_STATE_READING_ADDRESS;
322   app->a11y_bus_pid = pid;
323   g_debug ("Launched a11y bus, child is %ld", (long) pid);
324   if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf)))
325     {
326       app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno));
327       kill (app->a11y_bus_pid, SIGTERM);
328       goto error;
329     }
330   close (app->pipefd[0]);
331   app->pipefd[0] = -1;
332   app->state = A11Y_BUS_STATE_RUNNING;
333
334   /* Trim the trailing newline */
335   app->a11y_bus_address = g_strchomp (g_strdup (addr_buf));
336   g_debug ("a11y bus address: %s", app->a11y_bus_address);
337
338 #ifdef HAVE_X11
339   {
340     Display *display = XOpenDisplay (NULL);
341     if (display)
342       {
343         Atom bus_address_atom = XInternAtom (display, "AT_SPI_BUS", False);
344         XChangeProperty (display,
345                          XDefaultRootWindow (display),
346                          bus_address_atom,
347                          XA_STRING, 8, PropModeReplace,
348                          (guchar *) app->a11y_bus_address, strlen (app->a11y_bus_address));
349         XFlush (display);
350         XCloseDisplay (display);
351       }
352   }
353 #endif
354
355   return TRUE;
356   
357  error:
358   close (app->pipefd[0]);
359   close (app->pipefd[1]);
360   app->state = A11Y_BUS_STATE_ERROR;
361
362   return FALSE;
363 }
364
365 static void
366 handle_method_call (GDBusConnection       *connection,
367                     const gchar           *sender,
368                     const gchar           *object_path,
369                     const gchar           *interface_name,
370                     const gchar           *method_name,
371                     GVariant              *parameters,
372                     GDBusMethodInvocation *invocation,
373                     gpointer               user_data)
374 {
375   A11yBusLauncher *app = user_data;
376
377   if (g_strcmp0 (method_name, "GetAddress") == 0)
378     {
379       ensure_a11y_bus (app);
380       if (app->a11y_bus_pid > 0)
381         g_dbus_method_invocation_return_value (invocation,
382                                                g_variant_new ("(s)", app->a11y_bus_address));
383       else
384         g_dbus_method_invocation_return_dbus_error (invocation,
385                                                     "org.a11y.Bus.Error",
386                                                     app->a11y_launch_error_message);
387     }
388 }
389
390 static GVariant *
391 handle_get_property  (GDBusConnection       *connection,
392                       const gchar           *sender,
393                       const gchar           *object_path,
394                       const gchar           *interface_name,
395                       const gchar           *property_name,
396                     GError **error,
397                     gpointer               user_data)
398 {
399   A11yBusLauncher *app = user_data;
400
401   if (g_strcmp0 (property_name, "IsEnabled") == 0)
402     return g_variant_new ("b", app->a11y_enabled);
403   else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0)
404     return g_variant_new ("b", app->screen_reader_enabled);
405   else
406     return NULL;
407 }
408
409 static void
410 handle_a11y_enabled_change (A11yBusLauncher *app, gboolean enabled,
411                                gboolean notify_gsettings)
412 {
413   GVariantBuilder builder;
414   GVariantBuilder invalidated_builder;
415
416   if (enabled == app->a11y_enabled)
417     return;
418
419   app->a11y_enabled = enabled;
420
421   if (notify_gsettings && app->interface_schema)
422     {
423       g_settings_set_boolean (app->interface_schema, "toolkit-accessibility",
424                               enabled);
425       g_settings_sync ();
426     }
427
428   g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
429   g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
430   g_variant_builder_add (&builder, "{sv}", "IsEnabled",
431                          g_variant_new_boolean (enabled));
432
433   g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus",
434                                  "org.freedesktop.DBus.Properties",
435                                  "PropertiesChanged",
436                                  g_variant_new ("(sa{sv}as)", "org.a11y.Status",
437                                                 &builder,
438                                                 &invalidated_builder),
439                                  NULL);
440
441   g_variant_builder_clear (&builder);
442   g_variant_builder_clear (&invalidated_builder);
443 }
444
445 static void
446 handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled,
447                                gboolean notify_gsettings)
448 {
449   GVariantBuilder builder;
450   GVariantBuilder invalidated_builder;
451
452   if (enabled == app->screen_reader_enabled)
453     return;
454
455   /* If the screen reader is being enabled, we should enable accessibility
456    * if it isn't enabled already */
457   if (enabled)
458     handle_a11y_enabled_change (app, enabled, notify_gsettings);
459
460   app->screen_reader_enabled = enabled;
461
462   if (notify_gsettings && app->a11y_schema)
463     {
464       g_settings_set_boolean (app->a11y_schema, "screen-reader-enabled",
465                               enabled);
466       g_settings_sync ();
467     }
468
469   g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
470   g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
471   g_variant_builder_add (&builder, "{sv}", "ScreenReaderEnabled",
472                          g_variant_new_boolean (enabled));
473
474   g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus",
475                                  "org.freedesktop.DBus.Properties",
476                                  "PropertiesChanged",
477                                  g_variant_new ("(sa{sv}as)", "org.a11y.Status",
478                                                 &builder,
479                                                 &invalidated_builder),
480                                  NULL);
481
482   g_variant_builder_clear (&builder);
483   g_variant_builder_clear (&invalidated_builder);
484 }
485
486 static gboolean
487 handle_set_property  (GDBusConnection       *connection,
488                       const gchar           *sender,
489                       const gchar           *object_path,
490                       const gchar           *interface_name,
491                       const gchar           *property_name,
492                       GVariant *value,
493                     GError **error,
494                     gpointer               user_data)
495 {
496   A11yBusLauncher *app = user_data;
497   const gchar *type = g_variant_get_type_string (value);
498   gboolean enabled;
499   
500   if (g_strcmp0 (type, "b") != 0)
501     {
502       g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
503                        "org.a11y.Status.%s expects a boolean but got %s", property_name, type);
504       return FALSE;
505     }
506
507   enabled = g_variant_get_boolean (value);
508
509   if (g_strcmp0 (property_name, "IsEnabled") == 0)
510     {
511       handle_a11y_enabled_change (app, enabled, TRUE);
512       return TRUE;
513     }
514   else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0)
515     {
516       handle_screen_reader_enabled_change (app, enabled, TRUE);
517       return TRUE;
518     }
519   else
520     {
521       g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
522                        "Unknown property '%s'", property_name);
523       return FALSE;
524     }
525 }
526
527 static const GDBusInterfaceVTable bus_vtable =
528 {
529   handle_method_call,
530   NULL, /* handle_get_property, */
531   NULL  /* handle_set_property */
532 };
533
534 static const GDBusInterfaceVTable status_vtable =
535 {
536   NULL, /* handle_method_call */
537   handle_get_property,
538   handle_set_property
539 };
540
541 static void
542 on_bus_acquired (GDBusConnection *connection,
543                  const gchar     *name,
544                  gpointer         user_data)
545 {
546   A11yBusLauncher *app = user_data;
547   GError *error;
548   guint registration_id;
549   
550   if (connection == NULL)
551     {
552       g_main_loop_quit (app->loop);
553       return;
554     }
555   app->session_bus = connection;
556
557   if (app->launch_immediately)
558     {
559       ensure_a11y_bus (app);
560       if (app->state == A11Y_BUS_STATE_ERROR)
561         {
562           g_main_loop_quit (app->loop);
563           return;
564         }
565     }
566
567   error = NULL;
568   registration_id = g_dbus_connection_register_object (connection,
569                                                        "/org/a11y/bus",
570                                                        introspection_data->interfaces[0],
571                                                        &bus_vtable,
572                                                        _global_app,
573                                                        NULL,
574                                                        &error);
575   if (registration_id == 0)
576     {
577       g_error ("%s", error->message);
578       g_clear_error (&error);
579     }
580
581   g_dbus_connection_register_object (connection,
582                                      "/org/a11y/bus",
583                                      introspection_data->interfaces[1],
584                                      &status_vtable,
585                                      _global_app,
586                                      NULL,
587                                      NULL);
588 }
589
590 static void
591 on_name_lost (GDBusConnection *connection,
592               const gchar     *name,
593               gpointer         user_data)
594 {
595   A11yBusLauncher *app = user_data;
596   if (app->session_bus == NULL
597       && connection == NULL
598       && app->a11y_launch_error_message == NULL)
599     app->a11y_launch_error_message = g_strdup ("Failed to connect to session bus");
600   g_main_loop_quit (app->loop);
601 }
602
603 static void
604 on_name_acquired (GDBusConnection *connection,
605                   const gchar     *name,
606                   gpointer         user_data)
607 {
608   g_bus_watch_name (G_BUS_TYPE_SESSION,
609                     "org.gnome.SessionManager",
610                     G_BUS_NAME_WATCHER_FLAGS_NONE,
611                     name_appeared_handler, NULL,
612                     user_data, NULL);
613 }
614
615 static int sigterm_pipefd[2];
616
617 static void
618 sigterm_handler (int signum)
619 {
620   write (sigterm_pipefd[1], "X", 1);
621 }
622
623 static gboolean
624 on_sigterm_pipe (GIOChannel  *channel,
625                  GIOCondition condition,
626                  gpointer     data)
627 {
628   A11yBusLauncher *app = data;
629   
630   g_main_loop_quit (app->loop);
631
632   return FALSE;
633 }
634
635 static void
636 init_sigterm_handling (A11yBusLauncher *app)
637 {
638   GIOChannel *sigterm_channel;
639
640   if (pipe (sigterm_pipefd) < 0)
641     g_error ("Failed to create pipe: %s", strerror (errno));
642   signal (SIGTERM, sigterm_handler);
643
644   sigterm_channel = g_io_channel_unix_new (sigterm_pipefd[0]);
645   g_io_add_watch (sigterm_channel,
646                   G_IO_IN | G_IO_ERR | G_IO_HUP,
647                   on_sigterm_pipe,
648                   app);
649 }
650
651 static gboolean
652 already_running ()
653 {
654 #ifdef HAVE_X11
655   Atom AT_SPI_BUS;
656   Atom actual_type;
657   Display *bridge_display;
658   int actual_format;
659   unsigned char *data = NULL;
660   unsigned long nitems;
661   unsigned long leftover;
662   gboolean result = FALSE;
663
664   bridge_display = XOpenDisplay (NULL);
665   if (!bridge_display)
666               return FALSE;
667       
668   AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
669   XGetWindowProperty (bridge_display,
670                       XDefaultRootWindow (bridge_display),
671                       AT_SPI_BUS, 0L,
672                       (long) BUFSIZ, False,
673                       (Atom) 31, &actual_type, &actual_format,
674                       &nitems, &leftover, &data);
675
676   if (data)
677   {
678     GDBusConnection *bus;
679     bus = g_dbus_connection_new_for_address_sync ((const gchar *)data, 0,
680                                                   NULL, NULL, NULL);
681     if (bus != NULL)
682       {
683         result = TRUE;
684         g_object_unref (bus);
685       }
686   }
687
688   XCloseDisplay (bridge_display);
689   return result;
690 #else
691   return FALSE;
692 #endif
693 }
694
695 static GSettings *
696 get_schema (const gchar *name)
697 {
698   const char * const *schemas = NULL;
699   gint i;
700
701   schemas = g_settings_list_schemas ();
702   for (i = 0; schemas[i]; i++)
703   {
704     if (!strcmp (schemas[i], name))
705       return g_settings_new (schemas[i]);
706   }
707
708   return NULL;
709 }
710
711 static void
712 gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data)
713 {
714   gboolean new_val = g_settings_get_boolean (gsettings, key);
715   A11yBusLauncher *app = user_data;
716
717   if (!strcmp (key, "toolkit-accessibility"))
718     handle_a11y_enabled_change (_global_app, new_val, FALSE);
719   else if (!strcmp (key, "screen-reader-enabled"))
720     handle_screen_reader_enabled_change (_global_app, new_val, FALSE);
721 }
722
723 int
724 main (int    argc,
725       char **argv)
726 {
727   GError *error = NULL;
728   GMainLoop *loop;
729   GDBusConnection *session_bus;
730   int name_owner_id;
731   gboolean a11y_set = FALSE;
732   gboolean screen_reader_set = FALSE;
733   gint i;
734
735   if (already_running ())
736     return 0;
737
738   _global_app = g_slice_new0 (A11yBusLauncher);
739   _global_app->loop = g_main_loop_new (NULL, FALSE);
740
741   for (i = 1; i < argc; i++)
742     {
743       if (!strcmp (argv[i], "--launch-immediately"))
744         _global_app->launch_immediately = TRUE;
745       else if (sscanf (argv[i], "--a11y=%d", &_global_app->a11y_enabled) == 1)
746         a11y_set = TRUE;
747       else if (sscanf (argv[i], "--screen-reader=%d",
748                        &_global_app->screen_reader_enabled) == 1)
749         screen_reader_set = TRUE;
750     else
751       g_error ("usage: %s [--launch-immediately] [--a11y=0|1] [--screen-reader=0|1]", argv[0]);
752     }
753
754   _global_app->interface_schema = get_schema ("org.gnome.desktop.interface");
755   _global_app->a11y_schema = get_schema ("org.gnome.desktop.a11y.applications");
756
757   if (!a11y_set)
758     {
759       _global_app->a11y_enabled = _global_app->interface_schema
760                                   ? g_settings_get_boolean (_global_app->interface_schema, "toolkit-accessibility")
761                                   : _global_app->launch_immediately;
762     }
763
764   if (!screen_reader_set)
765     {
766       _global_app->screen_reader_enabled = _global_app->a11y_schema
767                                   ? g_settings_get_boolean (_global_app->a11y_schema, "screen-reader-enabled")
768                                   : FALSE;
769     }
770
771   if (_global_app->interface_schema)
772     g_signal_connect (_global_app->interface_schema,
773                       "changed::toolkit-accessibility",
774                       G_CALLBACK (gsettings_key_changed), _global_app);
775
776   if (_global_app->a11y_schema)
777     g_signal_connect (_global_app->a11y_schema,
778                       "changed::screen-reader-enabled",
779                       G_CALLBACK (gsettings_key_changed), _global_app);
780
781   init_sigterm_handling (_global_app);
782
783   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
784   g_assert (introspection_data != NULL);
785
786   name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
787                                   "org.a11y.Bus",
788                                   G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
789                                   on_bus_acquired,
790                                   on_name_acquired,
791                                   on_name_lost,
792                                   _global_app,
793                                   NULL);
794
795   g_main_loop_run (_global_app->loop);
796
797   if (_global_app->a11y_bus_pid > 0)
798     kill (_global_app->a11y_bus_pid, SIGTERM);
799
800   /* Clear the X property if our bus is gone; in the case where e.g. 
801    * GDM is launching a login on an X server it was using before,
802    * we don't want early login processes to pick up the stale address.
803    */
804 #ifdef HAVE_X11
805   {
806     Display *display = XOpenDisplay (NULL);
807     if (display)
808       {
809         Atom bus_address_atom = XInternAtom (display, "AT_SPI_BUS", False);
810         XDeleteProperty (display,
811                          XDefaultRootWindow (display),
812                          bus_address_atom);
813
814         XFlush (display);
815         XCloseDisplay (display);
816       }
817   }
818 #endif
819
820   if (_global_app->a11y_launch_error_message)
821     {
822       g_printerr ("Failed to launch bus: %s", _global_app->a11y_launch_error_message);
823       return 1;
824     }
825   return 0;
826 }