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