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 Accessibility_Role role;
187 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
188 else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
190 return (atk_object_get_role(child) == roles[0]);
195 match_roles_any_p (AtkObject *child,
201 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
203 role = atk_object_get_role(child);
205 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
206 if (role == roles[i])
213 match_roles_none_p (AtkObject *child,
219 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
221 role = atk_object_get_role(child);
223 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
224 if (role == roles[i])
231 match_roles_lookup (AtkObject *child,
232 MatchRulePrivate *mrp)
234 switch (mrp->rolematchtype){
235 case Accessibility_Collection_MATCH_ALL :
236 if (match_roles_all_p (child, mrp->roles))
240 case Accessibility_Collection_MATCH_ANY :
241 if (match_roles_any_p (child, mrp->roles))
245 case Accessibility_Collection_MATCH_NONE :
246 if (match_roles_none_p (child, mrp->roles))
257 match_interfaces_all_p (AtkObject *obj,
265 for (i = 0; ifaces[i]; i++)
266 if (!child_interface_p (obj, ifaces [i])){
273 match_interfaces_any_p (AtkObject *obj,
282 for (i = 0; ifaces[i]; i++)
283 if (child_interface_p (obj, ifaces [i])){
290 match_interfaces_none_p (AtkObject *obj,
295 for (i = 0; ifaces[i]; i++)
296 if (child_interface_p (obj, ifaces [i]))
303 match_interfaces_lookup (AtkObject *child,
304 MatchRulePrivate *mrp)
306 switch (mrp->interfacematchtype){
308 case Accessibility_Collection_MATCH_ALL :
309 if (match_interfaces_all_p (child, mrp->ifaces))
313 case Accessibility_Collection_MATCH_ANY :
314 if (match_interfaces_any_p (child, mrp->ifaces))
318 case Accessibility_Collection_MATCH_NONE :
319 if (match_interfaces_none_p (child, mrp->ifaces))
329 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
332 match_attributes_all_p (AtkObject *child,
333 AtkAttributeSet *attributes)
337 gint length, oa_length;
338 gboolean flag = FALSE;
340 if (attributes == NULL || g_slist_length (attributes) == 0)
343 oa = atk_object_get_attributes(child);
344 length = g_slist_length(attributes);
345 oa_length = g_slist_length(oa);
347 for (i = 0; i < length; i++) {
348 AtkAttribute *attr = g_slist_nth_data(attributes, i);
349 for (k = 0; k < oa_length; k++) {
350 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
351 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
352 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
360 atk_attribute_set_free(oa);
364 atk_attribute_set_free(oa);
369 match_attributes_any_p (AtkObject *child,
370 AtkAttributeSet *attributes)
375 gint length, oa_length;
377 length = g_slist_length(attributes);
381 oa = atk_object_get_attributes(child);
382 oa_length = g_slist_length(oa);
384 for (i = 0; i < length; i++){
385 AtkAttribute *attr = g_slist_nth_data(attributes, i);
386 for (k = 0; k < oa_length; k++){
387 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
388 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
389 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
390 atk_attribute_set_free(oa);
395 atk_attribute_set_free(oa);
400 match_attributes_none_p (AtkObject *child,
401 AtkAttributeSet *attributes)
406 gint length, oa_length;
408 length = g_slist_length(attributes);
412 oa = atk_object_get_attributes(child);
413 oa_length = g_slist_length(oa);
415 for (i = 0; i < length; i++){
416 AtkAttribute *attr = g_slist_nth_data(attributes, i);
417 for (k = 0; k < oa_length; k++){
418 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
419 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
420 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
421 atk_attribute_set_free(oa);
426 atk_attribute_set_free(oa);
431 match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
433 switch (mrp->attributematchtype){
435 case Accessibility_Collection_MATCH_ALL :
436 if (match_attributes_all_p (child, mrp->attributes))
440 case Accessibility_Collection_MATCH_ANY :
441 if (match_attributes_any_p (child, mrp->attributes))
445 case Accessibility_Collection_MATCH_NONE :
446 if (match_attributes_none_p (child, mrp->attributes))
456 traverse_p (AtkObject *child,
457 const gboolean traverse)
461 else return !child_collection_p (child);
465 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
466 gint kount, gint max,
467 AtkObject *obj, glong index, gboolean flag,
468 AtkObject *pobj, gboolean recurse,
472 glong acount = atk_object_get_n_accessible_children (obj);
473 gboolean prev = pobj? TRUE : FALSE;
475 for (; i < acount && (max == 0 || kount < max); i++){
477 atk_object_ref_accessible_child(obj, i);
479 g_object_unref(child);
480 if (prev && child == pobj){
484 if (flag && match_interfaces_lookup (child, mrp)
485 && match_states_lookup (child, mrp)
486 && match_roles_lookup (child, mrp)
487 && match_attributes_lookup (child, mrp)
490 ls = g_list_append (ls, child);
497 if (recurse && traverse_p (child, traverse))
498 kount = sort_order_canonical (mrp, ls, kount,
500 pobj, recurse, traverse);
506 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
507 gint kount, gint max,
508 AtkObject *obj, gboolean flag,
515 /* This breaks us out of the recursion. */
516 if (!obj || obj == pobj)
521 /* Add to the list if it matches */
522 if (flag && match_interfaces_lookup (obj, mrp)
523 && match_states_lookup (obj, mrp)
524 && match_roles_lookup (obj, mrp)
525 && match_attributes_lookup (obj, mrp))
527 ls = g_list_append (ls, obj);
531 if(!flag) flag = TRUE;
533 /* Get the current nodes index in it's parent and the parent object. */
534 indexinparent = atk_object_get_index_in_parent (obj);
535 parent = atk_object_get_parent(obj);
537 if(indexinparent > 0)
539 /* there are still some siblings to visit so get the previous sibling
540 and get it's last descendant.
541 First, get the previous sibling */
542 nextobj = atk_object_ref_accessible_child (parent,
544 g_object_unref(nextobj);
546 /* Now, drill down the right side to the last descendant */
547 while(atk_object_get_n_accessible_children (nextobj) > 0)
549 nextobj = atk_object_ref_accessible_child(nextobj,
550 atk_object_get_n_accessible_children (nextobj)-1);
551 g_object_unref (nextobj);
553 /* recurse with the last descendant */
554 kount = sort_order_rev_canonical (mrp, ls, kount, max,
555 nextobj, TRUE, pobj);
559 /* no more siblings so next node must be the parent */
560 kount = sort_order_rev_canonical (mrp, ls, kount, max,
568 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
569 GList *ls, gint kount, gint max,
570 AtkObject *obj, glong index,
573 gboolean recurse, gboolean traverse)
576 case Accessibility_Collection_SORT_ORDER_CANONICAL :
577 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
578 pobj, recurse, traverse);
580 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
581 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
582 pobj, recurse, traverse);
586 g_warning ("Sort method not implemented yet");
594 read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
596 DBusMessageIter mrc, arrayc;
597 dbus_uint32_t *array;
598 dbus_int32_t matchType;
603 char *interfaces = NULL;
605 // TODO: error checking
606 dbus_message_iter_recurse(iter, &mrc);
607 dbus_message_iter_recurse(&mrc, &arrayc);
608 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
609 bitarray_to_seq(array, array_count, &mrp->states);
610 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
612 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
614 dbus_message_iter_next(&mrc);
615 dbus_message_iter_read_basic(&mrc, &matchType);
616 dbus_message_iter_next(&mrc);
617 mrp->statematchtype = matchType;;
619 dbus_message_iter_recurse(&mrc, &arrayc);
620 mrp->attributes = NULL;
621 while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
623 dbus_message_iter_get_basic(&arrayc, &str);
624 // TODO: remove this print
625 g_print("Got attribute: %s\n", str);
626 attr = g_new (AtkAttribute, 1);
629 int len = strcspn(str, ":");
630 attr->name = g_strndup(str, len);
634 if (str[len] == ' ') len++;
635 attr->value = g_strdup(str + len);
637 else attr->value = NULL;
638 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
640 dbus_message_iter_next(&arrayc);
642 dbus_message_iter_next(&mrc);
643 dbus_message_iter_read_basic(&mrc, &matchType);
644 mrp->attributematchtype = matchType;;
645 dbus_message_iter_next(&mrc);
646 /* Get roles and role match */
647 dbus_message_iter_recurse(&mrc, &arrayc);
648 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
649 bitarray_to_seq(array, array_count, &mrp->roles);
650 dbus_message_iter_next(&mrc);
651 dbus_message_iter_read_basic(&mrc, &matchType);
652 mrp->rolematchtype = matchType;;
653 dbus_message_iter_next(&mrc);
654 /* Get interfaces and interface match */
655 dbus_message_iter_read_basic(&mrc, &interfaces);
656 dbus_message_iter_next(&mrc);
657 mrp->ifaces = g_strsplit(interfaces, ";", 0);
658 dbus_message_iter_read_basic(&mrc, &matchType);
659 mrp->interfacematchtype = matchType;;
660 dbus_message_iter_next(&mrc);
662 dbus_message_iter_read_basic(&mrc, &mrp->invert);
663 dbus_message_iter_next(iter);
668 return_and_free_list(DBusMessage *message, GList *ls)
671 DBusMessageIter iter, iter_array;
674 reply = dbus_message_new_method_return(message);
675 if (!reply) return NULL;
676 dbus_message_iter_init_append(reply, &iter);
677 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
678 for (item = ls; item; item = g_list_next(item))
680 char *path = (char *) spi_dbus_object_to_path ((AtkObject *)item->data);
681 dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
684 if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
688 // TODO: Handle out of memory
693 static void free_mrp_data(MatchRulePrivate *mrp)
696 atk_attribute_set_free(mrp->attributes);
698 g_strfreev(mrp->ifaces);
702 GetMatchesFrom (DBusMessage *message,
703 AtkObject *current_object,
704 MatchRulePrivate *mrp,
705 const Accessibility_Collection_SortOrder sortby,
706 const dbus_bool_t isrestrict,
708 const dbus_bool_t traverse)
713 atk_object_get_index_in_parent (current_object);
716 ls = g_list_append (ls, current_object);
720 parent = atk_object_get_parent (current_object);
721 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
722 FALSE, NULL, TRUE, traverse);
725 kount = query_exec (mrp, sortby, ls, 0, count,
726 current_object, 0, FALSE, NULL,
729 ls = g_list_remove (ls, ls->data);
731 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
732 ls = g_list_reverse (ls);
735 return return_and_free_list (message, ls);
739 inorder traversal from a given object in the hierarchy
743 inorder (AtkObject *collection, MatchRulePrivate *mrp,
744 GList *ls, gint kount, gint max,
748 dbus_bool_t traverse)
752 /* First, look through the children recursively. */
753 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
756 /* Next, we look through the right subtree */
757 while ((max == 0 || kount < max)
758 && obj != collection)
761 atk_object_get_parent (obj);
762 i = atk_object_get_index_in_parent (obj);
763 kount = sort_order_canonical (mrp, ls, kount, max, parent,
764 i+1, TRUE, FALSE, TRUE, TRUE);
770 kount = sort_order_canonical (mrp, ls, kount, max,
771 obj, i + 1, TRUE, FALSE,
779 GetMatchesInOrder: get matches from a given object in an inorder traversal.
783 GetMatchesInOrder (DBusMessage *message,
784 AtkObject *current_object,
785 MatchRulePrivate *mrp,
786 const Accessibility_Collection_SortOrder sortby,
787 const dbus_bool_t recurse,
789 const dbus_bool_t traverse)
795 ls = g_list_append (ls, current_object);
797 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
799 kount = inorder (obj, mrp, ls, 0, count,
800 current_object, TRUE, NULL, traverse);
802 ls = g_list_remove (ls, ls->data);
804 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
805 ls = g_list_reverse (ls);
808 return return_and_free_list (message, ls);
812 GetMatchesInBackOrder: get matches from a given object in a
813 reverse order traversal.
817 GetMatchesInBackOrder (DBusMessage *message,
818 AtkObject *current_object,
819 MatchRulePrivate *mrp,
820 const Accessibility_Collection_SortOrder sortby,
824 AtkObject *collection;
827 ls = g_list_append (ls, current_object);
829 collection = atk_dbus_path_to_object (dbus_message_get_path (message));
831 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
834 ls = g_list_remove (ls, ls->data);
836 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
837 ls = g_list_reverse (ls);
840 return return_and_free_list (message, ls);
844 GetMatchesTo (DBusMessage *message,
845 AtkObject *current_object,
846 MatchRulePrivate *mrp,
847 const Accessibility_Collection_SortOrder sortby,
848 const dbus_bool_t recurse,
849 const dbus_bool_t isrestrict,
851 const dbus_bool_t traverse)
857 ls = g_list_append (ls, current_object);
860 obj = atk_object_get_parent (current_object);
861 kount = query_exec (mrp, sortby, ls, 0, count,
862 obj, 0, TRUE, current_object, TRUE, traverse);
865 obj = atk_dbus_path_to_object (dbus_message_get_path (message));
866 kount = query_exec (mrp, sortby, ls, 0, count,
867 obj, 0, TRUE, current_object, TRUE, traverse);
871 ls = g_list_remove (ls, ls->data);
873 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
874 ls = g_list_reverse (ls);
877 return return_and_free_list (message, ls);
881 impl_GetMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
883 char *current_object_path = NULL;
884 AtkObject *current_object;
885 DBusMessageIter iter;
886 MatchRulePrivate rule;
887 dbus_uint16_t sortby;
890 dbus_bool_t traverse;
893 dbus_message_iter_init(message, &iter);
894 dbus_message_iter_get_basic (&iter, current_object_path);
895 current_object = atk_dbus_path_to_object (current_object_path);
898 // TODO: object-not-found error
899 return spi_dbus_general_error (message);
901 dbus_message_iter_next (&iter);
902 if (!read_mr(&iter, &rule))
904 return spi_dbus_general_error (message);
906 dbus_message_iter_get_basic(&iter, &sortby);
907 dbus_message_iter_next(&iter);
908 dbus_message_iter_get_basic(&iter, &tree);
909 dbus_message_iter_next(&iter);
910 dbus_message_iter_get_basic(&iter, &count);
911 dbus_message_iter_next(&iter);
912 dbus_message_iter_get_basic(&iter, &traverse);
913 dbus_message_iter_next(&iter);
916 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
917 return GetMatchesFrom (message, current_object,
918 &rule, sortby, TRUE, count, traverse);
920 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
921 return GetMatchesFrom (message, current_object,
922 &rule, sortby, FALSE, count, traverse);
924 case Accessibility_Collection_TREE_INORDER :
925 return GetMatchesInOrder (message, current_object,
926 &rule, sortby, TRUE, count, traverse);
928 default : return NULL;
933 impl_GetMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
935 char *current_object_path = NULL;
936 AtkObject *current_object;
937 DBusMessageIter iter;
938 MatchRulePrivate rule;
939 dbus_uint16_t sortby;
943 dbus_bool_t traverse;
946 dbus_message_iter_init(message, &iter);
947 dbus_message_iter_get_basic (&iter, current_object_path);
948 current_object = atk_dbus_path_to_object (current_object_path);
951 // TODO: object-not-found error
952 return spi_dbus_general_error (message);
954 dbus_message_iter_next (&iter);
955 if (!read_mr(&iter, &rule))
957 return spi_dbus_general_error (message);
959 dbus_message_iter_get_basic(&iter, &sortby);
960 dbus_message_iter_next(&iter);
961 dbus_message_iter_get_basic(&iter, &tree);
962 dbus_message_iter_next(&iter);
963 dbus_message_iter_get_basic(&iter, &recurse);
964 dbus_message_iter_next(&iter);
965 dbus_message_iter_get_basic(&iter, &count);
966 dbus_message_iter_next(&iter);
967 dbus_message_iter_get_basic(&iter, &traverse);
968 dbus_message_iter_next(&iter);
971 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
972 return GetMatchesTo (message, current_object,
973 &rule, sortby, recurse, TRUE, count, traverse);
975 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
976 return GetMatchesTo (message, current_object,
977 &rule, sortby, recurse, FALSE, count, traverse);
979 case Accessibility_Collection_TREE_INORDER :
980 return GetMatchesInBackOrder (message, current_object,
981 &rule, sortby, count);
983 default : return NULL;
988 impl_GetMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
990 AtkObject *obj = atk_dbus_path_to_object (dbus_message_get_path (message));
991 DBusMessageIter iter;
992 MatchRulePrivate rule;
993 dbus_uint16_t sortby;
995 dbus_bool_t traverse;
998 dbus_message_iter_init(message, &iter);
999 if (!read_mr(&iter, &rule))
1001 return spi_dbus_general_error (message);
1003 dbus_message_iter_get_basic(&iter, &sortby);
1004 dbus_message_iter_next(&iter);
1005 dbus_message_iter_get_basic(&iter, &count);
1006 dbus_message_iter_next(&iter);
1007 dbus_message_iter_get_basic(&iter, &traverse);
1008 dbus_message_iter_next(&iter);
1009 ls = g_list_prepend (ls, obj);
1010 count = query_exec (&rule, sortby, ls, 0, count,
1011 obj, 0, TRUE, NULL, TRUE, traverse);
1012 ls = g_list_remove (ls, ls->data);
1014 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1015 ls = g_list_reverse (ls);
1016 free_mrp_data (&rule);
1017 return return_and_free_list (message, ls);
1020 static DRouteMethod methods[] = {
1021 { impl_GetMatchesFrom, "GetMatchesFrom" },
1022 { impl_GetMatchesTo, "GetMatchesTo" },
1023 { impl_GetMatches, "GetMatches" },
1028 spi_initialize_collection (DRoutePath *path)
1030 droute_path_add_interface (path,
1031 SPI_DBUS_INTERFACE_COLLECTION,