Correct typo.
[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
23 enum {
24   TEXT_CHANGED,
25   CARET_MOVED,
26   LAST_SIGNAL
27 };
28
29 struct _AtkTextIfaceClass
30 {
31   GObjectClass parent;
32 };
33
34 typedef struct _AtkTextIfaceClass AtkTextIfaceClass;
35
36 static void atk_text_base_init (gpointer *g_class);
37
38 static guint atk_text_signals[LAST_SIGNAL] = { 0 };
39
40 GType
41 atk_text_get_type ()
42 {
43   static GType type = 0;
44
45   if (!type) 
46     {
47       static const GTypeInfo tinfo =
48       {
49         sizeof (AtkTextIface),
50         (GBaseInitFunc) atk_text_base_init,
51         (GBaseFinalizeFunc) NULL,
52         (GClassInitFunc) NULL /* atk_text_interface_init */ ,
53         (GClassFinalizeFunc) NULL,
54
55       };
56
57       type = g_type_register_static (G_TYPE_INTERFACE, "AtkText", &tinfo, 0);
58     }
59
60   return type;
61 }
62
63 static void
64 atk_text_base_init (gpointer *g_class)
65 {
66   static gboolean initialized = FALSE;
67   
68   if (! initialized)
69     {
70       /* 
71        * Note that text_changed signal supports details "insert", "delete", 
72        * possibly "replace". 
73        */
74       
75       atk_text_signals[TEXT_CHANGED] =
76         g_signal_new ("text_changed",
77                       ATK_TYPE_TEXT,
78                       G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
79                       G_STRUCT_OFFSET (AtkTextIface, text_changed), 
80                       (GSignalAccumulator) NULL, NULL,
81                       atk_marshal_VOID__INT_INT,
82                       G_TYPE_NONE,
83                       2, G_TYPE_INT, G_TYPE_INT);
84       
85       atk_text_signals[CARET_MOVED] =
86         g_signal_new ("text_caret_moved",
87                       ATK_TYPE_TEXT,
88                       G_SIGNAL_RUN_LAST,
89                       G_STRUCT_OFFSET (AtkTextIface, caret_changed),
90                       (GSignalAccumulator) NULL, NULL,
91                       g_cclosure_marshal_VOID__INT,
92                       G_TYPE_NONE,
93                       1, G_TYPE_INT);
94       
95       initialized = TRUE;
96     }
97 }
98
99 /**
100  * atk_text_get_text:
101  * @text: an #AtkText
102  * @start_offset: start position
103  * @end_offset: end position
104  *
105  * Gets the specified text.
106  *
107  * Returns: the text from @start_offset up to, but not including @end_offset.
108  **/
109 gchar*
110 atk_text_get_text (AtkText      *text,
111                    gint         start_offset,
112                    gint         end_offset)
113 {
114   AtkTextIface *iface;
115   
116   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
117
118   iface = ATK_TEXT_GET_IFACE (text);
119
120   if (iface->get_text)
121     return (*(iface->get_text)) (text, start_offset, end_offset);
122   else
123     return NULL;
124 }
125
126 /**
127  * atk_text_get_character_at_offset:
128  * @text: an #AtkText
129  * @offset: position
130  *
131  * Gets the specified text.
132  *
133  * Returns: the character at @offset.
134  **/
135 gunichar
136 atk_text_get_character_at_offset (AtkText      *text,
137                                   gint         offset)
138 {
139   AtkTextIface *iface;
140
141   g_return_val_if_fail (ATK_IS_TEXT (text), (gunichar) 0);
142
143   iface = ATK_TEXT_GET_IFACE (text);
144
145   if (iface->get_character_at_offset)
146     return (*(iface->get_character_at_offset)) (text, offset);
147   else
148     return (gunichar) 0;
149 }
150
151 /**
152  * atk_text_get_text_after_offset:
153  * @text: an #AtkText
154  * @offset: position
155  * @boundary_type: An #AtkTextBoundary
156  * @start_offset: the start offset of the returned string.
157  * @end_offset: the end offset of the returned string.
158  *
159  * Gets the specified text.
160  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
161  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
162  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
163  * will be the offset and will continue to the start of the next sentence. 
164  * The first word may not be a complete word. Similarly for 
165  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
166  * ATK_TEXT_BOUNDARY_LINE_END
167  *
168  * Returns: the text after @offset up to the specified @boundary_type.
169  **/
170 gchar*
171 atk_text_get_text_after_offset (AtkText          *text,
172                                 gint             offset,
173                                 AtkTextBoundary  boundary_type,
174                                 gint             *start_offset,
175                                 gint             *end_offset)
176 {
177   AtkTextIface *iface;
178   gint local_start_offset, local_end_offset;
179   gint *real_start_offset, *real_end_offset;
180
181   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
182
183   if (start_offset)
184     real_start_offset = start_offset;
185   else
186     real_start_offset = &local_start_offset;
187   if (end_offset)
188     real_end_offset = end_offset;
189   else
190     real_end_offset = &local_end_offset;
191
192   iface = ATK_TEXT_GET_IFACE (text);
193
194   if (iface->get_text_after_offset)
195     return (*(iface->get_text_after_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
196   else
197     return NULL;
198 }
199
200 /**
201  * atk_text_get_text_at_offset:
202  * @text: an #AtkText
203  * @offset: position
204  * @boundary_type: An #AtkTextBoundary
205  * @start_offset: the start offset of the returned string.
206  * @end_offset: the end offset of the returned string.
207  *
208  * Gets the specified text.
209  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START or 
210  * ATK_TEXT_BOUNDARY_WORD_END a complete word is returned; 
211  * if the boundary type is  ATK_TEXT_BOUNDARY_SENTENCE_START or 
212  * ATK_TEXT_BOUNDARY_SENTENCE_END a complete sentence
213  * is returned; if the boundary type is ATK_TEXT_BOUNDARY_LINE_START or
214  * ATK_TEXT_BOUNDARY_LINE_END a complete line is returned.
215  *
216  * Returns: the text at @offset up to the specified @boundary_type.
217  **/
218 gchar*
219 atk_text_get_text_at_offset (AtkText          *text,
220                              gint             offset,
221                              AtkTextBoundary  boundary_type,
222                              gint             *start_offset,
223                              gint             *end_offset)
224 {
225   AtkTextIface *iface;
226   gint local_start_offset, local_end_offset;
227   gint *real_start_offset, *real_end_offset;
228
229   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
230
231   if (start_offset)
232     real_start_offset = start_offset;
233   else
234     real_start_offset = &local_start_offset;
235   if (end_offset)
236     real_end_offset = end_offset;
237   else
238     real_end_offset = &local_end_offset;
239
240   iface = ATK_TEXT_GET_IFACE (text);
241
242   if (iface->get_text_at_offset)
243     return (*(iface->get_text_at_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
244   else
245     return NULL;
246 }
247
248 /**
249  * atk_text_get_text_before_offset:
250  * @text: an #AtkText
251  * @offset: position
252  * @boundary_type: An #AtkTextBoundary
253  * @start_offset: the start offset of the returned string.
254  * @end_offset: the end offset of the returned string.
255  *
256  * Gets the specified text.
257  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
258  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
259  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
260  * will be at the start of the sentence, and will continue to the offset. 
261  * The last word may not be a complete word. Similarly for 
262  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
263  * ATK_TEXT_BOUNDARY_LINE_END
264  *
265  * Returns: the text before @offset starting from the specified @boundary_type.
266  **/
267 gchar*
268 atk_text_get_text_before_offset (AtkText          *text,
269                                  gint             offset,
270                                  AtkTextBoundary  boundary_type,
271                                  gint             *start_offset,
272                                  gint             *end_offset)
273 {
274   AtkTextIface *iface;
275   gint local_start_offset, local_end_offset;
276   gint *real_start_offset, *real_end_offset;
277
278   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
279
280   if (start_offset)
281     real_start_offset = start_offset;
282   else
283     real_start_offset = &local_start_offset;
284   if (end_offset)
285     real_end_offset = end_offset;
286   else
287     real_end_offset = &local_end_offset;
288
289   iface = ATK_TEXT_GET_IFACE (text);
290
291   if (iface->get_text_before_offset)
292     return (*(iface->get_text_before_offset)) (text, offset, boundary_type, real_start_offset, real_end_offset);
293   else
294     return NULL;
295 }
296
297 /**
298  * atk_text_get_caret_offset:
299  * @text: an #AtkText
300  *
301  * Gets the offset position of the caret (cursor).
302  *
303  * Returns: the offset position of the caret (cursor).
304  **/
305 gint
306 atk_text_get_caret_offset (AtkText *text)
307 {
308   AtkTextIface *iface;
309
310   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
311
312   iface = ATK_TEXT_GET_IFACE (text);
313
314   if (iface->get_caret_offset)
315     return (*(iface->get_caret_offset)) (text);
316   else
317     return -1;
318 }
319
320 /**
321  * atk_text_get_character_extents:
322  * @text: an #AtkText
323  * @offset: position
324  * @x: x-position of character
325  * @y: y-position of character
326  * @width: width of character
327  * @height: height of character
328  * @coords: specify whether coordinates are relative to the screen or widget window 
329  *
330  * Given an @offset, the @x, @y, @width, and @height values are filled
331  * appropriately. 
332  **/
333 void
334 atk_text_get_character_extents (AtkText *text,
335                                 gint offset,
336                                 gint *x,
337                                 gint *y,
338                                 gint *width,
339                                 gint *height,
340                                 AtkCoordType coords)
341 {
342   AtkTextIface *iface;
343   gint local_x, local_y, local_width, local_height;
344   gint *real_x, *real_y, *real_width, *real_height;
345
346   g_return_if_fail (ATK_IS_TEXT (text));
347
348   if (x)
349     real_x = x;
350   else
351     real_x = &local_x;
352   if (y)
353     real_y = y;
354   else
355     real_y = &local_y;
356   if (width)
357     real_width = width;
358   else
359     real_width = &local_width;
360   if (height)
361     real_height = height;
362   else
363     real_height = &local_height;
364
365   iface = ATK_TEXT_GET_IFACE (text);
366
367   if (iface->get_character_extents)
368     (*(iface->get_character_extents)) (text, offset, real_x, real_y, real_width, real_height, coords);
369   else
370     {
371       *real_x = 0;
372       *real_y = 0;
373       *real_width = 0;
374       *real_height = 0;
375     }
376 }
377
378 /**
379  *atk_text_get_run_attributes:
380  *@text: an #AtkText
381  *@offset: the offset at which to get the attributes
382  *@start_offset: the address to put the start offset of the range
383  *@end_offset: the address to put the end offset of the range
384  *
385  *Creates an #AtkAttributeSet which consists of the attributes explicitly
386  *set at the position @offset in the text. @start_offset and @end_offset are
387  *set to the start and end of the range around @offset where the attributes are
388  *invariant. See the ATK_ATTRIBUTE macros, such as #ATK_ATTRIBUTE_LEFT_MARGIN
389  *for types of text attributes that can be returned. Note that other 
390  *attributes that do not have corresponding macros may also be returned.
391  *
392  *Returns: an #AtkAttributeSet which contains the attributes explicitly set
393  *at @offset. This #AtkAttributeSet should be freed by a call to
394  *atk_attribute_set_free().
395  **/
396 AtkAttributeSet* 
397 atk_text_get_run_attributes (AtkText          *text,
398                              gint             offset,
399                              gint             *start_offset,
400                              gint             *end_offset)
401 {
402   AtkTextIface *iface;
403   gint local_start_offset, local_end_offset;
404   gint *real_start_offset, *real_end_offset;
405
406   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
407
408   if (start_offset)
409     real_start_offset = start_offset;
410   else
411     real_start_offset = &local_start_offset;
412   if (end_offset)
413     real_end_offset = end_offset;
414   else
415     real_end_offset = &local_end_offset;
416
417   iface = ATK_TEXT_GET_IFACE (text);
418
419   if (iface->get_run_attributes)
420     return (*(iface->get_run_attributes)) (text, offset, real_start_offset, real_end_offset);
421   else
422     return NULL;
423 }
424
425 /**
426  *atk_text_get_default_attributes:
427  *@text: an #AtkText
428  *
429  *Creates an #AtkAttributeSet which consists of the default values of
430  *attributes for the text. See the ATK_ATTRIBUTE macros, such as 
431  *#ATK_ATTRIBUTE_LEFT_MARGIN for types of text attributes that can be 
432  *returned. Note that other attributes that do not have corresponding macros 
433  *may also be returned.
434  *
435  *Returns: an #AtkAttributeSet which contains the default values of attributes.
436  *at @offset. This #AtkAttributeSet should be freed by a call to
437  *atk_attribute_set_free().
438  */
439 AtkAttributeSet* 
440 atk_text_get_default_attributes (AtkText          *text)
441 {
442   AtkTextIface *iface;
443
444   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
445
446   if (iface->get_default_attributes)
447     return (*(iface->get_default_attributes)) (text);
448   else
449     return NULL;
450 }
451
452 /**
453  * atk_text_get_character_count:
454  * @text: an #AtkText
455  *
456  * Gets the character count.
457  *
458  * Returns: the number of characters.
459  **/
460 gint
461 atk_text_get_character_count (AtkText *text)
462 {
463   AtkTextIface *iface;
464
465   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
466
467   iface = ATK_TEXT_GET_IFACE (text);
468
469   if (iface->get_character_count)
470     return (*(iface->get_character_count)) (text);
471   else
472     return -1;
473 }
474
475 /**
476  * atk_text_get_offset_at_point:
477  * @text: an #AtkText
478  * @x: screen x-position of character
479  * @y: screen y-position of character
480  * @coords: specify whether coordinates are relative to the screen or
481  * widget window 
482  *
483  * Gets the offset of the character located at coordinates @x and @y. @x and @y
484  * are interpreted as being relative to the screen or this widget's window
485  * depending on @coords.
486  *
487  * Returns: the offset to the character which is located at
488  * the specified @x and @y coordinates.
489  **/
490 gint
491 atk_text_get_offset_at_point (AtkText *text,
492                               gint x,
493                               gint y,
494                               AtkCoordType coords)
495 {
496   AtkTextIface *iface;
497
498   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
499
500   iface = ATK_TEXT_GET_IFACE (text);
501
502   if (iface->get_offset_at_point)
503     return (*(iface->get_offset_at_point)) (text, x, y, coords);
504   else
505     return -1;
506 }
507
508 /**
509  * atk_text_get_n_selections:
510  * @text: an #AtkText
511  *
512  * Gets the number of selected regions.
513  *
514  * Returns: The number of selected regions, or -1 if a failure
515  *   occurred.
516  **/
517 gint
518 atk_text_get_n_selections (AtkText *text)
519 {
520   AtkTextIface *iface;
521
522   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
523
524   iface = ATK_TEXT_GET_IFACE (text);
525
526   if (iface->get_n_selections)
527     return (*(iface->get_n_selections)) (text);
528   else
529     return -1;
530 }
531
532 /**
533  * atk_text_get_selection:
534  * @text: an #AtkText
535  * @selection_num: The selection number.  The selected regions are
536  * assigned numbers that correspond to how far the region is from the
537  * start of the text.  The selected region closest to the beginning
538  * of the text region is assigned the number 0, etc.  Note that adding,
539  * moving or deleting a selected region can change the numbering.
540  * @start_offset: passes back the start position of the selected region
541  * @end_offset: passes back the end position of the selected region
542  *
543  * Gets the text from the specified selection.
544  *
545  * Returns: the selected text.
546  **/
547 gchar*
548 atk_text_get_selection (AtkText *text, 
549                         gint    selection_num,
550                         gint    *start_offset,
551                         gint    *end_offset)
552 {
553   AtkTextIface *iface;
554   gint local_start_offset, local_end_offset;
555   gint *real_start_offset, *real_end_offset;
556
557   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
558
559   if (start_offset)
560     real_start_offset = start_offset;
561   else
562     real_start_offset = &local_start_offset;
563   if (end_offset)
564     real_end_offset = end_offset;
565   else
566     real_start_offset = &local_end_offset;
567
568   iface = ATK_TEXT_GET_IFACE (text);
569
570   if (iface->get_selection)
571   {
572     return (*(iface->get_selection)) (text, selection_num,
573        real_start_offset, real_end_offset);
574   }
575   else
576     return NULL;
577 }
578
579 /**
580  * atk_text_add_selection:
581  * @text: an #AtkText
582  * @start_offset: the start position of the selected region
583  * @end_offset: the end position of the selected region
584  *
585  * Adds a selection bounded by the specified offsets.
586  *
587  * Returns: %TRUE if success, %FALSE otherwise
588  **/
589 gboolean
590 atk_text_add_selection (AtkText *text, 
591                         gint    start_offset,
592                         gint    end_offset)
593 {
594   AtkTextIface *iface;
595
596   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
597
598   iface = ATK_TEXT_GET_IFACE (text);
599
600   if (iface->add_selection)
601     return (*(iface->add_selection)) (text, start_offset, end_offset);
602   else
603     return FALSE;
604 }
605
606 /**
607  * atk_text_remove_selection:
608  * @text: an #AtkText
609  * @selection_num: The selection number.  The selected regions are
610  * assigned numbers that correspond to how far the region is from the
611  * start of the text.  The selected region closest to the beginning
612  * of the text region is assigned the number 0, etc.  Note that adding,
613  * moving or deleting a selected region can change the numbering.
614  *
615  * Removes the specified selection.
616  *
617  * Returns: %TRUE if success, %FALSE otherwise
618  **/
619 gboolean
620 atk_text_remove_selection (AtkText *text, 
621                            gint    selection_num)
622 {
623   AtkTextIface *iface;
624
625   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
626
627   iface = ATK_TEXT_GET_IFACE (text);
628
629   if (iface->remove_selection)
630     return (*(iface->remove_selection)) (text, selection_num);
631   else
632     return FALSE;
633 }
634
635 /**
636  * atk_text_set_selection:
637  * @text: an #AtkText
638  * @selection_num: The selection number.  The selected regions are
639  * assigned numbers that correspond to how far the region is from the
640  * start of the text.  The selected region closest to the beginning
641  * of the text region is assigned the number 0, etc.  Note that adding,
642  * moving or deleting a selected region can change the numbering.
643  * @start_offset: the new start position of the selection
644  * @end_offset: the new end position of the selection
645  *
646  * Changes the start and end offset of the specified selection.
647  *
648  * Returns: %TRUE if success, %FALSE otherwise
649  **/
650 gboolean
651 atk_text_set_selection (AtkText *text, 
652                         gint    selection_num,
653                         gint    start_offset, 
654                         gint    end_offset)
655 {
656   AtkTextIface *iface;
657
658   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
659
660   iface = ATK_TEXT_GET_IFACE (text);
661
662   if (iface->set_selection)
663   {
664     return (*(iface->set_selection)) (text, selection_num,
665        start_offset, end_offset);
666   }
667   else
668     return FALSE;
669 }
670
671 /**
672  * atk_text_set_caret_offset:
673  * @text: an #AtkText
674  * @offset: position
675  *
676  * Sets the caret (cursor) position to the specified @offset.
677  *
678  * Returns: %TRUE if success, %FALSE otherwise.
679  **/
680 gboolean
681 atk_text_set_caret_offset (AtkText *text,
682                            gint    offset)
683 {
684   AtkTextIface *iface;
685
686   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
687
688   iface = ATK_TEXT_GET_IFACE (text);
689
690   if (iface->set_caret_offset)
691     {
692       return (*(iface->set_caret_offset)) (text, offset);
693     }
694   else
695     {
696       return FALSE;
697     }
698 }
699
700 /**
701  * atk_attribute_set_free:
702  * @attrib_set: The #AtkAttributeSet to free
703  *
704  * Frees the memory used by an #AtkAttributeSet, including all its
705  * #AtkAttributes.
706  **/
707 void
708 atk_attribute_set_free(AtkAttributeSet *attrib_set)
709 {
710   GSList *temp;
711
712   temp = attrib_set;
713
714   while (temp != NULL)
715     {
716       AtkAttribute *att;
717
718       att = temp->data;
719
720       g_free (att->name);
721       g_free (att->value);
722       g_free (att);
723       temp = temp->next;
724     }
725   g_slist_free (attrib_set);
726 }