2009-27-09 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / text-adaptor.c
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 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.
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  * Library General Public License for more details.
18  *
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.
23  */
24
25 #include <string.h>
26
27 #include <atk/atk.h>
28 #include <droute/droute.h>
29
30 #include "common/spi-dbus.h"
31
32 #include "accessible-marshaller.h"
33
34 static dbus_bool_t
35 impl_get_characterCount (DBusMessageIter * iter,
36                          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
44 impl_get_caretOffset (DBusMessageIter * iter,
45                       void *user_data)
46 {
47   AtkText *text = (AtkText *) user_data;
48   g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
49   return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
50 }
51
52 static DBusMessage *
53 impl_getText (DBusConnection * bus, DBusMessage * message, void *user_data)
54 {
55   AtkText *text = (AtkText *) user_data;
56   dbus_int32_t startOffset, endOffset;
57   gchar *txt;
58   DBusError error;
59   DBusMessage *reply;
60
61   g_return_val_if_fail (ATK_IS_TEXT (user_data),
62                         droute_not_yet_handled_error (message));
63   dbus_error_init (&error);
64   if (!dbus_message_get_args
65       (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
66        &endOffset, DBUS_TYPE_INVALID))
67     {
68       return droute_invalid_arguments_error (message);
69     }
70   txt = atk_text_get_text (text, startOffset, endOffset);
71   if (!txt)
72     txt = g_strdup ("");
73   reply = dbus_message_new_method_return (message);
74   if (reply)
75     {
76       dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
77                                 DBUS_TYPE_INVALID);
78     }
79   g_free (txt);
80   return reply;
81 }
82
83 static DBusMessage *
84 impl_setCaretOffset (DBusConnection * bus, DBusMessage * message,
85                      void *user_data)
86 {
87   AtkText *text = (AtkText *) user_data;
88   dbus_int32_t offset;
89   dbus_bool_t rv;
90   DBusError error;
91   DBusMessage *reply;
92
93   g_return_val_if_fail (ATK_IS_TEXT (user_data),
94                         droute_not_yet_handled_error (message));
95   dbus_error_init (&error);
96   if (!dbus_message_get_args
97       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
98     {
99       return droute_invalid_arguments_error (message);
100     }
101   rv = atk_text_set_caret_offset (text, offset);
102   reply = dbus_message_new_method_return (message);
103   if (reply)
104     {
105       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
106                                 DBUS_TYPE_INVALID);
107     }
108   return reply;
109 }
110
111 static DBusMessage *
112 impl_getTextBeforeOffset (DBusConnection * bus, DBusMessage * message,
113                           void *user_data)
114 {
115   AtkText *text = (AtkText *) user_data;
116   dbus_int32_t offset;
117   dbus_uint32_t type;
118   gchar *txt;
119   dbus_int32_t startOffset, endOffset;
120   gint intstart_offset = 0, intend_offset = 0;
121   DBusError error;
122   DBusMessage *reply;
123
124   g_return_val_if_fail (ATK_IS_TEXT (user_data),
125                         droute_not_yet_handled_error (message));
126   dbus_error_init (&error);
127   if (!dbus_message_get_args
128       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
129        DBUS_TYPE_INVALID))
130     {
131       return droute_invalid_arguments_error (message);
132     }
133   txt =
134     atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
135                                      &intstart_offset, &intend_offset);
136   startOffset = intstart_offset;
137   endOffset = intend_offset;
138   if (!txt)
139     txt = g_strdup ("");
140   reply = dbus_message_new_method_return (message);
141   if (reply)
142     {
143       dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt, DBUS_TYPE_INT32,
144                                 &startOffset, DBUS_TYPE_INT32, &endOffset,
145                                 DBUS_TYPE_INVALID);
146     }
147   g_free (txt);
148   return reply;
149 }
150
151 static DBusMessage *
152 impl_getTextAtOffset (DBusConnection * bus, DBusMessage * message,
153                       void *user_data)
154 {
155   AtkText *text = (AtkText *) user_data;
156   dbus_int32_t offset, type;
157   gchar *txt;
158   dbus_int32_t startOffset, endOffset;
159   gint intstart_offset = 0, intend_offset = 0;
160   DBusError error;
161   DBusMessage *reply;
162
163   g_return_val_if_fail (ATK_IS_TEXT (user_data),
164                         droute_not_yet_handled_error (message));
165   dbus_error_init (&error);
166   if (!dbus_message_get_args
167       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
168        DBUS_TYPE_INVALID))
169     {
170       return droute_invalid_arguments_error (message);
171     }
172   txt =
173     atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
174                                  &intstart_offset, &intend_offset);
175   startOffset = intstart_offset;
176   endOffset = intend_offset;
177   if (!txt)
178     txt = g_strdup ("");
179   reply = dbus_message_new_method_return (message);
180   if (reply)
181     {
182       dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt, DBUS_TYPE_INT32,
183                                 &startOffset, DBUS_TYPE_INT32, &endOffset,
184                                 DBUS_TYPE_INVALID);
185     }
186   g_free (txt);
187   return reply;
188 }
189
190 static DBusMessage *
191 impl_getTextAfterOffset (DBusConnection * bus, DBusMessage * message,
192                          void *user_data)
193 {
194   AtkText *text = (AtkText *) user_data;
195   dbus_int32_t offset;
196   dbus_uint32_t type;
197   gchar *txt;
198   dbus_int32_t startOffset, endOffset;
199   gint intstart_offset = 0, intend_offset = 0;
200   DBusError error;
201   DBusMessage *reply;
202
203   g_return_val_if_fail (ATK_IS_TEXT (user_data),
204                         droute_not_yet_handled_error (message));
205   dbus_error_init (&error);
206   if (!dbus_message_get_args
207       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
208        DBUS_TYPE_INVALID))
209     {
210       return droute_invalid_arguments_error (message);
211     }
212   txt =
213     atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
214                                     &intstart_offset, &intend_offset);
215   startOffset = intstart_offset;
216   endOffset = intend_offset;
217   if (!txt)
218     txt = g_strdup ("");
219   reply = dbus_message_new_method_return (message);
220   if (reply)
221     {
222       dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt, DBUS_TYPE_INT32,
223                                 &startOffset, DBUS_TYPE_INT32, &endOffset,
224                                 DBUS_TYPE_INVALID);
225     }
226   g_free (txt);
227   return reply;
228 }
229
230 static DBusMessage *
231 impl_getCharacterAtOffset (DBusConnection * bus, DBusMessage * message,
232                          void *user_data)
233 {
234   AtkText *text = (AtkText *) user_data;
235   dbus_int32_t offset;
236   dbus_int32_t ch;
237   DBusError error;
238   DBusMessage *reply;
239
240   g_return_val_if_fail (ATK_IS_TEXT (user_data),
241                         droute_not_yet_handled_error (message));
242   dbus_error_init (&error);
243   if (!dbus_message_get_args
244       (message, &error, 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, DBUS_TYPE_INVALID);
253     }
254   return reply;
255 }
256
257 static DBusMessage *
258 impl_getAttributeValue (DBusConnection * bus, DBusMessage * message,
259                         void *user_data)
260 {
261   AtkText *text = (AtkText *) user_data;
262   dbus_int32_t offset;
263   char *attributeName;
264   dbus_int32_t startOffset, endOffset;
265   dbus_bool_t defined;
266   gint intstart_offset = 0, intend_offset = 0;
267   char *rv = NULL;
268   DBusError error;
269   DBusMessage *reply;
270   AtkAttributeSet *set;
271   GSList *cur_attr;
272   AtkAttribute *at;
273
274   g_return_val_if_fail (ATK_IS_TEXT (user_data),
275                         droute_not_yet_handled_error (message));
276   dbus_error_init (&error);
277   if (!dbus_message_get_args
278       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
279        &attributeName, DBUS_TYPE_INVALID))
280     {
281       return droute_invalid_arguments_error (message);
282     }
283
284   set = atk_text_get_run_attributes (text, offset,
285                                      &intstart_offset, &intend_offset);
286   startOffset = intstart_offset;
287   endOffset = intend_offset;
288   defined = FALSE;
289   cur_attr = (GSList *) set;
290   while (cur_attr)
291     {
292       at = (AtkAttribute *) cur_attr->data;
293       if (!strcmp (at->name, attributeName))
294         {
295           rv = at->value;
296           defined = TRUE;
297           break;
298         }
299       cur_attr = cur_attr->next;
300     }
301   if (!rv)
302     rv = "";
303   reply = dbus_message_new_method_return (message);
304   if (reply)
305     {
306       dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INT32,
307                                 &startOffset, DBUS_TYPE_INT32, &endOffset,
308                                 DBUS_TYPE_BOOLEAN, &defined, DBUS_TYPE_INVALID);
309     }
310   atk_attribute_set_free (set);
311   return reply;
312 }
313
314 static char *
315 _string_from_attribute_set (AtkAttributeSet * set)
316 {
317   gchar *attributes, *tmp, *tmp2;
318   GSList *cur_attr;
319   AtkAttribute *at;
320
321   attributes = g_strdup ("");
322   cur_attr = (GSList *) set;
323   while (cur_attr)
324     {
325       at = (AtkAttribute *) cur_attr->data;
326       tmp = g_strdup_printf ("%s%s:%s%s",
327                              ((GSList *) (set) == cur_attr) ? "" : " ",
328                              at->name, at->value,
329                              (cur_attr->next) ? ";" : "");
330       tmp2 = g_strconcat (attributes, tmp, NULL);
331       g_free (tmp);
332       g_free (attributes);
333       attributes = tmp2;
334       cur_attr = cur_attr->next;
335     }
336   return attributes;
337 }
338
339 static DBusMessage *
340 impl_getAttributes (DBusConnection * bus, DBusMessage * message,
341                     void *user_data)
342 {
343   AtkText *text = (AtkText *) user_data;
344   dbus_int32_t offset;
345   dbus_int32_t startOffset, endOffset;
346   gint intstart_offset, intend_offset;
347   DBusError error;
348   DBusMessage *reply;
349   AtkAttributeSet *set;
350   DBusMessageIter iter;
351
352   g_return_val_if_fail (ATK_IS_TEXT (user_data),
353                         droute_not_yet_handled_error (message));
354   dbus_error_init (&error);
355   if (!dbus_message_get_args
356       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
357     {
358       return droute_invalid_arguments_error (message);
359     }
360
361   set = atk_text_get_run_attributes (text, offset,
362                                      &intstart_offset, &intend_offset);
363
364   startOffset = intstart_offset;
365   endOffset = intend_offset;
366   reply = dbus_message_new_method_return (message);
367   if (reply)
368     {
369       dbus_message_iter_init_append (reply, &iter);
370       spi_atk_append_attribute_set (&iter, set);
371       dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
372                                 DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID);
373     }
374   atk_attribute_set_free (set);
375   return reply;
376 }
377
378 static DBusMessage *
379 impl_getDefaultAttributes (DBusConnection * bus, DBusMessage * message,
380                            void *user_data)
381 {
382   AtkText *text = (AtkText *) user_data;
383   DBusError error;
384   DBusMessage *reply;
385   AtkAttributeSet *set;
386   DBusMessageIter iter;
387
388   g_return_val_if_fail (ATK_IS_TEXT (user_data),
389                         droute_not_yet_handled_error (message));
390   dbus_error_init (&error);
391
392   set = atk_text_get_default_attributes (text);
393   reply = dbus_message_new_method_return (message);
394   if (reply)
395     {
396       dbus_message_iter_init_append (reply, &iter);
397       spi_atk_append_attribute_set (&iter, set);
398     }
399   atk_attribute_set_free (set);
400   return reply;
401 }
402
403 static DBusMessage *
404 impl_getCharacterExtents (DBusConnection * bus, DBusMessage * message,
405                           void *user_data)
406 {
407   AtkText *text = (AtkText *) user_data;
408   dbus_int32_t offset;
409   dbus_uint32_t coordType;
410   dbus_int32_t x, y, width, height;
411   gint ix = 0, iy = 0, iw = 0, ih = 0;
412   DBusError error;
413   DBusMessage *reply;
414
415   g_return_val_if_fail (ATK_IS_TEXT (user_data),
416                         droute_not_yet_handled_error (message));
417   dbus_error_init (&error);
418   if (!dbus_message_get_args
419       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &coordType,
420        DBUS_TYPE_INVALID))
421     {
422       return droute_invalid_arguments_error (message);
423     }
424   atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
425                                   (AtkCoordType) coordType);
426   x = ix;
427   y = iy;
428   width = iw;
429   height = ih;
430   reply = dbus_message_new_method_return (message);
431   if (reply)
432     {
433       dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
434                                 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
435                                 &height, DBUS_TYPE_INVALID);
436     }
437   return reply;
438 }
439
440 static DBusMessage *
441 impl_getOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
442                        void *user_data)
443 {
444   AtkText *text = (AtkText *) user_data;
445   dbus_int32_t x, y;
446   dbus_uint32_t coordType;
447   dbus_int32_t rv;
448   DBusError error;
449   DBusMessage *reply;
450
451   g_return_val_if_fail (ATK_IS_TEXT (user_data),
452                         droute_not_yet_handled_error (message));
453   dbus_error_init (&error);
454   if (!dbus_message_get_args
455       (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
456        DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
457     {
458       return droute_invalid_arguments_error (message);
459     }
460   rv = atk_text_get_offset_at_point (text, x, y, coordType);
461   reply = dbus_message_new_method_return (message);
462   if (reply)
463     {
464       dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
465                                 DBUS_TYPE_INVALID);
466     }
467   return reply;
468 }
469
470 static DBusMessage *
471 impl_getNSelections (DBusConnection * bus, DBusMessage * message,
472                      void *user_data)
473 {
474   AtkText *text = (AtkText *) user_data;
475   dbus_int32_t rv;
476   DBusMessage *reply;
477
478   g_return_val_if_fail (ATK_IS_TEXT (user_data),
479                         droute_not_yet_handled_error (message));
480   rv = atk_text_get_n_selections (text);
481   reply = dbus_message_new_method_return (message);
482   if (reply)
483     {
484       dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
485                                 DBUS_TYPE_INVALID);
486     }
487   return reply;
488 }
489
490 static DBusMessage *
491 impl_getSelection (DBusConnection * bus, DBusMessage * message,
492                    void *user_data)
493 {
494   AtkText *text = (AtkText *) user_data;
495   dbus_int32_t selectionNum;
496   dbus_int32_t startOffset, endOffset;
497   gint intstart_offset = 0, intend_offset = 0;
498   DBusError error;
499   DBusMessage *reply;
500
501   g_return_val_if_fail (ATK_IS_TEXT (user_data),
502                         droute_not_yet_handled_error (message));
503   dbus_error_init (&error);
504   if (!dbus_message_get_args
505       (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
506     {
507       return droute_invalid_arguments_error (message);
508     }
509   /* atk_text_get_selection returns gchar * which we discard */
510   g_free (atk_text_get_selection
511           (text, selectionNum, &intstart_offset, &intend_offset));
512   startOffset = intstart_offset;
513   endOffset = intend_offset;
514   reply = dbus_message_new_method_return (message);
515   if (reply)
516     {
517       dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
518                                 DBUS_TYPE_INT32, &endOffset,
519                                 DBUS_TYPE_INVALID);
520     }
521   return reply;
522 }
523
524 static DBusMessage *
525 impl_addSelection (DBusConnection * bus, DBusMessage * message,
526                    void *user_data)
527 {
528   AtkText *text = (AtkText *) user_data;
529   dbus_int32_t startOffset, endOffset;
530   dbus_bool_t rv;
531   DBusError error;
532   DBusMessage *reply;
533
534   g_return_val_if_fail (ATK_IS_TEXT (user_data),
535                         droute_not_yet_handled_error (message));
536   dbus_error_init (&error);
537   if (!dbus_message_get_args
538       (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
539        &endOffset, DBUS_TYPE_INVALID))
540     {
541       return droute_invalid_arguments_error (message);
542     }
543   rv = atk_text_add_selection (text, startOffset, endOffset);
544   reply = dbus_message_new_method_return (message);
545   if (reply)
546     {
547       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
548                                 DBUS_TYPE_INVALID);
549     }
550   return reply;
551 }
552
553 static DBusMessage *
554 impl_removeSelection (DBusConnection * bus, DBusMessage * message,
555                       void *user_data)
556 {
557   AtkText *text = (AtkText *) user_data;
558   dbus_int32_t selectionNum;
559   dbus_bool_t rv;
560   DBusError error;
561   DBusMessage *reply;
562
563   g_return_val_if_fail (ATK_IS_TEXT (user_data),
564                         droute_not_yet_handled_error (message));
565   dbus_error_init (&error);
566   if (!dbus_message_get_args
567       (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
568     {
569       return droute_invalid_arguments_error (message);
570     }
571   rv = atk_text_remove_selection (text, selectionNum);
572   reply = dbus_message_new_method_return (message);
573   if (reply)
574     {
575       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
576                                 DBUS_TYPE_INVALID);
577     }
578   return reply;
579 }
580
581 static DBusMessage *
582 impl_setSelection (DBusConnection * bus, DBusMessage * message,
583                    void *user_data)
584 {
585   AtkText *text = (AtkText *) user_data;
586   dbus_int32_t selectionNum, startOffset, endOffset;
587   dbus_bool_t rv;
588   DBusError error;
589   DBusMessage *reply;
590
591   g_return_val_if_fail (ATK_IS_TEXT (user_data),
592                         droute_not_yet_handled_error (message));
593   dbus_error_init (&error);
594   if (!dbus_message_get_args
595       (message, &error, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
596        &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
597     {
598       return droute_invalid_arguments_error (message);
599     }
600   rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
601   reply = dbus_message_new_method_return (message);
602   if (reply)
603     {
604       dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
605                                 DBUS_TYPE_INVALID);
606     }
607   return reply;
608 }
609
610 static DBusMessage *
611 impl_getRangeExtents (DBusConnection * bus, DBusMessage * message,
612                       void *user_data)
613 {
614   AtkText *text = (AtkText *) user_data;
615   dbus_int32_t startOffset, endOffset;
616   dbus_uint32_t coordType;
617   AtkTextRectangle rect;
618   dbus_int32_t x, y, width, height;
619   DBusError error;
620   DBusMessage *reply;
621
622   g_return_val_if_fail (ATK_IS_TEXT (user_data),
623                         droute_not_yet_handled_error (message));
624   dbus_error_init (&error);
625   if (!dbus_message_get_args
626       (message, &error, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
627        &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
628     {
629       return droute_invalid_arguments_error (message);
630     }
631   memset (&rect, 0, sizeof (rect));
632   atk_text_get_range_extents (text, startOffset, endOffset,
633                               (AtkCoordType) coordType, &rect);
634   x = rect.x;
635   y = rect.y;
636   width = rect.width;
637   height = rect.height;
638   reply = dbus_message_new_method_return (message);
639   if (reply)
640     {
641       dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
642                                 &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
643                                 &height, DBUS_TYPE_INVALID);
644     }
645   return reply;
646 }
647
648 #define MAXRANGELEN 512
649
650 static DBusMessage *
651 impl_getBoundedRanges (DBusConnection * bus, DBusMessage * message,
652                        void *user_data)
653 {
654   AtkText *text = (AtkText *) user_data;
655   dbus_int32_t x, y, width, height;
656   dbus_uint32_t coordType, xClipType, yClipType;
657   DBusError error;
658   AtkTextRange **range_list = NULL;
659   AtkTextRectangle rect;
660   DBusMessage *reply;
661   DBusMessageIter iter, array, struc, variant;
662
663   g_return_val_if_fail (ATK_IS_TEXT (user_data),
664                         droute_not_yet_handled_error (message));
665   dbus_error_init (&error);
666   if (!dbus_message_get_args
667       (message, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
668        DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
669        &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
670        DBUS_TYPE_INVALID))
671     {
672       return droute_invalid_arguments_error (message);
673     }
674   rect.x = x;
675   rect.y = y;
676   rect.width = width;
677   rect.height = height;
678
679   range_list =
680     atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
681                                  (AtkTextClipType) xClipType,
682                                  (AtkTextClipType) yClipType);
683   reply = dbus_message_new_method_return (message);
684   if (!reply)
685     return NULL;
686   /* This isn't pleasant. */
687   dbus_message_iter_init_append (reply, &iter);
688   if (dbus_message_iter_open_container
689       (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
690     {
691       int len;
692       for (len = 0; len < MAXRANGELEN && range_list[len]; ++len)
693         {
694           if (dbus_message_iter_open_container
695               (&array, DBUS_TYPE_STRUCT, NULL, &struc))
696             {
697               dbus_int32_t val;
698               val = range_list[len]->start_offset;
699               dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
700               val = range_list[len]->end_offset;
701               dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
702               dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
703                                               &range_list[len]->content);
704               /* The variant is unimplemented in atk, but I don't want to
705                * unilaterally muck with the spec and remove it, so I'll just
706                * throw in a dummy value */
707               if (dbus_message_iter_open_container
708                   (&struc, DBUS_TYPE_VARIANT, "i", &variant))
709                 {
710                   dbus_uint32_t dummy = 0;
711                   dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
712                                                   &dummy);
713                   dbus_message_iter_close_container (&struc, &variant);
714                 }
715               dbus_message_iter_close_container (&array, &struc);
716             }
717         }
718       dbus_message_iter_close_container (&iter, &array);
719     }
720   return reply;
721 }
722
723 static DBusMessage *
724 impl_getAttributeRun (DBusConnection * bus, DBusMessage * message,
725                       void *user_data)
726 {
727   DBusError error;
728   AtkText *text = (AtkText *) user_data;
729   dbus_int32_t offset;
730   dbus_bool_t includeDefaults;
731   dbus_int32_t startOffset, endOffset;
732   gint intstart_offset = 0, intend_offset = 0;
733   DBusMessage *reply;
734   AtkAttributeSet *attributes, *default_attributes = NULL;
735   AtkAttribute *attr = NULL;
736   DBusMessageIter iter, iterArray;
737
738   g_return_val_if_fail (ATK_IS_TEXT (user_data),
739                         droute_not_yet_handled_error (message));
740   dbus_error_init (&error);
741   if (!dbus_message_get_args
742       (message, &error, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
743        &includeDefaults, DBUS_TYPE_INVALID))
744     {
745       return droute_invalid_arguments_error (message);
746     }
747
748   attributes =
749     atk_text_get_run_attributes (text, offset, &intstart_offset,
750                                  &intend_offset);
751
752   reply = dbus_message_new_method_return (message);
753   if (!reply)
754     return NULL;
755
756   dbus_message_iter_init_append (reply, &iter);
757   dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{ss}", &iterArray);
758   spi_atk_append_attribute_set_inner (&iterArray, attributes);
759   if (includeDefaults)
760     {
761       default_attributes = atk_text_get_default_attributes (text);
762       spi_atk_append_attribute_set_inner (&iterArray, default_attributes);
763     }
764   dbus_message_iter_close_container (&iter, &iterArray);
765
766   startOffset = intstart_offset;
767   endOffset = intend_offset;
768   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
769   dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
770
771   atk_attribute_set_free (attributes);
772   if (default_attributes)
773     atk_attribute_set_free (default_attributes);
774
775   return reply;
776 }
777
778 static DBusMessage *
779 impl_getDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
780                              void *user_data)
781 {
782   AtkText *text = (AtkText *) user_data;
783   DBusMessage *reply;
784   DBusMessageIter iter;
785   AtkAttributeSet *attributes;
786
787   g_return_val_if_fail (ATK_IS_TEXT (user_data),
788                         droute_not_yet_handled_error (message));
789
790   attributes = atk_text_get_default_attributes (text);
791
792   reply = dbus_message_new_method_return (message);
793   if (reply)
794     {
795       dbus_message_iter_init_append (reply, &iter);
796       spi_atk_append_attribute_set (&iter, attributes);
797     }
798
799   if (attributes)
800     atk_attribute_set_free (attributes);
801
802   return reply;
803 }
804
805 static DRouteMethod methods[] = {
806   {impl_getText, "getText"},
807   {impl_setCaretOffset, "setCaretOffset"},
808   {impl_getTextBeforeOffset, "getTextBeforeOffset"},
809   {impl_getTextAtOffset, "getTextAtOffset"},
810   {impl_getTextAfterOffset, "getTextAfterOffset"},
811   {impl_getCharacterAtOffset, "getCharacterAtOffset"},
812   {impl_getAttributeValue, "getAttributeValue"},
813   {impl_getAttributes, "getAttributes"},
814   {impl_getDefaultAttributes, "getDefaultAttributes"},
815   {impl_getCharacterExtents, "getCharacterExtents"},
816   {impl_getOffsetAtPoint, "getOffsetAtPoint"},
817   {impl_getNSelections, "getNSelections"},
818   {impl_getSelection, "getSelection"},
819   {impl_addSelection, "addSelection"},
820   {impl_removeSelection, "removeSelection"},
821   {impl_setSelection, "setSelection"},
822   {impl_getRangeExtents, "getRangeExtents"},
823   {impl_getBoundedRanges, "getBoundedRanges"},
824   {impl_getAttributeRun, "getAttributeRun"},
825   {impl_getDefaultAttributeSet, "getDefaultAttributeSet"},
826   {NULL, NULL}
827 };
828
829 static DRouteProperty properties[] = {
830   {impl_get_characterCount, NULL, "characterCount"},
831   {impl_get_caretOffset, NULL, "caretOffset"},
832   {NULL, NULL, NULL}
833 };
834
835 void
836 spi_initialize_text (DRoutePath *path)
837 {
838   droute_path_add_interface (path,
839                              SPI_DBUS_INTERFACE_TEXT,
840                              methods,
841                              properties);
842 };