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