1 /*
2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4 *
5 * Copyright 2008 Novell, Inc.
6 * Copyright 2001, 2002 Sun Microsystems Inc.,
7 * Copyright 2001, 2002 Ximian, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #include <string.h>
26
27 #include <atk/atk.h>
28 #include <droute/droute.h>
29 #include "bridge.h"
30
31 #include "spi-dbus.h"
32 #include "object.h"
33 #include "introspection.h"
34
35 static dbus_bool_t
impl_get_CharacterCount(DBusMessageIter * iter,void * user_data)36 impl_get_CharacterCount (DBusMessageIter * iter, void *user_data)
37 {
38 AtkText *text = (AtkText *) user_data;
39 g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
40 return droute_return_v_int32 (iter, atk_text_get_character_count (text));
41 }
42
43 static dbus_bool_t
impl_get_CaretOffset(DBusMessageIter * iter,void * user_data)44 impl_get_CaretOffset (DBusMessageIter * iter, void *user_data)
45 {
46 AtkText *text = (AtkText *) user_data;
47 g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
48 return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
49 }
50
51 static gchar *
validate_allocated_string(gchar * str)52 validate_allocated_string (gchar *str)
53 {
54 if (!str)
55 return g_strdup ("");
56 if (!g_utf8_validate (str, -1, NULL))
57 {
58 g_warning ("atk-bridge: received bad UTF-8 string from a get_text function");
59 g_free (str);
60 return g_strdup ("");
61 }
62 return str;
63 }
64
65 static DBusMessage *
impl_GetText(DBusConnection * bus,DBusMessage * message,void * user_data)66 impl_GetText (DBusConnection * bus, DBusMessage * message, void *user_data)
67 {
68 AtkText *text = (AtkText *) user_data;
69 dbus_int32_t startOffset, endOffset;
70 gchar *txt;
71 DBusMessage *reply;
72
73 g_return_val_if_fail (ATK_IS_TEXT (user_data),
74 droute_not_yet_handled_error (message));
75 if (!dbus_message_get_args
76 (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
77 &endOffset, DBUS_TYPE_INVALID))
78 {
79 return droute_invalid_arguments_error (message);
80 }
81 txt = atk_text_get_text (text, startOffset, endOffset);
82 txt = validate_allocated_string (txt);
83 reply = dbus_message_new_method_return (message);
84 if (reply)
85 {
86 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
87 DBUS_TYPE_INVALID);
88 }
89 g_free (txt);
90 return reply;
91 }
92
93 static DBusMessage *
impl_SetCaretOffset(DBusConnection * bus,DBusMessage * message,void * user_data)94 impl_SetCaretOffset (DBusConnection * bus, DBusMessage * message,
95 void *user_data)
96 {
97 AtkText *text = (AtkText *) user_data;
98 dbus_int32_t offset;
99 dbus_bool_t rv;
100 DBusMessage *reply;
101
102 g_return_val_if_fail (ATK_IS_TEXT (user_data),
103 droute_not_yet_handled_error (message));
104 if (!dbus_message_get_args
105 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
106 {
107 return droute_invalid_arguments_error (message);
108 }
109 rv = atk_text_set_caret_offset (text, offset);
110 reply = dbus_message_new_method_return (message);
111 if (reply)
112 {
113 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
114 DBUS_TYPE_INVALID);
115 }
116 return reply;
117 }
118
119 static DBusMessage *
impl_GetTextBeforeOffset(DBusConnection * bus,DBusMessage * message,void * user_data)120 impl_GetTextBeforeOffset (DBusConnection * bus, DBusMessage * message,
121 void *user_data)
122 {
123 AtkText *text = (AtkText *) user_data;
124 dbus_int32_t offset;
125 dbus_uint32_t type;
126 gchar *txt;
127 dbus_int32_t startOffset, endOffset;
128 gint intstart_offset = 0, intend_offset = 0;
129 DBusMessage *reply;
130
131 g_return_val_if_fail (ATK_IS_TEXT (user_data),
132 droute_not_yet_handled_error (message));
133 if (!dbus_message_get_args
134 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
135 DBUS_TYPE_INVALID))
136 {
137 return droute_invalid_arguments_error (message);
138 }
139 txt =
140 atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
141 &intstart_offset, &intend_offset);
142 startOffset = intstart_offset;
143 endOffset = intend_offset;
144 txt = validate_allocated_string (txt);
145 reply = dbus_message_new_method_return (message);
146 if (reply)
147 {
148 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
149 DBUS_TYPE_INT32, &startOffset,
150 DBUS_TYPE_INT32, &endOffset,
151 DBUS_TYPE_INVALID);
152 }
153 g_free (txt);
154 return reply;
155 }
156
157 static DBusMessage *
impl_GetTextAtOffset(DBusConnection * bus,DBusMessage * message,void * user_data)158 impl_GetTextAtOffset (DBusConnection * bus, DBusMessage * message,
159 void *user_data)
160 {
161 AtkText *text = (AtkText *) user_data;
162 dbus_int32_t offset, type;
163 gchar *txt;
164 dbus_int32_t startOffset, endOffset;
165 gint intstart_offset = 0, intend_offset = 0;
166 DBusMessage *reply;
167
168 g_return_val_if_fail (ATK_IS_TEXT (user_data),
169 droute_not_yet_handled_error (message));
170 if (!dbus_message_get_args
171 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
172 DBUS_TYPE_INVALID))
173 {
174 return droute_invalid_arguments_error (message);
175 }
176 txt =
177 atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
178 &intstart_offset, &intend_offset);
179 startOffset = intstart_offset;
180 endOffset = intend_offset;
181 txt = validate_allocated_string (txt);
182 reply = dbus_message_new_method_return (message);
183 if (reply)
184 {
185 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
186 DBUS_TYPE_INT32, &startOffset,
187 DBUS_TYPE_INT32, &endOffset,
188 DBUS_TYPE_INVALID);
189 }
190 g_free (txt);
191 return reply;
192 }
193
194 static DBusMessage *
impl_GetTextAfterOffset(DBusConnection * bus,DBusMessage * message,void * user_data)195 impl_GetTextAfterOffset (DBusConnection * bus, DBusMessage * message,
196 void *user_data)
197 {
198 AtkText *text = (AtkText *) user_data;
199 dbus_int32_t offset;
200 dbus_uint32_t type;
201 gchar *txt;
202 dbus_int32_t startOffset, endOffset;
203 gint intstart_offset = 0, intend_offset = 0;
204 DBusMessage *reply;
205
206 g_return_val_if_fail (ATK_IS_TEXT (user_data),
207 droute_not_yet_handled_error (message));
208 if (!dbus_message_get_args
209 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
210 DBUS_TYPE_INVALID))
211 {
212 return droute_invalid_arguments_error (message);
213 }
214 txt =
215 atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
216 &intstart_offset, &intend_offset);
217 startOffset = intstart_offset;
218 endOffset = intend_offset;
219 txt = validate_allocated_string (txt);
220 reply = dbus_message_new_method_return (message);
221 if (reply)
222 {
223 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
224 DBUS_TYPE_INT32, &startOffset,
225 DBUS_TYPE_INT32, &endOffset,
226 DBUS_TYPE_INVALID);
227 }
228 g_free (txt);
229 return reply;
230 }
231
232 static DBusMessage *
impl_GetCharacterAtOffset(DBusConnection * bus,DBusMessage * message,void * user_data)233 impl_GetCharacterAtOffset (DBusConnection * bus, DBusMessage * message,
234 void *user_data)
235 {
236 AtkText *text = (AtkText *) user_data;
237 dbus_int32_t offset;
238 dbus_int32_t ch;
239 DBusMessage *reply;
240
241 g_return_val_if_fail (ATK_IS_TEXT (user_data),
242 droute_not_yet_handled_error (message));
243 if (!dbus_message_get_args
244 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
245 {
246 return droute_invalid_arguments_error (message);
247 }
248 ch = atk_text_get_character_at_offset (text, offset);
249 reply = dbus_message_new_method_return (message);
250 if (reply)
251 {
252 dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch,
253 DBUS_TYPE_INVALID);
254 }
255 return reply;
256 }
257
258 static gchar *
get_text_for_legacy_implementations(AtkText * text,gint offset,AtkTextGranularity granularity,gint * start_offset,gint * end_offset)259 get_text_for_legacy_implementations(AtkText *text,
260 gint offset,
261 AtkTextGranularity granularity,
262 gint *start_offset,
263 gint *end_offset)
264 {
265 gchar *txt = 0;
266 AtkTextBoundary boundary = 0;
267 switch (granularity) {
268 case ATK_TEXT_GRANULARITY_CHAR:
269 boundary = ATK_TEXT_BOUNDARY_CHAR;
270 break;
271
272 case ATK_TEXT_GRANULARITY_WORD:
273 boundary = ATK_TEXT_BOUNDARY_WORD_START;
274 break;
275
276 case ATK_TEXT_GRANULARITY_SENTENCE:
277 boundary = ATK_TEXT_BOUNDARY_SENTENCE_START;
278 break;
279
280 case ATK_TEXT_GRANULARITY_LINE:
281 boundary = ATK_TEXT_BOUNDARY_LINE_START;
282 break;
283
284 case ATK_TEXT_GRANULARITY_PARAGRAPH:
285 /* This is not implemented in previous versions of ATK */
286 txt = g_strdup("");
287 break;
288
289 default:
290 g_assert_not_reached();
291 }
292
293 if (!txt)
294 {
295 txt =
296 atk_text_get_text_at_offset (text, offset, boundary,
297 start_offset, end_offset);
298 }
299
300 return txt;
301 }
302
303 static DBusMessage *
impl_GetStringAtOffset(DBusConnection * bus,DBusMessage * message,void * user_data)304 impl_GetStringAtOffset (DBusConnection * bus, DBusMessage * message,
305 void *user_data)
306 {
307 AtkText *text = (AtkText *) user_data;
308 dbus_int32_t offset;
309 dbus_uint32_t granularity;
310 gchar *txt = 0;
311 dbus_int32_t startOffset, endOffset;
312 gint intstart_offset = 0, intend_offset = 0;
313 DBusMessage *reply;
314
315 g_return_val_if_fail (ATK_IS_TEXT (user_data),
316 droute_not_yet_handled_error (message));
317 if (!dbus_message_get_args
318 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &granularity,
319 DBUS_TYPE_INVALID))
320 {
321 return droute_invalid_arguments_error (message);
322 }
323
324 txt =
325 atk_text_get_string_at_offset (text, offset, (AtkTextGranularity) granularity,
326 &intstart_offset, &intend_offset);
327
328 /* Accessibility layers implementing an older version of ATK (even if
329 * a new enough version of libatk is installed) might return NULL due
330 * not to provide an implementation for get_string_at_offset(), so we
331 * try with the legacy implementation if that's the case. */
332 if (!txt)
333 txt = get_text_for_legacy_implementations(text, offset,
334 (AtkTextGranularity) granularity,
335 &intstart_offset, &intend_offset);
336
337 startOffset = intstart_offset;
338 endOffset = intend_offset;
339 txt = validate_allocated_string (txt);
340 reply = dbus_message_new_method_return (message);
341 if (reply)
342 {
343 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
344 DBUS_TYPE_INT32, &startOffset,
345 DBUS_TYPE_INT32, &endOffset,
346 DBUS_TYPE_INVALID);
347 }
348 g_free (txt);
349 return reply;
350 }
351
352 static DBusMessage *
impl_GetAttributeValue(DBusConnection * bus,DBusMessage * message,void * user_data)353 impl_GetAttributeValue (DBusConnection * bus, DBusMessage * message,
354 void *user_data)
355 {
356 AtkText *text = (AtkText *) user_data;
357 dbus_int32_t offset;
358 char *attributeName;
359 gint intstart_offset = 0, intend_offset = 0;
360 char *rv = NULL;
361 DBusMessage *reply;
362 AtkAttributeSet *set;
363 GSList *cur_attr;
364 AtkAttribute *at;
365
366 g_return_val_if_fail (ATK_IS_TEXT (user_data),
367 droute_not_yet_handled_error (message));
368 if (!dbus_message_get_args
369 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
370 &attributeName, DBUS_TYPE_INVALID))
371 {
372 return droute_invalid_arguments_error (message);
373 }
374
375 set = atk_text_get_run_attributes (text, offset,
376 &intstart_offset, &intend_offset);
377 cur_attr = (GSList *) set;
378 while (cur_attr)
379 {
380 at = (AtkAttribute *) cur_attr->data;
381 if (!strcmp (at->name, attributeName))
382 {
383 rv = at->value;
384 break;
385 }
386 cur_attr = cur_attr->next;
387 }
388 if (!rv)
389 rv = "";
390 reply = dbus_message_new_method_return (message);
391 if (reply)
392 {
393 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INVALID);
394 }
395 atk_attribute_set_free (set);
396 return reply;
397 }
398
399 static DBusMessage *
impl_GetAttributes(DBusConnection * bus,DBusMessage * message,void * user_data)400 impl_GetAttributes (DBusConnection * bus, DBusMessage * message,
401 void *user_data)
402 {
403 AtkText *text = (AtkText *) user_data;
404 dbus_int32_t offset;
405 dbus_int32_t startOffset, endOffset;
406 gint intstart_offset, intend_offset;
407 DBusMessage *reply;
408 AtkAttributeSet *set;
409 DBusMessageIter iter;
410
411 g_return_val_if_fail (ATK_IS_TEXT (user_data),
412 droute_not_yet_handled_error (message));
413 if (!dbus_message_get_args
414 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
415 {
416 return droute_invalid_arguments_error (message);
417 }
418
419 set = atk_text_get_run_attributes (text, offset,
420 &intstart_offset, &intend_offset);
421
422 startOffset = intstart_offset;
423 endOffset = intend_offset;
424 reply = dbus_message_new_method_return (message);
425 if (reply)
426 {
427 dbus_message_iter_init_append (reply, &iter);
428 spi_object_append_attribute_set (&iter, set);
429 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
430 DBUS_TYPE_INT32, &endOffset,
431 DBUS_TYPE_INVALID);
432 }
433 atk_attribute_set_free (set);
434 return reply;
435 }
436
437 static DBusMessage *
impl_GetDefaultAttributes(DBusConnection * bus,DBusMessage * message,void * user_data)438 impl_GetDefaultAttributes (DBusConnection * bus, DBusMessage * message,
439 void *user_data)
440 {
441 AtkText *text = (AtkText *) user_data;
442 DBusMessage *reply;
443 AtkAttributeSet *set;
444 DBusMessageIter iter;
445
446 g_return_val_if_fail (ATK_IS_TEXT (user_data),
447 droute_not_yet_handled_error (message));
448
449 set = atk_text_get_default_attributes (text);
450 reply = dbus_message_new_method_return (message);
451 if (reply)
452 {
453 dbus_message_iter_init_append (reply, &iter);
454 spi_object_append_attribute_set (&iter, set);
455 }
456 atk_attribute_set_free (set);
457 return reply;
458 }
459
460 static DBusMessage *
impl_GetCharacterExtents(DBusConnection * bus,DBusMessage * message,void * user_data)461 impl_GetCharacterExtents (DBusConnection * bus, DBusMessage * message,
462 void *user_data)
463 {
464 AtkText *text = (AtkText *) user_data;
465 dbus_int32_t offset;
466 dbus_uint32_t coordType;
467 dbus_int32_t x, y, width, height;
468 gint ix = 0, iy = 0, iw = 0, ih = 0;
469 DBusMessage *reply;
470
471 g_return_val_if_fail (ATK_IS_TEXT (user_data),
472 droute_not_yet_handled_error (message));
473 if (!dbus_message_get_args
474 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32,
475 &coordType, DBUS_TYPE_INVALID))
476 {
477 return droute_invalid_arguments_error (message);
478 }
479 atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
480 (AtkCoordType) coordType);
481 x = ix;
482 y = iy;
483 width = iw;
484 height = ih;
485 reply = dbus_message_new_method_return (message);
486 if (reply)
487 {
488 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
489 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
490 &height, DBUS_TYPE_INVALID);
491 }
492 return reply;
493 }
494
495 static DBusMessage *
impl_GetOffsetAtPoint(DBusConnection * bus,DBusMessage * message,void * user_data)496 impl_GetOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
497 void *user_data)
498 {
499 AtkText *text = (AtkText *) user_data;
500 dbus_int32_t x, y;
501 dbus_uint32_t coordType;
502 dbus_int32_t rv;
503 DBusMessage *reply;
504
505 g_return_val_if_fail (ATK_IS_TEXT (user_data),
506 droute_not_yet_handled_error (message));
507 if (!dbus_message_get_args
508 (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
509 DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
510 {
511 return droute_invalid_arguments_error (message);
512 }
513 rv = atk_text_get_offset_at_point (text, x, y, coordType);
514 reply = dbus_message_new_method_return (message);
515 if (reply)
516 {
517 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
518 DBUS_TYPE_INVALID);
519 }
520 return reply;
521 }
522
523 static DBusMessage *
impl_GetNSelections(DBusConnection * bus,DBusMessage * message,void * user_data)524 impl_GetNSelections (DBusConnection * bus, DBusMessage * message,
525 void *user_data)
526 {
527 AtkText *text = (AtkText *) user_data;
528 dbus_int32_t rv;
529 DBusMessage *reply;
530
531 g_return_val_if_fail (ATK_IS_TEXT (user_data),
532 droute_not_yet_handled_error (message));
533 rv = atk_text_get_n_selections (text);
534 reply = dbus_message_new_method_return (message);
535 if (reply)
536 {
537 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
538 DBUS_TYPE_INVALID);
539 }
540 return reply;
541 }
542
543 static DBusMessage *
impl_GetSelection(DBusConnection * bus,DBusMessage * message,void * user_data)544 impl_GetSelection (DBusConnection * bus, DBusMessage * message,
545 void *user_data)
546 {
547 AtkText *text = (AtkText *) user_data;
548 dbus_int32_t selectionNum;
549 dbus_int32_t startOffset, endOffset;
550 gint intstart_offset = 0, intend_offset = 0;
551 DBusMessage *reply;
552
553 g_return_val_if_fail (ATK_IS_TEXT (user_data),
554 droute_not_yet_handled_error (message));
555 if (!dbus_message_get_args
556 (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
557 {
558 return droute_invalid_arguments_error (message);
559 }
560 /* atk_text_get_selection returns gchar * which we discard */
561 g_free (atk_text_get_selection
562 (text, selectionNum, &intstart_offset, &intend_offset));
563 startOffset = intstart_offset;
564 endOffset = intend_offset;
565 reply = dbus_message_new_method_return (message);
566 if (reply)
567 {
568 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
569 DBUS_TYPE_INT32, &endOffset,
570 DBUS_TYPE_INVALID);
571 }
572 return reply;
573 }
574
575 static DBusMessage *
impl_AddSelection(DBusConnection * bus,DBusMessage * message,void * user_data)576 impl_AddSelection (DBusConnection * bus, DBusMessage * message,
577 void *user_data)
578 {
579 AtkText *text = (AtkText *) user_data;
580 dbus_int32_t startOffset, endOffset;
581 dbus_bool_t rv;
582 DBusMessage *reply;
583
584 g_return_val_if_fail (ATK_IS_TEXT (user_data),
585 droute_not_yet_handled_error (message));
586 if (!dbus_message_get_args
587 (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
588 &endOffset, DBUS_TYPE_INVALID))
589 {
590 return droute_invalid_arguments_error (message);
591 }
592 rv = atk_text_add_selection (text, startOffset, endOffset);
593 reply = dbus_message_new_method_return (message);
594 if (reply)
595 {
596 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
597 DBUS_TYPE_INVALID);
598 }
599 return reply;
600 }
601
602 static DBusMessage *
impl_RemoveSelection(DBusConnection * bus,DBusMessage * message,void * user_data)603 impl_RemoveSelection (DBusConnection * bus, DBusMessage * message,
604 void *user_data)
605 {
606 AtkText *text = (AtkText *) user_data;
607 dbus_int32_t selectionNum;
608 dbus_bool_t rv;
609 DBusMessage *reply;
610
611 g_return_val_if_fail (ATK_IS_TEXT (user_data),
612 droute_not_yet_handled_error (message));
613 if (!dbus_message_get_args
614 (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
615 {
616 return droute_invalid_arguments_error (message);
617 }
618 rv = atk_text_remove_selection (text, selectionNum);
619 reply = dbus_message_new_method_return (message);
620 if (reply)
621 {
622 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
623 DBUS_TYPE_INVALID);
624 }
625 return reply;
626 }
627
628 static DBusMessage *
impl_SetSelection(DBusConnection * bus,DBusMessage * message,void * user_data)629 impl_SetSelection (DBusConnection * bus, DBusMessage * message,
630 void *user_data)
631 {
632 AtkText *text = (AtkText *) user_data;
633 dbus_int32_t selectionNum, startOffset, endOffset;
634 dbus_bool_t rv;
635 DBusMessage *reply;
636
637 g_return_val_if_fail (ATK_IS_TEXT (user_data),
638 droute_not_yet_handled_error (message));
639 if (!dbus_message_get_args
640 (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
641 &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
642 {
643 return droute_invalid_arguments_error (message);
644 }
645 rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
646 reply = dbus_message_new_method_return (message);
647 if (reply)
648 {
649 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
650 DBUS_TYPE_INVALID);
651 }
652 return reply;
653 }
654
655 static DBusMessage *
impl_GetRangeExtents(DBusConnection * bus,DBusMessage * message,void * user_data)656 impl_GetRangeExtents (DBusConnection * bus, DBusMessage * message,
657 void *user_data)
658 {
659 AtkText *text = (AtkText *) user_data;
660 dbus_int32_t startOffset, endOffset;
661 dbus_uint32_t coordType;
662 AtkTextRectangle rect;
663 dbus_int32_t x, y, width, height;
664 DBusMessage *reply;
665
666 g_return_val_if_fail (ATK_IS_TEXT (user_data),
667 droute_not_yet_handled_error (message));
668 if (!dbus_message_get_args
669 (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
670 &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
671 {
672 return droute_invalid_arguments_error (message);
673 }
674 memset (&rect, 0, sizeof (rect));
675 atk_text_get_range_extents (text, startOffset, endOffset,
676 (AtkCoordType) coordType, &rect);
677 x = rect.x;
678 y = rect.y;
679 width = rect.width;
680 height = rect.height;
681 reply = dbus_message_new_method_return (message);
682 if (reply)
683 {
684 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
685 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
686 &height, DBUS_TYPE_INVALID);
687 }
688 return reply;
689 }
690
691 #define MAXRANGELEN 512
692
693 static DBusMessage *
impl_GetBoundedRanges(DBusConnection * bus,DBusMessage * message,void * user_data)694 impl_GetBoundedRanges (DBusConnection * bus, DBusMessage * message,
695 void *user_data)
696 {
697 AtkText *text = (AtkText *) user_data;
698 dbus_int32_t x, y, width, height;
699 dbus_uint32_t coordType, xClipType, yClipType;
700 AtkTextRange **range_list = NULL;
701 AtkTextRectangle rect;
702 DBusMessage *reply;
703 DBusMessageIter iter, array, struc, variant;
704
705 g_return_val_if_fail (ATK_IS_TEXT (user_data),
706 droute_not_yet_handled_error (message));
707 if (!dbus_message_get_args
708 (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
709 DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
710 &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
711 DBUS_TYPE_INVALID))
712 {
713 return droute_invalid_arguments_error (message);
714 }
715 rect.x = x;
716 rect.y = y;
717 rect.width = width;
718 rect.height = height;
719
720 range_list =
721 atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
722 (AtkTextClipType) xClipType,
723 (AtkTextClipType) yClipType);
724 reply = dbus_message_new_method_return (message);
725 if (!reply)
726 return NULL;
727 /* This isn't pleasant. */
728 dbus_message_iter_init_append (reply, &iter);
729 if (dbus_message_iter_open_container
730 (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
731 {
732 int len;
733 int count = (range_list ? MAXRANGELEN : 0);
734 for (len = 0; len < count && range_list[len]; ++len)
735 {
736 if (dbus_message_iter_open_container
737 (&array, DBUS_TYPE_STRUCT, NULL, &struc))
738 {
739 dbus_int32_t val;
740 val = range_list[len]->start_offset;
741 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
742 val = range_list[len]->end_offset;
743 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
744 dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
745 &range_list[len]->content);
746 /* The variant is unimplemented in atk, but I don't want to
747 * unilaterally muck with the spec and remove it, so I'll just
748 * throw in a dummy value */
749 if (dbus_message_iter_open_container
750 (&struc, DBUS_TYPE_VARIANT, "i", &variant))
751 {
752 dbus_uint32_t dummy = 0;
753 dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
754 &dummy);
755 dbus_message_iter_close_container (&struc, &variant);
756 }
757 dbus_message_iter_close_container (&array, &struc);
758 g_free (range_list[len]->content);
759 g_free (range_list[len]);
760 }
761 }
762 dbus_message_iter_close_container (&iter, &array);
763 }
764
765 if (range_list)
766 g_free (range_list);
767
768 return reply;
769 }
770
771 static DBusMessage *
impl_GetAttributeRun(DBusConnection * bus,DBusMessage * message,void * user_data)772 impl_GetAttributeRun (DBusConnection * bus, DBusMessage * message,
773 void *user_data)
774 {
775 AtkText *text = (AtkText *) user_data;
776 dbus_int32_t offset;
777 dbus_bool_t includeDefaults;
778 dbus_int32_t startOffset, endOffset;
779 gint intstart_offset = 0, intend_offset = 0;
780 DBusMessage *reply;
781 AtkAttributeSet *attributes = NULL;
782 DBusMessageIter iter;
783
784 g_return_val_if_fail (ATK_IS_TEXT (user_data),
785 droute_not_yet_handled_error (message));
786 if (!dbus_message_get_args
787 (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
788 &includeDefaults, DBUS_TYPE_INVALID))
789 {
790 return droute_invalid_arguments_error (message);
791 }
792
793 if (includeDefaults)
794 {
795 attributes = g_slist_concat (attributes,
796 atk_text_get_default_attributes (text));
797 }
798
799 attributes = g_slist_concat (attributes,
800 atk_text_get_run_attributes (text, offset,
801 &intstart_offset,
802 &intend_offset));
803
804 reply = dbus_message_new_method_return (message);
805 if (!reply)
806 return NULL;
807
808 dbus_message_iter_init_append (reply, &iter);
809 spi_object_append_attribute_set (&iter, attributes);
810
811 startOffset = intstart_offset;
812 endOffset = intend_offset;
813 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
814 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
815
816 atk_attribute_set_free (attributes);
817
818 return reply;
819 }
820
821 static DBusMessage *
impl_GetDefaultAttributeSet(DBusConnection * bus,DBusMessage * message,void * user_data)822 impl_GetDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
823 void *user_data)
824 {
825 AtkText *text = (AtkText *) user_data;
826 DBusMessage *reply;
827 DBusMessageIter iter;
828 AtkAttributeSet *attributes;
829
830 g_return_val_if_fail (ATK_IS_TEXT (user_data),
831 droute_not_yet_handled_error (message));
832
833 attributes = atk_text_get_default_attributes (text);
834
835 reply = dbus_message_new_method_return (message);
836 if (reply)
837 {
838 dbus_message_iter_init_append (reply, &iter);
839 spi_object_append_attribute_set (&iter, attributes);
840 }
841
842 if (attributes)
843 atk_attribute_set_free (attributes);
844
845 return reply;
846 }
847
848 static DBusMessage *
impl_ScrollSubstringTo(DBusConnection * bus,DBusMessage * message,void * user_data)849 impl_ScrollSubstringTo (DBusConnection * bus,
850 DBusMessage * message, void *user_data)
851 {
852 AtkText *text = (AtkText *) user_data;
853 dbus_int32_t startOffset, endOffset;
854 dbus_uint32_t type;
855 dbus_bool_t ret;
856 DBusMessage *reply = NULL;
857
858 g_return_val_if_fail (ATK_IS_TEXT (user_data),
859 droute_not_yet_handled_error (message));
860
861 if (!dbus_message_get_args
862 (message, NULL, DBUS_TYPE_INT32, &startOffset,
863 DBUS_TYPE_INT32, &endOffset,
864 DBUS_TYPE_UINT32, &type,
865 DBUS_TYPE_INVALID))
866 {
867 return droute_invalid_arguments_error (message);
868 }
869
870 ret = atk_text_scroll_substring_to (text, startOffset, endOffset, type);
871
872 reply = dbus_message_new_method_return (message);
873 if (reply)
874 {
875 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
876 DBUS_TYPE_INVALID);
877 }
878 return reply;
879 }
880
881 static DBusMessage *
impl_ScrollSubstringToPoint(DBusConnection * bus,DBusMessage * message,void * user_data)882 impl_ScrollSubstringToPoint (DBusConnection * bus,
883 DBusMessage * message, void *user_data)
884 {
885 AtkText *text = (AtkText *) user_data;
886 dbus_int32_t startOffset, endOffset;
887 dbus_uint32_t type;
888 dbus_int32_t x, y;
889 dbus_bool_t ret;
890 DBusMessage *reply = NULL;
891
892 g_return_val_if_fail (ATK_IS_TEXT (user_data),
893 droute_not_yet_handled_error (message));
894
895 if (!dbus_message_get_args
896 (message, NULL, DBUS_TYPE_INT32, &startOffset,
897 DBUS_TYPE_INT32, &endOffset,
898 DBUS_TYPE_UINT32, &type,
899 DBUS_TYPE_INT32, &x,
900 DBUS_TYPE_INT32, &y,
901 DBUS_TYPE_INVALID))
902 {
903 return droute_invalid_arguments_error (message);
904 }
905
906 ret = atk_text_scroll_substring_to_point (text, startOffset, endOffset, type, x, y);
907
908 reply = dbus_message_new_method_return (message);
909 if (reply)
910 {
911 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
912 DBUS_TYPE_INVALID);
913 }
914 return reply;
915 }
916
917 static DRouteMethod methods[] = {
918 {impl_GetText, "GetText"},
919 {impl_SetCaretOffset, "SetCaretOffset"},
920 {impl_GetTextBeforeOffset, "GetTextBeforeOffset"},
921 {impl_GetTextAtOffset, "GetTextAtOffset"},
922 {impl_GetTextAfterOffset, "GetTextAfterOffset"},
923 {impl_GetStringAtOffset, "GetStringAtOffset"},
924 {impl_GetCharacterAtOffset, "GetCharacterAtOffset"},
925 {impl_GetAttributeValue, "GetAttributeValue"},
926 {impl_GetAttributes, "GetAttributes"},
927 {impl_GetDefaultAttributes, "GetDefaultAttributes"},
928 {impl_GetCharacterExtents, "GetCharacterExtents"},
929 {impl_GetOffsetAtPoint, "GetOffsetAtPoint"},
930 {impl_GetNSelections, "GetNSelections"},
931 {impl_GetSelection, "GetSelection"},
932 {impl_AddSelection, "AddSelection"},
933 {impl_RemoveSelection, "RemoveSelection"},
934 {impl_SetSelection, "SetSelection"},
935 {impl_GetRangeExtents, "GetRangeExtents"},
936 {impl_GetBoundedRanges, "GetBoundedRanges"},
937 {impl_GetAttributeRun, "GetAttributeRun"},
938 {impl_GetDefaultAttributeSet, "GetDefaultAttributeSet"},
939 {impl_ScrollSubstringTo, "ScrollSubstringTo"},
940 {impl_ScrollSubstringToPoint, "ScrollSubstringToPoint"},
941 {NULL, NULL}
942 };
943
944 static DRouteProperty properties[] = {
945 {impl_get_CharacterCount, NULL, "CharacterCount"},
946 {impl_get_CaretOffset, NULL, "CaretOffset"},
947 {NULL, NULL, NULL}
948 };
949
950 void
spi_initialize_text(DRoutePath * path)951 spi_initialize_text (DRoutePath * path)
952 {
953 spi_atk_add_interface (path,
954 ATSPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties);
955 };
956