Clarified behavior of atk_text_get_text_... interfaces
[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
22 enum {
23   TEXT_CHANGED,
24   CARET_MOVED,
25   LAST_SIGNAL
26 };
27
28 struct _AtkTextIfaceClass
29 {
30   GObjectClass parent;
31 };
32
33 typedef struct _AtkTextIfaceClass AtkTextIfaceClass;
34
35 static void atk_text_base_init (gpointer *g_class);
36
37 static guint atk_text_signals[LAST_SIGNAL] = { 0 };
38
39 GType
40 atk_text_get_type ()
41 {
42   static GType type = 0;
43
44   if (!type) 
45     {
46       static const GTypeInfo tinfo =
47       {
48         sizeof (AtkTextIface),
49         (GBaseInitFunc) atk_text_base_init,
50         (GBaseFinalizeFunc) NULL,
51         (GClassInitFunc) NULL /* atk_text_interface_init */ ,
52         (GClassFinalizeFunc) NULL,
53
54       };
55
56       type = g_type_register_static (G_TYPE_INTERFACE, "AtkText", &tinfo, 0);
57     }
58
59   return type;
60 }
61
62 static void
63 atk_text_base_init (gpointer *g_class)
64 {
65   static gboolean initialized = FALSE;
66
67   if (! initialized)
68     {
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                      NULL, NULL,
81                      g_cclosure_marshal_VOID__VOID,
82                      G_TYPE_NONE,
83                      0, G_TYPE_NONE);
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                      NULL, NULL,
91                      g_cclosure_marshal_VOID__INT,
92                      G_TYPE_NONE,
93                      1, G_TYPE_INT);
94   }
95 }
96
97 /**
98  * atk_text_get_text:
99  * @text: an #AtkText
100  * @start_offset: start position
101  * @end_offset: end position
102  *
103  * Returns: the text from @start_offset up to, but not including @end_offset.
104  **/
105 gchar*
106 atk_text_get_text (AtkText      *text,
107                    gint         start_offset,
108                    gint         end_offset)
109 {
110   AtkTextIface *iface;
111
112   g_return_val_if_fail (text != NULL, NULL);
113   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
114
115   iface = ATK_TEXT_GET_IFACE (text);
116
117   if (iface->get_text)
118     return (*(iface->get_text)) (text, start_offset, end_offset);
119   else
120     return NULL;
121 }
122
123 /**
124  * atk_text_get_character_at_offset
125  * @text: an #AtkText
126  * @offset: position
127  *
128  * Returns: the character at @offset.
129  **/
130 gunichar
131 atk_text_get_character_at_offset (AtkText      *text,
132                                   gint         offset)
133 {
134   AtkTextIface *iface;
135
136   g_return_val_if_fail (text != NULL, (gunichar) 0);
137   g_return_val_if_fail (ATK_IS_TEXT (text), (gunichar) 0);
138
139   iface = ATK_TEXT_GET_IFACE (text);
140
141   if (iface->get_character_at_offset)
142     return (*(iface->get_character_at_offset)) (text, offset);
143   else
144     return (gunichar) 0;
145 }
146
147 /**
148  * atk_text_get_text_after_offset
149  * @text: an #AtkText
150  * @offset: position
151  * @boundary_type: An #AtkTextBoundary
152  *
153  * Returns: the text after @offset up to the specified @boundary_type.
154  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
155  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
156  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
157  * will be the offset and will continue to the start of the next sentence. 
158  * The first word may not be a complete word. Similarly for 
159  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
160  * ATK_TEXT_BOUNDARY_LINE_END
161  **/
162 gchar*
163 atk_text_get_text_after_offset (AtkText          *text,
164                                 gint             offset,
165                                 AtkTextBoundary  boundary_type)
166 {
167   AtkTextIface *iface;
168
169   g_return_val_if_fail (text != NULL, NULL);
170   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
171
172   iface = ATK_TEXT_GET_IFACE (text);
173
174   if (iface->get_text_after_offset)
175     return (*(iface->get_text_after_offset)) (text, offset, boundary_type);
176   else
177     return NULL;
178 }
179
180 /**
181  * atk_text_get_text_at_offset
182  * @text: an #AtkText
183  * @offset: position
184  * @boundary_type: An #AtkTextBoundary
185  *
186  * Returns: the text at @offset up to the specified @boundary_type.
187  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START or 
188  * ATK_TEXT_BOUNDARY_WORD_END a complete word is returned; 
189  * if the boundary type is  ATK_TEXT_BOUNDARY_SENTENCE_START or 
190  * ATK_TEXT_BOUNDARY_SENTENCE_END a complete sentence
191  * is returned; if the boundary type is ATK_TEXT_BOUNDARY_LINE_START or
192  * ATK_TEXT_BOUNDARY_LINE_END a complete line is returned.
193  **/
194 gchar*
195 atk_text_get_text_at_offset (AtkText          *text,
196                              gint             offset,
197                              AtkTextBoundary  boundary_type)
198 {
199   AtkTextIface *iface;
200
201   g_return_val_if_fail (text != NULL, NULL);
202   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
203
204   iface = ATK_TEXT_GET_IFACE (text);
205
206   if (iface->get_text_at_offset)
207     return (*(iface->get_text_at_offset)) (text, offset, boundary_type);
208   else
209     return NULL;
210 }
211
212 /**
213  * atk_text_get_text_before_offset
214  * @text: an #AtkText
215  * @offset: position
216  * @boundary_type: An #AtkTextBoundary
217  *
218  * Returns: the text before @offset starting from the specified @boundary_type.
219  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
220  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
221  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
222  * will be at the start of the sentence, and will continue to the offset. 
223  * The last word may not be a complete word. Similarly for 
224  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
225  * ATK_TEXT_BOUNDARY_LINE_END
226  **/
227 gchar*
228 atk_text_get_text_before_offset (AtkText          *text,
229                                  gint             offset,
230                                  AtkTextBoundary  boundary_type)
231 {
232   AtkTextIface *iface;
233
234   g_return_val_if_fail (text != NULL, NULL);
235   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
236
237   iface = ATK_TEXT_GET_IFACE (text);
238
239   if (iface->get_text_before_offset)
240     return (*(iface->get_text_before_offset)) (text, offset, boundary_type);
241   else
242     return NULL;
243 }
244
245 /**
246  * atk_text_get_caret_offset
247  * @text: an #AtkText
248  *
249  * Returns: the position of the caret (cursor).
250  **/
251 gint
252 atk_text_get_caret_offset (AtkText *text)
253 {
254   AtkTextIface *iface;
255
256   g_return_val_if_fail (text != NULL, -1);
257   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
258
259   iface = ATK_TEXT_GET_IFACE (text);
260
261   if (iface->get_caret_offset)
262     return (*(iface->get_caret_offset)) (text);
263   else
264     return -1;
265 }
266
267 /**
268  * atk_text_get_row_col_at_offset
269  * @text: an #AtkText
270  * @offset: position
271  * @row: row number
272  * @col: column number
273  *
274  * Given an @offset, the @row and @col arguments are filled appropriately.
275  **/
276 void
277 atk_text_get_row_col_at_offset (AtkText *text,
278                                 gint offset,
279                                 gint *row,
280                                 gint *col)
281 {
282   AtkTextIface *iface;
283
284   g_return_if_fail (text != NULL);
285   g_return_if_fail (ATK_IS_TEXT (text));
286
287   iface = ATK_TEXT_GET_IFACE (text);
288
289   if (iface->get_row_col_at_offset)
290     (*(iface->get_row_col_at_offset)) (text, offset, row, col);
291   else
292     {
293       *row = 0;
294       *col = 0;
295     }
296 }
297
298 /**
299  * atk_text_get_range_attributes
300  * @text: an #AtkText
301  * @start_offset: start position
302  * @end_offset: end position
303  *
304  * Returns a #PangoAttrList with the text attributes between the
305  * @start_offset and the @end_offset.
306  **/
307 PangoAttrList*
308 atk_text_get_range_attributes (AtkText *text,
309                                gint start_offset,
310                                gint end_offset)
311 {
312   AtkTextIface *iface;
313
314   g_return_val_if_fail (text != NULL, NULL);
315   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
316
317   iface = ATK_TEXT_GET_IFACE (text);
318
319   if (iface->get_range_attributes)
320     return (*(iface->get_range_attributes)) (text, start_offset, end_offset);
321   else
322     return NULL;
323 }
324
325 /**
326  * atk_text_get_character_extents
327  * @text: an #AtkText
328  * @offset: position
329  * @x: x-position of character
330  * @y: y-position of character
331  * @length: length of character
332  * @width: width of character
333  *
334  * Given an @offset, the @x, @y, @length, and @width values are filled
335  * appropriately.
336  **/
337 void
338 atk_text_get_character_extents (AtkText *text,
339                                 gint offset,
340                                 gint *x,
341                                 gint *y,
342                                 gint *length,
343                                 gint *width)
344 {
345   AtkTextIface *iface;
346
347   g_return_if_fail (text != NULL);
348   g_return_if_fail (ATK_IS_TEXT (text));
349
350   iface = ATK_TEXT_GET_IFACE (text);
351
352   if (iface->get_character_extents)
353     (*(iface->get_character_extents)) (text, offset, x, y, length, width);
354   else
355     {
356       *x = 0;
357       *x = 0;
358       *length = 0;
359       *width = 0;
360     }
361 }
362
363 /**
364  * atk_text_get_character_count
365  * @text: an #AtkText
366  *
367  * Returns: the number of characters.
368  **/
369 gint
370 atk_text_get_character_count (AtkText *text)
371 {
372   AtkTextIface *iface;
373
374   g_return_val_if_fail (text != NULL, -1);
375   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
376
377   iface = ATK_TEXT_GET_IFACE (text);
378
379   if (iface->get_character_count)
380     return (*(iface->get_character_count)) (text);
381   else
382     return -1;
383 }
384
385 /**
386  * atk_text_get_offset_at_point
387  * @text: an #AtkText
388  * @x: x-position of character
389  * @y: y-position of character
390  *
391  * Returns: the offset to the character which is located at
392  * the specified @x and @y coordinates.
393  **/
394 gint
395 atk_text_get_offset_at_point (AtkText *text,
396                               gint x,
397                               gint y)
398 {
399   AtkTextIface *iface;
400
401   g_return_val_if_fail (text != NULL, -1);
402   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
403
404   iface = ATK_TEXT_GET_IFACE (text);
405
406   if (iface->get_offset_at_point)
407     return (*(iface->get_offset_at_point)) (text, x, y);
408   else
409     return -1;
410 }
411
412 /**
413  * atk_text_get_selected_text
414  * @text: an #AtkText
415  *
416  * Returns: the selected text.
417  **/
418 gchar*
419 atk_text_get_selected_text (AtkText *text)
420 {
421   AtkTextIface *iface;
422
423   g_return_val_if_fail (text != NULL, NULL);
424   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
425
426   iface = ATK_TEXT_GET_IFACE (text);
427
428   if (iface->get_selected_text)
429     return (*(iface->get_selected_text)) (text);
430   else
431     return NULL;
432 }
433
434 /**
435  * atk_text_get_selection_bounds
436  * @text: an #AtkText
437  * @start_offset: start position
438  * @end_offset: end position
439  *
440  * @start_offset and @end_offset are filled with the
441  * current selection bounds.
442  **/
443 void
444 atk_text_get_selection_bounds (AtkText *text,
445                                gint    *start_offset,
446                                gint    *end_offset)
447 {
448   AtkTextIface *iface;
449
450   g_return_if_fail (text != NULL);
451   g_return_if_fail (ATK_IS_TEXT (text));
452
453   iface = ATK_TEXT_GET_IFACE (text);
454
455   if (iface->get_selection_bounds)
456     (*(iface->get_selection_bounds)) (text, start_offset, end_offset);
457   else
458   {
459     *start_offset = 0;
460     *end_offset = 0;
461   }
462 }
463
464 /**
465  * atk_text_set_selection_bounds
466  * @text: an #AtkText
467  * @start_offset: start position
468  * @end_offset: end position
469  *
470  * The selection bounds are set to the specified @start_offset
471  * and @end_offset values.
472  * 
473  * Returns: %TRUE if success, %FALSE otherwise.
474  **/
475 gboolean
476 atk_text_set_selection_bounds (AtkText *text,
477                                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->set_selection_bounds)
488     {
489       return (*(iface->set_selection_bounds)) (text, start_offset, end_offset);
490     }
491   else
492     {
493       return FALSE;
494     }
495 }
496
497 /**
498  * atk_text_set_caret_offset
499  * @text: an #AtkText
500  * @offset: position
501  *
502  * Sets the caret (cursor) position to the specified @offset.
503  *
504  * Returns: %TRUE if success, %FALSE otherwise.
505  **/
506 gboolean
507 atk_text_set_caret_offset (AtkText *text,
508                            gint    offset)
509 {
510   AtkTextIface *iface;
511
512   g_return_val_if_fail (text != NULL, FALSE);
513   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
514
515   iface = ATK_TEXT_GET_IFACE (text);
516
517   if (iface->set_caret_offset)
518     {
519       return (*(iface->set_caret_offset)) (text, offset);
520     }
521   else
522     {
523       return FALSE;
524     }
525 }