]> Pileus Git - ~andy/gtk/blobdiff - gtk/a11y/gtktextviewaccessible.c
Change FSF Address
[~andy/gtk] / gtk / a11y / gtktextviewaccessible.c
index 4f4e9f4ff5dd5d1c9b14ba4139e146a2fc7ab6db..8931754b86a80117a710b853ebcb28c4073d5170 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
 
 #include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <string.h>
 #include <stdlib.h>
 #include <glib-object.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
 #include "gtktextviewaccessible.h"
-#include "gailmisc.h"
+#include "gtk/gtkwidgetprivate.h"
 
 
-static void setup_buffer (GtkTextView           *view,GtkTextViewAccessible *accessible);
 static void       insert_text_cb       (GtkTextBuffer    *buffer,
                                                         GtkTextIter      *arg1,
                                                         gchar            *arg2,
@@ -40,20 +41,17 @@ static void       delete_range_cb      (GtkTextBuffer    *buffer,
                                                         GtkTextIter      *arg1,
                                                         GtkTextIter      *arg2,
                                                         gpointer         user_data);
-static void       changed_cb           (GtkTextBuffer    *buffer,
-                                                        gpointer         user_data);
 static void       mark_set_cb          (GtkTextBuffer    *buffer,
                                                         GtkTextIter      *arg1,
                                                         GtkTextMark      *arg2,
                                                         gpointer         user_data);
-static gint             insert_idle_handler            (gpointer         data);
 
 
 static void atk_editable_text_interface_init      (AtkEditableTextIface      *iface);
 static void atk_text_interface_init               (AtkTextIface              *iface);
 static void atk_streamable_content_interface_init (AtkStreamableContentIface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GtkTextViewAccessible, gtk_text_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
+G_DEFINE_TYPE_WITH_CODE (GtkTextViewAccessible, _gtk_text_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
                          G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
                          G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
                          G_IMPLEMENT_INTERFACE (ATK_TYPE_STREAMABLE_CONTENT, atk_streamable_content_interface_init))
@@ -63,24 +61,11 @@ static void
 gtk_text_view_accessible_initialize (AtkObject *obj,
                                      gpointer   data)
 {
-  ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->initialize (obj, data);
-
-  setup_buffer (GTK_TEXT_VIEW (data), GTK_TEXT_VIEW_ACCESSIBLE (obj));
+  ATK_OBJECT_CLASS (_gtk_text_view_accessible_parent_class)->initialize (obj, data);
 
   obj->role = ATK_ROLE_TEXT;
 }
 
-static void
-gtk_text_view_accessible_finalize (GObject *object)
-{
-  GtkTextViewAccessible *text_view = GTK_TEXT_VIEW_ACCESSIBLE (object);
-
-  if (text_view->insert_notify_handler)
-    g_source_remove (text_view->insert_notify_handler);
-
-  G_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->finalize (object);
-}
-
 static void
 gtk_text_view_accessible_notify_gtk (GObject    *obj,
                                      GParamSpec *pspec)
@@ -96,12 +81,8 @@ gtk_text_view_accessible_notify_gtk (GObject    *obj,
       editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
       atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, editable);
     }
-  else if (!strcmp (pspec->name, "buffer"))
-    {
-      setup_buffer (GTK_TEXT_VIEW (obj), GTK_TEXT_VIEW_ACCESSIBLE (atk_obj));
-    }
   else
-    GTK_WIDGET_ACCESSIBLE_CLASS (gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec);
+    GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec);
 }
 
 static AtkStateSet*
@@ -114,7 +95,7 @@ gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
   if (widget == NULL)
     return NULL;
 
-  state_set = ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->ref_state_set (accessible);
+  state_set = ATK_OBJECT_CLASS (_gtk_text_view_accessible_parent_class)->ref_state_set (accessible);
 
   if (gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)))
     atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
@@ -124,42 +105,58 @@ gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
 }
 
 static void
-gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
+gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible,
+                                        GtkTextBuffer         *old_buffer,
+                                        GtkTextBuffer         *new_buffer)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
-  GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
-
-  gobject_class->finalize = gtk_text_view_accessible_finalize;
+  if (old_buffer)
+    {
+      g_signal_handlers_disconnect_matched (old_buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, accessible);
+    }
 
