2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008 Novell, Inc.
6 * Copyright 2001, 2002 Sun Microsystems Inc.,
7 * Copyright 2001, 2002 Ximian, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
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 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
28 #include <droute/droute.h>
30 #include "common/spi-dbus.h"
32 #include "introspection.h"
35 impl_get_CharacterCount (DBusMessageIter * iter, void *user_data)
37 AtkText *text = (AtkText *) user_data;
38 g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
39 return droute_return_v_int32 (iter, atk_text_get_character_count (text));
43 impl_get_CaretOffset (DBusMessageIter * iter, void *user_data)
45 AtkText *text = (AtkText *) user_data;
46 g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
47 return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
51 validate_allocated_string (gchar *str)
55 if (!g_utf8_validate (str, -1, NULL))
57 g_warning ("atk-bridge: received bad UTF-8 string from a get_text function");
65 impl_GetText (DBusConnection * bus, DBusMessage * message, void *user_data)
67 AtkText *text = (AtkText *) user_data;
68 dbus_int32_t startOffset, endOffset;
73 g_return_val_if_fail (ATK_IS_TEXT (user_data),
74 droute_not_yet_handled_error (message));
75 dbus_error_init (&error);
76 if (!dbus_message_get_args
77 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
78 &endOffset, DBUS_TYPE_INVALID))
80 return droute_invalid_arguments_error (message);
82 txt = atk_text_get_text (text, startOffset, endOffset);
83 txt = validate_allocated_string (txt);
84 reply = dbus_message_new_method_return (message);
87 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
95 impl_SetCaretOffset (DBusConnection * bus, DBusMessage * message,
98 AtkText *text = (AtkText *) user_data;
104 g_return_val_if_fail (ATK_IS_TEXT (user_data),
105 droute_not_yet_handled_error (message));
106 dbus_error_init (&error);
107 if (!dbus_message_get_args
108 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
110 return droute_invalid_arguments_error (message);
112 rv = atk_text_set_caret_offset (text, offset);
113 reply = dbus_message_new_method_return (message);
116 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
123 impl_GetTextBeforeOffset (DBusConnection * bus, DBusMessage * message,
126 AtkText *text = (AtkText *) user_data;
130 dbus_int32_t startOffset, endOffset;
131 gint intstart_offset = 0, intend_offset = 0;
135 g_return_val_if_fail (ATK_IS_TEXT (user_data),
136 droute_not_yet_handled_error (message));
137 dbus_error_init (&error);
138 if (!dbus_message_get_args
139 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
142 return droute_invalid_arguments_error (message);
145 atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
146 &intstart_offset, &intend_offset);
147 startOffset = intstart_offset;
148 endOffset = intend_offset;
149 txt = validate_allocated_string (txt);
150 reply = dbus_message_new_method_return (message);
153 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
154 DBUS_TYPE_INT32, &startOffset,
155 DBUS_TYPE_INT32, &endOffset,
163 impl_GetTextAtOffset (DBusConnection * bus, DBusMessage * message,
166 AtkText *text = (AtkText *) user_data;
167 dbus_int32_t offset, type;
169 dbus_int32_t startOffset, endOffset;
170 gint intstart_offset = 0, intend_offset = 0;
174 g_return_val_if_fail (ATK_IS_TEXT (user_data),
175 droute_not_yet_handled_error (message));
176 dbus_error_init (&error);
177 if (!dbus_message_get_args
178 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
181 return droute_invalid_arguments_error (message);
184 atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
185 &intstart_offset, &intend_offset);
186 startOffset = intstart_offset;
187 endOffset = intend_offset;
188 txt = validate_allocated_string (txt);
189 reply = dbus_message_new_method_return (message);
192 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
193 DBUS_TYPE_INT32, &startOffset,
194 DBUS_TYPE_INT32, &endOffset,
202 impl_GetTextAfterOffset (DBusConnection * bus, DBusMessage * message,
205 AtkText *text = (AtkText *) user_data;
209 dbus_int32_t startOffset, endOffset;
210 gint intstart_offset = 0, intend_offset = 0;
214 g_return_val_if_fail (ATK_IS_TEXT (user_data),
215 droute_not_yet_handled_error (message));
216 dbus_error_init (&error);
217 if (!dbus_message_get_args
218 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
221 return droute_invalid_arguments_error (message);
224 atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
225 &intstart_offset, &intend_offset);
226 startOffset = intstart_offset;
227 endOffset = intend_offset;
228 txt = validate_allocated_string (txt);
229 reply = dbus_message_new_method_return (message);
232 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
233 DBUS_TYPE_INT32, &startOffset,
234 DBUS_TYPE_INT32, &endOffset,
242 impl_GetCharacterAtOffset (DBusConnection * bus, DBusMessage * message,
245 AtkText *text = (AtkText *) user_data;
251 g_return_val_if_fail (ATK_IS_TEXT (user_data),
252 droute_not_yet_handled_error (message));
253 dbus_error_init (&error);
254 if (!dbus_message_get_args
255 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
257 return droute_invalid_arguments_error (message);
259 ch = atk_text_get_character_at_offset (text, offset);
260 reply = dbus_message_new_method_return (message);
263 dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch,
270 impl_GetAttributeValue (DBusConnection * bus, DBusMessage * message,
273 AtkText *text = (AtkText *) user_data;
276 dbus_int32_t startOffset, endOffset;
278 gint intstart_offset = 0, intend_offset = 0;
282 AtkAttributeSet *set;
286 g_return_val_if_fail (ATK_IS_TEXT (user_data),
287 droute_not_yet_handled_error (message));
288 dbus_error_init (&error);
289 if (!dbus_message_get_args
290 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
291 &attributeName, DBUS_TYPE_INVALID))
293 return droute_invalid_arguments_error (message);
296 set = atk_text_get_run_attributes (text, offset,
297 &intstart_offset, &intend_offset);
298 startOffset = intstart_offset;
299 endOffset = intend_offset;
301 cur_attr = (GSList *) set;
304 at = (AtkAttribute *) cur_attr->data;
305 if (!strcmp (at->name, attributeName))
311 cur_attr = cur_attr->next;
315 reply = dbus_message_new_method_return (message);
318 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INT32,
319 &startOffset, DBUS_TYPE_INT32, &endOffset,
320 DBUS_TYPE_BOOLEAN, &defined,
323 atk_attribute_set_free (set);
328 _string_from_attribute_set (AtkAttributeSet * set)
330 gchar *attributes, *tmp, *tmp2;
334 attributes = g_strdup ("");
335 cur_attr = (GSList *) set;
338 at = (AtkAttribute *) cur_attr->data;
339 tmp = g_strdup_printf ("%s%s:%s%s",
340 ((GSList *) (set) == cur_attr) ? "" : " ",
342 (cur_attr->next) ? ";" : "");
343 tmp2 = g_strconcat (attributes, tmp, NULL);
347 cur_attr = cur_attr->next;
353 impl_GetAttributes (DBusConnection * bus, DBusMessage * message,
356 AtkText *text = (AtkText *) user_data;
358 dbus_int32_t startOffset, endOffset;
359 gint intstart_offset, intend_offset;
362 AtkAttributeSet *set;
363 DBusMessageIter iter;
365 g_return_val_if_fail (ATK_IS_TEXT (user_data),
366 droute_not_yet_handled_error (message));
367 dbus_error_init (&error);
368 if (!dbus_message_get_args
369 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
371 return droute_invalid_arguments_error (message);
374 set = atk_text_get_run_attributes (text, offset,
375 &intstart_offset, &intend_offset);
377 startOffset = intstart_offset;
378 endOffset = intend_offset;
379 reply = dbus_message_new_method_return (message);
382 dbus_message_iter_init_append (reply, &iter);
383 spi_object_append_attribute_set (&iter, set);
384 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
385 DBUS_TYPE_INT32, &endOffset,
388 atk_attribute_set_free (set);
393 impl_GetDefaultAttributes (DBusConnection * bus, DBusMessage * message,
396 AtkText *text = (AtkText *) user_data;
399 AtkAttributeSet *set;
400 DBusMessageIter iter;
402 g_return_val_if_fail (ATK_IS_TEXT (user_data),
403 droute_not_yet_handled_error (message));
404 dbus_error_init (&error);
406 set = atk_text_get_default_attributes (text);
407 reply = dbus_message_new_method_return (message);
410 dbus_message_iter_init_append (reply, &iter);
411 spi_object_append_attribute_set (&iter, set);
413 atk_attribute_set_free (set);
418 impl_GetCharacterExtents (DBusConnection * bus, DBusMessage * message,
421 AtkText *text = (AtkText *) user_data;
423 dbus_uint32_t coordType;
424 dbus_int32_t x, y, width, height;
425 gint ix = 0, iy = 0, iw = 0, ih = 0;
429 g_return_val_if_fail (ATK_IS_TEXT (user_data),
430 droute_not_yet_handled_error (message));
431 dbus_error_init (&error);
432 if (!dbus_message_get_args
433 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32,
434 &coordType, DBUS_TYPE_INVALID))
436 return droute_invalid_arguments_error (message);
438 atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
439 (AtkCoordType) coordType);
444 reply = dbus_message_new_method_return (message);
447 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
448 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
449 &height, DBUS_TYPE_INVALID);
455 impl_GetOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
458 AtkText *text = (AtkText *) user_data;
460 dbus_uint32_t coordType;
465 g_return_val_if_fail (ATK_IS_TEXT (user_data),
466 droute_not_yet_handled_error (message));
467 dbus_error_init (&error);
468 if (!dbus_message_get_args
469 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
470 DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
472 return droute_invalid_arguments_error (message);
474 rv = atk_text_get_offset_at_point (text, x, y, coordType);
475 reply = dbus_message_new_method_return (message);
478 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
485 impl_GetNSelections (DBusConnection * bus, DBusMessage * message,
488 AtkText *text = (AtkText *) user_data;
492 g_return_val_if_fail (ATK_IS_TEXT (user_data),
493 droute_not_yet_handled_error (message));
494 rv = atk_text_get_n_selections (text);
495 reply = dbus_message_new_method_return (message);
498 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
505 impl_GetSelection (DBusConnection * bus, DBusMessage * message,
508 AtkText *text = (AtkText *) user_data;
509 dbus_int32_t selectionNum;
510 dbus_int32_t startOffset, endOffset;
511 gint intstart_offset = 0, intend_offset = 0;
515 g_return_val_if_fail (ATK_IS_TEXT (user_data),
516 droute_not_yet_handled_error (message));
517 dbus_error_init (&error);
518 if (!dbus_message_get_args
519 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
521 return droute_invalid_arguments_error (message);
523 /* atk_text_get_selection returns gchar * which we discard */
524 g_free (atk_text_get_selection
525 (text, selectionNum, &intstart_offset, &intend_offset));
526 startOffset = intstart_offset;
527 endOffset = intend_offset;
528 reply = dbus_message_new_method_return (message);
531 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
532 DBUS_TYPE_INT32, &endOffset,
539 impl_AddSelection (DBusConnection * bus, DBusMessage * message,
542 AtkText *text = (AtkText *) user_data;
543 dbus_int32_t startOffset, endOffset;
548 g_return_val_if_fail (ATK_IS_TEXT (user_data),
549 droute_not_yet_handled_error (message));
550 dbus_error_init (&error);
551 if (!dbus_message_get_args
552 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
553 &endOffset, DBUS_TYPE_INVALID))
555 return droute_invalid_arguments_error (message);
557 rv = atk_text_add_selection (text, startOffset, endOffset);
558 reply = dbus_message_new_method_return (message);
561 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
568 impl_RemoveSelection (DBusConnection * bus, DBusMessage * message,
571 AtkText *text = (AtkText *) user_data;
572 dbus_int32_t selectionNum;
577 g_return_val_if_fail (ATK_IS_TEXT (user_data),
578 droute_not_yet_handled_error (message));
579 dbus_error_init (&error);
580 if (!dbus_message_get_args
581 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
583 return droute_invalid_arguments_error (message);
585 rv = atk_text_remove_selection (text, selectionNum);
586 reply = dbus_message_new_method_return (message);
589 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
596 impl_SetSelection (DBusConnection * bus, DBusMessage * message,
599 AtkText *text = (AtkText *) user_data;
600 dbus_int32_t selectionNum, startOffset, endOffset;
605 g_return_val_if_fail (ATK_IS_TEXT (user_data),
606 droute_not_yet_handled_error (message));
607 dbus_error_init (&error);
608 if (!dbus_message_get_args
609 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
610 &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
612 return droute_invalid_arguments_error (message);
614 rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
615 reply = dbus_message_new_method_return (message);
618 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
625 impl_GetRangeExtents (DBusConnection * bus, DBusMessage * message,
628 AtkText *text = (AtkText *) user_data;
629 dbus_int32_t startOffset, endOffset;
630 dbus_uint32_t coordType;
631 AtkTextRectangle rect;
632 dbus_int32_t x, y, width, height;
636 g_return_val_if_fail (ATK_IS_TEXT (user_data),
637 droute_not_yet_handled_error (message));
638 dbus_error_init (&error);
639 if (!dbus_message_get_args
640 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
641 &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
643 return droute_invalid_arguments_error (message);
645 memset (&rect, 0, sizeof (rect));
646 atk_text_get_range_extents (text, startOffset, endOffset,
647 (AtkCoordType) coordType, &rect);
651 height = rect.height;
652 reply = dbus_message_new_method_return (message);
655 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
656 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
657 &height, DBUS_TYPE_INVALID);
662 #define MAXRANGELEN 512
665 impl_GetBoundedRanges (DBusConnection * bus, DBusMessage * message,
668 AtkText *text = (AtkText *) user_data;
669 dbus_int32_t x, y, width, height;
670 dbus_uint32_t coordType, xClipType, yClipType;
672 AtkTextRange **range_list = NULL;
673 AtkTextRectangle rect;
675 DBusMessageIter iter, array, struc, variant;
677 g_return_val_if_fail (ATK_IS_TEXT (user_data),
678 droute_not_yet_handled_error (message));
679 dbus_error_init (&error);
680 if (!dbus_message_get_args
681 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
682 DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
683 &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
686 return droute_invalid_arguments_error (message);
691 rect.height = height;
694 atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
695 (AtkTextClipType) xClipType,
696 (AtkTextClipType) yClipType);
697 reply = dbus_message_new_method_return (message);
700 /* This isn't pleasant. */
701 dbus_message_iter_init_append (reply, &iter);
702 if (dbus_message_iter_open_container
703 (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
706 for (len = 0; len < MAXRANGELEN && range_list[len]; ++len)
708 if (dbus_message_iter_open_container
709 (&array, DBUS_TYPE_STRUCT, NULL, &struc))
712 val = range_list[len]->start_offset;
713 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
714 val = range_list[len]->end_offset;
715 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
716 dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
717 &range_list[len]->content);
718 /* The variant is unimplemented in atk, but I don't want to
719 * unilaterally muck with the spec and remove it, so I'll just
720 * throw in a dummy value */
721 if (dbus_message_iter_open_container
722 (&struc, DBUS_TYPE_VARIANT, "i", &variant))
724 dbus_uint32_t dummy = 0;
725 dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
727 dbus_message_iter_close_container (&struc, &variant);
729 dbus_message_iter_close_container (&array, &struc);
732 dbus_message_iter_close_container (&iter, &array);
738 impl_GetAttributeRun (DBusConnection * bus, DBusMessage * message,
742 AtkText *text = (AtkText *) user_data;
744 dbus_bool_t includeDefaults;
745 dbus_int32_t startOffset, endOffset;
746 gint intstart_offset = 0, intend_offset = 0;
748 AtkAttributeSet *attributes = NULL;
749 AtkAttribute *attr = NULL;
750 DBusMessageIter iter, iterArray;
752 g_return_val_if_fail (ATK_IS_TEXT (user_data),
753 droute_not_yet_handled_error (message));
754 dbus_error_init (&error);
755 if (!dbus_message_get_args
756 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
757 &includeDefaults, DBUS_TYPE_INVALID))
759 return droute_invalid_arguments_error (message);
763 atk_text_get_run_attributes (text, offset, &intstart_offset,
768 attributes = g_slist_concat (attributes,
769 atk_text_get_default_attributes (text));
772 reply = dbus_message_new_method_return (message);
776 dbus_message_iter_init_append (reply, &iter);
777 spi_object_append_attribute_set (&iter, attributes);
779 startOffset = intstart_offset;
780 endOffset = intend_offset;
781 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
782 dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
784 atk_attribute_set_free (attributes);
790 impl_GetDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
793 AtkText *text = (AtkText *) user_data;
795 DBusMessageIter iter;
796 AtkAttributeSet *attributes;
798 g_return_val_if_fail (ATK_IS_TEXT (user_data),
799 droute_not_yet_handled_error (message));
801 attributes = atk_text_get_default_attributes (text);
803 reply = dbus_message_new_method_return (message);
806 dbus_message_iter_init_append (reply, &iter);
807 spi_object_append_attribute_set (&iter, attributes);
811 atk_attribute_set_free (attributes);
816 static DRouteMethod methods[] = {
817 {impl_GetText, "GetText"},
818 {impl_SetCaretOffset, "SetCaretOffset"},
819 {impl_GetTextBeforeOffset, "GetTextBeforeOffset"},
820 {impl_GetTextAtOffset, "GetTextAtOffset"},
821 {impl_GetTextAfterOffset, "GetTextAfterOffset"},
822 {impl_GetCharacterAtOffset, "GetCharacterAtOffset"},
823 {impl_GetAttributeValue, "GetAttributeValue"},
824 {impl_GetAttributes, "GetAttributes"},
825 {impl_GetDefaultAttributes, "GetDefaultAttributes"},
826 {impl_GetCharacterExtents, "GetCharacterExtents"},
827 {impl_GetOffsetAtPoint, "GetOffsetAtPoint"},
828 {impl_GetNSelections, "GetNSelections"},
829 {impl_GetSelection, "GetSelection"},
830 {impl_AddSelection, "AddSelection"},
831 {impl_RemoveSelection, "RemoveSelection"},
832 {impl_SetSelection, "SetSelection"},
833 {impl_GetRangeExtents, "GetRangeExtents"},
834 {impl_GetBoundedRanges, "GetBoundedRanges"},
835 {impl_GetAttributeRun, "GetAttributeRun"},
836 {impl_GetDefaultAttributeSet, "GetDefaultAttributeSet"},
840 static DRouteProperty properties[] = {
841 {impl_get_CharacterCount, NULL, "CharacterCount"},
842 {impl_get_CaretOffset, NULL, "CaretOffset"},
847 spi_initialize_text (DRoutePath * path)
849 droute_path_add_interface (path,
850 SPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties);