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