]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextbtree.c
Make PLT-reduction work with gcc4, and don't include everything in
[~andy/gtk] / gtk / gtktextbtree.c
index 7f270e19a8da16ceab35e61e44517b0775d93661..ac5a9fc9043f4f4b7e0cd6ec3824b36b6ce73c40 100644 (file)
  */
 
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
+#include <config.h>
 #include "gtktextbtree.h"
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include "gtksignal.h"
 #include "gtktexttag.h"
 #include "gtktexttagtable.h"
 #include "gtktextlayout.h"
 #include "gtktextiterprivate.h"
 #include "gtkdebug.h"
 #include "gtktextmarkprivate.h"
+#include "gtkalias.h"
 
 /*
  * Types
@@ -100,7 +101,7 @@ struct _NodeData {
 
   /* Height and width of this node */
   gint height;
-  gint width : 24;
+  signed int width : 24;
 
   /* boolean indicating whether the lines below this node are in need of validation.
    * However, width/height should always represent the current total width and
@@ -108,7 +109,7 @@ struct _NodeData {
    * width/height on the lines needs recomputing, not whether the totals
    * need recomputing.
    */
-  gint valid : 8;
+  guint valid : 8;             /* Actually a boolean */
 };
 
 
@@ -425,9 +426,9 @@ _gtk_text_btree_new (GtkTextTagTable *table,
   tree->end_iter_segment_byte_index = 0;
   tree->end_iter_segment_char_offset = 0;
   
-  g_object_ref (G_OBJECT (tree->table));
+  g_object_ref (tree->table);
 
-  tree->tag_changed_handler = g_signal_connect (G_OBJECT (tree->table),
+  tree->tag_changed_handler = g_signal_connect (tree->table,
                                                "tag_changed",
                                                G_CALLBACK (tag_changed_cb),
                                                tree);
@@ -471,8 +472,8 @@ _gtk_text_btree_new (GtkTextTagTable *table,
 
     seg->body.mark.not_deleteable = TRUE;
 
-    g_object_ref (G_OBJECT (tree->insert_mark));
-    g_object_ref (G_OBJECT (tree->selection_bound_mark));
+    g_object_ref (tree->insert_mark);
+    g_object_ref (tree->selection_bound_mark);
   }
 
   tree->refcount = 1;
@@ -499,10 +500,10 @@ _gtk_text_btree_unref (GtkTextBTree *tree)
 
   if (tree->refcount == 0)
     {      
-      g_signal_handler_disconnect (G_OBJECT (tree->table),
+      g_signal_handler_disconnect (tree->table,
                                    tree->tag_changed_handler);
 
-      g_object_unref (G_OBJECT (tree->table));
+      g_object_unref (tree->table);
       tree->table = NULL;
       
       gtk_text_btree_node_destroy (tree, tree->root_node);
@@ -517,9 +518,9 @@ _gtk_text_btree_unref (GtkTextBTree *tree)
          tree->child_anchor_table = NULL;
        }
 
-      g_object_unref (G_OBJECT (tree->insert_mark));
+      g_object_unref (tree->insert_mark);
       tree->insert_mark = NULL;
-      g_object_unref (G_OBJECT (tree->selection_bound_mark));
+      g_object_unref (tree->selection_bound_mark);
       tree->selection_bound_mark = NULL;
 
       g_free (tree);
@@ -555,6 +556,174 @@ _gtk_text_btree_segments_changed (GtkTextBTree *tree)
  * Indexable segment mutation
  */
 
+/*
+ *  The following function is responsible for resolving the bidi direction
+ *  for the lines between start and end. But it also calculates any
+ *  dependent bidi direction for surrounding lines that change as a result
+ *  of the bidi direction decisions within the range. The function is
+ *  trying to do as little propagation as is needed.
+ */
+static void
+gtk_text_btree_resolve_bidi (GtkTextIter *start,
+                            GtkTextIter *end)
+{
+  GtkTextBTree *tree = _gtk_text_iter_get_btree (start);
+  GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line;
+  PangoDirection last_strong, dir_above_propagated, dir_below_propagated;
+
+  /* Resolve the strong bidi direction for all lines between
+   * start and end.
+  */
+  start_line = _gtk_text_iter_get_text_line (start);
+  start_line_prev = _gtk_text_line_previous (start_line);
+  end_line = _gtk_text_iter_get_text_line (end);
+  end_line_next = _gtk_text_line_next (end_line);
+  
+  line = start_line;
+  while (line && line != end_line_next)
+    {
+      /* Loop through the segments and search for a strong character
+       */
+      GtkTextLineSegment *seg = line->segments;
+      line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+      
+      while (seg)
+        {
+          if (seg->byte_count > 0)
+            {
+             PangoDirection pango_dir;
+
+              pango_dir = pango_find_base_dir (seg->body.chars,
+                                              seg->byte_count);
+             
+              if (pango_dir != PANGO_DIRECTION_NEUTRAL)
+                {
+                  line->dir_strong = pango_dir;
+                  break;
+                }
+            }
+          seg = seg->next;
+        }
+
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Sweep forward */
+
+  /* The variable dir_above_propagated contains the forward propagated
+   * direction before start. It is neutral if start is in the beginning
+   * of the buffer.
+   */
+  dir_above_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (start_line_prev)
+    dir_above_propagated = start_line_prev->dir_propagated_forward;
+
+  /* Loop forward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = start_line;
+  last_strong = dir_above_propagated;
+  while (line != end_line_next)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+      
+      line->dir_propagated_forward = last_strong;
+      
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Continue propagating as long as the previous resolved forward
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter end_propagate;
+    
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_forward != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_forward = last_strong;
+        
+        line = _gtk_text_line_next(line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* The last line to invalidate is the last line before the
+     * line with the strong character. Or in case of the end of the
+     * buffer, the last line of the buffer. (There seems to be an
+     * extra "virtual" last line in the buffer that must not be used
+     * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the
+     * _gtk_text_line_previous is ok in that case as well.)
+     */
+    line = _gtk_text_line_previous (line);
+    _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
+    _gtk_text_btree_invalidate_region (tree, end, &end_propagate);
+  }
+  
+  /* Sweep backward */
+
+  /* The variable dir_below_propagated contains the backward propagated
+   * direction after end. It is neutral if end is at the end of
+   * the buffer.
+  */
+  dir_below_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (end_line_next)
+    dir_below_propagated = end_line_next->dir_propagated_back;
+
+  /* Loop backward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = end_line;
+  last_strong = dir_below_propagated;
+  while (line != start_line_prev)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+
+      line->dir_propagated_back = last_strong;
+
+      line = _gtk_text_line_previous (line);
+    }
+
+  /* Continue propagating as long as the resolved backward dir
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter start_propagate;
+
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_back != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_back = last_strong;
+
+        line = _gtk_text_line_previous (line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* We only need to invalidate for backwards propagation if the
+     * line we ended up on didn't get a direction from forwards
+     * propagation.
+     */
+    if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
+      {
+        _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
+        _gtk_text_btree_invalidate_region(tree, &start_propagate, start);
+      }
+  }
+}
+
 void
 _gtk_text_btree_delete (GtkTextIter *start,
                         GtkTextIter *end)
@@ -885,6 +1054,8 @@ _gtk_text_btree_delete (GtkTextIter *start,
   /* Re-initialize our iterators */
   _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
   *end = *start;
+
+  gtk_text_btree_resolve_bidi (start, end);
 }
 
 void
@@ -1051,6 +1222,8 @@ _gtk_text_btree_insert (GtkTextIter *iter,
 
     /* Convenience for the user */
     *iter = end;
+
+    gtk_text_btree_resolve_bidi (&start, &end);
   }
 }
 
@@ -2212,7 +2385,7 @@ _gtk_text_btree_get_text (const GtkTextIter *start_orig,
 
   gtk_text_iter_order (&start, &end);
 
-  retval = g_string_new ("");
+  retval = g_string_new (NULL);
 
   tree = _gtk_text_iter_get_btree (&start);
 
@@ -2656,6 +2829,14 @@ _gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
 void
 _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
                              const GtkTextIter *iter)
+{
+  _gtk_text_btree_select_range (tree, iter, iter);
+}
+
+void
+_gtk_text_btree_select_range (GtkTextBTree      *tree,
+                             const GtkTextIter *ins,
+                              const GtkTextIter *bound)
 {
   GtkTextIter start, end;
 
@@ -2664,11 +2845,14 @@ _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
 
   /* Move insert AND selection_bound before we redisplay */
   real_set_mark (tree, tree->insert_mark,
-                 "insert", FALSE, iter, TRUE, FALSE);
+                 "insert", FALSE, ins, TRUE, FALSE);
   real_set_mark (tree, tree->selection_bound_mark,
-                 "selection_bound", FALSE, iter, TRUE, FALSE);
+                 "selection_bound", FALSE, bound, TRUE, FALSE);
+
+  redisplay_region (tree, ins, bound);
 }
 
