1 /* GTK+ - accessibility implementations
2 * Copyright 2001, 2002, 2003 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, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <sys/types.h>
21
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <glib-object.h>
29 #include <glib/gstdio.h>
30 #include <gtk/gtk.h>
31 #include "gtktextviewaccessibleprivate.h"
32 #include "gtktextbufferprivate.h"
33 #include "gtk/gtkwidgetprivate.h"
34
35 struct _GtkTextViewAccessiblePrivate
36 {
37 gint insert_offset;
38 gint selection_bound;
39 };
40
41 static void insert_text_cb (GtkTextBuffer *buffer,
42 GtkTextIter *arg1,
43 gchar *arg2,
44 gint arg3,
45 gpointer user_data);
46 static void delete_range_cb (GtkTextBuffer *buffer,
47 GtkTextIter *arg1,
48 GtkTextIter *arg2,
49 gpointer user_data);
50 static void delete_range_after_cb (GtkTextBuffer *buffer,
51 GtkTextIter *arg1,
52 GtkTextIter *arg2,
53 gpointer user_data);
54 static void mark_set_cb (GtkTextBuffer *buffer,
55 GtkTextIter *arg1,
56 GtkTextMark *arg2,
57 gpointer user_data);
58
59
60 static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
61 static void atk_text_interface_init (AtkTextIface *iface);
62 static void atk_streamable_content_interface_init (AtkStreamableContentIface *iface);
63
G_DEFINE_TYPE_WITH_CODE(GtkTextViewAccessible,gtk_text_view_accessible,GTK_TYPE_CONTAINER_ACCESSIBLE,G_ADD_PRIVATE (GtkTextViewAccessible)G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT,atk_editable_text_interface_init)G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT,atk_text_interface_init)G_IMPLEMENT_INTERFACE (ATK_TYPE_STREAMABLE_CONTENT,atk_streamable_content_interface_init))64 G_DEFINE_TYPE_WITH_CODE (GtkTextViewAccessible, gtk_text_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
65 G_ADD_PRIVATE (GtkTextViewAccessible)
66 G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
67 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
68 G_IMPLEMENT_INTERFACE (ATK_TYPE_STREAMABLE_CONTENT, atk_streamable_content_interface_init))
69
70
71 static void
72 gtk_text_view_accessible_initialize (AtkObject *obj,
73 gpointer data)
74 {
75 ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->initialize (obj, data);
76
77 obj->role = ATK_ROLE_TEXT;
78 }
79
80 static void
gtk_text_view_accessible_notify_gtk(GObject * obj,GParamSpec * pspec)81 gtk_text_view_accessible_notify_gtk (GObject *obj,
82 GParamSpec *pspec)
83 {
84 AtkObject *atk_obj;
85
86 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
87
88 if (!strcmp (pspec->name, "editable"))
89 {
90 gboolean editable;
91
92 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
93 atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, editable);
94 }
95 else
96 GTK_WIDGET_ACCESSIBLE_CLASS (gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec);
97 }
98
99 static AtkStateSet*
gtk_text_view_accessible_ref_state_set(AtkObject * accessible)100 gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
101 {
102 AtkStateSet *state_set;
103 GtkWidget *widget;
104
105 state_set = ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->ref_state_set (accessible);
106
107 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
108 if (widget == NULL)
109 {
110 atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
111 return state_set;
112 }
113
114 if (gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)))
115 atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
116 atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
117
118 return state_set;
119 }
120
121 static void
gtk_text_view_accessible_change_buffer(GtkTextViewAccessible * accessible,GtkTextBuffer * old_buffer,GtkTextBuffer * new_buffer)122 gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible,
123 GtkTextBuffer *old_buffer,
124 GtkTextBuffer *new_buffer)
125 {
126 if (old_buffer)
127 {
128 g_signal_handlers_disconnect_matched (old_buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, accessible);
129
130 g_signal_emit_by_name (accessible,
131 "text-changed::delete",
132 0,
133 gtk_text_buffer_get_char_count (old_buffer));
134 }
135
136 if (new_buffer)
137 {
138 g_signal_connect_after (new_buffer, "insert-text", G_CALLBACK (insert_text_cb), accessible);
139 g_signal_connect (new_buffer, "delete-range", G_CALLBACK (delete_range_cb), accessible);
140 g_signal_connect_after (new_buffer, "delete-range", G_CALLBACK (delete_range_after_cb), accessible);
141 g_signal_connect_after (new_buffer, "mark-set", G_CALLBACK (mark_set_cb), accessible);
142
143 g_signal_emit_by_name (accessible,
144 "text-changed::insert",
145 0,
146 gtk_text_buffer_get_char_count (new_buffer));
147 }
148 }
149
150 static void
gtk_text_view_accessible_widget_set(GtkAccessible * accessible)151 gtk_text_view_accessible_widget_set (GtkAccessible *accessible)
152 {
153 gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
154 NULL,
155 gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))));
156 }
157
158 static void
gtk_text_view_accessible_widget_unset(GtkAccessible * accessible)159 gtk_text_view_accessible_widget_unset (GtkAccessible *accessible)
160 {
161 gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
162 gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))),
163 NULL);
164 }
165
166 static void
gtk_text_view_accessible_class_init(GtkTextViewAccessibleClass * klass)167 gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
168 {
169 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
170 GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
171 GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
172
173 accessible_class->widget_set = gtk_text_view_accessible_widget_set;
174 accessible_class->widget_unset = gtk_text_view_accessible_widget_unset;
175
176 class->ref_state_set = gtk_text_view_accessible_ref_state_set;
177 class->initialize = gtk_text_view_accessible_initialize;
178
179 widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
180 }
181
182 static void
gtk_text_view_accessible_init(GtkTextViewAccessible * accessible)183 gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
184 {
185 accessible->priv = gtk_text_view_accessible_get_instance_private (accessible);
186 }
187
188 static gchar *
gtk_text_view_accessible_get_text(AtkText * text,gint start_offset,gint end_offset)189 gtk_text_view_accessible_get_text (AtkText *text,
190 gint start_offset,
191 gint end_offset)
192 {
193 GtkTextView *view;
194 GtkTextBuffer *buffer;
195 GtkTextIter start, end;
196 GtkWidget *widget;
197
198 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
199 if (widget == NULL)
200 return NULL;
201
202 view = GTK_TEXT_VIEW (widget);
203 buffer = gtk_text_view_get_buffer (view);
204 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
205 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
206
207 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
208 }
209
210 static gchar *
gtk_text_view_accessible_get_text_after_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)211 gtk_text_view_accessible_get_text_after_offset (AtkText *text,
212 gint offset,
213 AtkTextBoundary boundary_type,
214 gint *start_offset,
215 gint *end_offset)
216 {
217 GtkWidget *widget;
218 GtkTextView *view;
219 GtkTextBuffer *buffer;
220 GtkTextIter pos;
221 GtkTextIter start, end;
222
223 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
224 if (widget == NULL)
225 return NULL;
226
227 view = GTK_TEXT_VIEW (widget);
228 buffer = gtk_text_view_get_buffer (view);
229 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
230 start = end = pos;
231 if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
232 {
233 gtk_text_view_forward_display_line (view, &end);
234 start = end;
235 gtk_text_view_forward_display_line (view, &end);
236 }
237 else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
238 {
239 gtk_text_view_forward_display_line_end (view, &end);
240 start = end;
241 gtk_text_view_forward_display_line (view, &end);
242 gtk_text_view_forward_display_line_end (view, &end);
243 }
244 else
245 _gtk_text_buffer_get_text_after (buffer, boundary_type, &pos, &start, &end);
246
247 *start_offset = gtk_text_iter_get_offset (&start);
248 *end_offset = gtk_text_iter_get_offset (&end);
249
250 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
251 }
252
253 static gchar *
gtk_text_view_accessible_get_text_at_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)254 gtk_text_view_accessible_get_text_at_offset (AtkText *text,
255 gint offset,
256 AtkTextBoundary boundary_type,
257 gint *start_offset,
258 gint *end_offset)
259 {
260 GtkWidget *widget;
261 GtkTextView *view;
262 GtkTextBuffer *buffer;
263 GtkTextIter pos;
264 GtkTextIter start, end;
265
266 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
267 if (widget == NULL)
268 return NULL;
269
270 view = GTK_TEXT_VIEW (widget);
271 buffer = gtk_text_view_get_buffer (view);
272 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
273 start = end = pos;
274 if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
275 {
276 gtk_text_view_backward_display_line_start (view, &start);
277 gtk_text_view_forward_display_line (view, &end);
278 }
279 else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
280 {
281 gtk_text_view_backward_display_line_start (view, &start);
282 if (!gtk_text_iter_is_start (&start))
283 {
284 gtk_text_view_backward_display_line (view, &start);
285 gtk_text_view_forward_display_line_end (view, &start);
286 }
287 gtk_text_view_forward_display_line_end (view, &end);
288 }
289 else
290 _gtk_text_buffer_get_text_at (buffer, boundary_type, &pos, &start, &end);
291
292 *start_offset = gtk_text_iter_get_offset (&start);
293 *end_offset = gtk_text_iter_get_offset (&end);
294
295 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
296 }
297
298 static gchar *
gtk_text_view_accessible_get_text_before_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)299 gtk_text_view_accessible_get_text_before_offset (AtkText *text,
300 gint offset,
301 AtkTextBoundary boundary_type,
302 gint *start_offset,
303 gint *end_offset)
304 {
305 GtkWidget *widget;
306 GtkTextView *view;
307 GtkTextBuffer *buffer;
308 GtkTextIter pos;
309 GtkTextIter start, end;
310
311 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
312 if (widget == NULL)
313 return NULL;
314
315 view = GTK_TEXT_VIEW (widget);
316 buffer = gtk_text_view_get_buffer (view);
317 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
318 start = end = pos;
319
320 if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
321 {
322 gtk_text_view_backward_display_line_start (view, &start);
323 end = start;
324 gtk_text_view_backward_display_line (view, &start);
325 gtk_text_view_backward_display_line_start (view, &start);
326 }
327 else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
328 {
329 gtk_text_view_backward_display_line_start (view, &start);
330 if (!gtk_text_iter_is_start (&start))
331 {
332 gtk_text_view_backward_display_line (view, &start);
333 end = start;
334 gtk_text_view_forward_display_line_end (view, &end);
335 if (!gtk_text_iter_is_start (&start))
336 {
337 if (gtk_text_view_backward_display_line (view, &start))
338 gtk_text_view_forward_display_line_end (view, &start);
339 else
340 gtk_text_iter_set_offset (&start, 0);
341 }
342 }
343 else
344 end = start;
345 }
346 else
347 _gtk_text_buffer_get_text_before (buffer, boundary_type, &pos, &start, &end);
348
349 *start_offset = gtk_text_iter_get_offset (&start);
350 *end_offset = gtk_text_iter_get_offset (&end);
351
352 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
353 }
354
355 static gunichar
gtk_text_view_accessible_get_character_at_offset(AtkText * text,gint offset)356 gtk_text_view_accessible_get_character_at_offset (AtkText *text,
357 gint offset)
358 {
359 GtkWidget *widget;
360 GtkTextIter start, end;
361 GtkTextBuffer *buffer;
362 gchar *string;
363 gunichar unichar;
364
365 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
366 if (widget == NULL)
367 return '\0';
368
369 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
370 if (offset >= gtk_text_buffer_get_char_count (buffer))
371 return '\0';
372
373 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
374 end = start;
375 gtk_text_iter_forward_char (&end);
376 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
377 unichar = g_utf8_get_char (string);
378 g_free (string);
379
380 return unichar;
381 }
382
383 static gint
gtk_text_view_accessible_get_character_count(AtkText * text)384 gtk_text_view_accessible_get_character_count (AtkText *text)
385 {
386 GtkWidget *widget;
387 GtkTextBuffer *buffer;
388
389 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
390 if (widget == NULL)
391 return 0;
392
393 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
394 return gtk_text_buffer_get_char_count (buffer);
395 }
396
397 static gint
get_insert_offset(GtkTextBuffer * buffer)398 get_insert_offset (GtkTextBuffer *buffer)
399 {
400 GtkTextMark *insert;
401 GtkTextIter iter;
402
403 insert = gtk_text_buffer_get_insert (buffer);
404 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
405 return gtk_text_iter_get_offset (&iter);
406 }
407
408 static gint
gtk_text_view_accessible_get_caret_offset(AtkText * text)409 gtk_text_view_accessible_get_caret_offset (AtkText *text)
410 {
411 GtkWidget *widget;
412 GtkTextBuffer *buffer;
413
414 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
415 if (widget == NULL)
416 return 0;
417
418 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
419 return get_insert_offset (buffer);
420 }
421
422 static gboolean
gtk_text_view_accessible_set_caret_offset(AtkText * text,gint offset)423 gtk_text_view_accessible_set_caret_offset (AtkText *text,
424 gint offset)
425 {
426 GtkTextView *view;
427 GtkWidget *widget;
428 GtkTextBuffer *buffer;
429 GtkTextIter iter;
430
431 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
432 if (widget == NULL)
433 return FALSE;
434
435 view = GTK_TEXT_VIEW (widget);
436 buffer = gtk_text_view_get_buffer (view);
437
438 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
439 gtk_text_buffer_place_cursor (buffer, &iter);
440 gtk_text_view_scroll_to_iter (view, &iter, 0, FALSE, 0, 0);
441
442 return TRUE;
443 }
444
445 static gint
gtk_text_view_accessible_get_offset_at_point(AtkText * text,gint x,gint y,AtkCoordType coords)446 gtk_text_view_accessible_get_offset_at_point (AtkText *text,
447 gint x,
448 gint y,
449 AtkCoordType coords)
450 {
451 GtkTextView *view;
452 GtkTextIter iter;
453 gint x_widget, y_widget, x_window, y_window, buff_x, buff_y;
454 GtkWidget *widget;
455 GdkWindow *window;
456 GdkRectangle rect;
457
458 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
459 if (widget == NULL)
460 return -1;
461
462 view = GTK_TEXT_VIEW (widget);
463 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
464 gdk_window_get_origin (window, &x_widget, &y_widget);
465
466 if (coords == ATK_XY_SCREEN)
467 {
468 x = x - x_widget;
469 y = y - y_widget;
470 }
471 else if (coords == ATK_XY_WINDOW)
472 {
473 window = gdk_window_get_toplevel (window);
474 gdk_window_get_origin (window, &x_window, &y_window);
475
476 x = x - x_widget + x_window;
477 y = y - y_widget + y_window;
478 }
479 else
480 return -1;
481
482 gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET,
483 x, y, &buff_x, &buff_y);
484 gtk_text_view_get_visible_rect (view, &rect);
485
486 /* Clamp point to visible rectangle */
487 buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1);
488 buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1);
489
490 gtk_text_view_get_iter_at_location (view, &iter, buff_x, buff_y);
491
492 /* The iter at a location sometimes points to the next character.
493 * See bug 111031. We work around that
494 */
495 gtk_text_view_get_iter_location (view, &iter, &rect);
496 if (buff_x < rect.x)
497 gtk_text_iter_backward_char (&iter);
498 return gtk_text_iter_get_offset (&iter);
499 }
500
501 static void
gtk_text_view_accessible_get_character_extents(AtkText * text,gint offset,gint * x,gint * y,gint * width,gint * height,AtkCoordType coords)502 gtk_text_view_accessible_get_character_extents (AtkText *text,
503 gint offset,
504 gint *x,
505 gint *y,
506 gint *width,
507 gint *height,
508 AtkCoordType coords)
509 {
510 GtkTextView *view;
511 GtkTextBuffer *buffer;
512 GtkTextIter iter;
513 GtkWidget *widget;
514 GdkRectangle rectangle;
515 GdkWindow *window;
516 gint x_widget, y_widget, x_window, y_window;
517
518 *x = 0;
519 *y = 0;
520 *width = 0;
521 *height = 0;
522
523 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
524 if (widget == NULL)
525 return;
526
527 view = GTK_TEXT_VIEW (widget);
528 buffer = gtk_text_view_get_buffer (view);
529 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
530 gtk_text_view_get_iter_location (view, &iter, &rectangle);
531
532 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
533 if (window == NULL)
534 return;
535
536 gdk_window_get_origin (window, &x_widget, &y_widget);
537
538 *height = rectangle.height;
539 *width = rectangle.width;
540
541 gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
542 rectangle.x, rectangle.y, x, y);
543 if (coords == ATK_XY_WINDOW)
544 {
545 window = gdk_window_get_toplevel (window);
546 gdk_window_get_origin (window, &x_window, &y_window);
547 *x += x_widget - x_window;
548 *y += y_widget - y_window;
549 }
550 else if (coords == ATK_XY_SCREEN)
551 {
552 *x += x_widget;
553 *y += y_widget;
554 }
555 else
556 {
557 *x = 0;
558 *y = 0;
559 *height = 0;
560 *width = 0;
561 }
562 }
563
564 static AtkAttributeSet *
add_text_attribute(AtkAttributeSet * attributes,AtkTextAttribute attr,gchar * value)565 add_text_attribute (AtkAttributeSet *attributes,
566 AtkTextAttribute attr,
567 gchar *value)
568 {
569 AtkAttribute *at;
570
571 at = g_new (AtkAttribute, 1);
572 at->name = g_strdup (atk_text_attribute_get_name (attr));
573 at->value = value;
574
575 return g_slist_prepend (attributes, at);
576 }
577
578 static AtkAttributeSet *
add_text_int_attribute(AtkAttributeSet * attributes,AtkTextAttribute attr,gint i)579 add_text_int_attribute (AtkAttributeSet *attributes,
580 AtkTextAttribute attr,
581 gint i)
582
583 {
584 gchar *value;
585
586 value = g_strdup (atk_text_attribute_get_value (attr, i));
587
588 return add_text_attribute (attributes, attr, value);
589 }
590
591 static AtkAttributeSet *
gtk_text_view_accessible_get_run_attributes(AtkText * text,gint offset,gint * start_offset,gint * end_offset)592 gtk_text_view_accessible_get_run_attributes (AtkText *text,
593 gint offset,
594 gint *start_offset,
595 gint *end_offset)
596 {
597 GtkTextView *view;
598 GtkTextBuffer *buffer;
599 GtkWidget *widget;
600 GtkTextIter iter;
601 AtkAttributeSet *attrib_set = NULL;
602 GSList *tags, *temp_tags;
603 gdouble scale = 1;
604 gboolean val_set = FALSE;
605
606 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
607 if (widget == NULL)
608 return NULL;
609
610 view = GTK_TEXT_VIEW (widget);
611 buffer = gtk_text_view_get_buffer (view);
612
613 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
614
615 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
616 *end_offset = gtk_text_iter_get_offset (&iter);
617
618 gtk_text_iter_backward_to_tag_toggle (&iter, NULL);
619 *start_offset = gtk_text_iter_get_offset (&iter);
620
621 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
622
623 tags = gtk_text_iter_get_tags (&iter);
624 tags = g_slist_reverse (tags);
625
626 temp_tags = tags;
627 while (temp_tags && !val_set)
628 {
629 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
630
631 g_object_get (tag, "style-set", &val_set, NULL);
632 if (val_set)
633 {
634 PangoStyle style;
635 g_object_get (tag, "style", &style, NULL);
636 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STYLE, style);
637 }
638 temp_tags = temp_tags->next;
639 }
640 val_set = FALSE;
641
642 temp_tags = tags;
643 while (temp_tags && !val_set)
644 {
645 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
646
647 g_object_get (tag, "variant-set", &val_set, NULL);
648 if (val_set)
649 {
650 PangoVariant variant;
651 g_object_get (tag, "variant", &variant, NULL);
652 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT, variant);
653 }
654 temp_tags = temp_tags->next;
655 }
656 val_set = FALSE;
657
658 temp_tags = tags;
659 while (temp_tags && !val_set)
660 {
661 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
662
663 g_object_get (tag, "stretch-set", &val_set, NULL);
664 if (val_set)
665 {
666 PangoStretch stretch;
667 g_object_get (tag, "stretch", &stretch, NULL);
668 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH, stretch);
669 }
670 temp_tags = temp_tags->next;
671 }
672 val_set = FALSE;
673
674 temp_tags = tags;
675 while (temp_tags && !val_set)
676 {
677 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
678
679 g_object_get (tag, "justification-set", &val_set, NULL);
680 if (val_set)
681 {
682 GtkJustification justification;
683 g_object_get (tag, "justification", &justification, NULL);
684 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_JUSTIFICATION, justification);
685 }
686 temp_tags = temp_tags->next;
687 }
688 val_set = FALSE;
689
690 temp_tags = tags;
691 while (temp_tags && !val_set)
692 {
693 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
694 GtkTextDirection direction;
695
696 g_object_get (tag, "direction", &direction, NULL);
697
698 if (direction != GTK_TEXT_DIR_NONE)
699 {
700 val_set = TRUE;
701 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_DIRECTION, direction);
702 }
703 temp_tags = temp_tags->next;
704 }
705 val_set = FALSE;
706
707 temp_tags = tags;
708 while (temp_tags && !val_set)
709 {
710 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
711
712 g_object_get (tag, "wrap-mode-set", &val_set, NULL);
713 if (val_set)
714 {
715 GtkWrapMode wrap_mode;
716 g_object_get (tag, "wrap-mode", &wrap_mode, NULL);
717 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_WRAP_MODE, wrap_mode);
718 }
719 temp_tags = temp_tags->next;
720 }
721 val_set = FALSE;
722
723 temp_tags = tags;
724 while (temp_tags && !val_set)
725 {
726 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
727
728 g_object_get (tag, "foreground-set", &val_set, NULL);
729 if (val_set)
730 {
731 GdkRGBA *rgba;
732 gchar *value;
733
734 g_object_get (tag, "foreground-rgba", &rgba, NULL);
735 value = g_strdup_printf ("%u,%u,%u",
736 (guint) rgba->red * 65535,
737 (guint) rgba->green * 65535,
738 (guint) rgba->blue * 65535);
739 gdk_rgba_free (rgba);
740 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value);
741 }
742 temp_tags = temp_tags->next;
743 }
744 val_set = FALSE;
745
746 temp_tags = tags;
747 while (temp_tags && !val_set)
748 {
749 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
750
751 g_object_get (tag, "background-set", &val_set, NULL);
752 if (val_set)
753 {
754 GdkRGBA *rgba;
755 gchar *value;
756
757 g_object_get (tag, "background-rgba", &rgba, NULL);
758 value = g_strdup_printf ("%u,%u,%u",
759 (guint) rgba->red * 65535,
760 (guint) rgba->green * 65535,
761 (guint) rgba->blue * 65535);
762 gdk_rgba_free (rgba);
763 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_BG_COLOR, value);
764 }
765 temp_tags = temp_tags->next;
766 }
767 val_set = FALSE;
768
769 temp_tags = tags;
770 while (temp_tags && !val_set)
771 {
772 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
773
774 g_object_get (tag, "family-set", &val_set, NULL);
775
776 if (val_set)
777 {
778 gchar *value;
779 g_object_get (tag, "family", &value, NULL);
780 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value);
781 }
782 temp_tags = temp_tags->next;
783 }
784 val_set = FALSE;
785
786 temp_tags = tags;
787 while (temp_tags && !val_set)
788 {
789 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
790
791 g_object_get (tag, "language-set", &val_set, NULL);
792
793 if (val_set)
794 {
795 gchar *value;
796 g_object_get (tag, "language", &value, NULL);
797 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value);
798 }
799 temp_tags = temp_tags->next;
800 }
801 val_set = FALSE;
802
803 temp_tags = tags;
804 while (temp_tags && !val_set)
805 {
806 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
807
808 g_object_get (tag, "weight-set", &val_set, NULL);
809
810 if (val_set)
811 {
812 gint weight;
813 gchar *value;
814 g_object_get (tag, "weight", &weight, NULL);
815 value = g_strdup_printf ("%d", weight);
816 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value);
817 }
818 temp_tags = temp_tags->next;
819 }
820 val_set = FALSE;
821
822 /* scale is special as the effective value is the product
823 * of all specified values
824 */
825 temp_tags = tags;
826 while (temp_tags)
827 {
828 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
829 gboolean scale_set;
830
831 g_object_get (tag, "scale-set", &scale_set, NULL);
832 if (scale_set)
833 {
834 gdouble font_scale;
835 g_object_get (tag, "scale", &font_scale, NULL);
836 val_set = TRUE;
837 scale *= font_scale;
838 }
839 temp_tags = temp_tags->next;
840 }
841 if (val_set)
842 {
843 gchar *value;
844 value = g_strdup_printf ("%g", scale);
845 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_SCALE, value);
846 }
847 val_set = FALSE;
848
849 temp_tags = tags;
850 while (temp_tags && !val_set)
851 {
852 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
853
854 g_object_get (tag, "size-set", &val_set, NULL);
855 if (val_set)
856 {
857 gint size;
858 gchar *value;
859 g_object_get (tag, "size", &size, NULL);
860 value = g_strdup_printf ("%i", size);
861 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value);
862 }
863 temp_tags = temp_tags->next;
864 }
865 val_set = FALSE;
866
867 temp_tags = tags;
868 while (temp_tags && !val_set)
869 {
870 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
871
872 g_object_get (tag, "strikethrough-set", &val_set, NULL);
873 if (val_set)
874 {
875 gboolean strikethrough;
876 g_object_get (tag, "strikethrough", &strikethrough, NULL);
877 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STRIKETHROUGH, strikethrough);
878 }
879 temp_tags = temp_tags->next;
880 }
881 val_set = FALSE;
882
883 temp_tags = tags;
884 while (temp_tags && !val_set)
885 {
886 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
887
888 g_object_get (tag, "underline-set", &val_set, NULL);
889 if (val_set)
890 {
891 PangoUnderline underline;
892 g_object_get (tag, "underline", &underline, NULL);
893 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_UNDERLINE, underline);
894 }
895 temp_tags = temp_tags->next;
896 }
897 val_set = FALSE;
898
899 temp_tags = tags;
900 while (temp_tags && !val_set)
901 {
902 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
903
904 g_object_get (tag, "rise-set", &val_set, NULL);
905 if (val_set)
906 {
907 gint rise;
908 gchar *value;
909 g_object_get (tag, "rise", &rise, NULL);
910 value = g_strdup_printf ("%i", rise);
911 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_RISE, value);
912 }
913 temp_tags = temp_tags->next;
914 }
915 val_set = FALSE;
916
917 temp_tags = tags;
918 while (temp_tags && !val_set)
919 {
920 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
921
922 g_object_get (tag, "background-full-height-set", &val_set, NULL);
923 if (val_set)
924 {
925 gboolean bg_full_height;
926 g_object_get (tag, "background-full-height", &bg_full_height, NULL);
927 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_BG_FULL_HEIGHT, bg_full_height);
928 }
929 temp_tags = temp_tags->next;
930 }
931 val_set = FALSE;
932
933 temp_tags = tags;
934 while (temp_tags && !val_set)
935 {
936 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
937
938 g_object_get (tag, "pixels-inside-wrap-set", &val_set, NULL);
939 if (val_set)
940 {
941 gint pixels;
942 gchar *value;
943 g_object_get (tag, "pixels-inside-wrap", &pixels, NULL);
944 value = g_strdup_printf ("%i", pixels);
945 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
946 }
947 temp_tags = temp_tags->next;
948 }
949 val_set = FALSE;
950
951 temp_tags = tags;
952 while (temp_tags && !val_set)
953 {
954 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
955
956 g_object_get (tag, "pixels-below-lines-set", &val_set, NULL);
957 if (val_set)
958 {
959 gint pixels;
960 gchar *value;
961 g_object_get (tag, "pixels-below-lines", &pixels, NULL);
962 value = g_strdup_printf ("%i", pixels);
963 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
964 }
965 temp_tags = temp_tags->next;
966 }
967 val_set = FALSE;
968
969 temp_tags = tags;
970 while (temp_tags && !val_set)
971 {
972 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
973
974 g_object_get (tag, "pixels-above-lines-set", &val_set, NULL);
975 if (val_set)
976 {
977 gint pixels;
978 gchar *value;
979 g_object_get (tag, "pixels-above-lines", &pixels, NULL);
980 value = g_strdup_printf ("%i", pixels);
981 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
982 }
983 temp_tags = temp_tags->next;
984 }
985 val_set = FALSE;
986
987 temp_tags = tags;
988 while (temp_tags && !val_set)
989 {
990 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
991
992 g_object_get (tag, "editable-set", &val_set, NULL);
993 if (val_set)
994 {
995 gboolean editable;
996 g_object_get (tag, "editable", &editable, NULL);
997 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_EDITABLE, editable);
998 }
999 temp_tags = temp_tags->next;
1000 }
1001 val_set = FALSE;
1002
1003 temp_tags = tags;
1004 while (temp_tags && !val_set)
1005 {
1006 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1007
1008 g_object_get (tag, "invisible-set", &val_set, NULL);
1009 if (val_set)
1010 {
1011 gboolean invisible;
1012 g_object_get (tag, "invisible", &invisible, NULL);
1013 attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_INVISIBLE, invisible);
1014 }
1015 temp_tags = temp_tags->next;
1016 }
1017 val_set = FALSE;
1018
1019 temp_tags = tags;
1020 while (temp_tags && !val_set)
1021 {
1022 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1023
1024 g_object_get (tag, "indent-set", &val_set, NULL);
1025 if (val_set)
1026 {
1027 gint indent;
1028 gchar *value;
1029 g_object_get (tag, "indent", &indent, NULL);
1030 value = g_strdup_printf ("%i", indent);
1031 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_INDENT, value);
1032 }
1033 temp_tags = temp_tags->next;
1034 }
1035 val_set = FALSE;
1036
1037 temp_tags = tags;
1038 while (temp_tags && !val_set)
1039 {
1040 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1041
1042 g_object_get (tag, "right-margin-set", &val_set, NULL);
1043 if (val_set)
1044 {
1045 gint margin;
1046 gchar *value;
1047 g_object_get (tag, "right-margin", &margin, NULL);
1048 value = g_strdup_printf ("%i", margin);
1049 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
1050 }
1051 temp_tags = temp_tags->next;
1052 }
1053 val_set = FALSE;
1054
1055 temp_tags = tags;
1056 while (temp_tags && !val_set)
1057 {
1058 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
1059
1060 g_object_get (tag, "left-margin-set", &val_set, NULL);
1061 if (val_set)
1062 {
1063 gint margin;
1064 gchar *value;
1065 g_object_get (tag, "left-margin", &margin, NULL);
1066 value = g_strdup_printf ("%i", margin);
1067 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_LEFT_MARGIN, value);
1068 }
1069 temp_tags = temp_tags->next;
1070 }
1071 val_set = FALSE;
1072
1073 g_slist_free (tags);
1074 return attrib_set;
1075 }
1076
1077 static AtkAttributeSet *
gtk_text_view_accessible_get_default_attributes(AtkText * text)1078 gtk_text_view_accessible_get_default_attributes (AtkText *text)
1079 {
1080 GtkTextView *view;
1081 GtkWidget *widget;
1082 GtkTextAttributes *text_attrs;
1083 AtkAttributeSet *attributes;
1084 PangoFontDescription *font;
1085 gchar *value;
1086
1087 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1088 if (widget == NULL)
1089 return NULL;
1090
1091 view = GTK_TEXT_VIEW (widget);
1092 text_attrs = gtk_text_view_get_default_attributes (view);
1093
1094 attributes = NULL;
1095
1096 font = text_attrs->font;
1097
1098 if (font)
1099 {
1100 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STYLE,
1101 pango_font_description_get_style (font));
1102
1103 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
1104 pango_font_description_get_variant (font));
1105
1106 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
1107 pango_font_description_get_stretch (font));
1108
1109 value = g_strdup (pango_font_description_get_family (font));
1110 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
1111
1112 value = g_strdup_printf ("%d", pango_font_description_get_weight (font));
1113 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
1114
1115 value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE);
1116 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
1117 }
1118
1119 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
1120 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
1121 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
1122 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
1123 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
1124 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
1125
1126 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
1127 text_attrs->appearance.strikethrough);
1128 attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
1129 text_attrs->appearance.underline);
1130
1131 value = g_strdup_printf ("%u,%u,%u",
1132 text_attrs->appearance.bg_color.red,
1133 text_attrs->appearance.bg_color.green,
1134 text_attrs->appearance.bg_color.blue);
1135 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
1136
1137 value = g_strdup_printf ("%u,%u,%u",
1138 text_attrs->appearance.fg_color.red,
1139 text_attrs->appearance.fg_color.green,
1140 text_attrs->appearance.fg_color.blue);
1141 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
1142
1143 value = g_strdup_printf ("%g", text_attrs->font_scale);
1144 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
1145
1146 value = g_strdup ((gchar *)(text_attrs->language));
1147 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, value);
1148
1149 value = g_strdup_printf ("%i", text_attrs->appearance.rise);
1150 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
1151
1152 value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
1153 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
1154
1155 value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
1156 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
1157
1158 value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
1159 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
1160
1161 value = g_strdup_printf ("%i", text_attrs->indent);
1162 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_INDENT, value);
1163
1164 value = g_strdup_printf ("%i", text_attrs->left_margin);
1165 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, value);
1166
1167 value = g_strdup_printf ("%i", text_attrs->right_margin);
1168 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
1169
1170 gtk_text_attributes_unref (text_attrs);
1171 return attributes;
1172 }
1173
1174 static gint
gtk_text_view_accessible_get_n_selections(AtkText * text)1175 gtk_text_view_accessible_get_n_selections (AtkText *text)
1176 {
1177 GtkWidget *widget;
1178 GtkTextBuffer *buffer;
1179
1180 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1181 if (widget == NULL)
1182 return 0;
1183
1184 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1185 if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
1186 return 1;
1187
1188 return 0;
1189 }
1190
1191 static gchar *
gtk_text_view_accessible_get_selection(AtkText * atk_text,gint selection_num,gint * start_pos,gint * end_pos)1192 gtk_text_view_accessible_get_selection (AtkText *atk_text,
1193 gint selection_num,
1194 gint *start_pos,
1195 gint *end_pos)
1196 {
1197 GtkTextView *view;
1198 GtkWidget *widget;
1199 GtkTextBuffer *buffer;
1200 GtkTextIter start, end;
1201 gchar *text;
1202
1203 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
1204 if (widget == NULL)
1205 return NULL;
1206
1207 if (selection_num != 0)
1208 return NULL;
1209
1210 view = GTK_TEXT_VIEW (widget);
1211 buffer = gtk_text_view_get_buffer (view);
1212
1213 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1214 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1215 else
1216 text = NULL;
1217
1218 *start_pos = gtk_text_iter_get_offset (&start);
1219 *end_pos = gtk_text_iter_get_offset (&end);
1220
1221 return text;
1222 }
1223
1224 static gboolean
gtk_text_view_accessible_add_selection(AtkText * text,gint start_pos,gint end_pos)1225 gtk_text_view_accessible_add_selection (AtkText *text,
1226 gint start_pos,
1227 gint end_pos)
1228 {
1229 GtkWidget *widget;
1230 GtkTextBuffer *buffer;
1231 GtkTextIter start, end;
1232
1233 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1234 if (widget == NULL)
1235 return FALSE;
1236
1237 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1238
1239 if (!gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
1240 {
1241 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1242 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1243 gtk_text_buffer_select_range (buffer, &end, &start);
1244
1245 return TRUE;
1246 }
1247 else
1248 return FALSE;
1249 }
1250
1251 static gboolean
gtk_text_view_accessible_remove_selection(AtkText * text,gint selection_num)1252 gtk_text_view_accessible_remove_selection (AtkText *text,
1253 gint selection_num)
1254 {
1255 GtkWidget *widget;
1256 GtkTextBuffer *buffer;
1257 GtkTextMark *insert;
1258 GtkTextIter iter;
1259 GtkTextIter start, end;
1260
1261 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1262 if (widget == NULL)
1263 return FALSE;
1264
1265 if (selection_num != 0)
1266 return FALSE;
1267
1268 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1269
1270 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1271 {
1272 insert = gtk_text_buffer_get_insert (buffer);
1273 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
1274 gtk_text_buffer_place_cursor (buffer, &iter);
1275 return TRUE;
1276 }
1277 else
1278 return FALSE;
1279 }
1280
1281 static gboolean
gtk_text_view_accessible_set_selection(AtkText * text,gint selection_num,gint start_pos,gint end_pos)1282 gtk_text_view_accessible_set_selection (AtkText *text,
1283 gint selection_num,
1284 gint start_pos,
1285 gint end_pos)
1286 {
1287 GtkWidget *widget;
1288 GtkTextBuffer *buffer;
1289 GtkTextIter start, end;
1290
1291 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1292 if (widget == NULL)
1293 return FALSE;
1294
1295 if (selection_num != 0)
1296 return FALSE;
1297
1298 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1299
1300 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1301 {
1302 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1303 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1304 gtk_text_buffer_select_range (buffer, &end, &start);
1305
1306 return TRUE;
1307 }
1308 else
1309 return FALSE;
1310 }
1311
1312 static gboolean
gtk_text_view_accessible_scroll_substring_to(AtkText * text,gint start_offset,gint end_offset,AtkScrollType type)1313 gtk_text_view_accessible_scroll_substring_to(AtkText *text,
1314 gint start_offset,
1315 gint end_offset,
1316 AtkScrollType type)
1317 {
1318 GtkTextView *view;
1319 GtkWidget *widget;
1320 GtkTextBuffer *buffer;
1321 GtkTextIter iter;
1322 gdouble xalign = -1.0, yalign = -1.0;
1323 gboolean use_align = TRUE;
1324 gint offset, rtl = 0;
1325
1326 if (end_offset < start_offset)
1327 return FALSE;
1328
1329 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1330 if (widget == NULL)
1331 return FALSE;
1332
1333 view = GTK_TEXT_VIEW (widget);
1334 buffer = gtk_text_view_get_buffer (view);
1335
1336 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1337 rtl = 1;
1338
1339 /*
1340 * Opportunistically pick which offset should be used to calculate
1341 * the scrolling factor.
1342 *
1343 * Considering only an extremity of the substring is good enough when
1344 * the selected string doesn't include line break and isn't larger than
1345 * the visible rectangle.
1346 */
1347 switch (type)
1348 {
1349 case ATK_SCROLL_TOP_LEFT:
1350 offset = (rtl) ? end_offset : start_offset;
1351 xalign = 0.0;
1352 yalign = 0.0;
1353 break;
1354 case ATK_SCROLL_BOTTOM_RIGHT:
1355 offset = (rtl) ? start_offset : end_offset;
1356 xalign = 1.0;
1357 yalign = 1.0;
1358 break;
1359 case ATK_SCROLL_TOP_EDGE:
1360 offset = start_offset;
1361 yalign = 0.0;
1362 break;
1363 case ATK_SCROLL_BOTTOM_EDGE:
1364 offset = end_offset;
1365 yalign = 1.0;
1366 break;
1367 case ATK_SCROLL_LEFT_EDGE:
1368 offset = (rtl) ? end_offset : start_offset;
1369 xalign = 0.0;
1370 break;
1371 case ATK_SCROLL_RIGHT_EDGE:
1372 offset = (rtl) ? start_offset : end_offset;
1373 xalign = 1.0;
1374 break;
1375 case ATK_SCROLL_ANYWHERE:
1376 offset = start_offset;
1377 use_align = FALSE;
1378 xalign = yalign = 0.0;
1379 break;
1380 default:
1381 return FALSE;
1382 }
1383
1384 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
1385
1386 /* Get current iter location to be able to scroll in a single direction. */
1387 if (use_align && (xalign == -1.0 || yalign == -1.0))
1388 {
1389 GdkRectangle rect, irect;
1390
1391 gtk_text_view_get_visible_rect (view, &rect);
1392 gtk_text_view_get_iter_location (view, &iter, &irect);
1393
1394 if (xalign == -1.0)
1395 xalign = ((gdouble) (irect.x - rect.x)) / (rect.width - 1);
1396 if (yalign == -1.0)
1397 yalign = ((gdouble) (irect.y - rect.y)) / (rect.height - 1);
1398 }
1399
1400 gtk_text_view_scroll_to_iter (view, &iter, 0, use_align, xalign, yalign);
1401
1402 return TRUE;
1403 }
1404
1405 static void
atk_text_interface_init(AtkTextIface * iface)1406 atk_text_interface_init (AtkTextIface *iface)
1407 {
1408 iface->get_text = gtk_text_view_accessible_get_text;
1409 iface->get_text_after_offset = gtk_text_view_accessible_get_text_after_offset;
1410 iface->get_text_at_offset = gtk_text_view_accessible_get_text_at_offset;
1411 iface->get_text_before_offset = gtk_text_view_accessible_get_text_before_offset;
1412 iface->get_character_at_offset = gtk_text_view_accessible_get_character_at_offset;
1413 iface->get_character_count = gtk_text_view_accessible_get_character_count;
1414 iface->get_caret_offset = gtk_text_view_accessible_get_caret_offset;
1415 iface->set_caret_offset = gtk_text_view_accessible_set_caret_offset;
1416 iface->get_offset_at_point = gtk_text_view_accessible_get_offset_at_point;
1417 iface->get_character_extents = gtk_text_view_accessible_get_character_extents;
1418 iface->get_n_selections = gtk_text_view_accessible_get_n_selections;
1419 iface->get_selection = gtk_text_view_accessible_get_selection;
1420 iface->add_selection = gtk_text_view_accessible_add_selection;
1421 iface->remove_selection = gtk_text_view_accessible_remove_selection;
1422 iface->set_selection = gtk_text_view_accessible_set_selection;
1423 iface->get_run_attributes = gtk_text_view_accessible_get_run_attributes;
1424 iface->get_default_attributes = gtk_text_view_accessible_get_default_attributes;
1425 iface->scroll_substring_to = gtk_text_view_accessible_scroll_substring_to;
1426 }
1427
1428 /* atkeditabletext.h */
1429
1430 static gboolean
gtk_text_view_accessible_set_run_attributes(AtkEditableText * text,AtkAttributeSet * attributes,gint start_offset,gint end_offset)1431 gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
1432 AtkAttributeSet *attributes,
1433 gint start_offset,
1434 gint end_offset)
1435 {
1436 GtkTextView *view;
1437 GtkTextBuffer *buffer;
1438 GtkWidget *widget;
1439 GtkTextTag *tag;
1440 GtkTextIter start;
1441 GtkTextIter end;
1442 gint j;
1443 GdkColor *color;
1444 gchar** RGB_vals;
1445 GSList *l;
1446
1447 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1448 if (widget == NULL)
1449 return FALSE;
1450
1451 view = GTK_TEXT_VIEW (widget);
1452 if (!gtk_text_view_get_editable (view))
1453 return FALSE;
1454
1455 buffer = gtk_text_view_get_buffer (view);
1456
1457 if (attributes == NULL)
1458 return FALSE;
1459
1460 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1461 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
1462
1463 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
1464
1465 for (l = attributes; l; l = l->next)
1466 {
1467 gchar *name;
1468 gchar *value;
1469 AtkAttribute *at;
1470
1471 at = l->data;
1472
1473 name = at->name;
1474 value = at->value;
1475
1476 if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
1477 g_object_set (G_OBJECT (tag), "left-margin", atoi (value), NULL);
1478
1479 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
1480 g_object_set (G_OBJECT (tag), "right-margin", atoi (value), NULL);
1481
1482 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
1483 g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
1484
1485 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
1486 g_object_set (G_OBJECT (tag), "pixels-above-lines", atoi (value), NULL);
1487
1488 else if (!strcmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
1489 g_object_set (G_OBJECT (tag), "pixels-below-lines", atoi (value), NULL);
1490
1491 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
1492 g_object_set (G_OBJECT (tag), "pixels-inside-wrap", atoi (value), NULL);
1493
1494 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
1495 g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
1496
1497 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE)))
1498 g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL);
1499
1500 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT)))
1501 g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL);
1502
1503 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
1504 {
1505 g_object_set (G_OBJECT (tag), "bg-full-height",
1506 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
1507 NULL);
1508 }
1509
1510 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE)))
1511 g_object_set (G_OBJECT (tag), "language", value, NULL);
1512
1513 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME)))
1514 g_object_set (G_OBJECT (tag), "family", value, NULL);
1515
1516 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE)))
1517 {
1518 g_object_set (G_OBJECT (tag), "editable",
1519 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
1520 NULL);
1521 }
1522
1523 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE)))
1524 {
1525 g_object_set (G_OBJECT (tag), "invisible",
1526 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
1527 NULL);
1528 }
1529
1530 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE)))
1531 {
1532 for (j = 0; j < 3; j++)
1533 {
1534 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j)))
1535 {
1536 g_object_set (G_OBJECT (tag), "underline", j, NULL);
1537 break;
1538 }
1539 }
1540 }
1541
1542 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH)))
1543 {
1544 g_object_set (G_OBJECT (tag), "strikethrough",
1545 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))),
1546 NULL);
1547 }
1548
1549 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR)))
1550 {
1551 RGB_vals = g_strsplit (value, ",", 3);
1552 color = g_malloc (sizeof (GdkColor));
1553 color->red = atoi (RGB_vals[0]);
1554 color->green = atoi (RGB_vals[1]);
1555 color->blue = atoi (RGB_vals[2]);
1556 g_object_set (G_OBJECT (tag), "background-gdk", color, NULL);
1557 }
1558
1559 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
1560 {
1561 RGB_vals = g_strsplit (value, ",", 3);
1562 color = g_malloc (sizeof (GdkColor));
1563 color->red = atoi (RGB_vals[0]);
1564 color->green = atoi (RGB_vals[1]);
1565 color->blue = atoi (RGB_vals[2]);
1566 g_object_set (G_OBJECT (tag), "foreground-gdk", color, NULL);
1567 }
1568
1569 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
1570 {
1571 for (j = 0; j < 9; j++)
1572 {
1573 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j)))
1574 {
1575 g_object_set (G_OBJECT (tag), "stretch", j, NULL);
1576 break;
1577 }
1578 }
1579 }
1580
1581 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION)))
1582 {
1583 for (j = 0; j < 4; j++)
1584 {
1585 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j)))
1586 {
1587 g_object_set (G_OBJECT (tag), "justification", j, NULL);
1588 break;
1589 }
1590 }
1591 }
1592
1593 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION)))
1594 {
1595 for (j = 0; j < 3; j++)
1596 {
1597 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j)))
1598 {
1599 g_object_set (G_OBJECT (tag), "direction", j, NULL);
1600 break;
1601 }
1602 }
1603 }
1604
1605 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT)))
1606 {
1607 for (j = 0; j < 2; j++)
1608 {
1609 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j)))
1610 {
1611 g_object_set (G_OBJECT (tag), "variant", j, NULL);
1612 break;
1613 }
1614 }
1615 }
1616
1617 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE)))
1618 {
1619 for (j = 0; j < 3; j++)
1620 {
1621 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
1622 {
1623 g_object_set (G_OBJECT (tag), "wrap-mode", j, NULL);
1624 break;
1625 }
1626 }
1627 }
1628
1629 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE)))
1630 {
1631 for (j = 0; j < 3; j++)
1632 {
1633 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j)))
1634 {
1635 g_object_set (G_OBJECT (tag), "style", j, NULL);
1636 break;
1637 }
1638 }
1639 }
1640
1641 else
1642 return FALSE;
1643 }
1644
1645 gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
1646
1647 return TRUE;
1648 }
1649
1650 static void
gtk_text_view_accessible_set_text_contents(AtkEditableText * text,const gchar * string)1651 gtk_text_view_accessible_set_text_contents (AtkEditableText *text,
1652 const gchar *string)
1653 {
1654 GtkTextView *view;
1655 GtkWidget *widget;
1656 GtkTextBuffer *buffer;
1657
1658 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1659 if (widget == NULL)
1660 return;
1661
1662 view = GTK_TEXT_VIEW (widget);
1663 if (!gtk_text_view_get_editable (view))
1664 return;
1665
1666 buffer = gtk_text_view_get_buffer (view);
1667 gtk_text_buffer_set_text (buffer, string, -1);
1668 }
1669
1670 static void
gtk_text_view_accessible_insert_text(AtkEditableText * text,const gchar * string,gint length,gint * position)1671 gtk_text_view_accessible_insert_text (AtkEditableText *text,
1672 const gchar *string,
1673 gint length,
1674 gint *position)
1675 {
1676 GtkTextView *view;
1677 GtkWidget *widget;
1678 GtkTextBuffer *buffer;
1679 GtkTextIter iter;
1680
1681 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1682 if (widget == NULL)
1683 return;
1684
1685 view = GTK_TEXT_VIEW (widget);
1686 if (!gtk_text_view_get_editable (view))
1687 return;
1688
1689 buffer = gtk_text_view_get_buffer (view);
1690 gtk_text_buffer_get_iter_at_offset (buffer, &iter, *position);
1691 gtk_text_buffer_insert (buffer, &iter, string, length);
1692 }
1693
1694 static void
gtk_text_view_accessible_copy_text(AtkEditableText * text,gint start_pos,gint end_pos)1695 gtk_text_view_accessible_copy_text (AtkEditableText *text,
1696 gint start_pos,
1697 gint end_pos)
1698 {
1699 GtkWidget *widget;
1700 GtkTextBuffer *buffer;
1701 GtkTextIter start, end;
1702 gchar *str;
1703 GtkClipboard *clipboard;
1704
1705 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1706 if (widget == NULL)
1707 return;
1708
1709 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1710
1711 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1712 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1713 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1714
1715 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1716 gtk_clipboard_set_text (clipboard, str, -1);
1717 }
1718
1719 static void
gtk_text_view_accessible_cut_text(AtkEditableText * text,gint start_pos,gint end_pos)1720 gtk_text_view_accessible_cut_text (AtkEditableText *text,
1721 gint start_pos,
1722 gint end_pos)
1723 {
1724 GtkTextView *view;
1725 GtkWidget *widget;
1726 GtkTextBuffer *buffer;
1727 GtkTextIter start, end;
1728 gchar *str;
1729 GtkClipboard *clipboard;
1730
1731 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1732 if (widget == NULL)
1733 return;
1734
1735 view = GTK_TEXT_VIEW (widget);
1736 if (!gtk_text_view_get_editable (view))
1737 return;
1738 buffer = gtk_text_view_get_buffer (view);
1739
1740 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1741 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1742 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1743 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1744 gtk_clipboard_set_text (clipboard, str, -1);
1745 gtk_text_buffer_delete (buffer, &start, &end);
1746 }
1747
1748 static void
gtk_text_view_accessible_delete_text(AtkEditableText * text,gint start_pos,gint end_pos)1749 gtk_text_view_accessible_delete_text (AtkEditableText *text,
1750 gint start_pos,
1751 gint end_pos)
1752 {
1753 GtkTextView *view;
1754 GtkWidget *widget;
1755 GtkTextBuffer *buffer;
1756 GtkTextIter start_itr;
1757 GtkTextIter end_itr;
1758
1759 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1760 if (widget == NULL)
1761 return;
1762
1763 view = GTK_TEXT_VIEW (widget);
1764 if (!gtk_text_view_get_editable (view))
1765 return;
1766 buffer = gtk_text_view_get_buffer (view);
1767
1768 gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos);
1769 gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos);
1770 gtk_text_buffer_delete (buffer, &start_itr, &end_itr);
1771 }
1772
1773 typedef struct
1774 {
1775 GtkTextBuffer* buffer;
1776 gint position;
1777 } PasteData;
1778
1779 static void
paste_received(GtkClipboard * clipboard,const gchar * text,gpointer data)1780 paste_received (GtkClipboard *clipboard,
1781 const gchar *text,
1782 gpointer data)
1783 {
1784 PasteData* paste = data;
1785 GtkTextIter pos_itr;
1786
1787 if (text)
1788 {
1789 gtk_text_buffer_get_iter_at_offset (paste->buffer, &pos_itr, paste->position);
1790 gtk_text_buffer_insert (paste->buffer, &pos_itr, text, -1);
1791 }
1792
1793 g_object_unref (paste->buffer);
1794 }
1795
1796 static void
gtk_text_view_accessible_paste_text(AtkEditableText * text,gint position)1797 gtk_text_view_accessible_paste_text (AtkEditableText *text,
1798 gint position)
1799 {
1800 GtkTextView *view;
1801 GtkWidget *widget;
1802 GtkTextBuffer *buffer;
1803 PasteData paste;
1804 GtkClipboard *clipboard;
1805
1806 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1807 if (widget == NULL)
1808 return;
1809
1810 view = GTK_TEXT_VIEW (widget);
1811 if (!gtk_text_view_get_editable (view))
1812 return;
1813 buffer = gtk_text_view_get_buffer (view);
1814
1815 paste.buffer = buffer;
1816 paste.position = position;
1817
1818 g_object_ref (paste.buffer);
1819 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1820 gtk_clipboard_request_text (clipboard, paste_received, &paste);
1821 }
1822
1823 static void
atk_editable_text_interface_init(AtkEditableTextIface * iface)1824 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1825 {
1826 iface->set_text_contents = gtk_text_view_accessible_set_text_contents;
1827 iface->insert_text = gtk_text_view_accessible_insert_text;
1828 iface->copy_text = gtk_text_view_accessible_copy_text;
1829 iface->cut_text = gtk_text_view_accessible_cut_text;
1830 iface->delete_text = gtk_text_view_accessible_delete_text;
1831 iface->paste_text = gtk_text_view_accessible_paste_text;
1832 iface->set_run_attributes = gtk_text_view_accessible_set_run_attributes;
1833 }
1834
1835 /* Callbacks */
1836
1837 static void
gtk_text_view_accessible_update_cursor(GtkTextViewAccessible * accessible,GtkTextBuffer * buffer)1838 gtk_text_view_accessible_update_cursor (GtkTextViewAccessible *accessible,
1839 GtkTextBuffer * buffer)
1840 {
1841 int prev_insert_offset, prev_selection_bound;
1842 int insert_offset, selection_bound;
1843 GtkTextIter iter;
1844
1845 prev_insert_offset = accessible->priv->insert_offset;
1846 prev_selection_bound = accessible->priv->selection_bound;
1847
1848 gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
1849 insert_offset = gtk_text_iter_get_offset (&iter);
1850 gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_selection_bound (buffer));
1851 selection_bound = gtk_text_iter_get_offset (&iter);
1852
1853 if (prev_insert_offset == insert_offset && prev_selection_bound == selection_bound)
1854 return;
1855
1856 accessible->priv->insert_offset = insert_offset;
1857 accessible->priv->selection_bound = selection_bound;
1858
1859 if (prev_insert_offset != insert_offset)
1860 g_signal_emit_by_name (accessible, "text-caret-moved", insert_offset);
1861
1862 if (prev_insert_offset != prev_selection_bound || insert_offset != selection_bound)
1863 g_signal_emit_by_name (accessible, "text-selection-changed");
1864 }
1865
1866 static void
insert_text_cb(GtkTextBuffer * buffer,GtkTextIter * iter,gchar * text,gint len,gpointer data)1867 insert_text_cb (GtkTextBuffer *buffer,
1868 GtkTextIter *iter,
1869 gchar *text,
1870 gint len,
1871 gpointer data)
1872 {
1873 GtkTextViewAccessible *accessible = data;
1874 gint position;
1875 gint length;
1876
1877 position = gtk_text_iter_get_offset (iter);
1878 length = g_utf8_strlen (text, len);
1879
1880 g_signal_emit_by_name (accessible, "text-changed::insert", position - length, length);
1881
1882 gtk_text_view_accessible_update_cursor (accessible, buffer);
1883 }
1884
1885 static void
delete_range_cb(GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end,gpointer data)1886 delete_range_cb (GtkTextBuffer *buffer,
1887 GtkTextIter *start,
1888 GtkTextIter *end,
1889 gpointer data)
1890 {
1891 GtkTextViewAccessible *accessible = data;
1892 gint offset, length;
1893
1894 offset = gtk_text_iter_get_offset (start);
1895 length = gtk_text_iter_get_offset (end) - offset;
1896
1897 g_signal_emit_by_name (accessible,
1898 "text-changed::delete",
1899 offset,
1900 length);
1901 }
1902
1903 static void
delete_range_after_cb(GtkTextBuffer * buffer,GtkTextIter * start,GtkTextIter * end,gpointer data)1904 delete_range_after_cb (GtkTextBuffer *buffer,
1905 GtkTextIter *start,
1906 GtkTextIter *end,
1907 gpointer data)
1908 {
1909 GtkTextViewAccessible *accessible = data;
1910
1911 gtk_text_view_accessible_update_cursor (accessible, buffer);
1912 }
1913
1914 static void
mark_set_cb(GtkTextBuffer * buffer,GtkTextIter * location,GtkTextMark * mark,gpointer data)1915 mark_set_cb (GtkTextBuffer *buffer,
1916 GtkTextIter *location,
1917 GtkTextMark *mark,
1918 gpointer data)
1919 {
1920 GtkTextViewAccessible *accessible = data;
1921
1922 /*
1923 * Only generate the signal for the "insert" mark, which
1924 * represents the cursor.
1925 */
1926 if (mark == gtk_text_buffer_get_insert (buffer))
1927 {
1928 gtk_text_view_accessible_update_cursor (accessible, buffer);
1929 }
1930 else if (mark == gtk_text_buffer_get_selection_bound (buffer))
1931 {
1932 gtk_text_view_accessible_update_cursor (accessible, buffer);
1933 }
1934 }
1935
1936 static gint
gail_streamable_content_get_n_mime_types(AtkStreamableContent * streamable)1937 gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable)
1938 {
1939 GtkWidget *widget;
1940 GtkTextBuffer *buffer;
1941 gint n_mime_types = 0;
1942
1943 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1944 if (widget == NULL)
1945 return 0;
1946
1947 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1948 if (buffer)
1949 {
1950 gint i;
1951 gboolean advertises_plaintext = FALSE;
1952 GdkAtom *atoms;
1953
1954 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1955 for (i = 0; i < n_mime_types-1; ++i)
1956 if (!strcmp ("text/plain", gdk_atom_name (atoms[i])))
1957 advertises_plaintext = TRUE;
1958 if (!advertises_plaintext)
1959 n_mime_types++;
1960 }
1961
1962 return n_mime_types;
1963 }
1964
1965 static const gchar *
gail_streamable_content_get_mime_type(AtkStreamableContent * streamable,gint i)1966 gail_streamable_content_get_mime_type (AtkStreamableContent *streamable,
1967 gint i)
1968 {
1969 GtkWidget *widget;
1970 GtkTextBuffer *buffer;
1971
1972 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1973 if (widget == NULL)
1974 return 0;
1975
1976 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1977 if (buffer)
1978 {
1979 gint n_mime_types = 0;
1980 GdkAtom *atoms;
1981
1982 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1983 if (i < n_mime_types)
1984 return gdk_atom_name (atoms [i]);
1985 else if (i == n_mime_types)
1986 return "text/plain";
1987 }
1988
1989 return NULL;
1990 }
1991
1992 static GIOChannel *
gail_streamable_content_get_stream(AtkStreamableContent * streamable,const gchar * mime_type)1993 gail_streamable_content_get_stream (AtkStreamableContent *streamable,
1994 const gchar *mime_type)
1995 {
1996 GtkWidget *widget;
1997 GtkTextBuffer *buffer;
1998 gint i, n_mime_types = 0;
1999 GdkAtom *atoms;
2000
2001 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
2002 if (widget == NULL)
2003 return 0;
2004
2005 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
2006 if (!buffer)
2007 return NULL;
2008
2009 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
2010
2011 for (i = 0; i < n_mime_types; ++i)
2012 {
2013 if (!strcmp ("text/plain", mime_type) ||
2014 !strcmp (gdk_atom_name (atoms[i]), mime_type))
2015 {
2016 guint8 *cbuf;
2017 GError *err = NULL;
2018 gsize len, written;
2019 gchar tname[80];
2020 GtkTextIter start, end;
2021 GIOChannel *gio = NULL;
2022 int fd;
2023
2024 gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
2025 gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
2026 if (!strcmp ("text/plain", mime_type))
2027 {
2028 cbuf = (guint8*) gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
2029 len = strlen ((const char *) cbuf);
2030 }
2031 else
2032 {
2033 cbuf = gtk_text_buffer_serialize (buffer, buffer, atoms[i], &start, &end, &len);
2034 }
2035 g_snprintf (tname, 20, "streamXXXXXX");
2036 fd = g_mkstemp (tname);
2037 gio = g_io_channel_unix_new (fd);
2038 g_io_channel_set_encoding (gio, NULL, &err);
2039 if (!err)
2040 g_io_channel_write_chars (gio, (const char *) cbuf, (gssize) len, &written, &err);
2041 else
2042 g_message ("%s", err->message);
2043 if (!err)
2044 g_io_channel_seek_position (gio, 0, G_SEEK_SET, &err);
2045 else
2046 g_message ("%s", err->message);
2047 if (!err)
2048 g_io_channel_flush (gio, &err);
2049 else
2050 g_message ("%s", err->message);
2051 if (err)
2052 {
2053 g_message ("<error writing to stream [%s]>", tname);
2054 g_error_free (err);
2055 }
2056 /* make sure the file is removed on unref of the giochannel */
2057 else
2058 {
2059 g_unlink (tname);
2060 return gio;
2061 }
2062 }
2063 }
2064
2065 return NULL;
2066 }
2067
2068 static void
atk_streamable_content_interface_init(AtkStreamableContentIface * iface)2069 atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
2070 {
2071 iface->get_n_mime_types = gail_streamable_content_get_n_mime_types;
2072 iface->get_mime_type = gail_streamable_content_get_mime_type;
2073 iface->get_stream = gail_streamable_content_get_stream;
2074 }
2075
2076 void
_gtk_text_view_accessible_set_buffer(GtkTextView * textview,GtkTextBuffer * old_buffer)2077 _gtk_text_view_accessible_set_buffer (GtkTextView *textview,
2078 GtkTextBuffer *old_buffer)
2079 {
2080 GtkTextViewAccessible *accessible;
2081
2082 g_return_if_fail (GTK_IS_TEXT_VIEW (textview));
2083 g_return_if_fail (old_buffer == NULL || GTK_IS_TEXT_BUFFER (old_buffer));
2084
2085 accessible = GTK_TEXT_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (textview)));
2086 if (accessible == NULL)
2087 return;
2088
2089 gtk_text_view_accessible_change_buffer (accessible,
2090 old_buffer,
2091 gtk_text_view_get_buffer (textview));
2092 }
2093
2094