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.
25 #include "accessible.h"
29 get_text (DBusMessage * message)
31 AtkObject *obj = atk_dbus_get_object (dbus_message_get_path (message));
34 return ATK_TEXT (obj);
38 get_text_from_path (const char *path, void *user_data)
40 AtkObject *obj = atk_dbus_get_object (path);
41 if (!obj || !ATK_IS_TEXT(obj))
43 return ATK_TEXT (obj);
47 impl_get_characterCount (const char *path, DBusMessageIter * iter,
50 AtkText *text = get_text_from_path (path, user_data);
53 return droute_return_v_int32 (iter, atk_text_get_character_count (text));
57 impl_get_caretOffset (const char *path, DBusMessageIter * iter,
60 AtkText *text = get_text_from_path (path, user_data);
63 return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
67 impl_getText (DBusConnection * bus, DBusMessage * message, void *user_data)
69 AtkText *text = get_text (message);
70 dbus_int32_t startOffset, endOffset;
76 return spi_dbus_general_error (message);
77 dbus_error_init (&error);
78 if (!dbus_message_get_args
79 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
80 &endOffset, DBUS_TYPE_INVALID))
82 return SPI_DBUS_RETURN_ERROR (message, &error);
84 txt = atk_text_get_text (text, startOffset, endOffset);
87 reply = dbus_message_new_method_return (message);
90 dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
98 impl_setCaretOffset (DBusConnection * bus, DBusMessage * message,
101 AtkText *text = get_text (message);
108 return spi_dbus_general_error (message);
109 dbus_error_init (&error);
110 if (!dbus_message_get_args
111 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
113 return SPI_DBUS_RETURN_ERROR (message, &error);
115 rv = atk_text_set_caret_offset (text, offset);
116 reply = dbus_message_new_method_return (message);
119 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
126 impl_getTextBeforeOffset (DBusConnection * bus, DBusMessage * message,
129 AtkText *text = get_text (message);
133 dbus_int32_t startOffset, endOffset;
134 gint intstart_offset = 0, intend_offset = 0;
139 return spi_dbus_general_error (message);
140 dbus_error_init (&error);
141 if (!dbus_message_get_args
142 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
145 return SPI_DBUS_RETURN_ERROR (message, &error);
148 atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
149 &intstart_offset, &intend_offset);
150 startOffset = intstart_offset;
151 endOffset = intend_offset;
154 reply = dbus_message_new_method_return (message);
157 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
158 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
159 &txt, DBUS_TYPE_INVALID);
166 impl_getTextAtOffset (DBusConnection * bus, DBusMessage * message,
169 AtkText *text = get_text (message);
170 dbus_int32_t offset, type;
172 dbus_int32_t startOffset, endOffset;
173 gint intstart_offset = 0, intend_offset = 0;
178 return spi_dbus_general_error (message);
179 dbus_error_init (&error);
180 if (!dbus_message_get_args
181 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
184 return SPI_DBUS_RETURN_ERROR (message, &error);
187 atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
188 &intstart_offset, &intend_offset);
189 startOffset = intstart_offset;
190 endOffset = intend_offset;
193 reply = dbus_message_new_method_return (message);
196 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
197 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
198 &txt, DBUS_TYPE_INVALID);
205 impl_getTextAfterOffset (DBusConnection * bus, DBusMessage * message,
208 AtkText *text = get_text (message);
212 dbus_int32_t startOffset, endOffset;
213 gint intstart_offset = 0, intend_offset = 0;
218 return spi_dbus_general_error (message);
219 dbus_error_init (&error);
220 if (!dbus_message_get_args
221 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
224 return SPI_DBUS_RETURN_ERROR (message, &error);
227 atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
228 &intstart_offset, &intend_offset);
229 startOffset = intstart_offset;
230 endOffset = intend_offset;
233 reply = dbus_message_new_method_return (message);
236 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
237 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
238 &txt, DBUS_TYPE_INVALID);
245 impl_getCharacterAtOffset (DBusConnection * bus, DBusMessage * message,
248 AtkText *text = get_text (message);
255 return spi_dbus_general_error (message);
256 dbus_error_init (&error);
257 if (!dbus_message_get_args
258 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
260 return SPI_DBUS_RETURN_ERROR (message, &error);
262 ch = atk_text_get_character_at_offset (text, offset);
263 reply = dbus_message_new_method_return (message);
266 dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch, DBUS_TYPE_INVALID);
272 impl_getAttributeValue (DBusConnection * bus, DBusMessage * message,
275 AtkText *text = get_text (message);
278 dbus_int32_t startOffset, endOffset;
280 gint intstart_offset = 0, intend_offset = 0;
284 AtkAttributeSet *set;
289 return spi_dbus_general_error (message);
290 dbus_error_init (&error);
291 if (!dbus_message_get_args
292 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
293 &attributeName, DBUS_TYPE_INVALID))
295 return SPI_DBUS_RETURN_ERROR (message, &error);
298 set = atk_text_get_run_attributes (text, offset,
299 &intstart_offset, &intend_offset);
300 startOffset = intstart_offset;
301 endOffset = intend_offset;
303 cur_attr = (GSList *) set;
306 at = (AtkAttribute *) cur_attr->data;
307 if (!strcmp (at->name, attributeName))
313 cur_attr = cur_attr->next;
317 reply = dbus_message_new_method_return (message);
320 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
321 DBUS_TYPE_INT32, &endOffset,
322 DBUS_TYPE_BOOLEAN, &defined, DBUS_TYPE_STRING,
323 &rv, DBUS_TYPE_INVALID);
325 atk_attribute_set_free (set);
330 _string_from_attribute_set (AtkAttributeSet * set)
332 gchar *attributes, *tmp, *tmp2;
336 attributes = g_strdup ("");
337 cur_attr = (GSList *) set;
340 at = (AtkAttribute *) cur_attr->data;
341 tmp = g_strdup_printf ("%s%s:%s%s",
342 ((GSList *) (set) == cur_attr) ? "" : " ",
344 (cur_attr->next) ? ";" : "");
345 tmp2 = g_strconcat (attributes, tmp, NULL);
349 cur_attr = cur_attr->next;
355 impl_getAttributes (DBusConnection * bus, DBusMessage * message,
358 AtkText *text = get_text (message);
360 dbus_int32_t startOffset, endOffset;
361 gint intstart_offset, intend_offset;
365 AtkAttributeSet *set;
368 return spi_dbus_general_error (message);
369 dbus_error_init (&error);
370 if (!dbus_message_get_args
371 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
373 return SPI_DBUS_RETURN_ERROR (message, &error);
376 set = atk_text_get_run_attributes (text, offset,
377 &intstart_offset, &intend_offset);
379 rv = _string_from_attribute_set (set);
381 startOffset = intstart_offset;
382 endOffset = intend_offset;
383 reply = dbus_message_new_method_return (message);
386 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INT32, &startOffset,
387 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID);
389 atk_attribute_set_free (set);
395 impl_getDefaultAttributes (DBusConnection * bus, DBusMessage * message,
398 AtkText *text = get_text (message);
402 AtkAttributeSet *set;
405 return spi_dbus_general_error (message);
406 dbus_error_init (&error);
408 set = atk_text_get_default_attributes (text);
409 rv = _string_from_attribute_set (set);
410 reply = dbus_message_new_method_return (message);
413 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv,
417 atk_attribute_set_free (set);
422 impl_getCharacterExtents (DBusConnection * bus, DBusMessage * message,
425 AtkText *text = get_text (message);
427 dbus_int16_t coordType;
428 dbus_int32_t x, y, width, height;
429 gint ix = 0, iy = 0, iw = 0, ih = 0;
434 return spi_dbus_general_error (message);
435 dbus_error_init (&error);
436 if (!dbus_message_get_args
437 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INT16, &coordType,
440 return SPI_DBUS_RETURN_ERROR (message, &error);
442 atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
443 (AtkCoordType) coordType);
448 reply = dbus_message_new_method_return (message);
451 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
452 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
453 &height, DBUS_TYPE_INVALID);
459 impl_getOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
462 AtkText *text = get_text (message);
464 dbus_int16_t coordType;
470 return spi_dbus_general_error (message);
471 dbus_error_init (&error);
472 if (!dbus_message_get_args
473 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
474 DBUS_TYPE_INT16, &coordType, DBUS_TYPE_INVALID))
476 return SPI_DBUS_RETURN_ERROR (message, &error);
478 rv = atk_text_get_offset_at_point (text, x, y, coordType);
479 reply = dbus_message_new_method_return (message);
482 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
489 impl_getNSelections (DBusConnection * bus, DBusMessage * message,
492 AtkText *text = get_text (message);
497 return spi_dbus_general_error (message);
498 rv = atk_text_get_n_selections (text);
499 reply = dbus_message_new_method_return (message);
502 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
509 impl_getSelection (DBusConnection * bus, DBusMessage * message,
512 AtkText *text = get_text (message);
513 dbus_int32_t selectionNum;
514 dbus_int32_t startOffset, endOffset;
515 gint intstart_offset = 0, intend_offset = 0;
520 return spi_dbus_general_error (message);
521 dbus_error_init (&error);
522 if (!dbus_message_get_args
523 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
525 return SPI_DBUS_RETURN_ERROR (message, &error);
527 /* atk_text_get_selection returns gchar * which we discard */
528 g_free (atk_text_get_selection
529 (text, selectionNum, &intstart_offset, &intend_offset));
530 startOffset = intstart_offset;
531 endOffset = intend_offset;
532 reply = dbus_message_new_method_return (message);
535 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
536 DBUS_TYPE_INT32, &endOffset,
543 impl_addSelection (DBusConnection * bus, DBusMessage * message,
546 AtkText *text = get_text (message);
547 dbus_int32_t startOffset, endOffset;
553 return spi_dbus_general_error (message);
554 dbus_error_init (&error);
555 if (!dbus_message_get_args
556 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
557 &endOffset, DBUS_TYPE_INVALID))
559 return SPI_DBUS_RETURN_ERROR (message, &error);
561 rv = atk_text_add_selection (text, startOffset, endOffset);
562 reply = dbus_message_new_method_return (message);
565 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
572 impl_removeSelection (DBusConnection * bus, DBusMessage * message,
575 AtkText *text = get_text (message);
576 dbus_int32_t selectionNum;
582 return spi_dbus_general_error (message);
583 dbus_error_init (&error);
584 if (!dbus_message_get_args
585 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
587 return SPI_DBUS_RETURN_ERROR (message, &error);
589 rv = atk_text_remove_selection (text, selectionNum);
590 reply = dbus_message_new_method_return (message);
593 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
600 impl_setSelection (DBusConnection * bus, DBusMessage * message,
603 AtkText *text = get_text (message);
604 dbus_int32_t selectionNum, startOffset, endOffset;
610 return spi_dbus_general_error (message);
611 dbus_error_init (&error);
612 if (!dbus_message_get_args
613 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
614 &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
616 return SPI_DBUS_RETURN_ERROR (message, &error);
618 rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
619 reply = dbus_message_new_method_return (message);
622 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
629 impl_getRangeExtents (DBusConnection * bus, DBusMessage * message,
632 AtkText *text = get_text (message);
633 dbus_int32_t startOffset, endOffset;
634 dbus_int16_t coordType;
635 AtkTextRectangle rect;
636 dbus_int32_t x, y, width, height;
641 return spi_dbus_general_error (message);
642 dbus_error_init (&error);
643 if (!dbus_message_get_args
644 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
645 &endOffset, DBUS_TYPE_INT16, &coordType, DBUS_TYPE_INVALID))
647 return SPI_DBUS_RETURN_ERROR (message, &error);
649 memset (&rect, 0, sizeof (rect));
650 atk_text_get_range_extents (text, startOffset, endOffset,
651 (AtkCoordType) coordType, &rect);
655 height = rect.height;
656 reply = dbus_message_new_method_return (message);
659 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
660 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
661 &height, DBUS_TYPE_INVALID);
666 #define MAXRANGELEN 512
669 impl_getBoundedRanges (DBusConnection * bus, DBusMessage * message,
672 AtkText *text = get_text (message);
673 dbus_int32_t x, y, width, height;
674 dbus_int16_t coordType, xClipType, yClipType;
676 AtkTextRange **range_list = NULL;
677 AtkTextRectangle rect;
679 DBusMessageIter iter, array, struc, variant;
682 return spi_dbus_general_error (message);
683 dbus_error_init (&error);
684 if (!dbus_message_get_args
685 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
686 DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
687 &coordType, DBUS_TYPE_INT32, &xClipType, DBUS_TYPE_INT32, &yClipType,
690 return SPI_DBUS_RETURN_ERROR (message, &error);
695 rect.height = height;
698 atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
699 (AtkTextClipType) xClipType,
700 (AtkTextClipType) yClipType);
701 reply = dbus_message_new_method_return (message);
704 /* This isn't pleasant. */
705 dbus_message_iter_init_append (reply, &iter);
706 if (dbus_message_iter_open_container
707 (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
710 for (len = 0; len < MAXRANGELEN && range_list[len]; ++len)
712 if (dbus_message_iter_open_container
713 (&array, DBUS_TYPE_STRUCT, NULL, &struc))
716 val = range_list[len]->start_offset;
717 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
718 val = range_list[len]->end_offset;
719 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
720 dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
721 &range_list[len]->content);
722 /* The variant is unimplemented in atk, but I don't want to
723 * unilaterally muck with the spec and remove it, so I'll just
724 * throw in a dummy value */
725 if (dbus_message_iter_open_container
726 (&array, DBUS_TYPE_VARIANT, "i", &variant))
728 dbus_uint32_t dummy = 0;
729 dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
731 dbus_message_iter_close_container (&struc, &variant);
733 dbus_message_iter_close_container (&array, &struc);
736 dbus_message_iter_close_container (&iter, &array);
742 impl_getAttributeRun (DBusConnection * bus, DBusMessage * message,
746 AtkText *text = get_text (message);
748 dbus_bool_t includeDefaults;
749 dbus_int32_t startOffset, endOffset;
750 gint intstart_offset = 0, intend_offset = 0;
752 AtkAttributeSet *attributes, *default_attributes = NULL;
753 AtkAttribute *attr = NULL;
755 gint n_attributes = 0, total_attributes = 0, n_default_attributes = 0;
759 return spi_dbus_general_error (message);
760 dbus_error_init (&error);
761 if (!dbus_message_get_args
762 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
763 &includeDefaults, DBUS_TYPE_INVALID))
765 return SPI_DBUS_RETURN_ERROR (message, &error);
769 atk_text_get_run_attributes (text, offset, &intstart_offset,
773 total_attributes = n_attributes = g_slist_length (attributes);
777 default_attributes = atk_text_get_default_attributes (text);
778 if (default_attributes)
779 n_default_attributes = g_slist_length (default_attributes);
780 total_attributes += n_default_attributes;
783 startOffset = intstart_offset;
784 endOffset = intend_offset;
786 retval = (char **) g_malloc (total_attributes * sizeof (char *));
788 if (total_attributes)
790 for (i = 0; i < n_attributes; ++i)
792 attr = g_slist_nth_data (attributes, i);
793 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
796 for (j = 0; j < n_default_attributes; ++i, ++j)
798 attr = g_slist_nth_data (default_attributes, j);
799 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
802 atk_attribute_set_free (attributes);
803 if (default_attributes)
804 atk_attribute_set_free (default_attributes);
806 reply = dbus_message_new_method_return (message);
809 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
810 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_ARRAY,
811 DBUS_TYPE_STRING, &retval, total_attributes,
814 for (i = 0; i < total_attributes; i++)
821 impl_getDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
824 AtkText *text = get_text (message);
826 AtkAttributeSet *attributes;
827 AtkAttribute *attr = NULL;
829 gint n_attributes = 0;
833 return spi_dbus_general_error (message);
835 attributes = atk_text_get_default_attributes (text);
837 n_attributes = g_slist_length (attributes);
839 retval = g_new (char *, n_attributes);
841 for (i = 0; i < n_attributes; ++i)
843 attr = g_slist_nth_data (attributes, i);
844 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
847 atk_attribute_set_free (attributes);
848 reply = dbus_message_new_method_return (message);
851 dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
852 &retval, n_attributes, DBUS_TYPE_INVALID);
854 for (i = 0; i < n_attributes; i++)
860 static DRouteMethod methods[] = {
861 {impl_getText, "getText"},
862 {impl_setCaretOffset, "setCaretOffset"},
863 {impl_getTextBeforeOffset, "getTextBeforeOffset"},
864 {impl_getTextAtOffset, "getTextAtOffset"},
865 {impl_getTextAfterOffset, "getTextAfterOffset"},
866 {impl_getCharacterAtOffset, "getCharacterAtOffset"},
867 {impl_getAttributeValue, "getAttributeValue"},
868 {impl_getAttributes, "getAttributes"},
869 {impl_getDefaultAttributes, "getDefaultAttributes"},
870 {impl_getCharacterExtents, "getCharacterExtents"},
871 {impl_getOffsetAtPoint, "getOffsetAtPoint"},
872 {impl_getNSelections, "getNSelections"},
873 {impl_getSelection, "getSelection"},
874 {impl_addSelection, "addSelection"},
875 {impl_removeSelection, "removeSelection"},
876 {impl_setSelection, "setSelection"},
877 {impl_getRangeExtents, "getRangeExtents"},
878 {impl_getBoundedRanges, "getBoundedRanges"},
879 {impl_getAttributeRun, "getAttributeRun"},
880 {impl_getDefaultAttributeSet, "getDefaultAttributeSet"},
884 static DRouteProperty properties[] = {
885 {impl_get_characterCount, NULL, "characterCount"},
886 {impl_get_caretOffset, NULL, "caretOffset"},
891 spi_initialize_text (DRouteData * data)
893 droute_add_interface (data, SPI_DBUS_INTERFACE_TEXT, methods,
895 (DRouteGetDatumFunction) get_text_from_path, NULL);