+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;
+
+ 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
+is_client_connected(A11yBusLauncher *app)
+{
+ guint watchers = g_hash_table_size(app->client_watcher_id);
+ LOGD("clients connected: %d", watchers);
+ return watchers > 0;
+}
+
+static void
+remove_client_watch(A11yBusLauncher *app,
+ const gchar *sender)
+{
+ LOGD("Remove client watcher for %s", sender);
+ guint watcher_id = GPOINTER_TO_UINT(g_hash_table_lookup(app->client_watcher_id, sender));
+ if (watcher_id)
+ g_bus_unwatch_name(watcher_id);
+
+ g_hash_table_remove(app->client_watcher_id, sender);
+ if (!is_client_connected(app))
+ handle_a11y_enabled_change (app, FALSE, TRUE);
+}
+
+static void
+on_client_name_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ A11yBusLauncher *app = user_data;
+ remove_client_watch(app, name);
+}
+
+static void
+add_client_watch(A11yBusLauncher *app,
+ const gchar *sender)
+{
+ LOGD("Add client watcher for %s", sender);
+
+ if (g_hash_table_contains(app->client_watcher_id, sender))
+ {
+ LOGI("Watcher for %s already registered", sender);
+ return;
+ }
+
+ guint watcher_id = g_bus_watch_name(G_BUS_TYPE_SESSION,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ on_client_name_vanished,
+ app,
+ NULL);
+
+ g_hash_table_insert(app->client_watcher_id, g_strdup(sender), GUINT_TO_POINTER(watcher_id));
+ handle_a11y_enabled_change (app, TRUE, TRUE);
+}
+
+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)
+ {
+ if (enabled)
+ add_client_watch(app, sender);
+ else
+ remove_client_watch(app, sender);
+ 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 =