From 72f9224d6ec1d5d968915fd681b6af905ea267ad Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Stawicki?= Date: Tue, 9 May 2017 16:38:59 +0200 Subject: [PATCH] Support many at-spi clients Commit allows many clients to enable the at-spi2 bus by setting the org.a11y.Status.IsEnabled property to true. Commit assumption: clients have to maintain an open connection to the session dbus after setting the org.a11y.Status.IsEnabled property, last closed connection will disable the at-spi2 bus. Commit requires: https://review.tizen.org/gerrit/#/c/132375/ https://review.tizen.org/gerrit/#/c/132480/ Change-Id: If3fabab59fa01f6ab7913fc6bad8df70ed134bee --- bus/at-spi-bus-launcher.c | 71 +++++++++++++++++++++++++++++++------ test/Makefile.am | 5 +-- test/at_spi2_tool.c | 89 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 139 insertions(+), 26 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 87b2da7..bb6f9f9 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -78,6 +78,7 @@ typedef struct { gboolean launch_immediately; gboolean a11y_enabled; gboolean screen_reader_enabled; + GHashTable *client_watcher_id; GDBusConnection *session_bus; GSettings *a11y_schema; GSettings *interface_schema; @@ -344,11 +345,6 @@ handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled, 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) @@ -375,6 +371,61 @@ handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled, } 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, @@ -399,7 +450,10 @@ handle_set_property (GDBusConnection *connection, if (g_strcmp0 (property_name, "IsEnabled") == 0) { - handle_a11y_enabled_change (app, enabled, TRUE); + if (enabled) + add_client_watch(app, sender); + else + remove_client_watch(app, sender); return TRUE; } else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0) @@ -600,7 +654,6 @@ 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); @@ -772,9 +825,6 @@ main (int argc, #endif LOGD("Starting atspi bus launcher"); - GError *error = NULL; - GMainLoop *loop; - GDBusConnection *session_bus; int name_owner_id; gboolean a11y_set = FALSE; gboolean screen_reader_set = FALSE; @@ -789,6 +839,7 @@ main (int argc, _global_app = g_slice_new0 (A11yBusLauncher); _global_app->loop = g_main_loop_new (NULL, FALSE); _global_app->launch_screen_reader_repeats = 0; + _global_app->client_watcher_id = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); for (i = 1; i < argc; i++) { diff --git a/test/Makefile.am b/test/Makefile.am index 6725315..828f126 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,8 +3,9 @@ LDADD = $(top_builddir)/atspi/libatspi.la bin_PROGRAMS = at_spi2_tool at_spi2_tool_SOURCES = at_spi2_tool.c at_spi2_tool_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) -I$(top_builddir)/atspi -at_spi2_tool_CFLAGS = $(GLIB_CFLAGS) --std=c99 -Wall $(GOBJ_LIBS) $(DBUS_CFLAGS) -at_spi2_tool_LDFLAGS = +at_spi2_tool_CFLAGS = $(GIO_CFLAGS) $(GLIB_CFLAGS) --std=c99 -Wall $(GOBJ_LIBS) $(DBUS_CFLAGS) +at_spi2_tool_LDFLAGS = $(GIO_LIBS) + noinst_PROGRAMS = memory memory_SOURCES = memory.c diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 018acc7..deac3be 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -4,6 +4,7 @@ #include #include #include +#include #define ERROR_STATE -1 #define SAFE_BUFFER_SIZE 2048 @@ -345,7 +346,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) flows_from); if (ret >= SAFE_BUFFER_SIZE) - fprintf(stderr, "\n%s, %s %s: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); + fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); free(node_name); free(node_role_name); @@ -427,6 +428,8 @@ void _print_help() printf("-v, --version\t\tshow actual version of tool\n"); printf("-g, --show-legend\tprint AT-SPI state legend\n"); printf("-l, --list-apps\t\tlist all applications of desktop\n"); + printf("-a, --at-spi-client \tenable/disable org.a11y.Status.IsEnabled property\n"); + printf("-s, --sleep \tsleep N seconds\n"); printf("-d, --tree-dump\t\tdump tree for selected application\n"); printf("-c, --tree-check\tcheck tree for selected application\n"); printf("-f, --first-match\tperform dump or check only for first matching application\n"); @@ -443,14 +446,21 @@ void _print_version() printf("AT-SPI2-CORE-UTIL v%s\n", VERSION); } -static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, bool dump, bool check, bool first_match, int length_limit) +static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bool first_match, int length_limit) { + + AtspiAccessible *desktop = atspi_get_desktop(0); + if (!desktop) { + fprintf(stderr, "atspi_get_desktop failed\n"); + return; + } + int count = atspi_accessible_get_child_count(desktop, NULL); bool app_name_matched = false; for (int i = 0; i < count; i++) { AtspiAccessible *child = atspi_accessible_get_child_at_index(desktop, i, NULL); if (child == NULL) { - fprintf(stderr, "\n%s, %s %s: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__); + fprintf(stderr, "\n%s, %s %d: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__); continue; } @@ -481,15 +491,59 @@ static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, if (!app_name_matched && (dump || check)) fprintf(stderr, "There is no application with name: %s. Try again.\n", app_name); + + g_object_unref(desktop); +} + +static void _at_spi_client_enable(gboolean enabled) +{ + static GDBusProxy *proxy = NULL; //we keep proxy (dbus connection) until program exits + GVariant *result; + GError *error = NULL; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_NONE; + + + if (!proxy) { + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + flags, + NULL, /* GDBusInterfaceInfo */ + "org.a11y.Bus", + "/org/a11y/bus", + "org.freedesktop.DBus.Properties", + NULL, /* GCancellable */ + &error); + if (error) { + fprintf(stderr, "Failed to create proxy object for '/org/a11y/bus': %s\n", error->message); + g_error_free(error); + return; + } + } + + result = g_dbus_proxy_call_sync(proxy, + "Set", + g_variant_new ("(ssv)", "org.a11y.Status", "IsEnabled", g_variant_new_boolean(enabled)), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (result) + g_variant_unref(result); + + if (error) { + fprintf(stderr, "Fail to call org.freedesktop.DBus.Properties.Set: %s\n", error->message); + g_error_free(error); + } } -static void _run_command(int argc, char *argv[], AtspiAccessible *desktop) +static void _run_command(int argc, char *argv[]) { struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'v'}, {"show-legend", no_argument, 0, 'g'}, {"list-apps", no_argument, 0, 'l'}, + {"at-spi-client", no_argument, 0, 'a'}, + {"sleep", required_argument, 0, 's'}, {"tree-dump", required_argument, 0, 'd'}, {"tree-check", required_argument, 0, 'c'}, {"first-match", no_argument, 0, 'f'}, @@ -501,9 +555,10 @@ static void _run_command(int argc, char *argv[], AtspiAccessible *desktop) int option_index = 0; bool traverse_flags[FLAG_NO] = {false}; char *app_name = NULL; + gboolean enable_at_spi_client; while (TRUE) { - command = getopt_long(argc, argv, "hvgld:c:ft:i:", long_options, &option_index); + command = getopt_long(argc, argv, "hvgla:s:d:c:ft:i:", long_options, &option_index); if (command == ERROR_STATE) break; @@ -522,7 +577,19 @@ static void _run_command(int argc, char *argv[], AtspiAccessible *desktop) break; case 'l': - _atspi_tree_traverse(desktop, NULL, false, false, false, module_name_limit); + _atspi_tree_traverse(NULL, false, false, false, module_name_limit); + break; + + case 'a': + enable_at_spi_client = TRUE; + if(optarg[0] == 'f' || optarg[0] == '0') + enable_at_spi_client = FALSE; + + _at_spi_client_enable(enable_at_spi_client); + break; + + case 's': + sleep(atoi(optarg)); break; case 'd': @@ -557,7 +624,7 @@ static void _run_command(int argc, char *argv[], AtspiAccessible *desktop) } if (traverse_flags[DUMP] || traverse_flags[CHECK]) - _atspi_tree_traverse(desktop, app_name, traverse_flags[DUMP], traverse_flags[CHECK], traverse_flags[FIRST_MATCH], module_name_limit); + _atspi_tree_traverse(app_name, traverse_flags[DUMP], traverse_flags[CHECK], traverse_flags[FIRST_MATCH], module_name_limit); } int main(int argc, char *argv[]) @@ -574,13 +641,7 @@ int main(int argc, char *argv[]) return -1; } - AtspiAccessible *desktop = atspi_get_desktop(0); - if (!desktop) { - fprintf(stderr, "atspi_get_desktop failed\n"); - return -1; - } - - _run_command(argc, argv, desktop); + _run_command(argc, argv); return 0; } -- 2.7.4