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