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