1
/*
2
 * AT-SPI - Assistive Technology Service Provider Interface
3
 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4
 *
5
 * Copyright 2007 IBM Corp.
6
 * Copyright 2010, 2011 Novell, Inc.
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the
20
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
 * Boston, MA 02110-1301, USA.
22
 */
23

            
24
#include "atspi-private.h"
25

            
26
/* TODO: Improve documentation and implement some missing functions */
27

            
28
/**
29
 * AtspiCollection
30
 *
31
 * An interface designed to allow accessibles which satisfy a set of
32
 * criteria to be returned.
33
 *
34
 * An interface designed to allow accessibles which satisfy a set of
35
 * criteria to be returned. This interface can be used to avoid iteration
36
 * or client-side search of the object tree.
37
 */
38

            
39
/**
40
 * atspi_collection_is_ancestor_of:
41
 *
42
 * Not yet implemented.
43
 *
44
 **/
45
gboolean
46
atspi_collection_is_ancestor_of (AtspiCollection *collection,
47
                                 AtspiAccessible *test,
48
                                 GError **error)
49
{
50
  g_warning ("AT-SPI: TODO: Implement is_ancestor_of");
51
  return FALSE;
52
}
53

            
54
static DBusMessage *
55
5
new_message (AtspiCollection *collection, char *method)
56
{
57
  AtspiAccessible *accessible;
58

            
59
5
  g_assert (collection != NULL);
60

            
61
5
  accessible = ATSPI_ACCESSIBLE (collection);
62
5
  if (!accessible->parent.app)
63
    return NULL;
64
5
  return dbus_message_new_method_call (accessible->parent.app->bus_name,
65
5
                                       accessible->parent.path,
66
                                       atspi_interface_collection,
67
                                       method);
68
}
69

            
70
static gboolean
71
5
append_match_rule (DBusMessage *message, AtspiMatchRule *rule)
72
{
73
  DBusMessageIter iter;
74

            
75
5
  dbus_message_iter_init_append (message, &iter);
76
5
  return _atspi_match_rule_marshal (rule, &iter);
77
}
78

            
79
static gboolean
80
4
append_accessible (DBusMessage *message, AtspiAccessible *accessible)
81
{
82
  DBusMessageIter iter;
83

            
84
4
  dbus_message_iter_init_append (message, &iter);
85
4
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH,
86
4
                                  &accessible->parent.path);
87
4
  return TRUE; /* TODO: Check for out-of-memory */
88
}
89

            
90
static GArray *
91
5
return_accessibles (DBusMessage *message)
92
{
93
  DBusMessageIter iter, iter_array;
94
5
  GArray *ret = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *));
95

            
96
5
  _ATSPI_DBUS_CHECK_SIG (message, "a(so)", NULL, NULL);
97

            
98
5
  dbus_message_iter_init (message, &iter);
99
5
  dbus_message_iter_recurse (&iter, &iter_array);
100

            
101
24
  while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
102
    {
103
      AtspiAccessible *accessible;
104
19
      accessible = _atspi_dbus_consume_accessible (&iter_array);
105
19
      ret = g_array_append_val (ret, accessible);
106
      /* Iter was moved already, so no need to call dbus_message_iter_next */
107
    }
108
5
  dbus_message_unref (message);
109
5
  return ret;
110
}
111

            
112
/**
113
 * atspi_collection_get_matches:
114
 * @collection: A pointer to the #AtspiCollection to query.
115
 * @rule: An #AtspiMatchRule describing the match criteria.
116
 * @sortby: An #AtspiCollectionSortOrder specifying the way the results are to
117
 *          be sorted.
118
 * @count: The maximum number of results to return, or 0 for no limit.
119
 * @traverse: Not supported.
120
 *
121
 * Gets all #AtspiAccessible objects from the @collection matching a given
122
 * @rule.
123
 *
124
 * Returns: (element-type AtspiAccessible*) (transfer full): All
125
 *          #AtspiAccessible objects matching the given match rule.
126
 **/
127
GArray *
128
1
atspi_collection_get_matches (AtspiCollection *collection,
129
                              AtspiMatchRule *rule,
130
                              AtspiCollectionSortOrder sortby,
131
                              gint count,
132
                              gboolean traverse,
133
                              GError **error)
134
{
135
1
  DBusMessage *message = new_message (collection, "GetMatches");
136
  DBusMessage *reply;
137
1
  dbus_int32_t d_sortby = sortby;
138
1
  dbus_int32_t d_count = count;
139
1
  dbus_bool_t d_traverse = traverse;
140

            
141
1
  if (!message)
142
    return NULL;
143

            
144
1
  if (!append_match_rule (message, rule))
145
    return NULL;
146
1
  dbus_message_append_args (message, DBUS_TYPE_UINT32, &d_sortby,
147
                            DBUS_TYPE_INT32, &d_count,
148
                            DBUS_TYPE_BOOLEAN, &d_traverse,
149
                            DBUS_TYPE_INVALID);
150
1
  reply = _atspi_dbus_send_with_reply_and_block (message, error);
151
1
  if (!reply)
152
    return NULL;
153
1
  return return_accessibles (reply);
154
}
155

            
156
/**
157
 * atspi_collection_get_matches_to:
158
 * @collection: A pointer to the #AtspiCollection to query.
159
 * @current_object: The object at which to start searching.
160
 * @rule: An #AtspiMatchRule describing the match criteria.
161
 * @sortby: An #AtspiCollectionSortOrder specifying the way the results are to
162
 *          be sorted.
163
 * @tree: An #AtspiCollectionTreeTraversalType specifying restrictions on
164
 *          the objects to be traversed.
165
 * @limit_scope: If #TRUE, only descendants of @current_object's parent
166
 *          will be returned. Otherwise (if #FALSE), any accessible may be
167
 *          returned if it would preceed @current_object in a flattened
168
 *          hierarchy.
169
 * @count: The maximum number of results to return, or 0 for no limit.
170
 * @traverse: Not supported.
171
 *
172
 * Gets all #AtspiAccessible objects from the @collection, after
173
 * @current_object, matching a given @rule.
174
 *
175
 * Returns: (element-type AtspiAccessible*) (transfer full): All
176
 *          #AtspiAccessible objects matching the given match rule after
177
 *          @current_object.
178
 **/
