From 59196d54df4ccefff67fc31afb56f9ad35a75a9c Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 28 Jun 2017 17:45:04 +0900 Subject: [PATCH 01/16] Revert "Add relation-dump option to at_spi2_tool" This reverts commit e757756d750e7d736aee31c71b68116a71031f58. Change-Id: If8b0b10885f424c2b2370a26c14ceaa15ef779e9 --- test/at_spi2_tool.c | 141 ++++++++++++++++------------------------------------ 1 file changed, 44 insertions(+), 97 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 95c726c..018acc7 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -4,7 +4,6 @@ #include #include #include -#include #define ERROR_STATE -1 #define SAFE_BUFFER_SIZE 2048 @@ -18,8 +17,6 @@ #define DUMP 0 #define CHECK 1 #define FIRST_MATCH 2 -#define RELATION_TABLE_COLUMN_COUNT 7 -#define RELATION_COLUMN_WIDTH 20 #define VERSION "1.1" static unsigned indent_width = 2; @@ -82,6 +79,12 @@ typedef struct _Box_Size { char *width; } Box_Size; +char *_strdup(const char *c) +{ + char *result = (char *)calloc(1, strlen(c) + 1); + return result ? strcpy(result, c) : result; +} + static char *_multiply_string(char c, unsigned number) { char *result = (char *)calloc(1, number + 1); @@ -96,7 +99,7 @@ static char *_multiply_string(char c, unsigned number) static void _print_module_legend() { - printf("\n[[node],[node role name],[attributes list],[x,y,width,height],[node name],[states list][relations]\n\n"); + printf("\n[[node],[node role name],[attributes list],[x,y,width,height],[node name],[states list][flow to node, flow from node]\n\n"); } static void _print_atspi_states_legend() @@ -247,7 +250,7 @@ static char *_get_states(AtspiAccessible *node, int length_limit) state_type = g_array_index(states, AtspiStateType, i); char node_state_str[8]; - snprintf(node_state_str, 8, "(%d)", state_type); + sprintf(node_state_str, "(%d)", state_type); _combine_strings(&state_string, node_state_str); } @@ -285,6 +288,32 @@ static char *_get_attributes(AtspiAccessible *node, int length_limit) return result; } +static char *_get_object_in_relation(AtspiAccessible *source, AtspiRelationType search_type) +{ + if (source == NULL) + return ""; + + GArray *relations = atspi_accessible_get_relation_set(source, NULL); + + if (relations == NULL) + return ""; + + AtspiAccessible *ret = NULL; + for (int i = 0; i < relations->len; ++i) { + AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i); + AtspiRelationType type = atspi_relation_get_relation_type(relation); + + if (type == search_type) { + ret = atspi_relation_get_target(relation, 0); + break; + } + } + + g_array_free(relations, TRUE); + + return ret ? atspi_accessible_get_path(ret, NULL) : g_strdup(""); +} + static char *_get_info(AtspiAccessible *node, int length_limit) { if (!node) @@ -298,10 +327,11 @@ static char *_get_info(AtspiAccessible *node, int length_limit) Box_Size *box_size = _get_box_size(node); char *states = _get_states(node, length_limit); - GArray *relations = atspi_accessible_get_relation_set(node, NULL); + char *flows_to = _get_object_in_relation(node, ATSPI_RELATION_FLOWS_TO); + char *flows_from = _get_object_in_relation(node, ATSPI_RELATION_FLOWS_FROM); char result[SAFE_BUFFER_SIZE]; - int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]", + int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s,%s]]", path, node_role_name, attributes, @@ -311,7 +341,8 @@ static char *_get_info(AtspiAccessible *node, int length_limit) box_size->height, node_name, states, - (relations && relations->len) ? "*" : ""); + flows_to, + flows_from); if (ret >= SAFE_BUFFER_SIZE) fprintf(stderr, "\n%s, %s %s: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); @@ -326,9 +357,10 @@ static char *_get_info(AtspiAccessible *node, int length_limit) free(box_size); } free(states); - g_array_free(relations, TRUE); + free(flows_to); + free(flows_from); - return g_strdup(result); + return _strdup(result); } static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessible *parent_candidate, int parent_candidate_index) @@ -341,7 +373,7 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi char parent_status[NUMBER_WIDTH]; if (parent == NULL) - strncpy(parent_status, "_", NUMBER_WIDTH); + strcpy(parent_status, "_"); else snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index); @@ -406,93 +438,11 @@ void _print_help() printf("\tat_spi2_tool -i1 -c starter\n"); printf("\t show AT-SPI tree with integrity test for node \"starter\" using one-space indentation\n"); } - void _print_version() { printf("AT-SPI2-CORE-UTIL v%s\n", VERSION); } -static void _print_horizontal_line_in_relation_table() { - for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { - for (int j = 0; j < RELATION_COLUMN_WIDTH; j++) - printf("-"); - printf("+"); - } - printf("\n"); -} - -static void _print_legend_for_relation_table() { - char *table[] = {"OBJECT", "CONTROLLER_FOR", "CONTROLLED_BY", "FLOWS_TO", "FLOWS_FROM", "DESCRIBED_BY", "OTHER RELATION [ID]"}; - assert(sizeof(table) / sizeof(table[0]) == RELATION_TABLE_COLUMN_COUNT); - for(int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) - printf("%*s|", RELATION_COLUMN_WIDTH , table[i]); - printf("\n"); - _print_horizontal_line_in_relation_table(); -} - -static char *_get_path_to_object_in_relation(AtspiRelation *relation) { - if (!relation) - return NULL; - gint last_index = atspi_relation_get_n_targets(relation) - 1; - AtspiAccessible *target = atspi_relation_get_target(relation, last_index); - return atspi_accessible_get_path(target, NULL); -} - -static void _print_relations_for_object(AtspiAccessible *node) { - GArray *relations = atspi_accessible_get_relation_set(node, NULL); - if (!relations) - return; - - if (relations->len) { - int size = RELATION_TABLE_COLUMN_COUNT * sizeof(char *); - char **table = malloc(size); - memset(table, 0, size); - table[0] = atspi_accessible_get_path(node, NULL); - char buf[8] = ""; - for (int i = 0; i < relations->len; i++) { - AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i); - AtspiRelationType type = atspi_relation_get_relation_type(relation); - switch (type) { - case ATSPI_RELATION_CONTROLLER_FOR: - table[1] = _get_path_to_object_in_relation(relation); - break; - case ATSPI_RELATION_CONTROLLED_BY: - table[2] = _get_path_to_object_in_relation(relation); - break; - case ATSPI_RELATION_FLOWS_TO: - table[3] = _get_path_to_object_in_relation(relation); - break; - case ATSPI_RELATION_FLOWS_FROM: - table[4] = _get_path_to_object_in_relation(relation); - break; - case ATSPI_RELATION_DESCRIBED_BY: - table[5] = _get_path_to_object_in_relation(relation); - break; - default: - snprintf(buf, 8, " [%d]", type); - _combine_strings(&table[RELATION_TABLE_COLUMN_COUNT - 1], buf); - } - } - - for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { - printf("%*s|", RELATION_COLUMN_WIDTH, table[i] ? table[i] : ""); - free(table[i]); - } - free(table); - - printf("\n"); - _print_horizontal_line_in_relation_table(); - } - g_array_free(relations, TRUE); - - int count = atspi_accessible_get_child_count(node, NULL); - for (int i = 0; i < count; i++) { - AtspiAccessible *child = atspi_accessible_get_child_at_index(node, i, NULL); - if (child) - _print_relations_for_object(child); - } -} - static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, bool dump, bool check, bool first_match, int length_limit) { int count = atspi_accessible_get_child_count(desktop, NULL); @@ -522,11 +472,8 @@ static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, if (first_match) { free(name); break; - } else { + } else printf("\n"); - _print_legend_for_relation_table(); - _print_relations_for_object(child); - } free(name); } -- 2.7.4 From 283c2b766fb92ed95f4fe3d2b79cc898d592c8c2 Mon Sep 17 00:00:00 2001 From: Radoslaw Cybulski Date: Mon, 10 Apr 2017 10:42:22 +0200 Subject: [PATCH 02/16] Extends support for uniquely identyfing objects. - adds atspi_accessible_get_unique_id function, which returns unique identifier across all bridges, - and atspi_accessible_get_bus_name function, which returns identifier of the bridge for given object. Change-Id: Idccd85e3269e5a36c8d96bc8588f4eac175c52f6 --- atspi/atspi-accessible.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++- atspi/atspi-accessible.h | 4 ++++ test/at_spi2_tool.c | 18 ++++++++-------- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index c3392bd..e112574 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -237,11 +237,62 @@ atspi_accessible_get_name (AtspiAccessible *obj, GError **error) return g_strdup (obj->name); } + +/** + * atspi_accessible_get_unique_id: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * + * Gets the identificator, uniquely identifying object, or NULL if an error occured. + * + * Returns: a UTF-8 string describing the #AtspiAccessible object + * or NULL on exception or NULL object passed. + **/ +gchar * +atspi_accessible_get_unique_id(AtspiAccessible *obj, GError **error) +{ + if (!obj) { + g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "argument is null"); + return NULL; + } + + gchar *id = NULL; + gchar *bus_name = atspi_accessible_get_bus_name(obj, error); + if (bus_name && bus_name[0]) { + gchar *path = atspi_accessible_get_path(obj, error); + if (path && path[0]) + id = g_strdup_printf("%s:%s", bus_name, path); + else + g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get path"); + g_free(path); + } + else + g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get bus name"); + g_free(bus_name); + return id; +} + +/** + * atspi_accessible_get_bus_name: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * + * Gets the bus name, where object belongs. + * + * Returns: a UTF-8 string describing the #AtspiAccessible object's + * bus name or empty string on exception or NULL object passed. + **/ +gchar * +atspi_accessible_get_bus_name(AtspiAccessible *obj, GError **error) +{ + if (!obj || !obj->parent.app) + return g_strdup(""); + return g_strdup (obj->parent.app->bus_name); +} + /** * atspi_accessible_get_path: * @obj: a pointer to the #AtspiAccessible object on which to operate. * - * Gets the path, uniquely identifying object. + * Gets the path, uniquely identifying object over its bus name. * * Returns: a UTF-8 string describing the #AtspiAccessible object * or empty string on exception or NULL object passed. diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index f07394e..de60b90 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -77,6 +77,10 @@ gchar * atspi_accessible_get_description (AtspiAccessible *obj, GError **error); gchar * atspi_accessible_get_path (AtspiAccessible *obj, GError **error); +gchar * atspi_accessible_get_bus_name (AtspiAccessible *obj, GError **error); + +gchar * atspi_accessible_get_unique_id (AtspiAccessible *obj, GError **error); + AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **error); gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error); diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 018acc7..948aae4 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -311,7 +311,7 @@ static char *_get_object_in_relation(AtspiAccessible *source, AtspiRelationType g_array_free(relations, TRUE); - return ret ? atspi_accessible_get_path(ret, NULL) : g_strdup(""); + return ret ? atspi_accessible_get_unique_id(ret, NULL) : g_strdup(""); } static char *_get_info(AtspiAccessible *node, int length_limit) @@ -321,7 +321,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) char *node_name = atspi_accessible_get_name(node, NULL); char *node_role_name = atspi_accessible_get_role_name(node, NULL); - char *path = atspi_accessible_get_path(node, NULL); + char *unique_id = atspi_accessible_get_unique_id(node, NULL); char *attributes = _get_attributes(node, length_limit); Box_Size *box_size = _get_box_size(node); @@ -332,7 +332,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) char result[SAFE_BUFFER_SIZE]; int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s,%s]]", - path, + unique_id, node_role_name, attributes, box_size->x, @@ -349,7 +349,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) free(node_name); free(node_role_name); - free(path); + free(unique_id); free(attributes); if (box_size) { free(box_size->width); @@ -377,12 +377,12 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi else snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index); - char *parent_path = atspi_accessible_get_path(parent, NULL); - char *parent_candidate_path = atspi_accessible_get_path(parent_candidate, NULL); + char *parent_unique_id = atspi_accessible_get_unique_id(parent, NULL); + char *parent_candidate_unique_id = atspi_accessible_get_unique_id(parent_candidate, NULL); snprintf(output, CHECK_OUTPUT_WIDTH, "[FAIL<%d,%s><%s,%s>]", parent_candidate_index, parent_status, - parent_candidate_path, parent_path); - free(parent_path); - free(parent_candidate_path); + parent_candidate_unique_id, parent_unique_id); + free(parent_unique_id); + free(parent_candidate_unique_id); } else { snprintf(output, CHECK_OUTPUT_WIDTH, "[OK]"); -- 2.7.4 From 29f7a16080f961af341fb827646bf378d4448ec1 Mon Sep 17 00:00:00 2001 From: Radoslaw Cybulski Date: Fri, 3 Mar 2017 16:30:04 +0100 Subject: [PATCH 03/16] Add navigation helper functions for screen-reader and friends This patch adds GetNavigableAtPoint accessibility interface - the function finds accessibility object at given coordinates. This massively (10-15 times) reduce amount of IPC calls (and time spent) in typical screen-reader scenario. Requires: - https://review.tizen.org/gerrit/c/117306/ (elementary) Change-Id: I0515e220f451fb196c0e346ea8e2dbd6d0d7d02f --- atspi/atspi-accessible.c | 41 +++++++++++++++++++++++++++++++++ atspi/atspi-accessible.h | 2 ++ atspi/atspi-component.c | 9 ++++---- atspi/atspi-component.h | 6 ++--- atspi/atspi-misc-private.h | 5 +++- atspi/atspi-misc.c | 57 ++++++++++++++++++++++++++++++++-------------- 6 files changed, 95 insertions(+), 25 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index e112574..a579254 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -314,6 +314,47 @@ atspi_accessible_get_path(AtspiAccessible *obj, GError **error) } /** + * atspi_accessible_get_navigable_at_point: + * @root: a pointer to the #AtspiAccessible to start search from. + * @x: a #gint specifying the x coordinate of the point in question. + * @y: a #gint specifying the y coordinate of the point in question. + * @ctype: the coordinate system of the point (@x, @y) + * (e.g. ATSPI_COORD_TYPE_WINDOW, ATSPI_COORD_TYPE_SCREEN). + * + * Finds the accessible element closest to user (highest in z-order), at a given coordinate within an #AtspiAccessible. + * This should be the element, that should be picked, when doing mouse click or finger tap at given coordinates. + * + * Returns: (nullable) (transfer full): a pointer to an + * #AtspiAccessible descendant (of any depth) of the specified component which + * contains the point (@x, @y), or NULL if no descendant contains + * the point. + **/ +AtspiAccessible * +atspi_accessible_get_navigable_at_point (AtspiAccessible *root, + gint x, + gint y, + AtspiCoordType ctype, GError **error) +{ + dbus_int32_t d_x = x, d_y = y; + dbus_uint32_t d_ctype = ctype; + DBusMessage *reply; + AtspiAccessible *return_value = NULL; + unsigned char recurse = 0; + + g_return_val_if_fail (root != NULL, FALSE); + do { + reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype); + + AtspiAccessible *tmp = _atspi_dbus_return_accessible_and_recurse_info_from_message (reply, &recurse); + if (!tmp) break; + if (return_value) + g_object_unref(return_value); + return_value = root = tmp; + } while(recurse); + return return_value; +} + +/** * atspi_accessible_get_description: * @obj: a pointer to the #AtspiAccessible object on which to operate. * diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index de60b90..82b779e 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -81,6 +81,8 @@ gchar * atspi_accessible_get_bus_name (AtspiAccessible *obj, GError **error); gchar * atspi_accessible_get_unique_id (AtspiAccessible *obj, GError **error); +AtspiAccessible *atspi_accessible_get_navigable_at_point (AtspiAccessible *root, gint x, gint y, AtspiCoordType ctype, GError **error); + AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **error); gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error); diff --git a/atspi/atspi-component.c b/atspi/atspi-component.c index bdbe57c..c246348 100644 --- a/atspi/atspi-component.c +++ b/atspi/atspi-component.c @@ -122,6 +122,7 @@ atspi_component_get_accessible_at_point (AtspiComponent *obj, return _atspi_dbus_return_accessible_from_message (reply); } + /** * atspi_component_get_extents: * @obj: a pointer to the #AtspiComponent to query. @@ -215,7 +216,7 @@ atspi_component_get_size (AtspiComponent *obj, GError **error) * atspi_component_get_layer: * @obj: a pointer to the #AtspiComponent to query. * - * Queries which layer the component is painted into, to help determine its + * Queries which layer the component is painted into, to help determine its * visibility in terms of stacking order. * * Returns: the #AtspiComponentLayer into which this component is painted. @@ -237,7 +238,7 @@ atspi_component_get_layer (AtspiComponent *obj, GError **error) * Queries the z stacking order of a component which is in the MDI or window * layer. (Bigger z-order numbers mean nearer the top) * - * Returns: a #gshort indicating the stacking order of the component + * Returns: a #gshort indicating the stacking order of the component * in the MDI layer, or -1 if the component is not in the MDI layer. **/ gshort @@ -316,9 +317,9 @@ atspi_component_clear_highlight (AtspiComponent *obj, GError **error) * * Gets the opacity/alpha value of a component, if alpha blending is in use. * - * Returns: the opacity value of a component, as a #gdouble between 0.0 and 1.0. + * Returns: the opacity value of a component, as a #gdouble between 0.0 and 1.0. **/ -gdouble +gdouble atspi_component_get_alpha (AtspiComponent *obj, GError **error) { double retval = 1; diff --git a/atspi/atspi-component.h b/atspi/atspi-component.h index 1388072..4363e55 100644 --- a/atspi/atspi-component.h +++ b/atspi/atspi-component.h @@ -4,7 +4,7 @@ * * Copyright 2002 Ximian, Inc. * 2002 Sun Microsystems Inc. - * + * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -44,7 +44,7 @@ struct _AtspiRect /** * ATSPI_TYPE_RECT: - * + * * The #GType for a boxed type holding a #AtspiRect. */ #define ATSPI_TYPE_RECT (atspi_rect_get_type ()) @@ -62,7 +62,7 @@ struct _AtspiPoint /** * ATSPI_TYPE_POINT: - * + * * The #GType for a boxed type holding a #AtspiPoint. */ #define ATSPI_TYPE_POINT (atspi_point_get_type ()) diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h index fe5ca56..53133a7 100644 --- a/atspi/atspi-misc-private.h +++ b/atspi/atspi-misc-private.h @@ -5,7 +5,7 @@ * Copyright 2002 Ximian, Inc. * 2002 Sun Microsystems Inc. * Copyright 2010, 2011 Novell, Inc. - * + * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -81,6 +81,9 @@ AtspiAccessible * _atspi_dbus_return_accessible_from_message (DBusMessage *message); AtspiAccessible * +_atspi_dbus_return_accessible_and_recurse_info_from_message (DBusMessage *message, unsigned char *recurse); + +AtspiAccessible * _atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter); AtspiHyperlink * diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 679e0da..c6b4581 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -110,7 +110,7 @@ _atspi_get_iface_num (const char *iface) GHashTable * _atspi_get_live_refs (void) { - if (!live_refs) + if (!live_refs) { live_refs = g_hash_table_new (g_direct_hash, g_direct_equal); } @@ -598,31 +598,54 @@ _atspi_ref_accessible (const char *app, const char *path) return ref_accessible (app, path); } -AtspiAccessible * -_atspi_dbus_return_accessible_from_message (DBusMessage *message) +static AtspiAccessible * +_atspi_dbus_return_accessible_and_recurse_info_from_message_impl (DBusMessage *message, unsigned char *recurse) { DBusMessageIter iter; AtspiAccessible *retval = NULL; const char *signature; + const char *expected_signature = recurse ? "(so)y" : "(so)"; - if (!message) - return NULL; + if (!message) return NULL; signature = dbus_message_get_signature (message); - if (!strcmp (signature, "(so)")) + if (!strcmp (signature, expected_signature)) { dbus_message_iter_init (message, &iter); retval = _atspi_dbus_return_accessible_from_iter (&iter); + if (recurse) { + unsigned char value = 0; + dbus_message_iter_get_basic (&iter, &value); + dbus_message_iter_next (&iter); + *recurse = (value != 0); + } } else { - g_warning ("AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange signature %s", signature); + g_warning ("AT-SPI: Called _atspi_dbus_return_accessible_from_message with unexpected signature %s", signature); } dbus_message_unref (message); return retval; } AtspiAccessible * +_atspi_dbus_return_accessible_from_message (DBusMessage *message) +{ + return _atspi_dbus_return_accessible_and_recurse_info_from_message_impl(message, NULL); +} + +AtspiAccessible * +_atspi_dbus_return_accessible_and_recurse_info_from_message(DBusMessage *message, unsigned char *recurse) +{ + if (recurse == NULL) { + g_error("AT-SPI: Called _atspi_dbus_return_accessible_and_recurse_info_from_message with NULL argument recurse"); + dbus_message_unref (message); + return NULL; + } + return _atspi_dbus_return_accessible_and_recurse_info_from_message_impl(message, recurse); +} + +AtspiAccessible * _atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter) { const char *app_name, *path; @@ -637,7 +660,7 @@ _atspi_dbus_return_hyperlink_from_message (DBusMessage *message) DBusMessageIter iter; AtspiHyperlink *retval = NULL; const char *signature; - + if (!message) return NULL; @@ -850,7 +873,7 @@ spi_display_name (void) * * Connects to the accessibility registry and initializes the SPI. * - * Returns: 0 on success, 1 if already initialized, or an integer error code. + * Returns: 0 on success, 1 if already initialized, or an integer error code. **/ int atspi_init (void) @@ -947,7 +970,7 @@ atspi_event_quit (void) /** * atspi_exit: * - * Disconnects from #AtspiRegistry instances and releases + * Disconnects from #AtspiRegistry instances and releases * any floating resources. Call only once at exit. * * Returns: 0 if there were no leaks, otherwise other integer values. @@ -1122,9 +1145,9 @@ _atspi_dbus_call_partial_va (gpointer obj, { AtspiObject *aobj = ATSPI_OBJECT (obj); DBusError err; - DBusMessage *msg = NULL, *reply = NULL; - DBusMessageIter iter; - const char *p; + DBusMessage *msg = NULL, *reply = NULL; + DBusMessageIter iter; + const char *p; dbus_error_init (&err); @@ -1451,7 +1474,7 @@ get_accessibility_bus_address_x11 (void) g_warning ("Could not open X display"); return NULL; } - + AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False); XGetWindowProperty (bridge_display, XDefaultRootWindow (bridge_display), @@ -1499,7 +1522,7 @@ get_accessibility_bus_address_dbus (void) dbus_error_free (&error); goto out; } - + { const char *tmp_address; if (!dbus_message_get_args (reply, @@ -1579,7 +1602,7 @@ atspi_get_a11y_bus (void) return NULL; } } - + /* Simulate a weak ref on the bus */ dbus_connection_set_data (a11y_bus, a11y_dbus_slot, a11y_bus, a11y_bus_free); @@ -1768,7 +1791,7 @@ _atspi_dbus_update_cache_from_dict (AtspiAccessible *accessible, DBusMessageIter g_value_set_boxed (val, &extents); } if (val) - g_hash_table_insert (cache, g_strdup (key), val); + g_hash_table_insert (cache, g_strdup (key), val); dbus_message_iter_next (&iter_dict); } -- 2.7.4 From fe9f99e73477e139716655ac657eef387d8524d1 Mon Sep 17 00:00:00 2001 From: Radoslaw Cybulski Date: Thu, 9 Mar 2017 18:09:34 +0100 Subject: [PATCH 04/16] Add navigation helper functions for screen-reader and friends (part 2) Change-Id: I67eb6da5262a9de721dc2cb569255079dc221ec9 --- atspi/atspi-accessible.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++- atspi/atspi-accessible.h | 2 + atspi/atspi-constants.h | 5 +++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index a579254..71fd816 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -341,7 +341,7 @@ atspi_accessible_get_navigable_at_point (AtspiAccessible *root, AtspiAccessible *return_value = NULL; unsigned char recurse = 0; - g_return_val_if_fail (root != NULL, FALSE); + g_return_val_if_fail (root != NULL, NULL); do { reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype); @@ -354,6 +354,118 @@ atspi_accessible_get_navigable_at_point (AtspiAccessible *root, return return_value; } +static unsigned char are_objects_on_the_same_bus(AtspiAccessible *obj1, AtspiAccessible *obj2) +{ + const char *bus_name_1 = obj1->parent.app->bus_name; + const char *bus_name_2 = obj2->parent.app->bus_name; + return strcmp(bus_name_1, bus_name_2) == 0; +} + +static unsigned char object_is_valid(AtspiAccessible *obj) +{ + if (!obj) + return 0; + AtspiStateSet *ss = atspi_accessible_get_state_set(obj); + if (!ss) + return 0; + unsigned char valid = atspi_state_set_contains(ss, ATSPI_STATE_DEFUNCT) == 0; + g_object_unref(ss); + return valid; +} + +typedef enum { + NEIGHBOR_SEARCH_MODE_NORMAL = 0, + NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1, + NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2, +} GetNeighborSearchMode; +/** + * atspi_accessible_get_neighbor: + * @root: a pointer to a #AtspiAccessible, which represents current root of subtree to search + * @start: a pointer to the #AtspiAccessible to start search from (can be null, which means start from root) + * @direction: direction, in which search (forward or backward) + * + * Calculates next (or previous) accessible element in logical order or null if none found. + * + * Returns: (nullable) (transfer full): a pointer to an + * #AtspiAccessible element, which is next (previous) in logical order or null if none found. + **/ +AtspiAccessible * +atspi_accessible_get_neighbor (AtspiAccessible *root, + AtspiAccessible *start, + AtspiNeighborSearchDirection direction, + GError **error) +{ + g_return_val_if_fail (object_is_valid(root), NULL); + if (!object_is_valid(start)) + start = root; + const char *root_path = ATSPI_OBJECT(root)->path; + AtspiAccessible *return_value = NULL; + g_object_ref(start); + unsigned char recurse; + GetNeighborSearchMode search_mode = NEIGHBOR_SEARCH_MODE_NORMAL; + GQueue *children_root_stack = g_queue_new(); + + while(1) { + const char *path = are_objects_on_the_same_bus(root, start) ? root_path : ""; + DBusMessage *reply = _atspi_dbus_call_partial (start, atspi_interface_accessible, "GetNeighbor", error, "sii", path, (int)direction, (int)search_mode); + AtspiAccessible *ret = _atspi_dbus_return_accessible_and_recurse_info_from_message (reply, &recurse); + // got return value and request for recursive search, it means ret is on another bridge, than start + // thus we're recursing. should the recurse failed to find anything it will end with + if (ret && recurse) { + g_object_unref(G_OBJECT(start)); + g_queue_push_tail(children_root_stack, ret); + start = ret; + g_object_ref(start); + search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT; + continue; + } + // found the one we've been looking for + if (ret) { + g_object_unref(G_OBJECT(start)); + return_value = ret; + break; + } + + // we've stepped into different bridges previously and now we're going back to the last one + // and continuing search where we left + if (!g_queue_is_empty(children_root_stack)) { + g_object_unref(G_OBJECT(start)); + start = g_queue_pop_tail(children_root_stack); + search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING; + continue; + } + // there's no more bridges to check, but we might have started from one + // in that case there might be bridges "below" start, which we yet have to visit + if (!are_objects_on_the_same_bus(root, start)) { + unsigned char continue_loop = 1; + while(continue_loop) { + AtspiAccessible *parent = atspi_accessible_get_parent(start, NULL); + continue_loop = parent ? are_objects_on_the_same_bus(start, parent) : 0; + g_object_unref(G_OBJECT(start)); + start = parent; + } + // going up thru parents put us in weird place (we didnt meet root on the way) + // so we bail out + if (!start) + break; + + // start object now points to different bridge and must be treated as "resume after recursing" + search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING; + continue; + } + + // nothing found + g_object_unref(start); + return_value = NULL; + break; + } + while(!g_queue_is_empty(children_root_stack)) + g_object_unref(g_queue_pop_tail(children_root_stack)); + g_queue_free(children_root_stack); + + return return_value; +} + /** * atspi_accessible_get_description: * @obj: a pointer to the #AtspiAccessible object on which to operate. diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 82b779e..293946b 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -83,6 +83,8 @@ gchar * atspi_accessible_get_unique_id (AtspiAccessible *obj, GError **error); AtspiAccessible *atspi_accessible_get_navigable_at_point (AtspiAccessible *root, gint x, gint y, AtspiCoordType ctype, GError **error); +AtspiAccessible *atspi_accessible_get_neighbor (AtspiAccessible *root, AtspiAccessible *start, AtspiNeighborSearchDirection direction, GError **error); + AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **error); gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error); diff --git a/atspi/atspi-constants.h b/atspi/atspi-constants.h index dd10679..24f3852 100644 --- a/atspi/atspi-constants.h +++ b/atspi/atspi-constants.h @@ -136,6 +136,11 @@ typedef enum { ATSPI_COORD_TYPE_WINDOW, } AtspiCoordType; +typedef enum { + ATSPI_NEIGHBOR_SEARCH_FORWARD = 1, + ATSPI_NEIGHBOR_SEARCH_BACKWARD = 2, +} AtspiNeighborSearchDirection; + /** * ATSPI_COORD_TYPE_COUNT: * -- 2.7.4 From 8fd84fce6f1ef2a9e694a14cfb77a29ed269a686 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 19 May 2017 19:44:31 +0900 Subject: [PATCH 05/16] Reduce action related IPC If there are more than 10 actions on an object, then more than 10 IPC occurs for doing more than 10th action. Change-Id: Id3767be2978357d147e7f2ecf96aee8e48641c16 --- atspi/atspi-action.c | 22 ++++++++++++++++++++++ atspi/atspi-action.h | 1 + 2 files changed, 23 insertions(+) diff --git a/atspi/atspi-action.c b/atspi/atspi-action.c index 731773a..d4e963e 100644 --- a/atspi/atspi-action.c +++ b/atspi/atspi-action.c @@ -214,6 +214,28 @@ atspi_action_do_action (AtspiAction *obj, gint i, GError **error) return retval; } +/** + * atspi_action_do_action_name: + * @obj: a pointer to the #AtspiAction to query. + * @name: a action name specifying which action to invoke. + * + * Invoke the action indicated by name. + * + * Returns: #TRUE if the action is successfully invoked, otherwise #FALSE. + **/ +gboolean +atspi_action_do_action_name (AtspiAction *obj, gchar *name, GError **error) +{ + const char *action_name = name; + dbus_bool_t retval = FALSE; + + g_return_val_if_fail (obj != NULL, FALSE); + + _atspi_dbus_call (obj, atspi_interface_action, "DoActionName", error, "s=>b", action_name, &retval); + + return retval; +} + static void atspi_action_base_init (AtspiAction *klass) { diff --git a/atspi/atspi-action.h b/atspi/atspi-action.h index 99de8af..00f3a2e 100644 --- a/atspi/atspi-action.h +++ b/atspi/atspi-action.h @@ -57,6 +57,7 @@ gchar * atspi_action_get_key_binding (AtspiAction *obj, gint i, GError **error); gchar * atspi_action_get_localized_name (AtspiAction *obj, gint i, GError **error); gboolean atspi_action_do_action (AtspiAction *obj, gint i, GError **error); +gboolean atspi_action_do_action_name (AtspiAction *obj, gchar *name, GError **error); #ifndef ATSPI_DISABLE_DEPRECATED gchar * atspi_action_get_description (AtspiAction *obj, gint i, GError **error); -- 2.7.4 From 69e5ff7f2c6833af43ac2e36da4c7fb84c923034 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 26 May 2017 22:03:26 +0900 Subject: [PATCH 06/16] Add atspi_accessible_get_reading_material To get reading material to be used screen-reader side. This is not stable. You have to handle all alocated memory as below on screen-reader side. AtspiAccessibleReadingMaterial *rm g_object_unref(rm->parent); g_object_unref(rm->described_by_accessible); g_hash_table_unref(rm->attributes); free(rm->name); free(rm->labeled_by_name); free(rm->text_interface_name); free(rm->localized_role_name); free(rm->description); free(rm); Related patch set: https://review.tizen.org/gerrit/#/c/131358/ (this one, at-spi2-core) https://review.tizen.org/gerrit/#/c/131359/ (elementary) https://review.tizen.org/gerrit/#/c/131511/ (at-spi2-atk) https://review.tizen.org/gerrit/#/c/131714/ (screen-reader) Change-Id: I968b058098162efe1cbec309411492ca29f696c8 --- atspi/atspi-accessible.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ atspi/atspi-accessible.h | 30 ++++++++ atspi/atspi-types.h | 1 + 3 files changed, 211 insertions(+) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 71fd816..02a526c 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -354,6 +354,186 @@ atspi_accessible_get_navigable_at_point (AtspiAccessible *root, return return_value; } +/** + * atspi_accessible_get_reading_material: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * + * Gets reading material + * + * Returns: reading material to be used screen-reader side. This is not stable. + * You have to handle all alocated memory as below on screen-reader side. + * + * AtspiAccessibleReadingMaterial *rm + * g_object_unref(rm->parent); + * g_object_unref(rm->described_by_accessible); + * g_hash_table_unref(rm->attributes); + * free(rm->name); + * free(rm->labeled_by_name); + * free(rm->text_interface_name); + * free(rm->localized_role_name); + * free(rm->description); + * free(rm); + **/ +AtspiAccessibleReadingMaterial * +atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error) +{ + AtspiAccessible *parent; + AtspiAccessibleReadingMaterial *reading_material = NULL; + const char *name; + double current_value; + gint count; + guint64 val; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter iter_array; + dbus_uint32_t role; + dbus_uint32_t *states; + dbus_int32_t index_in_parent; + dbus_int32_t child_count; + dbus_bool_t is_selected; + + g_return_val_if_fail (obj != NULL, NULL); + + reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetReadingMaterial", error, ""); + + _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausiddddsibbii(so)auiui(so)", NULL, NULL); + + reading_material = calloc(1, sizeof(AtspiAccessibleReadingMaterial)); + if (!reading_material) + { + return reading_material; + } + + dbus_message_iter_init (reply, &iter); + + /* get attributes */ + reading_material->attributes = _atspi_dbus_hash_from_iter (&iter); + dbus_message_iter_next (&iter); + + /* get name */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->name = g_strdup (name); + dbus_message_iter_next (&iter); + + /* get name of relation LABELED_BY */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->labeled_by_name = g_strdup (name); + dbus_message_iter_next (&iter); + + /* get name of text interface */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->text_interface_name = g_strdup (name); + dbus_message_iter_next (&iter); + + /* get role */ + dbus_message_iter_get_basic (&iter, &role); + reading_material->role = role; + dbus_message_iter_next (&iter); + + /* get state set */ + dbus_message_iter_recurse (&iter, &iter_array); + dbus_message_iter_get_fixed_array (&iter_array, &states, &count); + val = ((guint64)states [1]) << 32; + val += states [0]; + reading_material->states = val; + dbus_message_iter_next (&iter); + + /* get localized role name */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->localized_role_name = g_strdup (name); + dbus_message_iter_next (&iter); + + /* get child count */ + dbus_message_iter_get_basic (&iter, &child_count); + reading_material->child_count = child_count; + dbus_message_iter_next (&iter); + + /* get current value */ + dbus_message_iter_get_basic (&iter, ¤t_value); + reading_material->value = current_value; + dbus_message_iter_next (&iter); + + /* get minimum increment */ + dbus_message_iter_get_basic (&iter, ¤t_value); + reading_material->increment = current_value; + dbus_message_iter_next (&iter); + + /* get maximum value */ + dbus_message_iter_get_basic (&iter, ¤t_value); + reading_material->upper = current_value; + dbus_message_iter_next (&iter); + + /* get minimum value */ + dbus_message_iter_get_basic (&iter, ¤t_value); + reading_material->lower = current_value; + dbus_message_iter_next (&iter); + + /* get description */ + dbus_message_iter_get_basic (&iter, &name); + reading_material->description = g_strdup (name); + dbus_message_iter_next (&iter); + + /* get index in parent */ + dbus_message_iter_get_basic (&iter, &index_in_parent); + reading_material->index_in_parent = index_in_parent; + dbus_message_iter_next (&iter); + + /* get selected in parent */ + dbus_message_iter_get_basic (&iter, &is_selected); + reading_material->is_selected_in_parent = is_selected; + dbus_message_iter_next (&iter); + + /* get has checkbox child */ + dbus_message_iter_get_basic (&iter, &is_selected); + reading_material->has_checkbox_child = is_selected; + dbus_message_iter_next (&iter); + + /* get list children count */ + dbus_message_iter_get_basic (&iter, &child_count); + reading_material->list_children_count = child_count; + dbus_message_iter_next (&iter); + + /* get first selected child index */ + dbus_message_iter_get_basic (&iter, &index_in_parent); + reading_material->first_selected_child_index = index_in_parent; + dbus_message_iter_next (&iter); + + //////////////// + /* get parent */ + parent = _atspi_dbus_return_accessible_from_iter (&iter); + reading_material->parent = parent; + + /* parent states */ + dbus_message_iter_recurse (&iter, &iter_array); + dbus_message_iter_get_fixed_array (&iter_array, &states, &count); + val = ((guint64)states [1]) << 32; + val += states [0]; + reading_material->parent_states = val; + dbus_message_iter_next (&iter); + + /* get parent child count */ + dbus_message_iter_get_basic (&iter, &child_count); + reading_material->parent_child_count = child_count; + dbus_message_iter_next (&iter); + + /* get parent role */ + dbus_message_iter_get_basic (&iter, &role); + reading_material->parent_role = role; + dbus_message_iter_next (&iter); + + /* get parent selected child count */ + dbus_message_iter_get_basic (&iter, &child_count); + reading_material->parent_selected_child_count = child_count; + dbus_message_iter_next (&iter); + + //////////////////////////////////////// + /* get relation object - DESCRIBED_BY */ + parent = _atspi_dbus_return_accessible_from_iter (&iter); + reading_material->described_by_accessible = parent; + + return reading_material; +} + static unsigned char are_objects_on_the_same_bus(AtspiAccessible *obj1, AtspiAccessible *obj2) { const char *bus_name_1 = obj1->parent.app->bus_name; diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 293946b..0b5152b 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.h @@ -45,6 +45,34 @@ G_BEGIN_DECLS typedef struct _AtspiAccessiblePrivate AtspiAccessiblePrivate; +struct _AtspiAccessibleReadingMaterial +{ + AtspiAccessible *parent; + AtspiAccessible *described_by_accessible; + GHashTable *attributes; + AtspiRole role; + AtspiRole parent_role; + char *name; + char *labeled_by_name; + char *text_interface_name; + char *localized_role_name; + char *description; + gdouble value; + gdouble increment; + gdouble lower; + gdouble upper; + gint64 states; + gint64 parent_states; + gint child_count; + gint index_in_parent; + gint list_children_count; + gint first_selected_child_index; + gint parent_child_count; + gint parent_selected_child_count; + gboolean is_selected_in_parent; + gboolean has_checkbox_child; +}; + struct _AtspiAccessible { AtspiObject parent; @@ -85,6 +113,8 @@ AtspiAccessible *atspi_accessible_get_navigable_at_point (AtspiAccessible *root, AtspiAccessible *atspi_accessible_get_neighbor (AtspiAccessible *root, AtspiAccessible *start, AtspiNeighborSearchDirection direction, GError **error); +AtspiAccessibleReadingMaterial *atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error); + AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **error); gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error); diff --git a/atspi/atspi-types.h b/atspi/atspi-types.h index e458a8e..45b815c 100644 --- a/atspi/atspi-types.h +++ b/atspi/atspi-types.h @@ -43,6 +43,7 @@ typedef struct _AtspiTable AtspiTable; typedef struct _AtspiTableCell AtspiTableCell; typedef struct _AtspiText AtspiText; typedef struct _AtspiValue AtspiValue; +typedef struct _AtspiAccessibleReadingMaterial AtspiAccessibleReadingMaterial; typedef guint AtspiControllerEventMask; -- 2.7.4 From 429b6e38d794bd0d51cc871e15fd2c856c68f448 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 14 Jun 2017 13:56:52 +0900 Subject: [PATCH 07/16] Use deputy object sent by "GetNavigableAtPoint" The deputy means embedding side object works for embedded object. If there is no object at point on embedded side, then the deputy object should have highlight. So far the deputy object is elm_access, and the elm_access takes highlight. So there is no chance to have highlight on embedded side. This patch set reuires: elementary: b82beff73c41f52542d71fd6f4d9ad4ddcb4bacc Change-Id: I2136242b73883757bd50331b10f3e1f8a6bff986 --- atspi/atspi-accessible.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- atspi/atspi-misc-private.h | 3 --- atspi/atspi-misc.c | 35 ++++++----------------------------- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 02a526c..bafe114 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -340,13 +340,39 @@ atspi_accessible_get_navigable_at_point (AtspiAccessible *root, DBusMessage *reply; AtspiAccessible *return_value = NULL; unsigned char recurse = 0; + DBusMessageIter iter; + AtspiAccessible *deputy = NULL; g_return_val_if_fail (root != NULL, NULL); do { reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype); - AtspiAccessible *tmp = _atspi_dbus_return_accessible_and_recurse_info_from_message (reply, &recurse); - if (!tmp) break; + _ATSPI_DBUS_CHECK_SIG (reply, "(so)y(so)", NULL, NULL); + + dbus_message_iter_init (reply, &iter); + AtspiAccessible *tmp = _atspi_dbus_return_accessible_from_iter (&iter); + + unsigned char value = 0; + dbus_message_iter_get_basic (&iter, &value); + dbus_message_iter_next (&iter); + recurse = (value != 0); + + /* keep deputy if tmp has deputy */ + if (!deputy) + deputy = _atspi_dbus_return_accessible_from_iter (&iter); + + dbus_message_unref(reply); + + if (!tmp) { + if (deputy) { + /* TODO: need to check deputy works for return value */ + if (return_value) + g_object_unref(return_value); + return deputy; + } + break; + } + if (return_value) g_object_unref(return_value); return_value = root = tmp; @@ -584,11 +610,22 @@ atspi_accessible_get_neighbor (AtspiAccessible *root, unsigned char recurse; GetNeighborSearchMode search_mode = NEIGHBOR_SEARCH_MODE_NORMAL; GQueue *children_root_stack = g_queue_new(); + DBusMessageIter iter; while(1) { const char *path = are_objects_on_the_same_bus(root, start) ? root_path : ""; DBusMessage *reply = _atspi_dbus_call_partial (start, atspi_interface_accessible, "GetNeighbor", error, "sii", path, (int)direction, (int)search_mode); - AtspiAccessible *ret = _atspi_dbus_return_accessible_and_recurse_info_from_message (reply, &recurse); + + dbus_message_iter_init (reply, &iter); + AtspiAccessible *ret = _atspi_dbus_return_accessible_from_iter (&iter); + + unsigned char value = 0; + dbus_message_iter_get_basic (&iter, &value); + dbus_message_iter_next (&iter); + recurse = (value != 0); + + dbus_message_unref(reply); + // got return value and request for recursive search, it means ret is on another bridge, than start // thus we're recursing. should the recurse failed to find anything it will end with if (ret && recurse) { @@ -611,6 +648,7 @@ atspi_accessible_get_neighbor (AtspiAccessible *root, if (!g_queue_is_empty(children_root_stack)) { g_object_unref(G_OBJECT(start)); start = g_queue_pop_tail(children_root_stack); + search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING; continue; } @@ -624,6 +662,7 @@ atspi_accessible_get_neighbor (AtspiAccessible *root, g_object_unref(G_OBJECT(start)); start = parent; } + // going up thru parents put us in weird place (we didnt meet root on the way) // so we bail out if (!start) diff --git a/atspi/atspi-misc-private.h b/atspi/atspi-misc-private.h index 53133a7..27b3717 100644 --- a/atspi/atspi-misc-private.h +++ b/atspi/atspi-misc-private.h @@ -81,9 +81,6 @@ AtspiAccessible * _atspi_dbus_return_accessible_from_message (DBusMessage *message); AtspiAccessible * -_atspi_dbus_return_accessible_and_recurse_info_from_message (DBusMessage *message, unsigned char *recurse); - -AtspiAccessible * _atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter); AtspiHyperlink * diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index c6b4581..193257b 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -598,54 +598,31 @@ _atspi_ref_accessible (const char *app, const char *path) return ref_accessible (app, path); } -static AtspiAccessible * -_atspi_dbus_return_accessible_and_recurse_info_from_message_impl (DBusMessage *message, unsigned char *recurse) +AtspiAccessible * +_atspi_dbus_return_accessible_from_message (DBusMessage *message) { DBusMessageIter iter; AtspiAccessible *retval = NULL; const char *signature; - const char *expected_signature = recurse ? "(so)y" : "(so)"; - if (!message) return NULL; + if (!message) + return NULL; signature = dbus_message_get_signature (message); - if (!strcmp (signature, expected_signature)) + if (!strcmp (signature, "(so)")) { dbus_message_iter_init (message, &iter); retval = _atspi_dbus_return_accessible_from_iter (&iter); - if (recurse) { - unsigned char value = 0; - dbus_message_iter_get_basic (&iter, &value); - dbus_message_iter_next (&iter); - *recurse = (value != 0); - } } else { - g_warning ("AT-SPI: Called _atspi_dbus_return_accessible_from_message with unexpected signature %s", signature); + g_warning ("AT-SPI: Called _atspi_dbus_return_accessible_from_message with strange signature %s", signature); } dbus_message_unref (message); return retval; } AtspiAccessible * -_atspi_dbus_return_accessible_from_message (DBusMessage *message) -{ - return _atspi_dbus_return_accessible_and_recurse_info_from_message_impl(message, NULL); -} - -AtspiAccessible * -_atspi_dbus_return_accessible_and_recurse_info_from_message(DBusMessage *message, unsigned char *recurse) -{ - if (recurse == NULL) { - g_error("AT-SPI: Called _atspi_dbus_return_accessible_and_recurse_info_from_message with NULL argument recurse"); - dbus_message_unref (message); - return NULL; - } - return _atspi_dbus_return_accessible_and_recurse_info_from_message_impl(message, recurse); -} - -AtspiAccessible * _atspi_dbus_return_accessible_from_iter (DBusMessageIter *iter) { const char *app_name, *path; -- 2.7.4 From 80d3c912259746251bb90d3035079dc71030f82d Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Thu, 15 Jun 2017 21:29:03 +0900 Subject: [PATCH 08/16] Add NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE mode The "GetNeighbor" method returns an accessible object which has same bus with root object. But the returned recurse value is 1. The following is the case. If embedded object has highlight, and there is no more previous object, then it returns PROXY object which has embedding side bus information. In this case, the "GetNeighbor" should find previous sibling object in embedding process. The "GetNeighbor" is using NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE for this case. Change-Id: Icae2709b2746bd970643034c2d66b1c196c65ca9 --- atspi/atspi-accessible.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index bafe114..40053f2 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -583,6 +583,7 @@ typedef enum { NEIGHBOR_SEARCH_MODE_NORMAL = 0, NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1, NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2, + NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3, } GetNeighborSearchMode; /** * atspi_accessible_get_neighbor: @@ -630,10 +631,17 @@ atspi_accessible_get_neighbor (AtspiAccessible *root, // thus we're recursing. should the recurse failed to find anything it will end with if (ret && recurse) { g_object_unref(G_OBJECT(start)); - g_queue_push_tail(children_root_stack, ret); start = ret; g_object_ref(start); - search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT; + if (are_objects_on_the_same_bus(root, ret)) + { + search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE; + } + else + { + g_queue_push_tail(children_root_stack, ret); + search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT; + } continue; } // found the one we've been looking for -- 2.7.4 From 7b0103f7c7775e7b0f50cb0939c891fbf0a0bcff Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 30 Jun 2017 15:50:52 +0900 Subject: [PATCH 09/16] atspi_action_do_action_name: change parameter type The name is not changed in atspi_action_do_action_name. So the type of name should be const gchar* Change-Id: I6a9329ea34ef566dd444cae5112dead99ef4a9ce --- atspi/atspi-action.c | 2 +- atspi/atspi-action.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atspi/atspi-action.c b/atspi/atspi-action.c index d4e963e..ccf05bd 100644 --- a/atspi/atspi-action.c +++ b/atspi/atspi-action.c @@ -224,7 +224,7 @@ atspi_action_do_action (AtspiAction *obj, gint i, GError **error) * Returns: #TRUE if the action is successfully invoked, otherwise #FALSE. **/ gboolean -atspi_action_do_action_name (AtspiAction *obj, gchar *name, GError **error) +atspi_action_do_action_name (AtspiAction *obj, const gchar *name, GError **error) { const char *action_name = name; dbus_bool_t retval = FALSE; diff --git a/atspi/atspi-action.h b/atspi/atspi-action.h index 00f3a2e..d30395e 100644 --- a/atspi/atspi-action.h +++ b/atspi/atspi-action.h @@ -57,7 +57,7 @@ gchar * atspi_action_get_key_binding (AtspiAction *obj, gint i, GError **error); gchar * atspi_action_get_localized_name (AtspiAction *obj, gint i, GError **error); gboolean atspi_action_do_action (AtspiAction *obj, gint i, GError **error); -gboolean atspi_action_do_action_name (AtspiAction *obj, gchar *name, GError **error); +gboolean atspi_action_do_action_name (AtspiAction *obj, const gchar *name, GError **error); #ifndef ATSPI_DISABLE_DEPRECATED gchar * atspi_action_get_description (AtspiAction *obj, gint i, GError **error); -- 2.7.4 From 23b49ea6ed68e056d1d8de4756293ca026ec09ce Mon Sep 17 00:00:00 2001 From: Pawel Kurowski Date: Thu, 1 Jun 2017 12:45:08 +0200 Subject: [PATCH 10/16] Add relation-dump option to at_spi2_tool Flags -d and -c now inform when object has relations to list. Change-Id: I0c9a03c8d18ddf965c72ceac2bb804742c4540bf --- test/at_spi2_tool.c | 155 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 45 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index dfbc051..15adca5 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -5,6 +5,7 @@ #include #include #include +#include #define ERROR_STATE -1 #define SAFE_BUFFER_SIZE 2048 @@ -18,6 +19,8 @@ #define DUMP 0 #define CHECK 1 #define FIRST_MATCH 2 +#define RELATION_TABLE_COLUMN_COUNT 7 +#define RELATION_COLUMN_WIDTH 20 #define VERSION "1.1" static unsigned indent_width = 2; @@ -80,12 +83,6 @@ typedef struct _Box_Size { char *width; } Box_Size; -char *_strdup(const char *c) -{ - char *result = (char *)calloc(1, strlen(c) + 1); - return result ? strcpy(result, c) : result; -} - static char *_multiply_string(char c, unsigned number) { char *result = (char *)calloc(1, number + 1); @@ -100,7 +97,7 @@ static char *_multiply_string(char c, unsigned number) static void _print_module_legend() { - printf("\n[[node],[node role name],[attributes list],[x,y,width,height],[node name],[states list][flow to node, flow from node]\n\n"); + printf("\n[[node],[node role name],[attributes list],[x,y,width,height],[node name],[states list][relations]\n\n"); } static void _print_atspi_states_legend() @@ -251,7 +248,7 @@ static char *_get_states(AtspiAccessible *node, int length_limit) state_type = g_array_index(states, AtspiStateType, i); char node_state_str[8]; - sprintf(node_state_str, "(%d)", state_type); + snprintf(node_state_str, 8, "(%d)", state_type); _combine_strings(&state_string, node_state_str); } @@ -289,32 +286,6 @@ static char *_get_attributes(AtspiAccessible *node, int length_limit) return result; } -static char *_get_object_in_relation(AtspiAccessible *source, AtspiRelationType search_type) -{ - if (source == NULL) - return ""; - - GArray *relations = atspi_accessible_get_relation_set(source, NULL); - - if (relations == NULL) - return ""; - - AtspiAccessible *ret = NULL; - for (int i = 0; i < relations->len; ++i) { - AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i); - AtspiRelationType type = atspi_relation_get_relation_type(relation); - - if (type == search_type) { - ret = atspi_relation_get_target(relation, 0); - break; - } - } - - g_array_free(relations, TRUE); - - return ret ? atspi_accessible_get_unique_id(ret, NULL) : g_strdup(""); -} - static char *_get_info(AtspiAccessible *node, int length_limit) { if (!node) @@ -328,11 +299,10 @@ static char *_get_info(AtspiAccessible *node, int length_limit) Box_Size *box_size = _get_box_size(node); char *states = _get_states(node, length_limit); - char *flows_to = _get_object_in_relation(node, ATSPI_RELATION_FLOWS_TO); - char *flows_from = _get_object_in_relation(node, ATSPI_RELATION_FLOWS_FROM); + GArray *relations = atspi_accessible_get_relation_set(node, NULL); char result[SAFE_BUFFER_SIZE]; - int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s,%s]]", + int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]", unique_id, node_role_name, attributes, @@ -342,8 +312,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) box_size->height, node_name, states, - flows_to, - flows_from); + (relations && relations->len) ? "*" : ""); if (ret >= SAFE_BUFFER_SIZE) fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); @@ -358,10 +327,9 @@ static char *_get_info(AtspiAccessible *node, int length_limit) free(box_size); } free(states); - free(flows_to); - free(flows_from); + g_array_free(relations, TRUE); - return _strdup(result); + return g_strdup(result); } static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessible *parent_candidate, int parent_candidate_index) @@ -374,7 +342,7 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi char parent_status[NUMBER_WIDTH]; if (parent == NULL) - strcpy(parent_status, "_"); + strncpy(parent_status, "_", NUMBER_WIDTH); else snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index); @@ -441,11 +409,105 @@ void _print_help() printf("\tat_spi2_tool -i1 -c starter\n"); printf("\t show AT-SPI tree with integrity test for node \"starter\" using one-space indentation\n"); } + void _print_version() { printf("AT-SPI2-CORE-UTIL v%s\n", VERSION); } +static void _print_horizontal_line_in_relation_table() { + for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { + for (int j = 0; j < RELATION_COLUMN_WIDTH; j++) + printf("-"); + printf("+"); + } + printf("\n"); +} + +static void _print_legend_for_relation_table() { + char *table[] = {"OBJECT", "CONTROLLER_FOR", "CONTROLLED_BY", "FLOWS_TO", "FLOWS_FROM", "DESCRIBED_BY", "OTHER RELATION [ID]"}; + assert(ARRAY_SIZE(table) == RELATION_TABLE_COLUMN_COUNT); + for(int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) + printf("%*s|", RELATION_COLUMN_WIDTH , table[i]); + printf("\n"); + _print_horizontal_line_in_relation_table(); +} + +static char *_get_unique_id_of_object_in_relation(AtspiRelation *relation) { + if (!relation) + return NULL; + + gint last_index = atspi_relation_get_n_targets(relation) - 1; + AtspiAccessible *target = atspi_relation_get_target(relation, last_index); + return atspi_accessible_get_unique_id(target, NULL); +} + +static void _print_relations_for_object(AtspiAccessible *node) { + GArray *relations = atspi_accessible_get_relation_set(node, NULL); + if (!relations) + return; + + if (!relations->len) { + g_array_free(relations, FALSE); + return; + } + + char **table = calloc(RELATION_TABLE_COLUMN_COUNT, sizeof(char *)); + if (!table) { + fprintf(stderr, "Calloc failed. Can't alloc memory for object relations string\n"); + return; + } + + table[0] = atspi_accessible_get_unique_id(node, NULL); + for (int i = 0; i < relations->len; i++) { + AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i); + AtspiRelationType type = atspi_relation_get_relation_type(relation); + int idx; + switch (type) { + case ATSPI_RELATION_CONTROLLER_FOR: idx = 1; break; + case ATSPI_RELATION_CONTROLLED_BY: idx = 2; break; + case ATSPI_RELATION_FLOWS_TO: idx = 3; break; + case ATSPI_RELATION_FLOWS_FROM: idx = 4; break; + case ATSPI_RELATION_DESCRIBED_BY: idx = 5; break; + default: idx = 0; + } + + if (idx > 0) + table[idx] = _get_unique_id_of_object_in_relation(relation); + else { + char buf[16]; + snprintf(buf, sizeof(buf), " [%d]", type); + _combine_strings(&table[RELATION_TABLE_COLUMN_COUNT - 1], buf); + } + } + + for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { + printf("%*s|", RELATION_COLUMN_WIDTH, table[i] ? table[i] : ""); + free(table[i]); + } + free(table); + + printf("\n"); + _print_horizontal_line_in_relation_table(); + g_array_free(relations, TRUE); +} + +static void _print_relations_for_objects_in_tree(AtspiAccessible *node) { + _print_relations_for_object(node); + + int count = atspi_accessible_get_child_count(node, NULL); + for (int i = 0; i < count; i++) { + AtspiAccessible *child = atspi_accessible_get_child_at_index(node, i, NULL); + if (child) + _print_relations_for_objects_in_tree(child); + } +} + +static void _print_relations_table(AtspiAccessible *node) { + _print_legend_for_relation_table(); + _print_relations_for_objects_in_tree(node); +} + static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bool first_match, int length_limit) { @@ -460,7 +522,7 @@ static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bo 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 %d: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__); + fprintf(stderr, "\n%s, %s %d: Null application occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__); continue; } @@ -478,12 +540,15 @@ static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bo _test_atspi_parent_child_relation(child, desktop, i); _print_atspi_tree_verify_maybe_r(0, child, check, length_limit); + printf("\n"); + _print_relations_table(child); if (first_match) { free(name); break; - } else + } else { printf("\n"); + } free(name); } -- 2.7.4 From 73e22e1f4da152c9b77ecd2f5a0face5692c2a51 Mon Sep 17 00:00:00 2001 From: Pawel Kurowski Date: Mon, 17 Jul 2017 22:15:35 +0200 Subject: [PATCH 11/16] add attributes table to at_spi2_tool atributes table will be printed, when atributes string is too long add relations_found flag which tells if relation table legend should be printed Change-Id: I2a0b71f5e8b439881f5b83e9b7f1a17556f9e713 --- test/at_spi2_tool.c | 161 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 127 insertions(+), 34 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 15adca5..08c2af5 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -20,7 +20,9 @@ #define CHECK 1 #define FIRST_MATCH 2 #define RELATION_TABLE_COLUMN_COUNT 7 -#define RELATION_COLUMN_WIDTH 20 +#define ATTRIBUTE_TABLE_COLUMN_COUNT 3 +#define RELATION_TABLE_COLUMN_WIDTH 20 +#define ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH 20 #define VERSION "1.1" static unsigned indent_width = 2; @@ -260,7 +262,7 @@ static char *_get_states(AtspiAccessible *node, int length_limit) return state_string; } -static char *_get_attributes(AtspiAccessible *node, int length_limit) +static char *_get_attributes(AtspiAccessible *node, int length_limit, bool *attributes_are_too_long) { GHashTable *attributes = atspi_accessible_get_attributes(node, NULL); @@ -273,20 +275,24 @@ static char *_get_attributes(AtspiAccessible *node, int length_limit) g_hash_table_iter_init (&attributes_iter, attributes); char *result = NULL; while (g_hash_table_iter_next (&attributes_iter, &attr_key, &attr_value)) { - char attributes_string[ATTR_WIDTH]; - int ret = snprintf(attributes_string, ATTR_WIDTH, "(%s=%s)", (char *)attr_key, (char *)attr_value); - if (ret >= ATTR_WIDTH) - fprintf(stderr, "\n_get_attributes: generated string is too long. Buffer overflow\n"); + char attributes_string[SAFE_BUFFER_SIZE]; + int ret = snprintf(attributes_string, SAFE_BUFFER_SIZE, "(%s=%s)", (char *)attr_key, (char *)attr_value); + if (ret >= SAFE_BUFFER_SIZE) + fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); _combine_strings(&result, attributes_string); } g_hash_table_unref(attributes); - _truncate_string(result, length_limit); + int real_truncate_size = (length_limit < ATTR_WIDTH && length_limit > MINIMAL_MODULE_WIDTH) ? length_limit : ATTR_WIDTH; + if (result && attributes_are_too_long && strlen(result) > real_truncate_size) + *attributes_are_too_long = true; + + _truncate_string(result, real_truncate_size); return result; } -static char *_get_info(AtspiAccessible *node, int length_limit) +static char *_get_info(AtspiAccessible *node, int length_limit, bool *attributes_are_too_long, bool *app_has_relations) { if (!node) return NULL; @@ -295,11 +301,12 @@ static char *_get_info(AtspiAccessible *node, int length_limit) char *node_role_name = atspi_accessible_get_role_name(node, NULL); char *unique_id = atspi_accessible_get_unique_id(node, NULL); - char *attributes = _get_attributes(node, length_limit); + char *attributes = _get_attributes(node, length_limit, attributes_are_too_long); Box_Size *box_size = _get_box_size(node); char *states = _get_states(node, length_limit); GArray *relations = atspi_accessible_get_relation_set(node, NULL); + bool current_node_has_relations = (relations && relations->len); char result[SAFE_BUFFER_SIZE]; int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]", @@ -312,11 +319,14 @@ static char *_get_info(AtspiAccessible *node, int length_limit) box_size->height, node_name, states, - (relations && relations->len) ? "*" : ""); + current_node_has_relations ? "*" : ""); if (ret >= SAFE_BUFFER_SIZE) fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); + if (current_node_has_relations) + *app_has_relations = true; + free(node_name); free(node_role_name); free(unique_id); @@ -360,7 +370,8 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi printf("%-*s\t", CHECK_OUTPUT_WIDTH, output); } -static int _print_atspi_tree_verify_maybe_r(int indent_number, AtspiAccessible *object, bool check_integrity, int length_limit) +static int _print_atspi_tree_verify_maybe_r(int indent_number, AtspiAccessible *object, bool check_integrity, int length_limit, + bool *attributes_are_too_long, bool *app_has_relations) { char *indent = _multiply_string(' ', indent_number*indent_width); if (indent != NULL) { @@ -368,7 +379,7 @@ static int _print_atspi_tree_verify_maybe_r(int indent_number, AtspiAccessible * free(indent); } - char *node_info = _get_info(object, length_limit); + char *node_info = _get_info(object, length_limit, attributes_are_too_long, app_has_relations); if (node_info != NULL) { printf("%s\n", node_info); free(node_info); @@ -381,7 +392,7 @@ static int _print_atspi_tree_verify_maybe_r(int indent_number, AtspiAccessible * if (check_integrity) _test_atspi_parent_child_relation(child, object, i); - _print_atspi_tree_verify_maybe_r(indent_number + 1, child, check_integrity, length_limit); + _print_atspi_tree_verify_maybe_r(indent_number + 1, child, check_integrity, length_limit, attributes_are_too_long, app_has_relations); } } return 0; @@ -415,24 +426,15 @@ void _print_version() printf("AT-SPI2-CORE-UTIL v%s\n", VERSION); } -static void _print_horizontal_line_in_relation_table() { +static void _print_horizontal_line_in_relations_table() { for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { - for (int j = 0; j < RELATION_COLUMN_WIDTH; j++) + for (int j = 0; j < RELATION_TABLE_COLUMN_WIDTH; j++) printf("-"); printf("+"); } printf("\n"); } -static void _print_legend_for_relation_table() { - char *table[] = {"OBJECT", "CONTROLLER_FOR", "CONTROLLED_BY", "FLOWS_TO", "FLOWS_FROM", "DESCRIBED_BY", "OTHER RELATION [ID]"}; - assert(ARRAY_SIZE(table) == RELATION_TABLE_COLUMN_COUNT); - for(int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) - printf("%*s|", RELATION_COLUMN_WIDTH , table[i]); - printf("\n"); - _print_horizontal_line_in_relation_table(); -} - static char *_get_unique_id_of_object_in_relation(AtspiRelation *relation) { if (!relation) return NULL; @@ -482,32 +484,116 @@ static void _print_relations_for_object(AtspiAccessible *node) { } for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) { - printf("%*s|", RELATION_COLUMN_WIDTH, table[i] ? table[i] : ""); + printf("%*s|", RELATION_TABLE_COLUMN_WIDTH, table[i] ? table[i] : ""); free(table[i]); } free(table); printf("\n"); - _print_horizontal_line_in_relation_table(); + _print_horizontal_line_in_relations_table(); g_array_free(relations, TRUE); } -static void _print_relations_for_objects_in_tree(AtspiAccessible *node) { - _print_relations_for_object(node); +typedef void (*print_information_about_object_function)(AtspiAccessible *); + +static void _iterate_over_tree(print_information_about_object_function func, AtspiAccessible *node) { + func(node); int count = atspi_accessible_get_child_count(node, NULL); for (int i = 0; i < count; i++) { AtspiAccessible *child = atspi_accessible_get_child_at_index(node, i, NULL); if (child) - _print_relations_for_objects_in_tree(child); + _iterate_over_tree(func, child); } } +static void _print_relations_for_objects_in_tree(AtspiAccessible *node) { + _iterate_over_tree(_print_relations_for_object, node); +} + +static void _print_header_for_relation_table() { + char *table[] = {"OBJECT", "CONTROLLER_FOR", "CONTROLLED_BY", "FLOWS_TO", "FLOWS_FROM", "DESCRIBED_BY", "OTHER RELATION [ID]"}; + assert(ARRAY_SIZE(table) == RELATION_TABLE_COLUMN_COUNT); + + _print_horizontal_line_in_relations_table(); + + for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) + printf("%*s|", RELATION_TABLE_COLUMN_WIDTH , table[i]); + + printf("\n"); + _print_horizontal_line_in_relations_table(); +} + static void _print_relations_table(AtspiAccessible *node) { - _print_legend_for_relation_table(); + printf("\nRELATIONS TABLE\n"); + _print_header_for_relation_table(); _print_relations_for_objects_in_tree(node); } +static void _print_horizontal_line_in_attributes_table() { + int size_factor = 1; + for (int i = 0; i < ATTRIBUTE_TABLE_COLUMN_COUNT; i++) { + if (i == ATTRIBUTE_TABLE_COLUMN_COUNT - 1) + size_factor = 4; + for (int j = 0; j < ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * size_factor; j++) + printf("-"); + printf("+"); + } + printf("\n"); +} + +static void _print_attributes_for_object(AtspiAccessible *node) { + GHashTable *attributes = atspi_accessible_get_attributes(node, NULL); + + if (!attributes) + return; + + char *unique_id = atspi_accessible_get_unique_id(node, NULL); + GHashTableIter attributes_iter; + gpointer attr_key; + gpointer attr_value; + + g_hash_table_iter_init (&attributes_iter, attributes); + while (g_hash_table_iter_next (&attributes_iter, &attr_key, &attr_value)) { + printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH, unique_id ? unique_id : ""); + printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH, attr_key ? (char *) attr_key : ""); + printf("%*s|\n", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * 4, attr_value ? (char *) attr_value : ""); + } + + if (g_hash_table_size (attributes)) + _print_horizontal_line_in_attributes_table(); + + g_hash_table_unref(attributes); + free(unique_id); +} + +static void _print_attributes_for_objects_in_tree(AtspiAccessible *node) { + _iterate_over_tree(_print_attributes_for_object, node); +} + +static void _print_header_for_attributes_table() { + char *table[] = {"OBJECT", "ATTRIBUTE KEY", "ATTRIBUTE VALUE"}; + assert(ARRAY_SIZE(table) == ATTRIBUTE_TABLE_COLUMN_COUNT); + + _print_horizontal_line_in_attributes_table(); + + int size_factor = 1; + for (int i = 0; i < ATTRIBUTE_TABLE_COLUMN_COUNT; i++) { + if (i == ATTRIBUTE_TABLE_COLUMN_COUNT - 1) + size_factor = 4; + printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * size_factor , table[i]); + } + + printf("\n"); + _print_horizontal_line_in_attributes_table(); +} + +static void _print_attributes_table(AtspiAccessible *node) { + printf("\nATTRIBUTES TABLE\n"); + _print_header_for_attributes_table(); + _print_attributes_for_objects_in_tree(node); +} + static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bool first_match, int length_limit) { @@ -519,6 +605,7 @@ static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bo 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) { @@ -527,6 +614,8 @@ static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bo } char *name = atspi_accessible_get_name(child, NULL); + bool attributes_are_too_long = false; + bool app_has_relations = false; if (!dump && !check) printf("%s\n", name); @@ -539,9 +628,13 @@ static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bo if (check) _test_atspi_parent_child_relation(child, desktop, i); - _print_atspi_tree_verify_maybe_r(0, child, check, length_limit); - printf("\n"); - _print_relations_table(child); + _print_atspi_tree_verify_maybe_r(0, child, check, length_limit, &attributes_are_too_long, &app_has_relations); + + if (app_has_relations) + _print_relations_table(child); + + if (attributes_are_too_long) + _print_attributes_table(child); if (first_match) { free(name); @@ -647,7 +740,7 @@ static void _run_command(int argc, char *argv[]) case 'a': enable_at_spi_client = TRUE; - if(optarg[0] == 'f' || optarg[0] == '0') + if (optarg[0] == 'f' || optarg[0] == '0') enable_at_spi_client = FALSE; _at_spi_client_enable(enable_at_spi_client); -- 2.7.4 From 2c0f9a891f49d36cb5d133dd0f54d96e77283cf2 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 19 Jul 2017 15:15:28 +0900 Subject: [PATCH 12/16] bus: follow D-bus policy Tizen D-bus policy does not support Smack rule. The following patch set of D-bus probably affects dbus-daemon which is used for accessibility. https://review.tizen.org/gerrit/#/c/133270/ It was not possilbe to launch dbus-daemon with following error message. org.a11y.Bus[2457]: Failed to start message bus: Attribute "smack" is invalid on element in this context org.a11y.Bus[2457]: Failed to launch bus: Bus exited with code 1 Change-Id: I67435b1a27f91193348d1e699805b6d09be8fddc --- bus/accessibility.conf.in | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/bus/accessibility.conf.in b/bus/accessibility.conf.in index 77f12f8..9336ad7 100644 --- a/bus/accessibility.conf.in +++ b/bus/accessibility.conf.in @@ -8,28 +8,11 @@ unix:tmpdir=/tmp - owner - - - - - - - + - - - - - - - - - - -- 2.7.4 From 87ea2e308098bb8fb316fc5fc7fd39141dfbc51d Mon Sep 17 00:00:00 2001 From: Mariusz Wachowicz Date: Thu, 10 Aug 2017 11:29:48 +0200 Subject: [PATCH 13/16] move ref_accessible function to public scope this function is needed outside at-spi library (other projects, e.g. universal-switch), to get AtspiAccessible object after it has been received as application name and path name Change-Id: I51e72af3f191d4a14174cd0b4819522154e3e1ba --- atspi/atspi-misc.c | 10 +++++----- atspi/atspi-misc.h | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 193257b..02eab8c 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -260,7 +260,7 @@ get_application (const char *bus_name) return app; } -static AtspiAccessible * +AtspiAccessible * ref_accessible (const char *app_name, const char *path) { AtspiApplication *app; @@ -1149,11 +1149,12 @@ out: process_deferred_messages (); if (dbus_error_is_set (&err)) { - /* TODO: Set gerror */ + g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, err.message); dbus_error_free (&err); + if (reply) + dbus_message_unref(reply); } - - if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + else if (reply && dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { const char *err_str = NULL; dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &err_str, DBUS_TYPE_INVALID); @@ -1162,7 +1163,6 @@ out: dbus_message_unref (reply); return NULL; } - return reply; } diff --git a/atspi/atspi-misc.h b/atspi/atspi-misc.h index f13596f..e39d7b8 100644 --- a/atspi/atspi-misc.h +++ b/atspi/atspi-misc.h @@ -47,6 +47,9 @@ void atspi_set_main_context (GMainContext *cnx); gchar * atspi_role_get_name (AtspiRole role); + +AtspiAccessible *ref_accessible(const char *app_name, const char *path); + G_END_DECLS #endif /* _ATSPI_MISC_H_ */ -- 2.7.4 From 9dc6aaf0f801e52d145783e15125148efec16bae Mon Sep 17 00:00:00 2001 From: Bowon Ryu Date: Fri, 11 Aug 2017 16:10:56 +0900 Subject: [PATCH 14/16] at_spi2_tool: Apply ASLR to executable files. Change-Id: I86b9dd51723548d1b888eed7847668ca9e318110 Signed-off-by: Bowon Ryu --- test/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 828f126..bb9acb9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,8 +3,8 @@ 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 = $(GIO_CFLAGS) $(GLIB_CFLAGS) --std=c99 -Wall $(GOBJ_LIBS) $(DBUS_CFLAGS) -at_spi2_tool_LDFLAGS = $(GIO_LIBS) +at_spi2_tool_CFLAGS = $(GIO_CFLAGS) $(GLIB_CFLAGS) --std=c99 -Wall -fPIE $(GOBJ_LIBS) $(DBUS_CFLAGS) +at_spi2_tool_LDFLAGS = $(GIO_LIBS) -pie noinst_PROGRAMS = memory -- 2.7.4 From adf4836bec89de9e7a93a6988c7ae6ea7870936c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Stawicki?= Date: Mon, 5 Jun 2017 17:40:47 +0200 Subject: [PATCH 15/16] at-spi-bus-launcher: launch universal-switch Change-Id: I16bff1e30b2c72c812be767f1b21f88a65ee1787 --- bus/at-spi-bus-launcher.c | 197 +++++++++++++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 72 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index bb6f9f9..7948d1b 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -35,7 +35,11 @@ #include #endif +//TODO: move to vconf/vconf-internal-setting-keys.h? +#define VCONFKEY_SETAPPL_ACCESSIBILITY_UNIVERSAL_SWITCH "db/setting/accessibility/universal-switch" + #define APP_CONTROL_OPERATION_SCREEN_READ "http://tizen.org/appcontrol/operation/read_screen" +#define APP_CONTROL_OPERATION_UNIVERSAL_SWITCH "http://tizen.org/appcontrol/operation/universal_switch" #include #include @@ -64,7 +68,7 @@ FILE *log_file; #define LOGD(arg...) do {if (log_file) {fprintf(log_file, ##arg);fprintf(log_file, "\n"); fflush(log_file);}} while(0) #endif -static gboolean _launch_screen_reader_repeat_until_success(gpointer user_data); +static gboolean _launch_process_repeat_until_success(gpointer user_data); typedef enum { A11Y_BUS_STATE_IDLE = 0, @@ -74,6 +78,14 @@ typedef enum { } A11yBusState; typedef struct { + const char * name; + const char * app_control_operation; + const char * vconf_key; + int launch_repeats; + int pid; +} A11yBusClient; + +typedef struct { GMainLoop *loop; gboolean launch_immediately; gboolean a11y_enabled; @@ -83,9 +95,8 @@ typedef struct { GSettings *a11y_schema; GSettings *interface_schema; - int launch_screen_reader_repeats; - gboolean screen_reader_needed; - int pid; + A11yBusClient screen_reader; + A11yBusClient universal_switch; A11yBusState state; @@ -662,24 +673,43 @@ gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data) } static int -_screen_reader_dead_tracker (int pid, void *data) +_process_dead_tracker (int pid, void *data) { A11yBusLauncher *app = data; - if (app->pid > 0 && pid == app->pid) + if (app->screen_reader.pid > 0 && pid == app->screen_reader.pid) { LOGE("screen reader is dead, pid: %d, restarting", pid); - app->pid = 0; - g_timeout_add_seconds (2, _launch_screen_reader_repeat_until_success, app); + app->screen_reader.pid = 0; + g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->screen_reader); + } + + if (app->universal_switch.pid > 0 && pid == app->universal_switch.pid) + { + LOGE("universal switch is dead, pid: %d, restarting", pid); + app->universal_switch.pid = 0; + g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->universal_switch); } return 0; } +static void +_register_process_dead_tracker () +{ + if(_global_app->screen_reader.pid > 0 || _global_app->universal_switch.pid > 0) { + LOGD("registering process dead tracker"); + aul_listen_app_dead_signal(_process_dead_tracker, _global_app); + } else { + LOGD("unregistering process dead tracker"); + aul_listen_app_dead_signal(NULL, NULL); + } +} + + static gboolean -_launch_screen_reader(gpointer user_data, gboolean by_vconf_change) +_launch_client(A11yBusClient *client, gboolean by_vconf_change) { - A11yBusLauncher *bl = user_data; - LOGD("Launching screen reader"); + LOGD("Launching %s", client->name); bundle *kb = NULL; gboolean ret = FALSE; @@ -700,120 +730,147 @@ _launch_screen_reader(gpointer user_data, gboolean by_vconf_change) } } - int operation_error = appsvc_set_operation(kb, APP_CONTROL_OPERATION_SCREEN_READ); + int operation_error = appsvc_set_operation(kb, client->app_control_operation); LOGD("appsvc_set_operation: %i", operation_error); - bl->pid = appsvc_run_service(kb, 0, NULL, NULL); + client->pid = appsvc_run_service(kb, 0, NULL, NULL); - if (bl->pid > 0) + if (client->pid > 0) { - LOGD("Screen reader launched with pid: %i", bl->pid); - LOGD("registering screen reader dead tracker"); - aul_listen_app_dead_signal(_screen_reader_dead_tracker, bl); + LOGD("Process launched with pid: %i", client->pid); + _register_process_dead_tracker(); ret = TRUE; } else { - LOGD("Can't start screen-reader - error code: %i", bl->pid); + LOGD("Can't start %s - error code: %i", client->name, client->pid); } - bundle_free(kb); return ret; } static gboolean -_launch_screen_reader_repeat_until_success(gpointer user_data) { - A11yBusLauncher *bl = user_data; +_launch_process_repeat_until_success(gpointer user_data) { + A11yBusClient *client = user_data; - if (bl->launch_screen_reader_repeats > 100 || bl->pid > 0) + if (client->launch_repeats > 100 || client->pid > 0) { //do not try anymore return FALSE; } - gboolean ret = _launch_screen_reader(user_data, FALSE); + gboolean ret = _launch_client(client, FALSE); if (ret) { //we managed to - bl->launch_screen_reader_repeats = 0; + client->launch_repeats = 0; return FALSE; } + client->launch_repeats++; //try again return TRUE; } static gboolean -_terminate_screen_reader(A11yBusLauncher *bl) +_terminate_process(int pid) { - LOGD("Terminating screen reader"); int ret; int ret_aul; - if (bl->pid <= 0) + if (pid <= 0) return FALSE; - - LOGD("unregistering screen reader dead tracker"); - aul_listen_app_dead_signal(NULL, NULL); - - int status = aul_app_get_status_bypid(bl->pid); + int status = aul_app_get_status_bypid(pid); if (status < 0) { - LOGD("App with pid %d already terminated", bl->pid); - bl->pid = 0; + LOGD("App with pid %d already terminated", pid); return TRUE; } - LOGD("terminate process with pid %d", bl->pid); - ret_aul = aul_terminate_pid(bl->pid); + LOGD("terminate process with pid %d", pid); + ret_aul = aul_terminate_pid(pid); if (ret_aul >= 0) { LOGD("Terminating with aul_terminate_pid: return is %d", ret_aul); - bl->pid = 0; return TRUE; } else LOGD("aul_terminate_pid failed: return is %d", ret_aul); LOGD("Unable to terminate process using aul api. Sending SIGTERM signal"); - ret = kill(bl->pid, SIGTERM); + ret = kill(pid, SIGTERM); if (!ret) { - bl->pid = 0; return TRUE; } - LOGD("Unable to terminate process: %d with api or signal.", bl->pid); + LOGD("Unable to terminate process: %d with api or signal.", pid); return FALSE; } -void screen_reader_cb(keynode_t *node, void *user_data) +static gboolean +_terminate_client(A11yBusClient *client) { - A11yBusLauncher *bl = user_data; - int ret; + LOGD("Terminating %s", client->name); + int pid = client->pid; + client->pid = 0; + _register_process_dead_tracker(); + gboolean ret = _terminate_process(pid); + return ret; +} - ret = vconf_keynode_get_bool(node); - LOGD("vconf_keynode_get_bool(node): %i", ret); - if (ret < 0) +void vconf_client_cb(keynode_t *node, void *user_data) +{ + A11yBusClient *client = user_data; + int client_needed = vconf_keynode_get_bool(node); + LOGD("vconf_keynode_get_bool(node): %i", client_needed); + if (client_needed < 0) return; //check if process really exists (e.g didn't crash) - if (bl->pid > 0) + if (client->pid > 0) { - int err = kill(bl->pid,0); + int err = kill(client->pid,0); //process doesn't exist if (err == ESRCH) - bl->pid = 0; + client->pid = 0; } - bl->screen_reader_needed = ret; - LOGD("bl->screen_reader_needed: %i, bl->pid: %i", ret, bl->pid); - if (!bl->screen_reader_needed && (bl->pid > 0)) - _terminate_screen_reader(bl); - else if (bl->screen_reader_needed && (bl->pid <= 0)) - _launch_screen_reader(bl, TRUE); + LOGD("client_needed: %i, client->pid: %i", client_needed, client->pid); + if (!client_needed && (client->pid > 0)) + _terminate_client(client); + else if (client_needed && (client->pid <= 0)) + _launch_client(client, TRUE); +} + + +static gboolean register_client(A11yBusClient *client) +{ + gboolean client_needed = FALSE; + + if(!client->vconf_key) { + LOGE("Vconf_key missing for client: %s \n", client->vconf_key); + return FALSE; + } + + int ret = vconf_get_bool(client->vconf_key, &client_needed); + if (ret != 0) + { + LOGD("Could not read %s key value.\n", client->vconf_key); + return FALSE; + } + ret = vconf_notify_key_changed(client->vconf_key, vconf_client_cb, client); + if(ret != 0) + { + LOGD("Could not add information level callback\n"); + return FALSE; + } + + if (client_needed) + g_timeout_add_seconds(2,_launch_process_repeat_until_success, client); + return TRUE; } int @@ -825,7 +882,6 @@ main (int argc, #endif LOGD("Starting atspi bus launcher"); - int name_owner_id; gboolean a11y_set = FALSE; gboolean screen_reader_set = FALSE; gint i; @@ -838,9 +894,16 @@ 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); + _global_app->screen_reader.name = "screen-reader"; + _global_app->screen_reader.app_control_operation = APP_CONTROL_OPERATION_SCREEN_READ; + _global_app->screen_reader.vconf_key = VCONFKEY_SETAPPL_ACCESSIBILITY_TTS; + + _global_app->universal_switch.name = "universal-switch"; + _global_app->universal_switch.app_control_operation = APP_CONTROL_OPERATION_UNIVERSAL_SWITCH; + _global_app->universal_switch.vconf_key = VCONFKEY_SETAPPL_ACCESSIBILITY_UNIVERSAL_SWITCH; + for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "--launch-immediately")) @@ -886,7 +949,7 @@ main (int argc, introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (introspection_data != NULL); - name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, + g_bus_own_name (G_BUS_TYPE_SESSION, "org.a11y.Bus", G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, on_bus_acquired, @@ -895,20 +958,10 @@ main (int argc, _global_app, NULL); - int ret = vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &_global_app->screen_reader_needed); - if (ret != 0) - { - LOGD("Could not read VCONFKEY_SETAPPL_ACCESSIBILITY_TTS key value.\n"); - return FALSE; - } - ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, screen_reader_cb, _global_app); - if(ret != 0) - { - LOGD("Could not add information level callback\n"); - return FALSE; - } - if (_global_app->screen_reader_needed) - g_timeout_add_seconds(2,_launch_screen_reader_repeat_until_success, _global_app); + if(!register_client(&_global_app->screen_reader)) + return FALSE; + if(!register_client(&_global_app->universal_switch)) + return FALSE; g_main_loop_run (_global_app->loop); -- 2.7.4 From f0a290a4980997257594fd44f0ba4b71689edb7b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Stawicki?= Date: Thu, 7 Sep 2017 12:37:38 +0200 Subject: [PATCH 16/16] bugfix: at-spi-bus-launcher terminates when unviersal-switch vconf key not defined Change-Id: I4a891f300aeb4261938a9e5dbdf4cdf5749c7d05 --- bus/at-spi-bus-launcher.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 7948d1b..d180a15 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -958,10 +958,8 @@ main (int argc, _global_app, NULL); - if(!register_client(&_global_app->screen_reader)) - return FALSE; - if(!register_client(&_global_app->universal_switch)) - return FALSE; + register_client (&_global_app->screen_reader); + register_client (&_global_app->universal_switch); g_main_loop_run (_global_app->loop); -- 2.7.4