#include <string.h>
#include <getopt.h>
#include <stdbool.h>
+#include <assert.h>
#define ERROR_STATE -1
#define SAFE_BUFFER_SIZE 2048
#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;
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);
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()
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);
}
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)
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,
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__);
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)
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);
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);
if (first_match) {
free(name);
break;
- } else
+ } else {
printf("\n");
+ _print_legend_for_relation_table();
+ _print_relations_for_object(child);
+ }
free(name);
}