Added atk_text_ref_run_attributes() and atk_text_set_run_attributes().
[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_newc ("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_newc ("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 (text != NULL, NULL);
117   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
118
119   iface = ATK_TEXT_GET_IFACE (text);
120
121   if (iface->get_text)
122     return (*(iface->get_text)) (text, start_offset, end_offset);
123   else
124     return NULL;
125 }
126
127 /**
128  * atk_text_get_character_at_offset
129  * @text: an #AtkText
130  * @offset: position
131  *
132  * Gets the specified text.
133  *
134  * Returns: the character at @offset.
135  **/
136 gunichar
137 atk_text_get_character_at_offset (AtkText      *text,
138                                   gint         offset)
139 {
140   AtkTextIface *iface;
141
142   g_return_val_if_fail (text != NULL, (gunichar) 0);
143   g_return_val_if_fail (ATK_IS_TEXT (text), (gunichar) 0);
144
145   iface = ATK_TEXT_GET_IFACE (text);
146
147   if (iface->get_character_at_offset)
148     return (*(iface->get_character_at_offset)) (text, offset);
149   else
150     return (gunichar) 0;
151 }
152
153 /**
154  * atk_text_get_text_after_offset
155  * @text: an #AtkText
156  * @offset: position
157  * @boundary_type: An #AtkTextBoundary
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 {
175   AtkTextIface *iface;
176
177   g_return_val_if_fail (text != NULL, NULL);
178   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
179
180   iface = ATK_TEXT_GET_IFACE (text);
181
182   if (iface->get_text_after_offset)
183     return (*(iface->get_text_after_offset)) (text, offset, boundary_type);
184   else
185     return NULL;
186 }
187
188 /**
189  * atk_text_get_text_at_offset
190  * @text: an #AtkText
191  * @offset: position
192  * @boundary_type: An #AtkTextBoundary
193  *
194  * Gets the specified text.
195  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START or 
196  * ATK_TEXT_BOUNDARY_WORD_END a complete word is returned; 
197  * if the boundary type is  ATK_TEXT_BOUNDARY_SENTENCE_START or 
198  * ATK_TEXT_BOUNDARY_SENTENCE_END a complete sentence
199  * is returned; if the boundary type is ATK_TEXT_BOUNDARY_LINE_START or
200  * ATK_TEXT_BOUNDARY_LINE_END a complete line is returned.
201  *
202  * Returns: the text at @offset up to the specified @boundary_type.
203  **/
204 gchar*
205 atk_text_get_text_at_offset (AtkText          *text,
206                              gint             offset,
207                              AtkTextBoundary  boundary_type)
208 {
209   AtkTextIface *iface;
210
211   g_return_val_if_fail (text != NULL, NULL);
212   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
213
214   iface = ATK_TEXT_GET_IFACE (text);
215
216   if (iface->get_text_at_offset)
217     return (*(iface->get_text_at_offset)) (text, offset, boundary_type);
218   else
219     return NULL;
220 }
221
222 /**
223  * atk_text_get_text_before_offset
224  * @text: an #AtkText
225  * @offset: position
226  * @boundary_type: An #AtkTextBoundary
227  *
228  * Gets the specified text.
229  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
230  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
231  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
232  * will be at the start of the sentence, and will continue to the offset. 
233  * The last word may not be a complete word. Similarly for 
234  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
235  * ATK_TEXT_BOUNDARY_LINE_END
236  *
237  * Returns: the text before @offset starting from the specified @boundary_type.
238  **/
239 gchar*
240 atk_text_get_text_before_offset (AtkText          *text,
241                                  gint             offset,
242                                  AtkTextBoundary  boundary_type)
243 {
244   AtkTextIface *iface;
245
246   g_return_val_if_fail (text != NULL, NULL);
247   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
248
249   iface = ATK_TEXT_GET_IFACE (text);
250
251   if (iface->get_text_before_offset)
252     return (*(iface->get_text_before_offset)) (text, offset, boundary_type);
253   else
254     return NULL;
255 }
256
257 /**
258  * atk_text_get_caret_offset
259  * @text: an #AtkText
260  *
261  * Gets the offset position of the caret (cursor).
262  *
263  * Returns: the offset position of the caret (cursor), or -1 if
264  *    one does not exist (or is not supported by the widget).
265  **/
266 gint
267 atk_text_get_caret_offset (AtkText *text)
268 {
269   AtkTextIface *iface;
270
271   g_return_val_if_fail (text != NULL, -1);
272   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
273
274   iface = ATK_TEXT_GET_IFACE (text);
275
276   if (iface->get_caret_offset)
277     return (*(iface->get_caret_offset)) (text);
278   else
279     return -1;
280 }
281
282 /**
283  * atk_text_get_character_extents
284  * @text: an #AtkText
285  * @offset: position
286  * @x: x-position of character
287  * @y: y-position of character
288  * @length: length of character
289  * @width: width of character
290  *
291  * Given an @offset, the @x, @y, @length, and @width values are filled
292  * appropriately.
293  **/
294 void
295 atk_text_get_character_extents (AtkText *text,
296                                 gint offset,
297                                 gint *x,
298                                 gint *y,
299                                 gint *length,
300                                 gint *width)
301 {
302   AtkTextIface *iface;
303
304   g_return_if_fail (text != NULL);
305   g_return_if_fail (ATK_IS_TEXT (text));
306
307   iface = ATK_TEXT_GET_IFACE (text);
308
309   if (iface->get_character_extents)
310     (*(iface->get_character_extents)) (text, offset, x, y, length, width);
311   else
312     {
313       *x = 0;
314       *x = 0;
315       *length = 0;
316       *width = 0;
317     }
318 }
319
320 /**
321  *atk_text_ref_run_attributes:
322  *@text: an #AtkText
323  *@offset: the offset at which to get the attributes
324  *@start_offset: the address to put the start offset of the range
325  *@end_offset: the address to put the end offset of the range
326  *
327  *Creates an #AtkAttributeSet which consists of the attributes explicitly
328  *set at the position @offset in the text. @start_offset and @end_offset are
329  *set to the start and end of the range around @offset where the attributes are
330  *invariant.
331  *
332  *Returns: an #AtkAttributeSet which contains the attributes explicitly set
333  *at @offset
334  **/
335 AtkAttributeSet* atk_text_ref_run_attributes              (AtkText          *text,
336                                                            gint             offset,
337                                                            gint             *start_offset,
338                                                            gint             *end_offset)
339 {
340   AtkTextIface *iface;
341
342   g_return_val_if_fail (text != NULL, NULL);
343   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
344
345   iface = ATK_TEXT_GET_IFACE (text);
346
347   if (iface->ref_run_attributes)
348     return (*(iface->ref_run_attributes)) (text, offset, start_offset, end_offset);
349   else
350     return NULL;
351 }
352
353 /**
354  * atk_text_get_character_count
355  * @text: an #AtkText
356  *
357  * Gets the character count.
358  *
359  * Returns: the number of characters.
360  **/
361 gint
362 atk_text_get_character_count (AtkText *text)
363 {
364   AtkTextIface *iface;
365
366   g_return_val_if_fail (text != NULL, -1);
367   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
368
369   iface = ATK_TEXT_GET_IFACE (text);
370
371   if (iface->get_character_count)
372     return (*(iface->get_character_count)) (text);
373   else
374     return -1;
375 }
376
377 /**
378  * atk_text_get_offset_at_point
379  * @text: an #AtkText
380  * @x: screen x-position of character
381  * @y: screen y-position of character
382  *
383  * Gets the x,y screen coordinates of the specified character.
384  *
385  * Returns: the offset to the character which is located at
386  * the specified @x and @y coordinates.
387  **/
388 gint
389 atk_text_get_offset_at_point (AtkText *text,
390                               gint x,
391                               gint y)
392 {
393   AtkTextIface *iface;
394
395   g_return_val_if_fail (text != NULL, -1);
396   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
397
398   iface = ATK_TEXT_GET_IFACE (text);
399
400   if (iface->get_offset_at_point)
401     return (*(iface->get_offset_at_point)) (text, x, y);
402   else
403     return -1;
404 }
405
406 /**
407  * atk_text_get_n_selections
408  * @text: an #AtkText
409  *
410  * Gets the number of selected regions.
411  *
412  * Returns: The number of selected regions, or -1 if a failure
413  *   occurred.
414  **/
415 gint
416 atk_text_get_n_selections (AtkText *text)
417 {
418   AtkTextIface *iface;
419
420   g_return_val_if_fail (text != NULL, -1);
421   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
422
423   iface = ATK_TEXT_GET_IFACE (text);
424
425   if (iface->get_n_selections)
426     return (*(iface->get_n_selections)) (text);
427   else
428     return -1;
429 }
430
431 /**
432  * atk_text_get_selection
433  * @text: an #AtkText
434  * @selection_num: The selection number.  The selected regions are
435  * assigned numbers that corrispond to how far the region is from the
436  * start of the text.  The selected region closest to the beginning
437  * of the text region is assigned the number 0, etc.  Note that adding,
438  * moving or deleting a selected region can change the numbering.
439  * @start_offset: passes back the start position of the selected region
440  * @end_offset: passes back the end position of the selected region
441  *
442  * Gets the text from the specified selection.
443  *
444  * Returns: the selected text.
445  **/
446 gchar*
447 atk_text_get_selection (AtkText *text, gint selection_num,
448    gint *start_offset, gint *end_offset)
449 {
450   AtkTextIface *iface;
451
452   g_return_val_if_fail (text != NULL, NULL);
453   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
454
455   iface = ATK_TEXT_GET_IFACE (text);
456
457   if (iface->get_selection)
458   {
459     return (*(iface->get_selection)) (text, selection_num,
460        start_offset, end_offset);
461   }
462   else
463     return NULL;
464 }
465
466 /**
467  * atk_text_add_selection
468  * @text: an #AtkText
469  * @start_offset: the start position of the selected region
470  * @end_offset: the end position of the selected region
471  *
472  * Adds a selection bounded by the specified offsets.
473  *
474  * Returns: %TRUE if success, %FALSE otherwise
475  **/
476 gboolean
477 atk_text_add_selection (AtkText *text, gint start_offset,
478    gint end_offset)
479 {
480   AtkTextIface *iface;
481
482   g_return_val_if_fail (text != NULL, FALSE);
483   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
484
485   iface = ATK_TEXT_GET_IFACE (text);
486
487   if (iface->add_selection)
488     return (*(iface->add_selection)) (text, start_offset, end_offset);
489   else
490     return FALSE;
491 }
492
493 /**
494  * atk_text_remove_selection
495  * @text: an #AtkText
496  * @selection_num: The selection number.  The selected regions are
497  * assigned numbers that corrispond to how far the region is from the
498  * start of the text.  The selected region closest to the beginning
499  * of the text region is assigned the number 0, etc.  Note that adding,
500  * moving or deleting a selected region can change the numbering.
501  *
502  * Removes the specified selection
503  *
504  * Returns: %TRUE if success, %FALSE otherwise
505  **/
506 gboolean
507 atk_text_remove_selection (AtkText *text, gint selection_num)
508 {
509   AtkTextIface *iface;
510
511   g_return_val_if_fail (text != NULL, FALSE);
512   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
513
514   iface = ATK_TEXT_GET_IFACE (text);
515
516   if (iface->remove_selection)
517     return (*(iface->remove_selection)) (text, selection_num);
518   else
519     return FALSE;
520 }
521
522 /**
523  * atk_text_set_selection
524  * @text: an #AtkText
525  * @selection_num: The selection number.  The selected regions are
526  * assigned numbers that corrispond to how far the region is from the
527  * start of the text.  The selected region closest to the beginning
528  * of the text region is assigned the number 0, etc.  Note that adding,
529  * moving or deleting a selected region can change the numbering.
530  * @start_offset: the new start position of the selection
531  * @end_offset: the new end position of the selection
532  *
533  * Changes the start and end offset of the specified selection
534  *
535  * Returns: %TRUE if success, %FALSE otherwise
536  **/
537 gboolean
538 atk_text_set_selection (AtkText *text, gint selection_num,
539    gint start_offset, gint end_offset)
540 {
541   AtkTextIface *iface;
542
543   g_return_val_if_fail (text != NULL, FALSE);
544   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
545
546   iface = ATK_TEXT_GET_IFACE (text);
547
548   if (iface->set_selection)
549   {
550     return (*(iface->set_selection)) (text, selection_num,
551        start_offset, end_offset);
552   }
553   else
554     return FALSE;
555 }
556
557 /**
558  *atk_text_set_run_attributes:
559  *@text: an #AtkText
560  *@attrib: an #AtkAttributeSet
561  *@start_offset: start of range in which to set attributes
562  *@end_offset: end of range in which to set attributes
563  *
564  *Sets the attributes for a specified range
565  *
566  *Returns: %TRUE if attributes successfully set for the specified
567  *range, otherwise %FALSE
568  **/
569 gboolean
570 atk_text_set_run_attributes (AtkText *text,
571                              AtkAttributeSet *attrib,
572                              gint start_offset,
573                              gint end_offset)
574 {
575   AtkTextIface *iface;
576
577   g_return_val_if_fail (text != NULL, FALSE);
578   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
579
580   iface = ATK_TEXT_GET_IFACE (text);
581
582   if (iface->set_run_attributes)
583     {
584       return (*(iface->set_run_attributes)) (text, attrib, start_offset, end_offset);
585     }
586   else
587     {
588       return FALSE;
589     }
590 }
591
592 /**
593  * atk_text_set_caret_offset
594  * @text: an #AtkText
595  * @offset: position
596  *
597  * Sets the caret (cursor) position to the specified @offset.
598  *
599  * Returns: %TRUE if success, %FALSE otherwise.
600  **/
601 gboolean
602 atk_text_set_caret_offset (AtkText *text,
603                            gint    offset)
604 {
605   AtkTextIface *iface;
606
607   g_return_val_if_fail (text != NULL, FALSE);
608   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
609
610   iface = ATK_TEXT_GET_IFACE (text);
611
612   if (iface->set_caret_offset)
613     {
614       return (*(iface->set_caret_offset)) (text, offset);
615     }
616   else
617     {
618       return FALSE;
619     }
620 }