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