-  class->ref_state_set = gtk_text_view_accessible_ref_state_set;
-  class->initialize = gtk_text_view_accessible_initialize;
+  if (new_buffer)
+    {
+      g_signal_connect_after (new_buffer, "insert-text", G_CALLBACK (insert_text_cb), accessible);
+      g_signal_connect (new_buffer, "delete-range", G_CALLBACK (delete_range_cb), accessible);
+      g_signal_connect_after (new_buffer, "mark-set", G_CALLBACK (mark_set_cb), accessible);
+    }
+}
 
-  widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
+static void
+gtk_text_view_accessible_widget_set (GtkAccessible *accessible)
+{
+  gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
+                                          NULL,
+                                          gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))));
 }
 
 static void
-gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
+gtk_text_view_accessible_widget_unset (GtkAccessible *accessible)
 {
-  accessible->signal_name = NULL;
-  accessible->previous_insert_offset = -1;
-  accessible->previous_selection_bound = -1;
-  accessible->insert_notify_handler = 0;
+  gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
+                                          gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))),
+                                          NULL);
 }
 
 static void
-setup_buffer (GtkTextView           *view,
-              GtkTextViewAccessible *accessible)
+_gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
 {
-  GtkTextBuffer *buffer;
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
+  GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
 
-  buffer = gtk_text_view_get_buffer (view);
+  accessible_class->widget_set = gtk_text_view_accessible_widget_set;
+  accessible_class->widget_unset = gtk_text_view_accessible_widget_unset;
 
-  /* Set up signal callbacks */
-  g_signal_connect (buffer, "insert-text", G_CALLBACK (insert_text_cb), view);
-  g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view);
-  g_signal_connect (buffer, "mark-set", G_CALLBACK (mark_set_cb), view);
-  g_signal_connect (buffer, "changed", G_CALLBACK (changed_cb), view);
+  class->ref_state_set = gtk_text_view_accessible_ref_state_set;
+  class->initialize = gtk_text_view_accessible_initialize;
+
+  widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
+}
+
+static void
+_gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
+{
 }
 
 static gchar *
