X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fat-spi-bus-launcher.c;h=261353f9a2431eb56eaf97a0b2f467005c4f8bbf;hb=f0c90bddb04b7ab71efb91e7a54950a076d344d5;hp=930097930e85b7142ae94f28a5f1dd7f92a37276;hpb=f0b979c8d448ff45c93afb9670f7decf6a2e3a04;p=platform%2Fupstream%2Fat-spi2-core.git diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 9300979..261353f 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -27,10 +27,13 @@ #include #include #include +#include #include +#ifdef HAVE_X11 #include #include +#endif typedef enum { A11Y_BUS_STATE_IDLE = 0, @@ -42,7 +45,13 @@ typedef enum { typedef struct { GMainLoop *loop; gboolean launch_immediately; + gboolean a11y_enabled; + gboolean screen_reader_enabled; GDBusConnection *session_bus; + GSettings *a11y_schema; + GSettings *interface_schema; + + GDBusProxy *client_proxy; A11yBusState state; /* -1 == error, 0 == pending, > 0 == running */ @@ -61,10 +70,152 @@ static const gchar introspection_xml[] = " " " " " " + "" + "" + "" + "" ""; static GDBusNodeInfo *introspection_data = NULL; static void +respond_to_end_session (GDBusProxy *proxy) +{ + GVariant *parameters; + + parameters = g_variant_new ("(bs)", TRUE, ""); + + g_dbus_proxy_call (proxy, + "EndSessionResponse", parameters, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); +} + +static void +g_signal_cb (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + + if (g_strcmp0 (signal_name, "QueryEndSession") == 0) + respond_to_end_session (proxy); + else if (g_strcmp0 (signal_name, "EndSession") == 0) + respond_to_end_session (proxy); + else if (g_strcmp0 (signal_name, "Stop") == 0) + g_main_loop_quit (app->loop); +} + +static void +client_proxy_ready_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + GError *error = NULL; + + app->client_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + + if (error != NULL) + { + g_warning ("Failed to get a client proxy: %s", error->message); + g_error_free (error); + + return; + } + + g_signal_connect (app->client_proxy, "g-signal", + G_CALLBACK (g_signal_cb), app); +} + +static void +register_client (A11yBusLauncher *app) +{ + GDBusProxyFlags flags; + GDBusProxy *sm_proxy; + GError *error; + const gchar *app_id; + const gchar *autostart_id; + gchar *client_startup_id; + GVariant *parameters; + GVariant *variant; + gchar *object_path; + + flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS; + + error = NULL; + sm_proxy = g_dbus_proxy_new_sync (app->session_bus, flags, NULL, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + NULL, &error); + + if (error != NULL) + { + g_warning ("Failed to get session manager proxy: %s", error->message); + g_error_free (error); + + return; + } + + app_id = "at-spi-bus-launcher"; + autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); + + if (autostart_id != NULL) + { + client_startup_id = g_strdup (autostart_id); + g_unsetenv ("DESKTOP_AUTOSTART_ID"); + } + else + { + client_startup_id = g_strdup (""); + } + + parameters = g_variant_new ("(ss)", app_id, client_startup_id); + g_free (client_startup_id); + + error = NULL; + variant = g_dbus_proxy_call_sync (sm_proxy, + "RegisterClient", parameters, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + + g_object_unref (sm_proxy); + + if (error != NULL) + { + g_warning ("Failed to register client: %s", error->message); + g_error_free (error); + + return; + } + + g_variant_get (variant, "(o)", &object_path); + g_variant_unref (variant); + + flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, flags, NULL, + "org.gnome.SessionManager", object_path, + "org.gnome.SessionManager.ClientPrivate", + NULL, client_proxy_ready_cb, app); + + g_free (object_path); +} + +static void +name_appeared_handler (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + + register_client (app); +} + +static void setup_bus_child (gpointer data) { A11yBusLauncher *app = data; @@ -125,18 +276,24 @@ on_bus_exited (GPid pid, g_main_loop_quit (app->loop); } -static void +static gboolean ensure_a11y_bus (A11yBusLauncher *app) { GPid pid; char *argv[] = { DBUS_DAEMON, NULL, "--nofork", "--print-address", "3", NULL }; char addr_buf[2048]; GError *error = NULL; + const char *config_path = NULL; if (app->a11y_bus_pid != 0) - return; - - argv[1] = g_strdup_printf ("--config-file=%s/at-spi2/accessibility.conf", SYSCONFDIR); + return FALSE; + + if (g_file_test (SYSCONFDIR"/at-spi2/accessibility.conf", G_FILE_TEST_EXISTS)) + config_path = "--config-file="SYSCONFDIR"/at-spi2/accessibility.conf"; + else + config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf"; + + argv[1] = config_path; if (pipe (app->pipefd) < 0) g_error ("Failed to create pipe: %s", strerror (errno)); @@ -178,6 +335,7 @@ ensure_a11y_bus (A11yBusLauncher *app) app->a11y_bus_address = g_strchomp (g_strdup (addr_buf)); g_debug ("a11y bus address: %s", app->a11y_bus_address); +#ifdef HAVE_X11 { Display *display = XOpenDisplay (NULL); if (display) @@ -188,17 +346,20 @@ ensure_a11y_bus (A11yBusLauncher *app) bus_address_atom, XA_STRING, 8, PropModeReplace, (guchar *) app->a11y_bus_address, strlen (app->a11y_bus_address)); + XFlush (display); + XCloseDisplay (display); } - XFlush (display); - XCloseDisplay (display); } +#endif - return; + return TRUE; error: close (app->pipefd[0]); close (app->pipefd[1]); app->state = A11Y_BUS_STATE_ERROR; + + return FALSE; } static void @@ -226,13 +387,157 @@ handle_method_call (GDBusConnection *connection, } } -static const GDBusInterfaceVTable interface_vtable = +static GVariant * +handle_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + + if (g_strcmp0 (property_name, "IsEnabled") == 0) + return g_variant_new ("b", app->a11y_enabled); + else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0) + return g_variant_new ("b", app->screen_reader_enabled); + else + return NULL; +} + +static void +handle_a11y_enabled_change (A11yBusLauncher *app, gboolean enabled, + gboolean notify_gsettings) +{ + GVariantBuilder builder; + GVariantBuilder invalidated_builder; + + if (enabled == app->a11y_enabled) + return; + + app->a11y_enabled = enabled; + + if (notify_gsettings && app->interface_schema) + { + g_settings_set_boolean (app->interface_schema, "toolkit-accessibility", + enabled); + g_settings_sync (); + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); + g_variant_builder_add (&builder, "{sv}", "IsEnabled", + g_variant_new_boolean (enabled)); + + g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new ("(sa{sv}as)", "org.a11y.Status", + &builder, + &invalidated_builder), + NULL); + + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); +} + +static void +handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled, + gboolean notify_gsettings) +{ + GVariantBuilder builder; + GVariantBuilder invalidated_builder; + + if (enabled == app->screen_reader_enabled) + return; + + /* If the screen reader is being enabled, we should enable accessibility + * if it isn't enabled already */ + if (enabled) + handle_a11y_enabled_change (app, enabled, notify_gsettings); + + app->screen_reader_enabled = enabled; + + if (notify_gsettings && app->a11y_schema) + { + g_settings_set_boolean (app->a11y_schema, "screen-reader-enabled", + enabled); + g_settings_sync (); + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); + g_variant_builder_add (&builder, "{sv}", "ScreenReaderEnabled", + g_variant_new_boolean (enabled)); + + g_dbus_connection_emit_signal (app->session_bus, NULL, "/org/a11y/bus", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new ("(sa{sv}as)", "org.a11y.Status", + &builder, + &invalidated_builder), + NULL); + + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); +} + +static gboolean +handle_set_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GVariant *value, + GError **error, + gpointer user_data) +{ + A11yBusLauncher *app = user_data; + const gchar *type = g_variant_get_type_string (value); + gboolean enabled; + + if (g_strcmp0 (type, "b") != 0) + { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "org.a11y.Status.%s expects a boolean but got %s", property_name, type); + return FALSE; + } + + enabled = g_variant_get_boolean (value); + + if (g_strcmp0 (property_name, "IsEnabled") == 0) + { + handle_a11y_enabled_change (app, enabled, TRUE); + return TRUE; + } + else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0) + { + handle_screen_reader_enabled_change (app, enabled, TRUE); + return TRUE; + } + else + { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Unknown property '%s'", property_name); + return FALSE; + } +} + +static const GDBusInterfaceVTable bus_vtable = { handle_method_call, - NULL, + NULL, /* handle_get_property, */ NULL /* handle_set_property */ }; +static const GDBusInterfaceVTable status_vtable = +{ + NULL, /* handle_method_call */ + handle_get_property, + handle_set_property +}; + static void on_bus_acquired (GDBusConnection *connection, const gchar *name, @@ -263,12 +568,23 @@ on_bus_acquired (GDBusConnection *connection, registration_id = g_dbus_connection_register_object (connection, "/org/a11y/bus", introspection_data->interfaces[0], - &interface_vtable, + &bus_vtable, _global_app, NULL, &error); if (registration_id == 0) - g_error ("%s", error->message); + { + g_error ("%s", error->message); + g_clear_error (&error); + } + + g_dbus_connection_register_object (connection, + "/org/a11y/bus", + introspection_data->interfaces[1], + &status_vtable, + _global_app, + NULL, + NULL); } static void @@ -289,8 +605,11 @@ on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { - A11yBusLauncher *app = user_data; - (void) app; + g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.SessionManager", + G_BUS_NAME_WATCHER_FLAGS_NONE, + name_appeared_handler, NULL, + user_data, NULL); } static int sigterm_pipefd[2]; @@ -330,23 +649,75 @@ init_sigterm_handling (A11yBusLauncher *app) } static gboolean -is_a11y_using_corba (void) +already_running () { - char *gconf_argv[] = { "gconftool-2", "--get", "/desktop/gnome/interface/at-spi-corba", NULL }; - char *stdout = NULL; - int estatus; +#ifdef HAVE_X11 + Atom AT_SPI_BUS; + Atom actual_type; + Display *bridge_display; + int actual_format; + unsigned char *data = NULL; + unsigned long nitems; + unsigned long leftover; 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); + bridge_display = XOpenDisplay (NULL); + if (!bridge_display) + return FALSE; + + 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); + + if (data) + { + GDBusConnection *bus; + bus = g_dbus_connection_new_for_address_sync ((const gchar *)data, 0, + NULL, NULL, NULL); + if (bus != NULL) + { + result = TRUE; + g_object_unref (bus); + } + } + + XCloseDisplay (bridge_display); return result; +#else + return FALSE; +#endif +} + +static GSettings * +get_schema (const gchar *name) +{ + const char * const *schemas = NULL; + gint i; + + schemas = g_settings_list_schemas (); + for (i = 0; schemas[i]; i++) + { + if (!strcmp (schemas[i], name)) + return g_settings_new (schemas[i]); + } + + return NULL; +} + +static void +gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data) +{ + gboolean new_val = g_settings_get_boolean (gsettings, key); + A11yBusLauncher *app = user_data; + + if (!strcmp (key, "toolkit-accessibility")) + handle_a11y_enabled_change (_global_app, new_val, FALSE); + else if (!strcmp (key, "screen-reader-enabled")) + handle_screen_reader_enabled_change (_global_app, new_val, FALSE); } int @@ -357,15 +728,55 @@ main (int argc, GMainLoop *loop; GDBusConnection *session_bus; int name_owner_id; + gboolean a11y_set = FALSE; + gboolean screen_reader_set = FALSE; + gint i; - g_type_init (); - - if (is_a11y_using_corba ()) + if (already_running ()) 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); + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "--launch-immediately")) + _global_app->launch_immediately = TRUE; + else if (sscanf (argv[i], "--a11y=%d", &_global_app->a11y_enabled) == 1) + a11y_set = TRUE; + else if (sscanf (argv[i], "--screen-reader=%d", + &_global_app->screen_reader_enabled) == 1) + screen_reader_set = TRUE; + else + g_error ("usage: %s [--launch-immediately] [--a11y=0|1] [--screen-reader=0|1]", argv[0]); + } + + _global_app->interface_schema = get_schema ("org.gnome.desktop.interface"); + _global_app->a11y_schema = get_schema ("org.gnome.desktop.a11y.applications"); + + if (!a11y_set) + { + _global_app->a11y_enabled = _global_app->interface_schema + ? g_settings_get_boolean (_global_app->interface_schema, "toolkit-accessibility") + : _global_app->launch_immediately; + } + + if (!screen_reader_set) + { + _global_app->screen_reader_enabled = _global_app->a11y_schema + ? g_settings_get_boolean (_global_app->a11y_schema, "screen-reader-enabled") + : FALSE; + } + + if (_global_app->interface_schema) + g_signal_connect (_global_app->interface_schema, + "changed::toolkit-accessibility", + G_CALLBACK (gsettings_key_changed), _global_app); + + if (_global_app->a11y_schema) + g_signal_connect (_global_app->a11y_schema, + "changed::screen-reader-enabled", + G_CALLBACK (gsettings_key_changed), _global_app); init_sigterm_handling (_global_app); @@ -390,6 +801,7 @@ main (int argc, * GDM is launching a login on an X server it was using before, * we don't want early login processes to pick up the stale address. */ +#ifdef HAVE_X11 { Display *display = XOpenDisplay (NULL); if (display) @@ -403,6 +815,7 @@ main (int argc, XCloseDisplay (display); } } +#endif if (_global_app->a11y_launch_error_message) {