179
GArray *
180
1
atspi_collection_get_matches_to (AtspiCollection *collection,
181
                                 AtspiAccessible *current_object,
182
                                 AtspiMatchRule *rule,
183
                                 AtspiCollectionSortOrder sortby,
184
                                 AtspiCollectionTreeTraversalType tree,
185
                                 gboolean limit_scope,
186
                                 gint count,
187
                                 gboolean traverse,
188
                                 GError **error)
189
{
190
1
  DBusMessage *message = new_message (collection, "GetMatchesTo");
191
  DBusMessage *reply;
192
1
  dbus_int32_t d_sortby = sortby;
193
1
  dbus_int32_t d_tree = tree;
194
1
  dbus_bool_t d_limit_scope = limit_scope;
195
1
  dbus_int32_t d_count = count;
196
1
  dbus_bool_t d_traverse = traverse;
197

            
198
1
  if (!message)
199
    return NULL;
200

            
201
1
  if (!append_accessible (message, current_object))
202
    return NULL;
203
1
  if (!append_match_rule (message, rule))
204
    return NULL;
205
1
  dbus_message_append_args (message, DBUS_TYPE_UINT32, &d_sortby,
206
                            DBUS_TYPE_UINT32, &d_tree,
207
                            DBUS_TYPE_BOOLEAN, &d_limit_scope,
208
                            DBUS_TYPE_INT32, &d_count,
209
                            DBUS_TYPE_BOOLEAN, &d_traverse,
210
                            DBUS_TYPE_INVALID);
211
1
  reply = _atspi_dbus_send_with_reply_and_block (message, error);
212
1
  if (!reply)
213
    return NULL;
214
1
  return return_accessibles (reply);
215
}
216

            
217
/**
218
 * atspi_collection_get_matches_from:
219
 * @collection: A pointer to the #AtspiCollection to query.
220
 * @current_object: Upon reaching this object, searching should stop.
221
 * @rule: An #AtspiMatchRule describing the match criteria.
222
 * @sortby: An #AtspiCollectionSortOrder specifying the way the results are to
223
 *          be sorted.
224
 * @tree: An #AtspiCollectionTreeTraversalType specifying restrictions on
225
 *          the objects to be traversed.
226
 * @count: The maximum number of results to return, or 0 for no limit.
227
 * @traverse: Not supported.
228
 *
229
 * Gets all #AtspiAccessible objects from the @collection, before
230
 * @current_object, matching a given @rule.
231
 *
232
 * Returns: (element-type AtspiAccessible*) (transfer full): All
233
 *          #AtspiAccessible objects matching the given match rule that preceed
234
 *          @current_object.
235
 **/
236
GArray *
237
3
atspi_collection_get_matches_from (AtspiCollection *collection,
238
                                   AtspiAccessible *current_object,
239
                                   AtspiMatchRule *rule,
240
                                   AtspiCollectionSortOrder sortby,
241
                                   AtspiCollectionTreeTraversalType tree,
242
                                   gint count,
243
                                   gboolean traverse,
244
                                   GError **error)
245
{
246
3
  DBusMessage *message = new_message (collection, "GetMatchesFrom");
247
  DBusMessage *reply;
248
3
  dbus_int32_t d_sortby = sortby;
249
3
  dbus_int32_t d_tree = tree;
250
3
  dbus_int32_t d_count = count;
251
3
  dbus_bool_t d_traverse = traverse;
252

            
253
3
  if (!message)
254
    return NULL;
255

            
256
3
  if (!append_accessible (message, current_object))
257
    return NULL;
258
3
  if (!append_match_rule (message, rule))
259
    return NULL;
260
3
  dbus_message_append_args (message, DBUS_TYPE_UINT32, &d_sortby,
261
                            DBUS_TYPE_UINT32, &d_tree,
262
                            DBUS_TYPE_INT32, &d_count,
263
                            DBUS_TYPE_BOOLEAN, &d_traverse,
264
                            DBUS_TYPE_INVALID);
265
3
  reply = _atspi_dbus_send_with_reply_and_block (message, error);
266
3
  if (!reply)
267
    return NULL;
268
3
  return return_accessibles (reply);
269
}
270

            
271
/**
272
 * atspi_collection_get_active_descendant:
273
 *
274
 * Returns: (transfer full): The active descendant of the given object.
275
 * Not yet implemented.
276
 **/
277
AtspiAccessible *
278
atspi_collection_get_active_descendant (AtspiCollection *collection, GError **error)
279
{
280
  g_warning ("AT-SPI: TODO: Implement get_active_descendants");
281
  return NULL;
282
}
283

            
284
static void
285
4
atspi_collection_base_init (AtspiCollection *klass)
286
{
287
4
}
288

            
289
GType
290
7
atspi_collection_get_type (void)
291
{
292
  static GType type = 0;
293

            
294
7
  if (!type)
295
    {
296
      static const GTypeInfo tinfo = {
297
        sizeof (AtspiCollection),
298
        (GBaseInitFunc) atspi_collection_base_init,
299
        (GBaseFinalizeFunc) NULL,
300
      };
301

            
302
2
      type = g_type_register_static (G_TYPE_INTERFACE, "AtspiCollection", &tinfo, 0);
303
    }
304
7
  return type;
305
}