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 "common/bitarray.h"
31 #include "common/spi-dbus.h"
32 #include "common/spi-stateset.h"
34 #include "accessible-register.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, gchar * repo_id)
54 if (!strcasecmp (repo_id, "action"))
55 return ATK_IS_ACTION (child);
56 if (!strcasecmp (repo_id, "component"))
57 return ATK_IS_COMPONENT (child);
58 if (!strcasecmp (repo_id, "editabletext"))
59 return ATK_IS_EDITABLE_TEXT (child);
60 if (!strcasecmp (repo_id, "text"))
61 return ATK_IS_TEXT (child);
62 if (!strcasecmp (repo_id, "hypertext"))
63 return ATK_IS_HYPERTEXT (child);
64 if (!strcasecmp (repo_id, "image"))
65 return ATK_IS_IMAGE (child);
66 if (!strcasecmp (repo_id, "selection"))
67 return ATK_IS_SELECTION (child);
68 if (!strcasecmp (repo_id, "table"))
69 return ATK_IS_TABLE (child);
70 if (!strcasecmp (repo_id, "value"))
71 return ATK_IS_VALUE (child);
72 if (!strcasecmp (repo_id, "streamablecontent"))
73 return ATK_IS_STREAMABLE_CONTENT (child);
74 if (!strcasecmp (repo_id, "document"))
75 return ATK_IS_DOCUMENT (child);
79 #define child_collection_p(ch) (TRUE)
82 match_states_all_p (AtkObject * child, gint * set)
91 chs = atk_object_ref_state_set (child);
93 // TODO: use atk-state_set_contains_states; would be more efficient
94 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
96 if (!atk_state_set_contains_state (chs, set[i]))
103 g_object_unref (chs);
108 match_states_any_p (AtkObject * child, gint * set)
112 gboolean ret = FALSE;
117 chs = atk_object_ref_state_set (child);
119 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
121 if (!atk_state_set_contains_state (chs, set[i]))
128 g_object_unref (chs);
133 match_states_none_p (AtkObject * child, gint * set)
142 chs = atk_object_ref_state_set (child);
144 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
146 if (atk_state_set_contains_state (chs, set[i]))
153 g_object_unref (chs);
157 // TODO: need to convert at-spi roles/states to atk roles/states */
159 match_states_lookup (AtkObject * child, MatchRulePrivate * mrp)
161 switch (mrp->statematchtype)
163 case Accessibility_Collection_MATCH_ALL:
164 if (match_states_all_p (child, mrp->states))
168 case Accessibility_Collection_MATCH_ANY:
169 if (match_states_any_p (child, mrp->states))
173 case Accessibility_Collection_MATCH_NONE:
174 if (match_states_none_p (child, mrp->states))
185 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
186 // would be more efficient
187 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
190 match_roles_all_p (AtkObject * child, gint * roles)
192 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
194 else if (roles[1] != BITARRAY_SEQ_TERM)
197 return (atk_object_get_role (child) == roles[0]);
202 match_roles_any_p (AtkObject * child, gint * roles)
204 Accessibility_Role role;
207 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
210 role = spi_accessible_role_from_atk_role (atk_object_get_role (child));
212 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
213 if (role == roles[i])
220 match_roles_none_p (AtkObject * child, gint * roles)
225 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
228 role = atk_object_get_role (child);
230 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
231 if (role == roles[i])
238 match_roles_lookup (AtkObject * child, MatchRulePrivate * mrp)
240 switch (mrp->rolematchtype)
242 case Accessibility_Collection_MATCH_ALL:
243 if (match_roles_all_p (child, mrp->roles))
247 case Accessibility_Collection_MATCH_ANY:
248 if (match_roles_any_p (child, mrp->roles))
252 case Accessibility_Collection_MATCH_NONE:
253 if (match_roles_none_p (child, mrp->roles))
265 match_interfaces_all_p (AtkObject * obj, gchar ** ifaces)
272 for (i = 0; ifaces[i]; i++)
273 if (!child_interface_p (obj, ifaces[i]))
281 match_interfaces_any_p (AtkObject * obj, gchar ** ifaces)
289 for (i = 0; ifaces[i]; i++)
290 if (child_interface_p (obj, ifaces[i]))
298 match_interfaces_none_p (AtkObject * obj, gchar ** ifaces)
302 for (i = 0; ifaces[i]; i++)
303 if (child_interface_p (obj, ifaces[i]))
310 match_interfaces_lookup (AtkObject * child, MatchRulePrivate * mrp)
312 switch (mrp->interfacematchtype)
315 case Accessibility_Collection_MATCH_ALL:
316 if (match_interfaces_all_p (child, mrp->ifaces))
320 case Accessibility_Collection_MATCH_ANY:
321 if (match_interfaces_any_p (child, mrp->ifaces))
325 case Accessibility_Collection_MATCH_NONE:
326 if (match_interfaces_none_p (child, mrp->ifaces))
337 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
340 match_attributes_all_p (AtkObject * child, AtkAttributeSet * attributes)
344 gint length, oa_length;
345 gboolean flag = FALSE;
347 if (attributes == NULL || g_slist_length (attributes) == 0)
350 oa = atk_object_get_attributes (child);
351 length = g_slist_length (attributes);
352 oa_length = g_slist_length (oa);
354 for (i = 0; i < length; i++)
356 AtkAttribute *attr = g_slist_nth_data (attributes, i);
357 for (k = 0; k < oa_length; k++)
359 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
360 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
361 !g_ascii_strcasecmp (oa_attr->value, attr->value))
371 atk_attribute_set_free (oa);
375 atk_attribute_set_free (oa);
380 match_attributes_any_p (AtkObject * child, AtkAttributeSet * attributes)
385 gint length, oa_length;
387 length = g_slist_length (attributes);
391 oa = atk_object_get_attributes (child);
392 oa_length = g_slist_length (oa);
394 for (i = 0; i < length; i++)
396 AtkAttribute *attr = g_slist_nth_data (attributes, i);
397 for (k = 0; k < oa_length; k++)
399 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
400 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
401 !g_ascii_strcasecmp (oa_attr->value, attr->value))
403 atk_attribute_set_free (oa);
408 atk_attribute_set_free (oa);
413 match_attributes_none_p (AtkObject * child, AtkAttributeSet * attributes)
418 gint length, oa_length;
420 length = g_slist_length (attributes);
424 oa = atk_object_get_attributes (child);
425 oa_length = g_slist_length (oa);
427 for (i = 0; i < length; i++)
429 AtkAttribute *attr = g_slist_nth_data (attributes, i);
430 for (k = 0; k < oa_length; k++)
432 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
433 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
434 !g_ascii_strcasecmp (oa_attr->value, attr->value))
436 atk_attribute_set_free (oa);
441 atk_attribute_set_free (oa);
446 match_attributes_lookup (AtkObject * child, MatchRulePrivate * mrp)
448 switch (mrp->attributematchtype)
451 case Accessibility_Collection_MATCH_ALL:
452 if (match_attributes_all_p (child, mrp->attributes))
456 case Accessibility_Collection_MATCH_ANY:
457 if (match_attributes_any_p (child, mrp->attributes))
461 case Accessibility_Collection_MATCH_NONE:
462 if (match_attributes_none_p (child, mrp->attributes))
473 traverse_p (AtkObject * child, const gboolean traverse)
478 return !child_collection_p (child);
482 sort_order_canonical (MatchRulePrivate * mrp, GList * ls,
483 gint kount, gint max,
484 AtkObject * obj, glong index, gboolean flag,
485 AtkObject * pobj, gboolean recurse, gboolean traverse)
488 glong acount = atk_object_get_n_accessible_children (obj);
489 gboolean prev = pobj ? TRUE : FALSE;
491 for (; i < acount && (max == 0 || kount < max); i++)
493 AtkObject *child = atk_object_ref_accessible_child (obj, i);
495 g_object_unref (child);
496 if (prev && child == pobj)
501 if (flag && match_interfaces_lookup (child, mrp)
502 && match_states_lookup (child, mrp)
503 && match_roles_lookup (child, mrp)
504 && match_attributes_lookup (child, mrp))
507 ls = g_list_append (ls, child);
514 if (recurse && traverse_p (child, traverse))
515 kount = sort_order_canonical (mrp, ls, kount,
517 pobj, recurse, traverse);
523 sort_order_rev_canonical (MatchRulePrivate * mrp, GList * ls,
524 gint kount, gint max,
525 AtkObject * obj, gboolean flag, AtkObject * pobj)
531 /* This breaks us out of the recursion. */
532 if (!obj || obj == pobj)
537 /* Add to the list if it matches */
538 if (flag && match_interfaces_lookup (obj, mrp)
539 && match_states_lookup (obj, mrp)
540 && match_roles_lookup (obj, mrp) && match_attributes_lookup (obj, mrp))
542 ls = g_list_append (ls, obj);
549 /* Get the current nodes index in it's parent and the parent object. */
550 indexinparent = atk_object_get_index_in_parent (obj);
551 parent = atk_object_get_parent (obj);
553 if (indexinparent > 0)
555 /* there are still some siblings to visit so get the previous sibling
556 and get it's last descendant.
557 First, get the previous sibling */
558 nextobj = atk_object_ref_accessible_child (parent, indexinparent - 1);
559 g_object_unref (nextobj);
561 /* Now, drill down the right side to the last descendant */
562 while (atk_object_get_n_accessible_children (nextobj) > 0)
564 nextobj = atk_object_ref_accessible_child (nextobj,
565 atk_object_get_n_accessible_children
567 g_object_unref (nextobj);
569 /* recurse with the last descendant */
570 kount = sort_order_rev_canonical (mrp, ls, kount, max,
571 nextobj, TRUE, pobj);
575 /* no more siblings so next node must be the parent */
576 kount = sort_order_rev_canonical (mrp, ls, kount, max,
584 query_exec (MatchRulePrivate * mrp, Accessibility_Collection_SortOrder sortby,
585 GList * ls, gint kount, gint max,
586 AtkObject * obj, glong index,
588 AtkObject * pobj, gboolean recurse, gboolean traverse)
592 case Accessibility_Collection_SORT_ORDER_CANONICAL:
593 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
594 pobj, recurse, traverse);
596 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL:
597 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
598 pobj, recurse, traverse);
602 g_warning ("Sort method not implemented yet");
610 bitarray_to_seq (int *array, int array_count, int **ret)
615 int *out = (int *) g_malloc (out_size * sizeof (int));
619 for (i = 0; i < array_count; i++)
621 for (j = 0; j < 32; j++)
623 if (array[i] & (1 << j))
625 if (out_count == out_size - 2)
628 out = (int *) g_realloc (out, out_size * sizeof (int));
632 out[out_count++] = i * 32 + j;
636 out[out_count] = BITARRAY_SEQ_TERM;
643 read_mr (DBusMessageIter * iter, MatchRulePrivate * mrp)
645 DBusMessageIter mrc, arrayc;
646 dbus_uint32_t *array;
647 dbus_int32_t matchType;
652 char *interfaces = NULL;
654 dbus_message_iter_recurse (iter, &mrc);
655 dbus_message_iter_recurse (&mrc, &arrayc);
656 dbus_message_iter_get_fixed_array (&arrayc, &array, &array_count);
657 bitarray_to_seq (array, array_count, &mrp->states);
658 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
660 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
662 dbus_message_iter_next (&mrc);
663 dbus_message_iter_get_basic (&mrc, &matchType);
664 dbus_message_iter_next (&mrc);
665 mrp->statematchtype = matchType;;
667 mrp->attributes = NULL;
668 if (dbus_message_iter_get_arg_type (&mrc) == DBUS_TYPE_STRING)
673 dbus_message_iter_get_basic (&mrc, &str);
674 attributes = g_strsplit (str, "\n", -1);
675 for (pp = attributes; *pp; pp++)
678 attr = g_new (AtkAttribute, 1);
681 int len = strcspn (str, ":");
682 attr->name = g_strndup (str, len);
688 attr->value = g_strdup (str + len);
692 mrp->attributes = g_slist_prepend (mrp->attributes, attr);
695 g_strfreev (attributes);
699 dbus_message_iter_recurse (&mrc, &arrayc);
700 while (dbus_message_iter_get_arg_type (&arrayc) != DBUS_TYPE_INVALID)
702 dbus_message_iter_get_basic (&arrayc, &str);
703 // TODO: remove this print
704 g_print ("Got attribute: %s\n", str);
705 attr = g_new (AtkAttribute, 1);
708 int len = strcspn (str, ":");
709 attr->name = g_strndup (str, len);
715 attr->value = g_strdup (str + len);
719 mrp->attributes = g_slist_prepend (mrp->attributes, attr);
721 dbus_message_iter_next (&arrayc);
724 dbus_message_iter_next (&mrc);
725 dbus_message_iter_get_basic (&mrc, &matchType);
726 mrp->attributematchtype = matchType;;
727 dbus_message_iter_next (&mrc);
728 /* Get roles and role match */
729 dbus_message_iter_recurse (&mrc, &arrayc);
730 dbus_message_iter_get_fixed_array (&arrayc, &array, &array_count);
731 bitarray_to_seq (array, array_count, &mrp->roles);
732 dbus_message_iter_next (&mrc);
733 dbus_message_iter_get_basic (&mrc, &matchType);
734 mrp->rolematchtype = matchType;;
735 dbus_message_iter_next (&mrc);
736 /* Get interfaces and interface match */
737 dbus_message_iter_get_basic (&mrc, &interfaces);
738 dbus_message_iter_next (&mrc);
739 mrp->ifaces = g_strsplit (interfaces, ";", 0);
740 dbus_message_iter_get_basic (&mrc, &matchType);
741 mrp->interfacematchtype = matchType;;
742 dbus_message_iter_next (&mrc);
744 dbus_message_iter_get_basic (&mrc, &mrp->invert);
745 dbus_message_iter_next (iter);
750 return_and_free_list (DBusMessage * message, GList * ls)
753 DBusMessageIter iter, iter_array;
756 reply = dbus_message_new_method_return (message);
759 dbus_message_iter_init_append (reply, &iter);
760 if (!dbus_message_iter_open_container
761 (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
763 for (item = ls; item; item = g_list_next (item))
765 spi_object_append_reference (&iter_array, ATK_OBJECT (item->data));
767 if (!dbus_message_iter_close_container (&iter, &iter_array))
772 // TODO: Handle out of memory
778 free_mrp_data (MatchRulePrivate * mrp)
780 g_free (mrp->states);
781 atk_attribute_set_free (mrp->attributes);
783 g_strfreev (mrp->ifaces);
787 GetMatchesFrom (DBusMessage * message,
788 AtkObject * current_object,
789 MatchRulePrivate * mrp,
790 const Accessibility_Collection_SortOrder sortby,
791 const dbus_bool_t isrestrict,
792 dbus_int32_t count, const dbus_bool_t traverse)
796 glong index = atk_object_get_index_in_parent (current_object);
799 ls = g_list_append (ls, current_object);
803 parent = atk_object_get_parent (current_object);
804 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
805 FALSE, NULL, TRUE, traverse);
808 kount = query_exec (mrp, sortby, ls, 0, count,
809 current_object, 0, FALSE, NULL, TRUE, traverse);
811 ls = g_list_remove (ls, ls->data);
813 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
814 ls = g_list_reverse (ls);
817 return return_and_free_list (message, ls);
821 inorder traversal from a given object in the hierarchy
825 inorder (AtkObject * collection, MatchRulePrivate * mrp,
826 GList * ls, gint kount, gint max,
828 gboolean flag, AtkObject * pobj, dbus_bool_t traverse)
832 /* First, look through the children recursively. */
833 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
836 /* Next, we look through the right subtree */
837 while ((max == 0 || kount < max) && obj != collection)
839 AtkObject *parent = atk_object_get_parent (obj);
840 i = atk_object_get_index_in_parent (obj);
841 kount = sort_order_canonical (mrp, ls, kount, max, parent,
842 i + 1, TRUE, FALSE, TRUE, TRUE);
848 kount = sort_order_canonical (mrp, ls, kount, max,
849 obj, i + 1, TRUE, FALSE, TRUE, TRUE);
856 GetMatchesInOrder: get matches from a given object in an inorder traversal.
860 GetMatchesInOrder (DBusMessage * message,
861 AtkObject * current_object,
862 MatchRulePrivate * mrp,
863 const Accessibility_Collection_SortOrder sortby,
864 const dbus_bool_t recurse,
865 dbus_int32_t count, const dbus_bool_t traverse)
871 ls = g_list_append (ls, current_object);
873 obj = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
875 kount = inorder (obj, mrp, ls, 0, count,
876 current_object, TRUE, NULL, traverse);
878 ls = g_list_remove (ls, ls->data);
880 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
881 ls = g_list_reverse (ls);
884 return return_and_free_list (message, ls);
888 GetMatchesInBackOrder: get matches from a given object in a
889 reverse order traversal.
893 GetMatchesInBackOrder (DBusMessage * message,
894 AtkObject * current_object,
895 MatchRulePrivate * mrp,
896 const Accessibility_Collection_SortOrder sortby,
900 AtkObject *collection;
903 ls = g_list_append (ls, current_object);
905 collection = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
907 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
910 ls = g_list_remove (ls, ls->data);
912 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
913 ls = g_list_reverse (ls);
916 return return_and_free_list (message, ls);
920 GetMatchesTo (DBusMessage * message,
921 AtkObject * current_object,
922 MatchRulePrivate * mrp,
923 const Accessibility_Collection_SortOrder sortby,
924 const dbus_bool_t recurse,
925 const dbus_bool_t isrestrict,
926 dbus_int32_t count, const dbus_bool_t traverse)
931 ls = g_list_append (ls, current_object);
935 obj = ATK_OBJECT (atk_object_get_parent (current_object));
936 kount = query_exec (mrp, sortby, ls, 0, count,
937 obj, 0, TRUE, current_object, TRUE, traverse);
941 obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
942 kount = query_exec (mrp, sortby, ls, 0, count,
943 obj, 0, TRUE, current_object, TRUE, traverse);
947 ls = g_list_remove (ls, ls->data);
949 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
950 ls = g_list_reverse (ls);
953 return return_and_free_list (message, ls);
957 impl_GetMatchesFrom (DBusConnection * bus, DBusMessage * message,
960 char *current_object_path = NULL;
961 AtkObject *current_object;
962 DBusMessageIter iter;
963 MatchRulePrivate rule;
964 dbus_uint32_t sortby;
967 dbus_bool_t traverse;
969 const char *signature;
971 signature = dbus_message_get_signature (message);
972 if (strcmp (signature, "o(aiisiaiisib)uuib") != 0 &&
973 strcmp (signature, "o(aii(as)iaiisib)uuib") != 0)
975 return droute_invalid_arguments_error (message);
978 dbus_message_iter_init (message, &iter);
979 dbus_message_iter_get_basic (&iter, ¤t_object_path);
980 current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
983 // TODO: object-not-found error
984 return spi_dbus_general_error (message);
986 dbus_message_iter_next (&iter);
987 if (!read_mr (&iter, &rule))
989 return spi_dbus_general_error (message);
991 dbus_message_iter_get_basic (&iter, &sortby);
992 dbus_message_iter_next (&iter);
993 dbus_message_iter_get_basic (&iter, &tree);
994 dbus_message_iter_next (&iter);
995 dbus_message_iter_get_basic (&iter, &count);
996 dbus_message_iter_next (&iter);
997 dbus_message_iter_get_basic (&iter, &traverse);
998 dbus_message_iter_next (&iter);
1002 case Accessibility_Collection_TREE_RESTRICT_CHILDREN:
1003 return GetMatchesFrom (message, current_object,
1004 &rule, sortby, TRUE, count, traverse);
1006 case Accessibility_Collection_TREE_RESTRICT_SIBLING:
1007 return GetMatchesFrom (message, current_object,
1008 &rule, sortby, FALSE, count, traverse);
1010 case Accessibility_Collection_TREE_INORDER:
1011 return GetMatchesInOrder (message, current_object,
1012 &rule, sortby, TRUE, count, traverse);
1019 static DBusMessage *
1020 impl_GetMatchesTo (DBusConnection * bus, DBusMessage * message,
1023 char *current_object_path = NULL;
1024 AtkObject *current_object;
1025 DBusMessageIter iter;
1026 MatchRulePrivate rule;
1027 dbus_uint32_t sortby;
1029 dbus_bool_t recurse;
1031 dbus_bool_t traverse;
1033 const char *signature;
1035 signature = dbus_message_get_signature (message);
1036 if (strcmp (signature, "o(aiisiaiisib)uubib") != 0 &&
1037 strcmp (signature, "o(aii(as)iaiisib)uubib") != 0)
1039 return droute_invalid_arguments_error (message);
1042 dbus_message_iter_init (message, &iter);
1043 dbus_message_iter_get_basic (&iter, ¤t_object_path);
1044 current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
1045 if (!current_object)
1047 // TODO: object-not-found error
1048 return spi_dbus_general_error (message);
1050 dbus_message_iter_next (&iter);
1051 if (!read_mr (&iter, &rule))
1053 return spi_dbus_general_error (message);
1055 dbus_message_iter_get_basic (&iter, &sortby);
1056 dbus_message_iter_next (&iter);
1057 dbus_message_iter_get_basic (&iter, &tree);
1058 dbus_message_iter_next (&iter);
1059 dbus_message_iter_get_basic (&iter, &recurse);
1060 dbus_message_iter_next (&iter);
1061 dbus_message_iter_get_basic (&iter, &count);
1062 dbus_message_iter_next (&iter);
1063 dbus_message_iter_get_basic (&iter, &traverse);
1064 dbus_message_iter_next (&iter);
1068 case Accessibility_Collection_TREE_RESTRICT_CHILDREN:
1069 return GetMatchesTo (message, current_object,
1070 &rule, sortby, recurse, TRUE, count, traverse);
1072 case Accessibility_Collection_TREE_RESTRICT_SIBLING:
1073 return GetMatchesTo (message, current_object,
1074 &rule, sortby, recurse, FALSE, count, traverse);
1076 case Accessibility_Collection_TREE_INORDER:
1077 return GetMatchesInBackOrder (message, current_object,
1078 &rule, sortby, count);
1085 static DBusMessage *
1086 impl_GetMatches (DBusConnection * bus, DBusMessage * message, void *user_data)
1088 AtkObject *obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
1089 DBusMessageIter iter;
1090 MatchRulePrivate rule;
1091 dbus_uint32_t sortby;
1093 dbus_bool_t traverse;
1095 const char *signature;
1097 signature = dbus_message_get_signature (message);
1098 if (strcmp (signature, "(aiisiaiisib)uib") != 0 &&
1099 strcmp (signature, "(aii(as)iaiisib)uib") != 0)
1101 return droute_invalid_arguments_error (message);
1104 dbus_message_iter_init (message, &iter);
1105 if (!read_mr (&iter, &rule))
1107 return spi_dbus_general_error (message);
1109 dbus_message_iter_get_basic (&iter, &sortby);
1110 dbus_message_iter_next (&iter);
1111 dbus_message_iter_get_basic (&iter, &count);
1112 dbus_message_iter_next (&iter);
1113 dbus_message_iter_get_basic (&iter, &traverse);
1114 dbus_message_iter_next (&iter);
1115 ls = g_list_prepend (ls, obj);
1116 count = query_exec (&rule, sortby, ls, 0, count,
1117 obj, 0, TRUE, NULL, TRUE, traverse);
1118 ls = g_list_remove (ls, ls->data);
1120 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1121 ls = g_list_reverse (ls);
1122 free_mrp_data (&rule);
1123 return return_and_free_list (message, ls);
1126 static DRouteMethod methods[] = {
1127 {impl_GetMatchesFrom, "GetMatchesFrom"},
1128 {impl_GetMatchesTo, "GetMatchesTo"},
1129 {impl_GetMatches, "GetMatches"},
1134 spi_initialize_collection (DRoutePath * path)
1136 droute_path_add_interface (path,
1137 SPI_DBUS_INTERFACE_COLLECTION, methods, NULL);