@@ -192,6 +189,7 @@ gtk_text_view_accessible_get_text_after_offset (AtkText         *text,
                                                 gint            *end_offset)
 {
   GtkWidget *widget;
+  GtkTextView *view;
   GtkTextBuffer *buffer;
   GtkTextIter pos;
   GtkTextIter start, end;
@@ -200,12 +198,29 @@ gtk_text_view_accessible_get_text_after_offset (AtkText         *text,
   if (widget == NULL)
     return NULL;
 
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+  view = GTK_TEXT_VIEW (widget);
+  buffer = gtk_text_view_get_buffer (view);
   gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
-  _gtk_text_buffer_get_text_after (buffer, boundary_type,
-                                   &pos, &start, &end);
+  start = end = pos;
+  if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
+    {
+      gtk_text_view_forward_display_line (view, &end);
+      start = end;
+      gtk_text_view_forward_display_line (view, &end);
+    }
+  else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
+    {
+      gtk_text_view_forward_display_line_end (view, &end);
+      start = end;
+      gtk_text_view_forward_display_line (view, &end);
+      gtk_text_view_forward_display_line_end (view, &end);
+    }
+  else
+    _gtk_text_buffer_get_text_after (buffer, boundary_type, &pos, &start, &end);
+
   *start_offset = gtk_text_iter_get_offset (&start);
   *end_offset = gtk_text_iter_get_offset (&end);
+
   return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
 }
 
@@ -217,6 +232,7 @@ gtk_text_view_accessible_get_text_at_offset (AtkText         *text,
                                              gint            *end_offset)
 {
   GtkWidget *widget;
+  GtkTextView *view;
   GtkTextBuffer *buffer;
   GtkTextIter pos;
   GtkTextIter start, end;
@@ -225,12 +241,31 @@ gtk_text_view_accessible_get_text_at_offset (AtkText         *text,
   if (widget == NULL)
     return NULL;
 
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+  view = GTK_TEXT_VIEW (widget);
+  buffer = gtk_text_view_get_buffer (view);
   gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
-  _gtk_text_buffer_get_text_at (buffer, boundary_type,
-                                &pos, &start, &end);
+  start = end = pos;
+  if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
+    {
+      gtk_text_view_backward_display_line_start (view, &start);
+      gtk_text_view_forward_display_line (view, &end);
+    }
+  else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
+    {
+      gtk_text_view_backward_display_line_start (view, &start);
+      if (!gtk_text_iter_is_start (&start))
+        {
+          gtk_text_view_backward_display_line (view, &start);
+          gtk_text_view_forward_display_line_end (view, &start);
+        }
+      gtk_text_view_forward_display_line_end (view, &end);
+    }
+  else
+    _gtk_text_buffer_get_text_at (buffer, boundary_type, &pos, &start, &end);
+
   *start_offset = gtk_text_iter_get_offset (&start);
   *end_offset = gtk_text_iter_get_offset (&end);
+
   return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
 }
 
@@ -242,6 +277,7 @@ gtk_text_view_accessible_get_text_before_offset (AtkText         *text,
                                                  gint            *end_offset)
 {
   GtkWidget *widget;
+  GtkTextView *view;
   GtkTextBuffer *buffer;
   GtkTextIter pos;
   GtkTextIter start, end;
@@ -250,12 +286,43 @@ gtk_text_view_accessible_get_text_before_offset (AtkText         *text,
   if (widget == NULL)
     return NULL;
 
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+  view = GTK_TEXT_VIEW (widget);
+  buffer = gtk_text_view_get_buffer (view);
   gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
-  _gtk_text_buffer_get_text_before (buffer, boundary_type,
-                                    &pos, &start, &end);
+  start = end = pos;
+
+  if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START)
+    {
+      gtk_text_view_backward_display_line_start (view, &start);
+      end = start;
+      gtk_text_view_backward_display_line (view, &start);
+      gtk_text_view_backward_display_line_start (view, &start);
+    }
+  else if (boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
+    {
+      gtk_text_view_backward_display_line_start (view, &start);
+      if (!gtk_text_iter_is_start (&start))
+        {
+          gtk_text_view_backward_display_line (view, &start);
+          end = start;
+          gtk_text_view_forward_display_line_end (view, &end);
+          if (!gtk_text_iter_is_start (&start))
+            {
+              if (gtk_text_view_backward_display_line (view, &start))
+                gtk_text_view_forward_display_line_end (view, &start);
+              else
+                gtk_text_iter_set_offset (&start, 0);
+            }
+        }
+      else
+        end = start;
+    }
+  else
+    _gtk_text_buffer_get_text_before (buffer, boundary_type, &pos, &start, &end);
+
   *start_offset = gtk_text_iter_get_offset (&start);
   *end_offset = gtk_text_iter_get_offset (&end);
+
   return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
 }
 
@@ -460,6 +527,33 @@ gtk_text_view_accessible_get_character_extents (AtkText      *text,
     }
 }
 
+static AtkAttributeSet *
+add_text_attribute (AtkAttributeSet  *attributes,
+                    AtkTextAttribute  attr,
+                    gchar            *value)
+{
+  AtkAttribute *at;
+
+  at = g_new (AtkAttribute, 1);
+  at->name = g_strdup (atk_text_attribute_get_name (attr));
+  at->value = value;
+
+  return g_slist_prepend (attributes, at);
+}
+
+static AtkAttributeSet *
+add_text_int_attribute (AtkAttributeSet  *attributes,
+                        AtkTextAttribute  attr,
+                        gint              i)
+
+{
+  gchar *value;
+
+  value = g_strdup (atk_text_attribute_get_value (attr, i));
+
+  return add_text_attribute (attributes, attr, value);
+}
+
 static AtkAttributeSet *
 gtk_text_view_accessible_get_run_attributes (AtkText *text,
                                              gint     offset,
@@ -469,6 +563,12 @@ gtk_text_view_accessible_get_run_attributes (AtkText *text,
   GtkTextView *view;
   GtkTextBuffer *buffer;
   GtkWidget *widget;
+  GtkTextIter iter;
+  AtkAttributeSet *attrib_set = NULL;
+  GSList *tags, *temp_tags;
+  gdouble scale = 1;
+  gboolean val_set = FALSE;
+
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
@@ -477,23 +577,468 @@ gtk_text_view_accessible_get_run_attributes (AtkText *text,
   view = GTK_TEXT_VIEW (widget);
   buffer = gtk_text_view_get_buffer (view);
 
-  return gail_misc_buffer_get_run_attributes (buffer, offset,
-                                              start_offset, end_offset);
-}
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
 
-static AtkAttributeSet *
-add_text_attribute (AtkAttributeSet  *attributes,
-                    AtkTextAttribute  attr,
-                    gint              i)
-{
-  AtkAttribute *at;
+  gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
+  *end_offset = gtk_text_iter_get_offset (&iter);
 
-  at = g_new (AtkAttribute, 1);
+  gtk_text_iter_backward_to_tag_toggle (&iter, NULL);
+  *start_offset = gtk_text_iter_get_offset (&iter);
 
-  at->name = g_strdup (atk_text_attribute_get_name (attr));
-  at->value = g_strdup (atk_text_attribute_get_value (attr, i));
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
 
-  return g_slist_prepend (attributes, at);
+  tags = gtk_text_iter_get_tags (&iter);
+  tags = g_slist_reverse (tags);
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "style-set", &val_set, NULL);
+      if (val_set)
+        {
+          PangoStyle style;
+          g_object_get (tag, "style", &style, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STYLE, style);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "variant-set", &val_set, NULL);
+      if (val_set)
+        {
+          PangoVariant variant;
+          g_object_get (tag, "variant", &variant, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT, variant);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "stretch-set", &val_set, NULL);
+      if (val_set)
+        {
+          PangoStretch stretch;
+          g_object_get (tag, "stretch", &stretch, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH, stretch);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "justification-set", &val_set, NULL);
+      if (val_set)
+        {
+          GtkJustification justification;
+          g_object_get (tag, "justification", &justification, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_JUSTIFICATION, justification);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      GtkTextDirection direction;
+
+      g_object_get (tag, "direction", &direction, NULL);
+
+      if (direction != GTK_TEXT_DIR_NONE)
+        {
+          val_set = TRUE;
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_DIRECTION, direction);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "wrap-mode-set", &val_set, NULL);
+      if (val_set)
+        {
+          GtkWrapMode wrap_mode;
+          g_object_get (tag, "wrap-mode", &wrap_mode, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_WRAP_MODE, wrap_mode);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "foreground-set", &val_set, NULL);
+      if (val_set)
+        {
+          GdkRGBA *rgba;
+          gchar *value;
+
+          g_object_get (tag, "foreground-rgba", &rgba, NULL);
+          value = g_strdup_printf ("%u,%u,%u",
+                                   (guint) rgba->red * 65535,
+                                   (guint) rgba->green * 65535,
+                                   (guint) rgba->blue * 65535);
+          gdk_rgba_free (rgba);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "background-set", &val_set, NULL);
+      if (val_set)
+        {
+          GdkRGBA *rgba;
+          gchar *value;
+
+          g_object_get (tag, "background-rgba", &rgba, NULL);
+          value = g_strdup_printf ("%u,%u,%u",
+                                   (guint) rgba->red * 65535,
+                                   (guint) rgba->green * 65535,
+                                   (guint) rgba->blue * 65535);
+          gdk_rgba_free (rgba);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_BG_COLOR, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "family-set", &val_set, NULL);
+
+      if (val_set)
+        {
+          gchar *value;
+          g_object_get (tag, "family", &value, NULL);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "language-set", &val_set, NULL);
+
+      if (val_set)
+        {
+          gchar *value;
+          g_object_get (tag, "language", &value, NULL);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "weight-set", &val_set, NULL);
+
+      if (val_set)
+        {
+          gint weight;
+          gchar *value;
+          g_object_get (tag, "weight", &weight, NULL);
+          value = g_strdup_printf ("%d", weight);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  /* scale is special as the effective value is the product
+   * of all specified values
+   */
+  temp_tags = tags;
+  while (temp_tags)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+      gboolean scale_set;
+
+      g_object_get (tag, "scale-set", &scale_set, NULL);
+      if (scale_set)
+        {
+          gdouble font_scale;
+          g_object_get (tag, "scale", &font_scale, NULL);
+          val_set = TRUE;
+          scale *= font_scale;
+        }
+      temp_tags = temp_tags->next;
+    }
+  if (val_set)
+    {
+      gchar *value;
+      value = g_strdup_printf ("%g", scale);
+      attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_SCALE, value);
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "size-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint size;
+          gchar *value;
+          g_object_get (tag, "size", &size, NULL);
+          value = g_strdup_printf ("%i", size);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "strikethrough-set", &val_set, NULL);
+      if (val_set)
+        {
+          gboolean strikethrough;
+          g_object_get (tag, "strikethrough", &strikethrough, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_STRIKETHROUGH, strikethrough);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "underline-set", &val_set, NULL);
+      if (val_set)
+        {
+          PangoUnderline underline;
+          g_object_get (tag, "underline", &underline, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_UNDERLINE, underline);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "rise-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint rise;
+          gchar *value;
+          g_object_get (tag, "rise", &rise, NULL);
+          value = g_strdup_printf ("%i", rise);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_RISE, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "background-full-height-set", &val_set, NULL);
+      if (val_set)
+        {
+          gboolean bg_full_height;
+          g_object_get (tag, "background-full-height", &bg_full_height, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_BG_FULL_HEIGHT, bg_full_height);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "pixels-inside-wrap-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint pixels;
+          gchar *value;
+          g_object_get (tag, "pixels-inside-wrap", &pixels, NULL);
+          value = g_strdup_printf ("%i", pixels);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "pixels-below-lines-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint pixels;
+          gchar *value;
+          g_object_get (tag, "pixels-below-lines", &pixels, NULL);
+          value = g_strdup_printf ("%i", pixels);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "pixels-above-lines-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint pixels;
+          gchar *value;
+          g_object_get (tag, "pixels-above-lines", &pixels, NULL);
+          value = g_strdup_printf ("%i", pixels);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "editable-set", &val_set, NULL);
+      if (val_set)
+        {
+          gboolean editable;
+          g_object_get (tag, "editable", &editable, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_EDITABLE, editable);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "invisible-set", &val_set, NULL);
+      if (val_set)
+        {
+          gboolean invisible;
+          g_object_get (tag, "invisible", &invisible, NULL);
+          attrib_set = add_text_int_attribute (attrib_set, ATK_TEXT_ATTR_INVISIBLE, invisible);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "indent-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint indent;
+          gchar *value;
+          g_object_get (tag, "indent", &indent, NULL);
+          value = g_strdup_printf ("%i", indent);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_INDENT, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "right-margin-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint margin;
+          gchar *value;
+          g_object_get (tag, "right-margin", &margin, NULL);
+          value = g_strdup_printf ("%i", margin);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  temp_tags = tags;
+  while (temp_tags && !val_set)
+    {
+      GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
+
+      g_object_get (tag, "left-margin-set", &val_set, NULL);
+      if (val_set)
+        {
+          gint margin;
+          gchar *value;
+          g_object_get (tag, "left-margin", &margin, NULL);
+          value = g_strdup_printf ("%i", margin);
+          attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_LEFT_MARGIN, value);
+        }
+      temp_tags = temp_tags->next;
+    }
+  val_set = FALSE;
+
+  g_slist_free (tags);
+  return attrib_set;
 }
 
 static AtkAttributeSet *
@@ -519,75 +1064,75 @@ gtk_text_view_accessible_get_default_attributes (AtkText *text)
 
   if (font)
     {
-      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STYLE,
-                                       pango_font_description_get_style (font));
+      attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STYLE,
+                                           pango_font_description_get_style (font));
 
-      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
-                                       pango_font_description_get_variant (font));
+      attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
+                                           pango_font_description_get_variant (font));
 
