]> Pileus Git - ~andy/gtk/blobdiff - gtk/a11y/gtktextviewaccessible.c
filechooserbutton: Emit 'selection-changed' when changing the selection programmatically
[~andy/gtk] / gtk / a11y / gtktextviewaccessible.c
index d0fa153c42c13c57c069cbb88db9cdc237f01860..ca07161d22e37e92e93d1480daddd82d99aba22a 100644 (file)
@@ -1,4 +1,4 @@
-/* GAIL - The GNOME Accessibility Implementation Library
+/* GTK+ - accessibility implementations
  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -12,9 +12,7 @@
  * 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 <glib-object.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
-#include "gtktextviewaccessible.h"
+#include "gtktextviewaccessibleprivate.h"
+#include "gtk/gtkwidgetprivate.h"
 
+struct _GtkTextViewAccessiblePrivate
+{
+  gint insert_offset;
+  gint selection_bound;
+};
 
-static void setup_buffer (GtkTextView           *view,GtkTextViewAccessible *accessible);
 static void       insert_text_cb       (GtkTextBuffer    *buffer,
                                                         GtkTextIter      *arg1,
                                                         gchar            *arg2,
@@ -53,7 +56,7 @@ static void atk_editable_text_interface_init      (AtkEditableTextIface      *if
 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,9 +66,7 @@ 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;
 }
@@ -85,12 +86,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*
@@ -103,7 +100,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);
@@ -113,34 +110,73 @@ 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)
 {
-  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
-  GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
+  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;
+      g_signal_emit_by_name (accessible,
+                             "text-changed::delete",
+                             0,
+                             gtk_text_buffer_get_char_count (old_buffer));
+    }
 
-  widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
+  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);
+
+      g_signal_emit_by_name (accessible,
+                             "text-changed::insert",
+                             0,
+                             gtk_text_buffer_get_char_count (new_buffer));
+    }
 }
 
 static void
-_gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
+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
-setup_buffer (GtkTextView           *view,
-              GtkTextViewAccessible *accessible)
+gtk_text_view_accessible_widget_unset (GtkAccessible *accessible)
 {
-  GtkTextBuffer *buffer;
+  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);
+}
 
-  buffer = gtk_text_view_get_buffer (view);
+static void
+gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
+{
+  AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
+  GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
+
+  accessible_class->widget_set = gtk_text_view_accessible_widget_set;
+  accessible_class->widget_unset = gtk_text_view_accessible_widget_unset;
+
+  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;
 
-  /* Set up signal callbacks */
-  g_signal_connect_after (buffer, "insert-text", G_CALLBACK (insert_text_cb), view);
-  g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view);
-  g_signal_connect_after (buffer, "mark-set", G_CALLBACK (mark_set_cb), view);
+  g_type_class_add_private (klass, sizeof (GtkTextViewAccessiblePrivate));
+}
+
+static void
+gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
+{
+  accessible->priv = G_TYPE_INSTANCE_GET_PRIVATE (accessible,
+                                                  GTK_TYPE_TEXT_VIEW_ACCESSIBLE,
+                                                  GtkTextViewAccessiblePrivate);
 }
 
 static gchar *
@@ -173,6 +209,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;
@@ -181,12 +218,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);
 }
 
@@ -198,6 +252,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;
@@ -206,12 +261,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);
 }
 
@@ -223,6 +297,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;
@@ -231,12 +306,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);
 }
 
@@ -483,7 +589,6 @@ gtk_text_view_accessible_get_run_attributes (AtkText *text,
   gdouble scale = 1;
   gboolean val_set = FALSE;
 
-
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     return NULL;
@@ -1261,22 +1366,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);
@@ -1289,7 +1394,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);
         }
@@ -1340,7 +1445,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)))
@@ -1350,7 +1455,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)))
@@ -1407,7 +1512,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;
                 }
             }
@@ -1629,8 +1734,8 @@ gtk_text_view_accessible_update_cursor (GtkTextViewAccessible *accessible,
   int insert_offset, selection_bound;
   GtkTextIter iter;
 
-  prev_insert_offset = accessible->insert_offset;
-  prev_selection_bound = accessible->selection_bound;
+  prev_insert_offset = accessible->priv->insert_offset;
+  prev_selection_bound = accessible->priv->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);
@@ -1640,8 +1745,8 @@ gtk_text_view_accessible_update_cursor (GtkTextViewAccessible *accessible,
   if (prev_insert_offset == insert_offset && prev_selection_bound == selection_bound)
     return;
 
-  accessible->insert_offset = insert_offset;
-  accessible->selection_bound = selection_bound;
+  accessible->priv->insert_offset = insert_offset;
+  accessible->priv->selection_bound = selection_bound;
 
   if (prev_insert_offset != insert_offset)
     g_signal_emit_by_name (accessible, "text-caret-moved", insert_offset);
@@ -1657,13 +1762,10 @@ 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)));
-
   position = gtk_text_iter_get_offset (iter);
   length = g_utf8_strlen (text, len);
  
@@ -1678,17 +1780,14 @@ delete_range_cb (GtkTextBuffer *buffer,
                  GtkTextIter   *end,
                  gpointer       data)
 {
-  GtkTextView *view = data;
-  GtkTextViewAccessible *accessible;
+  GtkTextViewAccessible *accessible = data;
   gint offset, length;
 
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
-
   offset = gtk_text_iter_get_offset (start);
   length = gtk_text_iter_get_offset (end) - offset;
 
   g_signal_emit_by_name (accessible,
-                         "text_changed::delete",
+                         "text-changed::delete",
                          offset,
                          length);
 
@@ -1701,10 +1800,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
@@ -1859,3 +1955,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));
+}
+