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