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