From 3c791208d80c80e44f602f1958cad46cfce50040 Mon Sep 17 00:00:00 2001 From: Radoslaw Cybulski Date: Tue, 6 Dec 2016 18:34:15 +0100 Subject: [PATCH 01/16] fix for non-navigatable end call window in call-ui application, by Mr Shin-Woo Kim Change-Id: I3c6fc0163e1bacac5ea3518c181cc7ef69cec62f --- atspi/atspi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 48759ca..fdb4e9b 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -387,7 +387,7 @@ handle_name_owner_changed (DBusConnection *bus, DBusMessage *message, void *user else if (app_hash) { AtspiApplication *app = g_hash_table_lookup (app_hash, old); - if (app && app->bus_name && !strcmp(app->bus_name, name)) + if (app && name && app->bus_name && !strcmp(app->bus_name, name)) g_object_run_dispose (G_OBJECT (app)); } return DBUS_HANDLER_RESULT_HANDLED; -- 2.7.4 From a589caf6449fd0feccc0b9bf6f14a27ce58d7e5d Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Tue, 13 Dec 2016 10:34:13 +0900 Subject: [PATCH 02/16] Fix SVACE issue WID164553 - name is not NULL always Change-Id: Idff718d0416e98a0556f9421f1d3c76235756ab7 --- atspi/atspi-misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index fdb4e9b..48759ca 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -387,7 +387,7 @@ handle_name_owner_changed (DBusConnection *bus, DBusMessage *message, void *user else if (app_hash) { AtspiApplication *app = g_hash_table_lookup (app_hash, old); - if (app && name && app->bus_name && !strcmp(app->bus_name, name)) + if (app && app->bus_name && !strcmp(app->bus_name, name)) g_object_run_dispose (G_OBJECT (app)); } return DBUS_HANDLER_RESULT_HANDLED; -- 2.7.4 From 0b029582159e4080824a651c6b358f38cd5610ef Mon Sep 17 00:00:00 2001 From: Lukasz Wlazly Date: Mon, 23 Jan 2017 16:14:17 +0100 Subject: [PATCH 03/16] at_spi2_tool refactor Change-Id: I4140f479b95a1a5e91be3654f549ee845757db42 --- test/at_spi2_tool.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 594a7c8..743b90c 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -340,7 +340,7 @@ static char *_get_info(AtspiAccessible *node, int length_limit) _get_object_in_relation(node, ATSPI_RELATION_FLOWS_FROM)); if (ret >= SAFE_BUFFER_SIZE) - fprintf(stderr, "\n_get_info: generated string is too long. Buffer overflow\n"); + fprintf(stderr, "\n%s, %s %s: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); free(node_name); free(node_role_name); @@ -436,8 +436,10 @@ static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, 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) - break; + if (child == NULL) { + fprintf(stderr, "\n%s, %s %s: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__); + continue; + } char *name = atspi_accessible_get_name(child, NULL); -- 2.7.4 From 2a9f101b5bdcd8f382b6a730750e0352f711fd72 Mon Sep 17 00:00:00 2001 From: Radoslaw Cybulski Date: Tue, 21 Feb 2017 15:55:05 +0100 Subject: [PATCH 04/16] Add ability to retrieve atspi object's path, which uniquely identifies atspi object across all processes Change-Id: I60fba10c202845427f247814db40436f01fe3117 --- atspi/Makefile.am | 4 +- atspi/atspi-accessible.c | 96 ++++++++++++++++++++++++++++++------------------ atspi/atspi-accessible.h | 6 ++- test/at_spi2_tool.c | 17 +++++---- 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/atspi/Makefile.am b/atspi/Makefile.am index a860fcc..9944d44 100644 --- a/atspi/Makefile.am +++ b/atspi/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libatspi.la libatspi_la_LDFLAGS = @LDFLAGS@ @LT_VERSION_INFO@ @LIBTOOL_EXPORT_OPTIONS@ -no-undefined -libatspi_la_CFLAGS = $(DBUS_CFLAGS) \ +libatspi_la_CFLAGS = $(DBUS_CFLAGS) $(AUL_CFLAGS) \ $(DBIND_CFLAGS) \ $(GLIB_CFLAGS) \ -I$(top_srcdir)/registryd \ @@ -10,7 +10,7 @@ libatspi_la_CFLAGS = $(DBUS_CFLAGS) \ -I$(top_builddir) \ -I$(top_srcdir) -libatspi_la_LIBADD = $(DBUS_LIBS) \ +libatspi_la_LIBADD = $(DBUS_LIBS) $(AUL_LIBS) \ $(GOBJ_LIBS) \ $(X_LIBS) \ $(top_builddir)/dbind/libdbind.la diff --git a/atspi/atspi-accessible.c b/atspi/atspi-accessible.c index 2d77357..c3392bd 100644 --- a/atspi/atspi-accessible.c +++ b/atspi/atspi-accessible.c @@ -220,7 +220,7 @@ atspi_accessible_class_init (AtspiAccessibleClass *klass) * * Gets the name of an #AtspiAccessible object. * - * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object + * Returns: a UTF-8 string indicating the name of the #AtspiAccessible object * or NULL on exception. **/ gchar * @@ -238,12 +238,37 @@ atspi_accessible_get_name (AtspiAccessible *obj, GError **error) } /** + * atspi_accessible_get_path: + * @obj: a pointer to the #AtspiAccessible object on which to operate. + * + * Gets the path, uniquely identifying object. + * + * Returns: a UTF-8 string describing the #AtspiAccessible object + * or empty string on exception or NULL object passed. + **/ +gchar * +atspi_accessible_get_path(AtspiAccessible *obj, GError **error) +{ + static const char *prefix = "/org/a11y/atspi/accessible/"; + static int prefix_len = 27; + + if (!obj) + return g_strdup(""); + AtspiObject *o = ATSPI_OBJECT (obj); + if (!o) + return g_strdup(""); + if (strncmp(o->path, prefix, prefix_len) == 0) + return g_strdup(o->path + prefix_len); + return g_strdup (o->path); +} + +/** * atspi_accessible_get_description: * @obj: a pointer to the #AtspiAccessible object on which to operate. * * Gets the description of an #AtspiAccessible object. * - * Returns: a UTF-8 string describing the #AtspiAccessible object + * Returns: a UTF-8 string describing the #AtspiAccessible object * or NULL on exception. **/ gchar * @@ -378,7 +403,7 @@ atspi_accessible_get_child_at_index (AtspiAccessible *obj, * atspi_accessible_get_index_in_parent: * @obj: a pointer to the #AtspiAccessible object on which to operate. * - * Gets the index of an #AtspiAccessible object within its parent's + * Gets the index of an #AtspiAccessible object within its parent's * #AtspiAccessible children list. * * Returns: a #glong indicating the index of the #AtspiAccessible object @@ -523,12 +548,12 @@ atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error) * atspi_accessible_get_localized_role_name: * @obj: a pointer to the #AtspiAccessible object on which to operate. * - * Gets a UTF-8 string corresponding to the name of the role played by an + * Gets a UTF-8 string corresponding to the name of the role played by an * object, translated to the current locale. * This method will return useful values for roles that fall outside the * enumeration used in atspi_accessible_getRole (). * - * Returns: a localized, UTF-8 string specifying the type of UI role played + * Returns: a localized, UTF-8 string specifying the type of UI role played * by an #AtspiAccessible object. * **/ @@ -583,7 +608,6 @@ atspi_accessible_get_state_set (AtspiAccessible *obj) dbus_message_unref (reply); _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES); } - return g_object_ref (obj->states); } @@ -591,7 +615,7 @@ atspi_accessible_get_state_set (AtspiAccessible *obj) * atspi_accessible_get_attributes: * @obj: The #AtspiAccessible being queried. * - * Gets the #AttributeSet representing any assigned + * Gets the #AttributeSet representing any assigned * name-value pair attributes or annotations for this object. * For typographic, textual, or textually-semantic attributes, see * atspi_text_get_attributes instead. @@ -638,7 +662,7 @@ add_to_attribute_array (gpointer key, gpointer value, gpointer data) * atspi_accessible_get_attributes_as_array: * @obj: The #AtspiAccessible being queried. * - * Gets a #GArray representing any assigned + * Gets a #GArray representing any assigned * name-value pair attributes or annotations for this object. * For typographic, textual, or textually-semantic attributes, see * atspi_text_get_attributes_as_array instead. @@ -796,7 +820,7 @@ atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error) * Gets the application id for a #AtspiAccessible object. * Only works on application root objects. * - * Returns: a positive #gint indicating the id for the #AtspiAccessible object + * Returns: a positive #gint indicating the id for the #AtspiAccessible object * or -1 on exception. **/ gint @@ -847,7 +871,7 @@ _atspi_accessible_is_a (AtspiAccessible *accessible, * atspi_accessible_is_action: * @obj: a pointer to the #AtspiAccessible instance to query. * - * Query whether the specified #AtspiAccessible implements the + * Query whether the specified #AtspiAccessible implements the * #AtspiAction interface. * * Returns: #TRUE if @obj implements the #AtspiAction interface, @@ -877,7 +901,7 @@ atspi_accessible_is_application (AtspiAccessible *obj) atspi_interface_application); } -/** +/** * atspi_accessible_is_collection: * @obj: a pointer to the #AtspiAccessible instance to query. * @@ -943,7 +967,7 @@ atspi_accessible_is_editable_text (AtspiAccessible *obj) return _atspi_accessible_is_a (obj, atspi_interface_editable_text); } - + /** * atspi_accessible_is_hypertext: * @obj: a pointer to the #AtspiAccessible instance to query. @@ -965,7 +989,7 @@ atspi_accessible_is_hypertext (AtspiAccessible *obj) * atspi_accessible_is_hyperlink: * @obj: a pointer to the #AtspiAccessible instance to query. * - * Query whether the specified #AtspiAccessible implements the + * Query whether the specified #AtspiAccessible implements the * #AtspiHyperlink interface. * * Returns: #TRUE if @obj implements the #AtspiHypertext interface, @@ -1072,7 +1096,7 @@ atspi_accessible_is_streamable_content (AtspiAccessible *obj) * atspi_accessible_is_text: * @obj: a pointer to the #AtspiAccessible instance to query. * - * Query whether the specified #AtspiAccessible implements the + * Query whether the specified #AtspiAccessible implements the * #AtspiText interface. * * Returns: #TRUE if @obj implements the #AtspiText interface, @@ -1117,7 +1141,7 @@ AtspiAction * atspi_accessible_get_action (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_action) ? - g_object_ref (ATSPI_ACTION (accessible)) : NULL); + g_object_ref (ATSPI_ACTION (accessible)) : NULL); } /** @@ -1133,7 +1157,7 @@ AtspiAction * atspi_accessible_get_action_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_action) ? - g_object_ref (ATSPI_ACTION (accessible)) : NULL); + g_object_ref (ATSPI_ACTION (accessible)) : NULL); } /** @@ -1151,7 +1175,7 @@ AtspiCollection * atspi_accessible_get_collection (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ? - g_object_ref (ATSPI_COLLECTION (accessible)) : NULL); + g_object_ref (ATSPI_COLLECTION (accessible)) : NULL); } /** @@ -1167,7 +1191,7 @@ AtspiCollection * atspi_accessible_get_collection_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ? - g_object_ref (ATSPI_COLLECTION (accessible)) : NULL); + g_object_ref (ATSPI_COLLECTION (accessible)) : NULL); } /** @@ -1219,7 +1243,7 @@ AtspiDocument * atspi_accessible_get_document (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_document) ? - g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL); + g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL); } /** @@ -1235,7 +1259,7 @@ AtspiDocument * atspi_accessible_get_document_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_document) ? - g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL); + g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL); } /** @@ -1253,7 +1277,7 @@ AtspiEditableText * atspi_accessible_get_editable_text (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ? - g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL); + g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL); } /** @@ -1269,7 +1293,7 @@ AtspiEditableText * atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ? - g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL); + g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL); } /** @@ -1303,7 +1327,7 @@ AtspiHypertext * atspi_accessible_get_hypertext (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ? - g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL); + g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL); } /** @@ -1319,7 +1343,7 @@ AtspiHypertext * atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ? - g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL); + g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL); } /** @@ -1337,7 +1361,7 @@ AtspiImage * atspi_accessible_get_image (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_image) ? - g_object_ref (ATSPI_IMAGE (accessible)) : NULL); + g_object_ref (ATSPI_IMAGE (accessible)) : NULL); } /** @@ -1353,7 +1377,7 @@ AtspiImage * atspi_accessible_get_image_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_image) ? - g_object_ref (ATSPI_IMAGE (accessible)) : NULL); + g_object_ref (ATSPI_IMAGE (accessible)) : NULL); } /** @@ -1371,7 +1395,7 @@ AtspiSelection * atspi_accessible_get_selection (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ? - g_object_ref (ATSPI_SELECTION (accessible)) : NULL); + g_object_ref (ATSPI_SELECTION (accessible)) : NULL); } /** @@ -1387,7 +1411,7 @@ AtspiSelection * atspi_accessible_get_selection_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ? - g_object_ref (ATSPI_SELECTION (accessible)) : NULL); + g_object_ref (ATSPI_SELECTION (accessible)) : NULL); } #if 0 @@ -1404,7 +1428,7 @@ AtspiStreamableContent * atspi_accessible_get_streamable_content (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ? - accessible : NULL); + accessible : NULL); } #endif @@ -1423,7 +1447,7 @@ AtspiTable * atspi_accessible_get_table (AtspiAccessible *obj) { return (_atspi_accessible_is_a (obj, atspi_interface_table) ? - g_object_ref (ATSPI_TABLE (obj)) : NULL); + g_object_ref (ATSPI_TABLE (obj)) : NULL); } /** @@ -1439,7 +1463,7 @@ AtspiTable * atspi_accessible_get_table_iface (AtspiAccessible *obj) { return (_atspi_accessible_is_a (obj, atspi_interface_table) ? - g_object_ref (ATSPI_TABLE (obj)) : NULL); + g_object_ref (ATSPI_TABLE (obj)) : NULL); } /** @@ -1455,7 +1479,7 @@ AtspiTableCell * atspi_accessible_get_table_cell (AtspiAccessible *obj) { return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ? - g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL); + g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL); } /** @@ -1507,7 +1531,7 @@ AtspiValue * atspi_accessible_get_value (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_value) ? - g_object_ref (ATSPI_VALUE (accessible)) : NULL); + g_object_ref (ATSPI_VALUE (accessible)) : NULL); } /** @@ -1523,7 +1547,7 @@ AtspiValue * atspi_accessible_get_value_iface (AtspiAccessible *accessible) { return (_atspi_accessible_is_a (accessible, atspi_interface_value) ? - g_object_ref (ATSPI_VALUE (accessible)) : NULL); + g_object_ref (ATSPI_VALUE (accessible)) : NULL); } static void @@ -1583,11 +1607,11 @@ atspi_accessible_get_interfaces (AtspiAccessible *obj) return ret; } -AtspiAccessible * +AtspiAccessible * _atspi_accessible_new (AtspiApplication *app, const gchar *path) { AtspiAccessible *accessible; - + accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL); g_return_val_if_fail (accessible != NULL, NULL); diff --git a/atspi/atspi-accessible.h b/atspi/atspi-accessible.h index 2c3f8cc..f07394e 100644 --- a/atspi/atspi-accessible.h +++ b/atspi/atspi-accessible.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 @@ -66,7 +66,7 @@ struct _AtspiAccessibleClass AtspiObjectClass parent_class; }; -GType atspi_accessible_get_type (void); +GType atspi_accessible_get_type (void); AtspiAccessible * _atspi_accessible_new (AtspiApplication *app, const gchar *path); @@ -75,6 +75,8 @@ gchar * atspi_accessible_get_name (AtspiAccessible *obj, GError **error); gchar * atspi_accessible_get_description (AtspiAccessible *obj, GError **error); +gchar * atspi_accessible_get_path (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 743b90c..badaaa3 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -287,15 +287,15 @@ static char *_get_attributes(AtspiAccessible *node, int length_limit) return result; } -static AtspiAccessible *_get_object_in_relation(AtspiAccessible *source, AtspiRelationType search_type) +static char *_get_object_in_relation(AtspiAccessible *source, AtspiRelationType search_type) { if (source == NULL) - return NULL; + return ""; GArray *relations = atspi_accessible_get_relation_set(source, NULL); if (relations == NULL) - return NULL; + return ""; AtspiAccessible *ret = NULL; for (int i = 0; i < relations->len; ++i) { @@ -310,7 +310,7 @@ static AtspiAccessible *_get_object_in_relation(AtspiAccessible *source, AtspiRe g_array_free(relations, TRUE); - return ret; + return ret ? atspi_accessible_get_path(ret, NULL) : g_strdup(""); } static char *_get_info(AtspiAccessible *node, int length_limit) @@ -320,14 +320,15 @@ 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 *attributes = _get_attributes(node, length_limit); Box_Size *box_size = _get_box_size(node); char *states = _get_states(node, length_limit); char result[SAFE_BUFFER_SIZE]; - int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%p],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%p,%p]]", - node, + int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s,%s]]", + path, node_role_name, attributes, box_size->x, @@ -369,7 +370,9 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi else snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index); - snprintf(output, CHECK_OUTPUT_WIDTH, "[FAIL<%d,%s><%p,%p>]", parent_candidate_index, parent_status, parent_candidate, parent); + snprintf(output, CHECK_OUTPUT_WIDTH, "[FAIL<%d,%s><%s,%s>]", parent_candidate_index, parent_status, + atspi_accessible_get_path(parent_candidate, NULL), + atspi_accessible_get_path(parent, NULL)); } else { snprintf(output, CHECK_OUTPUT_WIDTH, "[OK]"); -- 2.7.4 From b95659e66457646684e98ccbd878e2fb346b489c Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Mon, 27 Mar 2017 12:56:54 +0900 Subject: [PATCH 05/16] tool: fix memory leak Change-Id: I90c8f22d555c36db6f66e2250e333bf32ea86d8e --- test/at_spi2_tool.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index badaaa3..2eae131 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -326,6 +326,9 @@ 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); + char result[SAFE_BUFFER_SIZE]; int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s,%s]]", path, @@ -337,14 +340,15 @@ static char *_get_info(AtspiAccessible *node, int length_limit) box_size->height, node_name, states, - _get_object_in_relation(node, ATSPI_RELATION_FLOWS_TO), - _get_object_in_relation(node, ATSPI_RELATION_FLOWS_FROM)); + 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__); free(node_name); free(node_role_name); + free(path); free(attributes); if (box_size) { free(box_size->width); @@ -352,6 +356,8 @@ static char *_get_info(AtspiAccessible *node, int length_limit) free(box_size); } free(states); + free(flows_to); + free(flows_from); return _strdup(result); } @@ -370,9 +376,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); snprintf(output, CHECK_OUTPUT_WIDTH, "[FAIL<%d,%s><%s,%s>]", parent_candidate_index, parent_status, - atspi_accessible_get_path(parent_candidate, NULL), - atspi_accessible_get_path(parent, NULL)); + parent_candidate_path, parent_path); + free(parent_path); + free(parent_candidate_path); } else { snprintf(output, CHECK_OUTPUT_WIDTH, "[OK]"); -- 2.7.4 From 576781b36f2d342e20acdf750b7b19d3ff9c6628 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 4 Apr 2017 10:45:24 +0900 Subject: [PATCH 06/16] Fix memory leak bus/at-spi-bus-launcher.c argv[1] is allocated in memory by g_strdup_printf. but do not free. So I add g_free function. test/at_spi2_tool.c Added a null check to avoid double free. Change-Id: I80ce6af2839c4dfe9c1460885f5b93f281f7ef29 --- bus/at-spi-bus-launcher.c | 29 ++++++++++++++++------------- test/at_spi2_tool.c | 3 ++- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 3f6c917..db1db5c 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -1,6 +1,6 @@ /* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- - * - * at-spi-bus-launcher: Manage the a11y bus as a child process + * + * at-spi-bus-launcher: Manage the a11y bus as a child process * * Copyright 2011 Red Hat, Inc. * @@ -124,7 +124,7 @@ setup_bus_child (gpointer data) #ifdef __linux #include prctl (PR_SET_PDEATHSIG, 15); -#endif +#endif } /** @@ -156,7 +156,7 @@ on_bus_exited (GPid pid, gpointer data) { A11yBusLauncher *app = data; - + app->a11y_bus_pid = -1; app->state = A11Y_BUS_STATE_ERROR; if (app->a11y_launch_error_message == NULL) @@ -169,7 +169,7 @@ on_bus_exited (GPid pid, app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status)); } g_main_loop_quit (app->loop); -} +} static gboolean ensure_a11y_bus (A11yBusLauncher *app) @@ -181,12 +181,12 @@ ensure_a11y_bus (A11yBusLauncher *app) if (app->a11y_bus_pid != 0) return FALSE; - + argv[1] = g_strdup_printf ("--config-file=%s/at-spi2/accessibility.conf", SYSCONFDIR); if (pipe (app->pipefd) < 0) g_error ("Failed to create pipe: %s", strerror (errno)); - + if (!g_spawn_async (NULL, argv, NULL, @@ -241,9 +241,12 @@ ensure_a11y_bus (A11yBusLauncher *app) } #endif + if (argv[1]) g_free(argv[1]); + return TRUE; - + error: + if (argv[1]) g_free(argv[1]); close (app->pipefd[0]); close (app->pipefd[1]); app->state = A11Y_BUS_STATE_ERROR; @@ -379,7 +382,7 @@ handle_set_property (GDBusConnection *connection, A11yBusLauncher *app = user_data; const gchar *type = g_variant_get_type_string (value); gboolean enabled; - + if (g_strcmp0 (type, "b") != 0) { g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, @@ -429,7 +432,7 @@ on_bus_acquired (GDBusConnection *connection, A11yBusLauncher *app = user_data; GError *error; guint registration_id; - + if (connection == NULL) { g_main_loop_quit (app->loop); @@ -506,7 +509,7 @@ on_sigterm_pipe (GIOChannel *channel, gpointer data) { A11yBusLauncher *app = data; - + g_main_loop_quit (app->loop); return FALSE; @@ -544,7 +547,7 @@ already_running () bridge_display = XOpenDisplay (NULL); if (!bridge_display) return FALSE; - + AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False); XGetWindowProperty (bridge_display, XDefaultRootWindow (bridge_display), @@ -828,7 +831,7 @@ main (int argc, if (_global_app->a11y_bus_pid > 0) kill (_global_app->a11y_bus_pid, SIGTERM); - /* Clear the X property if our bus is gone; in the case where e.g. + /* Clear the X property if our bus is gone; in the case where e.g. * GDM is launching a login on an X server it was using before, * we don't want early login processes to pick up the stale address. */ diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 2eae131..018acc7 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -240,12 +240,13 @@ static char *_get_states(AtspiAccessible *node, int length_limit) { AtspiStateSet *node_state_set = atspi_accessible_get_state_set(node); GArray *states = atspi_state_set_get_states(node_state_set); + if (!states) return NULL; g_array_sort(states, _int_sort_function); AtspiStateType state_type; char *state_string = NULL; - for (int i = 0; states && (i < states->len); i++) { + for (int i = 0; i < states->len; i++) { state_type = g_array_index(states, AtspiStateType, i); char node_state_str[8]; -- 2.7.4 From 4a435a0629752f9ee5a8a1a86566c3e48029dd20 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Tue, 16 May 2017 14:22:27 +0900 Subject: [PATCH 07/16] Convey launching condition to screen-reader The screen-reader reads "Screen reader (TTS) on" when the screen-reader launches. It is not necessary to read this information for the screen-reader launching at booting time. It is necessary only if the screen-reader is launched by the Vconf value change from the Settings application. Change-Id: I73cb17be6c6b561d77ed2f6d7226a21896f62e1a --- bus/at-spi-bus-launcher.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index db1db5c..89860b6 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -604,7 +604,7 @@ gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data) } static gboolean -_launch_screen_reader(gpointer user_data) +_launch_screen_reader(gpointer user_data, gboolean by_vconf_change) { A11yBusLauncher *bl = user_data; LOGD("Launching screen reader"); @@ -619,6 +619,15 @@ _launch_screen_reader(gpointer user_data) LOGD("Can't create bundle"); return FALSE; } + + if (by_vconf_change) + { + if (bundle_add_str(kb, "by_vconf_change", "yes") != BUNDLE_ERROR_NONE) + { + LOGD("Can't add information to bundle"); + } + } + int operation_error = appsvc_set_operation(kb, APP_CONTROL_OPERATION_SCREEN_READ); LOGD("appsvc_set_operation: %i", operation_error); @@ -649,7 +658,7 @@ _launch_screen_reader_repeat_until_success(gpointer user_data) { return FALSE; } - gboolean ret = _launch_screen_reader(user_data); + gboolean ret = _launch_screen_reader(user_data, FALSE); if (ret) { @@ -727,7 +736,7 @@ void screen_reader_cb(keynode_t *node, void *user_data) 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); + _launch_screen_reader(bl, TRUE); } int -- 2.7.4 From 67b77c5a624ccab97c840e689fed4dfcb46e0aa1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pawe=C5=82=20Stawicki?= Date: Thu, 16 Mar 2017 14:09:32 +0100 Subject: [PATCH 08/16] add screen-reader dead tracker to at-spi-bus-launcher Commit adds _screen_reader_dead_tracker method to track if screen-reader gets killed. Commit needs: https://review.tizen.org/gerrit/#/c/117565/ replaces: https://review.tizen.org/gerrit/#/c/117557/ invalidates: https://review.tizen.org/gerrit/#/c/117556/ Change-Id: I8ea33c75f4e2fa4c0d868deec52a574c993a21b0 --- bus/at-spi-bus-launcher.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/bus/at-spi-bus-launcher.c b/bus/at-spi-bus-launcher.c index 89860b6..87b2da7 100644 --- a/bus/at-spi-bus-launcher.c +++ b/bus/at-spi-bus-launcher.c @@ -64,6 +64,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); typedef enum { A11Y_BUS_STATE_IDLE = 0, @@ -329,6 +330,8 @@ handle_a11y_enabled_change (A11yBusLauncher *app, gboolean enabled, &builder, &invalidated_builder), NULL); + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); } static void @@ -367,6 +370,8 @@ handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled, &builder, &invalidated_builder), NULL); + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); } static gboolean @@ -603,6 +608,20 @@ gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data) handle_screen_reader_enabled_change (_global_app, new_val, FALSE); } +static int +_screen_reader_dead_tracker (int pid, void *data) +{ + A11yBusLauncher *app = data; + + if (app->pid > 0 && pid == app->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); + } + return 0; +} + static gboolean _launch_screen_reader(gpointer user_data, gboolean by_vconf_change) { @@ -636,6 +655,8 @@ _launch_screen_reader(gpointer user_data, gboolean by_vconf_change) if (bl->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); ret = TRUE; } else @@ -680,6 +701,9 @@ _terminate_screen_reader(A11yBusLauncher *bl) return FALSE; + LOGD("unregistering screen reader dead tracker"); + aul_listen_app_dead_signal(NULL, NULL); + int status = aul_app_get_status_bypid(bl->pid); if (status < 0) -- 2.7.4 From e757756d750e7d736aee31c71b68116a71031f58 Mon Sep 17 00:00:00 2001 From: Pawel Kurowski Date: Thu, 1 Jun 2017 12:45:08 +0200 Subject: [PATCH 09/16] Add relation-dump option to at_spi2_tool Flags -d and -c now inform when object has relations to list. Change-Id: If831d8258aaf6d7b71f3f05ebf75e88d3fab56c1 --- test/at_spi2_tool.c | 141 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 44 deletions(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index 018acc7..e9b3d68 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -4,6 +4,7 @@ #include #include #include +#include #define ERROR_STATE -1 #define SAFE_BUFFER_SIZE 2048 @@ -17,6 +18,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; @@ -79,12 +82,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); @@ -99,7 +96,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() @@ -250,7 +247,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); } @@ -288,32 +285,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_path(ret, NULL) : g_strdup(""); -} - static char *_get_info(AtspiAccessible *node, int length_limit) { if (!node) @@ -327,11 +298,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]]", path, node_role_name, attributes, @@ -341,8 +311,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 %s: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__); @@ -357,10 +326,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) @@ -373,7 +341,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); @@ -438,11 +406,93 @@ 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); @@ -472,8 +522,11 @@ 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 a38a10da4b100564777fd2e6a8cca9e08ce44d55 Mon Sep 17 00:00:00 2001 From: Pawel Kurowski Date: Fri, 16 Jun 2017 20:36:00 +0200 Subject: [PATCH 10/16] Fix wrong strncpy usage Change-Id: Id4ee0975ccbce4043ded7d00f7238e057db26f3b --- test/at_spi2_tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c index e9b3d68..95c726c 100644 --- a/test/at_spi2_tool.c +++ b/test/at_spi2_tool.c @@ -341,7 +341,7 @@ static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessi char parent_status[NUMBER_WIDTH]; if (parent == NULL) - strncpy(parent_status, NUMBER_WIDTH, "_"); + strncpy(parent_status, "_", NUMBER_WIDTH); else snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index); -- 2.7.4 From f6c437e75f96339276474872317e46d1b89c5d81 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Fri, 23 Jun 2017 11:37:02 +0900 Subject: [PATCH 11/16] Decrements the reference count of session_bus dbus_bus_get increments reference count of a DBusConnection. It is callers responsibility to all dbus_connection_unref after use. [Gnome] https://bugzilla.gnome.org/show_bug.cgi?id=784120 Change-Id: Ic1b23755fa9a2a46aaa2ad970254063a5486f8f6 --- atspi/atspi-misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/atspi/atspi-misc.c b/atspi/atspi-misc.c index 48759ca..679e0da 100644 --- a/atspi/atspi-misc.c +++ b/atspi/atspi-misc.c @@ -1497,7 +1497,7 @@ get_accessibility_bus_address_dbus (void) g_warning ("Error retrieving accessibility bus address: %s: %s", error.name, error.message); dbus_error_free (&error); - return NULL; + goto out; } { @@ -1509,12 +1509,14 @@ get_accessibility_bus_address_dbus (void) DBUS_TYPE_INVALID)) { dbus_message_unref (reply); - return NULL; + goto out; } address = g_strdup (tmp_address); dbus_message_unref (reply); } - + +out: + dbus_connection_unref (session_bus); return address; } -- 2.7.4 From 59196d54df4ccefff67fc31afb56f9ad35a75a9c Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Wed, 28 Jun 2017 17:45:04 +0900 Subject: [PATCH 12/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 13/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 14/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 15/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 16/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