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