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"
36 #include "introspection.h"
38 typedef struct _MatchRulePrivate MatchRulePrivate;
39 struct _MatchRulePrivate
42 Accessibility_Collection_MatchType statematchtype;
43 AtkAttributeSet *attributes;
44 Accessibility_Collection_MatchType attributematchtype;
46 Accessibility_Collection_MatchType rolematchtype;
48 Accessibility_Collection_MatchType interfacematchtype;
53 child_interface_p (AtkObject * child, gchar * repo_id)
55 if (!strcasecmp (repo_id, "action"))
56 return ATK_IS_ACTION (child);
57 if (!strcasecmp (repo_id, "component"))
58 return ATK_IS_COMPONENT (child);
59 if (!strcasecmp (repo_id, "editabletext"))
60 return ATK_IS_EDITABLE_TEXT (child);
61 if (!strcasecmp (repo_id, "text"))
62 return ATK_IS_TEXT (child);
63 if (!strcasecmp (repo_id, "hypertext"))
64 return ATK_IS_HYPERTEXT (child);
65 if (!strcasecmp (repo_id, "image"))
66 return ATK_IS_IMAGE (child);
67 if (!strcasecmp (repo_id, "selection"))
68 return ATK_IS_SELECTION (child);
69 if (!strcasecmp (repo_id, "table"))
70 return ATK_IS_TABLE (child);
71 if (!strcasecmp (repo_id, "value"))
72 return ATK_IS_VALUE (child);
73 if (!strcasecmp (repo_id, "streamablecontent"))
74 return ATK_IS_STREAMABLE_CONTENT (child);
75 if (!strcasecmp (repo_id, "document"))
76 return ATK_IS_DOCUMENT (child);
80 #define child_collection_p(ch) (TRUE)
83 match_states_all_p (AtkObject * child, gint * set)
92 chs = atk_object_ref_state_set (child);
94 // TODO: use atk-state_set_contains_states; would be more efficient
95 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
97 if (!atk_state_set_contains_state (chs, set[i]))
104 g_object_unref (chs);
109 match_states_any_p (AtkObject * child, gint * set)
113 gboolean ret = FALSE;
118 chs = atk_object_ref_state_set (child);
120 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
122 if (!atk_state_set_contains_state (chs, set[i]))
129 g_object_unref (chs);
134 match_states_none_p (AtkObject * child, gint * set)
143 chs = atk_object_ref_state_set (child);
145 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
147 if (atk_state_set_contains_state (chs, set[i]))
154 g_object_unref (chs);
158 // TODO: need to convert at-spi roles/states to atk roles/states */
160 match_states_lookup (AtkObject * child, MatchRulePrivate * mrp)
162 switch (mrp->statematchtype)
164 case Accessibility_Collection_MATCH_ALL:
165 if (match_states_all_p (child, mrp->states))
169 case Accessibility_Collection_MATCH_ANY:
170 if (match_states_any_p (child, mrp->states))
174 case Accessibility_Collection_MATCH_NONE:
175 if (match_states_none_p (child, mrp->states))
186 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
187 // would be more efficient
188 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
191 match_roles_all_p (AtkObject * child, gint * roles)
193 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
195 else if (roles[1] != BITARRAY_SEQ_TERM)
198 return (atk_object_get_role (child) == roles[0]);
203 match_roles_any_p (AtkObject * child, gint * roles)
205 Accessibility_Role role;
208 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
211 role = spi_accessible_role_from_atk_role (atk_object_get_role (child));
213 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
214 if (role == roles[i])
221 match_roles_none_p (AtkObject * child, gint * roles)
226 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
229 role = atk_object_get_role (child);
231 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
232 if (role == roles[i])
239 match_roles_lookup (AtkObject * child, MatchRulePrivate * mrp)
241 switch (mrp->rolematchtype)
243 case Accessibility_Collection_MATCH_ALL:
244 if (match_roles_all_p (child, mrp->roles))
248 case Accessibility_Collection_MATCH_ANY:
249 if (match_roles_any_p (child, mrp->roles))
253 case Accessibility_Collection_MATCH_NONE:
254 if (match_roles_none_p (child, mrp->roles))
266 match_interfaces_all_p (AtkObject * obj, gchar ** ifaces)
273 for (i = 0; ifaces[i]; i++)
274 if (!child_interface_p (obj, ifaces[i]))
282 match_interfaces_any_p (AtkObject * obj, gchar ** ifaces)
290 for (i = 0; ifaces[i]; i++)
291 if (child_interface_p (obj, ifaces[i]))
299 match_interfaces_none_p (AtkObject * obj, gchar ** ifaces)
303 for (i = 0; ifaces[i]; i++)
304 if (child_interface_p (obj, ifaces[i]))
311 match_interfaces_lookup (AtkObject * child, MatchRulePrivate * mrp)
313 switch (mrp->interfacematchtype)
316 case Accessibility_Collection_MATCH_ALL:
317 if (match_interfaces_all_p (child, mrp->ifaces))
321 case Accessibility_Collection_MATCH_ANY:
322 if (match_interfaces_any_p (child, mrp->ifaces))
326 case Accessibility_Collection_MATCH_NONE:
327 if (match_interfaces_none_p (child, mrp->ifaces))
338 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
341 match_attributes_all_p (AtkObject * child, AtkAttributeSet * attributes)
345 gint length, oa_length;
346 gboolean flag = FALSE;
348 if (attributes == NULL || g_slist_length (attributes) == 0)
351 oa = atk_object_get_attributes (child);
352 length = g_slist_length (attributes);
353 oa_length = g_slist_length (oa);
355 for (i = 0; i < length; i++)
357 AtkAttribute *attr = g_slist_nth_data (attributes, i);
358 for (k = 0; k < oa_length; k++)
360 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
361 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
362 !g_ascii_strcasecmp (oa_attr->value, attr->value))
372 atk_attribute_set_free (oa);
376 atk_attribute_set_free (oa);
381 match_attributes_any_p (AtkObject * child, AtkAttributeSet * attributes)
386 gint length, oa_length;
388 length = g_slist_length (attributes);
392 oa = atk_object_get_attributes (child);
393 oa_length = g_slist_length (oa);
395 for (i = 0; i < length; i++)
397 AtkAttribute *attr = g_slist_nth_data (attributes, i);
398 for (k = 0; k < oa_length; k++)
400 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
401 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
402 !g_ascii_strcasecmp (oa_attr->value, attr->value))
404 atk_attribute_set_free (oa);
409 atk_attribute_set_free (oa);
414 match_attributes_none_p (AtkObject * child, AtkAttributeSet * attributes)
419 gint length, oa_length;
421 length = g_slist_length (attributes);
425 oa = atk_object_get_attributes (child);
426 oa_length = g_slist_length (oa);
428 for (i = 0; i < length; i++)
430 AtkAttribute *attr = g_slist_nth_data (attributes, i);
431 for (k = 0; k < oa_length; k++)
433 AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
434 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
435 !g_ascii_strcasecmp (oa_attr->value, attr->value))
437 atk_attribute_set_free (oa);
442 atk_attribute_set_free (oa);
447 match_attributes_lookup (AtkObject * child, MatchRulePrivate * mrp)
449 switch (mrp->attributematchtype)
452 case Accessibility_Collection_MATCH_ALL:
453 if (match_attributes_all_p (child, mrp->attributes))
457 case Accessibility_Collection_MATCH_ANY:
458 if (match_attributes_any_p (child, mrp->attributes))
462 case Accessibility_Collection_MATCH_NONE:
463 if (match_attributes_none_p (child, mrp->attributes))
474 traverse_p (AtkObject * child, const gboolean traverse)
479 return !child_collection_p (child);
483 sort_order_canonical (MatchRulePrivate * mrp, GList * ls,
484 gint kount, gint max,
485 AtkObject * obj, glong index, gboolean flag,
486 AtkObject * pobj, gboolean recurse, gboolean traverse)
489 glong acount = atk_object_get_n_accessible_children (obj);
490 gboolean prev = pobj ? TRUE : FALSE;
492 for (; i < acount && (max == 0 || kount < max); i++)
494 AtkObject *child = atk_object_ref_accessible_child (obj, i);
496 g_object_unref (child);
497 if (prev && child == pobj)
502 if (flag && match_interfaces_lookup (child, mrp)
503 && match_states_lookup (child, mrp)
504 && match_roles_lookup (child, mrp)
505 && match_attributes_lookup (child, mrp))
508 ls = g_list_append (ls, child);
515 if (recurse && traverse_p (child, traverse))
516 kount = sort_order_canonical (mrp, ls, kount,
518 pobj, recurse, traverse);
524 sort_order_rev_canonical (MatchRulePrivate * mrp, GList * ls,
525 gint kount, gint max,
526 AtkObject * obj, gboolean flag, AtkObject * pobj)
532 /* This breaks us out of the recursion. */
533 if (!obj || obj == pobj)
538 /* Add to the list if it matches */
539 if (flag && match_interfaces_lookup (obj, mrp)
540 && match_states_lookup (obj, mrp)
541 && match_roles_lookup (obj, mrp) && match_attributes_lookup (obj, mrp)
542 && (max == 0 || kount < max))
544 ls = g_list_append (ls, obj);
551 /* Get the current nodes index in it's parent and the parent object. */
552 indexinparent = atk_object_get_index_in_parent (obj);
553 parent = atk_object_get_parent (obj);
555 if (indexinparent > 0 && (max == 0 || kount < max))
557 /* there are still some siblings to visit so get the previous sibling
558 and get it's last descendant.
559 First, get the previous sibling */
560 nextobj = atk_object_ref_accessible_child (parent, indexinparent - 1);
561 g_object_unref (nextobj);
563 /* Now, drill down the right side to the last descendant */
564 while (atk_object_get_n_accessible_children (nextobj) > 0)
566 nextobj = atk_object_ref_accessible_child (nextobj,
567 atk_object_get_n_accessible_children
569 g_object_unref (nextobj);
571 /* recurse with the last descendant */
572 kount = sort_order_rev_canonical (mrp, ls, kount, max,
573 nextobj, TRUE, pobj);
575 else if (max == 0 || kount < max)
577 /* no more siblings so next node must be the parent */
578 kount = sort_order_rev_canonical (mrp, ls, kount, max,
586 query_exec (MatchRulePrivate * mrp, Accessibility_Collection_SortOrder sortby,
587 GList * ls, gint kount, gint max,
588 AtkObject * obj, glong index,
590 AtkObject * pobj, gboolean recurse, gboolean traverse)
594 case Accessibility_Collection_SORT_ORDER_CANONICAL:
595 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
596 pobj, recurse, traverse);
598 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL:
599 kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
600 pobj, recurse, traverse);
604 g_warning ("Sort method not implemented yet");
612 bitarray_to_seq (int *array, int array_count, int **ret)
617 int *out = (int *) g_malloc (out_size * sizeof (int));
621 for (i = 0; i < array_count; i++)
623 for (j = 0; j < 32; j++)
625 if (array[i] & (1 << j))
627 if (out_count == out_size - 2)
630 out = (int *) g_realloc (out, out_size * sizeof (int));
634 out[out_count++] = i * 32 + j;
638 out[out_count] = BITARRAY_SEQ_TERM;
645 read_mr (DBusMessageIter * iter, MatchRulePrivate * mrp)
647 DBusMessageIter mrc, arrayc;
648 dbus_uint32_t *array;
649 dbus_int32_t matchType;
654 char *interfaces = NULL;
656 dbus_message_iter_recurse (iter, &mrc);
657 dbus_message_iter_recurse (&mrc, &arrayc);
658 dbus_message_iter_get_fixed_array (&arrayc, &array, &array_count);
659 bitarray_to_seq (array, array_count, &mrp->states);
660 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
662 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
664 dbus_message_iter_next (&mrc);
665 dbus_message_iter_get_basic (&mrc, &matchType);
666 dbus_message_iter_next (&mrc);
667 mrp->statematchtype = matchType;;
669 mrp->attributes = NULL;
670 if (dbus_message_iter_get_arg_type (&mrc) == DBUS_TYPE_STRING)
675 dbus_message_iter_get_basic (&mrc, &str);
676 attributes = g_strsplit (str, "\n", -1);
677 for (pp = attributes; *pp; pp++)
680 attr = g_new (AtkAttribute, 1);
683 int len = strcspn (str, ":");
684 attr->name = g_strndup (str, len);
690 attr->value = g_strdup (str + len);
694 mrp->attributes = g_slist_prepend (mrp->attributes, attr);
697 g_strfreev (attributes);
701 dbus_message_iter_recurse (&mrc, &arrayc);
702 while (dbus_message_iter_get_arg_type (&arrayc) != DBUS_TYPE_INVALID)
704 dbus_message_iter_get_basic (&arrayc, &str);
705 // TODO: remove this print
706 g_print ("Got attribute: %s\n", str);
707 attr = g_new (AtkAttribute, 1);
710 int len = strcspn (str, ":");
711 attr->name = g_strndup (str, len);
717 attr->value = g_strdup (str + len);
721 mrp->attributes = g_slist_prepend (mrp->attributes, attr);
723 dbus_message_iter_next (&arrayc);
726 dbus_message_iter_next (&mrc);
727 dbus_message_iter_get_basic (&mrc, &matchType);
728 mrp->attributematchtype = matchType;;
729 dbus_message_iter_next (&mrc);
730 /* Get roles and role match */
731 dbus_message_iter_recurse (&mrc, &arrayc);
732 dbus_message_iter_get_fixed_array (&arrayc, &array, &array_count);
733 bitarray_to_seq (array, array_count, &mrp->roles);
734 dbus_message_iter_next (&mrc);
735 dbus_message_iter_get_basic (&mrc, &matchType);
736 mrp->rolematchtype = matchType;;
737 dbus_message_iter_next (&mrc);
738 /* Get interfaces and interface match */
739 dbus_message_iter_get_basic (&mrc, &interfaces);
740 dbus_message_iter_next (&mrc);
741 mrp->ifaces = g_strsplit (interfaces, ";", 0);
742 dbus_message_iter_get_basic (&mrc, &matchType);
743 mrp->interfacematchtype = matchType;;
744 dbus_message_iter_next (&mrc);
746 dbus_message_iter_get_basic (&mrc, &mrp->invert);
747 dbus_message_iter_next (iter);
752 return_and_free_list (DBusMessage * message, GList * ls)
755 DBusMessageIter iter, iter_array;
758 reply = dbus_message_new_method_return (message);
761 dbus_message_iter_init_append (reply, &iter);
762 if (!dbus_message_iter_open_container
763 (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
765 for (item = ls; item; item = g_list_next (item))
767 spi_object_append_reference (&iter_array, ATK_OBJECT (item->data));
769 if (!dbus_message_iter_close_container (&iter, &iter_array))
774 // TODO: Handle out of memory
780 free_mrp_data (MatchRulePrivate * mrp)
782 g_free (mrp->states);
783 atk_attribute_set_free (mrp->attributes);
785 g_strfreev (mrp->ifaces);
789 GetMatchesFrom (DBusMessage * message,
790 AtkObject * current_object,
791 MatchRulePrivate * mrp,
792 const Accessibility_Collection_SortOrder sortby,
793 const dbus_bool_t isrestrict,
794 dbus_int32_t count, const dbus_bool_t traverse)
798 glong index = atk_object_get_index_in_parent (current_object);
801 ls = g_list_append (ls, current_object);
805 parent = atk_object_get_parent (current_object);
806 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
807 FALSE, NULL, TRUE, traverse);
810 kount = query_exec (mrp, sortby, ls, 0, count,
811 current_object, 0, FALSE, NULL, TRUE, traverse);
813 ls = g_list_remove (ls, ls->data);
815 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
816 ls = g_list_reverse (ls);
819 return return_and_free_list (message, ls);
823 inorder traversal from a given object in the hierarchy
827 inorder (AtkObject * collection, MatchRulePrivate * mrp,
828 GList * ls, gint kount, gint max,
830 gboolean flag, AtkObject * pobj, dbus_bool_t traverse)
834 /* First, look through the children recursively. */
835 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
838 /* Next, we look through the right subtree */
839 while ((max == 0 || kount < max) && obj != collection)
841 AtkObject *parent = atk_object_get_parent (obj);
842 i = atk_object_get_index_in_parent (obj);
843 kount = sort_order_canonical (mrp, ls, kount, max, parent,
844 i + 1, TRUE, FALSE, TRUE, TRUE);
848 if (max == 0 || kount < max)
850 kount = sort_order_canonical (mrp, ls, kount, max,
851 obj, i + 1, TRUE, FALSE, TRUE, TRUE);
858 GetMatchesInOrder: get matches from a given object in an inorder traversal.
862 GetMatchesInOrder (DBusMessage * message,
863 AtkObject * current_object,
864 MatchRulePrivate * mrp,
865 const Accessibility_Collection_SortOrder sortby,
866 const dbus_bool_t recurse,
867 dbus_int32_t count, const dbus_bool_t traverse)
873 ls = g_list_append (ls, current_object);
875 obj = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
877 kount = inorder (obj, mrp, ls, 0, count,
878 current_object, TRUE, NULL, traverse);
880 ls = g_list_remove (ls, ls->data);
882 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
883 ls = g_list_reverse (ls);
886 return return_and_free_list (message, ls);
890 GetMatchesInBackOrder: get matches from a given object in a
891 reverse order traversal.
895 GetMatchesInBackOrder (DBusMessage * message,
896 AtkObject * current_object,
897 MatchRulePrivate * mrp,
898 const Accessibility_Collection_SortOrder sortby,
902 AtkObject *collection;
905 ls = g_list_append (ls, current_object);
907 collection = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
909 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
912 ls = g_list_remove (ls, ls->data);
914 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
915 ls = g_list_reverse (ls);
918 return return_and_free_list (message, ls);
922 GetMatchesTo (DBusMessage * message,
923 AtkObject * current_object,
924 MatchRulePrivate * mrp,
925 const Accessibility_Collection_SortOrder sortby,
926 const dbus_bool_t recurse,
927 const dbus_bool_t isrestrict,
928 dbus_int32_t count, const dbus_bool_t traverse)
933 ls = g_list_append (ls, current_object);
937 obj = ATK_OBJECT (atk_object_get_parent (current_object));
938 kount = query_exec (mrp, sortby, ls, 0, count,
939 obj, 0, TRUE, current_object, TRUE, traverse);
943 obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
944 kount = query_exec (mrp, sortby, ls, 0, count,
945 obj, 0, TRUE, current_object, TRUE, traverse);
949 ls = g_list_remove (ls, ls->data);
951 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
952 ls = g_list_reverse (ls);
955 return return_and_free_list (message, ls);
959 impl_GetMatchesFrom (DBusConnection * bus, DBusMessage * message,
962 char *current_object_path = NULL;
963 AtkObject *current_object;
964 DBusMessageIter iter;
965 MatchRulePrivate rule;
966 dbus_uint32_t sortby;
969 dbus_bool_t traverse;
971 const char *signature;
973 signature = dbus_message_get_signature (message);
974 if (strcmp (signature, "o(aiisiaiisib)uuib") != 0 &&
975 strcmp (signature, "o(aii(as)iaiisib)uuib") != 0)
977 return droute_invalid_arguments_error (message);
980 dbus_message_iter_init (message, &iter);
981 dbus_message_iter_get_basic (&iter, ¤t_object_path);
982 current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
985 // TODO: object-not-found error
986 return spi_dbus_general_error (message);
988 dbus_message_iter_next (&iter);
989 if (!read_mr (&iter, &rule))
991 return spi_dbus_general_error (message);
993 dbus_message_iter_get_basic (&iter, &sortby);
994 dbus_message_iter_next (&iter);
995 dbus_message_iter_get_basic (&iter, &tree);
996 dbus_message_iter_next (&iter);
997 dbus_message_iter_get_basic (&iter, &count);
998 dbus_message_iter_next (&iter);
999 dbus_message_iter_get_basic (&iter, &traverse);
1000 dbus_message_iter_next (&iter);
1004 case Accessibility_Collection_TREE_RESTRICT_CHILDREN:
1005 return GetMatchesFrom (message, current_object,
1006 &rule, sortby, TRUE, count, traverse);
1008 case Accessibility_Collection_TREE_RESTRICT_SIBLING:
1009 return GetMatchesFrom (message, current_object,
1010 &rule, sortby, FALSE, count, traverse);
1012 case Accessibility_Collection_TREE_INORDER:
1013 return GetMatchesInOrder (message, current_object,
1014 &rule, sortby, TRUE, count, traverse);
1021 static DBusMessage *
1022 impl_GetMatchesTo (DBusConnection * bus, DBusMessage * message,
1025 char *current_object_path = NULL;
1026 AtkObject *current_object;
1027 DBusMessageIter iter;
1028 MatchRulePrivate rule;
1029 dbus_uint32_t sortby;
1031 dbus_bool_t recurse;
1033 dbus_bool_t traverse;
1035 const char *signature;
1037 signature = dbus_message_get_signature (message);
1038 if (strcmp (signature, "o(aiisiaiisib)uubib") != 0 &&
1039 strcmp (signature, "o(aii(as)iaiisib)uubib") != 0)
1041 return droute_invalid_arguments_error (message);
1044 dbus_message_iter_init (message, &iter);
1045 dbus_message_iter_get_basic (&iter, ¤t_object_path);
1046 current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
1047 if (!current_object)
1049 // TODO: object-not-found error
1050 return spi_dbus_general_error (message);
1052 dbus_message_iter_next (&iter);
1053 if (!read_mr (&iter, &rule))
1055 return spi_dbus_general_error (message);
1057 dbus_message_iter_get_basic (&iter, &sortby);
1058 dbus_message_iter_next (&iter);
1059 dbus_message_iter_get_basic (&iter, &tree);
1060 dbus_message_iter_next (&iter);
1061 dbus_message_iter_get_basic (&iter, &recurse);
1062 dbus_message_iter_next (&iter);
1063 dbus_message_iter_get_basic (&iter, &count);
1064 dbus_message_iter_next (&iter);
1065 dbus_message_iter_get_basic (&iter, &traverse);
1066 dbus_message_iter_next (&iter);
1070 case Accessibility_Collection_TREE_RESTRICT_CHILDREN:
1071 return GetMatchesTo (message, current_object,
1072 &rule, sortby, recurse, TRUE, count, traverse);
1074 case Accessibility_Collection_TREE_RESTRICT_SIBLING:
1075 return GetMatchesTo (message, current_object,
1076 &rule, sortby, recurse, FALSE, count, traverse);
1078 case Accessibility_Collection_TREE_INORDER:
1079 return GetMatchesInBackOrder (message, current_object,
1080 &rule, sortby, count);
1087 static DBusMessage *
1088 impl_GetMatches (DBusConnection * bus, DBusMessage * message, void *user_data)
1090 AtkObject *obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
1091 DBusMessageIter iter;
1092 MatchRulePrivate rule;
1093 dbus_uint32_t sortby;
1095 dbus_bool_t traverse;
1097 const char *signature;
1099 signature = dbus_message_get_signature (message);
1100 if (strcmp (signature, "(aiisiaiisib)uib") != 0 &&
1101 strcmp (signature, "(aii(as)iaiisib)uib") != 0)
1103 return droute_invalid_arguments_error (message);
1106 dbus_message_iter_init (message, &iter);
1107 if (!read_mr (&iter, &rule))
1109 return spi_dbus_general_error (message);
1111 dbus_message_iter_get_basic (&iter, &sortby);
1112 dbus_message_iter_next (&iter);
1113 dbus_message_iter_get_basic (&iter, &count);
1114 dbus_message_iter_next (&iter);
1115 dbus_message_iter_get_basic (&iter, &traverse);
1116 dbus_message_iter_next (&iter);
1117 ls = g_list_prepend (ls, obj);
1118 count = query_exec (&rule, sortby, ls, 0, count,
1119 obj, 0, TRUE, NULL, TRUE, traverse);
1120 ls = g_list_remove (ls, ls->data);
1122 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1123 ls = g_list_reverse (ls);
1124 free_mrp_data (&rule);
1125 return return_and_free_list (message, ls);
1128 static DRouteMethod methods[] = {
1129 {impl_GetMatchesFrom, "GetMatchesFrom"},
1130 {impl_GetMatchesTo, "GetMatchesTo"},
1131 {impl_GetMatches, "GetMatches"},
1136 spi_initialize_collection (DRoutePath * path)
1138 droute_path_add_interface (path,
1139 SPI_DBUS_INTERFACE_COLLECTION, spi_org_a11y_atspi_Collection, methods, NULL);