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