-      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
-                                       pango_font_description_get_stretch (font));
+      attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
+                                           pango_font_description_get_stretch (font));
 
       value = g_strdup (pango_font_description_get_family (font));
-      attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
+      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
 
       value = g_strdup_printf ("%d", pango_font_description_get_weight (font));
-      attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
+      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
 
       value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE);
-      attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
+      attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
     }
 
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
 
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
-                                   text_attrs->appearance.strikethrough);
-  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
-                                   text_attrs->appearance.underline);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
+                                       text_attrs->appearance.strikethrough);
+  attributes = add_text_int_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
+                                       text_attrs->appearance.underline);
 
   value = g_strdup_printf ("%u,%u,%u",
                            text_attrs->appearance.bg_color.red,
                            text_attrs->appearance.bg_color.green,
                            text_attrs->appearance.bg_color.blue);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
 
   value = g_strdup_printf ("%u,%u,%u",
                            text_attrs->appearance.fg_color.red,
                            text_attrs->appearance.fg_color.green,
                            text_attrs->appearance.fg_color.blue);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
 
   value = g_strdup_printf ("%g", text_attrs->font_scale);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
 
   value = g_strdup ((gchar *)(text_attrs->language));
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, value);
 
   value = g_strdup_printf ("%i", text_attrs->appearance.rise);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
 
   value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
 
   value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
 
   value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
 
   value = g_strdup_printf ("%i", text_attrs->indent);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_INDENT, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_INDENT, value);
 
   value = g_strdup_printf ("%i", text_attrs->left_margin);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, value);
 
   value = g_strdup_printf ("%i", text_attrs->right_margin);
