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_getAttributeValue (DBusConnection * bus, DBusMessage * message,
248 AtkText *text = get_text (message);
251 dbus_int32_t startOffset, endOffset;
253 gint intstart_offset = 0, intend_offset = 0;
257 AtkAttributeSet *set;
262 return spi_dbus_general_error (message);
263 dbus_error_init (&error);
264 if (!dbus_message_get_args
265 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
266 &attributeName, DBUS_TYPE_INVALID))
268 return SPI_DBUS_RETURN_ERROR (message, &error);
271 set = atk_text_get_run_attributes (text, offset,
272 &intstart_offset, &intend_offset);
273 startOffset = intstart_offset;
274 endOffset = intend_offset;
276 cur_attr = (GSList *) set;
279 at = (AtkAttribute *) cur_attr->data;
280 if (!strcmp (at->name, attributeName))
286 cur_attr = cur_attr->next;
290 reply = dbus_message_new_method_return (message);
293 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
294 DBUS_TYPE_INT32, &endOffset,
295 DBUS_TYPE_BOOLEAN, &defined, DBUS_TYPE_STRING,
296 &rv, DBUS_TYPE_INVALID);
298 atk_attribute_set_free (set);
303 _string_from_attribute_set (AtkAttributeSet * set)
305 gchar *attributes, *tmp, *tmp2;
309 attributes = g_strdup ("");
310 cur_attr = (GSList *) set;
313 at = (AtkAttribute *) cur_attr->data;
314 tmp = g_strdup_printf ("%s%s:%s%s",
315 ((GSList *) (set) == cur_attr) ? "" : " ",
317 (cur_attr->next) ? ";" : "");
318 tmp2 = g_strconcat (attributes, tmp, NULL);
322 cur_attr = cur_attr->next;
328 impl_getAttributes (DBusConnection * bus, DBusMessage * message,
331 AtkText *text = get_text (message);
333 dbus_int32_t startOffset, endOffset;
334 gint intstart_offset, intend_offset;
338 AtkAttributeSet *set;
341 return spi_dbus_general_error (message);
342 dbus_error_init (&error);
343 if (!dbus_message_get_args
344 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
346 return SPI_DBUS_RETURN_ERROR (message, &error);
349 set = atk_text_get_run_attributes (text, offset,
350 &intstart_offset, &intend_offset);
351 startOffset = intstart_offset;
352 endOffset = intend_offset;
353 rv = _string_from_attribute_set (set);
354 reply = dbus_message_new_method_return (message);
357 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
358 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
359 &rv, DBUS_TYPE_INVALID);
362 atk_attribute_set_free (set);
367 impl_getDefaultAttributes (DBusConnection * bus, DBusMessage * message,
370 AtkText *text = get_text (message);
374 AtkAttributeSet *set;
377 return spi_dbus_general_error (message);
378 dbus_error_init (&error);
380 set = atk_text_get_default_attributes (text);
381 rv = _string_from_attribute_set (set);
382 reply = dbus_message_new_method_return (message);
385 dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv,
389 atk_attribute_set_free (set);
394 impl_getCharacterExtents (DBusConnection * bus, DBusMessage * message,
397 AtkText *text = get_text (message);
399 dbus_uint32_t coordType;
400 dbus_int32_t x, y, width, height;
401 gint ix = 0, iy = 0, iw = 0, ih = 0;
406 return spi_dbus_general_error (message);
407 dbus_error_init (&error);
408 if (!dbus_message_get_args
409 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INT32, &coordType,
412 return SPI_DBUS_RETURN_ERROR (message, &error);
414 atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
415 (AtkCoordType) coordType);
420 reply = dbus_message_new_method_return (message);
423 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
424 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
425 &height, DBUS_TYPE_INVALID);
431 impl_getOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
434 AtkText *text = get_text (message);
436 dbus_uint32_t coordType;
442 return spi_dbus_general_error (message);
443 dbus_error_init (&error);
444 if (!dbus_message_get_args
445 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
446 DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
448 return SPI_DBUS_RETURN_ERROR (message, &error);
450 rv = atk_text_get_offset_at_point (text, x, y, coordType);
451 reply = dbus_message_new_method_return (message);
454 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
461 impl_getNSelections (DBusConnection * bus, DBusMessage * message,
464 AtkText *text = get_text (message);
469 return spi_dbus_general_error (message);
470 rv = atk_text_get_n_selections (text);
471 reply = dbus_message_new_method_return (message);
474 dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
481 impl_getSelection (DBusConnection * bus, DBusMessage * message,
484 AtkText *text = get_text (message);
485 dbus_int32_t selectionNum;
486 dbus_int32_t startOffset, endOffset;
487 gint intstart_offset = 0, intend_offset = 0;
492 return spi_dbus_general_error (message);
493 dbus_error_init (&error);
494 if (!dbus_message_get_args
495 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
497 return SPI_DBUS_RETURN_ERROR (message, &error);
499 /* atk_text_get_selection returns gchar * which we discard */
500 g_free (atk_text_get_selection
501 (text, selectionNum, &intstart_offset, &intend_offset));
502 startOffset = intstart_offset;
503 endOffset = intend_offset;
504 reply = dbus_message_new_method_return (message);
507 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
508 DBUS_TYPE_INT32, &endOffset,
515 impl_addSelection (DBusConnection * bus, DBusMessage * message,
518 AtkText *text = get_text (message);
519 dbus_int32_t startOffset, endOffset;
525 return spi_dbus_general_error (message);
526 dbus_error_init (&error);
527 if (!dbus_message_get_args
528 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
529 &endOffset, DBUS_TYPE_INVALID))
531 return SPI_DBUS_RETURN_ERROR (message, &error);
533 rv = atk_text_add_selection (text, startOffset, endOffset);
534 reply = dbus_message_new_method_return (message);
537 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
544 impl_removeSelection (DBusConnection * bus, DBusMessage * message,
547 AtkText *text = get_text (message);
548 dbus_int32_t selectionNum;
554 return spi_dbus_general_error (message);
555 dbus_error_init (&error);
556 if (!dbus_message_get_args
557 (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
559 return SPI_DBUS_RETURN_ERROR (message, &error);
561 rv = atk_text_remove_selection (text, selectionNum);
562 reply = dbus_message_new_method_return (message);
565 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
572 impl_setSelection (DBusConnection * bus, DBusMessage * message,
575 AtkText *text = get_text (message);
576 dbus_int32_t selectionNum, startOffset, endOffset;
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_INT32,
586 &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
588 return SPI_DBUS_RETURN_ERROR (message, &error);
590 rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
591 reply = dbus_message_new_method_return (message);
594 dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
601 impl_getRangeExtents (DBusConnection * bus, DBusMessage * message,
604 AtkText *text = get_text (message);
605 dbus_int32_t startOffset, endOffset;
606 dbus_uint32_t coordType;
607 AtkTextRectangle rect;
608 dbus_int32_t x, y, width, height;
613 return spi_dbus_general_error (message);
614 dbus_error_init (&error);
615 if (!dbus_message_get_args
616 (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
617 &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
619 return SPI_DBUS_RETURN_ERROR (message, &error);
621 memset (&rect, 0, sizeof (rect));
622 atk_text_get_range_extents (text, startOffset, endOffset,
623 (AtkCoordType) coordType, &rect);
627 height = rect.height;
628 reply = dbus_message_new_method_return (message);
631 dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
632 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
633 &height, DBUS_TYPE_INVALID);
638 #define MAXRANGELEN 512
641 impl_getBoundedRanges (DBusConnection * bus, DBusMessage * message,
644 AtkText *text = get_text (message);
645 dbus_int32_t x, y, width, height;
646 dbus_uint32_t coordType, xClipType, yClipType;
648 AtkTextRange **range_list = NULL;
649 AtkTextRectangle rect;
651 DBusMessageIter iter, array, struc, variant;
654 return spi_dbus_general_error (message);
655 dbus_error_init (&error);
656 if (!dbus_message_get_args
657 (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
658 DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
659 &coordType, DBUS_TYPE_INT32, &xClipType, DBUS_TYPE_INT32, &yClipType,
662 return SPI_DBUS_RETURN_ERROR (message, &error);
667 rect.height = height;
670 atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
671 (AtkTextClipType) xClipType,
672 (AtkTextClipType) yClipType);
673 reply = dbus_message_new_method_return (message);
676 /* This isn't pleasant. */
677 dbus_message_iter_init_append (reply, &iter);
678 if (dbus_message_iter_open_container
679 (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
682 for (len = 0; len < MAXRANGELEN && range_list[len]; ++len)
684 if (dbus_message_iter_open_container
685 (&array, DBUS_TYPE_STRUCT, NULL, &struc))
688 val = range_list[len]->start_offset;
689 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
690 val = range_list[len]->end_offset;
691 dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
692 dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
693 &range_list[len]->content);
694 /* The variant is unimplemented in atk, but I don't want to
695 * unilaterally muck with the spec and remove it, so I'll just
696 * throw in a dummy value */
697 if (dbus_message_iter_open_container
698 (&array, DBUS_TYPE_VARIANT, "i", &variant))
700 dbus_uint32_t dummy = 0;
701 dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
703 dbus_message_iter_close_container (&struc, &variant);
705 dbus_message_iter_close_container (&array, &struc);
708 dbus_message_iter_close_container (&iter, &array);
714 impl_getAttributeRun (DBusConnection * bus, DBusMessage * message,
718 AtkText *text = get_text (message);
720 dbus_bool_t includeDefaults;
721 dbus_int32_t startOffset, endOffset;
722 gint intstart_offset = 0, intend_offset = 0;
724 AtkAttributeSet *attributes, *default_attributes = NULL;
725 AtkAttribute *attr = NULL;
727 gint n_attributes = 0, total_attributes = 0, n_default_attributes = 0;
731 return spi_dbus_general_error (message);
732 dbus_error_init (&error);
733 if (!dbus_message_get_args
734 (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
735 &includeDefaults, DBUS_TYPE_INVALID))
737 return SPI_DBUS_RETURN_ERROR (message, &error);
741 atk_text_get_run_attributes (text, offset, &intstart_offset,
745 total_attributes = n_attributes = g_slist_length (attributes);
749 default_attributes = atk_text_get_default_attributes (text);
750 if (default_attributes)
751 n_default_attributes = g_slist_length (default_attributes);
752 total_attributes += n_default_attributes;
755 startOffset = intstart_offset;
756 endOffset = intend_offset;
758 retval = (char **) g_malloc (total_attributes * sizeof (char *));
760 if (total_attributes)
762 for (i = 0; i < n_attributes; ++i)
764 attr = g_slist_nth_data (attributes, i);
765 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
768 for (j = 0; j < n_default_attributes; ++i, ++j)
770 attr = g_slist_nth_data (default_attributes, j);
771 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
774 atk_attribute_set_free (attributes);
775 if (default_attributes)
776 atk_attribute_set_free (default_attributes);
778 reply = dbus_message_new_method_return (message);
781 dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
782 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_ARRAY,
783 DBUS_TYPE_STRING, &retval, total_attributes,
786 for (i = 0; i < total_attributes; i++)
793 impl_getDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
796 AtkText *text = get_text (message);
798 AtkAttributeSet *attributes;
799 AtkAttribute *attr = NULL;
801 gint n_attributes = 0;
805 return spi_dbus_general_error (message);
807 attributes = atk_text_get_default_attributes (text);
809 n_attributes = g_slist_length (attributes);
811 retval = (char **) malloc (n_attributes * sizeof (char *));
813 for (i = 0; i < n_attributes; ++i)
815 attr = g_slist_nth_data (attributes, i);
816 retval[i] = g_strconcat (attr->name, ":", attr->value, NULL);
819 atk_attribute_set_free (attributes);
820 reply = dbus_message_new_method_return (message);
823 dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
824 &retval, n_attributes, DBUS_TYPE_INVALID);
826 for (i = 0; i < n_attributes; i++)
832 static DRouteMethod methods[] = {
833 {impl_getText, "getText"},
834 {impl_setCaretOffset, "setCaretOffset"},
835 {impl_getTextBeforeOffset, "getTextBeforeOffset"},
836 {impl_getTextAtOffset, "getTextAtOffset"},
837 {impl_getTextAfterOffset, "getTextAfterOffset"},
838 {impl_getAttributeValue, "getAttributeValue"},
839 {impl_getAttributes, "getAttributes"},
840 {impl_getDefaultAttributes, "getDefaultAttributes"},
841 {impl_getCharacterExtents, "getCharacterExtents"},
842 {impl_getOffsetAtPoint, "getOffsetAtPoint"},
843 {impl_getNSelections, "getNSelections"},
844 {impl_getSelection, "getSelection"},
845 {impl_addSelection, "addSelection"},
846 {impl_removeSelection, "removeSelection"},
847 {impl_setSelection, "setSelection"},
848 {impl_getRangeExtents, "getRangeExtents"},
849 {impl_getBoundedRanges, "getBoundedRanges"},
850 {impl_getAttributeRun, "getAttributeRun"},
851 {impl_getDefaultAttributeSet, "getDefaultAttributeSet"},
855 static DRouteProperty properties[] = {
856 {impl_get_characterCount, NULL, "characterCount"},
857 {impl_get_caretOffset, NULL, "caretOffset"},
862 spi_initialize_text (DRouteData * data)
864 droute_add_interface (data, "org.freedesktop.atspi.Text", methods,
866 (DRouteGetDatumFunction) get_text_from_path, NULL);