No issues found
1 /* GAIL - The GNOME Accessibility Implementation Library
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 Lesser 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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser 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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <gtk/gtk.h>
25 #include <libgnomecanvas/libgnomecanvas.h>
26 #include "gailcanvasitem.h"
27 #include "gailcanvastext.h"
28 #include <libgail-util/gail-util.h>
29
30 struct _GailCanvasText
31 {
32 GailCanvasItem parent;
33 GailTextUtil *textutil;
34 };
35
36 static void gail_canvas_text_text_interface_init (AtkTextIface *iface);
37 static gchar * gail_canvas_text_get_text (AtkText *text,
38 gint start_offset,
39 gint end_offset);
40 static gchar * gail_canvas_text_get_text_after_offset
41 (AtkText *text,
42 gint offset,
43 AtkTextBoundary boundary_type,
44 gint *start_offset,
45 gint *end_offset);
46 static gchar * gail_canvas_text_get_text_at_offset (AtkText *text,
47 gint offset,
48 AtkTextBoundary boundary_type,
49 gint *start_offset,
50 gint *end_offset);
51 static gchar * gail_canvas_text_get_text_before_offset
52 (AtkText *text,
53 gint offset,
54 AtkTextBoundary boundary_type,
55 gint *start_offset,
56 gint *end_offset);
57 static gunichar gail_canvas_text_get_character_at_offset
58 (AtkText *text,
59 gint offset);
60 static gint gail_canvas_text_get_character_count (AtkText *text);
61 static gint gail_canvas_text_get_caret_offset (AtkText *text);
62 static gboolean gail_canvas_text_set_caret_offset (AtkText *text,
63 gint offset);
64 static gint gail_canvas_text_get_offset_at_point (AtkText *text,
65 gint x,
66 gint y,
67 AtkCoordType coords);
68 static void gail_canvas_text_get_character_extents (AtkText *text,
69 gint offset,
70 gint *x,
71 gint *y,
72 gint *width,
73 gint *height,
74 AtkCoordType coords);
75 static AtkAttributeSet *
76 gail_canvas_text_get_run_attributes (AtkText *text,
77 gint offset,
78 gint *start_offset,
79 gint *end_offset);
80 static AtkAttributeSet *
81 gail_canvas_text_get_default_attributes (AtkText *text);
82 static gint gail_canvas_text_get_n_selections (AtkText *text);
83 static gchar * gail_canvas_text_get_selection (AtkText *text,
84 gint selection_num,
85 gint *start_pos,
86 gint *end_pos);
87 static gboolean gail_canvas_text_add_selection (AtkText *text,
88 gint start_pos,
89 gint end_pos);
90 static gboolean gail_canvas_text_remove_selection (AtkText *text,
91 gint selection_num);
92 static gboolean gail_canvas_text_set_selection (AtkText *text,
93 gint selection_num,
94 gint start_pos,
95 gint end_pos);
96 static gchar * get_text_near_offset (AtkText *text,
97 GailOffsetType function,
98 AtkTextBoundary boundary_type,
99 gint offset,
100 gint *start_offset,
101 gint *end_offset);
102
103 G_DEFINE_TYPE_WITH_CODE (GailCanvasText,
104 gail_canvas_text,
105 GAIL_TYPE_CANVAS_ITEM,
106 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT,
107 gail_canvas_text_text_interface_init);)
108
109 static void
110 gail_canvas_text_init (GailCanvasText *foo)
111 {
112 ;
113 }
114
115 AtkObject *
116 gail_canvas_text_new (GObject *obj)
117 {
118 gpointer object;
119 AtkObject *atk_object;
120 GailCanvasText *gail_text;
121
122 g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (obj), NULL);
123 object = g_object_new (GAIL_TYPE_CANVAS_TEXT, NULL);
124 atk_object = ATK_OBJECT (object);
125 gail_text = GAIL_CANVAS_TEXT (object);
126
127 atk_object_initialize (atk_object, obj);
128 gail_text->textutil = gail_text_util_new ();
129
130 if (GNOME_IS_CANVAS_TEXT (obj))
131 {
132 gail_text_util_text_setup (gail_text->textutil,
133 GNOME_CANVAS_TEXT (obj)->text);
134 }
135
136 atk_object->role = ATK_ROLE_TEXT;
137 return atk_object;
138 }
139
140 static void
141 gail_canvas_text_class_init (GailCanvasTextClass *klass)
142 {
143 }
144
145 static void
146 gail_canvas_text_text_interface_init (AtkTextIface *iface)
147 {
148 g_return_if_fail (iface != NULL);
149
150 iface->get_text = gail_canvas_text_get_text;
151 iface->get_text_after_offset = gail_canvas_text_get_text_after_offset;
152 iface->get_text_at_offset = gail_canvas_text_get_text_at_offset;
153 iface->get_text_before_offset = gail_canvas_text_get_text_before_offset;
154 iface->get_character_at_offset = gail_canvas_text_get_character_at_offset;
155 iface->get_character_count = gail_canvas_text_get_character_count;
156 iface->get_caret_offset = gail_canvas_text_get_caret_offset;
157 iface->set_caret_offset = gail_canvas_text_set_caret_offset;
158 iface->get_offset_at_point = gail_canvas_text_get_offset_at_point;
159 iface->get_character_extents = gail_canvas_text_get_character_extents;
160 iface->get_n_selections = gail_canvas_text_get_n_selections;
161 iface->get_selection = gail_canvas_text_get_selection;
162 iface->add_selection = gail_canvas_text_add_selection;
163 iface->remove_selection = gail_canvas_text_remove_selection;
164 iface->set_selection = gail_canvas_text_set_selection;
165 iface->get_run_attributes = gail_canvas_text_get_run_attributes;
166 iface->get_default_attributes = gail_canvas_text_get_default_attributes;
167 }
168
169 static gchar *
170 gail_canvas_text_get_text (AtkText *text,
171 gint start_offset,
172 gint end_offset)
173 {
174 GailCanvasText *gail_text;
175 GtkTextBuffer *buffer;
176 GtkTextIter start, end;
177
178 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), NULL);
179 gail_text = GAIL_CANVAS_TEXT (text);
180 g_return_val_if_fail (gail_text->textutil, NULL);
181
182 buffer = gail_text->textutil->buffer;
183 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
184 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
185
186 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
187 }
188
189 static gchar *
190 gail_canvas_text_get_text_after_offset (AtkText *text,
191 gint offset,
192 AtkTextBoundary boundary_type,
193 gint *start_offset,
194 gint *end_offset)
195 {
196 return get_text_near_offset (text, GAIL_AFTER_OFFSET,
197 boundary_type, offset,
198 start_offset, end_offset);
199 }
200
201 static gchar *
202 gail_canvas_text_get_text_at_offset (AtkText *text,
203 gint offset,
204 AtkTextBoundary boundary_type,
205 gint *start_offset,
206 gint *end_offset)
207 {
208 return get_text_near_offset (text, GAIL_AT_OFFSET,
209 boundary_type, offset,
210 start_offset, end_offset);
211 }
212
213 static gchar *
214 gail_canvas_text_get_text_before_offset (AtkText *text,
215 gint offset,
216 AtkTextBoundary boundary_type,
217 gint *start_offset,
218 gint *end_offset)
219 {
220 return get_text_near_offset (text, GAIL_BEFORE_OFFSET,
221 boundary_type, offset,
222 start_offset, end_offset);
223 }
224
225 static gunichar
226 gail_canvas_text_get_character_at_offset (AtkText *text,
227 gint offset)
228 {
229 GailCanvasText *gail_item;
230 GtkTextIter start, end;
231 GtkTextBuffer *buffer;
232 gchar *string;
233 gchar *index;
234 gunichar unichar;
235
236 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), '\0');
237 gail_item = GAIL_CANVAS_TEXT (text);
238 buffer = gail_item->textutil->buffer;
239 if (offset >= gtk_text_buffer_get_char_count (buffer))
240 return '\0';
241
242 gtk_text_buffer_get_start_iter (buffer, &start);
243 gtk_text_buffer_get_end_iter (buffer, &end);
244 string = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
245 index = g_utf8_offset_to_pointer (string, offset);
246
247 unichar = g_utf8_get_char (index);
248 g_free (string);
249 return unichar;
250 }
251
252 static gint
253 gail_canvas_text_get_character_count (AtkText *text)
254 {
255 GtkTextBuffer *buffer;
256 GailCanvasText *gail_text;
257
258 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), 0);
259 gail_text = GAIL_CANVAS_TEXT (text);
260 g_return_val_if_fail (gail_text->textutil, 0);
261 buffer = gail_text->textutil->buffer;
262 return gtk_text_buffer_get_char_count (buffer);
263 }
264
265 static gint
266 gail_canvas_text_get_caret_offset (AtkText *text)
267 {
268 GailCanvasText *gail_text;
269 GtkTextBuffer *buffer;
270 GtkTextMark *cursor_mark;
271 GtkTextIter cursor_itr;
272
273 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), 0);
274 gail_text = GAIL_CANVAS_TEXT (text);
275 g_return_val_if_fail (gail_text->textutil, 0);
276 buffer = gail_text->textutil->buffer;
277 cursor_mark = gtk_text_buffer_get_insert (buffer);
278 gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
279 return gtk_text_iter_get_offset (&cursor_itr);
280 }
281
282 static gboolean
283 gail_canvas_text_set_caret_offset (AtkText *text,
284 gint offset)
285 {
286 GailCanvasText *gail_text;
287 GtkTextBuffer *buffer;
288 GtkTextIter pos_itr;
289
290 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), FALSE);
291 gail_text = GAIL_CANVAS_TEXT (text);
292 g_return_val_if_fail (gail_text->textutil, FALSE);
293 buffer = gail_text->textutil->buffer;
294 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, offset);
295 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
296 return TRUE;
297 }
298
299 static gint
300 gail_canvas_text_get_offset_at_point (AtkText *text,
301 gint x,
302 gint y,
303 AtkCoordType coords)
304 {
305 return -1;
306 }
307
308 static void
309 gail_canvas_text_get_character_extents (AtkText *text,
310 gint offset,
311 gint *x,
312 gint *y,
313 gint *width,
314 gint *height,
315 AtkCoordType coords)
316 {
317 return;
318 }
319
320 static AtkAttributeSet *
321 gail_canvas_text_get_run_attributes (AtkText *text,
322 gint offset,
323 gint *start_offset,
324 gint *end_offset)
325 {
326 GailCanvasText *gail_text;
327
328 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), NULL);
329 gail_text = GAIL_CANVAS_TEXT (text);
330 g_return_val_if_fail (gail_text->textutil, NULL);
331
332 return gail_misc_buffer_get_run_attributes (gail_text->textutil->buffer,
333 offset, start_offset, end_offset);
334 }
335
336 static AtkAttributeSet *
337 gail_canvas_text_get_default_attributes (AtkText *text)
338 {
339 return NULL;
340 }
341
342 static gint
343 gail_canvas_text_get_n_selections (AtkText *text)
344 {
345 GailCanvasText *gail_text;
346 GtkTextBuffer *buffer;
347 GtkTextIter start, end;
348 gint select_start, select_end;
349
350 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), -1);
351 gail_text = GAIL_CANVAS_TEXT (text);
352 g_return_val_if_fail (gail_text->textutil, -1);
353 buffer = gail_text->textutil->buffer;
354
355 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
356 select_start = gtk_text_iter_get_offset (&start);
357 select_end = gtk_text_iter_get_offset (&end);
358
359 if (select_start != select_end)
360 return 1;
361 else
362 return 0;
363 }
364
365 static gchar *
366 gail_canvas_text_get_selection (AtkText *text,
367 gint selection_num,
368 gint *start_pos,
369 gint *end_pos)
370 {
371 GailCanvasText *gail_text;
372 GtkTextBuffer *buffer;
373 GtkTextIter start, end;
374
375 /* Only let the user get the selection if one is set, and if the
376 * selection_num is 0.
377 */
378 if (selection_num != 0)
379 return NULL;
380
381 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), NULL);
382 gail_text = GAIL_CANVAS_TEXT (text);
383 g_return_val_if_fail (gail_text->textutil, NULL);
384 buffer = gail_text->textutil->buffer;
385
386 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
387 *start_pos = gtk_text_iter_get_offset (&start);
388 *end_pos = gtk_text_iter_get_offset (&end);
389
390 if (*start_pos != *end_pos)
391 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
392 else
393 return NULL;
394 }
395
396 static gboolean
397 gail_canvas_text_add_selection (AtkText *text,
398 gint start_pos,
399 gint end_pos)
400 {
401 GailCanvasText *gail_text;
402 GtkTextBuffer *buffer;
403 GtkTextIter pos_itr;
404 GtkTextIter start, end;
405 gint select_start, select_end;
406
407 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), FALSE);
408 gail_text = GAIL_CANVAS_TEXT (text);
409 g_return_val_if_fail (gail_text->textutil, FALSE);
410 buffer = gail_text->textutil->buffer;
411
412 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
413 select_start = gtk_text_iter_get_offset (&start);
414 select_end = gtk_text_iter_get_offset (&end);
415
416 /* If there is already a selection, then don't allow another to be added,
417 * since GtkTextView only supports one selected region.
418 */
419 if (select_start == select_end)
420 {
421 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
422 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
423 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
424 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
425 return TRUE;
426 }
427 else
428 return FALSE;
429 }
430
431 static gboolean
432 gail_canvas_text_remove_selection (AtkText *text,
433 gint selection_num)
434 {
435 GailCanvasText *gail_text;
436 GtkTextBuffer *buffer;
437 GtkTextMark *cursor_mark;
438 GtkTextIter cursor_itr;
439 GtkTextIter start, end;
440 gint select_start, select_end;
441
442 if (selection_num != 0)
443 return FALSE;
444
445 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), FALSE);
446 gail_text = GAIL_CANVAS_TEXT (text);
447 g_return_val_if_fail (gail_text->textutil, FALSE);
448 buffer = gail_text->textutil->buffer;
449
450 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
451 select_start = gtk_text_iter_get_offset (&start);
452 select_end = gtk_text_iter_get_offset (&end);
453
454 if (select_start != select_end)
455 {
456 /* Setting the start & end of the selected region to the caret position
457 * turns off the selection.
458 */
459 cursor_mark = gtk_text_buffer_get_insert (buffer);
460 gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
461 gtk_text_buffer_move_mark_by_name (buffer, "insert", &cursor_itr);
462 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
463 return TRUE;
464 }
465 else
466 return FALSE;
467 }
468
469 static gboolean
470 gail_canvas_text_set_selection (AtkText *text,
471 gint selection_num,
472 gint start_pos,
473 gint end_pos)
474 {
475 GailCanvasText *gail_text;
476 GtkTextBuffer *buffer;
477 GtkTextIter pos_itr;
478 GtkTextIter start, end;
479 gint select_start, select_end;
480
481 /* Only let the user move the selection if one is set, and if the
482 * selection_num is 0
483 */
484 if (selection_num != 0)
485 return FALSE;
486
487 g_return_val_if_fail (GAIL_IS_CANVAS_TEXT (text), FALSE);
488 gail_text = GAIL_CANVAS_TEXT (text);
489 g_return_val_if_fail (gail_text->textutil, FALSE);
490 buffer = gail_text->textutil->buffer;
491
492 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
493 select_start = gtk_text_iter_get_offset (&start);
494 select_end = gtk_text_iter_get_offset (&end);
495
496 if (select_start != select_end)
497 {
498 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
499 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
500 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
501 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
502 return TRUE;
503 }
504 else
505 return FALSE;
506 }
507
508 static gchar *
509 get_text_near_offset (AtkText *text,
510 GailOffsetType function,
511 AtkTextBoundary boundary_type,
512 gint offset,
513 gint *start_offset,
514 gint *end_offset)
515 {
516 return gail_text_util_get_text (GAIL_CANVAS_TEXT (text)->textutil, NULL,
517 function, boundary_type, offset,
518 start_offset, end_offset);
519 }