-  attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
+  attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
 
   gtk_text_attributes_unref (text_attrs);
   return attributes;
@@ -802,22 +1347,22 @@ gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
       value = at->value;
 
       if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
-        g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL);
+        g_object_set (G_OBJECT (tag), "left-margin", atoi (value), NULL);
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
-        g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL);
+        g_object_set (G_OBJECT (tag), "right-margin", atoi (value), NULL);
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
         g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
-        g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL);
+        g_object_set (G_OBJECT (tag), "pixels-above-lines", atoi (value), NULL);
 
       else if (!strcmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
-        g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL);
+        g_object_set (G_OBJECT (tag), "pixels-below-lines", atoi (value), NULL);
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
-        g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL);
+        g_object_set (G_OBJECT (tag), "pixels-inside-wrap", atoi (value), NULL);
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
         g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
@@ -830,7 +1375,7 @@ gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
         {
-          g_object_set (G_OBJECT (tag), "bg_full_height",
+          g_object_set (G_OBJECT (tag), "bg-full-height",
                    (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
                    NULL);
         }
@@ -881,7 +1426,7 @@ gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
           color->red = atoi (RGB_vals[0]);
           color->green = atoi (RGB_vals[1]);
           color->blue = atoi (RGB_vals[2]);
-          g_object_set (G_OBJECT (tag), "background_gdk", color, NULL);
+          g_object_set (G_OBJECT (tag), "background-gdk", color, NULL);
         }
  
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
@@ -891,7 +1436,7 @@ gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
           color->red = atoi (RGB_vals[0]);
           color->green = atoi (RGB_vals[1]);
           color->blue = atoi (RGB_vals[2]);
-          g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL);
+          g_object_set (G_OBJECT (tag), "foreground-gdk", color, NULL);
         }
 
       else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