+
 void
 _gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
                                     const gchar *name)
@@ -2698,7 +2882,7 @@ _gtk_text_btree_release_mark_segment (GtkTextBTree       *tree,
   /* Remove the ref on the mark, which frees segment as a side effect
    * if this is the last reference.
    */
-  g_object_unref (G_OBJECT (segment->body.mark.obj));
+  g_object_unref (segment->body.mark.obj);
 }
 
 void
@@ -4306,9 +4490,7 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
       line_ancestor = line->parent;
       line_ancestor_parent = line->parent->parent;
 
-      node = line_ancestor_parent->children.node;
-      while (node != line_ancestor &&
-             line_ancestor != info->tag_root)
+      while (line_ancestor != info->tag_root)
         {
           GSList *child_nodes = NULL;
           GSList *tmp;
@@ -4316,8 +4498,12 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
           /* Create reverse-order list of nodes before
            * line_ancestor
            */
-          while (node != line_ancestor
-                 && node != NULL)
+          if (line_ancestor_parent != NULL)
+           node = line_ancestor_parent->children.node;
+         else
+           node = line_ancestor;
+
+          while (node != line_ancestor && node != NULL)
             {
               child_nodes = g_slist_prepend (child_nodes, node);
 
@@ -4347,8 +4533,6 @@ _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
           /* Didn't find anything on this level; go up one level. */
           line_ancestor = line_ancestor_parent;
           line_ancestor_parent = line_ancestor->parent;
-
-          node = line_ancestor_parent->children.node;
         }
 
       /* No dice. */
@@ -4487,6 +4671,9 @@ gtk_text_line_new (void)
   GtkTextLine *line;
 
   line = g_new0(GtkTextLine, 1);
+  line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_forward = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_back = PANGO_DIRECTION_NEUTRAL;
 
   return line;
 }
