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 */
25 #include "accessible.h"
26 #include "spi-common/bitarray.h"
29 #define get_object(message) atk_dbus_get_object(dbus_message_get_path(message))
31 typedef struct _MatchRulePrivate MatchRulePrivate;
32 struct _MatchRulePrivate
35 Accessibility_Collection_MatchType statematchtype;
36 AtkAttributeSet *attributes;
37 Accessibility_Collection_MatchType attributematchtype;
39 Accessibility_Collection_MatchType rolematchtype;
41 Accessibility_Collection_MatchType interfacematchtype;
46 child_interface_p (AtkObject *child,
49 if (!strcasecmp(repo_id, "action")) return atk_is_action(child);
50 if (!strcasecmp(repo_id, "component")) return atk_is_component(child);
51 if (!strcasecmp(repo_id, "editabletext")) return atk_is_editable_text(child);
52 if (!strcasecmp(repo_id, "text")) return atk_is_text(child);
53 if (!strcasecmp(repo_id, "hypertext")) return atk_is_hypertext(child);
54 if (!strcasecmp(repo_id, "image")) return atk_is_image(child);
55 if (!strcasecmp(repo_id, "selection")) return atk_is_selection(child);
56 if (!strcasecmp(repo_id, "table")) return atk_is_table(child);
57 if (!strcasecmp(repo_id, "value")) return atk_is_value(child);
58 if (!strcasecmp(repo_id, "streamablecontent")) return atk_is_streamable_content(child);
59 if (!strcasecmp(repo_id, "document")) return atk_is_document(child);
63 #define child_collection_p(ch) (TRUE)
66 match_states_all_p (AtkObject *child,
76 chs = atk_object_ref_state_set (child);
78 // TODO: use atk-state_set_contains_states; would be more efficient
79 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
81 if (!atk_state_set_contains_state(chs, set[i]))
93 match_states_any_p (AtkObject *child,
103 chs = atk_object_ref_state_set (child);
105 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
107 if (!atk_state_set_contains_state(chs, set[i]))
119 match_states_none_p (AtkObject *child,
129 chs = atk_object_ref_state_set (child);
131 for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
133 if (atk_state_set_contains_state(chs, set[i]))
144 // TODO: need to convert at-spi roles/states to atk roles/states */
146 match_states_lookup (AtkObject *child,
147 MatchRulePrivate *mrp)
149 switch (mrp->statematchtype){
150 case Accessibility_Collection_MATCH_ALL :
151 if (match_states_all_p (child, mrp->states))
155 case Accessibility_Collection_MATCH_ANY :
156 if (match_states_any_p (child, mrp->states))
160 case Accessibility_Collection_MATCH_NONE :
161 if (match_states_none_p (child, mrp->states))
171 // TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
172 // would be more efficient
173 #define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
176 match_roles_all_p (AtkObject *child,
179 Accessibility_Role role;
181 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
182 else if (roles[1] != BITARRAY_SEQ_TERM) return FALSE;
184 return (atk_object_get_role(child) == roles[0]);
189 match_roles_any_p (AtkObject *child,
195 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
197 role = atk_object_get_role(child);
199 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
200 if (role == roles[i])
207 match_roles_none_p (AtkObject *child,
213 if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM) return TRUE;
215 role = atk_object_get_role(child);
217 for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
218 if (role == roles[i])
225 match_roles_lookup (AtkObject *child,
226 MatchRulePrivate *mrp)
228 switch (mrp->rolematchtype){
229 case Accessibility_Collection_MATCH_ALL :
230 if (match_roles_all_p (child, mrp->roles))
234 case Accessibility_Collection_MATCH_ANY :
235 if (match_roles_any_p (child, mrp->roles))
239 case Accessibility_Collection_MATCH_NONE :
240 if (match_roles_none_p (child, mrp->roles))
251 match_interfaces_all_p (AtkObject *obj,
259 for (i = 0; ifaces[i]; i++)
260 if (!child_interface_p (obj, ifaces [i])){
267 match_interfaces_any_p (AtkObject *obj,
276 for (i = 0; ifaces[i]; i++)
277 if (child_interface_p (obj, ifaces [i])){
284 match_interfaces_none_p (AtkObject *obj,
289 for (i = 0; ifaces[i]; i++)
290 if (child_interface_p (obj, ifaces [i]))
297 match_interfaces_lookup (AtkObject *child,
298 MatchRulePrivate *mrp)
300 switch (mrp->interfacematchtype){
302 case Accessibility_Collection_MATCH_ALL :
303 if (match_interfaces_all_p (child, mrp->ifaces))
307 case Accessibility_Collection_MATCH_ANY :
308 if (match_interfaces_any_p (child, mrp->ifaces))
312 case Accessibility_Collection_MATCH_NONE :
313 if (match_interfaces_none_p (child, mrp->ifaces))
323 #define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
326 match_attributes_all_p (AtkObject *child,
327 AtkAttributeSet *attributes)
331 gint length, oa_length;
332 gboolean flag = FALSE;
334 if (attributes == NULL || g_slist_length (attributes) == 0)
337 oa = atk_object_get_attributes(child);
338 length = g_slist_length(attributes);
339 oa_length = g_slist_length(oa);
341 for (i = 0; i < length; i++) {
342 AtkAttribute *attr = g_slist_nth_data(attributes, i);
343 for (k = 0; k < oa_length; k++) {
344 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
345 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
346 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
354 atk_attribute_set_free(oa);
358 atk_attribute_set_free(oa);
363 match_attributes_any_p (AtkObject *child,
364 AtkAttributeSet *attributes)
369 gint length, oa_length;
371 length = g_slist_length(attributes);
375 oa = atk_object_get_attributes(child);
376 oa_length = g_slist_length(oa);
378 for (i = 0; i < length; i++){
379 AtkAttribute *attr = g_slist_nth_data(attributes, i);
380 for (k = 0; k < oa_length; k++){
381 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
382 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
383 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
384 atk_attribute_set_free(oa);
389 atk_attribute_set_free(oa);
394 match_attributes_none_p (AtkObject *child,
395 AtkAttributeSet *attributes)
400 gint length, oa_length;
402 length = g_slist_length(attributes);
406 oa = atk_object_get_attributes(child);
407 oa_length = g_slist_length(oa);
409 for (i = 0; i < length; i++){
410 AtkAttribute *attr = g_slist_nth_data(attributes, i);
411 for (k = 0; k < oa_length; k++){
412 AtkAttribute *oa_attr = g_slist_nth_data(attributes, i);
413 if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
414 !g_ascii_strcasecmp (oa_attr->value, attr->value)){
415 atk_attribute_set_free(oa);
420 atk_attribute_set_free(oa);
425 match_attributes_lookup (AtkObject *child, MatchRulePrivate *mrp)
427 switch (mrp->attributematchtype){
429 case Accessibility_Collection_MATCH_ALL :
430 if (match_attributes_all_p (child, mrp->attributes))
434 case Accessibility_Collection_MATCH_ANY :
435 if (match_attributes_any_p (child, mrp->attributes))
439 case Accessibility_Collection_MATCH_NONE :
440 if (match_attributes_none_p (child, mrp->attributes))
450 traverse_p (AtkObject *child,
451 const gboolean traverse)
455 else return !child_collection_p (child);
459 sort_order_canonical (MatchRulePrivate *mrp, GList *ls,
460 gint kount, gint max,
461 AtkObject *obj, glong index, gboolean flag,
462 AtkObject *pobj, gboolean recurse,
466 glong acount = atk_object_get_n_accessible_children (obj);
467 gboolean prev = pobj? TRUE : FALSE;
469 for (; i < acount && (max == 0 || kount < max); i++){
471 atk_object_ref_accessible_child(obj, i);
473 g_object_unref(child);
474 if (prev && child == pobj){
478 if (flag && match_interfaces_lookup (child, mrp)
479 && match_states_lookup (child, mrp)
480 && match_roles_lookup (child, mrp)
481 && match_attributes_lookup (child, mrp)
484 ls = g_list_append (ls, child);
491 if (recurse && traverse_p (child, traverse))
492 kount = sort_order_canonical (mrp, ls, kount,
494 pobj, recurse, traverse);
500 sort_order_rev_canonical (MatchRulePrivate *mrp, GList *ls,
501 gint kount, gint max,
502 AtkObject *obj, gboolean flag,
509 /* This breaks us out of the recursion. */
510 if (!obj || obj == pobj)
515 /* Add to the list if it matches */
516 if (flag && match_interfaces_lookup (obj, mrp)
517 && match_states_lookup (obj, mrp)
518 && match_roles_lookup (obj, mrp)
519 && match_attributes_lookup (obj, mrp))
521 ls = g_list_append (ls, obj);
525 if(!flag) flag = TRUE;
527 /* Get the current nodes index in it's parent and the parent object. */
528 indexinparent = atk_object_get_index_in_parent (obj);
529 parent = atk_object_get_parent(obj);
531 if(indexinparent > 0)
533 /* there are still some siblings to visit so get the previous sibling
534 and get it's last descendant.
535 First, get the previous sibling */
536 nextobj = atk_object_ref_accessible_child (parent,
538 g_object_unref(nextobj);
540 /* Now, drill down the right side to the last descendant */
541 while(atk_object_get_n_accessible_children (nextobj) > 0)
543 nextobj = atk_object_ref_accessible_child(nextobj,
544 atk_object_get_n_accessible_children (nextobj)-1);
545 g_object_unref (nextobj);
547 /* recurse with the last descendant */
548 kount = sort_order_rev_canonical (mrp, ls, kount, max,
549 nextobj, TRUE, pobj);
553 /* no more siblings so next node must be the parent */
554 kount = sort_order_rev_canonical (mrp, ls, kount, max,
562 query_exec (MatchRulePrivate *mrp, Accessibility_Collection_SortOrder sortby,
563 GList *ls, gint kount, gint max,
564 AtkObject *obj, glong index,
567 gboolean recurse, gboolean traverse)
570 case Accessibility_Collection_SORT_ORDER_CANONICAL :
571 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
572 pobj, recurse, traverse);
574 case Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL :
575 kount = sort_order_canonical(mrp, ls, 0, max, obj, index, flag,
576 pobj, recurse, traverse);
580 g_warning ("Sort method not implemented yet");
588 read_mr(DBusMessageIter *iter, MatchRulePrivate *mrp)
590 DBusMessageIter mrc, arrayc;
591 dbus_uint32_t *array;
592 dbus_int32_t matchType;
597 char *interfaces = NULL;
599 // TODO: error checking
600 dbus_message_iter_recurse(iter, &mrc);
601 dbus_message_iter_recurse(&mrc, &arrayc);
602 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
603 bitarray_to_seq(array, array_count, &mrp->states);
604 for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
606 mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
608 dbus_message_iter_next(&mrc);
609 dbus_message_iter_read_basic(&mrc, &matchType);
610 dbus_message_iter_next(&mrc);
611 mrp->statematchtype = matchType;;
613 dbus_message_iter_recurse(&mrc, &arrayc);
614 mrp->attributes = NULL;
615 while (dbus_message_iter_get_arg_type(&arrayc) != DBUS_TYPE_INVALID)
617 dbus_message_iter_get_basic(&arrayc, &str);
618 // TODO: remove this print
619 g_print("Got attribute: %s\n", str);
620 attr = g_new (AtkAttribute, 1);
623 int len = strcspn(str, ":");
624 attr->name = g_strndup(str, len);
628 if (str[len] == ' ') len++;
629 attr->value = g_strdup(str + len);
631 else attr->value = NULL;
632 mrp->attributes = g_slist_prepend(mrp->attributes, attr);
634 dbus_message_iter_next(&arrayc);
636 dbus_message_iter_next(&mrc);
637 dbus_message_iter_read_basic(&mrc, &matchType);
638 mrp->attributematchtype = matchType;;
639 dbus_message_iter_next(&mrc);
640 /* Get roles and role match */
641 dbus_message_iter_recurse(&mrc, &arrayc);
642 dbus_message_iter_get_fixed_array(&arrayc, &array, &array_count);
643 bitarray_to_seq(array, array_count, &mrp->roles);
644 dbus_message_iter_next(&mrc);
645 dbus_message_iter_read_basic(&mrc, &matchType);
646 mrp->rolematchtype = matchType;;
647 dbus_message_iter_next(&mrc);
648 /* Get interfaces and interface match */
649 dbus_message_iter_read_basic(&mrc, &interfaces);
650 dbus_message_iter_next(&mrc);
651 mrp->ifaces = g_strsplit(interfaces, ";", 0);
652 dbus_message_iter_read_basic(&mrc, &matchType);
653 mrp->interfacematchtype = matchType;;
654 dbus_message_iter_next(&mrc);
656 dbus_message_iter_read_basic(&mrc, &mrp->invert);
657 dbus_message_iter_next(iter);
662 return_and_free_list(DBusMessage *message, GList *ls)
665 DBusMessageIter iter, iter_array;
668 reply = dbus_message_new_method_return(message);
669 if (!reply) return NULL;
670 dbus_message_iter_init_append(reply, &iter);
671 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &iter_array)) goto oom;
672 for (item = ls; item; item = g_list_next(item))
674 char *path = spi_dbus_get_path((AtkObject *)item->data);
675 dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_OBJECT_PATH, &path);
678 if (!dbus_message_iter_close_container(&iter, &iter_array)) goto oom;
682 // TODO: Handle out of memory
687 static void free_mrp_data(MatchRulePrivate *mrp)
690 atk_attribute_set_free(mrp->attributes);
692 g_strfreev(mrp->ifaces);
696 getMatchesFrom (DBusMessage *message,
697 AtkObject *current_object,
698 MatchRulePrivate *mrp,
699 const Accessibility_Collection_SortOrder sortby,
700 const dbus_bool_t isrestrict,
702 const dbus_bool_t traverse)
707 atk_object_get_index_in_parent (current_object);
710 ls = g_list_append (ls, current_object);
714 parent = atk_object_get_parent (current_object);
715 kount = query_exec (mrp, sortby, ls, 0, count, parent, index,
716 FALSE, NULL, TRUE, traverse);
719 kount = query_exec (mrp, sortby, ls, 0, count,
720 current_object, 0, FALSE, NULL,
723 ls = g_list_remove (ls, ls->data);
725 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
726 ls = g_list_reverse (ls);
729 return return_and_free_list (message, ls);
733 inorder traversal from a given object in the hierarchy
737 inorder (AtkObject *collection, MatchRulePrivate *mrp,
738 GList *ls, gint kount, gint max,
742 dbus_bool_t traverse)
746 /* First, look through the children recursively. */
747 kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
750 /* Next, we look through the right subtree */
751 while ((max == 0 || kount < max)
752 && obj != collection)
755 atk_object_get_parent (obj);
756 i = atk_object_get_index_in_parent (obj);
757 kount = sort_order_canonical (mrp, ls, kount, max, parent,
758 i+1, TRUE, FALSE, TRUE, TRUE);
764 kount = sort_order_canonical (mrp, ls, kount, max,
765 obj, i + 1, TRUE, FALSE,
773 GetMatchesInOrder: get matches from a given object in an inorder traversal.
777 getMatchesInOrder (DBusMessage *message,
778 AtkObject *current_object,
779 MatchRulePrivate *mrp,
780 const Accessibility_Collection_SortOrder sortby,
781 const dbus_bool_t recurse,
783 const dbus_bool_t traverse)
789 ls = g_list_append (ls, current_object);
791 obj = atk_dbus_get_object (dbus_message_get_path (message));
793 kount = inorder (obj, mrp, ls, 0, count,
794 current_object, TRUE, NULL, traverse);
796 ls = g_list_remove (ls, ls->data);
798 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
799 ls = g_list_reverse (ls);
802 return return_and_free_list (message, ls);
806 GetMatchesInBackOrder: get matches from a given object in a
807 reverse order traversal.
811 getMatchesInBackOrder (DBusMessage *message,
812 AtkObject *current_object,
813 MatchRulePrivate *mrp,
814 const Accessibility_Collection_SortOrder sortby,
818 AtkObject *collection;
821 ls = g_list_append (ls, current_object);
823 collection = atk_dbus_get_object (dbus_message_get_path (message));
825 kount = sort_order_rev_canonical (mrp, ls, 0, count, current_object,
828 ls = g_list_remove (ls, ls->data);
830 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
831 ls = g_list_reverse (ls);
834 return return_and_free_list (message, ls);
838 getMatchesTo (DBusMessage *message,
839 AtkObject *current_object,
840 MatchRulePrivate *mrp,
841 const Accessibility_Collection_SortOrder sortby,
842 const dbus_bool_t recurse,
843 const dbus_bool_t isrestrict,
845 const dbus_bool_t traverse)
851 ls = g_list_append (ls, current_object);
854 obj = atk_object_get_parent (current_object);
855 kount = query_exec (mrp, sortby, ls, 0, count,
856 obj, 0, TRUE, current_object, TRUE, traverse);
859 obj = atk_dbus_get_object (dbus_message_get_path (message));
860 kount = query_exec (mrp, sortby, ls, 0, count,
861 obj, 0, TRUE, current_object, TRUE, traverse);
865 ls = g_list_remove (ls, ls->data);
867 if (sortby != Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
868 ls = g_list_reverse (ls);
871 return return_and_free_list (message, ls);
875 impl_getMatchesFrom (DBusConnection *bus, DBusMessage *message, void *user_data)
877 char *current_object_path = NULL;
878 AtkObject *current_object;
879 DBusMessageIter iter;
880 MatchRulePrivate rule;
881 dbus_uint16_t sortby;
884 dbus_bool_t traverse;
887 dbus_message_iter_init(message, &iter);
888 dbus_message_iter_get_basic (&iter, current_object_path);
889 current_object = atk_dbus_get_object (current_object_path);
892 // TODO: object-not-found error
893 return spi_dbus_general_error (message);
895 dbus_message_iter_next (&iter);
896 if (!read_mr(&iter, &rule))
898 return spi_dbus_general_error (message);
900 dbus_message_iter_get_basic(&iter, &sortby);
901 dbus_message_iter_next(&iter);
902 dbus_message_iter_get_basic(&iter, &tree);
903 dbus_message_iter_next(&iter);
904 dbus_message_iter_get_basic(&iter, &count);
905 dbus_message_iter_next(&iter);
906 dbus_message_iter_get_basic(&iter, &traverse);
907 dbus_message_iter_next(&iter);
910 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
911 return getMatchesFrom (message, current_object,
912 &rule, sortby, TRUE, count, traverse);
914 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
915 return getMatchesFrom (message, current_object,
916 &rule, sortby, FALSE, count, traverse);
918 case Accessibility_Collection_TREE_INORDER :
919 return getMatchesInOrder (message, current_object,
920 &rule, sortby, TRUE, count, traverse);
922 default : return NULL;
927 impl_getMatchesTo (DBusConnection *bus, DBusMessage *message, void *user_data)
929 char *current_object_path = NULL;
930 AtkObject *current_object;
931 DBusMessageIter iter;
932 MatchRulePrivate rule;
933 dbus_uint16_t sortby;
937 dbus_bool_t traverse;
940 dbus_message_iter_init(message, &iter);
941 dbus_message_iter_get_basic (&iter, current_object_path);
942 current_object = atk_dbus_get_object (current_object_path);
945 // TODO: object-not-found error
946 return spi_dbus_general_error (message);
948 dbus_message_iter_next (&iter);
949 if (!read_mr(&iter, &rule))
951 return spi_dbus_general_error (message);
953 dbus_message_iter_get_basic(&iter, &sortby);
954 dbus_message_iter_next(&iter);
955 dbus_message_iter_get_basic(&iter, &tree);
956 dbus_message_iter_next(&iter);
957 dbus_message_iter_get_basic(&iter, &recurse);
958 dbus_message_iter_next(&iter);
959 dbus_message_iter_get_basic(&iter, &count);
960 dbus_message_iter_next(&iter);
961 dbus_message_iter_get_basic(&iter, &traverse);
962 dbus_message_iter_next(&iter);
965 case Accessibility_Collection_TREE_RESTRICT_CHILDREN :
966 return getMatchesTo (message, current_object,
967 &rule, sortby, recurse, TRUE, count, traverse);
969 case Accessibility_Collection_TREE_RESTRICT_SIBLING :
970 return getMatchesTo (message, current_object,
971 &rule, sortby, recurse, FALSE, count, traverse);
973 case Accessibility_Collection_TREE_INORDER :
974 return getMatchesInBackOrder (message, current_object,
975 &rule, sortby, count);
977 default : return NULL;
982 impl_getMatches(DBusConnection *bus, DBusMessage *message, void *user_data)
984 AtkObject *obj = get_object(message);
985 DBusMessageIter iter;
986 MatchRulePrivate rule;
987 dbus_uint16_t sortby;
989 dbus_bool_t traverse;
992 dbus_message_iter_init(message, &iter);
993 if (!read_mr(&iter, &rule))
995 return spi_dbus_general_error (message);
997 dbus_message_iter_get_basic(&iter, &sortby);
998 dbus_message_iter_next(&iter);
999 dbus_message_iter_get_basic(&iter, &count);
1000 dbus_message_iter_next(&iter);
1001 dbus_message_iter_get_basic(&iter, &traverse);
1002 dbus_message_iter_next(&iter);
1003 ls = g_list_prepend (ls, obj);
1004 count = query_exec (&rule, sortby, ls, 0, count,
1005 obj, 0, TRUE, NULL, TRUE, traverse);
1006 ls = g_list_remove (ls, ls->data);
1008 if (sortby == Accessibility_Collection_SORT_ORDER_REVERSE_CANONICAL)
1009 ls = g_list_reverse (ls);
1010 free_mrp_data (&rule);
1011 return return_and_free_list (message, ls);
1014 static DRouteMethod methods[] = {
1015 { impl_getMatchesFrom, "getMatchesFrom" },
1016 { impl_getMatchesTo, "getMatchesTo" },
1017 {impl_getMatches, "getMatches" },
1022 spi_initialize_collection (DRouteData * data)
1024 droute_add_interface (data, SPI_DBUS_INTERFACE_COLLECTION,
1025 methods, NULL, NULL, NULL);