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