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