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 = spi_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 = spi_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);
378 startOffset = intstart_offset;
379 endOffset = intend_offset;
380 rv = _string_from_attribute_set (set);
381 reply = dbus_message_new_method_return (message);
384 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
385 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
386 &rv, DBUS_TYPE_INVALID);
389 atk_attribute_set_free (set);
394 impl_getDefaultAttributes (DBusConnection * bus, DBusMessage * message,
397 AtkText *text = get_text (message);
401 AtkAttributeSet *set;
404 return spi_dbus_general_error (message);
405 dbus_error_init (&error);
407 set = atk_text_get_default_attributes (text);
408 rv = _string_from_attribute_set (set);
409 reply = dbus_message_new_method_return (message);
412 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv,
416 atk_attribute_set_free (set);
421 impl_getCharacterExtents (DBusConnection * bus, DBusMessage * message,
424 AtkText *text = get_text (message);
426 dbus_uint32_t coordType;
427 dbus_int32_t x, y, width, height;
428 gint ix = 0, iy = 0, iw = 0, ih = 0;
433 return spi_dbus_general_error (message);
434 dbus_error_init (&error);
435 if (!dbus_message_get_args
436 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INT32, &coordType,
439 return SPI_DBUS_RETURN_ERROR (message, &error);
441 atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
442 (AtkCoordType) coordType);
447 reply = dbus_message_new_method_return (message);
450 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
451 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
452 &height, DBUS_TYPE_INVALID);
458 impl_getOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
461 AtkText *text = get_text (message);
463 dbus_uint32_t coordType;
469 return spi_dbus_general_error (message);
470 dbus_error_init (&error);
471 if (!dbus_message_get_args
472 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
473 DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
475 return SPI_DBUS_RETURN_ERROR (message, &error);
477 rv = atk_text_get_offset_at_point (text, x, y, coordType);
478 reply = dbus_message_new_method_return (message);
481 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
488 impl_getNSelections (DBusConnection * bus, DBusMessage * message,
491 AtkText *text = get_text (message);
496 return spi_dbus_general_error (message);
497 rv = atk_text_get_n_selections (text);
498 reply = dbus_message_new_method_return (message);
501 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
508 impl_getSelection (DBusConnection * bus, DBusMessage * message,
511 AtkText *text = get_text (message);
512 dbus_int32_t selectionNum;
513 dbus_int32_t startOffset, endOffset;
514 gint intstart_offset = 0, intend_offset = 0;
519 return spi_dbus_general_error (message);
520 dbus_error_init (&error);
521 if (!dbus_message_get_args
522 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
524 return SPI_DBUS_RETURN_ERROR (message, &error);
526 /* atk_text_get_selection returns gchar * which we discard */
527 g_free (atk_text_get_selection
528 (text, selectionNum, &intstart_offset, &intend_offset));
529 startOffset = intstart_offset;
530 endOffset = intend_offset;
531 reply = dbus_message_new_method_return (message);
534 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
535 DBUS_TYPE_INT32, &endOffset,
542 impl_addSelection (DBusConnection * bus, DBusMessage * message,
545 AtkText *text = get_text (message);
546 dbus_int32_t startOffset, endOffset;
552 return spi_dbus_general_error (message);
553 dbus_error_init (&error);
554 if (!dbus_message_get_args
555 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
556 &endOffset, DBUS_TYPE_INVALID))
558 return SPI_DBUS_RETURN_ERROR (message, &error);
560 rv = atk_text_add_selection (text, startOffset, endOffset);
561 reply = dbus_message_new_method_return (message);
564 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
571 impl_removeSelection (DBusConnection * bus, DBusMessage * message,
574 AtkText *text = get_text (message);
575 dbus_int32_t selectionNum;
581 return spi_dbus_general_error (message);
582 dbus_error_init (&error);
583 if (!dbus_message_get_args
584 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
586 return SPI_DBUS_RETURN_ERROR (message, &error);
588 rv = atk_text_remove_selection (text, selectionNum);
589 reply = dbus_message_new_method_return (message);
592 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
599 impl_setSelection (DBusConnection * bus, DBusMessage * message,
602 AtkText *text = get_text (message);
603 dbus_int32_t selectionNum, startOffset, endOffset;
609 return spi_dbus_general_error (message);
610 dbus_error_init (&error);
611 if (!dbus_message_get_args
612 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
613 &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
615 return SPI_DBUS_RETURN_ERROR (message, &error);
617 rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
618 reply = dbus_message_new_method_return (message);
621 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
628 impl_getRangeExtents (DBusConnection * bus, DBusMessage * message,
631 AtkText *text = get_text (message);
632 dbus_int32_t startOffset, endOffset;
633 dbus_uint32_t coordType;
634 AtkTextRectangle rect;
635 dbus_int32_t x, y, width, height;
640 return spi_dbus_general_error (message);
641 dbus_error_init (&error);
642 if (!dbus_message_get_args
643 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
644 &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
646 return SPI_DBUS_RETURN_ERROR (message, &error);
648 memset (&rect, 0, sizeof (rect));
649 atk_text_get_range_extents (text, startOffset, endOffset,
650 (AtkCoordType) coordType, &rect);
654 height = rect.height;
655 reply = dbus_message_new_method_return (message);
658 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
659 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
660 &height, DBUS_TYPE_INVALID);
665 #define MAXRANGELEN 512
668 impl_getBoundedRanges (DBusConnection * bus, DBusMessage * message,
671 AtkText *text = get_text (message);
672 dbus_int32_t x, y, width, height;
673 dbus_uint32_t coordType, xClipType, yClipType;
675 AtkTextRange **range_list = NULL;
676 AtkTextRectangle rect;
678 DBusMessageIter iter, array, struc, variant;
681 return spi_dbus_general_error (message);
682 dbus_error_init (&error);
683 if (!dbus_message_get_args
684 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
685 DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
686 &coordType, DBUS_TYPE_INT32, &xClipType, DBUS_TYPE_INT32, &yClipType,
689 return SPI_DBUS_RETURN_ERROR (message, &error);
694 rect.height = height;
697 atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
698 (AtkTextClipType) xClipType,
699 (AtkTextClipType) yClipType);
700 reply = dbus_message_new_method_return (message);
703 /* This isn't pleasant. */
704 dbus_message_iter_init_append (reply, &iter);
705 if (dbus_message_iter_open_container
706 (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
709 for (len = 0; len < MAXRANGELEN && range_list[len]; ++len)
711 if (dbus_message_iter_open_container
712 (&array, DBUS_TYPE_STRUCT, NULL, &struc))
715 val = range_list[len]->start_offset;
716 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
717 val = range_list[len]->end_offset;
718 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
719 dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
720 &range_list[len]->content);
721 /* The variant is unimplemented in atk, but I don't want to
722 * unilaterally muck with the spec and remove it, so I'll just
723 * throw in a dummy value */
724 if (dbus_message_iter_open_container
725 (&array, DBUS_TYPE_VARIANT, "i", &variant))
727 dbus_uint32_t dummy = 0;
728 dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
730 dbus_message_iter_close_container (&struc, &variant);
732 dbus_message_iter_close_container (&array, &struc);
735 dbus_message_iter_close_container (&iter, &array);
741 impl_getAttributeRun (DBusConnection * bus, DBusMessage * message,
745 AtkText *text = get_text (message);
747 dbus_bool_t includeDefaults;
748 dbus_int32_t startOffset, endOffset;
749 gint intstart_offset = 0, intend_offset = 0;
751 AtkAttributeSet *attributes, *default_attributes = NULL;
752 AtkAttribute *attr = NULL;
754 gint n_attributes = 0, total_attributes = 0, n_default_attributes = 0;
758 return spi_dbus_general_error (message);
759 dbus_error_init (&error);
760 if (!dbus_message_get_args
761 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
762 &includeDefaults, DBUS_TYPE_INVALID))
764 return SPI_DBUS_RETURN_ERROR (message, &error);
768 atk_text_get_run_attributes (text, offset, &intstart_offset,
772 total_attributes = n_attributes = g_slist_length (attributes);
776 default_attributes = atk_text_get_default_attributes (text);
777 if (default_attributes)
778 n_default_attributes = g_slist_length (default_attributes);
779 total_attributes += n_default_attributes;
782 startOffset = intstart_offset;
783 endOffset = intend_offset;
785 retval = (char **) g_malloc (total_attributes * sizeof (char *));
787 if (total_attributes)
789 for (i = 0; i < n_attributes; ++i)
791 attr = g_slist_nth_data (attributes, i);
792 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
795 for (j = 0; j < n_default_attributes; ++i, ++j)
797 attr = g_slist_nth_data (default_attributes, j);
798 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
801 atk_attribute_set_free (attributes);
802 if (default_attributes)
803 atk_attribute_set_free (default_attributes);
805 reply = dbus_message_new_method_return (message);
808 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
809 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_ARRAY,
810 DBUS_TYPE_STRING, &retval, total_attributes,
813 for (i = 0; i < total_attributes; i++)
820 impl_getDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
823 AtkText *text = get_text (message);
825 AtkAttributeSet *attributes;
826 AtkAttribute *attr = NULL;
828 gint n_attributes = 0;
832 return spi_dbus_general_error (message);
834 attributes = atk_text_get_default_attributes (text);
836 n_attributes = g_slist_length (attributes);
838 retval = g_new (char *, n_attributes);
840 for (i = 0; i < n_attributes; ++i)
842 attr = g_slist_nth_data (attributes, i);
843 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
846 atk_attribute_set_free (attributes);
847 reply = dbus_message_new_method_return (message);
850 dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
851 &retval, n_attributes, DBUS_TYPE_INVALID);
853 for (i = 0; i < n_attributes; i++)
859 static DRouteMethod methods[] = {
860 {impl_getText, "getText"},
861 {impl_setCaretOffset, "setCaretOffset"},
862 {impl_getTextBeforeOffset, "getTextBeforeOffset"},
863 {impl_getTextAtOffset, "getTextAtOffset"},
864 {impl_getTextAfterOffset, "getTextAfterOffset"},
865 {impl_getCharacterAtOffset, "getCharacterAtOffset"},
866 {impl_getAttributeValue, "getAttributeValue"},
867 {impl_getAttributes, "getAttributes"},
868 {impl_getDefaultAttributes, "getDefaultAttributes"},
869 {impl_getCharacterExtents, "getCharacterExtents"},
870 {impl_getOffsetAtPoint, "getOffsetAtPoint"},
871 {impl_getNSelections, "getNSelections"},
872 {impl_getSelection, "getSelection"},
873 {impl_addSelection, "addSelection"},
874 {impl_removeSelection, "removeSelection"},
875 {impl_setSelection, "setSelection"},
876 {impl_getRangeExtents, "getRangeExtents"},
877 {impl_getBoundedRanges, "getBoundedRanges"},
878 {impl_getAttributeRun, "getAttributeRun"},
879 {impl_getDefaultAttributeSet, "getDefaultAttributeSet"},
883 static DRouteProperty properties[] = {
884 {impl_get_characterCount, NULL, "characterCount"},
885 {impl_get_caretOffset, NULL, "caretOffset"},
890 spi_initialize_text (DRouteData * data)
892 droute_add_interface (data, SPI_DBUS_INTERFACE_TEXT, methods,
894 (DRouteGetDatumFunction) get_text_from_path, NULL);