2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2007 IBM Corp.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 /* collection.c: implements the Collection interface */
28 #include <droute/droute.h>
30 #include "accessible-register.h"
31 #include "accessible-marshaller.h"
33 #include "common/bitarray.h"
34 #include "common/spi-dbus.h"
35 #include "common/spi-stateset.h"
37 typedef struct _MatchRulePrivate MatchRulePrivate;
38 struct _MatchRulePrivate
41 Accessibility_Collection_MatchType statematchtype;
42 AtkAttributeSet *attributes;
43 Accessibility_Collection_MatchType attributematchtype;
45 Accessibility_Collection_MatchType rolematchtype;
47 Accessibility_Collection_MatchType interfacematchtype;
52 child_interface_p (AtkObject *child,
55 if (!strcasecmp(repo_id, "action")) return atk_is_action(child);
56 if (!strcasecmp(repo_id, "component")) return atk_is_component(child);
57 if (!strcasecmp(repo_id, "editabletext")) return atk_is_editable_text(child);
58 if (!strcasecmp(repo_id, "text")) return atk_is_text(child);
59 if (!strcasecmp(repo_id, "hypertext")) return atk_is_hypertext(child);
60 if (!strcasecmp(repo_id, "image")) return atk_is_image(child);
61 if (!strcasecmp(repo_id, "selection")) return atk_is_selection(child);
62 if (!strcasecmp(repo_id, "table")) return atk_is_table(child);
63 if (!strcasecmp(repo_id, "value")) return atk_is_value(child);
64 if (!strcasecmp(repo_id, "streamablecontent")) return atk_is_streamable_content(child);
65 if (!strcasecmp(repo_id, "document")) return atk_is_document(child);
69 #define child_collection_p(ch) (TRUE)
72 match_states_all_p (AtkObject *child,
82 chs = atk_object_ref_state_set (child);
84 // TODO: use atk-state_set_contains_states; would be more efficient
85 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
87 if (!atk_state_set_contains_state(chs, set[i]))
99 match_states_any_p (AtkObject *child,
104 gboolean ret = FALSE;
109 chs = atk_object_ref_state_set (child);
111 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
113 if (!atk_state_set_contains_state(chs, set[i]))
125 match_states_none_p (AtkObject *child,
135 chs = atk_object_ref_state_set (child);
137 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
139 if (atk_state_set_contains_state(chs, set[i]))
150 // TODO: need to convert at-spi roles/states to atk roles/states */
152 match_states_lookup (AtkObject *child,
153 MatchRulePrivate *mrp)
155 switch (mrp->statematchtype){
156 case Accessibility_Collection_MATCH_ALL :
157 if (match_states_all_p (child, mrp->states))
161 case Accessibility_Collection_MATCH_ANY :
162 if (match_states_any_p (child, mrp->states))
166 case Accessibility_Collection_MATCH_NONE :
167 if (match_states_none_p (child, mrp->states))
177 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
178 // would be more efficient
179 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
182 match_roles_all_p (AtkObject *child,
185 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
186 else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
188 return (atk_object_get_role(child) == roles[0]);
193 match_roles_any_p (AtkObject *child,
196 Accessibility_Role role;
199 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
201 role = spi_accessible_role_from_atk_role(atk_object_get_role(child));
203 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
204 if (role == roles[i])
211 match_roles_none_p (AtkObject *child,
217 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
219 role = atk_object_get_role(child);
221 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
222 if (role == roles[i])
229 match_roles_lookup (AtkObject *child,
230 MatchRulePrivate *mrp)
232 switch (mrp->rolematchtype){
233 case Accessibility_Collection_MATCH_ALL :
234 if (match_roles_all_p (child, mrp->roles))
238 case Accessibility_Collection_MATCH_ANY :
239 if (match_roles_any_p (child, mrp->roles))
243 case Accessibility_Collection_MATCH_NONE :
244 if (match_roles_none_p (child, mrp->roles))
255 match_interfaces_all_p (AtkObject *obj,
263 for (i = 0; ifaces[i]; i++)
264 if (!child_interface_p (obj, ifaces [i])){
271 match_interfaces_any_p (AtkObject *obj,
280 for (i = 0; ifaces[i]; i++)
281 if (child_interface_p (obj, ifaces [i])){
288 match_interfaces_none_p (AtkObject *obj,
293 for (i = 0; ifaces[i]; i++)
294 if (child_interface_p (obj, ifaces [i]))
301 match_interfaces_lookup (AtkObject *child,
302 MatchRulePrivate *mrp)
304 switch (mrp->interfacematchtype){
306 case Accessibility_Collection_MATCH_ALL :
307 if (match_interfaces_all_p (child, mrp->ifaces))
311 case Accessibility_Collection_MATCH_ANY :
312 if (match_interfaces_any_p (child, mrp->ifaces))
316 case Accessibility_Collection_MATCH_NONE :
317 if (match_interfaces_none_p (child, mrp->ifaces))
327 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
330 match_attributes_all_p (AtkObject *child,
331 AtkAttributeSet *attributes)
335 gint length, oa_length;
336 gboolean flag = FALSE;
338 if (attributes == NULL || g_slist_length (attributes) == 0)
341 oa = atk_object_get_attributes(child);
342 length = g_slist_length(attributes);
343 oa_length = g_slist_length(oa);
345 for (i = 0; i < length; i++) {
346 AtkAttribute *attr = g_slist_nth_data(attributes, i);
347 for (k = 0; k < oa_length; k++) {
348 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
349 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
350 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
358 atk_attribute_set_free(oa);
362 atk_attribute_set_free(oa);
367 match_attributes_any_p (AtkObject *child,
368 AtkAttributeSet *attributes)
373 gint length, oa_length;
375 length = g_slist_length(attributes);
379 oa = atk_object_get_attributes(child);
380 oa_length = g_slist_length(oa);
382 for (i = 0; i < length; i++){
383 AtkAttribute *attr = g_slist_nth_data(attributes, i);
384 for (k = 0; k < oa_length; k++){
385 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
386 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
387 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
388 atk_attribute_set_free(oa);
393 atk_attribute_set_free(oa);
398 match_attributes_none_p (AtkObject *child,
399 AtkAttributeSet *attributes)
404 gint length, oa_length;
406 length = g_slist_length(attributes);
410 oa = atk_object_get_attributes(child);
411 oa_length = g_slist_length(oa);
413 for (i = 0; i < length; i++){
414 AtkAttribute *attr = g_slist_nth_data(attributes, i);
415 for (k = 0; k < oa_length; k++){
416 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
417 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
418 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
419 atk_attribute_set_free(oa);
424 atk_attribute_set_free(oa);
429 match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
431 switch (mrp->attributematchtype){
433 case Accessibility_Collection_MATCH_ALL :
434 if (match_attributes_all_p (child, mrp->attributes))
438 case Accessibility_Collection_MATCH_ANY :
439 if (match_attributes_any_p (child, mrp->attributes))
443 case Accessibility_Collection_MATCH_NONE :
444 if (match_attributes_none_p (child, mrp->attributes))
454 traverse_p (AtkObject *child,
455 const gboolean traverse)
459 else return !child_collection_p (child);
463 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
464 gint kount, gint max,
465 AtkObject *obj, glong index, gboolean flag,
466 AtkObject *pobj, gboolean recurse,
470 glong acount = atk_object_get_n_accessible_children (obj);
471 gboolean prev = pobj? TRUE : FALSE;
473 for (; i < acount && (max == 0 || kount < max); i++){
475 atk_object_ref_accessible_child(obj, i);
477 g_object_unref(child);
478 if (prev && child == pobj){
482 if (flag && match_interfaces_lookup (child, mrp)
483 && match_states_lookup (child, mrp)
484 && match_roles_lookup (child, mrp)
485 && match_attributes_lookup (child, mrp)
488 ls = g_list_append (ls, child);
495 if (recurse && traverse_p (child, traverse))
496 kount = sort_order_canonical (mrp, ls, kount,
498 pobj, recurse, traverse);
504 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
505 gint kount, gint max,
506 AtkObject *obj, gboolean flag,
513 /* This breaks us out of the recursion. */
514 if (!obj || obj == pobj)
519 /* Add to the list if it matches */
520 if (flag && match_interfaces_lookup (obj, mrp)
521 && match_states_lookup (obj, mrp)
522 && match_roles_lookup (obj, mrp)
523 && match_attributes_lookup (obj, mrp))
525 ls = g_list_append (ls, obj);
529 if(!flag) flag = TRUE;
531 /* Get the current nodes index in it's parent and the parent object. */
532 indexinparent = atk_object_get_index_in_parent (obj);
533 parent = atk_object_get_parent(obj);
535 if(indexinparent > 0)
537 /* there are still some siblings to visit so get the previous sibling
538 and get it's last descendant.
539 First, get the previous sibling */
540 nextobj = atk_object_ref_accessible_child (parent,
542 g_object_unref(nextobj);
544 /* Now, drill down the right side to the last descendant */
545 while(atk_object_get_n_accessible_children (nextobj) > 0)
547 nextobj = atk_object_ref_accessible_child(nextobj,
548 atk_object_get_n_accessible_children (nextobj)-1);
549 g_object_unref (nextobj);
551 /* recurse with the last descendant */
552 kount = sort_order_rev_canonical (mrp, ls, kount, max,
553 nextobj, TRUE, pobj);
557 /* no more siblings so next node must be the parent */
558 kount = sort_order_rev_canonical (mrp, ls, kount, max,
566 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
567 GList *ls, gint kount, gint max,
568 AtkObject *obj, glong index,
571 gboolean recurse, gboolean traverse)
574 case Accessibility_Collection_SORT_ORDER_CANONICAL :
575 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
576 pobj, recurse, traverse);
578 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
579 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
580 pobj, recurse, traverse);
584 g_warning ("Sort method not implemented yet");
592 bitarray_to_seq (int *array, int array_count, int **ret)
597 int *out = (int *)g_malloc(out_size * sizeof(int));
601 for (i = 0; i < array_count; i++)
603 for (j = 0; j < 32; j++)
605 if (array[i] & (1 << j))
607 if (out_count == out_size - 2)
610 out = (int *)g_realloc(out, out_size * sizeof(int));
614 out[out_count++] = i * 32 + j;
618 out[out_count] = BITARRAY_SEQ_TERM;
625 read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
627 DBusMessageIter mrc, arrayc;
628 dbus_uint32_t *array;
629 dbus_int32_t matchType;
634 char *interfaces = NULL;
636 dbus_message_iter_recurse(iter, &mrc);
637 dbus_message_iter_recurse(&mrc, &arrayc);
638 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
639 bitarray_to_seq(array, array_count, &mrp->states);
640 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
642 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
644 dbus_message_iter_next(&mrc);
645 dbus_message_iter_get_basic(&mrc, &matchType);
646 dbus_message_iter_next(&mrc);
647 mrp->statematchtype = matchType;;
649 mrp->attributes = NULL;
650 if (dbus_message_iter_get_arg_type (&mrc) == DBUS_TYPE_STRING)
655 dbus_message_iter_get_basic(&mrc, &str);
656 attributes = g_strsplit(str, "\n", -1);
657 for (pp = attributes; *pp; pp++)
660 attr = g_new (AtkAttribute, 1);
663 int len = strcspn(str, ":");
664 attr->name = g_strndup(str, len);
668 if (str[len] == ' ') len++;
669 attr->value = g_strdup(str + len);
671 else attr->value = NULL;
672 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
675 g_strfreev (attributes);
678 dbus_message_iter_recurse(&mrc, &arrayc);
679 while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
681 dbus_message_iter_get_basic(&arrayc, &str);
682 // TODO: remove this print
683 g_print("Got attribute: %s\n", str);
684 attr = g_new (AtkAttribute, 1);
687 int len = strcspn(str, ":");
688 attr->name = g_strndup(str, len);
692 if (str[len] == ' ') len++;
693 attr->value = g_strdup(str + len);
695 else attr->value = NULL;
696 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
698 dbus_message_iter_next(&arrayc);
701 dbus_message_iter_next(&mrc);
702 dbus_message_iter_get_basic(&mrc, &matchType);
703 mrp->attributematchtype = matchType;;
704 dbus_message_iter_next(&mrc);
705 /* Get roles and role match */
706 dbus_message_iter_recurse(&mrc, &arrayc);
707 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
708 bitarray_to_seq(array, array_count, &mrp->roles);
709 dbus_message_iter_next(&mrc);
710 dbus_message_iter_get_basic(&mrc, &matchType);
711 mrp->rolematchtype = matchType;;
712 dbus_message_iter_next(&mrc);
713 /* Get interfaces and interface match */
714 dbus_message_iter_get_basic(&mrc, &interfaces);
715 dbus_message_iter_next(&mrc);
716 mrp->ifaces = g_strsplit(interfaces, ";", 0);
717 dbus_message_iter_get_basic(&mrc, &matchType);
718 mrp->interfacematchtype = matchType;;
719 dbus_message_iter_next(&mrc);
721 dbus_message_iter_get_basic(&mrc, &mrp->invert);
722 dbus_message_iter_next(iter);
727 return_and_free_list(DBusMessage *message, GList *ls)
730 DBusMessageIter iter, iter_array;
733 reply = dbus_message_new_method_return(message);
734 if (!reply) return NULL;
735 dbus_message_iter_init_append(reply, &iter);
736 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array)) goto oom;
737 for (item = ls; item; item = g_list_next(item))
739 spi_dbus_append_name_and_path (message, &iter_array, ATK_OBJECT(item->data), TRUE, FALSE);
741 if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
745 // TODO: Handle out of memory
750 static void free_mrp_data(MatchRulePrivate *mrp)
753 atk_attribute_set_free(mrp->attributes);
755 g_strfreev(mrp->ifaces);
759 GetMatchesFrom (DBusMessage *message,
760 AtkObject *current_object,
761 MatchRulePrivate *mrp,
762 const Accessibility_Collection_SortOrder sortby,
763 const dbus_bool_t isrestrict,
765 const dbus_bool_t traverse)
770 atk_object_get_index_in_parent (current_object);
773 ls = g_list_append (ls, current_object);
777 parent = atk_object_get_parent (current_object);
778 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
779 FALSE, NULL, TRUE, traverse);
782 kount = query_exec (mrp, sortby, ls, 0, count,
783 current_object, 0, FALSE, NULL,
786 ls = g_list_remove (ls, ls->data);
788 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
789 ls = g_list_reverse (ls);
792 return return_and_free_list (message, ls);
796 inorder traversal from a given object in the hierarchy
800 inorder (AtkObject *collection, MatchRulePrivate *mrp,
801 GList *ls, gint kount, gint max,
805 dbus_bool_t traverse)
809 /* First, look through the children recursively. */
810 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
813 /* Next, we look through the right subtree */
814 while ((max == 0 || kount < max)
815 && obj != collection)
818 atk_object_get_parent (obj);
819 i = atk_object_get_index_in_parent (obj);
820 kount = sort_order_canonical (mrp, ls, kount, max, parent,
821 i+1, TRUE, FALSE, TRUE, TRUE);
827 kount = sort_order_canonical (mrp, ls, kount, max,
828 obj, i + 1, TRUE, FALSE,
836 GetMatchesInOrder: get matches from a given object in an inorder traversal.
840 GetMatchesInOrder (DBusMessage *message,
841 AtkObject *current_object,
842 MatchRulePrivate *mrp,
843 const Accessibility_Collection_SortOrder sortby,
844 const dbus_bool_t recurse,
846 const dbus_bool_t traverse)
852 ls = g_list_append (ls, current_object);
854 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
856 kount = inorder (obj, mrp, ls, 0, count,
857 current_object, TRUE, NULL, traverse);
859 ls = g_list_remove (ls, ls->data);
861 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
862 ls = g_list_reverse (ls);
865 return return_and_free_list (message, ls);
869 GetMatchesInBackOrder: get matches from a given object in a
870 reverse order traversal.
874 GetMatchesInBackOrder (DBusMessage *message,
875 AtkObject *current_object,
876 MatchRulePrivate *mrp,
877 const Accessibility_Collection_SortOrder sortby,
881 AtkObject *collection;
884 ls = g_list_append (ls, current_object);
886 collection = atk_dbus_path_to_object (dbus_message_get_path (message));
888 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
891 ls = g_list_remove (ls, ls->data);
893 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
894 ls = g_list_reverse (ls);
897 return return_and_free_list (message, ls);
901 GetMatchesTo (DBusMessage *message,
902 AtkObject *current_object,
903 MatchRulePrivate *mrp,
904 const Accessibility_Collection_SortOrder sortby,
905 const dbus_bool_t recurse,
906 const dbus_bool_t isrestrict,
908 const dbus_bool_t traverse)
913 ls = g_list_append (ls, current_object);
916 obj = atk_object_get_parent (current_object);
917 kount = query_exec (mrp, sortby, ls, 0, count,
918 obj, 0, TRUE, current_object, TRUE, traverse);
921 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
922 kount = query_exec (mrp, sortby, ls, 0, count,
923 obj, 0, TRUE, current_object, TRUE, traverse);
927 ls = g_list_remove (ls, ls->data);
929 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
930 ls = g_list_reverse (ls);
933 return return_and_free_list (message, ls);
937 impl_GetMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
939 char *current_object_path = NULL;
940 AtkObject *current_object;
941 DBusMessageIter iter;
942 MatchRulePrivate rule;
943 dbus_uint32_t sortby;
946 dbus_bool_t traverse;
948 const char *signature;
950 signature = dbus_message_get_signature(message);
951 if (strcmp (signature, "o(aiisiaiisib)uuib") != 0 &&
952 strcmp(signature, "o(aii(as)iaiisib)uuib") != 0)
954 return droute_invalid_arguments_error(message);
957 dbus_message_iter_init(message, &iter);
958 dbus_message_iter_get_basic (&iter, ¤t_object_path);
959 current_object = atk_dbus_path_to_object (current_object_path);
962 // TODO: object-not-found error
963 return spi_dbus_general_error (message);
965 dbus_message_iter_next (&iter);
966 if (!read_mr(&iter, &rule))
968 return spi_dbus_general_error (message);
970 dbus_message_iter_get_basic(&iter, &sortby);
971 dbus_message_iter_next(&iter);
972 dbus_message_iter_get_basic(&iter, &tree);
973 dbus_message_iter_next(&iter);
974 dbus_message_iter_get_basic(&iter, &count);
975 dbus_message_iter_next(&iter);
976 dbus_message_iter_get_basic(&iter, &traverse);
977 dbus_message_iter_next(&iter);
980 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
981 return GetMatchesFrom (message, current_object,
982 &rule, sortby, TRUE, count, traverse);
984 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
985 return GetMatchesFrom (message, current_object,
986 &rule, sortby, FALSE, count, traverse);
988 case Accessibility_Collection_TREE_INORDER :
989 return GetMatchesInOrder (message, current_object,
990 &rule, sortby, TRUE, count, traverse);
992 default : return NULL;
997 impl_GetMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
999 char *current_object_path = NULL;
1000 AtkObject *current_object;
1001 DBusMessageIter iter;
1002 MatchRulePrivate rule;
1003 dbus_uint32_t sortby;
1005 dbus_bool_t recurse;
1007 dbus_bool_t traverse;
1009 const char *signature;
1011 signature = dbus_message_get_signature(message);
1012 if (strcmp (signature, "o(aiisiaiisib)uubib") != 0 &&
1013 strcmp(signature, "o(aii(as)iaiisib)uubib") != 0)
1015 return droute_invalid_arguments_error(message);
1018 dbus_message_iter_init(message, &iter);
1019 dbus_message_iter_get_basic (&iter, ¤t_object_path);
1020 current_object = atk_dbus_path_to_object (current_object_path);
1021 if (!current_object)
1023 // TODO: object-not-found error
1024 return spi_dbus_general_error (message);
1026 dbus_message_iter_next (&iter);
1027 if (!read_mr(&iter, &rule))
1029 return spi_dbus_general_error (message);
1031 dbus_message_iter_get_basic(&iter, &sortby);
1032 dbus_message_iter_next(&iter);
1033 dbus_message_iter_get_basic(&iter, &tree);
1034 dbus_message_iter_next(&iter);
1035 dbus_message_iter_get_basic(&iter, &recurse);
1036 dbus_message_iter_next(&iter);
1037 dbus_message_iter_get_basic(&iter, &count);
1038 dbus_message_iter_next(&iter);
1039 dbus_message_iter_get_basic(&iter, &traverse);
1040 dbus_message_iter_next(&iter);
1043 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
1044 return GetMatchesTo (message, current_object,
1045 &rule, sortby, recurse, TRUE, count, traverse);
1047 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
1048 return GetMatchesTo (message, current_object,
1049 &rule, sortby, recurse, FALSE, count, traverse);
1051 case Accessibility_Collection_TREE_INORDER :
1052 return GetMatchesInBackOrder (message, current_object,
1053 &rule, sortby, count);
1055 default : return NULL;
1059 static DBusMessage *
1060 impl_GetMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
1062 AtkObject *obj = atk_dbus_path_to_object (dbus_message_get_path (message));
1063 DBusMessageIter iter;
1064 MatchRulePrivate rule;
1065 dbus_uint32_t sortby;
1067 dbus_bool_t traverse;
1069 const char *signature;
1071 signature = dbus_message_get_signature (message);
1072 if (strcmp (signature, "(aiisiaiisib)uib") != 0 &&
1073 strcmp(signature, "(aii(as)iaiisib)uib") != 0)
1075 return droute_invalid_arguments_error(message);
1078 dbus_message_iter_init(message, &iter);
1079 if (!read_mr(&iter, &rule))
1081 return spi_dbus_general_error (message);
1083 dbus_message_iter_get_basic(&iter, &sortby);
1084 dbus_message_iter_next(&iter);
1085 dbus_message_iter_get_basic(&iter, &count);
1086 dbus_message_iter_next(&iter);
1087 dbus_message_iter_get_basic(&iter, &traverse);
1088 dbus_message_iter_next(&iter);
1089 ls = g_list_prepend (ls, obj);
1090 count = query_exec (&rule, sortby, ls, 0, count,
1091 obj, 0, TRUE, NULL, TRUE, traverse);
1092 ls = g_list_remove (ls, ls->data);
1094 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1095 ls = g_list_reverse (ls);
1096 free_mrp_data (&rule);
1097 return return_and_free_list (message, ls);
1100 static DRouteMethod methods[] = {
1101 { impl_GetMatchesFrom, "GetMatchesFrom" },
1102 { impl_GetMatchesTo, "GetMatchesTo" },
1103 { impl_GetMatches, "GetMatches" },
1108 spi_initialize_collection (DRoutePath *path)
1110 droute_path_add_interface (path,
1111 SPI_DBUS_INTERFACE_COLLECTION,