@@ -5778,7 +5965,7 @@ gtk_text_btree_get_tag_info (GtkTextBTree *tree,
       info = g_new (GtkTextTagInfo, 1);
 
       info->tag = tag;
-      g_object_ref (G_OBJECT (tag));
+      g_object_ref (tag);
       info->tag_root = NULL;
       info->toggle_count = 0;
 
@@ -5826,7 +6013,7 @@ gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
           list->next = NULL;
           g_slist_free (list);
 
-          g_object_unref (G_OBJECT (info->tag));
+          g_object_unref (info->tag);
 
           g_free (info);
           return;
@@ -6687,15 +6874,15 @@ _gtk_text_btree_check (GtkTextBTree *tree)
   GtkTextLine *line;
   GtkTextLineSegment *seg;
   GtkTextTag *tag;
-  GSList *taglist = NULL;
+  GSList *all_tags, *taglist = NULL;
   int count;
   GtkTextTagInfo *info;
 
   /*
    * Make sure that the tag toggle counts and the tag root pointers are OK.
    */
-  for (taglist = list_of_tags (tree->table);
-       taglist != NULL ; taglist = taglist->next)
+  all_tags = list_of_tags (tree->table);
+  for (taglist = all_tags; taglist != NULL ; taglist = taglist->next)
     {
       tag = taglist->data;
       info = gtk_text_btree_get_existing_tag_info (tree, tag);
@@ -6779,8 +6966,7 @@ _gtk_text_btree_check (GtkTextBTree *tree)
         }
     }
 
-  g_slist_free (taglist);
-  taglist = NULL;
+  g_slist_free (all_tags);
 
   /*
    * Call a recursive procedure to do the main body of checks.
@@ -7057,4 +7243,5 @@ _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
     }
 }
 
-
+#define __GTK_TEXT_BTREE_C__
+#include "gtkaliasdef.c"