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