@@ -948,7 +1493,7 @@ gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
             {
               if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
                 {
-                  g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL);
+                  g_object_set (G_OBJECT (tag), "wrap-mode", j, NULL);
                   break;
                 }
             }
@@ -1162,6 +1707,35 @@ atk_editable_text_interface_init (AtkEditableTextIface *iface)
 
 /* Callbacks */
 
+static void
+gtk_text_view_accessible_update_cursor (GtkTextViewAccessible *accessible,
+                                        GtkTextBuffer *        buffer)
+{
+  int prev_insert_offset, prev_selection_bound;
+  int insert_offset, selection_bound;
+  GtkTextIter iter;
+
+  prev_insert_offset = accessible->insert_offset;
+  prev_selection_bound = accessible->selection_bound;
+
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
+  insert_offset = gtk_text_iter_get_offset (&iter);
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_selection_bound (buffer));
+  selection_bound = gtk_text_iter_get_offset (&iter);
+
+  if (prev_insert_offset == insert_offset && prev_selection_bound == selection_bound)
+    return;
+
+  accessible->insert_offset = insert_offset;
+  accessible->selection_bound = selection_bound;
+
+  if (prev_insert_offset != insert_offset)
+    g_signal_emit_by_name (accessible, "text-caret-moved", insert_offset);
+
+  if (prev_insert_offset != prev_selection_bound || insert_offset != selection_bound)
+    g_signal_emit_by_name (accessible, "text-selection-changed");
+}
+
 static void
 insert_text_cb (GtkTextBuffer *buffer,
                 GtkTextIter   *iter,
@@ -1169,40 +1743,16 @@ insert_text_cb (GtkTextBuffer *buffer,
                 gint           len,
                 gpointer       data)
 {
-  GtkTextView *view = data;
-  GtkTextViewAccessible *accessible;
+  GtkTextViewAccessible *accessible = data;
   gint position;
   gint length;
 
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
-
-  accessible->signal_name = "text_changed::insert";
   position = gtk_text_iter_get_offset (iter);
   length = g_utf8_strlen (text, len);
  
-  if (accessible->length == 0)
-    {
-      accessible->position = position;
-      accessible->length = length;
-    }
-  else if (accessible->position + accessible->length == position)
-    {
-      accessible->length += length;
-    }
-  else
-    {
-      /*
-       * We have a non-contiguous insert so report what we have
-       */
-      if (accessible->insert_notify_handler)
-        {
-          g_source_remove (accessible->insert_notify_handler);
-        }
-      accessible->insert_notify_handler = 0;
-      insert_idle_handler (accessible);
-      accessible->position = position;
-      accessible->length = length;
-    }
+  g_signal_emit_by_name (accessible, "text-changed::insert", position - length, length);
+
+  gtk_text_view_accessible_update_cursor (accessible, buffer);
 }
 
 static void
@@ -1211,73 +1761,18 @@ delete_range_cb (GtkTextBuffer *buffer,
                  GtkTextIter   *end,
                  gpointer       data)
 {
-  GtkTextView *text = data;
-  GtkTextViewAccessible *accessible;
-  gint offset;
-  gint length;
-
+  GtkTextViewAccessible *accessible = data;
+  gint offset, length;
 
   offset = gtk_text_iter_get_offset (start);
   length = gtk_text_iter_get_offset (end) - offset;
 
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
-  if (accessible->insert_notify_handler)
-    {
-      g_source_remove (accessible->insert_notify_handler);
-      accessible->insert_notify_handler = 0;
-      if (accessible->position == offset &&
-          accessible->length == length)
-        {
-        /*
-         * Do not bother with insert and delete notifications
-         */
-          accessible->signal_name = NULL;
-          accessible->position = 0;
-          accessible->length = 0;
-          return;
-        }
-
-      insert_idle_handler (accessible);
-    }
-  g_signal_emit_by_name (accessible, "text_changed::delete", offset, length);
-}
-
-static gint
-get_selection_bound (GtkTextBuffer *buffer)
-{
-  GtkTextMark *bound;
-  GtkTextIter iter;
-
-  bound = gtk_text_buffer_get_selection_bound (buffer);
-  gtk_text_buffer_get_iter_at_mark (buffer, &iter, bound);
-  return gtk_text_iter_get_offset (&iter);
-}
-
-static void
-emit_text_caret_moved (GtkTextViewAccessible *accessible,
-                       gint                   offset)
-{
-  /*
-   * If we have text which has been inserted notify the user
-   */
-  if (accessible->insert_notify_handler)
-    {
-      g_source_remove (accessible->insert_notify_handler);
-      accessible->insert_notify_handler = 0;
-      insert_idle_handler (accessible);
-    }
+  g_signal_emit_by_name (accessible,
+                         "text-changed::delete",
+                         offset,
+                         length);
 
-  if (offset != accessible->previous_insert_offset)
-    {
-      /*
-       * If the caret position has not changed then don't bother notifying
-       *
-       * When mouse click is used to change caret position, notification
-       * is received on button down and button up.
-       */
-      g_signal_emit_by_name (accessible, "text_caret_moved", offset);
-      accessible->previous_insert_offset = offset;
-    }
+  gtk_text_view_accessible_update_cursor (accessible, buffer);
 }
 
 static void
@@ -1286,10 +1781,7 @@ mark_set_cb (GtkTextBuffer *buffer,
              GtkTextMark   *mark,
              gpointer       data)
 {
-  GtkTextView *text = data;
-  GtkTextViewAccessible *accessible;
-
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
+  GtkTextViewAccessible *accessible = data;
 
   /*
    * Only generate the signal for the "insert" mark, which
@@ -1297,84 +1789,12 @@ mark_set_cb (GtkTextBuffer *buffer,
    */
   if (mark == gtk_text_buffer_get_insert (buffer))
     {
-      gint insert_offset, selection_bound;
-      gboolean selection_changed;
-
-      insert_offset = gtk_text_iter_get_offset (location);
-
-      selection_bound = get_selection_bound (buffer);
-      if (selection_bound != insert_offset)
-        {
-          if (selection_bound != accessible->previous_selection_bound ||
-              insert_offset != accessible->previous_insert_offset)
-            selection_changed = TRUE;
-          else
-            selection_changed = FALSE;
-        }
-      else if (accessible->previous_selection_bound != accessible->previous_insert_offset)
-        selection_changed = TRUE;
-      else
-        selection_changed = FALSE;
-
-      emit_text_caret_moved (accessible, insert_offset);
-      /*
-       * insert and selection_bound marks are different to a selection
-       * has changed
-       */
-      if (selection_changed)
-        g_signal_emit_by_name (accessible, "text_selection_changed");
-      accessible->previous_selection_bound = selection_bound;
+      gtk_text_view_accessible_update_cursor (accessible, buffer);
     }
-}
-
-static void
-changed_cb (GtkTextBuffer *buffer,
-            gpointer       data)
-{
-  GtkTextView *text = data;
-  GtkTextViewAccessible *accessible;
-
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
-  if (accessible->signal_name)
+  else if (mark == gtk_text_buffer_get_selection_bound (buffer))
     {
-      if (!accessible->insert_notify_handler)
-        {
-          accessible->insert_notify_handler = gdk_threads_add_idle (insert_idle_handler, accessible);
-        }
-      return;
+      gtk_text_view_accessible_update_cursor (accessible, buffer);
     }
-  emit_text_caret_moved (accessible, get_insert_offset (buffer));
-  accessible->previous_selection_bound = get_selection_bound (buffer);
-}
-
-static gint
-insert_idle_handler (gpointer data)
-{
-  GtkTextViewAccessible *accessible = data;
-  GtkWidget *widget;
-  GtkTextBuffer *buffer;
-
-  g_signal_emit_by_name (data,
-                         accessible->signal_name,
-                         accessible->position,
-                         accessible->length);
-  accessible->signal_name = NULL;
-  accessible->position = 0;
-  accessible->length = 0;
-
-  widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
-  if (accessible->insert_notify_handler)
-    {
-    /*
-     * If called from idle handler notify caret moved
-     */
-      accessible->insert_notify_handler = 0;
-      emit_text_caret_moved (accessible, get_insert_offset (buffer));
-      accessible->previous_selection_bound = get_selection_bound (buffer);
-    }
-
-  return FALSE;
 }
 
 static gint
@@ -1516,3 +1936,22 @@ atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
   iface->get_mime_type = gail_streamable_content_get_mime_type;
   iface->get_stream = gail_streamable_content_get_stream;
 }
+
+void
+_gtk_text_view_accessible_set_buffer (GtkTextView   *textview,
+                                      GtkTextBuffer *old_buffer)
+{
+  GtkTextViewAccessible *accessible;
+
+  g_return_if_fail (GTK_IS_TEXT_VIEW (textview));
+  g_return_if_fail (old_buffer == NULL || GTK_IS_TEXT_BUFFER (old_buffer));
+
+  accessible = GTK_TEXT_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (textview)));
+  if (accessible == NULL)
+    return;
+
+  gtk_text_view_accessible_change_buffer (accessible,
+                                          old_buffer,
+                                          gtk_text_view_get_buffer (textview));
+}
+