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