Add missing #include <string.h>
[platform/upstream/atk.git] / atk / atktext.c
1 /* ATK - The Accessibility Toolkit for GTK+
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "atktext.h"
21 #include "atkmarshal.h"
22 #include "atk-enum-types.h"
23
24 #include <string.h>
25
26 GPtrArray *extra_attributes = NULL;
27
28 enum {
29   TEXT_CHANGED,
30   CARET_MOVED,
31   TEXT_SELECTION_CHANGED,
32   LAST_SIGNAL
33 };
34
35 static const gchar *bool[] = {"false",
36                               "true"};
37 static const gchar *style[] = {"normal",
38                                "oblique",
39                                "italic"};
40 static const gchar *variant[] = {"normal",
41                                  "small_caps"};
42 static const gchar *stretch[] = {"ultra_condensed",
43                                  "extra_condensed",
44                                  "condensed",
45                                  "semi_condensed",
46                                  "normal",
47                                  "semi_expanded",
48                                  "expanded",
49                                  "extra_expanded",
50                                  "ultra_expanded"};
51 static const gchar *justification[] = {"left",
52                                        "right",
53                                        "center",
54
55                                        "fill"};
56 static const gchar *direction[] = {"none",
57                                    "ltr",
58                                    "rtl"};
59 static const gchar *wrap_mode[] = {"none",
60                                    "char",
61                                    "word"};
62 static const gchar *underline[] = {"none",
63                                    "single",
64                                    "double",
65                                    "low"};
66
67 static void atk_text_base_init (gpointer *g_class);
68
69 static guint atk_text_signals[LAST_SIGNAL] = { 0 };
70
71 GType
72 atk_text_get_type ()
73 {
74   static GType type = 0;
75
76   if (!type) 
77     {
78       static const GTypeInfo tinfo =
79       {
80         sizeof (AtkTextIface),
81         (GBaseInitFunc) atk_text_base_init,
82         (GBaseFinalizeFunc) NULL,
83         (GClassInitFunc) NULL /* atk_text_interface_init */ ,
84         (GClassFinalizeFunc) NULL,
85
86       };
87
88       type = g_type_register_static (G_TYPE_INTERFACE, "AtkText", &tinfo, 0);
89     }
90
91   return type;
92 }
93
94 static void
95 atk_text_base_init (gpointer *g_class)
96 {
97   static gboolean initialized = FALSE;
98   
99   if (! initialized)
100     {
101       /* 
102        * Note that text_changed signal supports details "insert", "delete", 
103        * possibly "replace". 
104        */
105       
106       atk_text_signals[TEXT_CHANGED] =
107         g_signal_new ("text_changed",
108                       ATK_TYPE_TEXT,
109                       G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
110                       G_STRUCT_OFFSET (AtkTextIface, text_changed), 
111                       (GSignalAccumulator) NULL, NULL,
112                       atk_marshal_VOID__INT_INT,
113                       G_TYPE_NONE,
114                       2, G_TYPE_INT, G_TYPE_INT);
115       
116       atk_text_signals[CARET_MOVED] =
117         g_signal_new ("text_caret_moved",
118                       ATK_TYPE_TEXT,
119                       G_SIGNAL_RUN_LAST,
120                       G_STRUCT_OFFSET (AtkTextIface, caret_changed),
121                       (GSignalAccumulator) NULL, NULL,
122                       g_cclosure_marshal_VOID__INT,
123                       G_TYPE_NONE,
124                       1, G_TYPE_INT);
125       atk_text_signals[TEXT_SELECTION_CHANGED] =
126         g_signal_new ("text_selection_changed",
127                       ATK_TYPE_TEXT,
128                       G_SIGNAL_RUN_LAST,
129                       G_STRUCT_OFFSET (AtkTextIface, text_selection_changed),
130                       (GSignalAccumulator) NULL, NULL,
131                       g_cclosure_marshal_VOID__VOID,
132                       G_TYPE_NONE, 0);
133
134       
135       initialized = TRUE;
136     }
137 }
138
139 /**
140  * atk_text_get_text:
141  * @text: an #AtkText
142  * @start_offset: start position
143  * @end_offset: end position
144  *
145  * Gets the specified text.
146  *
147  * Returns: the text from @start_offset up to, but not including @end_offset.
148  **/
149 gchar*
150 atk_text_get_text (AtkText      *text,
151                    gint         start_offset,
152                    gint         end_offset)
153 {
154   AtkTextIface *iface;
155   
156   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
157
158   iface = ATK_TEXT_GET_IFACE (text);
159
160   if (iface->get_text)
161     return (*(iface->get_text)) (text, start_offset, end_offset);
162   else
163     return NULL;
164 }
165
166 /**
167  * atk_text_get_character_at_offset:
168  * @text: an #AtkText
169  * @offset: position
170  *
171  * Gets the specified text.
172  *
173  * Returns: the character at @offset.
174  **/
175 gunichar
176 atk_text_get_character_at_offset (AtkText      *text,
177                                   gint         offset)
178 {
179   AtkTextIface *iface;
180
181   g_return_val_if_fail (ATK_IS_TEXT (text), (gunichar) 0);
182
183   iface = ATK_TEXT_GET_IFACE (text);
184
185   if (iface->get_character_at_offset)
186     return (*(iface->get_character_at_offset)) (text, offset);
187   else
188     return (gunichar) 0;
189 }
190
191 /**
192  * atk_text_get_text_after_offset:
193  * @text: an #AtkText
194  * @offset: position
195  * @boundary_type: An #AtkTextBoundary
196  * @start_offset: the start offset of the returned string.
197  * @end_offset: the end offset of the returned string.
198  *
199  * Gets the specified text.
200  *
201  * If the boundary_type if ATK_TEXT_BOUNDARY_CHAR the character after the 
202  * offset is returned.
203  *
204  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START the returned string
205  * is from the word start after the offset to the next word start.
206  *
207  * The returned string will contain the word after the offset if the offset 
208  * is inside a word or if the offset is not inside a word.
209  *
210  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_END the returned string
211  * is from the word end at or after the offset to the next work end.
212  *
213  * The returned string will contain the word after the offset if the offset
214  * is inside a word and will contain the word after the word after the offset
215  * if the offset is not inside a word.
216  *
217  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the returned
218  * string is from the sentence start after the offset to the next sentence
219  * start.
220  *
221  * The returned string will contain the sentence after the offset if the offset
222  * is inside a sentence or if the offset is not inside a sentence.
223  *
224  * If the boundary_type is ATK_TEXT_BOUNDARY_SENTENCE_END the returned string
225  * is from the sentence end at or after the offset to the next sentence end.
226  *
227  * The returned string will contain the sentence after the offset if the offset
228  * is inside a sentence and will contain the sentence after the sentence
229  * after the offset if the offset is not inside a sentence.
230  *
231  * If the boundary type is ATK_TEXT_BOUNDARY_LINE_START the returned
232  * string is from the line start after the offset to the next line start.
233  *
234  * If the boundary_type is ATK_TEXT_BOUNDARY_LINE_END the returned string
235  * is from the line end at or after the offset to the next line start.
236  *
237  * Returns: the text after @offset bounded by the specified @boundary_type.
238  **/
239 gchar*
240 atk_text_get_text_after_offset (AtkText          *text,
241                                 gint             offset,
242                                 AtkTextBoundary  boundary_type,
243                                 gint             *start_offset,
244                                 gint             *end_offset)
245 {
246   AtkTextIface *iface;
247   gint local_start_offset, local_end_offset;
248   gint *real_start_offset, *real_end_offset;
249
250   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
251
252   if (start_offset)
253     real_start_offset = start_offset;
254   else
255     real_start_offset = &local_start_offset;
256   if (end_offset)
257     real_end_offset = end_offset;
258   else
259     real_end_offset = &local_end_offset;
260
261   iface = ATK_TEXT_GET_IFACE (text);
262
263   if (iface->get_text_after_offset)
264     return (*(iface->get_text_after_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
265   else
266     return NULL;
267 }
268
269 /**
270  * atk_text_get_text_at_offset:
271  * @text: an #AtkText
272  * @offset: position
273  * @boundary_type: An #AtkTextBoundary
274  * @start_offset: the start offset of the returned string.
275  * @end_offset: the end offset of the returned string.
276  *
277  * Gets the specified text.
278  *
279  * If the boundary_type if ATK_TEXT_BOUNDARY_CHAR the character at the
280  * offset is returned.
281  *
282  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START the returned string
283  * is from the word start at or before the offset to the word start after 
284  * the offset.
285  *
286  * The returned string will contain the word at the offset if the offset
287  * is inside a word and will contain the word before the offset if the 
288  * offset is not inside a word.
289  *
290  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_END the returned string
291  * is from the word end before the offset to the word end at or after the
292  * offset.
293  *
294  * The returned string will contain the word at the offset if the offset
295  * is inside a word and will contain the word after to the offset if the 
296  * offset is not inside a word.
297  *
298  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the returned
299  * string is from the sentence start at or before the offset to the sentence
300  * start after the offset.
301  *
302  * The returned string will contain the sentence at the offset if the offset
303  * is inside a sentence and will contain the sentence before the offset 
304  * if the offset is not inside a sentence.
305  *
306  * If the boundary_type is ATK_TEXT_BOUNDARY_SENTENCE_END the returned string
307  * is from the sentence end before the offset to the sentence end at or
308  * after the offset.
309  *
310  * The returned string will contain the sentence at the offset if the offset
311  * is inside a sentence and will contain the sentence after the offset 
312  * if the offset is not inside a sentence.
313  *
314  * If the boundary type is ATK_TEXT_BOUNDARY_LINE_START the returned
315  * string is from the line start at or before the offset to the line
316  * start after the offset.
317  *
318  * If the boundary_type is ATK_TEXT_BOUNDARY_LINE_END the returned string
319  * is from the line end before the offset to the line end at or after
320  * the offset.
321  *
322  * Returns: the text at @offset bounded by the specified @boundary_type.
323  **/
324 gchar*
325 atk_text_get_text_at_offset (AtkText          *text,
326                              gint             offset,
327                              AtkTextBoundary  boundary_type,
328                              gint             *start_offset,
329                              gint             *end_offset)
330 {
331   AtkTextIface *iface;
332   gint local_start_offset, local_end_offset;
333   gint *real_start_offset, *real_end_offset;
334
335   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
336
337   if (start_offset)
338     real_start_offset = start_offset;
339   else
340     real_start_offset = &local_start_offset;
341   if (end_offset)
342     real_end_offset = end_offset;
343   else
344     real_end_offset = &local_end_offset;
345
346   iface = ATK_TEXT_GET_IFACE (text);
347
348   if (iface->get_text_at_offset)
349     return (*(iface->get_text_at_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
350   else
351     return NULL;
352 }
353
354 /**
355  * atk_text_get_text_before_offset:
356  * @text: an #AtkText
357  * @offset: position
358  * @boundary_type: An #AtkTextBoundary
359  * @start_offset: the start offset of the returned string.
360  * @end_offset: the end offset of the returned string.
361  *
362  * Gets the specified text.
363  *
364  * If the boundary_type if ATK_TEXT_BOUNDARY_CHAR the character before the
365  * offset is returned.
366  *
367  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START the returned string
368  * is from the word start before the word start before the offset to 
369  * the word start before the offset.
370  *
371  * The returned string will contain the word before the offset if the offset
372  * is inside a word and will contain the word before the word before the 
373  * offset if the offset is not inside a word.
374  *
375  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_END the returned string
376  * is from the word end before the word end at or before the offset to the 
377  * word end at or before the offset.
378  *
379  * The returned string will contain the word before the offset if the offset
380  * is inside a word or if the offset is not inside a word.
381  *
382  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the returned
383  * string is from the sentence start before the sentence start before 
384  * the offset to the sentence start before the offset.
385  *
386  * The returned string will contain the sentence before the offset if the 
387  * offset is inside a sentence and will contain the sentence before the 
388  * sentence before the offset if the offset is not inside a sentence.
389  *
390  * If the boundary_type is ATK_TEXT_BOUNDARY_SENTENCE_END the returned string
391  * is from the sentence end before the sentence end at or before the offset to 
392  * the sentence end at or before the offset.
393  *
394  * The returned string will contain the sentence before the offset if the 
395  * offset is inside a sentence or if the offset is not inside a sentence.
396  *
397  * If the boundary type is ATK_TEXT_BOUNDARY_LINE_START the returned
398  * string is from the line start before the line start ar or before the offset 
399  * to the line start ar or before the offset.
400  *
401  * If the boundary_type is ATK_TEXT_BOUNDARY_LINE_END the returned string
402  * is from the line end before the line end before the offset to the 
403  * line end before the offset.
404  *
405  * Returns: the text before @offset bounded by the specified @boundary_type.
406  **/
407 gchar*
408 atk_text_get_text_before_offset (AtkText          *text,
409                                  gint             offset,
410                                  AtkTextBoundary  boundary_type,
411                                  gint             *start_offset,
412                                  gint             *end_offset)
413 {
414   AtkTextIface *iface;
415   gint local_start_offset, local_end_offset;
416   gint *real_start_offset, *real_end_offset;
417
418   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
419
420   if (start_offset)
421     real_start_offset = start_offset;
422   else
423     real_start_offset = &local_start_offset;
424   if (end_offset)
425     real_end_offset = end_offset;
426   else
427     real_end_offset = &local_end_offset;
428
429   iface = ATK_TEXT_GET_IFACE (text);
430
431   if (iface->get_text_before_offset)
432     return (*(iface->get_text_before_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
433   else
434     return NULL;
435 }
436
437 /**
438  * atk_text_get_caret_offset:
439  * @text: an #AtkText
440  *
441  * Gets the offset position of the caret (cursor).
442  *
443  * Returns: the offset position of the caret (cursor).
444  **/
445 gint
446 atk_text_get_caret_offset (AtkText *text)
447 {
448   AtkTextIface *iface;
449
450   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
451
452   iface = ATK_TEXT_GET_IFACE (text);
453
454   if (iface->get_caret_offset)
455     return (*(iface->get_caret_offset)) (text);
456   else
457     return -1;
458 }
459
460 /**
461  * atk_text_get_character_extents:
462  * @text: an #AtkText
463  * @offset: position
464  * @x: x-position of character
465  * @y: y-position of character
466  * @width: width of character
467  * @height: height of character
468  * @coords: specify whether coordinates are relative to the screen or widget window 
469  *
470  * Given an @offset, the @x, @y, @width, and @height values are filled
471  * appropriately. 
472  **/
473 void
474 atk_text_get_character_extents (AtkText *text,
475                                 gint offset,
476                                 gint *x,
477                                 gint *y,
478                                 gint *width,
479                                 gint *height,
480                                 AtkCoordType coords)
481 {
482   AtkTextIface *iface;
483   gint local_x, local_y, local_width, local_height;
484   gint *real_x, *real_y, *real_width, *real_height;
485
486   g_return_if_fail (ATK_IS_TEXT (text));
487
488   if (x)
489     real_x = x;
490   else
491     real_x = &local_x;
492   if (y)
493     real_y = y;
494   else
495     real_y = &local_y;
496   if (width)
497     real_width = width;
498   else
499     real_width = &local_width;
500   if (height)
501     real_height = height;
502   else
503     real_height = &local_height;
504
505   iface = ATK_TEXT_GET_IFACE (text);
506
507   if (iface->get_character_extents)
508     (*(iface->get_character_extents)) (text, offset, real_x, real_y, real_width, real_height, coords);
509   else
510     {
511       *real_x = 0;
512       *real_y = 0;
513       *real_width = 0;
514       *real_height = 0;
515     }
516 }
517
518 /**
519  *atk_text_get_run_attributes:
520  *@text: an #AtkText
521  *@offset: the offset at which to get the attributes
522  *@start_offset: the address to put the start offset of the range
523  *@end_offset: the address to put the end offset of the range
524  *
525  *Creates an #AtkAttributeSet which consists of the attributes explicitly
526  *set at the position @offset in the text. @start_offset and @end_offset are
527  *set to the start and end of the range around @offset where the attributes are
528  *invariant. See the enum AtkTextAttribute for types of text attributes that 
529  *can be returned. Note that other attributes may also be returned.
530  *
531  *Returns: an #AtkAttributeSet which contains the attributes explicitly set
532  *at @offset. This #AtkAttributeSet should be freed by a call to
533  *atk_attribute_set_free().
534  **/
535 AtkAttributeSet* 
536 atk_text_get_run_attributes (AtkText          *text,
537                              gint             offset,
538                              gint             *start_offset,
539                              gint             *end_offset)
540 {
541   AtkTextIface *iface;
542   gint local_start_offset, local_end_offset;
543   gint *real_start_offset, *real_end_offset;
544
545   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
546
547   if (start_offset)
548     real_start_offset = start_offset;
549   else
550     real_start_offset = &local_start_offset;
551   if (end_offset)
552     real_end_offset = end_offset;
553   else
554     real_end_offset = &local_end_offset;
555
556   iface = ATK_TEXT_GET_IFACE (text);
557
558   if (iface->get_run_attributes)
559     return (*(iface->get_run_attributes)) (text, offset, real_start_offset, real_end_offset);
560   else
561     return NULL;
562 }
563
564 /**
565  *atk_text_get_default_attributes:
566  *@text: an #AtkText
567  *
568  *Creates an #AtkAttributeSet which consists of the default values of
569  *attributes for the text. See the enum AtkTextAttribute for types of text 
570  *attributes that can be returned. Note that other attributes may also be 
571  *returned.
572  *
573  *Returns: an #AtkAttributeSet which contains the default values of attributes.
574  *at @offset. This #AtkAttributeSet should be freed by a call to
575  *atk_attribute_set_free().
576  */
577 AtkAttributeSet* 
578 atk_text_get_default_attributes (AtkText          *text)
579 {
580   AtkTextIface *iface;
581
582   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
583
584   iface = ATK_TEXT_GET_IFACE (text);
585
586   if (iface->get_default_attributes)
587     return (*(iface->get_default_attributes)) (text);
588   else
589     return NULL;
590 }
591
592 /**
593  * atk_text_get_character_count:
594  * @text: an #AtkText
595  *
596  * Gets the character count.
597  *
598  * Returns: the number of characters.
599  **/
600 gint
601 atk_text_get_character_count (AtkText *text)
602 {
603   AtkTextIface *iface;
604
605   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
606
607   iface = ATK_TEXT_GET_IFACE (text);
608
609   if (iface->get_character_count)
610     return (*(iface->get_character_count)) (text);
611   else
612     return -1;
613 }
614
615 /**
616  * atk_text_get_offset_at_point:
617  * @text: an #AtkText
618  * @x: screen x-position of character
619  * @y: screen y-position of character
620  * @coords: specify whether coordinates are relative to the screen or
621  * widget window 
622  *
623  * Gets the offset of the character located at coordinates @x and @y. @x and @y
624  * are interpreted as being relative to the screen or this widget's window
625  * depending on @coords.
626  *
627  * Returns: the offset to the character which is located at
628  * the specified @x and @y coordinates.
629  **/
630 gint
631 atk_text_get_offset_at_point (AtkText *text,
632                               gint x,
633                               gint y,
634                               AtkCoordType coords)
635 {
636   AtkTextIface *iface;
637
638   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
639
640   iface = ATK_TEXT_GET_IFACE (text);
641
642   if (iface->get_offset_at_point)
643     return (*(iface->get_offset_at_point)) (text, x, y, coords);
644   else
645     return -1;
646 }
647
648 /**
649  * atk_text_get_n_selections:
650  * @text: an #AtkText
651  *
652  * Gets the number of selected regions.
653  *
654  * Returns: The number of selected regions, or -1 if a failure
655  *   occurred.
656  **/
657 gint
658 atk_text_get_n_selections (AtkText *text)
659 {
660   AtkTextIface *iface;
661
662   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
663
664   iface = ATK_TEXT_GET_IFACE (text);
665
666   if (iface->get_n_selections)
667     return (*(iface->get_n_selections)) (text);
668   else
669     return -1;
670 }
671
672 /**
673  * atk_text_get_selection:
674  * @text: an #AtkText
675  * @selection_num: The selection number.  The selected regions are
676  * assigned numbers that correspond to how far the region is from the
677  * start of the text.  The selected region closest to the beginning
678  * of the text region is assigned the number 0, etc.  Note that adding,
679  * moving or deleting a selected region can change the numbering.
680  * @start_offset: passes back the start position of the selected region
681  * @end_offset: passes back the end position of the selected region
682  *
683  * Gets the text from the specified selection.
684  *
685  * Returns: the selected text.
686  **/
687 gchar*
688 atk_text_get_selection (AtkText *text, 
689                         gint    selection_num,
690                         gint    *start_offset,
691                         gint    *end_offset)
692 {
693   AtkTextIface *iface;
694   gint local_start_offset, local_end_offset;
695   gint *real_start_offset, *real_end_offset;
696
697   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
698
699   if (start_offset)
700     real_start_offset = start_offset;
701   else
702     real_start_offset = &local_start_offset;
703   if (end_offset)
704     real_end_offset = end_offset;
705   else
706     real_end_offset = &local_end_offset;
707
708   iface = ATK_TEXT_GET_IFACE (text);
709
710   if (iface->get_selection)
711   {
712     return (*(iface->get_selection)) (text, selection_num,
713        real_start_offset, real_end_offset);
714   }
715   else
716     return NULL;
717 }
718
719 /**
720  * atk_text_add_selection:
721  * @text: an #AtkText
722  * @start_offset: the start position of the selected region
723  * @end_offset: the end position of the selected region
724  *
725  * Adds a selection bounded by the specified offsets.
726  *
727  * Returns: %TRUE if success, %FALSE otherwise
728  **/
729 gboolean
730 atk_text_add_selection (AtkText *text, 
731                         gint    start_offset,
732                         gint    end_offset)
733 {
734   AtkTextIface *iface;
735
736   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
737
738   iface = ATK_TEXT_GET_IFACE (text);
739
740   if (iface->add_selection)
741     return (*(iface->add_selection)) (text, start_offset, end_offset);
742   else
743     return FALSE;
744 }
745
746 /**
747  * atk_text_remove_selection:
748  * @text: an #AtkText
749  * @selection_num: The selection number.  The selected regions are
750  * assigned numbers that correspond to how far the region is from the
751  * start of the text.  The selected region closest to the beginning
752  * of the text region is assigned the number 0, etc.  Note that adding,
753  * moving or deleting a selected region can change the numbering.
754  *
755  * Removes the specified selection.
756  *
757  * Returns: %TRUE if success, %FALSE otherwise
758  **/
759 gboolean
760 atk_text_remove_selection (AtkText *text, 
761                            gint    selection_num)
762 {
763   AtkTextIface *iface;
764
765   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
766
767   iface = ATK_TEXT_GET_IFACE (text);
768
769   if (iface->remove_selection)
770     return (*(iface->remove_selection)) (text, selection_num);
771   else
772     return FALSE;
773 }
774
775 /**
776  * atk_text_set_selection:
777  * @text: an #AtkText
778  * @selection_num: The selection number.  The selected regions are
779  * assigned numbers that correspond to how far the region is from the
780  * start of the text.  The selected region closest to the beginning
781  * of the text region is assigned the number 0, etc.  Note that adding,
782  * moving or deleting a selected region can change the numbering.
783  * @start_offset: the new start position of the selection
784  * @end_offset: the new end position of the selection
785  *
786  * Changes the start and end offset of the specified selection.
787  *
788  * Returns: %TRUE if success, %FALSE otherwise
789  **/
790 gboolean
791 atk_text_set_selection (AtkText *text, 
792                         gint    selection_num,
793                         gint    start_offset, 
794                         gint    end_offset)
795 {
796   AtkTextIface *iface;
797
798   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
799
800   iface = ATK_TEXT_GET_IFACE (text);
801
802   if (iface->set_selection)
803   {
804     return (*(iface->set_selection)) (text, selection_num,
805        start_offset, end_offset);
806   }
807   else
808     return FALSE;
809 }
810
811 /**
812  * atk_text_set_caret_offset:
813  * @text: an #AtkText
814  * @offset: position
815  *
816  * Sets the caret (cursor) position to the specified @offset.
817  *
818  * Returns: %TRUE if success, %FALSE otherwise.
819  **/
820 gboolean
821 atk_text_set_caret_offset (AtkText *text,
822                            gint    offset)
823 {
824   AtkTextIface *iface;
825
826   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
827
828   iface = ATK_TEXT_GET_IFACE (text);
829
830   if (iface->set_caret_offset)
831     {
832       return (*(iface->set_caret_offset)) (text, offset);
833     }
834   else
835     {
836       return FALSE;
837     }
838 }
839
840 /**
841  * atk_attribute_set_free:
842  * @attrib_set: The #AtkAttributeSet to free
843  *
844  * Frees the memory used by an #AtkAttributeSet, including all its
845  * #AtkAttributes.
846  **/
847 void
848 atk_attribute_set_free (AtkAttributeSet *attrib_set)
849 {
850   GSList *temp;
851
852   temp = attrib_set;
853
854   while (temp != NULL)
855     {
856       AtkAttribute *att;
857
858       att = temp->data;
859
860       g_free (att->name);
861       g_free (att->value);
862       g_free (att);
863       temp = temp->next;
864     }
865   g_slist_free (attrib_set);
866 }
867
868 /**
869  * atk_text_attribute_register:
870  * @name: a name string
871  *
872  * Associate @name with a new #AtkTextAttribute
873  *
874  * Returns: an #AtkTextAttribute associated with @name
875  **/
876 AtkTextAttribute
877 atk_text_attribute_register (const gchar *name)
878 {
879   g_return_val_if_fail (name, ATK_TEXT_ATTR_INVALID);
880
881   if (!extra_attributes)
882     extra_attributes = g_ptr_array_new ();
883
884   g_ptr_array_add (extra_attributes, g_strdup (name));
885   return extra_attributes->len + ATK_TEXT_ATTR_LAST_DEFINED;
886 }
887
888 /**
889  * atk_text_attribute_get_name:
890  * @attr: The #AtkTextAttribute whose name is required
891  *
892  * Gets the name corresponding to the #AtkTextAttribute
893  *
894  * Returns: a string containing the name; this string should not be freed
895  **/
896 G_CONST_RETURN gchar*
897 atk_text_attribute_get_name (AtkTextAttribute attr)
898 {
899   GTypeClass *type_class;
900   GEnumValue *value;
901   gchar *name = NULL;
902
903   type_class = g_type_class_ref (ATK_TYPE_TEXT_ATTRIBUTE);
904   g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), NULL);
905
906   value = g_enum_get_value (G_ENUM_CLASS (type_class), attr);
907
908   if (value)
909     {
910       name = value->value_nick;
911     }
912   else
913     {
914       if (extra_attributes)
915         {
916           gint n = attr;
917
918           n -= ATK_TEXT_ATTR_LAST_DEFINED + 1;
919
920           if (n < extra_attributes->len)
921
922             name = g_ptr_array_index (extra_attributes, n);
923         }
924     }
925   g_type_class_unref (type_class);
926   return name;
927 }
928
929 /**
930  * atk_text_attribute_for_name:
931  * @name: a string which is the (non-localized) name of an ATK text attribute.
932  *
933  * Get the #AtkTextAttribute type corresponding to a text attribute name.
934  *
935  * Returns: the #AtkTextAttribute enumerated type corresponding to the specified
936 name,
937  *          or #ATK_TEXT_ATTRIBUTE_INVALID if no matching text attribute is found.
938  **/
939 AtkTextAttribute
940 atk_text_attribute_for_name (const gchar *name)
941 {
942   GTypeClass *type_class;
943   GEnumValue *value;
944   AtkTextAttribute type = ATK_TEXT_ATTR_INVALID;
945
946   g_return_val_if_fail (name, ATK_TEXT_ATTR_INVALID);
947
948   type_class = g_type_class_ref (ATK_TYPE_TEXT_ATTRIBUTE);
949   g_return_val_if_fail (G_IS_ENUM_CLASS (type_class), ATK_TEXT_ATTR_INVALID);
950
951   value = g_enum_get_value_by_nick (G_ENUM_CLASS (type_class), name);
952
953   if (value)
954     {
955       type = value->value;
956     }
957   else
958     {
959       gint i;
960
961       if (extra_attributes)
962         {
963           for (i = 0; i < extra_attributes->len; i++)
964             {
965               gchar *extra_attribute = (gchar *)g_ptr_array_index (extra_attributes, i);
966
967               g_return_val_if_fail (extra_attribute, ATK_TEXT_ATTR_INVALID);
968
969               if (strcmp (name, extra_attribute) == 0)
970                 {
971                   type = i + 1 + ATK_TEXT_ATTR_LAST_DEFINED;
972                   break;
973                 }
974             }
975         }
976     }
977   g_type_class_unref (type_class);
978
979   return type;
980 }
981
982
983 /**
984  * atk_text_attribute_get_value:
985  * @attr: The #AtkTextAttribute for which a value is required
986  * @index: The index of the required value
987  *
988  * Gets the value for the index of the #AtkTextAttribute
989  *
990  * Returns: a string containing the value; this string should not be freed;
991  * NULL is returned if there are no values maintained for the attr value. 
992  **/
993 G_CONST_RETURN gchar*
994 atk_text_attribute_get_value (AtkTextAttribute attr,
995                               gint             index)
996 {
997   switch (attr)
998     {
999     case ATK_TEXT_ATTR_INVISIBLE:
1000     case ATK_TEXT_ATTR_EDITABLE:
1001     case ATK_TEXT_ATTR_BG_FULL_HEIGHT:
1002     case ATK_TEXT_ATTR_STRIKETHROUGH:
1003     case ATK_TEXT_ATTR_BG_STIPPLE:
1004     case ATK_TEXT_ATTR_FG_STIPPLE:
1005       g_assert (index >= 0 && index < 2);
1006       return bool[index];
1007     case ATK_TEXT_ATTR_UNDERLINE:
1008       g_assert (index >= 0 && index < 4);
1009       return underline[index];
1010     case ATK_TEXT_ATTR_WRAP_MODE:
1011       g_assert (index >= 0 && index < 3);
1012       return wrap_mode[index];
1013     case ATK_TEXT_ATTR_DIRECTION:
1014       g_assert (index >= 0 && index < 3);
1015       return direction[index];
1016     case ATK_TEXT_ATTR_JUSTIFICATION:
1017       g_assert (index >= 0 && index < 3);
1018       return justification[index];
1019     case ATK_TEXT_ATTR_STRETCH:
1020       g_assert (index >= 0 && index < 9);
1021       return stretch[index];
1022     case ATK_TEXT_ATTR_VARIANT:
1023       g_assert (index >= 0 && index < 2);
1024       return variant[index];
1025     case ATK_TEXT_ATTR_STYLE:
1026       g_assert (index >= 0 && index < 3);
1027       return style[index];
1028     default:
1029       return NULL;
1030    }
1031 }