summaryrefslogtreecommitdiff
path: root/atk-adaptor/collection-adaptor.c
diff options
context:
space:
mode:
Diffstat (limited to 'atk-adaptor/collection-adaptor.c')
-rw-r--r--atk-adaptor/collection-adaptor.c1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/atk-adaptor/collection-adaptor.c b/atk-adaptor/collection-adaptor.c
new file mode 100644
index 0000000..749198f
--- /dev/null
+++ b/atk-adaptor/collection-adaptor.c
@@ -0,0 +1,1033 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2007 IBM Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* collection.c: implements the Collection interface */
+
+#include <string.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+#include "accessible-register.h"
+#include "accessible-marshaller.h"
+
+#include "spi-common/bitarray.h"
+#include "spi-common/spi-dbus.h"
+
+typedef struct _MatchRulePrivate MatchRulePrivate;
+struct _MatchRulePrivate
+{
+ gint *states;
+ Accessibility_Collection_MatchType statematchtype;
+ AtkAttributeSet *attributes;
+ Accessibility_Collection_MatchType attributematchtype;
+ gint *roles;
+ Accessibility_Collection_MatchType rolematchtype;
+ gchar **ifaces;
+ Accessibility_Collection_MatchType interfacematchtype;
+ gboolean invert;
+};
+
+static gboolean
+child_interface_p (AtkObject *child,
+ gchar *repo_id)
+{
+ if (!strcasecmp(repo_id, "action")) return atk_is_action(child);
+ if (!strcasecmp(repo_id, "component")) return atk_is_component(child);
+ if (!strcasecmp(repo_id, "editabletext")) return atk_is_editable_text(child);
+ if (!strcasecmp(repo_id, "text")) return atk_is_text(child);
+ if (!strcasecmp(repo_id, "hypertext")) return atk_is_hypertext(child);
+ if (!strcasecmp(repo_id, "image")) return atk_is_image(child);
+ if (!strcasecmp(repo_id, "selection")) return atk_is_selection(child);
+ if (!strcasecmp(repo_id, "table")) return atk_is_table(child);
+ if (!strcasecmp(repo_id, "value")) return atk_is_value(child);
+ if (!strcasecmp(repo_id, "streamablecontent")) return atk_is_streamable_content(child);
+ if (!strcasecmp(repo_id, "document")) return atk_is_document(child);
+ return FALSE;
+}
+
+#define child_collection_p(ch) (TRUE)
+
+static gboolean
+match_states_all_p (AtkObject *child,
+ gint *set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = TRUE;
+
+ if (set == NULL)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ // TODO: use atk-state_set_contains_states; would be more efficient
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (!atk_state_set_contains_state(chs, set[i]))
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ g_object_unref(chs);
+ return ret;
+}
+
+static gboolean
+match_states_any_p (AtkObject *child,
+ gint *set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = FALSE;
+
+ if (set == NULL)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (!atk_state_set_contains_state(chs, set[i]))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ g_object_unref(chs);
+ return ret;
+}
+
+static gboolean
+match_states_none_p (AtkObject *child,
+ gint *set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = TRUE;
+
+ if (set == NULL)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (atk_state_set_contains_state(chs, set[i]))
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ g_object_unref(chs);
+ return ret;
+}
+
+// TODO: need to convert at-spi roles/states to atk roles/states */
+static gboolean
+match_states_lookup (AtkObject *child,
+ MatchRulePrivate *mrp)
+{
+ switch (mrp->statematchtype){
+ case Accessibility_Collection_MATCH_ALL :
+ if (match_states_all_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_ANY :
+ if (match_states_any_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_NONE :
+ if (match_states_none_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ default : break;
+ }
+
+ return FALSE;
+}
+
+// TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
+// would be more efficient
+#define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
+
+static gboolean
+match_roles_all_p (AtkObject *child,
+ gint *roles)
+{
+ Accessibility_Role role;
+
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
+ else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
+
+ return (atk_object_get_role(child) == roles[0]);
+
+}
+
+static gboolean
+match_roles_any_p (AtkObject *child,
+ gint *roles)
+{
+ AtkRole role;
+ int i;
+
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
+
+ role = atk_object_get_role(child);
+
+ for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
+ if (role == roles[i])
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+match_roles_none_p (AtkObject *child,
+ gint *roles)
+{
+ AtkRole role;
+ int i;
+
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
+
+ role = atk_object_get_role(child);
+
+ for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
+ if (role == roles[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+match_roles_lookup (AtkObject *child,
+ MatchRulePrivate *mrp)
+{
+ switch (mrp->rolematchtype){
+ case Accessibility_Collection_MATCH_ALL :
+ if (match_roles_all_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_ANY :
+ if (match_roles_any_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_NONE :
+ if (match_roles_none_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ default : break;
+
+ }
+ return FALSE;
+}
+
+static gboolean
+match_interfaces_all_p (AtkObject *obj,
+ gchar **ifaces)
+{
+ gint i;
+
+ if (ifaces == NULL)
+ return TRUE;
+
+ for (i = 0; ifaces[i]; i++)
+ if (!child_interface_p (obj, ifaces [i])){
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+match_interfaces_any_p (AtkObject *obj,
+ gchar **ifaces)
+{
+ gint i;
+
+ if (ifaces == NULL)
+ return TRUE;
+
+
+ for (i = 0; ifaces[i]; i++)
+ if (child_interface_p (obj, ifaces [i])){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+match_interfaces_none_p (AtkObject *obj,
+ gchar **ifaces)
+{
+ gint i;
+
+ for (i = 0; ifaces[i]; i++)
+ if (child_interface_p (obj, ifaces [i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+match_interfaces_lookup (AtkObject *child,
+ MatchRulePrivate *mrp)
+{
+ switch (mrp->interfacematchtype){
+
+ case Accessibility_Collection_MATCH_ALL :
+ if (match_interfaces_all_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_ANY :
+ if (match_interfaces_any_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_NONE :
+ if (match_interfaces_none_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ default : break;
+ }
+
+ return FALSE;
+}
+
+#define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
+
+static gboolean
+match_attributes_all_p (AtkObject *child,
+ AtkAttributeSet *attributes)
+{
+ int i, k;
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+ gboolean flag = FALSE;
+
+ if (attributes == NULL || g_slist_length (attributes) == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes(child);
+ length = g_slist_length(attributes);
+ oa_length = g_slist_length(oa);
+
+ for (i = 0; i < length; i++) {
+ AtkAttribute *attr = g_slist_nth_data(attributes, i);
+ for (k = 0; k < oa_length; k++) {
+ AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value)){
+ flag = TRUE;
+ break;
+ }
+ else
+ flag = FALSE;
+ }
+ if (!flag) {
+ atk_attribute_set_free(oa);
+ return FALSE;
+ }
+ }
+ atk_attribute_set_free(oa);
+ return TRUE;
+}
+
+static gboolean
+match_attributes_any_p (AtkObject *child,
+ AtkAttributeSet *attributes)
+{
+ int i, k;
+
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+
+ length = g_slist_length(attributes);
+ if (length == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes(child);
+ oa_length = g_slist_length(oa);
+
+ for (i = 0; i < length; i++){
+ AtkAttribute *attr = g_slist_nth_data(attributes, i);
+ for (k = 0; k < oa_length; k++){
+ AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value)){
+ atk_attribute_set_free(oa);
+ return TRUE;
+ }
+ }
+ }
+ atk_attribute_set_free(oa);
+ return FALSE;
+}
+
+static gboolean
+match_attributes_none_p (AtkObject *child,
+ AtkAttributeSet *attributes)
+{
+ int i, k;
+
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+
+ length = g_slist_length(attributes);
+ if (length == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes(child);
+ oa_length = g_slist_length(oa);
+
+ for (i = 0; i < length; i++){
+ AtkAttribute *attr = g_slist_nth_data(attributes, i);
+ for (k = 0; k < oa_length; k++){
+ AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value)){
+ atk_attribute_set_free(oa);
+ return FALSE;
+ }
+ }
+ }
+ atk_attribute_set_free(oa);
+ return TRUE;
+}
+
+static gboolean
+match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
+{
+ switch (mrp->attributematchtype){
+
+ case Accessibility_Collection_MATCH_ALL :
+ if (match_attributes_all_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_ANY :
+ if (match_attributes_any_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ case Accessibility_Collection_MATCH_NONE :
+ if (match_attributes_none_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ default : break;
+ }
+ return FALSE;
+}
+
+static gboolean
+traverse_p (AtkObject *child,
+ const gboolean traverse)
+{
+ if (traverse)
+ return TRUE;
+ else return !child_collection_p (child);
+}
+
+static int
+sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
+ gint kount, gint max,
+ AtkObject *obj, glong index, gboolean flag,
+ AtkObject *pobj, gboolean recurse,
+ gboolean traverse)
+{
+ gint i = index;
+ glong acount = atk_object_get_n_accessible_children (obj);
+ gboolean prev = pobj? TRUE : FALSE;
+
+ for (; i < acount && (max == 0 || kount < max); i++){
+ AtkObject *child =
+ atk_object_ref_accessible_child(obj, i);
+
+ g_object_unref(child);
+ if (prev && child == pobj){
+ return kount;
+ }
+
+ if (flag && match_interfaces_lookup (child, mrp)
+ && match_states_lookup (child, mrp)
+ && match_roles_lookup (child, mrp)
+ && match_attributes_lookup (child, mrp)
+ ){
+
+ ls = g_list_append (ls, child);
+ kount++;
+ }
+
+ if (!flag)
+ flag = TRUE;
+
+ if (recurse && traverse_p (child, traverse))
+ kount = sort_order_canonical (mrp, ls, kount,
+ max, child, 0, TRUE,
+ pobj, recurse, traverse);
+ }
+ return kount;
+}
+
+static int
+sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
+ gint kount, gint max,
+ AtkObject *obj, gboolean flag,
+ AtkObject *pobj)
+{
+ AtkObject *nextobj;
+ AtkObject *parent;
+ glong indexinparent;
+
+ /* This breaks us out of the recursion. */
+ if (!obj || obj == pobj)
+ {
+ return kount;
+ }
+
+ /* Add to the list if it matches */
+ if (flag && match_interfaces_lookup (obj, mrp)
+ && match_states_lookup (obj, mrp)
+ && match_roles_lookup (obj, mrp)
+ && match_attributes_lookup (obj, mrp))
+ {
+ ls = g_list_append (ls, obj);
+ kount++;
+ }
+
+ if(!flag) flag = TRUE;
+
+ /* Get the current nodes index in it's parent and the parent object. */
+ indexinparent = atk_object_get_index_in_parent (obj);
+ parent = atk_object_get_parent(obj);
+
+ if(indexinparent > 0)
+ {
+ /* there are still some siblings to visit so get the previous sibling
+ and get it's last descendant.
+ First, get the previous sibling */
+ nextobj = atk_object_ref_accessible_child (parent,
+ indexinparent-1);
+ g_object_unref(nextobj);
+
+ /* Now, drill down the right side to the last descendant */
+ while(atk_object_get_n_accessible_children (nextobj) > 0)
+ {
+ nextobj = atk_object_ref_accessible_child(nextobj,
+ atk_object_get_n_accessible_children (nextobj)-1);
+ g_object_unref (nextobj);
+ }
+ /* recurse with the last descendant */
+ kount = sort_order_rev_canonical (mrp, ls, kount, max,
+ nextobj, TRUE, pobj);
+ }
+ else
+ {
+ /* no more siblings so next node must be the parent */
+ kount = sort_order_rev_canonical (mrp, ls, kount, max,
+ parent, TRUE, pobj);
+
+ }
+ return kount;
+}
+
+static int
+query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
+ GList *ls, gint kount, gint max,
+ AtkObject *obj, glong index,
+ gboolean flag,
+ AtkObject *pobj,
+ gboolean recurse, gboolean traverse)
+{
+ switch (sortby) {
+ case Accessibility_Collection_SORT_ORDER_CANONICAL :
+ kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
+ pobj, recurse, traverse);
+ break;
+ case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
+ kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
+ pobj, recurse, traverse);
+ break;
+ default:
+ kount = 0;
+ g_warning ("Sort method not implemented yet");
+ break;
+ }
+
+ return kount;
+}
+
+static dbus_bool_t
+read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
+{
+ DBusMessageIter mrc, arrayc;
+ dbus_uint32_t *array;
+ dbus_int32_t matchType;
+ int array_count;
+ char *str;
+ AtkAttribute *attr;
+ int i;
+ char *interfaces = NULL;
+
+ // TODO: error checking
+ dbus_message_iter_recurse(iter, &mrc);
+ dbus_message_iter_recurse(&mrc, &arrayc);
+ dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
+ bitarray_to_seq(array, array_count, &mrp->states);
+ for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
+ }
+ dbus_message_iter_next(&mrc);
+ dbus_message_iter_read_basic(&mrc, &matchType);
+ dbus_message_iter_next(&mrc);
+ mrp->statematchtype = matchType;;
+ /* attributes */
+ dbus_message_iter_recurse(&mrc, &arrayc);
+ mrp->attributes = NULL;
+ while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
+ {
+ dbus_message_iter_get_basic(&arrayc, &str);
+ // TODO: remove this print
+ g_print("Got attribute: %s\n", str);
+ attr = g_new (AtkAttribute, 1);
+ if (attr)
+ {
+ int len = strcspn(str, ":");
+ attr->name = g_strndup(str, len);
+ if (str[len] == ':')
+ {
+ len++;
+ if (str[len] == ' ') len++;
+ attr->value = g_strdup(str + len);
+ }
+ else attr->value = NULL;
+ mrp->attributes = g_slist_prepend(mrp->attributes, attr);
+ }
+ dbus_message_iter_next(&arrayc);
+ }
+ dbus_message_iter_next(&mrc);
+ dbus_message_iter_read_basic(&mrc, &matchType);
+ mrp->attributematchtype = matchType;;
+ dbus_message_iter_next(&mrc);
+ /* Get roles and role match */
+ dbus_message_iter_recurse(&mrc, &arrayc);
+ dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
+ bitarray_to_seq(array, array_count, &mrp->roles);
+ dbus_message_iter_next(&mrc);
+ dbus_message_iter_read_basic(&mrc, &matchType);
+ mrp->rolematchtype = matchType;;
+ dbus_message_iter_next(&mrc);
+ /* Get interfaces and interface match */
+ dbus_message_iter_read_basic(&mrc, &interfaces);
+ dbus_message_iter_next(&mrc);
+ mrp->ifaces = g_strsplit(interfaces, ";", 0);
+ dbus_message_iter_read_basic(&mrc, &matchType);
+ mrp->interfacematchtype = matchType;;
+ dbus_message_iter_next(&mrc);
+ /* get invert */
+ dbus_message_iter_read_basic(&mrc, &mrp->invert);
+ dbus_message_iter_next(iter);
+ return TRUE;
+}
+
+static DBusMessage *
+return_and_free_list(DBusMessage *message, GList *ls)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ GList *item;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) return NULL;
+ dbus_message_iter_init_append(reply, &iter);
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
+ for (item = ls; item; item = g_list_next(item))
+ {
+ char *path = (char *) spi_dbus_object_to_path ((AtkObject *)item->data);
+ dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
+ g_free(path);
+ }
+ if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
+ g_list_free (ls);
+ return reply;
+oom:
+ // TODO: Handle out of memory
+ g_list_free (ls);
+ return reply;
+}
+
+static void free_mrp_data(MatchRulePrivate *mrp)
+{
+ g_free(mrp->states);
+ atk_attribute_set_free(mrp->attributes);
+ g_free(mrp->roles);
+ g_strfreev(mrp->ifaces);
+}
+
+static DBusMessage *
+getMatchesFrom (DBusMessage *message,
+ AtkObject *current_object,
+ MatchRulePrivate *mrp,
+ const Accessibility_Collection_SortOrder sortby,
+ const dbus_bool_t isrestrict,
+ dbus_int32_t count,
+ const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *parent;
+ glong index =
+ atk_object_get_index_in_parent (current_object);
+ gint kount = 0;
+
+ ls = g_list_append (ls, current_object);
+
+ if (!isrestrict)
+ {
+ parent = atk_object_get_parent (current_object);
+ kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
+ FALSE, NULL, TRUE, traverse);
+ }
+ else
+ kount = query_exec (mrp, sortby, ls, 0, count,
+ current_object, 0, FALSE, NULL,
+ TRUE, traverse);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+/*
+ inorder traversal from a given object in the hierarchy
+*/
+
+static int
+inorder (AtkObject *collection, MatchRulePrivate *mrp,
+ GList *ls, gint kount, gint max,
+ AtkObject *obj,
+ gboolean flag,
+ AtkObject *pobj,
+ dbus_bool_t traverse)
+{
+ int i = 0;
+
+ /* First, look through the children recursively. */
+ kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
+ NULL, TRUE, TRUE);
+
+ /* Next, we look through the right subtree */
+ while ((max == 0 || kount < max)
+ && obj != collection)
+ {
+ AtkObject *parent =
+ atk_object_get_parent (obj);
+ i = atk_object_get_index_in_parent (obj);
+ kount = sort_order_canonical (mrp, ls, kount, max, parent,
+ i+1, TRUE, FALSE, TRUE, TRUE);
+ obj = parent;
+ }
+
+ if (kount < max)
+ {
+ kount = sort_order_canonical (mrp, ls, kount, max,
+ obj, i + 1, TRUE, FALSE,
+ TRUE, TRUE);
+ }
+
+ return kount;
+}
+
+/*
+ GetMatchesInOrder: get matches from a given object in an inorder traversal.
+*/
+
+static DBusMessage *
+getMatchesInOrder (DBusMessage *message,
+ AtkObject *current_object,
+ MatchRulePrivate *mrp,
+ const Accessibility_Collection_SortOrder sortby,
+ const dbus_bool_t recurse,
+ dbus_int32_t count,
+ const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *obj;
+ gint kount = 0;
+
+ ls = g_list_append (ls, current_object);
+
+ obj = atk_dbus_path_to_object (dbus_message_get_path (message));
+
+ kount = inorder (obj, mrp, ls, 0, count,
+ current_object, TRUE, NULL, traverse);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+/*
+ GetMatchesInBackOrder: get matches from a given object in a
+ reverse order traversal.
+*/
+
+static DBusMessage *
+getMatchesInBackOrder (DBusMessage *message,
+ AtkObject *current_object,
+ MatchRulePrivate *mrp,
+ const Accessibility_Collection_SortOrder sortby,
+ dbus_int32_t count)
+{
+ GList *ls = NULL;
+ AtkObject *collection;
+ gint kount = 0;
+
+ ls = g_list_append (ls, current_object);
+
+ collection = atk_dbus_path_to_object (dbus_message_get_path (message));
+
+ kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
+ FALSE, collection);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+static DBusMessage *
+getMatchesTo (DBusMessage *message,
+ AtkObject *current_object,
+ MatchRulePrivate *mrp,
+ const Accessibility_Collection_SortOrder sortby,
+ const dbus_bool_t recurse,
+ const dbus_bool_t isrestrict,
+ dbus_int32_t count,
+ const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *obj;
+ gint kount = 0;
+
+ ls = g_list_append (ls, current_object);
+
+ if (recurse){
+ obj = atk_object_get_parent (current_object);
+ kount = query_exec (mrp, sortby, ls, 0, count,
+ obj, 0, TRUE, current_object, TRUE, traverse);
+ }
+ else{
+ obj = atk_dbus_path_to_object (dbus_message_get_path (message));
+ kount = query_exec (mrp, sortby, ls, 0, count,
+ obj, 0, TRUE, current_object, TRUE, traverse);
+
+ }
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+static DBusMessage *
+impl_getMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ char *current_object_path = NULL;
+ AtkObject *current_object;
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint16_t sortby;
+ dbus_uint16_t tree;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ GList *ls = NULL;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic (&iter, current_object_path);
+ current_object = atk_dbus_path_to_object (current_object_path);
+ if (!current_object)
+ {
+ // TODO: object-not-found error
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_next (&iter);
+ if (!read_mr(&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic(&iter, &sortby);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &tree);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &count);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &traverse);
+ dbus_message_iter_next(&iter);
+
+ switch (tree){
+ case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
+ return getMatchesFrom (message, current_object,
+ &rule, sortby, TRUE, count, traverse);
+ break;
+ case Accessibility_Collection_TREE_RESTRICT_SIBLING :
+ return getMatchesFrom (message, current_object,
+ &rule, sortby, FALSE, count, traverse);
+ break;
+ case Accessibility_Collection_TREE_INORDER :
+ return getMatchesInOrder (message, current_object,
+ &rule, sortby, TRUE, count, traverse);
+ break;
+ default : return NULL;
+ }
+}
+
+static DBusMessage *
+impl_getMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ char *current_object_path = NULL;
+ AtkObject *current_object;
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint16_t sortby;
+ dbus_uint16_t tree;
+ dbus_bool_t recurse;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ GList *ls = NULL;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic (&iter, current_object_path);
+ current_object = atk_dbus_path_to_object (current_object_path);
+ if (!current_object)
+ {
+ // TODO: object-not-found error
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_next (&iter);
+ if (!read_mr(&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic(&iter, &sortby);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &tree);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &recurse);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &count);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &traverse);
+ dbus_message_iter_next(&iter);
+
+ switch (tree){
+ case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
+ return getMatchesTo (message, current_object,
+ &rule, sortby, recurse, TRUE, count, traverse);
+ break;
+ case Accessibility_Collection_TREE_RESTRICT_SIBLING :
+ return getMatchesTo (message, current_object,
+ &rule, sortby, recurse, FALSE, count, traverse);
+ break;
+ case Accessibility_Collection_TREE_INORDER :
+ return getMatchesInBackOrder (message, current_object,
+ &rule, sortby, count);
+ break;
+ default : return NULL;
+ }
+}
+
+static DBusMessage *
+impl_getMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AtkObject *obj = path_to_object (message);
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint16_t sortby;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ GList *ls = NULL;
+
+ dbus_message_iter_init(message, &iter);
+ if (!read_mr(&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic(&iter, &sortby);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &count);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &traverse);
+ dbus_message_iter_next(&iter);
+ ls = g_list_prepend (ls, obj);
+ count = query_exec (&rule, sortby, ls, 0, count,
+ obj, 0, TRUE, NULL, TRUE, traverse);
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+ free_mrp_data (&rule);
+ return return_and_free_list (message, ls);
+}
+
+static DRouteMethod methods[] = {
+ { impl_getMatchesFrom, "getMatchesFrom" },
+ { impl_getMatchesTo, "getMatchesTo" },
+ { impl_getMatches, "getMatches" },
+ {NULL, NULL}
+};
+
+void
+spi_initialize_collection (DRoutePath *path)
+{
+ droute_path_add_interface (path,
+ SPI_DBUS_INTERFACE_COLLECTION,
+ methods,
+ NULL);
+};