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