#include <string.h>
#include <getopt.h>
#include <stdbool.h>
+#include <gio/gio.h>
#define ERROR_STATE -1
#define SAFE_BUFFER_SIZE 2048
{
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];
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) {
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)
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 *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, "[[%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,
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__);
+ fprintf(stderr, "\n%s, %s %d: 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);
free(box_size);
}
free(states);
+ free(flows_to);
+ free(flows_from);
return _strdup(result);
}
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);
+ 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,
+ parent_candidate_path, parent_path);
+ free(parent_path);
+ free(parent_candidate_path);
} else {
snprintf(output, CHECK_OUTPUT_WIDTH, "[OK]");
printf("-v, --version\t\tshow actual version of tool\n");
printf("-g, --show-legend\tprint AT-SPI state legend\n");
printf("-l, --list-apps\t\tlist all applications of desktop\n");
+ printf("-a, --at-spi-client <true|false>\tenable/disable org.a11y.Status.IsEnabled property\n");
+ printf("-s, --sleep <N>\tsleep N seconds\n");
printf("-d, --tree-dump\t\tdump tree for selected application\n");
printf("-c, --tree-check\tcheck tree for selected application\n");
printf("-f, --first-match\tperform dump or check only for first matching application\n");
printf("AT-SPI2-CORE-UTIL v%s\n", VERSION);
}
-static void _atspi_tree_traverse(AtspiAccessible *desktop, const char *app_name, bool dump, bool check, bool first_match, int length_limit)
+static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bool first_match, int length_limit)
{
+
+ AtspiAccessible *desktop = atspi_get_desktop(0);
+ if (!desktop) {
+ fprintf(stderr, "atspi_get_desktop failed\n");
+ return;
+ }
+
int count = atspi_accessible_get_child_count(desktop, NULL);
bool app_name_matched = false;
for (int i = 0; i < count; i++) {
AtspiAccessible *child = atspi_accessible_get_child_at_index(desktop, i, NULL);
if (child == NULL) {
- fprintf(stderr, "\n%s, %s %s: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__);
+ fprintf(stderr, "\n%s, %s %d: Null child occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__);
continue;
}
if (!app_name_matched && (dump || check))
fprintf(stderr, "There is no application with name: %s. Try again.\n", app_name);
+
+ g_object_unref(desktop);
}
-static void _run_command(int argc, char *argv[], AtspiAccessible *desktop)
+static void _at_spi_client_enable(gboolean enabled)
+{
+ static GDBusProxy *proxy = NULL; //we keep proxy (dbus connection) until program exits
+ GVariant *result;
+ GError *error = NULL;
+ GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_NONE;
+
+
+ if (!proxy) {
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ flags,
+ NULL, /* GDBusInterfaceInfo */
+ "org.a11y.Bus",
+ "/org/a11y/bus",
+ "org.freedesktop.DBus.Properties",
+ NULL, /* GCancellable */
+ &error);
+ if (error) {
+ fprintf(stderr, "Failed to create proxy object for '/org/a11y/bus': %s\n", error->message);
+ g_error_free(error);
+ return;
+ }
+ }
+
+ result = g_dbus_proxy_call_sync(proxy,
+ "Set",
+ g_variant_new ("(ssv)", "org.a11y.Status", "IsEnabled", g_variant_new_boolean(enabled)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (result)
+ g_variant_unref(result);
+
+ if (error) {
+ fprintf(stderr, "Fail to call org.freedesktop.DBus.Properties.Set: %s\n", error->message);
+ g_error_free(error);
+ }
+}
+
+static void _run_command(int argc, char *argv[])
{
struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{"show-legend", no_argument, 0, 'g'},
{"list-apps", no_argument, 0, 'l'},
+ {"at-spi-client", no_argument, 0, 'a'},
+ {"sleep", required_argument, 0, 's'},
{"tree-dump", required_argument, 0, 'd'},
{"tree-check", required_argument, 0, 'c'},
{"first-match", no_argument, 0, 'f'},
int option_index = 0;
bool traverse_flags[FLAG_NO] = {false};
char *app_name = NULL;
+ gboolean enable_at_spi_client;
while (TRUE) {
- command = getopt_long(argc, argv, "hvgld:c:ft:i:", long_options, &option_index);
+ command = getopt_long(argc, argv, "hvgla:s:d:c:ft:i:", long_options, &option_index);
if (command == ERROR_STATE)
break;
break;
case 'l':
- _atspi_tree_traverse(desktop, NULL, false, false, false, module_name_limit);
+ _atspi_tree_traverse(NULL, false, false, false, module_name_limit);
+ break;
+
+ case 'a':
+ enable_at_spi_client = TRUE;
+ if(optarg[0] == 'f' || optarg[0] == '0')
+ enable_at_spi_client = FALSE;
+
+ _at_spi_client_enable(enable_at_spi_client);
+ break;
+
+ case 's':
+ sleep(atoi(optarg));
break;
case 'd':
}
if (traverse_flags[DUMP] || traverse_flags[CHECK])
- _atspi_tree_traverse(desktop, app_name, traverse_flags[DUMP], traverse_flags[CHECK], traverse_flags[FIRST_MATCH], module_name_limit);
+ _atspi_tree_traverse(app_name, traverse_flags[DUMP], traverse_flags[CHECK], traverse_flags[FIRST_MATCH], module_name_limit);
}
int main(int argc, char *argv[])
return -1;
}
- AtspiAccessible *desktop = atspi_get_desktop(0);
- if (!desktop) {
- fprintf(stderr, "atspi_get_desktop failed\n");
- return -1;
- }
-
- _run_command(argc, argv, desktop);
+ _run_command(argc, argv);
return 0;
}