Support many at-spi clients 76/132376/2
authorPaweł Stawicki <p.stawicki@partner.samsung.com>
Tue, 9 May 2017 14:38:59 +0000 (16:38 +0200)
committerPaweł Stawicki <p.stawicki@partner.samsung.com>
Mon, 5 Jun 2017 14:17:59 +0000 (16:17 +0200)
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
test/Makefile.am
test/at_spi2_tool.c

index 87b2da7..bb6f9f9 100644 (file)
@@ -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++)
     {
index 6725315..828f126 100644 (file)
@@ -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
index 018acc7..deac3be 100644 (file)
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <stdbool.h>
+#include <gio/gio.h>
 
 #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 <true|false>\tenable/disable org.a11y.Status.IsEnabled property\n");
+       printf("-s, --sleep <N>\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;
 }