]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbtree.c
remove some debug code that seems to have caused a breakpoint in valid
[~andy/gtk] / gtk / gtktextbtree.c
1 /*
2  * gtktextbtree.c --
3  *
4  *      This file contains code that manages the B-tree representation
5  *      of text for the text buffer and implements character and
6  *      toggle segment types.
7  *
8  * Copyright (c) 1992-1994 The Regents of the University of California.
9  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10  * Copyright (c) 2000      Red Hat, Inc.
11  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
12  *
13  * This software is copyrighted by the Regents of the University of
14  * California, Sun Microsystems, Inc., and other parties.  The
15  * following terms apply to all files associated with the software
16  * unless explicitly disclaimed in individual files.
17  *
18  * The authors hereby grant permission to use, copy, modify,
19  * distribute, and license this software and its documentation for any
20  * purpose, provided that existing copyright notices are retained in
21  * all copies and that this notice is included verbatim in any
22  * distributions. No written agreement, license, or royalty fee is
23  * required for any of the authorized uses.  Modifications to this
24  * software may be copyrighted by their authors and need not follow
25  * the licensing terms described here, provided that the new terms are
26  * clearly indicated on the first page of each file where they apply.
27  *
28  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
29  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
30  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
31  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
32  * OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
37  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
38  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
39  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
40  *
41  * GOVERNMENT USE: If you are acquiring this software on behalf of the
42  * U.S. government, the Government shall have only "Restricted Rights"
43  * in the software and related documentation as defined in the Federal
44  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
45  * are acquiring the software on behalf of the Department of Defense,
46  * the software shall be classified as "Commercial Computer Software"
47  * and the Government shall have only "Restricted Rights" as defined
48  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
49  * foregoing, the authors grant the U.S. Government and others acting
50  * in its behalf permission to use and distribute the software in
51  * accordance with the terms specified in this license.
52  *
53  */
54
55 #include "gtktextbtree.h"
56 #include <string.h>
57 #include <ctype.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include "gtksignal.h"
61 #include "gtktexttag.h"
62 #include "gtktexttagtable.h"
63 #include "gtktextlayout.h"
64 #include "gtktextiterprivate.h"
65 #include "gtkdebug.h"
66 #include "gtktextmarkprivate.h"
67
68 /*
69  * Types
70  */
71
72
73 /*
74  * The structure below is used to pass information between
75  * _gtk_text_btree_get_tags and inc_count:
76  */
77
78 typedef struct TagInfo {
79   int numTags;                  /* Number of tags for which there
80                                  * is currently information in
81                                  * tags and counts. */
82   int arraySize;                        /* Number of entries allocated for
83                                          * tags and counts. */
84   GtkTextTag **tags;           /* Array of tags seen so far.
85                                 * Malloc-ed. */
86   int *counts;                  /* Toggle count (so far) for each
87                                  * entry in tags.  Malloc-ed. */
88 } TagInfo;
89
90
91 /*
92  * This is used to store per-view width/height info at the tree nodes.
93  */
94
95 typedef struct _NodeData NodeData;
96
97 struct _NodeData {
98   gpointer view_id;
99   NodeData *next;
100
101   /* Height and width of this node */
102   gint height;
103   gint width : 24;
104
105   /* boolean indicating whether the lines below this node are in need of validation.
106    * However, width/height should always represent the current total width and
107    * max height for lines below this node; the valid flag indicates whether the
108    * width/height on the lines needs recomputing, not whether the totals
109    * need recomputing.
110    */
111   gint valid : 8;
112 };
113
114
115 /*
116  * The data structure below keeps summary information about one tag as part
117  * of the tag information in a node.
118  */
119
120 typedef struct Summary {
121   GtkTextTagInfo *info;                     /* Handle for tag. */
122   int toggle_count;                     /* Number of transitions into or
123                                          * out of this tag that occur in
124                                          * the subtree rooted at this node. */
125   struct Summary *next;         /* Next in list of all tags for same
126                                  * node, or NULL if at end of list. */
127 } Summary;
128
129 /*
130  * The data structure below defines a node in the B-tree.
131  */
132
133 struct _GtkTextBTreeNode {
134   GtkTextBTreeNode *parent;         /* Pointer to parent node, or NULL if
135                                      * this is the root. */
136   GtkTextBTreeNode *next;           /* Next in list of siblings with the
137                                      * same parent node, or NULL for end
138                                      * of list. */
139   Summary *summary;             /* First in malloc-ed list of info
140                                  * about tags in this subtree (NULL if
141                                  * no tag info in the subtree). */
142   int level;                            /* Level of this node in the B-tree.
143                                          * 0 refers to the bottom of the tree
144                                          * (children are lines, not nodes). */
145   union {                               /* First in linked list of children. */
146     struct _GtkTextBTreeNode *node;         /* Used if level > 0. */
147     GtkTextLine *line;         /* Used if level == 0. */
148   } children;
149   int num_children;                     /* Number of children of this node. */
150   int num_lines;                        /* Total number of lines (leaves) in
151                                          * the subtree rooted here. */
152   int num_chars;                        /* Number of chars below here */
153
154   NodeData *node_data;
155 };
156
157
158 /*
159  * Used to store the list of views in our btree
160  */
161
162 typedef struct _BTreeView BTreeView;
163
164 struct _BTreeView {
165   gpointer view_id;
166   GtkTextLayout *layout;
167   BTreeView *next;
168   BTreeView *prev;
169 };
170
171 /*
172  * And the tree itself
173  */
174
175 struct _GtkTextBTree {
176   GtkTextBTreeNode *root_node;          /* Pointer to root of B-tree. */
177   GtkTextTagTable *table;
178   GHashTable *mark_table;
179   guint refcount;
180   GtkTextMark *insert_mark;
181   GtkTextMark *selection_bound_mark;
182   GtkTextBuffer *buffer;
183   BTreeView *views;
184   GSList *tag_infos;
185   guint tag_changed_handler;
186   guint tag_removed_handler;
187   /* Incremented when a segment with a byte size > 0
188      is added to or removed from the tree (i.e. the
189      length of a line may have changed, and lines may
190      have been added or removed). This invalidates
191      all outstanding iterators.
192   */
193   guint chars_changed_stamp;
194   /* Incremented when any segments are added or deleted;
195      this makes outstanding iterators recalculate their
196      pointed-to segment and segment offset.
197   */
198   guint segments_changed_stamp;
199
200   GtkTextLine *end_iter_line;
201
202   guint end_iter_line_stamp;
203
204   GHashTable *child_anchor_table;
205 };
206
207
208 /*
209  * Upper and lower bounds on how many children a node may have:
210  * rebalance when either of these limits is exceeded.  MAX_CHILDREN
211  * should be twice MIN_CHILDREN and MIN_CHILDREN must be >= 2.
212  */
213
214 /* Tk used MAX of 12 and MIN of 6. This makes the tree wide and
215    shallow. It appears to be faster to locate a particular line number
216    if the tree is narrow and deep, since it is more finely sorted.  I
217    guess this may increase memory use though, and make it slower to
218    walk the tree in order, or locate a particular byte index (which
219    is done by walking the tree in order).
220
221    There's basically a tradeoff here. However I'm thinking we want to
222    add pixels, byte counts, and char counts to the tree nodes,
223    at that point narrow and deep should speed up all operations,
224    not just the line number searches.
225 */
226
227 #if 1
228 #define MAX_CHILDREN 12
229 #define MIN_CHILDREN 6
230 #else
231 #define MAX_CHILDREN 6
232 #define MIN_CHILDREN 3
233 #endif
234
235 /*
236  * Prototypes
237  */
238
239 static BTreeView        *gtk_text_btree_get_view                 (GtkTextBTree     *tree,
240                                                                   gpointer          view_id);
241 static void              gtk_text_btree_rebalance                (GtkTextBTree     *tree,
242                                                                   GtkTextBTreeNode *node);
243 static GtkTextLine     * get_last_line                           (GtkTextBTree     *tree);
244 static void              post_insert_fixup                       (GtkTextBTree     *tree,
245                                                                   GtkTextLine      *insert_line,
246                                                                   gint              char_count_delta,
247                                                                   gint              line_count_delta);
248 static void              gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode *node,
249                                                                   GtkTextTagInfo   *info,
250                                                                   gint              adjust);
251 static gboolean          gtk_text_btree_node_has_tag             (GtkTextBTreeNode *node,
252                                                                   GtkTextTag       *tag);
253
254 static void             segments_changed                (GtkTextBTree     *tree);
255 static void             chars_changed                   (GtkTextBTree     *tree);
256 static void             summary_list_destroy            (Summary          *summary);
257 static GtkTextLine     *gtk_text_line_new               (void);
258 static void             gtk_text_line_destroy           (GtkTextBTree     *tree,
259                                                          GtkTextLine      *line);
260 static void             gtk_text_line_set_parent        (GtkTextLine      *line,
261                                                          GtkTextBTreeNode *node);
262 static void             gtk_text_btree_node_remove_data (GtkTextBTreeNode *node,
263                                                          gpointer          view_id);
264
265
266 static NodeData         *node_data_new          (gpointer  view_id);
267 static void              node_data_destroy      (NodeData *nd);
268 static void              node_data_list_destroy (NodeData *nd);
269 static NodeData         *node_data_find         (NodeData *nd,
270                                                  gpointer  view_id);
271
272 static GtkTextBTreeNode     *gtk_text_btree_node_new                  (void);
273 static void                  gtk_text_btree_node_invalidate_downward  (GtkTextBTreeNode *node);
274 static void                  gtk_text_btree_node_invalidate_upward    (GtkTextBTreeNode *node,
275                                                                        gpointer          view_id);
276 static NodeData *            gtk_text_btree_node_check_valid          (GtkTextBTreeNode *node,
277                                                                        gpointer          view_id);
278 static NodeData *            gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
279                                                                        gpointer          view_id);
280 static void                  gtk_text_btree_node_check_valid_upward   (GtkTextBTreeNode *node,
281                                                                        gpointer          view_id);
282
283 static void                  gtk_text_btree_node_remove_view         (BTreeView        *view,
284                                                                       GtkTextBTreeNode *node,
285                                                                       gpointer          view_id);
286 static void                  gtk_text_btree_node_destroy             (GtkTextBTree     *tree,
287                                                                       GtkTextBTreeNode *node);
288 static void                  gtk_text_btree_node_free_empty          (GtkTextBTree *tree,
289                                                                       GtkTextBTreeNode *node);
290 static NodeData         *    gtk_text_btree_node_ensure_data         (GtkTextBTreeNode *node,
291                                                                       gpointer          view_id);
292 static void                  gtk_text_btree_node_remove_data         (GtkTextBTreeNode *node,
293                                                                       gpointer          view_id);
294 static void                  gtk_text_btree_node_get_size            (GtkTextBTreeNode *node,
295                                                                       gpointer          view_id,
296                                                                       gint             *width,
297                                                                       gint             *height);
298 static GtkTextBTreeNode *    gtk_text_btree_node_common_parent       (GtkTextBTreeNode *node1,
299                                                                       GtkTextBTreeNode *node2);
300 static void get_tree_bounds       (GtkTextBTree     *tree,
301                                    GtkTextIter      *start,
302                                    GtkTextIter      *end);
303 static void tag_changed_cb        (GtkTextTagTable  *table,
304                                    GtkTextTag       *tag,
305                                    gboolean          size_changed,
306                                    GtkTextBTree     *tree);
307 static void tag_removed_cb        (GtkTextTagTable  *table,
308                                    GtkTextTag       *tag,
309                                    GtkTextBTree     *tree);
310 static void cleanup_line          (GtkTextLine      *line);
311 static void recompute_node_counts (GtkTextBTree     *tree,
312                                    GtkTextBTreeNode *node);
313 static void inc_count             (GtkTextTag       *tag,
314                                    int               inc,
315                                    TagInfo          *tagInfoPtr);
316
317 static void summary_destroy       (Summary          *summary);
318
319 static void gtk_text_btree_link_segment   (GtkTextLineSegment *seg,
320                                            const GtkTextIter  *iter);
321 static void gtk_text_btree_unlink_segment (GtkTextBTree       *tree,
322                                            GtkTextLineSegment *seg,
323                                            GtkTextLine        *line);
324
325
326 static GtkTextTagInfo *gtk_text_btree_get_tag_info          (GtkTextBTree   *tree,
327                                                              GtkTextTag     *tag);
328 static GtkTextTagInfo *gtk_text_btree_get_existing_tag_info (GtkTextBTree   *tree,
329                                                              GtkTextTag     *tag);
330 static void            gtk_text_btree_remove_tag_info       (GtkTextBTree   *tree,
331                                                              GtkTextTag     *tag);
332
333 static void redisplay_region (GtkTextBTree      *tree,
334                               const GtkTextIter *start,
335                               const GtkTextIter *end);
336
337 /* Inline thingies */
338
339 static inline void
340 segments_changed (GtkTextBTree *tree)
341 {
342   tree->segments_changed_stamp += 1;
343 }
344
345 static inline void
346 chars_changed (GtkTextBTree *tree)
347 {
348   tree->chars_changed_stamp += 1;
349 }
350
351 /*
352  * BTree operations
353  */
354
355 GtkTextBTree*
356 _gtk_text_btree_new (GtkTextTagTable *table,
357                     GtkTextBuffer *buffer)
358 {
359   GtkTextBTree *tree;
360   GtkTextBTreeNode *root_node;
361   GtkTextLine *line, *line2;
362
363   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
364   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
365
366   /*
367    * The tree will initially have two empty lines.  The second line
368    * isn't actually part of the tree's contents, but its presence
369    * makes several operations easier.  The tree will have one GtkTextBTreeNode,
370    * which is also the root of the tree.
371    */
372
373   /* Create the root node. */
374
375   root_node = gtk_text_btree_node_new ();
376
377   line = gtk_text_line_new ();
378   line2 = gtk_text_line_new ();
379
380   root_node->parent = NULL;
381   root_node->next = NULL;
382   root_node->summary = NULL;
383   root_node->level = 0;
384   root_node->children.line = line;
385   root_node->num_children = 2;
386   root_node->num_lines = 2;
387   root_node->num_chars = 2;
388
389   line->parent = root_node;
390   line->next = line2;
391
392   line->segments = _gtk_char_segment_new ("\n", 1);
393
394   line2->parent = root_node;
395   line2->next = NULL;
396   line2->segments = _gtk_char_segment_new ("\n", 1);
397
398   /* Create the tree itself */
399
400   tree = g_new0(GtkTextBTree, 1);
401   tree->root_node = root_node;
402   tree->table = table;
403   tree->views = NULL;
404
405   /* Set these to values that are unlikely to be found
406    * in random memory garbage, and also avoid
407    * duplicates between tree instances.
408    */
409   tree->chars_changed_stamp = g_random_int ();
410   tree->segments_changed_stamp = g_random_int ();
411
412   tree->end_iter_line_stamp = tree->chars_changed_stamp - 1;
413   tree->end_iter_line = NULL;
414
415   g_object_ref (G_OBJECT (tree->table));
416
417   tree->tag_changed_handler = g_signal_connect (G_OBJECT (tree->table),
418                                                 "tag_changed",
419                                                 G_CALLBACK (tag_changed_cb),
420                                                 tree);
421
422   tree->tag_removed_handler = g_signal_connect (G_OBJECT (tree->table),
423                                                 "tag_removed",
424                                                 G_CALLBACK (tag_removed_cb),
425                                                 tree);
426
427   tree->mark_table = g_hash_table_new (g_str_hash, g_str_equal);
428   tree->child_anchor_table = NULL;
429   
430   /* We don't ref the buffer, since the buffer owns us;
431    * we'd have some circularity issues. The buffer always
432    * lasts longer than the BTree
433    */
434   tree->buffer = buffer;
435
436   {
437     GtkTextIter start;
438     GtkTextLineSegment *seg;
439
440     _gtk_text_btree_get_iter_at_line_char (tree, &start, 0, 0);
441
442
443     tree->insert_mark = _gtk_text_btree_set_mark (tree,
444                                                  NULL,
445                                                  "insert",
446                                                  FALSE,
447                                                  &start,
448                                                  FALSE);
449
450     seg = tree->insert_mark->segment;
451
452     seg->body.mark.not_deleteable = TRUE;
453     seg->body.mark.visible = TRUE;
454
455     tree->selection_bound_mark = _gtk_text_btree_set_mark (tree,
456                                                           NULL,
457                                                           "selection_bound",
458                                                           FALSE,
459                                                           &start,
460                                                           FALSE);
461
462     seg = tree->selection_bound_mark->segment;
463
464     seg->body.mark.not_deleteable = TRUE;
465
466     g_object_ref (G_OBJECT (tree->insert_mark));
467     g_object_ref (G_OBJECT (tree->selection_bound_mark));
468   }
469
470   tree->refcount = 1;
471
472   return tree;
473 }
474
475 void
476 _gtk_text_btree_ref (GtkTextBTree *tree)
477 {
478   g_return_if_fail (tree != NULL);
479   g_return_if_fail (tree->refcount > 0);
480
481   tree->refcount += 1;
482 }
483
484 static void
485 mark_destroy_foreach (gpointer key, gpointer value, gpointer user_data)
486 {
487   GtkTextLineSegment *seg = value;
488
489   g_return_if_fail (seg->body.mark.tree == NULL);
490
491   g_object_unref (G_OBJECT (seg->body.mark.obj));
492 }
493
494 void
495 _gtk_text_btree_unref (GtkTextBTree *tree)
496 {
497   g_return_if_fail (tree != NULL);
498   g_return_if_fail (tree->refcount > 0);
499
500   tree->refcount -= 1;
501
502   if (tree->refcount == 0)
503     {
504       gtk_text_btree_node_destroy (tree, tree->root_node);
505
506       g_hash_table_foreach (tree->mark_table,
507                             mark_destroy_foreach,
508                             NULL);
509       g_hash_table_destroy (tree->mark_table);
510
511       g_object_unref (G_OBJECT (tree->insert_mark));
512       g_object_unref (G_OBJECT (tree->selection_bound_mark));
513
514       g_signal_handler_disconnect (G_OBJECT (tree->table),
515                                    tree->tag_changed_handler);
516
517       g_signal_handler_disconnect (G_OBJECT (tree->table),
518                                    tree->tag_removed_handler);
519
520       g_object_unref (G_OBJECT (tree->table));
521
522       g_free (tree);
523     }
524 }
525
526 GtkTextBuffer*
527 _gtk_text_btree_get_buffer (GtkTextBTree *tree)
528 {
529   return tree->buffer;
530 }
531
532 guint
533 _gtk_text_btree_get_chars_changed_stamp (GtkTextBTree *tree)
534 {
535   return tree->chars_changed_stamp;
536 }
537
538 guint
539 _gtk_text_btree_get_segments_changed_stamp (GtkTextBTree *tree)
540 {
541   return tree->segments_changed_stamp;
542 }
543
544 void
545 _gtk_text_btree_segments_changed (GtkTextBTree *tree)
546 {
547   g_return_if_fail (tree != NULL);
548   segments_changed (tree);
549 }
550
551 /*
552  * Indexable segment mutation
553  */
554
555 void
556 _gtk_text_btree_delete (GtkTextIter *start,
557                        GtkTextIter *end)
558 {
559   GtkTextLineSegment *prev_seg;             /* The segment just before the start
560                                              * of the deletion range. */
561   GtkTextLineSegment *last_seg;             /* The segment just after the end
562                                              * of the deletion range. */
563   GtkTextLineSegment *seg, *next;
564   GtkTextLine *curline;
565   GtkTextBTreeNode *curnode, *node;
566   GtkTextBTree *tree;
567   GtkTextLine *start_line;
568   GtkTextLine *end_line;
569   GtkTextLine *deleted_lines = NULL;        /* List of lines we've deleted */
570   gint start_byte_offset;
571
572   g_return_if_fail (start != NULL);
573   g_return_if_fail (end != NULL);
574   g_return_if_fail (_gtk_text_iter_get_btree (start) ==
575                     _gtk_text_iter_get_btree (end));
576
577   gtk_text_iter_order (start, end);
578
579   tree = _gtk_text_iter_get_btree (start);
580  
581   if (gtk_debug_flags & GTK_DEBUG_TEXT)
582     _gtk_text_btree_check (tree);
583   
584   {
585     /*
586      * The code below is ugly, but it's needed to make sure there
587      * is always a dummy empty line at the end of the text.  If the
588      * final newline of the file (just before the dummy line) is being
589      * deleted, then back up index to just before the newline.  If
590      * there is a newline just before the first character being deleted,
591      * then back up the first index too, so that an even number of lines
592      * gets deleted.  Furthermore, remove any tags that are present on
593      * the newline that isn't going to be deleted after all (this simulates
594      * deleting the newline and then adding a "clean" one back again).
595      */
596
597     gint line1;
598     gint line2;
599
600     line1 = gtk_text_iter_get_line (start);
601     line2 = gtk_text_iter_get_line (end);
602
603     if (line2 == _gtk_text_btree_line_count (tree))
604       {
605         GtkTextTag** tags;
606         int array_size;
607         GtkTextIter orig_end;
608
609         orig_end = *end;
610         gtk_text_iter_backward_char (end);
611
612         --line2;
613
614         if (gtk_text_iter_get_line_offset (start) == 0 &&
615             line1 != 0)
616           {
617             gtk_text_iter_backward_char (start);
618             --line1;
619           }
620
621         tags = _gtk_text_btree_get_tags (end,
622                                          &array_size);
623
624         if (tags != NULL)
625           {
626             int i;
627
628             i = 0;
629             while (i < array_size)
630               {
631                 _gtk_text_btree_tag (end, &orig_end, tags[i], FALSE);
632
633                 ++i;
634               }
635
636             g_free (tags);
637           }
638       }
639   }
640
641   /* Broadcast the need for redisplay before we break the iterators */
642   _gtk_text_btree_invalidate_region (tree, start, end);
643
644   /* Save the byte offset so we can reset the iterators */
645   start_byte_offset = gtk_text_iter_get_line_index (start);
646
647   start_line = _gtk_text_iter_get_text_line (start);
648   end_line = _gtk_text_iter_get_text_line (end);
649
650   /*
651    * Split the start and end segments, so we have a place
652    * to insert our new text.
653    *
654    * Tricky point:  split at end first;  otherwise the split
655    * at end may invalidate seg and/or prev_seg. This allows
656    * us to avoid invalidating segments for start.
657    */
658
659   last_seg = gtk_text_line_segment_split (end);
660   if (last_seg != NULL)
661     last_seg = last_seg->next;
662   else
663     last_seg = end_line->segments;
664
665   prev_seg = gtk_text_line_segment_split (start);
666   if (prev_seg != NULL)
667     {
668       seg = prev_seg->next;
669       prev_seg->next = last_seg;
670     }
671   else
672     {
673       seg = start_line->segments;
674       start_line->segments = last_seg;
675     }
676
677   /* notify iterators that their segments need recomputation,
678      just for robustness. */
679   segments_changed (tree);
680
681   /*
682    * Delete all of the segments between prev_seg and last_seg.
683    */
684
685   curline = start_line;
686   curnode = curline->parent;
687   while (seg != last_seg)
688     {
689       gint char_count = 0;
690
691       if (seg == NULL)
692         {
693           GtkTextLine *nextline;
694
695           /*
696            * We just ran off the end of a line.  First find the
697            * next line, then go back to the old line and delete it
698            * (unless it's the starting line for the range).
699            */
700
701           nextline = _gtk_text_line_next (curline);
702           if (curline != start_line)
703             {
704               if (curnode == start_line->parent)
705                 start_line->next = curline->next;
706               else
707                 curnode->children.line = curline->next;
708
709               for (node = curnode; node != NULL;
710                    node = node->parent)
711                 {
712                   /* Don't update node->num_chars, because
713                    * that was done when we deleted the segments.
714                    */
715                   node->num_lines -= 1;
716                 }
717
718               curnode->num_children -= 1;
719               curline->next = deleted_lines;
720               deleted_lines = curline;
721             }
722
723           curline = nextline;
724           seg = curline->segments;
725
726           /*
727            * If the GtkTextBTreeNode is empty then delete it and its parents,
728            * recursively upwards until a non-empty GtkTextBTreeNode is found.
729            */
730
731           while (curnode->num_children == 0)
732             {
733               GtkTextBTreeNode *parent;
734
735               parent = curnode->parent;
736               if (parent->children.node == curnode)
737                 {
738                   parent->children.node = curnode->next;
739                 }
740               else
741                 {
742                   GtkTextBTreeNode *prevnode = parent->children.node;
743                   while (prevnode->next != curnode)
744                     {
745                       prevnode = prevnode->next;
746                     }
747                   prevnode->next = curnode->next;
748                 }
749               parent->num_children--;
750               gtk_text_btree_node_free_empty (tree, curnode);
751               curnode = parent;
752             }
753           curnode = curline->parent;
754           continue;
755         }
756
757       next = seg->next;
758       char_count = seg->char_count;
759
760       if ((*seg->type->deleteFunc)(seg, curline, 0) != 0)
761         {
762           /*
763            * This segment refuses to die.  Move it to prev_seg and
764            * advance prev_seg if the segment has left gravity.
765            */
766
767           if (prev_seg == NULL)
768             {
769               seg->next = start_line->segments;
770               start_line->segments = seg;
771             }
772           else
773             {
774               seg->next = prev_seg->next;
775               prev_seg->next = seg;
776             }
777           if (seg->type->leftGravity)
778             {
779               prev_seg = seg;
780             }
781         }
782       else
783         {
784           /* Segment is gone. Decrement the char count of the node and
785              all its parents. */
786           for (node = curnode; node != NULL;
787                node = node->parent)
788             {
789               node->num_chars -= char_count;
790             }
791         }
792
793       seg = next;
794     }
795
796   /*
797    * If the beginning and end of the deletion range are in different
798    * lines, join the two lines together and discard the ending line.
799    */
800
801   if (start_line != end_line)
802     {
803       BTreeView *view;
804       GtkTextBTreeNode *ancestor_node;
805       GtkTextLine *prevline;
806       int chars_moved;      
807
808       /* last_seg was appended to start_line up at the top of this function */
809       chars_moved = 0;
810       for (seg = last_seg; seg != NULL;
811            seg = seg->next)
812         {
813           chars_moved += seg->char_count;
814           if (seg->type->lineChangeFunc != NULL)
815             {
816               (*seg->type->lineChangeFunc)(seg, end_line);
817             }
818         }
819
820       for (node = start_line->parent; node != NULL;
821            node = node->parent)
822         {
823           node->num_chars += chars_moved;
824         }
825       
826       curnode = end_line->parent;
827       for (node = curnode; node != NULL;
828            node = node->parent)
829         {
830           node->num_chars -= chars_moved;
831           node->num_lines--;
832         }
833       curnode->num_children--;
834       prevline = curnode->children.line;
835       if (prevline == end_line)
836         {
837           curnode->children.line = end_line->next;
838         }
839       else
840         {
841           while (prevline->next != end_line)
842             {
843               prevline = prevline->next;
844             }
845           prevline->next = end_line->next;
846         }
847       end_line->next = deleted_lines;
848       deleted_lines = end_line;
849
850       /* We now fix up the per-view aggregates. We add all the height and
851        * width for the deleted lines to the start line, so that when revalidation
852        * occurs, the correct change in size is seen.
853        */
854       ancestor_node = gtk_text_btree_node_common_parent (curnode, start_line->parent);
855       view = tree->views;
856       while (view)
857         {
858           GtkTextLine *line;
859           GtkTextLineData *ld;
860
861           gint deleted_width = 0;
862           gint deleted_height = 0;
863
864           line = deleted_lines;
865           while (line)
866             {
867               GtkTextLine *next_line = line->next;
868               ld = _gtk_text_line_get_data (line, view->view_id);
869
870               if (ld)
871                 {
872                   deleted_width = MAX (deleted_width, ld->width);
873                   deleted_height += ld->height;
874                 }
875
876               if (!view->next)
877                 gtk_text_line_destroy (tree, line);
878
879               line = next_line;
880             }
881
882           if (deleted_width > 0 || deleted_height > 0)
883             {
884               ld = _gtk_text_line_get_data (start_line, view->view_id);
885
886               /* FIXME: ld is _NOT_ necessarily non-null here, but there is currently
887                * no way to add ld without also validating the node, which would
888                * be improper at this point.
889                */
890               /* This assertion does actually fail sometimes, must
891                  fix before stable release -hp */
892               g_assert (ld);
893
894               ld->width = MAX (deleted_width, ld->width);
895               ld->height += deleted_height;
896               ld->valid = FALSE;
897             }
898
899           gtk_text_btree_node_check_valid_downward (ancestor_node, view->view_id);
900           if (ancestor_node->parent)
901             gtk_text_btree_node_check_valid_upward (ancestor_node->parent, view->view_id);
902
903           view = view->next;
904         }
905
906       /* avoid dangling pointer */
907       deleted_lines = NULL;
908       
909       gtk_text_btree_rebalance (tree, curnode);
910     }
911
912   /*
913    * Cleanup the segments in the new line.
914    */
915
916   cleanup_line (start_line);
917
918   /*
919    * Lastly, rebalance the first GtkTextBTreeNode of the range.
920    */
921
922   gtk_text_btree_rebalance (tree, start_line->parent);
923
924   /* Notify outstanding iterators that they
925      are now hosed */
926   chars_changed (tree);
927   segments_changed (tree);
928
929   if (gtk_debug_flags & GTK_DEBUG_TEXT)
930     _gtk_text_btree_check (tree);
931
932   /* Re-initialize our iterators */
933   _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
934   *end = *start;
935 }
936
937 void
938 _gtk_text_btree_insert (GtkTextIter *iter,
939                        const gchar *text,
940                        gint len)
941 {
942   GtkTextLineSegment *prev_seg;     /* The segment just before the first
943                                      * new segment (NULL means new segment
944                                      * is at beginning of line). */
945   GtkTextLineSegment *cur_seg;              /* Current segment;  new characters
946                                              * are inserted just after this one.
947                                              * NULL means insert at beginning of
948                                              * line. */
949   GtkTextLine *line;           /* Current line (new segments are
950                                 * added to this line). */
951   GtkTextLineSegment *seg;
952   GtkTextLine *newline;
953   int chunk_len;                        /* # characters in current chunk. */
954   gint sol;                           /* start of line */
955   gint eol;                           /* Pointer to character just after last
956                                        * one in current chunk.
957                                        */
958   gint delim;                          /* index of paragraph delimiter */
959   int line_count_delta;                /* Counts change to total number of
960                                         * lines in file.
961                                         */
962
963   int char_count_delta;                /* change to number of chars */
964   GtkTextBTree *tree;
965   gint start_byte_index;
966   GtkTextLine *start_line;
967
968   g_return_if_fail (text != NULL);
969   g_return_if_fail (iter != NULL);
970
971   if (len < 0)
972     len = strlen (text);
973
974   /* extract iterator info */
975   tree = _gtk_text_iter_get_btree (iter);
976   line = _gtk_text_iter_get_text_line (iter);
977   start_line = line;
978   start_byte_index = gtk_text_iter_get_line_index (iter);
979
980   /* Get our insertion segment split */
981   prev_seg = gtk_text_line_segment_split (iter);
982   cur_seg = prev_seg;
983
984   /* Invalidate all iterators */
985   chars_changed (tree);
986   segments_changed (tree);
987   
988   /*
989    * Chop the text up into lines and create a new segment for
990    * each line, plus a new line for the leftovers from the
991    * previous line.
992    */
993
994   eol = 0;
995   sol = 0;
996   line_count_delta = 0;
997   char_count_delta = 0;
998   while (eol < len)
999     {
1000       sol = eol;
1001       
1002       pango_find_paragraph_boundary (text + sol,
1003                                      len - sol,
1004                                      &delim,
1005                                      &eol);      
1006
1007       /* make these relative to the start of the text */
1008       delim += sol;
1009       eol += sol;
1010
1011       g_assert (eol >= sol);
1012       g_assert (delim >= sol);
1013       g_assert (eol >= delim);
1014       g_assert (sol >= 0);
1015       g_assert (eol <= len);
1016       
1017       chunk_len = eol - sol;
1018
1019       g_assert (g_utf8_validate (&text[sol], chunk_len, NULL));
1020       seg = _gtk_char_segment_new (&text[sol], chunk_len);
1021
1022       char_count_delta += seg->char_count;
1023
1024       if (cur_seg == NULL)
1025         {
1026           seg->next = line->segments;
1027           line->segments = seg;
1028         }
1029       else
1030         {
1031           seg->next = cur_seg->next;
1032           cur_seg->next = seg;
1033         }
1034
1035       if (delim == eol)
1036         {
1037           /* chunk didn't end with a paragraph separator */
1038           g_assert (eol == len);
1039           break;
1040         }
1041
1042       /*
1043        * The chunk ended with a newline, so create a new GtkTextLine
1044        * and move the remainder of the old line to it.
1045        */
1046
1047       newline = gtk_text_line_new ();
1048       gtk_text_line_set_parent (newline, line->parent);
1049       newline->next = line->next;
1050       line->next = newline;
1051       newline->segments = seg->next;
1052       seg->next = NULL;
1053       line = newline;
1054       cur_seg = NULL;
1055       line_count_delta++;
1056     }
1057
1058   /*
1059    * Cleanup the starting line for the insertion, plus the ending
1060    * line if it's different.
1061    */
1062
1063   cleanup_line (start_line);
1064   if (line != start_line)
1065     {
1066       cleanup_line (line);
1067     }
1068
1069   post_insert_fixup (tree, line, line_count_delta, char_count_delta);
1070
1071   /* Invalidate our region, and reset the iterator the user
1072      passed in to point to the end of the inserted text. */
1073   {
1074     GtkTextIter start;
1075     GtkTextIter end;
1076
1077
1078     _gtk_text_btree_get_iter_at_line (tree,
1079                                       &start,
1080                                       start_line,
1081                                       start_byte_index);
1082     end = start;
1083
1084     /* We could almost certainly be more efficient here
1085        by saving the information from the insertion loop
1086        above. FIXME */
1087     gtk_text_iter_forward_chars (&end, char_count_delta);
1088
1089     _gtk_text_btree_invalidate_region (tree,
1090                                       &start, &end);
1091
1092
1093     /* Convenience for the user */
1094     *iter = end;
1095   }
1096 }
1097
1098 static void
1099 insert_pixbuf_or_widget_segment (GtkTextIter        *iter,
1100                                  GtkTextLineSegment *seg)
1101
1102 {
1103   GtkTextIter start;
1104   GtkTextLineSegment *prevPtr;
1105   GtkTextLine *line;
1106   GtkTextBTree *tree;
1107   gint start_byte_offset;
1108
1109   line = _gtk_text_iter_get_text_line (iter);
1110   tree = _gtk_text_iter_get_btree (iter);
1111   start_byte_offset = gtk_text_iter_get_line_index (iter);
1112
1113   prevPtr = gtk_text_line_segment_split (iter);
1114   if (prevPtr == NULL)
1115     {
1116       seg->next = line->segments;
1117       line->segments = seg;
1118     }
1119   else
1120     {
1121       seg->next = prevPtr->next;
1122       prevPtr->next = seg;
1123     }
1124
1125   post_insert_fixup (tree, line, 0, seg->char_count);
1126
1127   chars_changed (tree);
1128   segments_changed (tree);
1129
1130   /* reset *iter for the user, and invalidate tree nodes */
1131
1132   _gtk_text_btree_get_iter_at_line (tree, &start, line, start_byte_offset);
1133
1134   *iter = start;
1135   gtk_text_iter_forward_char (iter); /* skip forward past the segment */
1136
1137   _gtk_text_btree_invalidate_region (tree, &start, iter);
1138 }
1139      
1140 void
1141 _gtk_text_btree_insert_pixbuf (GtkTextIter *iter,
1142                               GdkPixbuf   *pixbuf)
1143 {
1144   GtkTextLineSegment *seg;
1145   
1146   seg = _gtk_pixbuf_segment_new (pixbuf);
1147
1148   insert_pixbuf_or_widget_segment (iter, seg);
1149 }
1150
1151 void
1152 _gtk_text_btree_insert_child_anchor (GtkTextIter        *iter,
1153                                      GtkTextChildAnchor *anchor)
1154 {
1155   GtkTextLineSegment *seg;
1156   GtkTextBTree *tree;
1157
1158   if (anchor->segment != NULL)
1159     {
1160       g_warning (G_STRLOC": Same child anchor can't be inserted twice");
1161       return;
1162     }
1163   
1164   seg = _gtk_widget_segment_new (anchor);
1165
1166   tree = seg->body.child.tree = _gtk_text_iter_get_btree (iter);
1167   
1168   insert_pixbuf_or_widget_segment (iter, seg);
1169
1170   if (tree->child_anchor_table == NULL)
1171     tree->child_anchor_table = g_hash_table_new (NULL, NULL);
1172
1173   g_hash_table_insert (tree->child_anchor_table,
1174                        seg->body.child.obj,
1175                        seg->body.child.obj);
1176 }
1177
1178 void
1179 _gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor)
1180 {
1181   GtkTextLineSegment *seg;
1182
1183   seg = anchor->segment;
1184   
1185   g_hash_table_remove (seg->body.child.tree->child_anchor_table,
1186                        anchor);
1187 }
1188
1189 /*
1190  * View stuff
1191  */
1192
1193 static GtkTextLine*
1194 find_line_by_y (GtkTextBTree *tree, BTreeView *view,
1195                 GtkTextBTreeNode *node, gint y, gint *line_top,
1196                 GtkTextLine *last_line)
1197 {
1198   gint current_y = 0;
1199
1200   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1201     _gtk_text_btree_check (tree);
1202
1203   if (node->level == 0)
1204     {
1205       GtkTextLine *line;
1206
1207       line = node->children.line;
1208
1209       while (line != NULL && line != last_line)
1210         {
1211           GtkTextLineData *ld;
1212
1213           ld = _gtk_text_line_get_data (line, view->view_id);
1214
1215           if (ld)
1216             {
1217               if (y < (current_y + (ld ? ld->height : 0)))
1218                 return line;
1219
1220               current_y += ld->height;
1221               *line_top += ld->height;
1222             }
1223
1224           line = line->next;
1225         }
1226       return NULL;
1227     }
1228   else
1229     {
1230       GtkTextBTreeNode *child;
1231
1232       child = node->children.node;
1233
1234       while (child != NULL)
1235         {
1236           gint width;
1237           gint height;
1238
1239           gtk_text_btree_node_get_size (child, view->view_id,
1240                                         &width, &height);
1241
1242           if (y < (current_y + height))
1243             return find_line_by_y (tree, view, child,
1244                                    y - current_y, line_top,
1245                                    last_line);
1246
1247           current_y += height;
1248           *line_top += height;
1249
1250           child = child->next;
1251         }
1252
1253       return NULL;
1254     }
1255 }
1256
1257 GtkTextLine *
1258 _gtk_text_btree_find_line_by_y (GtkTextBTree *tree,
1259                                 gpointer      view_id,
1260                                 gint          ypixel,
1261                                 gint         *line_top_out)
1262 {
1263   GtkTextLine *line;
1264   BTreeView *view;
1265   GtkTextLine *last_line;
1266   gint line_top = 0;
1267
1268   view = gtk_text_btree_get_view (tree, view_id);
1269   g_return_val_if_fail (view != NULL, NULL);
1270
1271   last_line = get_last_line (tree);
1272
1273   line = find_line_by_y (tree, view, tree->root_node, ypixel, &line_top,
1274                          last_line);
1275
1276   if (line_top_out)
1277     *line_top_out = line_top;
1278
1279   return line;
1280 }
1281
1282 static gint
1283 find_line_top_in_line_list (GtkTextBTree *tree,
1284                             BTreeView *view,
1285                             GtkTextLine *line,
1286                             GtkTextLine *target_line,
1287                             gint y)
1288 {
1289   while (line != NULL)
1290     {
1291       GtkTextLineData *ld;
1292
1293       if (line == target_line)
1294         return y;
1295
1296       ld = _gtk_text_line_get_data (line, view->view_id);
1297       if (ld)
1298         y += ld->height;
1299
1300       line = line->next;
1301     }
1302
1303   g_assert_not_reached (); /* If we get here, our
1304                               target line didn't exist
1305                               under its parent node */
1306   return 0;
1307 }
1308
1309 gint
1310 _gtk_text_btree_find_line_top (GtkTextBTree *tree,
1311                               GtkTextLine *target_line,
1312                               gpointer view_id)
1313 {
1314   gint y = 0;
1315   BTreeView *view;
1316   GSList *nodes;
1317   GSList *iter;
1318   GtkTextBTreeNode *node;
1319
1320   view = gtk_text_btree_get_view (tree, view_id);
1321
1322   g_return_val_if_fail (view != NULL, 0);
1323
1324   nodes = NULL;
1325   node = target_line->parent;
1326   while (node != NULL)
1327     {
1328       nodes = g_slist_prepend (nodes, node);
1329       node = node->parent;
1330     }
1331
1332   iter = nodes;
1333   while (iter != NULL)
1334     {
1335       node = iter->data;
1336
1337       if (node->level == 0)
1338         {
1339           g_slist_free (nodes);
1340           return find_line_top_in_line_list (tree, view,
1341                                              node->children.line,
1342                                              target_line, y);
1343         }
1344       else
1345         {
1346           GtkTextBTreeNode *child;
1347           GtkTextBTreeNode *target_node;
1348
1349           g_assert (iter->next != NULL); /* not at level 0 */
1350           target_node = iter->next->data;
1351
1352           child = node->children.node;
1353
1354           while (child != NULL)
1355             {
1356               gint width;
1357               gint height;
1358
1359               if (child == target_node)
1360                 break;
1361               else
1362                 {
1363                   gtk_text_btree_node_get_size (child, view->view_id,
1364                                                 &width, &height);
1365                   y += height;
1366                 }
1367               child = child->next;
1368             }
1369           g_assert (child != NULL); /* should have broken out before we
1370                                        ran out of nodes */
1371         }
1372
1373       iter = g_slist_next (iter);
1374     }
1375
1376   g_assert_not_reached (); /* we return when we find the target line */
1377   return 0;
1378 }
1379
1380 void
1381 _gtk_text_btree_add_view (GtkTextBTree *tree,
1382                          GtkTextLayout *layout)
1383 {
1384   BTreeView *view;
1385   GtkTextLine *last_line;
1386   GtkTextLineData *line_data;
1387
1388   g_return_if_fail (tree != NULL);
1389   
1390   view = g_new (BTreeView, 1);
1391
1392   view->view_id = layout;
1393   view->layout = layout;
1394
1395   view->next = tree->views;
1396   view->prev = NULL;
1397
1398   if (tree->views)
1399     {
1400       g_assert (tree->views->prev == NULL);
1401       tree->views->prev = view;
1402     }
1403   
1404   tree->views = view;
1405
1406   /* The last line in the buffer has identity values for the per-view
1407    * data so that we can avoid special case checks for it in a large
1408    * number of loops
1409    */
1410   last_line = get_last_line (tree);
1411
1412   line_data = g_new (GtkTextLineData, 1);
1413   line_data->view_id = layout;
1414   line_data->next = NULL;
1415   line_data->width = 0;
1416   line_data->height = 0;
1417   line_data->valid = TRUE;
1418
1419   _gtk_text_line_add_data (last_line, line_data);
1420 }
1421
1422 void
1423 _gtk_text_btree_remove_view (GtkTextBTree *tree,
1424                              gpointer      view_id)
1425 {
1426   BTreeView *view;
1427   GtkTextLine *last_line;
1428   GtkTextLineData *line_data;
1429
1430   g_return_if_fail (tree != NULL);
1431   
1432   view = tree->views;
1433
1434   while (view != NULL)
1435     {
1436       if (view->view_id == view_id)
1437         break;
1438
1439       view = view->next;
1440     }
1441
1442   g_return_if_fail (view != NULL);
1443
1444   if (view->next)
1445     view->next->prev = view->prev;
1446
1447   if (view->prev)
1448     view->prev->next = view->next;
1449
1450   if (view == tree->views)
1451     tree->views = view->next;
1452
1453   /* Remove the line data for the last line which we added ourselves.
1454    * (Do this first, so that we don't try to call the view's line data destructor on it.)
1455    */
1456   last_line = get_last_line (tree);
1457   line_data = _gtk_text_line_remove_data (last_line, view_id);
1458   g_free (line_data);
1459
1460   gtk_text_btree_node_remove_view (view, tree->root_node, view_id);
1461
1462   view->layout = (gpointer) 0xdeadbeef;
1463   view->view_id = (gpointer) 0xdeadbeef;
1464   
1465   g_free (view);
1466 }
1467
1468 void
1469 _gtk_text_btree_invalidate_region (GtkTextBTree *tree,
1470                                   const GtkTextIter *start,
1471                                   const GtkTextIter *end)
1472 {
1473   BTreeView *view;
1474
1475   view = tree->views;
1476
1477   while (view != NULL)
1478     {
1479       gtk_text_layout_invalidate (view->layout, start, end);
1480
1481       view = view->next;
1482     }
1483 }
1484
1485 void
1486 _gtk_text_btree_get_view_size (GtkTextBTree *tree,
1487                               gpointer view_id,
1488                               gint *width,
1489                               gint *height)
1490 {
1491   g_return_if_fail (tree != NULL);
1492   g_return_if_fail (view_id != NULL);
1493
1494   gtk_text_btree_node_get_size (tree->root_node, view_id,
1495                                 width, height);
1496 }
1497
1498 /*
1499  * Tag
1500  */
1501
1502 typedef struct {
1503   GtkTextIter *iters;
1504   guint count;
1505   guint alloced;
1506 } IterStack;
1507
1508 static IterStack*
1509 iter_stack_new (void)
1510 {
1511   IterStack *stack;
1512   stack = g_new (IterStack, 1);
1513   stack->iters = NULL;
1514   stack->count = 0;
1515   stack->alloced = 0;
1516   return stack;
1517 }
1518
1519 static void
1520 iter_stack_push (IterStack *stack, const GtkTextIter *iter)
1521 {
1522   stack->count += 1;
1523   if (stack->count > stack->alloced)
1524     {
1525       stack->alloced = stack->count*2;
1526       stack->iters = g_realloc (stack->iters,
1527                                 stack->alloced*sizeof (GtkTextIter));
1528     }
1529   stack->iters[stack->count-1] = *iter;
1530 }
1531
1532 static gboolean
1533 iter_stack_pop (IterStack *stack, GtkTextIter *iter)
1534 {
1535   if (stack->count == 0)
1536     return FALSE;
1537   else
1538     {
1539       stack->count -= 1;
1540       *iter = stack->iters[stack->count];
1541       return TRUE;
1542     }
1543 }
1544
1545 static void
1546 iter_stack_free (IterStack *stack)
1547 {
1548   g_free (stack->iters);
1549   g_free (stack);
1550 }
1551
1552 static void
1553 iter_stack_invert (IterStack *stack)
1554 {
1555   if (stack->count > 0)
1556     {
1557       guint i = 0;
1558       guint j = stack->count - 1;
1559       while (i < j)
1560         {
1561           GtkTextIter tmp;
1562
1563           tmp = stack->iters[i];
1564           stack->iters[i] = stack->iters[j];
1565           stack->iters[j] = tmp;
1566
1567           ++i;
1568           --j;
1569         }
1570     }
1571 }
1572
1573 static void
1574 queue_tag_redisplay (GtkTextBTree      *tree,
1575                      GtkTextTag        *tag,
1576                      const GtkTextIter *start,
1577                      const GtkTextIter *end)
1578 {
1579   if (_gtk_text_tag_affects_size (tag))
1580     {
1581       _gtk_text_btree_invalidate_region (tree, start, end);
1582     }
1583   else if (_gtk_text_tag_affects_nonsize_appearance (tag))
1584     {
1585       /* We only need to queue a redraw, not a relayout */
1586       redisplay_region (tree, start, end);
1587     }
1588
1589   /* We don't need to do anything if the tag doesn't affect display */
1590 }
1591
1592 void
1593 _gtk_text_btree_tag (const GtkTextIter *start_orig,
1594                      const GtkTextIter *end_orig,
1595                      GtkTextTag        *tag,
1596                      gboolean           add)
1597 {
1598   GtkTextLineSegment *seg, *prev;
1599   GtkTextLine *cleanupline;
1600   gboolean toggled_on;
1601   GtkTextLine *start_line;
1602   GtkTextLine *end_line;
1603   GtkTextIter iter;
1604   GtkTextIter start, end;
1605   GtkTextBTree *tree;
1606   IterStack *stack;
1607   GtkTextTagInfo *info;
1608
1609   g_return_if_fail (start_orig != NULL);
1610   g_return_if_fail (end_orig != NULL);
1611   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1612   g_return_if_fail (_gtk_text_iter_get_btree (start_orig) ==
1613                     _gtk_text_iter_get_btree (end_orig));
1614   g_return_if_fail (tag->table == _gtk_text_iter_get_btree (start_orig)->table);
1615   
1616 #if 0
1617   printf ("%s tag %s from %d to %d\n",
1618           add ? "Adding" : "Removing",
1619           tag->name,
1620           gtk_text_buffer_get_offset (start_orig),
1621           gtk_text_buffer_get_offset (end_orig));
1622 #endif
1623
1624   if (gtk_text_iter_equal (start_orig, end_orig))
1625     return;
1626
1627   start = *start_orig;
1628   end = *end_orig;
1629
1630   gtk_text_iter_order (&start, &end);
1631
1632   tree = _gtk_text_iter_get_btree (&start);
1633
1634   queue_tag_redisplay (tree, tag, &start, &end);
1635
1636   info = gtk_text_btree_get_tag_info (tree, tag);
1637
1638   start_line = _gtk_text_iter_get_text_line (&start);
1639   end_line = _gtk_text_iter_get_text_line (&end);
1640
1641   /* Find all tag toggles in the region; we are going to delete them.
1642      We need to find them in advance, because
1643      forward_find_tag_toggle () won't work once we start playing around
1644      with the tree. */
1645   stack = iter_stack_new ();
1646   iter = start;
1647
1648   /* forward_to_tag_toggle() skips a toggle at the start iterator,
1649    * which is deliberate - we don't want to delete a toggle at the
1650    * start.
1651    */
1652   while (gtk_text_iter_forward_to_tag_toggle (&iter, tag))
1653     {
1654       if (gtk_text_iter_compare (&iter, &end) >= 0)
1655         break;
1656       else
1657         iter_stack_push (stack, &iter);
1658     }
1659
1660   /* We need to traverse the toggles in order. */
1661   iter_stack_invert (stack);
1662
1663   /*
1664    * See whether the tag is present at the start of the range.  If
1665    * the state doesn't already match what we want then add a toggle
1666    * there.
1667    */
1668
1669   toggled_on = gtk_text_iter_has_tag (&start, tag);
1670   if ( (add && !toggled_on) ||
1671        (!add && toggled_on) )
1672     {
1673       /* This could create a second toggle at the start position;
1674          cleanup_line () will remove it if so. */
1675       seg = _gtk_toggle_segment_new (info, add);
1676
1677       prev = gtk_text_line_segment_split (&start);
1678       if (prev == NULL)
1679         {
1680           seg->next = start_line->segments;
1681           start_line->segments = seg;
1682         }
1683       else
1684         {
1685           seg->next = prev->next;
1686           prev->next = seg;
1687         }
1688
1689       /* cleanup_line adds the new toggle to the node counts. */
1690 #if 0
1691       printf ("added toggle at start\n");
1692 #endif
1693       /* we should probably call segments_changed, but in theory
1694          any still-cached segments in the iters we are about to
1695          use are still valid, since they're in front
1696          of this spot. */
1697     }
1698
1699   /*
1700    *
1701    * Scan the range of characters and delete any internal tag
1702    * transitions.  Keep track of what the old state was at the end
1703    * of the range, and add a toggle there if it's needed.
1704    *
1705    */
1706
1707   cleanupline = start_line;
1708   while (iter_stack_pop (stack, &iter))
1709     {
1710       GtkTextLineSegment *indexable_seg;
1711       GtkTextLine *line;
1712
1713       line = _gtk_text_iter_get_text_line (&iter);
1714       seg = _gtk_text_iter_get_any_segment (&iter);
1715       indexable_seg = _gtk_text_iter_get_indexable_segment (&iter);
1716
1717       g_assert (seg != NULL);
1718       g_assert (indexable_seg != NULL);
1719       g_assert (seg != indexable_seg);
1720
1721       prev = line->segments;
1722
1723       /* Find the segment that actually toggles this tag. */
1724       while (seg != indexable_seg)
1725         {
1726           g_assert (seg != NULL);
1727           g_assert (indexable_seg != NULL);
1728           g_assert (seg != indexable_seg);
1729
1730           if ( (seg->type == &gtk_text_toggle_on_type ||
1731                 seg->type == &gtk_text_toggle_off_type) &&
1732                (seg->body.toggle.info == info) )
1733             break;
1734           else
1735             seg = seg->next;
1736         }
1737
1738       g_assert (seg != NULL);
1739       g_assert (indexable_seg != NULL);
1740
1741       g_assert (seg != indexable_seg); /* If this happens, then
1742                                           forward_to_tag_toggle was
1743                                           full of shit. */
1744       g_assert (seg->body.toggle.info->tag == tag);
1745
1746       /* If this happens, when previously tagging we didn't merge
1747          overlapping tags. */
1748       g_assert ( (toggled_on && seg->type == &gtk_text_toggle_off_type) ||
1749                  (!toggled_on && seg->type == &gtk_text_toggle_on_type) );
1750
1751       toggled_on = !toggled_on;
1752
1753 #if 0
1754       printf ("deleting %s toggle\n",
1755               seg->type == &gtk_text_toggle_on_type ? "on" : "off");
1756 #endif
1757       /* Remove toggle segment from the list. */
1758       if (prev == seg)
1759         {
1760           line->segments = seg->next;
1761         }
1762       else
1763         {
1764           while (prev->next != seg)
1765             {
1766               prev = prev->next;
1767             }
1768           prev->next = seg->next;
1769         }
1770
1771       /* Inform iterators we've hosed them. This actually reflects a
1772          bit of inefficiency; if you have the same tag toggled on and
1773          off a lot in a single line, we keep having the rescan from
1774          the front of the line. Of course we have to do that to get
1775          "prev" anyway, but here we are doing it an additional
1776          time. FIXME */
1777       segments_changed (tree);
1778
1779       /* Update node counts */
1780       if (seg->body.toggle.inNodeCounts)
1781         {
1782           _gtk_change_node_toggle_count (line->parent,
1783                                          info, -1);
1784           seg->body.toggle.inNodeCounts = FALSE;
1785         }
1786
1787       g_free (seg);
1788
1789       /* We only clean up lines when we're done with them, saves some
1790          gratuitous line-segment-traversals */
1791
1792       if (cleanupline != line)
1793         {
1794           cleanup_line (cleanupline);
1795           cleanupline = line;
1796         }
1797     }
1798
1799   iter_stack_free (stack);
1800
1801   /* toggled_on now reflects the toggle state _just before_ the
1802      end iterator. The end iterator could already have a toggle
1803      on or a toggle off. */
1804   if ( (add && !toggled_on) ||
1805        (!add && toggled_on) )
1806     {
1807       /* This could create a second toggle at the start position;
1808          cleanup_line () will remove it if so. */
1809
1810       seg = _gtk_toggle_segment_new (info, !add);
1811
1812       prev = gtk_text_line_segment_split (&end);
1813       if (prev == NULL)
1814         {
1815           seg->next = end_line->segments;
1816           end_line->segments = seg;
1817         }
1818       else
1819         {
1820           seg->next = prev->next;
1821           prev->next = seg;
1822         }
1823       /* cleanup_line adds the new toggle to the node counts. */
1824       g_assert (seg->body.toggle.inNodeCounts == FALSE);
1825 #if 0
1826       printf ("added toggle at end\n");
1827 #endif
1828     }
1829
1830   /*
1831    * Cleanup cleanupline and the last line of the range, if
1832    * these are different.
1833    */
1834
1835   cleanup_line (cleanupline);
1836   if (cleanupline != end_line)
1837     {
1838       cleanup_line (end_line);
1839     }
1840
1841   segments_changed (tree);
1842
1843   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1844     _gtk_text_btree_check (tree);
1845 }
1846
1847
1848 /*
1849  * "Getters"
1850  */
1851
1852 GtkTextLine*
1853 _gtk_text_btree_get_line (GtkTextBTree *tree,
1854                          gint  line_number,
1855                          gint *real_line_number)
1856 {
1857   GtkTextBTreeNode *node;
1858   GtkTextLine *line;
1859   int lines_left;
1860   int line_count;
1861
1862   line_count = _gtk_text_btree_line_count (tree);
1863
1864   if (line_number < 0)
1865     {
1866       line_number = line_count;
1867     }
1868   else if (line_number > line_count)
1869     {
1870       line_number = line_count;
1871     }
1872
1873   if (real_line_number)
1874     *real_line_number = line_number;
1875
1876   node = tree->root_node;
1877   lines_left = line_number;
1878
1879   /*
1880    * Work down through levels of the tree until a GtkTextBTreeNode is found at
1881    * level 0.
1882    */
1883
1884   while (node->level != 0)
1885     {
1886       for (node = node->children.node;
1887            node->num_lines <= lines_left;
1888            node = node->next)
1889         {
1890 #if 0
1891           if (node == NULL)
1892             {
1893               g_error ("gtk_text_btree_find_line ran out of GtkTextBTreeNodes");
1894             }
1895 #endif
1896           lines_left -= node->num_lines;
1897         }
1898     }
1899
1900   /*
1901    * Work through the lines attached to the level-0 GtkTextBTreeNode.
1902    */
1903
1904   for (line = node->children.line; lines_left > 0;
1905        line = line->next)
1906     {
1907 #if 0
1908       if (line == NULL)
1909         {
1910           g_error ("gtk_text_btree_find_line ran out of lines");
1911         }
1912 #endif
1913       lines_left -= 1;
1914     }
1915   return line;
1916 }
1917
1918 GtkTextLine*
1919 _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
1920                                  gint                char_index,
1921                                  gint               *line_start_index,
1922                                  gint               *real_char_index)
1923 {
1924   GtkTextBTreeNode *node;
1925   GtkTextLine *line;
1926   GtkTextLineSegment *seg;
1927   int chars_left;
1928   int chars_in_line;
1929   int bytes_in_line;
1930
1931   node = tree->root_node;
1932
1933   /* Clamp to valid indexes (-1 is magic for "highest index") */
1934   if (char_index < 0 || char_index >= node->num_chars)
1935     {
1936       char_index = node->num_chars - 1;
1937     }
1938
1939   *real_char_index = char_index;
1940
1941   /*
1942    * Work down through levels of the tree until a GtkTextBTreeNode is found at
1943    * level 0.
1944    */
1945
1946   chars_left = char_index;
1947   while (node->level != 0)
1948     {
1949       for (node = node->children.node;
1950            chars_left >= node->num_chars;
1951            node = node->next)
1952         {
1953           chars_left -= node->num_chars;
1954
1955           g_assert (chars_left >= 0);
1956         }
1957     }
1958
1959   if (chars_left == 0)
1960     {
1961       /* Start of a line */
1962
1963       *line_start_index = char_index;
1964       return node->children.line;
1965     }
1966
1967   /*
1968    * Work through the lines attached to the level-0 GtkTextBTreeNode.
1969    */
1970
1971   chars_in_line = 0;
1972   bytes_in_line = 0;
1973   seg = NULL;
1974   for (line = node->children.line; line != NULL; line = line->next)
1975     {
1976       seg = line->segments;
1977       while (seg != NULL)
1978         {
1979           if (chars_in_line + seg->char_count > chars_left)
1980             goto found; /* found our line/segment */
1981
1982           chars_in_line += seg->char_count;
1983
1984           seg = seg->next;
1985         }
1986
1987       chars_left -= chars_in_line;
1988
1989       chars_in_line = 0;
1990       seg = NULL;
1991     }
1992
1993  found:
1994
1995   g_assert (line != NULL); /* hosage, ran out of lines */
1996   g_assert (seg != NULL);
1997
1998   *line_start_index = char_index - chars_left;
1999   return line;
2000 }
2001
2002 GtkTextTag**
2003 _gtk_text_btree_get_tags (const GtkTextIter *iter,
2004                          gint *num_tags)
2005 {
2006   GtkTextBTreeNode *node;
2007   GtkTextLine *siblingline;
2008   GtkTextLineSegment *seg;
2009   int src, dst, index;
2010   TagInfo tagInfo;
2011   GtkTextLine *line;
2012   GtkTextBTree *tree;
2013   gint byte_index;
2014
2015 #define NUM_TAG_INFOS 10
2016
2017   line = _gtk_text_iter_get_text_line (iter);
2018   tree = _gtk_text_iter_get_btree (iter);
2019   byte_index = gtk_text_iter_get_line_index (iter);
2020
2021   tagInfo.numTags = 0;
2022   tagInfo.arraySize = NUM_TAG_INFOS;
2023   tagInfo.tags = g_new (GtkTextTag*, NUM_TAG_INFOS);
2024   tagInfo.counts = g_new (int, NUM_TAG_INFOS);
2025
2026   /*
2027    * Record tag toggles within the line of indexPtr but preceding
2028    * indexPtr. Note that if this loop segfaults, your
2029    * byte_index probably points past the sum of all
2030    * seg->byte_count */
2031
2032   for (index = 0, seg = line->segments;
2033        (index + seg->byte_count) <= byte_index;
2034        index += seg->byte_count, seg = seg->next)
2035     {
2036       if ((seg->type == &gtk_text_toggle_on_type)
2037           || (seg->type == &gtk_text_toggle_off_type))
2038         {
2039           inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2040         }
2041     }
2042
2043   /*
2044    * Record toggles for tags in lines that are predecessors of
2045    * line but under the same level-0 GtkTextBTreeNode.
2046    */
2047
2048   for (siblingline = line->parent->children.line;
2049        siblingline != line;
2050        siblingline = siblingline->next)
2051     {
2052       for (seg = siblingline->segments; seg != NULL;
2053            seg = seg->next)
2054         {
2055           if ((seg->type == &gtk_text_toggle_on_type)
2056               || (seg->type == &gtk_text_toggle_off_type))
2057             {
2058               inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2059             }
2060         }
2061     }
2062
2063   /*
2064    * For each GtkTextBTreeNode in the ancestry of this line, record tag
2065    * toggles for all siblings that precede that GtkTextBTreeNode.
2066    */
2067
2068   for (node = line->parent; node->parent != NULL;
2069        node = node->parent)
2070     {
2071       GtkTextBTreeNode *siblingPtr;
2072       Summary *summary;
2073
2074       for (siblingPtr = node->parent->children.node;
2075            siblingPtr != node; siblingPtr = siblingPtr->next)
2076         {
2077           for (summary = siblingPtr->summary; summary != NULL;
2078                summary = summary->next)
2079             {
2080               if (summary->toggle_count & 1)
2081                 {
2082                   inc_count (summary->info->tag, summary->toggle_count,
2083                              &tagInfo);
2084                 }
2085             }
2086         }
2087     }
2088
2089   /*
2090    * Go through the tag information and squash out all of the tags
2091    * that have even toggle counts (these tags exist before the point
2092    * of interest, but not at the desired character itself).
2093    */
2094
2095   for (src = 0, dst = 0; src < tagInfo.numTags; src++)
2096     {
2097       if (tagInfo.counts[src] & 1)
2098         {
2099           g_assert (GTK_IS_TEXT_TAG (tagInfo.tags[src]));
2100           tagInfo.tags[dst] = tagInfo.tags[src];
2101           dst++;
2102         }
2103     }
2104
2105   *num_tags = dst;
2106   g_free (tagInfo.counts);
2107   if (dst == 0)
2108     {
2109       g_free (tagInfo.tags);
2110       return NULL;
2111     }
2112   return tagInfo.tags;
2113 }
2114
2115 static void
2116 copy_segment (GString *string,
2117               gboolean include_hidden,
2118               gboolean include_nonchars,
2119               const GtkTextIter *start,
2120               const GtkTextIter *end)
2121 {
2122   GtkTextLineSegment *end_seg;
2123   GtkTextLineSegment *seg;
2124
2125   if (gtk_text_iter_equal (start, end))
2126     return;
2127
2128   seg = _gtk_text_iter_get_indexable_segment (start);
2129   end_seg = _gtk_text_iter_get_indexable_segment (end);
2130
2131   if (seg->type == &gtk_text_char_type)
2132     {
2133       gboolean copy = TRUE;
2134       gint copy_bytes = 0;
2135       gint copy_start = 0;
2136
2137       /* Don't copy if we're invisible; segments are invisible/not
2138          as a whole, no need to check each char */
2139       if (!include_hidden &&
2140           _gtk_text_btree_char_is_invisible (start))
2141         {
2142           copy = FALSE;
2143           /* printf (" <invisible>\n"); */
2144         }
2145
2146       copy_start = _gtk_text_iter_get_segment_byte (start);
2147
2148       if (seg == end_seg)
2149         {
2150           /* End is in the same segment; need to copy fewer bytes. */
2151           gint end_byte = _gtk_text_iter_get_segment_byte (end);
2152
2153           copy_bytes = end_byte - copy_start;
2154         }
2155       else
2156         copy_bytes = seg->byte_count - copy_start;
2157
2158       g_assert (copy_bytes != 0); /* Due to iter equality check at
2159                                      front of this function. */
2160
2161       if (copy)
2162         {
2163           g_assert ((copy_start + copy_bytes) <= seg->byte_count);
2164
2165           g_string_append_len (string,
2166                                seg->body.chars + copy_start,
2167                                copy_bytes);
2168         }
2169
2170       /* printf ("  :%s\n", string->str); */
2171     }
2172   else if (seg->type == &gtk_text_pixbuf_type ||
2173            seg->type == &gtk_text_child_type)
2174     {
2175       gboolean copy = TRUE;
2176
2177       if (!include_nonchars)
2178         {
2179           copy = FALSE;
2180         }
2181       else if (!include_hidden &&
2182                _gtk_text_btree_char_is_invisible (start))
2183         {
2184           copy = FALSE;
2185         }
2186
2187       if (copy)
2188         {
2189           g_string_append_len (string,
2190                                gtk_text_unknown_char_utf8,
2191                                3);
2192
2193         }
2194     }
2195 }
2196
2197 gchar*
2198 _gtk_text_btree_get_text (const GtkTextIter *start_orig,
2199                          const GtkTextIter *end_orig,
2200                          gboolean include_hidden,
2201                          gboolean include_nonchars)
2202 {
2203   GtkTextLineSegment *seg;
2204   GtkTextLineSegment *end_seg;
2205   GString *retval;
2206   GtkTextBTree *tree;
2207   gchar *str;
2208   GtkTextIter iter;
2209   GtkTextIter start;
2210   GtkTextIter end;
2211
2212   g_return_val_if_fail (start_orig != NULL, NULL);
2213   g_return_val_if_fail (end_orig != NULL, NULL);
2214   g_return_val_if_fail (_gtk_text_iter_get_btree (start_orig) ==
2215                         _gtk_text_iter_get_btree (end_orig), NULL);
2216
2217   start = *start_orig;
2218   end = *end_orig;
2219
2220   gtk_text_iter_order (&start, &end);
2221
2222   retval = g_string_new ("");
2223
2224   tree = _gtk_text_iter_get_btree (&start);
2225
2226   end_seg = _gtk_text_iter_get_indexable_segment (&end);
2227   iter = start;
2228   seg = _gtk_text_iter_get_indexable_segment (&iter);
2229   while (seg != end_seg)
2230     {
2231       copy_segment (retval, include_hidden, include_nonchars,
2232                     &iter, &end);
2233
2234       _gtk_text_iter_forward_indexable_segment (&iter);
2235
2236       seg = _gtk_text_iter_get_indexable_segment (&iter);
2237     }
2238
2239   copy_segment (retval, include_hidden, include_nonchars, &iter, &end);
2240
2241   str = retval->str;
2242   g_string_free (retval, FALSE);
2243   return str;
2244 }
2245
2246 gint
2247 _gtk_text_btree_line_count (GtkTextBTree *tree)
2248 {
2249   /* Subtract bogus line at the end; we return a count
2250      of usable lines. */
2251   return tree->root_node->num_lines - 1;
2252 }
2253
2254 gint
2255 _gtk_text_btree_char_count (GtkTextBTree *tree)
2256 {
2257   /* Exclude newline in bogus last line */
2258   return tree->root_node->num_chars - 1;
2259 }
2260
2261 #define LOTSA_TAGS 1000
2262 gboolean
2263 _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
2264 {
2265   gboolean invisible = FALSE;  /* if nobody says otherwise, it's visible */
2266
2267   int deftagCnts[LOTSA_TAGS];
2268   int *tagCnts = deftagCnts;
2269   GtkTextTag *deftags[LOTSA_TAGS];
2270   GtkTextTag **tags = deftags;
2271   int numTags;
2272   GtkTextBTreeNode *node;
2273   GtkTextLine *siblingline;
2274   GtkTextLineSegment *seg;
2275   GtkTextTag *tag;
2276   int i, index;
2277   GtkTextLine *line;
2278   GtkTextBTree *tree;
2279   gint byte_index;
2280
2281   line = _gtk_text_iter_get_text_line (iter);
2282   tree = _gtk_text_iter_get_btree (iter);
2283   byte_index = gtk_text_iter_get_line_index (iter);
2284
2285   numTags = gtk_text_tag_table_get_size (tree->table);
2286
2287   /* almost always avoid malloc, so stay out of system calls */
2288   if (LOTSA_TAGS < numTags)
2289     {
2290       tagCnts = g_new (int, numTags);
2291       tags = g_new (GtkTextTag*, numTags);
2292     }
2293
2294   for (i=0; i<numTags; i++)
2295     {
2296       tagCnts[i] = 0;
2297     }
2298
2299   /*
2300    * Record tag toggles within the line of indexPtr but preceding
2301    * indexPtr.
2302    */
2303
2304   for (index = 0, seg = line->segments;
2305        (index + seg->byte_count) <= byte_index; /* segfault here means invalid index */
2306        index += seg->byte_count, seg = seg->next)
2307     {
2308       if ((seg->type == &gtk_text_toggle_on_type)
2309           || (seg->type == &gtk_text_toggle_off_type))
2310         {
2311           tag = seg->body.toggle.info->tag;
2312           if (tag->invisible_set && tag->values->invisible)
2313             {
2314               tags[tag->priority] = tag;
2315               tagCnts[tag->priority]++;
2316             }
2317         }
2318     }
2319
2320   /*
2321    * Record toggles for tags in lines that are predecessors of
2322    * line but under the same level-0 GtkTextBTreeNode.
2323    */
2324
2325   for (siblingline = line->parent->children.line;
2326        siblingline != line;
2327        siblingline = siblingline->next)
2328     {
2329       for (seg = siblingline->segments; seg != NULL;
2330            seg = seg->next)
2331         {
2332           if ((seg->type == &gtk_text_toggle_on_type)
2333               || (seg->type == &gtk_text_toggle_off_type))
2334             {
2335               tag = seg->body.toggle.info->tag;
2336               if (tag->invisible_set && tag->values->invisible)
2337                 {
2338                   tags[tag->priority] = tag;
2339                   tagCnts[tag->priority]++;
2340                 }
2341             }
2342         }
2343     }
2344
2345   /*
2346    * For each GtkTextBTreeNode in the ancestry of this line, record tag toggles
2347    * for all siblings that precede that GtkTextBTreeNode.
2348    */
2349
2350   for (node = line->parent; node->parent != NULL;
2351        node = node->parent)
2352     {
2353       GtkTextBTreeNode *siblingPtr;
2354       Summary *summary;
2355
2356       for (siblingPtr = node->parent->children.node;
2357            siblingPtr != node; siblingPtr = siblingPtr->next)
2358         {
2359           for (summary = siblingPtr->summary; summary != NULL;
2360                summary = summary->next)
2361             {
2362               if (summary->toggle_count & 1)
2363                 {
2364                   tag = summary->info->tag;
2365                   if (tag->invisible_set && tag->values->invisible)
2366                     {
2367                       tags[tag->priority] = tag;
2368                       tagCnts[tag->priority] += summary->toggle_count;
2369                     }
2370                 }
2371             }
2372         }
2373     }
2374
2375   /*
2376    * Now traverse from highest priority to lowest,
2377    * take invisible value from first odd count (= on)
2378    */
2379
2380   for (i = numTags-1; i >=0; i--)
2381     {
2382       if (tagCnts[i] & 1)
2383         {
2384           /* FIXME not sure this should be if 0 */
2385 #if 0
2386 #ifndef ALWAYS_SHOW_SELECTION
2387           /* who would make the selection invisible? */
2388           if ((tag == tkxt->seltag)
2389               && !(tkxt->flags & GOT_FOCUS))
2390             {
2391               continue;
2392             }
2393 #endif
2394 #endif
2395           invisible = tags[i]->values->invisible;
2396           break;
2397         }
2398     }
2399
2400   if (LOTSA_TAGS < numTags)
2401     {
2402       g_free (tagCnts);
2403       g_free (tags);
2404     }
2405
2406   return invisible;
2407 }
2408
2409
2410 /*
2411  * Manipulate marks
2412  */
2413
2414 static void
2415 redisplay_region (GtkTextBTree      *tree,
2416                   const GtkTextIter *start,
2417                   const GtkTextIter *end)
2418 {
2419   BTreeView *view;
2420   GtkTextLine *start_line, *end_line;
2421
2422   if (gtk_text_iter_compare (start, end) > 0)
2423     {
2424       const GtkTextIter *tmp = start;
2425       start = end;
2426       end = tmp;
2427     }
2428
2429   start_line = _gtk_text_iter_get_text_line (start);
2430   end_line = _gtk_text_iter_get_text_line (end);
2431
2432   view = tree->views;
2433   while (view != NULL)
2434     {
2435       gint start_y, end_y;
2436       GtkTextLineData *ld;
2437
2438       start_y = _gtk_text_btree_find_line_top (tree, start_line, view->view_id);
2439
2440       if (end_line == start_line)
2441         end_y = start_y;
2442       else
2443         end_y = _gtk_text_btree_find_line_top (tree, end_line, view->view_id);
2444
2445       ld = _gtk_text_line_get_data (end_line, view->view_id);
2446       if (ld)
2447         end_y += ld->height;
2448
2449       gtk_text_layout_changed (view->layout, start_y,
2450                                end_y - start_y,
2451                                end_y - start_y);
2452
2453       view = view->next;
2454     }
2455 }
2456
2457 static void
2458 redisplay_mark (GtkTextLineSegment *mark)
2459 {
2460   GtkTextIter iter;
2461   GtkTextIter end;
2462
2463   _gtk_text_btree_get_iter_at_mark (mark->body.mark.tree,
2464                                    &iter,
2465                                    mark->body.mark.obj);
2466
2467   end = iter;
2468   gtk_text_iter_forward_char (&end);
2469
2470   _gtk_text_btree_invalidate_region (mark->body.mark.tree,
2471                                     &iter, &end);
2472 }
2473
2474 static void
2475 redisplay_mark_if_visible (GtkTextLineSegment *mark)
2476 {
2477   if (!mark->body.mark.visible)
2478     return;
2479   else
2480     redisplay_mark (mark);
2481 }
2482
2483 static void
2484 ensure_not_off_end (GtkTextBTree *tree,
2485                     GtkTextLineSegment *mark,
2486                     GtkTextIter *iter)
2487 {
2488   if (gtk_text_iter_get_line (iter) ==
2489       _gtk_text_btree_line_count (tree))
2490     gtk_text_iter_backward_char (iter);
2491 }
2492
2493 static GtkTextLineSegment*
2494 real_set_mark (GtkTextBTree      *tree,
2495                GtkTextMark       *existing_mark,
2496                const gchar       *name,
2497                gboolean           left_gravity,
2498                const GtkTextIter *where,
2499                gboolean           should_exist,
2500                gboolean           redraw_selections)
2501 {
2502   GtkTextLineSegment *mark;
2503   GtkTextIter iter;
2504
2505   g_return_val_if_fail (tree != NULL, NULL);
2506   g_return_val_if_fail (where != NULL, NULL);
2507   g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
2508
2509   if (existing_mark)
2510     mark = existing_mark->segment;
2511   else if (name != NULL)
2512     mark = g_hash_table_lookup (tree->mark_table,
2513                                 name);
2514   else
2515     mark = NULL;
2516
2517   if (should_exist && mark == NULL)
2518     {
2519       g_warning ("No mark `%s' exists!", name);
2520       return NULL;
2521     }
2522
2523   /* OK if !should_exist and it does already exist, in that case
2524    * we just move it.
2525    */
2526   
2527   iter = *where;
2528
2529   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2530     _gtk_text_iter_check (&iter);
2531   
2532   if (mark != NULL)
2533     {
2534       if (redraw_selections &&
2535           (mark == tree->insert_mark->segment ||
2536            mark == tree->selection_bound_mark->segment))
2537         {
2538           GtkTextIter old_pos;
2539
2540           _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
2541                                            mark->body.mark.obj);
2542           redisplay_region (tree, &old_pos, where);
2543         }
2544
2545       /*
2546        * don't let visible marks be after the final newline of the
2547        *  file.
2548        */
2549
2550       if (mark->body.mark.visible)
2551         {
2552           ensure_not_off_end (tree, mark, &iter);
2553         }
2554
2555       /* Redraw the mark's old location. */
2556       redisplay_mark_if_visible (mark);
2557
2558       /* Unlink mark from its current location.
2559          This could hose our iterator... */
2560       gtk_text_btree_unlink_segment (tree, mark,
2561                                      mark->body.mark.line);
2562       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2563       g_assert (mark->body.mark.line == _gtk_text_iter_get_text_line (&iter));
2564
2565       segments_changed (tree); /* make sure the iterator recomputes its
2566                                   segment */
2567     }
2568   else
2569     {
2570       mark = _gtk_mark_segment_new (tree,
2571                                     left_gravity,
2572                                     name);
2573
2574       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2575
2576       if (mark->body.mark.name)
2577         g_hash_table_insert (tree->mark_table,
2578                              mark->body.mark.name,
2579                              mark);
2580     }
2581
2582   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2583     _gtk_text_iter_check (&iter);
2584   
2585   /* Link mark into new location */
2586   gtk_text_btree_link_segment (mark, &iter);
2587
2588   /* Invalidate some iterators. */
2589   segments_changed (tree);
2590
2591   /*
2592    * update the screen at the mark's new location.
2593    */
2594
2595   redisplay_mark_if_visible (mark);
2596
2597   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2598     _gtk_text_iter_check (&iter);
2599
2600   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2601     _gtk_text_btree_check (tree);
2602   
2603   return mark;
2604 }
2605
2606
2607 GtkTextMark*
2608 _gtk_text_btree_set_mark (GtkTextBTree *tree,
2609                          GtkTextMark  *existing_mark,
2610                          const gchar *name,
2611                          gboolean left_gravity,
2612                          const GtkTextIter *iter,
2613                          gboolean should_exist)
2614 {
2615   GtkTextLineSegment *seg;
2616
2617   seg = real_set_mark (tree, existing_mark,
2618                        name, left_gravity, iter, should_exist,
2619                        TRUE);
2620
2621   return seg ? seg->body.mark.obj : NULL;
2622 }
2623
2624 gboolean
2625 _gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
2626                                      GtkTextIter  *start,
2627                                      GtkTextIter  *end)
2628 {
2629   GtkTextIter tmp_start, tmp_end;
2630
2631   _gtk_text_btree_get_iter_at_mark (tree, &tmp_start,
2632                                    tree->insert_mark);
2633   _gtk_text_btree_get_iter_at_mark (tree, &tmp_end,
2634                                    tree->selection_bound_mark);
2635
2636   if (gtk_text_iter_equal (&tmp_start, &tmp_end))
2637     {
2638       if (start)
2639         *start = tmp_start;
2640
2641       if (end)
2642         *end = tmp_end;
2643
2644       return FALSE;
2645     }
2646   else
2647     {
2648       gtk_text_iter_order (&tmp_start, &tmp_end);
2649
2650       if (start)
2651         *start = tmp_start;
2652
2653       if (end)
2654         *end = tmp_end;
2655
2656       return TRUE;
2657     }
2658 }
2659
2660 void
2661 _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
2662                              const GtkTextIter *iter)
2663 {
2664   GtkTextIter start, end;
2665
2666   if (_gtk_text_btree_get_selection_bounds (tree, &start, &end))
2667     redisplay_region (tree, &start, &end);
2668
2669   /* Move insert AND selection_bound before we redisplay */
2670   real_set_mark (tree, tree->insert_mark,
2671                  "insert", FALSE, iter, TRUE, FALSE);
2672   real_set_mark (tree, tree->selection_bound_mark,
2673                  "selection_bound", FALSE, iter, TRUE, FALSE);
2674 }
2675
2676 void
2677 _gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
2678                                     const gchar *name)
2679 {
2680   GtkTextMark *mark;
2681
2682   g_return_if_fail (tree != NULL);
2683   g_return_if_fail (name != NULL);
2684
2685   mark = g_hash_table_lookup (tree->mark_table,
2686                               name);
2687
2688   _gtk_text_btree_remove_mark (tree, mark);
2689 }
2690
2691 void
2692 _gtk_text_btree_remove_mark (GtkTextBTree *tree,
2693                             GtkTextMark *mark)
2694 {
2695   GtkTextLineSegment *segment;
2696
2697   g_return_if_fail (mark != NULL);
2698   g_return_if_fail (tree != NULL);
2699
2700   segment = mark->segment;
2701
2702   if (segment->body.mark.not_deleteable)
2703     {
2704       g_warning ("Can't delete special mark `%s'", segment->body.mark.name);
2705       return;
2706     }
2707
2708   /* This calls cleanup_line and segments_changed */
2709   gtk_text_btree_unlink_segment (tree, segment, segment->body.mark.line);
2710
2711   if (segment->body.mark.name)
2712     g_hash_table_remove (tree->mark_table, segment->body.mark.name);
2713
2714   /* Remove the ref on the mark that belonged to the segment. */
2715   g_object_unref (G_OBJECT (mark));
2716
2717   segment->body.mark.tree = NULL;
2718   segment->body.mark.line = NULL;
2719 }
2720
2721 gboolean
2722 _gtk_text_btree_mark_is_insert (GtkTextBTree *tree,
2723                                GtkTextMark *segment)
2724 {
2725   return segment == tree->insert_mark;
2726 }
2727
2728 gboolean
2729 _gtk_text_btree_mark_is_selection_bound (GtkTextBTree *tree,
2730                                         GtkTextMark *segment)
2731 {
2732   return segment == tree->selection_bound_mark;
2733 }
2734
2735 GtkTextMark*
2736 _gtk_text_btree_get_mark_by_name (GtkTextBTree *tree,
2737                                  const gchar *name)
2738 {
2739   GtkTextLineSegment *seg;
2740
2741   g_return_val_if_fail (tree != NULL, NULL);
2742   g_return_val_if_fail (name != NULL, NULL);
2743
2744   seg = g_hash_table_lookup (tree->mark_table, name);
2745
2746   return seg ? seg->body.mark.obj : NULL;
2747 }
2748
2749 /**
2750  * gtk_text_mark_set_visible:
2751  * @mark: a #GtkTextMark
2752  * @setting: visibility of mark
2753  * 
2754  * Sets the visibility of @mark; the insertion point is normally
2755  * visible, i.e. you can see it as a vertical bar. Also, the text
2756  * widget uses a visible mark to indicate where a drop will occur when
2757  * dragging-and-dropping text. Most other marks are not visible.
2758  * Marks are not visible by default.
2759  * 
2760  **/
2761 void
2762 gtk_text_mark_set_visible (GtkTextMark       *mark,
2763                            gboolean           setting)
2764 {
2765   GtkTextLineSegment *seg;
2766
2767   g_return_if_fail (mark != NULL);
2768
2769   seg = mark->segment;
2770
2771   if (seg->body.mark.visible == setting)
2772     return;
2773   else
2774     {
2775       seg->body.mark.visible = setting;
2776
2777       redisplay_mark (seg);
2778     }
2779 }
2780
2781 GtkTextLine*
2782 _gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree,
2783                                         GtkTextTag *tag)
2784 {
2785   GtkTextBTreeNode *node;
2786   GtkTextTagInfo *info;
2787
2788   g_return_val_if_fail (tree != NULL, NULL);
2789
2790   if (tag != NULL)
2791     {
2792       info = gtk_text_btree_get_existing_tag_info (tree, tag);
2793
2794       if (info == NULL)
2795         return NULL;
2796
2797       if (info->tag_root == NULL)
2798         return NULL;
2799
2800       node = info->tag_root;
2801
2802       /* We know the tag root has instances of the given
2803          tag below it */
2804
2805     continue_outer_loop:
2806       g_assert (node != NULL);
2807       while (node->level > 0)
2808         {
2809           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
2810           node = node->children.node;
2811           while (node != NULL)
2812             {
2813               if (gtk_text_btree_node_has_tag (node, tag))
2814                 goto continue_outer_loop;
2815
2816               node = node->next;
2817             }
2818           g_assert (node != NULL);
2819         }
2820
2821       g_assert (node != NULL); /* The tag summaries said some node had
2822                                   tag toggles... */
2823
2824       g_assert (node->level == 0);
2825
2826       return node->children.line;
2827     }
2828   else
2829     {
2830       /* Looking for any tag at all (tag == NULL).
2831          Unfortunately this can't be done in a simple and efficient way
2832          right now; so I'm just going to return the
2833          first line in the btree. FIXME */
2834       return _gtk_text_btree_get_line (tree, 0, NULL);
2835     }
2836 }
2837
2838 GtkTextLine*
2839 _gtk_text_btree_last_could_contain_tag (GtkTextBTree *tree,
2840                                        GtkTextTag *tag)
2841 {
2842   GtkTextBTreeNode *node;
2843   GtkTextBTreeNode *last_node;
2844   GtkTextLine *line;
2845   GtkTextTagInfo *info;
2846
2847   g_return_val_if_fail (tree != NULL, NULL);
2848
2849   if (tag != NULL)
2850     {
2851       info = gtk_text_btree_get_existing_tag_info (tree, tag);
2852
2853       if (info->tag_root == NULL)
2854         return NULL;
2855
2856       node = info->tag_root;
2857       /* We know the tag root has instances of the given
2858          tag below it */
2859
2860       while (node->level > 0)
2861         {
2862           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
2863           last_node = NULL;
2864           node = node->children.node;
2865           while (node != NULL)
2866             {
2867               if (gtk_text_btree_node_has_tag (node, tag))
2868                 last_node = node;
2869               node = node->next;
2870             }
2871
2872           node = last_node;
2873         }
2874
2875       g_assert (node != NULL); /* The tag summaries said some node had
2876                                   tag toggles... */
2877
2878       g_assert (node->level == 0);
2879
2880       /* Find the last line in this node */
2881       line = node->children.line;
2882       while (line->next != NULL)
2883         line = line->next;
2884
2885       return line;
2886     }
2887   else
2888     {
2889       /* This search can't be done efficiently at the moment,
2890          at least not without complexity.
2891          So, we just return the last line.
2892       */
2893       return _gtk_text_btree_get_line (tree, -1, NULL);
2894     }
2895 }
2896
2897
2898 /*
2899  * Lines
2900  */
2901
2902 gint
2903 _gtk_text_line_get_number (GtkTextLine *line)
2904 {
2905   GtkTextLine *line2;
2906   GtkTextBTreeNode *node, *parent, *node2;
2907   int index;
2908
2909   /*
2910    * First count how many lines precede this one in its level-0
2911    * GtkTextBTreeNode.
2912    */
2913
2914   node = line->parent;
2915   index = 0;
2916   for (line2 = node->children.line; line2 != line;
2917        line2 = line2->next)
2918     {
2919       if (line2 == NULL)
2920         {
2921           g_error ("gtk_text_btree_line_number couldn't find line");
2922         }
2923       index += 1;
2924     }
2925
2926   /*
2927    * Now work up through the levels of the tree one at a time,
2928    * counting how many lines are in GtkTextBTreeNodes preceding the current
2929    * GtkTextBTreeNode.
2930    */
2931
2932   for (parent = node->parent ; parent != NULL;
2933        node = parent, parent = parent->parent)
2934     {
2935       for (node2 = parent->children.node; node2 != node;
2936            node2 = node2->next)
2937         {
2938           if (node2 == NULL)
2939             {
2940               g_error ("gtk_text_btree_line_number couldn't find GtkTextBTreeNode");
2941             }
2942           index += node2->num_lines;
2943         }
2944     }
2945   return index;
2946 }
2947
2948 static GtkTextLineSegment*
2949 find_toggle_segment_before_char (GtkTextLine *line,
2950                                  gint char_in_line,
2951                                  GtkTextTag *tag)
2952 {
2953   GtkTextLineSegment *seg;
2954   GtkTextLineSegment *toggle_seg;
2955   int index;
2956
2957   toggle_seg = NULL;
2958   index = 0;
2959   seg = line->segments;
2960   while ( (index + seg->char_count) <= char_in_line )
2961     {
2962       if (((seg->type == &gtk_text_toggle_on_type)
2963            || (seg->type == &gtk_text_toggle_off_type))
2964           && (seg->body.toggle.info->tag == tag))
2965         toggle_seg = seg;
2966
2967       index += seg->char_count;
2968       seg = seg->next;
2969     }
2970
2971   return toggle_seg;
2972 }
2973
2974 static GtkTextLineSegment*
2975 find_toggle_segment_before_byte (GtkTextLine *line,
2976                                  gint byte_in_line,
2977                                  GtkTextTag *tag)
2978 {
2979   GtkTextLineSegment *seg;
2980   GtkTextLineSegment *toggle_seg;
2981   int index;
2982
2983   toggle_seg = NULL;
2984   index = 0;
2985   seg = line->segments;
2986   while ( (index + seg->byte_count) <= byte_in_line )
2987     {
2988       if (((seg->type == &gtk_text_toggle_on_type)
2989            || (seg->type == &gtk_text_toggle_off_type))
2990           && (seg->body.toggle.info->tag == tag))
2991         toggle_seg = seg;
2992
2993       index += seg->byte_count;
2994       seg = seg->next;
2995     }
2996
2997   return toggle_seg;
2998 }
2999
3000 static gboolean
3001 find_toggle_outside_current_line (GtkTextLine *line,
3002                                   GtkTextBTree *tree,
3003                                   GtkTextTag *tag)
3004 {
3005   GtkTextBTreeNode *node;
3006   GtkTextLine *sibling_line;
3007   GtkTextLineSegment *seg;
3008   GtkTextLineSegment *toggle_seg;
3009   int toggles;
3010   GtkTextTagInfo *info = NULL;
3011
3012   /*
3013    * No toggle in this line.  Look for toggles for the tag in lines
3014    * that are predecessors of line but under the same
3015    * level-0 GtkTextBTreeNode.
3016    */
3017   toggle_seg = NULL;
3018   sibling_line = line->parent->children.line;
3019   while (sibling_line != line)
3020     {
3021       seg = sibling_line->segments;
3022       while (seg != NULL)
3023         {
3024           if (((seg->type == &gtk_text_toggle_on_type)
3025                || (seg->type == &gtk_text_toggle_off_type))
3026               && (seg->body.toggle.info->tag == tag))
3027             toggle_seg = seg;
3028
3029           seg = seg->next;
3030         }
3031
3032       sibling_line = sibling_line->next;
3033     }
3034
3035   if (toggle_seg != NULL)
3036     return (toggle_seg->type == &gtk_text_toggle_on_type);
3037
3038   /*
3039    * No toggle in this GtkTextBTreeNode.  Scan upwards through the ancestors of
3040    * this GtkTextBTreeNode, counting the number of toggles of the given tag in
3041    * siblings that precede that GtkTextBTreeNode.
3042    */
3043
3044   info = gtk_text_btree_get_existing_tag_info (tree, tag);
3045
3046   if (info == NULL)
3047     return FALSE;
3048
3049   toggles = 0;
3050   node = line->parent;
3051   while (node->parent != NULL)
3052     {
3053       GtkTextBTreeNode *sibling_node;
3054
3055       sibling_node = node->parent->children.node;
3056       while (sibling_node != node)
3057         {
3058           Summary *summary;
3059
3060           summary = sibling_node->summary;
3061           while (summary != NULL)
3062             {
3063               if (summary->info == info)
3064                 toggles += summary->toggle_count;
3065
3066               summary = summary->next;
3067             }
3068
3069           sibling_node = sibling_node->next;
3070         }
3071
3072       if (node == info->tag_root)
3073         break;
3074
3075       node = node->parent;
3076     }
3077
3078   /*
3079    * An odd number of toggles means that the tag is present at the
3080    * given point.
3081    */
3082
3083   return (toggles & 1) != 0;
3084 }
3085
3086 /* FIXME this function is far too slow, for no good reason. */
3087 gboolean
3088 _gtk_text_line_char_has_tag (GtkTextLine *line,
3089                             GtkTextBTree *tree,
3090                             gint char_in_line,
3091                             GtkTextTag *tag)
3092 {
3093   GtkTextLineSegment *toggle_seg;
3094
3095   g_return_val_if_fail (line != NULL, FALSE);
3096
3097   /*
3098    * Check for toggles for the tag in the line but before
3099    * the char.  If there is one, its type indicates whether or
3100    * not the character is tagged.
3101    */
3102
3103   toggle_seg = find_toggle_segment_before_char (line, char_in_line, tag);
3104
3105   if (toggle_seg != NULL)
3106     return (toggle_seg->type == &gtk_text_toggle_on_type);
3107   else
3108     return find_toggle_outside_current_line (line, tree, tag);
3109 }
3110
3111 gboolean
3112 _gtk_text_line_byte_has_tag (GtkTextLine *line,
3113                             GtkTextBTree *tree,
3114                             gint byte_in_line,
3115                             GtkTextTag *tag)
3116 {
3117   GtkTextLineSegment *toggle_seg;
3118
3119   g_return_val_if_fail (line != NULL, FALSE);
3120
3121   /*
3122    * Check for toggles for the tag in the line but before
3123    * the char.  If there is one, its type indicates whether or
3124    * not the character is tagged.
3125    */
3126
3127   toggle_seg = find_toggle_segment_before_byte (line, byte_in_line, tag);
3128
3129   if (toggle_seg != NULL)
3130     return (toggle_seg->type == &gtk_text_toggle_on_type);
3131   else
3132     return find_toggle_outside_current_line (line, tree, tag);
3133 }
3134
3135 gboolean
3136 _gtk_text_line_is_last (GtkTextLine *line,
3137                        GtkTextBTree *tree)
3138 {
3139   return line == get_last_line (tree);
3140 }
3141
3142 GtkTextLine*
3143 _gtk_text_line_next (GtkTextLine *line)
3144 {
3145   GtkTextBTreeNode *node;
3146
3147   if (line->next != NULL)
3148     return line->next;
3149   else
3150     {
3151       /*
3152        * This was the last line associated with the particular parent
3153        * GtkTextBTreeNode.  Search up the tree for the next GtkTextBTreeNode,
3154        * then search down from that GtkTextBTreeNode to find the first
3155        * line.
3156        */
3157
3158       node = line->parent;
3159       while (node != NULL && node->next == NULL)
3160         node = node->parent;
3161
3162       if (node == NULL)
3163         return NULL;
3164
3165       node = node->next;
3166       while (node->level > 0)
3167         {
3168           node = node->children.node;
3169         }
3170
3171       g_assert (node->children.line != line);
3172
3173       return node->children.line;
3174     }
3175 }
3176
3177 GtkTextLine*
3178 _gtk_text_line_previous (GtkTextLine *line)
3179 {
3180   GtkTextBTreeNode *node;
3181   GtkTextBTreeNode *node2;
3182   GtkTextLine *prev;
3183
3184   /*
3185    * Find the line under this GtkTextBTreeNode just before the starting line.
3186    */
3187   prev = line->parent->children.line;        /* First line at leaf */
3188   while (prev != line)
3189     {
3190       if (prev->next == line)
3191         return prev;
3192
3193       prev = prev->next;
3194
3195       if (prev == NULL)
3196         g_error ("gtk_text_btree_previous_line ran out of lines");
3197     }
3198
3199   /*
3200    * This was the first line associated with the particular parent
3201    * GtkTextBTreeNode.  Search up the tree for the previous GtkTextBTreeNode,
3202    * then search down from that GtkTextBTreeNode to find its last line.
3203    */
3204   for (node = line->parent; ; node = node->parent)
3205     {
3206       if (node == NULL || node->parent == NULL)
3207         return NULL;
3208       else if (node != node->parent->children.node)
3209         break;
3210     }
3211
3212   for (node2 = node->parent->children.node; ;
3213        node2 = node2->children.node)
3214     {
3215       while (node2->next != node)
3216         node2 = node2->next;
3217
3218       if (node2->level == 0)
3219         break;
3220
3221       node = NULL;
3222     }
3223
3224   for (prev = node2->children.line ; ; prev = prev->next)
3225     {
3226       if (prev->next == NULL)
3227         return prev;
3228     }
3229
3230   g_assert_not_reached ();
3231   return NULL;
3232 }
3233
3234 void
3235 _gtk_text_line_add_data (GtkTextLine     *line,
3236                         GtkTextLineData *data)
3237 {
3238   g_return_if_fail (line != NULL);
3239   g_return_if_fail (data != NULL);
3240   g_return_if_fail (data->view_id != NULL);
3241
3242   if (line->views)
3243     {
3244       data->next = line->views;
3245       line->views = data;
3246     }
3247   else
3248     {
3249       line->views = data;
3250     }
3251 }
3252
3253 gpointer
3254 _gtk_text_line_remove_data (GtkTextLine *line,
3255                            gpointer view_id)
3256 {
3257   GtkTextLineData *prev;
3258   GtkTextLineData *iter;
3259
3260   g_return_val_if_fail (line != NULL, NULL);
3261   g_return_val_if_fail (view_id != NULL, NULL);
3262
3263   prev = NULL;
3264   iter = line->views;
3265   while (iter != NULL)
3266     {
3267       if (iter->view_id == view_id)
3268         break;
3269       prev = iter;
3270       iter = iter->next;
3271     }
3272
3273   if (iter)
3274     {
3275       if (prev)
3276         prev->next = iter->next;
3277       else
3278         line->views = iter->next;
3279
3280       return iter;
3281     }
3282   else
3283     return NULL;
3284 }
3285
3286 gpointer
3287 _gtk_text_line_get_data (GtkTextLine *line,
3288                          gpointer view_id)
3289 {
3290   GtkTextLineData *iter;
3291
3292   g_return_val_if_fail (line != NULL, NULL);
3293   g_return_val_if_fail (view_id != NULL, NULL);
3294
3295   iter = line->views;
3296   while (iter != NULL)
3297     {
3298       if (iter->view_id == view_id)
3299         break;
3300       iter = iter->next;
3301     }
3302
3303   return iter;
3304 }
3305
3306 void
3307 _gtk_text_line_invalidate_wrap (GtkTextLine *line,
3308                                 GtkTextLineData *ld)
3309 {
3310   /* For now this is totally unoptimized. FIXME?
3311
3312      We could probably optimize the case where the width removed
3313      is less than the max width for the parent node,
3314      and the case where the height is unchanged when we re-wrap.
3315   */
3316   
3317   g_return_if_fail (ld != NULL);
3318   
3319   ld->valid = FALSE;
3320   gtk_text_btree_node_invalidate_upward (line->parent, ld->view_id);
3321 }
3322
3323 gint
3324 _gtk_text_line_char_count (GtkTextLine *line)
3325 {
3326   GtkTextLineSegment *seg;
3327   gint size;
3328
3329   size = 0;
3330   seg = line->segments;
3331   while (seg != NULL)
3332     {
3333       size += seg->char_count;
3334       seg = seg->next;
3335     }
3336   return size;
3337 }
3338
3339 gint
3340 _gtk_text_line_byte_count (GtkTextLine *line)
3341 {
3342   GtkTextLineSegment *seg;
3343   gint size;
3344
3345   size = 0;
3346   seg = line->segments;
3347   while (seg != NULL)
3348     {
3349       size += seg->byte_count;
3350       seg = seg->next;
3351     }
3352
3353   return size;
3354 }
3355
3356 gint
3357 _gtk_text_line_char_index (GtkTextLine *target_line)
3358 {
3359   GSList *node_stack = NULL;
3360   GtkTextBTreeNode *iter;
3361   GtkTextLine *line;
3362   gint num_chars;
3363
3364   /* Push all our parent nodes onto a stack */
3365   iter = target_line->parent;
3366
3367   g_assert (iter != NULL);
3368
3369   while (iter != NULL)
3370     {
3371       node_stack = g_slist_prepend (node_stack, iter);
3372
3373       iter = iter->parent;
3374     }
3375
3376   /* Check that we have the root node on top of the stack. */
3377   g_assert (node_stack != NULL &&
3378             node_stack->data != NULL &&
3379             ((GtkTextBTreeNode*)node_stack->data)->parent == NULL);
3380
3381   /* Add up chars in all nodes before the nodes in our stack.
3382    */
3383
3384   num_chars = 0;
3385   iter = node_stack->data;
3386   while (iter != NULL)
3387     {
3388       GtkTextBTreeNode *child_iter;
3389       GtkTextBTreeNode *next_node;
3390
3391       next_node = node_stack->next ?
3392         node_stack->next->data : NULL;
3393       node_stack = g_slist_remove (node_stack, node_stack->data);
3394
3395       if (iter->level == 0)
3396         {
3397           /* stack should be empty when we're on the last node */
3398           g_assert (node_stack == NULL);
3399           break; /* Our children are now lines */
3400         }
3401
3402       g_assert (next_node != NULL);
3403       g_assert (iter != NULL);
3404       g_assert (next_node->parent == iter);
3405
3406       /* Add up chars before us in the tree */
3407       child_iter = iter->children.node;
3408       while (child_iter != next_node)
3409         {
3410           g_assert (child_iter != NULL);
3411
3412           num_chars += child_iter->num_chars;
3413
3414           child_iter = child_iter->next;
3415         }
3416
3417       iter = next_node;
3418     }
3419
3420   g_assert (iter != NULL);
3421   g_assert (iter == target_line->parent);
3422
3423   /* Since we don't store char counts in lines, only in segments, we
3424      have to iterate over the lines adding up segment char counts
3425      until we find our line.  */
3426   line = iter->children.line;
3427   while (line != target_line)
3428     {
3429       g_assert (line != NULL);
3430
3431       num_chars += _gtk_text_line_char_count (line);
3432
3433       line = line->next;
3434     }
3435
3436   g_assert (line == target_line);
3437
3438   return num_chars;
3439 }
3440
3441 GtkTextLineSegment*
3442 _gtk_text_line_byte_to_segment (GtkTextLine *line,
3443                                gint byte_offset,
3444                                gint *seg_offset)
3445 {
3446   GtkTextLineSegment *seg;
3447   int offset;
3448
3449   g_return_val_if_fail (line != NULL, NULL);
3450
3451   offset = byte_offset;
3452   seg = line->segments;
3453
3454   while (offset >= seg->byte_count)
3455     {
3456       g_assert (seg != NULL); /* means an invalid byte index */
3457       offset -= seg->byte_count;
3458       seg = seg->next;
3459     }
3460
3461   if (seg_offset)
3462     *seg_offset = offset;
3463
3464   return seg;
3465 }
3466
3467 GtkTextLineSegment*
3468 _gtk_text_line_char_to_segment (GtkTextLine *line,
3469                                gint char_offset,
3470                                gint *seg_offset)
3471 {
3472   GtkTextLineSegment *seg;
3473   int offset;
3474
3475   g_return_val_if_fail (line != NULL, NULL);
3476
3477   offset = char_offset;
3478   seg = line->segments;
3479
3480   while (offset >= seg->char_count)
3481     {
3482       g_assert (seg != NULL); /* means an invalid char index */
3483       offset -= seg->char_count;
3484       seg = seg->next;
3485     }
3486
3487   if (seg_offset)
3488     *seg_offset = offset;
3489
3490   return seg;
3491 }
3492
3493 GtkTextLineSegment*
3494 _gtk_text_line_byte_to_any_segment (GtkTextLine *line,
3495                                    gint byte_offset,
3496                                    gint *seg_offset)
3497 {
3498   GtkTextLineSegment *seg;
3499   int offset;
3500
3501   g_return_val_if_fail (line != NULL, NULL);
3502
3503   offset = byte_offset;
3504   seg = line->segments;
3505
3506   while (offset > 0 && offset >= seg->byte_count)
3507     {
3508       g_assert (seg != NULL); /* means an invalid byte index */
3509       offset -= seg->byte_count;
3510       seg = seg->next;
3511     }
3512
3513   if (seg_offset)
3514     *seg_offset = offset;
3515
3516   return seg;
3517 }
3518
3519 GtkTextLineSegment*
3520 _gtk_text_line_char_to_any_segment (GtkTextLine *line,
3521                                    gint char_offset,
3522                                    gint *seg_offset)
3523 {
3524   GtkTextLineSegment *seg;
3525   int offset;
3526
3527   g_return_val_if_fail (line != NULL, NULL);
3528
3529   offset = char_offset;
3530   seg = line->segments;
3531
3532   while (offset > 0 && offset >= seg->char_count)
3533     {
3534       g_assert (seg != NULL); /* means an invalid byte index */
3535       offset -= seg->char_count;
3536       seg = seg->next;
3537     }
3538
3539   if (seg_offset)
3540     *seg_offset = offset;
3541
3542   return seg;
3543 }
3544
3545 gint
3546 _gtk_text_line_byte_to_char (GtkTextLine *line,
3547                             gint byte_offset)
3548 {
3549   gint char_offset;
3550   GtkTextLineSegment *seg;
3551
3552   g_return_val_if_fail (line != NULL, 0);
3553   g_return_val_if_fail (byte_offset >= 0, 0);
3554
3555   char_offset = 0;
3556   seg = line->segments;
3557   while (byte_offset >= seg->byte_count) /* while (we need to go farther than
3558                                             the next segment) */
3559     {
3560       g_assert (seg != NULL); /* our byte_index was bogus if this happens */
3561
3562       byte_offset -= seg->byte_count;
3563       char_offset += seg->char_count;
3564
3565       seg = seg->next;
3566     }
3567
3568   g_assert (seg != NULL);
3569
3570   /* Now byte_offset is the offset into the current segment,
3571      and char_offset is the start of the current segment.
3572      Optimize the case where no chars use > 1 byte */
3573   if (seg->byte_count == seg->char_count)
3574     return char_offset + byte_offset;
3575   else
3576     {
3577       if (seg->type == &gtk_text_char_type)
3578         return char_offset + g_utf8_strlen (seg->body.chars, byte_offset);
3579       else
3580         {
3581           g_assert (seg->char_count == 1);
3582           g_assert (byte_offset == 0);
3583
3584           return char_offset;
3585         }
3586     }
3587 }
3588
3589 gint
3590 _gtk_text_line_char_to_byte (GtkTextLine *line,
3591                             gint         char_offset)
3592 {
3593   g_warning ("FIXME not implemented");
3594
3595   return 0;
3596 }
3597
3598 /* FIXME sync with char_locate (or figure out a clean
3599    way to merge the two functions) */
3600 gboolean
3601 _gtk_text_line_byte_locate (GtkTextLine *line,
3602                             gint byte_offset,
3603                             GtkTextLineSegment **segment,
3604                             GtkTextLineSegment **any_segment,
3605                             gint *seg_byte_offset,
3606                             gint *line_byte_offset)
3607 {
3608   GtkTextLineSegment *seg;
3609   GtkTextLineSegment *after_prev_indexable;
3610   GtkTextLineSegment *after_last_indexable;
3611   GtkTextLineSegment *last_indexable;
3612   gint offset;
3613   gint bytes_in_line;
3614
3615   g_return_val_if_fail (line != NULL, FALSE);
3616   g_return_val_if_fail (byte_offset >= 0, FALSE);
3617
3618   *segment = NULL;
3619   *any_segment = NULL;
3620   bytes_in_line = 0;
3621
3622   offset = byte_offset;
3623
3624   last_indexable = NULL;
3625   after_last_indexable = line->segments;
3626   after_prev_indexable = line->segments;
3627   seg = line->segments;
3628
3629   /* The loop ends when we're inside a segment;
3630      last_indexable refers to the last segment
3631      we passed entirely. */
3632   while (seg && offset >= seg->byte_count)
3633     {
3634       if (seg->char_count > 0)
3635         {
3636           offset -= seg->byte_count;
3637           bytes_in_line += seg->byte_count;
3638           last_indexable = seg;
3639           after_prev_indexable = after_last_indexable;
3640           after_last_indexable = last_indexable->next;
3641         }
3642
3643       seg = seg->next;
3644     }
3645
3646   if (seg == NULL)
3647     {
3648       /* We went off the end of the line */
3649       if (offset != 0)
3650         g_warning ("%s: byte index off the end of the line", G_STRLOC);
3651
3652       return FALSE;
3653     }
3654   else
3655     {
3656       *segment = seg;
3657       if (after_last_indexable != NULL)
3658         *any_segment = after_last_indexable;
3659       else
3660         *any_segment = *segment;
3661     }
3662
3663   /* Override any_segment if we're in the middle of a segment. */
3664   if (offset > 0)
3665     *any_segment = *segment;
3666
3667   *seg_byte_offset = offset;
3668
3669   g_assert (*segment != NULL);
3670   g_assert (*any_segment != NULL);
3671   g_assert (*seg_byte_offset < (*segment)->byte_count);
3672
3673   *line_byte_offset = bytes_in_line + *seg_byte_offset;
3674
3675   return TRUE;
3676 }
3677
3678 /* FIXME sync with byte_locate (or figure out a clean
3679    way to merge the two functions) */
3680 gboolean
3681 _gtk_text_line_char_locate     (GtkTextLine     *line,
3682                                 gint              char_offset,
3683                                 GtkTextLineSegment **segment,
3684                                 GtkTextLineSegment **any_segment,
3685                                 gint             *seg_char_offset,
3686                                 gint             *line_char_offset)
3687 {
3688   GtkTextLineSegment *seg;
3689   GtkTextLineSegment *after_prev_indexable;
3690   GtkTextLineSegment *after_last_indexable;
3691   GtkTextLineSegment *last_indexable;
3692   gint offset;
3693   gint chars_in_line;
3694
3695   g_return_val_if_fail (line != NULL, FALSE);
3696   g_return_val_if_fail (char_offset >= 0, FALSE);
3697   
3698   *segment = NULL;
3699   *any_segment = NULL;
3700   chars_in_line = 0;
3701
3702   offset = char_offset;
3703
3704   last_indexable = NULL;
3705   after_last_indexable = line->segments;
3706   after_prev_indexable = line->segments;
3707   seg = line->segments;
3708
3709   /* The loop ends when we're inside a segment;
3710      last_indexable refers to the last segment
3711      we passed entirely. */
3712   while (seg && offset >= seg->char_count)
3713     {
3714       if (seg->char_count > 0)
3715         {
3716           offset -= seg->char_count;
3717           chars_in_line += seg->char_count;
3718           last_indexable = seg;
3719           after_prev_indexable = after_last_indexable;
3720           after_last_indexable = last_indexable->next;
3721         }
3722
3723       seg = seg->next;
3724     }
3725
3726   if (seg == NULL)
3727     {
3728       /* end of the line */
3729       if (offset != 0)
3730         g_warning ("%s: char offset off the end of the line", G_STRLOC);
3731
3732       return FALSE;
3733     }
3734   else
3735     {
3736       *segment = seg;
3737       if (after_last_indexable != NULL)
3738         *any_segment = after_last_indexable;
3739       else
3740         *any_segment = *segment;
3741     }
3742
3743   /* Override any_segment if we're in the middle of a segment. */
3744   if (offset > 0)
3745     *any_segment = *segment;
3746
3747   *seg_char_offset = offset;
3748
3749   g_assert (*segment != NULL);
3750   g_assert (*any_segment != NULL);
3751   g_assert (*seg_char_offset < (*segment)->char_count);
3752
3753   *line_char_offset = chars_in_line + *seg_char_offset;
3754
3755   return TRUE;
3756 }
3757
3758 void
3759 _gtk_text_line_byte_to_char_offsets (GtkTextLine *line,
3760                                     gint byte_offset,
3761                                     gint *line_char_offset,
3762                                     gint *seg_char_offset)
3763 {
3764   GtkTextLineSegment *seg;
3765   int offset;
3766
3767   g_return_if_fail (line != NULL);
3768   g_return_if_fail (byte_offset >= 0);
3769
3770   *line_char_offset = 0;
3771
3772   offset = byte_offset;
3773   seg = line->segments;
3774
3775   while (offset >= seg->byte_count)
3776     {
3777       offset -= seg->byte_count;
3778       *line_char_offset += seg->char_count;
3779       seg = seg->next;
3780       g_assert (seg != NULL); /* means an invalid char offset */
3781     }
3782
3783   g_assert (seg->char_count > 0); /* indexable. */
3784
3785   /* offset is now the number of bytes into the current segment we
3786    * want to go. Count chars into the current segment.
3787    */
3788
3789   if (seg->type == &gtk_text_char_type)
3790     {
3791       *seg_char_offset = g_utf8_strlen (seg->body.chars, offset);
3792
3793       g_assert (*seg_char_offset < seg->char_count);
3794
3795       *line_char_offset += *seg_char_offset;
3796     }
3797   else
3798     {
3799       g_assert (offset == 0);
3800       *seg_char_offset = 0;
3801     }
3802 }
3803
3804 void
3805 _gtk_text_line_char_to_byte_offsets (GtkTextLine *line,
3806                                     gint char_offset,
3807                                     gint *line_byte_offset,
3808                                     gint *seg_byte_offset)
3809 {
3810   GtkTextLineSegment *seg;
3811   int offset;
3812
3813   g_return_if_fail (line != NULL);
3814   g_return_if_fail (char_offset >= 0);
3815
3816   *line_byte_offset = 0;
3817
3818   offset = char_offset;
3819   seg = line->segments;
3820
3821   while (offset >= seg->char_count)
3822     {
3823       offset -= seg->char_count;
3824       *line_byte_offset += seg->byte_count;
3825       seg = seg->next;
3826       g_assert (seg != NULL); /* means an invalid char offset */
3827     }
3828
3829   g_assert (seg->char_count > 0); /* indexable. */
3830
3831   /* offset is now the number of chars into the current segment we
3832      want to go. Count bytes into the current segment. */
3833
3834   if (seg->type == &gtk_text_char_type)
3835     {
3836       *seg_byte_offset = 0;
3837       while (offset > 0)
3838         {
3839           gint bytes;
3840           const char * start = seg->body.chars + *seg_byte_offset;
3841
3842           bytes = g_utf8_next_char (start) - start;
3843           *seg_byte_offset += bytes;
3844           offset -= 1;
3845         }
3846
3847       g_assert (*seg_byte_offset < seg->byte_count);
3848
3849       *line_byte_offset += *seg_byte_offset;
3850     }
3851   else
3852     {
3853       g_assert (offset == 0);
3854       *seg_byte_offset = 0;
3855     }
3856 }
3857
3858 static gint
3859 node_compare (GtkTextBTreeNode *lhs,
3860               GtkTextBTreeNode *rhs)
3861 {
3862   GtkTextBTreeNode *iter;
3863   GtkTextBTreeNode *node;
3864   GtkTextBTreeNode *common_parent;
3865   GtkTextBTreeNode *parent_of_lower;
3866   GtkTextBTreeNode *parent_of_higher;
3867   gboolean lhs_is_lower;
3868   GtkTextBTreeNode *lower;
3869   GtkTextBTreeNode *higher;
3870
3871   /* This function assumes that lhs and rhs are not underneath each
3872    * other.
3873    */
3874
3875   if (lhs == rhs)
3876     return 0;
3877
3878   if (lhs->level < rhs->level)
3879     {
3880       lhs_is_lower = TRUE;
3881       lower = lhs;
3882       higher = rhs;
3883     }
3884   else
3885     {
3886       lhs_is_lower = FALSE;
3887       lower = rhs;
3888       higher = lhs;
3889     }
3890
3891   /* Algorithm: find common parent of lhs/rhs. Save the child nodes
3892    * of the common parent we used to reach the common parent; the
3893    * ordering of these child nodes in the child list is the ordering
3894    * of lhs and rhs.
3895    */
3896
3897   /* Get on the same level (may be on same level already) */
3898   node = lower;
3899   while (node->level < higher->level)
3900     node = node->parent;
3901
3902   g_assert (node->level == higher->level);
3903
3904   g_assert (node != higher); /* Happens if lower is underneath higher */
3905
3906   /* Go up until we have two children with a common parent.
3907    */
3908   parent_of_lower = node;
3909   parent_of_higher = higher;
3910
3911   while (parent_of_lower->parent != parent_of_higher->parent)
3912     {
3913       parent_of_lower = parent_of_lower->parent;
3914       parent_of_higher = parent_of_higher->parent;
3915     }
3916
3917   g_assert (parent_of_lower->parent == parent_of_higher->parent);
3918
3919   common_parent = parent_of_lower->parent;
3920
3921   g_assert (common_parent != NULL);
3922
3923   /* See which is first in the list of common_parent's children */
3924   iter = common_parent->children.node;
3925   while (iter != NULL)
3926     {
3927       if (iter == parent_of_higher)
3928         {
3929           /* higher is less than lower */
3930
3931           if (lhs_is_lower)
3932             return 1; /* lhs > rhs */
3933           else
3934             return -1;
3935         }
3936       else if (iter == parent_of_lower)
3937         {
3938           /* lower is less than higher */
3939
3940           if (lhs_is_lower)
3941             return -1; /* lhs < rhs */
3942           else
3943             return 1;
3944         }
3945
3946       iter = iter->next;
3947     }
3948
3949   g_assert_not_reached ();
3950   return 0;
3951 }
3952
3953 /* remember that tag == NULL means "any tag" */
3954 GtkTextLine*
3955 _gtk_text_line_next_could_contain_tag (GtkTextLine *line,
3956                                       GtkTextBTree *tree,
3957                                       GtkTextTag  *tag)
3958 {
3959   GtkTextBTreeNode *node;
3960   GtkTextTagInfo *info;
3961   gboolean below_tag_root;
3962
3963   g_return_val_if_fail (line != NULL, NULL);
3964
3965   if (gtk_debug_flags & GTK_DEBUG_TEXT)
3966     _gtk_text_btree_check (tree);
3967
3968   if (tag == NULL)
3969     {
3970       /* Right now we can only offer linear-search if the user wants
3971        * to know about any tag toggle at all.
3972        */
3973       return _gtk_text_line_next (line);
3974     }
3975
3976   /* Our tag summaries only have node precision, not line
3977      precision. This means that if any line under a node could contain a
3978      tag, then any of the others could also contain a tag.
3979
3980      In the future we could have some mechanism to keep track of how
3981      many toggles we've found under a node so far, since we have a
3982      count of toggles under the node. But for now I'm going with KISS.
3983   */
3984
3985   /* return same-node line, if any. */
3986   if (line->next)
3987     return line->next;
3988
3989   info = gtk_text_btree_get_existing_tag_info (tree, tag);
3990   if (info == NULL)
3991     return NULL;
3992
3993   if (info->tag_root == NULL)
3994     return NULL;
3995
3996   if (info->tag_root == line->parent)
3997     return NULL; /* we were at the last line under the tag root */
3998
3999   /* We need to go up out of this node, and on to the next one with
4000      toggles for the target tag. If we're below the tag root, we need to
4001      find the next node below the tag root that has tag summaries. If
4002      we're not below the tag root, we need to see if the tag root is
4003      after us in the tree, and if so, return the first line underneath
4004      the tag root. */
4005
4006   node = line->parent;
4007   below_tag_root = FALSE;
4008   while (node != NULL)
4009     {
4010       if (node == info->tag_root)
4011         {
4012           below_tag_root = TRUE;
4013           break;
4014         }
4015
4016       node = node->parent;
4017     }
4018
4019   if (below_tag_root)
4020     {
4021       node = line->parent;
4022       while (node != info->tag_root)
4023         {
4024           if (node->next == NULL)
4025             node = node->parent;
4026           else
4027             {
4028               node = node->next;
4029
4030               if (gtk_text_btree_node_has_tag (node, tag))
4031                 goto found;
4032             }
4033         }
4034       return NULL;
4035     }
4036   else
4037     {
4038       gint ordering;
4039
4040       ordering = node_compare (line->parent, info->tag_root);
4041
4042       if (ordering < 0)
4043         {
4044           /* Tag root is ahead of us, so search there. */
4045           node = info->tag_root;
4046           goto found;
4047         }
4048       else
4049         {
4050           /* Tag root is after us, so no more lines that
4051            * could contain the tag.
4052            */
4053           return NULL;
4054         }
4055
4056       g_assert_not_reached ();
4057     }
4058
4059  found:
4060
4061   g_assert (node != NULL);
4062
4063   /* We have to find the first sub-node of this node that contains
4064    * the target tag.
4065    */
4066
4067   while (node->level > 0)
4068     {
4069       g_assert (node != NULL); /* If this fails, it likely means an
4070                                   incorrect tag summary led us on a
4071                                   wild goose chase down this branch of
4072                                   the tree. */
4073       node = node->children.node;
4074       while (node != NULL)
4075         {
4076           if (gtk_text_btree_node_has_tag (node, tag))
4077             break;
4078           node = node->next;
4079         }
4080     }
4081
4082   g_assert (node != NULL);
4083   g_assert (node->level == 0);
4084
4085   return node->children.line;
4086 }
4087
4088 static GtkTextLine*
4089 prev_line_under_node (GtkTextBTreeNode *node,
4090                       GtkTextLine      *line)
4091 {
4092   GtkTextLine *prev;
4093
4094   prev = node->children.line;
4095
4096   g_assert (prev);
4097
4098   if (prev != line)
4099     {
4100       while (prev->next != line)
4101         prev = prev->next;
4102
4103       return prev;
4104     }
4105
4106   return NULL;
4107 }
4108
4109 GtkTextLine*
4110 _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
4111                                           GtkTextBTree *tree,
4112                                           GtkTextTag   *tag)
4113 {
4114   GtkTextBTreeNode *node;
4115   GtkTextBTreeNode *found_node = NULL;
4116   GtkTextTagInfo *info;
4117   gboolean below_tag_root;
4118   GtkTextLine *prev;
4119   GtkTextBTreeNode *line_ancestor;
4120   GtkTextBTreeNode *line_ancestor_parent;
4121
4122   /* See next_could_contain_tag () for more extensive comments
4123    * on what's going on here.
4124    */
4125
4126   g_return_val_if_fail (line != NULL, NULL);
4127
4128   if (gtk_debug_flags & GTK_DEBUG_TEXT)
4129     _gtk_text_btree_check (tree);
4130
4131   if (tag == NULL)
4132     {
4133       /* Right now we can only offer linear-search if the user wants
4134        * to know about any tag toggle at all.
4135        */
4136       return _gtk_text_line_previous (line);
4137     }
4138
4139   /* Return same-node line, if any. */
4140   prev = prev_line_under_node (line->parent, line);
4141   if (prev)
4142     return prev;
4143
4144   info = gtk_text_btree_get_existing_tag_info (tree, tag);
4145   if (info == NULL)
4146     return NULL;
4147
4148   if (info->tag_root == NULL)
4149     return NULL;
4150
4151   if (info->tag_root == line->parent)
4152     return NULL; /* we were at the first line under the tag root */
4153
4154   /* Are we below the tag root */
4155   node = line->parent;
4156   below_tag_root = FALSE;
4157   while (node != NULL)
4158     {
4159       if (node == info->tag_root)
4160         {
4161           below_tag_root = TRUE;
4162           break;
4163         }
4164
4165       node = node->parent;
4166     }
4167
4168   if (below_tag_root)
4169     {
4170       /* Look for a previous node under this tag root that has our
4171        * tag.
4172        */
4173
4174       /* this assertion holds because line->parent is not the
4175        * tag root, we are below the tag root, and the tag
4176        * root exists.
4177        */
4178       g_assert (line->parent->parent != NULL);
4179
4180       line_ancestor = line->parent;
4181       line_ancestor_parent = line->parent->parent;
4182
4183       node = line_ancestor_parent->children.node;
4184       while (node != line_ancestor &&
4185              line_ancestor != info->tag_root)
4186         {
4187           GSList *child_nodes = NULL;
4188           GSList *tmp;
4189
4190           /* Create reverse-order list of nodes before
4191            * line_ancestor
4192            */
4193           while (node != line_ancestor
4194                  && node != NULL)
4195             {
4196               child_nodes = g_slist_prepend (child_nodes, node);
4197
4198               node = node->next;
4199             }
4200
4201           /* Try to find a node with our tag on it in the list */
4202           tmp = child_nodes;
4203           while (tmp != NULL)
4204             {
4205               GtkTextBTreeNode *this_node = tmp->data;
4206
4207               g_assert (this_node != line_ancestor);
4208
4209               if (gtk_text_btree_node_has_tag (this_node, tag))
4210                 {
4211                   found_node = this_node;
4212                   g_slist_free (child_nodes);
4213                   goto found;
4214                 }
4215
4216               tmp = g_slist_next (tmp);
4217             }
4218
4219           g_slist_free (child_nodes);
4220
4221           /* Didn't find anything on this level; go up one level. */
4222           line_ancestor = line_ancestor_parent;
4223           line_ancestor_parent = line_ancestor->parent;
4224
4225           node = line_ancestor_parent->children.node;
4226         }
4227
4228       /* No dice. */
4229       return NULL;
4230     }
4231   else
4232     {
4233       gint ordering;
4234
4235       ordering = node_compare (line->parent, info->tag_root);
4236
4237       if (ordering < 0)
4238         {
4239           /* Tag root is ahead of us, so no more lines
4240            * with this tag.
4241            */
4242           return NULL;
4243         }
4244       else
4245         {
4246           /* Tag root is after us, so grab last tagged
4247            * line underneath the tag root.
4248            */
4249           found_node = info->tag_root;
4250           goto found;
4251         }
4252
4253       g_assert_not_reached ();
4254     }
4255
4256  found:
4257
4258   g_assert (found_node != NULL);
4259
4260   /* We have to find the last sub-node of this node that contains
4261    * the target tag.
4262    */
4263   node = found_node;
4264
4265   while (node->level > 0)
4266     {
4267       GSList *child_nodes = NULL;
4268       GSList *iter;
4269       g_assert (node != NULL); /* If this fails, it likely means an
4270                                   incorrect tag summary led us on a
4271                                   wild goose chase down this branch of
4272                                   the tree. */
4273
4274       node = node->children.node;
4275       while (node != NULL)
4276         {
4277           child_nodes = g_slist_prepend (child_nodes, node);
4278           node = node->next;
4279         }
4280
4281       node = NULL; /* detect failure to find a child node. */
4282
4283       iter = child_nodes;
4284       while (iter != NULL)
4285         {
4286           if (gtk_text_btree_node_has_tag (iter->data, tag))
4287             {
4288               /* recurse into this node. */
4289               node = iter->data;
4290               break;
4291             }
4292
4293           iter = g_slist_next (iter);
4294         }
4295
4296       g_slist_free (child_nodes);
4297
4298       g_assert (node != NULL);
4299     }
4300
4301   g_assert (node != NULL);
4302   g_assert (node->level == 0);
4303
4304   /* this assertion is correct, but slow. */
4305   /* g_assert (node_compare (node, line->parent) < 0); */
4306
4307   /* Return last line in this node. */
4308
4309   prev = node->children.line;
4310   while (prev->next)
4311     prev = prev->next;
4312
4313   return prev;
4314 }
4315
4316 /*
4317  * Non-public function implementations
4318  */
4319
4320 static void
4321 summary_list_destroy (Summary *summary)
4322 {
4323   Summary *next;
4324   while (summary != NULL)
4325     {
4326       next = summary->next;
4327       summary_destroy (summary);
4328       summary = next;
4329     }
4330 }
4331
4332 static GtkTextLine*
4333 get_last_line (GtkTextBTree *tree)
4334 {
4335   if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
4336     {
4337       gint n_lines;
4338       GtkTextLine *line;
4339       gint real_line;
4340
4341       n_lines = _gtk_text_btree_line_count (tree);
4342
4343       g_assert (n_lines >= 1); /* num_lines doesn't return bogus last line. */
4344
4345       line = _gtk_text_btree_get_line (tree, n_lines, &real_line);
4346
4347       tree->end_iter_line_stamp = tree->chars_changed_stamp;
4348       tree->end_iter_line = line;
4349     }
4350
4351   return tree->end_iter_line;
4352 }
4353
4354 /*
4355  * Lines
4356  */
4357
4358 static GtkTextLine*
4359 gtk_text_line_new (void)
4360 {
4361   GtkTextLine *line;
4362
4363   line = g_new0(GtkTextLine, 1);
4364
4365   return line;
4366 }
4367
4368 static void
4369 gtk_text_line_destroy (GtkTextBTree *tree, GtkTextLine *line)
4370 {
4371   GtkTextLineData *ld;
4372   GtkTextLineData *next;
4373
4374   g_return_if_fail (line != NULL);
4375
4376   ld = line->views;
4377   while (ld != NULL)
4378     {
4379       BTreeView *view;
4380
4381       view = gtk_text_btree_get_view (tree, ld->view_id);
4382
4383       g_assert (view != NULL);
4384
4385       next = ld->next;
4386       gtk_text_layout_free_line_data (view->layout, line, ld);
4387
4388       ld = next;
4389     }
4390
4391   g_free (line);
4392 }
4393
4394 static void
4395 gtk_text_line_set_parent (GtkTextLine *line,
4396                           GtkTextBTreeNode *node)
4397 {
4398   if (line->parent == node)
4399     return;
4400   line->parent = node;
4401   gtk_text_btree_node_invalidate_upward (node, NULL);
4402 }
4403
4404 static void
4405 cleanup_line (GtkTextLine *line)
4406 {
4407   GtkTextLineSegment *seg, **prev_p;
4408   gboolean changed;
4409
4410   /*
4411    * Make a pass over all of the segments in the line, giving each
4412    * a chance to clean itself up.  This could potentially change
4413    * the structure of the line, e.g. by merging two segments
4414    * together or having two segments cancel themselves;  if so,
4415    * then repeat the whole process again, since the first structure
4416    * change might make other structure changes possible.  Repeat
4417    * until eventually there are no changes.
4418    */
4419
4420   changed = TRUE;
4421   while (changed)
4422     {
4423       changed = FALSE;
4424       for (prev_p = &line->segments, seg = *prev_p;
4425            seg != NULL;
4426            prev_p = &(*prev_p)->next, seg = *prev_p)
4427         {
4428           if (seg->type->cleanupFunc != NULL)
4429             {
4430               *prev_p = (*seg->type->cleanupFunc)(seg, line);
4431               if (seg != *prev_p)
4432                 changed = TRUE;
4433             }
4434         }
4435     }
4436 }
4437
4438 /*
4439  * Nodes
4440  */
4441
4442 static NodeData*
4443 node_data_new (gpointer view_id)
4444 {
4445   NodeData *nd;
4446   
4447   nd = g_new (NodeData, 1);
4448
4449   nd->view_id = view_id;
4450   nd->next = NULL;
4451   nd->width = 0;
4452   nd->height = 0;
4453   nd->valid = FALSE;
4454
4455   return nd;
4456 }
4457
4458 static void
4459 node_data_destroy (NodeData *nd)
4460 {
4461   g_free (nd);
4462 }
4463
4464 static void
4465 node_data_list_destroy (NodeData *nd)
4466 {
4467   NodeData *iter;
4468   NodeData *next;
4469
4470   iter = nd;
4471   while (iter != NULL)
4472     {
4473       next = iter->next;
4474       node_data_destroy (iter);
4475       iter = next;
4476     }
4477 }
4478
4479 static NodeData*
4480 node_data_find (NodeData *nd, gpointer view_id)
4481 {
4482   while (nd != NULL)
4483     {
4484       if (nd->view_id == view_id)
4485         break;
4486       nd = nd->next;
4487     }
4488   return nd;
4489 }
4490
4491 static void
4492 summary_destroy (Summary *summary)
4493 {
4494   /* Fill with error-triggering garbage */
4495   summary->info = (void*)0x1;
4496   summary->toggle_count = 567;
4497   summary->next = (void*)0x1;
4498   g_free (summary);
4499 }
4500
4501 static GtkTextBTreeNode*
4502 gtk_text_btree_node_new (void)
4503 {
4504   GtkTextBTreeNode *node;
4505
4506   node = g_new (GtkTextBTreeNode, 1);
4507
4508   node->node_data = NULL;
4509
4510   return node;
4511 }
4512
4513 static void
4514 gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode  *node,
4515                                          GtkTextTagInfo  *info,
4516                                          gint adjust)
4517 {
4518   Summary *summary;
4519
4520   summary = node->summary;
4521   while (summary != NULL)
4522     {
4523       if (summary->info == info)
4524         {
4525           summary->toggle_count += adjust;
4526           break;
4527         }
4528
4529       summary = summary->next;
4530     }
4531
4532   if (summary == NULL)
4533     {
4534       /* didn't find a summary for our tag. */
4535       g_return_if_fail (adjust > 0);
4536       summary = g_new (Summary, 1);
4537       summary->info = info;
4538       summary->toggle_count = adjust;
4539       summary->next = node->summary;
4540       node->summary = summary;
4541     }
4542 }
4543
4544 /* Note that the tag root and above do not have summaries
4545    for the tag; only nodes below the tag root have
4546    the summaries. */
4547 static gboolean
4548 gtk_text_btree_node_has_tag (GtkTextBTreeNode *node, GtkTextTag *tag)
4549 {
4550   Summary *summary;
4551
4552   summary = node->summary;
4553   while (summary != NULL)
4554     {
4555       if (tag == NULL ||
4556           summary->info->tag == tag)
4557         return TRUE;
4558
4559       summary = summary->next;
4560     }
4561
4562   return FALSE;
4563 }
4564
4565 /* Add node and all children to the damage region. */
4566 static void
4567 gtk_text_btree_node_invalidate_downward (GtkTextBTreeNode *node)
4568 {
4569   NodeData *nd;
4570
4571   nd = node->node_data;
4572   while (nd != NULL)
4573     {
4574       nd->valid = FALSE;
4575       nd = nd->next;
4576     }
4577
4578   if (node->level == 0)
4579     {
4580       GtkTextLine *line;
4581
4582       line = node->children.line;
4583       while (line != NULL)
4584         {
4585           GtkTextLineData *ld;
4586
4587           ld = line->views;
4588           while (ld != NULL)
4589             {
4590               ld->valid = FALSE;
4591               ld = ld->next;
4592             }
4593
4594           line = line->next;
4595         }
4596     }
4597   else
4598     {
4599       GtkTextBTreeNode *child;
4600
4601       child = node->children.node;
4602
4603       while (child != NULL)
4604         {
4605           gtk_text_btree_node_invalidate_downward (child);
4606
4607           child = child->next;
4608         }
4609     }
4610 }
4611
4612 static void
4613 gtk_text_btree_node_invalidate_upward (GtkTextBTreeNode *node, gpointer view_id)
4614 {
4615   GtkTextBTreeNode *iter;
4616
4617   iter = node;
4618   while (iter != NULL)
4619     {
4620       NodeData *nd;
4621
4622       if (view_id)
4623         {
4624           nd = node_data_find (iter->node_data, view_id);
4625
4626           if (nd == NULL || !nd->valid)
4627             break; /* Once a node is invalid, we know its parents are as well. */
4628
4629           nd->valid = FALSE;
4630         }
4631       else
4632         {
4633           gboolean should_continue = FALSE;
4634
4635           nd = iter->node_data;
4636           while (nd != NULL)
4637             {
4638               if (nd->valid)
4639                 {
4640                   should_continue = TRUE;
4641                   nd->valid = FALSE;
4642                 }
4643
4644               nd = nd->next;
4645             }
4646
4647           if (!should_continue)
4648             break; /* This node was totally invalidated, so are its
4649                       parents */
4650         }
4651
4652       iter = iter->parent;
4653     }
4654 }
4655
4656
4657 /**
4658  * _gtk_text_btree_is_valid:
4659  * @tree: a #GtkTextBTree
4660  * @view_id: ID for the view
4661  *
4662  * Check to see if the entire #GtkTextBTree is valid or not for
4663  * the given view.
4664  *
4665  * Return value: %TRUE if the entire #GtkTextBTree is valid
4666  **/
4667 gboolean
4668 _gtk_text_btree_is_valid (GtkTextBTree *tree,
4669                          gpointer      view_id)
4670 {
4671   NodeData *nd;
4672   g_return_val_if_fail (tree != NULL, FALSE);
4673
4674   nd = node_data_find (tree->root_node->node_data, view_id);
4675   return (nd && nd->valid);
4676 }
4677
4678 typedef struct _ValidateState ValidateState;
4679
4680 struct _ValidateState
4681 {
4682   gint remaining_pixels;
4683   gboolean in_validation;
4684   gint y;
4685   gint old_height;
4686   gint new_height;
4687 };
4688
4689 static void
4690 gtk_text_btree_node_validate (BTreeView         *view,
4691                               GtkTextBTreeNode  *node,
4692                               gpointer           view_id,
4693                               ValidateState     *state)
4694 {
4695   gint node_valid = TRUE;
4696   gint node_width = 0;
4697   gint node_height = 0;
4698
4699   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
4700   g_return_if_fail (!nd->valid);
4701
4702   if (node->level == 0)
4703     {
4704       GtkTextLine *line = node->children.line;
4705       GtkTextLineData *ld;
4706
4707       /* Iterate over leading valid lines */
4708       while (line != NULL)
4709         {
4710           ld = _gtk_text_line_get_data (line, view_id);
4711
4712           if (!ld || !ld->valid)
4713             break;
4714           else if (state->in_validation)
4715             {
4716               state->in_validation = FALSE;
4717               return;
4718             }
4719           else
4720             {
4721               state->y += ld->height;
4722               node_width = MAX (ld->width, node_width);
4723               node_height += ld->height;
4724             }
4725
4726           line = line->next;
4727         }
4728
4729       state->in_validation = TRUE;
4730
4731       /* Iterate over invalid lines */
4732       while (line != NULL)
4733         {
4734           ld = _gtk_text_line_get_data (line, view_id);
4735
4736           if (ld && ld->valid)
4737             break;
4738           else
4739             {
4740               if (ld)
4741                 state->old_height += ld->height;
4742               ld = gtk_text_layout_wrap (view->layout, line, ld);
4743               state->new_height += ld->height;
4744
4745               node_width = MAX (ld->width, node_width);
4746               node_height += ld->height;
4747
4748               state->remaining_pixels -= ld->height;
4749               if (state->remaining_pixels <= 0)
4750                 {
4751                   line = line->next;
4752                   break;
4753                 }
4754             }
4755
4756           line = line->next;
4757         }
4758
4759       /* Iterate over the remaining lines */
4760       while (line != NULL)
4761         {
4762           ld = _gtk_text_line_get_data (line, view_id);
4763           state->in_validation = FALSE;
4764
4765           if (!ld || !ld->valid)
4766             node_valid = FALSE;
4767
4768           if (ld)
4769             {
4770               node_width = MAX (ld->width, node_width);
4771               node_height += ld->height;
4772             }
4773
4774           line = line->next;
4775         }
4776     }
4777   else
4778     {
4779       GtkTextBTreeNode *child;
4780       NodeData *child_nd;
4781
4782       child = node->children.node;
4783
4784       /* Iterate over leading valid nodes */
4785       while (child)
4786         {
4787           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4788
4789           if (!child_nd->valid)
4790             break;
4791           else if (state->in_validation)
4792             {
4793               state->in_validation = FALSE;
4794               return;
4795             }
4796           else
4797             {
4798               state->y += child_nd->height;
4799               node_width = MAX (node_width, child_nd->width);
4800               node_height += child_nd->height;
4801             }
4802
4803           child = child->next;
4804         }
4805
4806       /* Iterate over invalid nodes */
4807       while (child)
4808         {
4809           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4810
4811           if (child_nd->valid)
4812             break;
4813           else
4814             {
4815               gtk_text_btree_node_validate (view, child, view_id, state);
4816
4817               if (!child_nd->valid)
4818                 node_valid = FALSE;
4819               node_width = MAX (node_width, child_nd->width);
4820               node_height += child_nd->height;
4821
4822               if (!state->in_validation || state->remaining_pixels <= 0)
4823                 {
4824                   child = child->next;
4825                   break;
4826                 }
4827             }
4828
4829           child = child->next;
4830         }
4831
4832       /* Iterate over the remaining lines */
4833       while (child)
4834         {
4835           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4836           state->in_validation = FALSE;
4837
4838           if (!child_nd->valid)
4839             node_valid = FALSE;
4840
4841           node_width = MAX (child_nd->width, node_width);
4842           node_height += child_nd->height;
4843
4844           child = child->next;
4845         }
4846     }
4847
4848   nd->width = node_width;
4849   nd->height = node_height;
4850   nd->valid = node_valid;
4851 }
4852
4853 /**
4854  * _gtk_text_btree_validate:
4855  * @tree: a #GtkTextBTree
4856  * @view_id: view id
4857  * @max_pixels: the maximum number of pixels to validate. (No more
4858  *              than one paragraph beyond this limit will be validated)
4859  * @y: location to store starting y coordinate of validated region
4860  * @old_height: location to store old height of validated region
4861  * @new_height: location to store new height of validated region
4862  *
4863  * Validate a single contiguous invalid region of a #GtkTextBTree for
4864  * a given view.
4865  *
4866  * Return value: %TRUE if a region has been validated, %FALSE if the
4867  * entire tree was already valid.
4868  **/
4869 gboolean
4870 _gtk_text_btree_validate (GtkTextBTree *tree,
4871                          gpointer      view_id,
4872                          gint          max_pixels,
4873                          gint         *y,
4874                          gint         *old_height,
4875                          gint         *new_height)
4876 {
4877   BTreeView *view;
4878
4879   g_return_val_if_fail (tree != NULL, FALSE);
4880
4881   view = gtk_text_btree_get_view (tree, view_id);
4882   g_return_val_if_fail (view != NULL, FALSE);
4883
4884   if (!_gtk_text_btree_is_valid (tree, view_id))
4885     {
4886       ValidateState state;
4887
4888       state.remaining_pixels = max_pixels;
4889       state.in_validation = FALSE;
4890       state.y = 0;
4891       state.old_height = 0;
4892       state.new_height = 0;
4893
4894       gtk_text_btree_node_validate (view,
4895                                     tree->root_node,
4896                                     view_id, &state);
4897
4898       if (y)
4899         *y = state.y;
4900       if (old_height)
4901         *old_height = state.old_height;
4902       if (new_height)
4903         *new_height = state.new_height;
4904
4905       if (gtk_debug_flags & GTK_DEBUG_TEXT)
4906         _gtk_text_btree_check (tree);
4907
4908       return TRUE;
4909     }
4910   else
4911     return FALSE;
4912 }
4913
4914 static void
4915 gtk_text_btree_node_compute_view_aggregates (GtkTextBTreeNode *node,
4916                                              gpointer          view_id,
4917                                              gint             *width_out,
4918                                              gint             *height_out,
4919                                              gboolean         *valid_out)
4920 {
4921   gint width = 0;
4922   gint height = 0;
4923   gboolean valid = TRUE;
4924
4925   if (node->level == 0)
4926     {
4927       GtkTextLine *line = node->children.line;
4928
4929       while (line != NULL)
4930         {
4931           GtkTextLineData *ld = _gtk_text_line_get_data (line, view_id);
4932
4933           if (!ld || !ld->valid)
4934             valid = FALSE;
4935
4936           if (ld)
4937             {
4938               width = MAX (ld->width, width);
4939               height += ld->height;
4940             }
4941
4942           line = line->next;
4943         }
4944     }
4945   else
4946     {
4947       GtkTextBTreeNode *child = node->children.node;
4948
4949       while (child)
4950         {
4951           NodeData *child_nd = node_data_find (child->node_data, view_id);
4952
4953           if (!child_nd || !child_nd->valid)
4954             valid = FALSE;
4955
4956           if (child_nd)
4957             {
4958               width = MAX (child_nd->width, width);
4959               height += child_nd->height;
4960             }
4961
4962           child = child->next;
4963         }
4964     }
4965
4966   *width_out = width;
4967   *height_out = height;
4968   *valid_out = valid;
4969 }
4970
4971
4972 /* Recompute the validity and size of the view data for a given
4973  * view at this node from the immediate children of the node
4974  */
4975 static NodeData *
4976 gtk_text_btree_node_check_valid (GtkTextBTreeNode *node,
4977                                  gpointer          view_id)
4978 {
4979   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
4980   gboolean valid;
4981   gint width;
4982   gint height;
4983
4984   gtk_text_btree_node_compute_view_aggregates (node, view_id,
4985                                                &width, &height, &valid);
4986   nd->width = width;
4987   nd->height = height;
4988   nd->valid = valid;
4989
4990   return nd;
4991 }
4992
4993 static void
4994 gtk_text_btree_node_check_valid_upward (GtkTextBTreeNode *node,
4995                                         gpointer          view_id)
4996 {
4997   while (node)
4998     {
4999       gtk_text_btree_node_check_valid (node, view_id);
5000       node = node->parent;
5001     }
5002 }
5003
5004 static NodeData *
5005 gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
5006                                           gpointer          view_id)
5007 {
5008   if (node->level == 0)
5009     {
5010       return gtk_text_btree_node_check_valid (node, view_id);
5011     }
5012   else
5013     {
5014       GtkTextBTreeNode *child = node->children.node;
5015
5016       NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
5017
5018       nd->valid = TRUE;
5019       nd->width = 0;
5020       nd->height = 0;
5021
5022       while (child)
5023         {
5024           NodeData *child_nd = gtk_text_btree_node_check_valid_downward (child, view_id);
5025
5026           if (!child_nd->valid)
5027             nd->valid = FALSE;
5028           nd->width = MAX (child_nd->width, nd->width);
5029           nd->height += child_nd->height;
5030
5031           child = child->next;
5032         }
5033       return nd;
5034     }
5035 }
5036
5037
5038
5039 /**
5040  * _gtk_text_btree_validate_line:
5041  * @tree: a #GtkTextBTree
5042  * @line: line to validate
5043  * @view_id: view ID for the view to validate
5044  *
5045  * Revalidate a single line of the btree for the given view, propagate
5046  * results up through the entire tree.
5047  **/
5048 void
5049 _gtk_text_btree_validate_line (GtkTextBTree     *tree,
5050                                GtkTextLine      *line,
5051                                gpointer          view_id)
5052 {
5053   GtkTextLineData *ld;
5054   BTreeView *view;
5055
5056   g_return_if_fail (tree != NULL);
5057   g_return_if_fail (line != NULL);
5058
5059   view = gtk_text_btree_get_view (tree, view_id);
5060   g_return_if_fail (view != NULL);
5061   
5062   ld = _gtk_text_line_get_data (line, view_id);
5063   if (!ld || !ld->valid)
5064     {
5065       ld = gtk_text_layout_wrap (view->layout, line, ld);
5066       
5067       gtk_text_btree_node_check_valid_upward (line->parent, view_id);
5068     }
5069 }
5070
5071 static void
5072 gtk_text_btree_node_remove_view (BTreeView *view, GtkTextBTreeNode *node, gpointer view_id)
5073 {
5074   if (node->level == 0)
5075     {
5076       GtkTextLine *line;
5077
5078       line = node->children.line;
5079       while (line != NULL)
5080         {
5081           GtkTextLineData *ld;
5082
5083           ld = _gtk_text_line_remove_data (line, view_id);
5084
5085           if (ld)
5086             gtk_text_layout_free_line_data (view->layout, line, ld);
5087
5088           line = line->next;
5089         }
5090     }
5091   else
5092     {
5093       GtkTextBTreeNode *child;
5094
5095       child = node->children.node;
5096
5097       while (child != NULL)
5098         {
5099           /* recurse */
5100           gtk_text_btree_node_remove_view (view, child, view_id);
5101
5102           child = child->next;
5103         }
5104     }
5105
5106   gtk_text_btree_node_remove_data (node, view_id);
5107 }
5108
5109 static void
5110 gtk_text_btree_node_destroy (GtkTextBTree *tree, GtkTextBTreeNode *node)
5111 {
5112   if (node->level == 0)
5113     {
5114       GtkTextLine *line;
5115       GtkTextLineSegment *seg;
5116
5117       while (node->children.line != NULL)
5118         {
5119           line = node->children.line;
5120           node->children.line = line->next;
5121           while (line->segments != NULL)
5122             {
5123               seg = line->segments;
5124               line->segments = seg->next;
5125
5126               if (GTK_IS_TEXT_MARK_SEGMENT (seg))
5127                 {
5128                   /* Set the mark as deleted */
5129                   seg->body.mark.tree = NULL;
5130                   seg->body.mark.line = NULL;
5131                 }
5132
5133               (*seg->type->deleteFunc) (seg, line, 1);
5134             }
5135           gtk_text_line_destroy (tree, line);
5136         }
5137     }
5138   else
5139     {
5140       GtkTextBTreeNode *childPtr;
5141
5142       while (node->children.node != NULL)
5143         {
5144           childPtr = node->children.node;
5145           node->children.node = childPtr->next;
5146           gtk_text_btree_node_destroy (tree, childPtr);
5147         }
5148     }
5149
5150   gtk_text_btree_node_free_empty (tree, node);
5151 }
5152
5153 static void
5154 gtk_text_btree_node_free_empty (GtkTextBTree *tree,
5155                                 GtkTextBTreeNode *node)
5156 {
5157   g_return_if_fail ((node->level > 0 && node->children.node == NULL) ||
5158                     (node->level == 0 && node->children.line == NULL));
5159
5160   summary_list_destroy (node->summary);
5161   node_data_list_destroy (node->node_data);
5162   g_free (node);
5163 }
5164
5165 static NodeData*
5166 gtk_text_btree_node_ensure_data (GtkTextBTreeNode *node, gpointer view_id)
5167 {
5168   NodeData *nd;
5169
5170   nd = node->node_data;
5171   while (nd != NULL)
5172     {
5173       if (nd->view_id == view_id)
5174         break;
5175
5176       nd = nd->next;
5177     }
5178
5179   if (nd == NULL)
5180     {
5181       nd = node_data_new (view_id);
5182       
5183       if (node->node_data)
5184         nd->next = node->node_data;
5185       
5186       node->node_data = nd;
5187     }
5188
5189   return nd;
5190 }
5191
5192 static void
5193 gtk_text_btree_node_remove_data (GtkTextBTreeNode *node, gpointer view_id)
5194 {
5195   NodeData *nd;
5196   NodeData *prev;
5197
5198   prev = NULL;
5199   nd = node->node_data;
5200   while (nd != NULL)
5201     {
5202       if (nd->view_id == view_id)
5203         break;
5204
5205       prev = nd;
5206       nd = nd->next;
5207     }
5208
5209   if (nd == NULL)
5210     return;
5211
5212   if (prev != NULL)
5213     prev->next = nd->next;
5214
5215   if (node->node_data == nd)
5216     node->node_data = nd->next;
5217
5218   nd->next = NULL;
5219
5220   node_data_destroy (nd);
5221 }
5222
5223 static void
5224 gtk_text_btree_node_get_size (GtkTextBTreeNode *node, gpointer view_id,
5225                               gint *width, gint *height)
5226 {
5227   NodeData *nd;
5228
5229   g_return_if_fail (width != NULL);
5230   g_return_if_fail (height != NULL);
5231
5232   nd = gtk_text_btree_node_ensure_data (node, view_id);
5233
5234   if (width)
5235     *width = nd->width;
5236   if (height)
5237     *height = nd->height;
5238 }
5239
5240 /* Find the closest common ancestor of the two nodes. FIXME: The interface
5241  * here isn't quite right, since for a lot of operations we want to
5242  * know which children of the common parent correspond to the two nodes
5243  * (e.g., when computing the order of two iters)
5244  */
5245 static GtkTextBTreeNode *
5246 gtk_text_btree_node_common_parent (GtkTextBTreeNode *node1,
5247                                    GtkTextBTreeNode *node2)
5248 {
5249   while (node1->level < node2->level)
5250     node1 = node1->parent;
5251   while (node2->level < node1->level)
5252     node2 = node2->parent;
5253   while (node1 != node2)
5254     {
5255       node1 = node1->parent;
5256       node2 = node2->parent;
5257     }
5258
5259   return node1;
5260 }
5261
5262 /*
5263  * BTree
5264  */
5265
5266 static BTreeView*
5267 gtk_text_btree_get_view (GtkTextBTree *tree, gpointer view_id)
5268 {
5269   BTreeView *view;
5270
5271   view = tree->views;
5272   while (view != NULL)
5273     {
5274       if (view->view_id == view_id)
5275         break;
5276       view = view->next;
5277     }
5278
5279   return view;
5280 }
5281
5282 static void
5283 get_tree_bounds (GtkTextBTree *tree,
5284                  GtkTextIter *start,
5285                  GtkTextIter *end)
5286 {
5287   _gtk_text_btree_get_iter_at_line_char (tree, start, 0, 0);
5288   _gtk_text_btree_get_end_iter (tree, end);
5289 }
5290
5291 static void
5292 tag_changed_cb (GtkTextTagTable *table,
5293                 GtkTextTag      *tag,
5294                 gboolean         size_changed,
5295                 GtkTextBTree    *tree)
5296 {
5297   if (size_changed)
5298     {
5299       /* We need to queue a relayout on all regions that are tagged with
5300        * this tag.
5301        */
5302
5303       GtkTextIter start;
5304       GtkTextIter end;
5305
5306       if (_gtk_text_btree_get_iter_at_first_toggle (tree, &start, tag))
5307         {
5308           /* Must be a last toggle if there was a first one. */
5309           _gtk_text_btree_get_iter_at_last_toggle (tree, &end, tag);
5310           _gtk_text_btree_invalidate_region (tree,
5311                                             &start, &end);
5312
5313         }
5314     }
5315   else
5316     {
5317       /* We only need to queue a redraw, not a relayout */
5318       BTreeView *view;
5319
5320       view = tree->views;
5321
5322       while (view != NULL)
5323         {
5324           gint width, height;
5325
5326           _gtk_text_btree_get_view_size (tree, view->view_id, &width, &height);
5327           gtk_text_layout_changed (view->layout, 0, height, height);
5328
5329           view = view->next;
5330         }
5331     }
5332 }
5333
5334 static void
5335 tag_removed_cb (GtkTextTagTable *table,
5336                 GtkTextTag *tag,
5337                 GtkTextBTree *tree)
5338 {
5339   /* Remove the tag from the tree */
5340
5341   GtkTextIter start;
5342   GtkTextIter end;
5343
5344   get_tree_bounds (tree, &start, &end);
5345
5346   _gtk_text_btree_tag (&start, &end, tag, FALSE);
5347   gtk_text_btree_remove_tag_info (tree, tag);
5348 }
5349
5350
5351 /* Rebalance the out-of-whack node "node" */
5352 static void
5353 gtk_text_btree_rebalance (GtkTextBTree *tree,
5354                           GtkTextBTreeNode *node)
5355 {
5356   /*
5357    * Loop over the entire ancestral chain of the GtkTextBTreeNode, working
5358    * up through the tree one GtkTextBTreeNode at a time until the root
5359    * GtkTextBTreeNode has been processed.
5360    */
5361
5362   while (node != NULL)
5363     {
5364       GtkTextBTreeNode *new_node, *child;
5365       GtkTextLine *line;
5366       int i;
5367
5368       /*
5369        * Check to see if the GtkTextBTreeNode has too many children.  If it does,
5370        * then split off all but the first MIN_CHILDREN into a separate
5371        * GtkTextBTreeNode following the original one.  Then repeat until the
5372        * GtkTextBTreeNode has a decent size.
5373        */
5374
5375       if (node->num_children > MAX_CHILDREN)
5376         {
5377           while (1)
5378             {
5379               /*
5380                * If the GtkTextBTreeNode being split is the root
5381                * GtkTextBTreeNode, then make a new root GtkTextBTreeNode above
5382                * it first.
5383                */
5384
5385               if (node->parent == NULL)
5386                 {
5387                   new_node = gtk_text_btree_node_new ();
5388                   new_node->parent = NULL;
5389                   new_node->next = NULL;
5390                   new_node->summary = NULL;
5391                   new_node->level = node->level + 1;
5392                   new_node->children.node = node;
5393                   recompute_node_counts (tree, new_node);
5394                   tree->root_node = new_node;
5395                 }
5396               new_node = gtk_text_btree_node_new ();
5397               new_node->parent = node->parent;
5398               new_node->next = node->next;
5399               node->next = new_node;
5400               new_node->summary = NULL;
5401               new_node->level = node->level;
5402               new_node->num_children = node->num_children - MIN_CHILDREN;
5403               if (node->level == 0)
5404                 {
5405                   for (i = MIN_CHILDREN-1,
5406                          line = node->children.line;
5407                        i > 0; i--, line = line->next)
5408                     {
5409                       /* Empty loop body. */
5410                     }
5411                   new_node->children.line = line->next;
5412                   line->next = NULL;
5413                 }
5414               else
5415                 {
5416                   for (i = MIN_CHILDREN-1,
5417                          child = node->children.node;
5418                        i > 0; i--, child = child->next)
5419                     {
5420                       /* Empty loop body. */
5421                     }
5422                   new_node->children.node = child->next;
5423                   child->next = NULL;
5424                 }
5425               recompute_node_counts (tree, node);
5426               node->parent->num_children++;
5427               node = new_node;
5428               if (node->num_children <= MAX_CHILDREN)
5429                 {
5430                   recompute_node_counts (tree, node);
5431                   break;
5432                 }
5433             }
5434         }
5435
5436       while (node->num_children < MIN_CHILDREN)
5437         {
5438           GtkTextBTreeNode *other;
5439           GtkTextBTreeNode *halfwaynode = NULL; /* Initialization needed only */
5440           GtkTextLine *halfwayline = NULL; /* to prevent cc warnings. */
5441           int total_children, first_children, i;
5442
5443           /*
5444            * Too few children for this GtkTextBTreeNode.  If this is the root then,
5445            * it's OK for it to have less than MIN_CHILDREN children
5446            * as long as it's got at least two.  If it has only one
5447            * (and isn't at level 0), then chop the root GtkTextBTreeNode out of
5448            * the tree and use its child as the new root.
5449            */
5450
5451           if (node->parent == NULL)
5452             {
5453               if ((node->num_children == 1) && (node->level > 0))
5454                 {
5455                   tree->root_node = node->children.node;
5456                   tree->root_node->parent = NULL;
5457
5458                   node->children.node = NULL;
5459                   gtk_text_btree_node_free_empty (tree, node);
5460                 }
5461               return;
5462             }
5463
5464           /*
5465            * Not the root.  Make sure that there are siblings to
5466            * balance with.
5467            */
5468
5469           if (node->parent->num_children < 2)
5470             {
5471               gtk_text_btree_rebalance (tree, node->parent);
5472               continue;
5473             }
5474
5475           /*
5476            * Find a sibling neighbor to borrow from, and arrange for
5477            * node to be the earlier of the pair.
5478            */
5479
5480           if (node->next == NULL)
5481             {
5482               for (other = node->parent->children.node;
5483                    other->next != node;
5484                    other = other->next)
5485                 {
5486                   /* Empty loop body. */
5487                 }
5488               node = other;
5489             }
5490           other = node->next;
5491
5492           /*
5493            * We're going to either merge the two siblings together
5494            * into one GtkTextBTreeNode or redivide the children among them to
5495            * balance their loads.  As preparation, join their two
5496            * child lists into a single list and remember the half-way
5497            * point in the list.
5498            */
5499
5500           total_children = node->num_children + other->num_children;
5501           first_children = total_children/2;
5502           if (node->children.node == NULL)
5503             {
5504               node->children = other->children;
5505               other->children.node = NULL;
5506               other->children.line = NULL;
5507             }
5508           if (node->level == 0)
5509             {
5510               GtkTextLine *line;
5511
5512               for (line = node->children.line, i = 1;
5513                    line->next != NULL;
5514                    line = line->next, i++)
5515                 {
5516                   if (i == first_children)
5517                     {
5518                       halfwayline = line;
5519                     }
5520                 }
5521               line->next = other->children.line;
5522               while (i <= first_children)
5523                 {
5524                   halfwayline = line;
5525                   line = line->next;
5526                   i++;
5527                 }
5528             }
5529           else
5530             {
5531               GtkTextBTreeNode *child;
5532
5533               for (child = node->children.node, i = 1;
5534                    child->next != NULL;
5535                    child = child->next, i++)
5536                 {
5537                   if (i <= first_children)
5538                     {
5539                       if (i == first_children)
5540                         {
5541                           halfwaynode = child;
5542                         }
5543                     }
5544                 }
5545               child->next = other->children.node;
5546               while (i <= first_children)
5547                 {
5548                   halfwaynode = child;
5549                   child = child->next;
5550                   i++;
5551                 }
5552             }
5553
5554           /*
5555            * If the two siblings can simply be merged together, do it.
5556            */
5557
5558           if (total_children <= MAX_CHILDREN)
5559             {
5560               recompute_node_counts (tree, node);
5561               node->next = other->next;
5562               node->parent->num_children--;
5563
5564               other->children.node = NULL;
5565               other->children.line = NULL;
5566               gtk_text_btree_node_free_empty (tree, other);
5567               continue;
5568             }
5569
5570           /*
5571            * The siblings can't be merged, so just divide their
5572            * children evenly between them.
5573            */
5574
5575           if (node->level == 0)
5576             {
5577               other->children.line = halfwayline->next;
5578               halfwayline->next = NULL;
5579             }
5580           else
5581             {
5582               other->children.node = halfwaynode->next;
5583               halfwaynode->next = NULL;
5584             }
5585
5586           recompute_node_counts (tree, node);
5587           recompute_node_counts (tree, other);
5588         }
5589
5590       node = node->parent;
5591     }
5592 }
5593
5594 static void
5595 post_insert_fixup (GtkTextBTree *tree,
5596                    GtkTextLine *line,
5597                    gint line_count_delta,
5598                    gint char_count_delta)
5599
5600 {
5601   GtkTextBTreeNode *node;
5602
5603   /*
5604    * Increment the line counts in all the parent GtkTextBTreeNodes of the insertion
5605    * point, then rebalance the tree if necessary.
5606    */
5607
5608   for (node = line->parent ; node != NULL;
5609        node = node->parent)
5610     {
5611       node->num_lines += line_count_delta;
5612       node->num_chars += char_count_delta;
5613     }
5614   node = line->parent;
5615   node->num_children += line_count_delta;
5616
5617   if (node->num_children > MAX_CHILDREN)
5618     {
5619       gtk_text_btree_rebalance (tree, node);
5620     }
5621
5622   if (gtk_debug_flags & GTK_DEBUG_TEXT)
5623     _gtk_text_btree_check (tree);
5624 }
5625
5626 static GtkTextTagInfo*
5627 gtk_text_btree_get_existing_tag_info (GtkTextBTree *tree,
5628                                       GtkTextTag   *tag)
5629 {
5630   GtkTextTagInfo *info;
5631   GSList *list;
5632
5633
5634   list = tree->tag_infos;
5635   while (list != NULL)
5636     {
5637       info = list->data;
5638       if (info->tag == tag)
5639         return info;
5640
5641       list = g_slist_next (list);
5642     }
5643
5644   return NULL;
5645 }
5646
5647 static GtkTextTagInfo*
5648 gtk_text_btree_get_tag_info (GtkTextBTree *tree,
5649                              GtkTextTag   *tag)
5650 {
5651   GtkTextTagInfo *info;
5652
5653   info = gtk_text_btree_get_existing_tag_info (tree, tag);
5654
5655   if (info == NULL)
5656     {
5657       /* didn't find it, create. */
5658
5659       info = g_new (GtkTextTagInfo, 1);
5660
5661       info->tag = tag;
5662       g_object_ref (G_OBJECT (tag));
5663       info->tag_root = NULL;
5664       info->toggle_count = 0;
5665
5666       tree->tag_infos = g_slist_prepend (tree->tag_infos, info);
5667     }
5668
5669   return info;
5670 }
5671
5672 static void
5673 gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
5674                                 GtkTextTag   *tag)
5675 {
5676   GtkTextTagInfo *info;
5677   GSList *list;
5678   GSList *prev;
5679
5680   prev = NULL;
5681   list = tree->tag_infos;
5682   while (list != NULL)
5683     {
5684       info = list->data;
5685       if (info->tag == tag)
5686         {
5687           if (prev != NULL)
5688             {
5689               prev->next = list->next;
5690             }
5691           else
5692             {
5693               tree->tag_infos = list->next;
5694             }
5695           list->next = NULL;
5696           g_slist_free (list);
5697
5698           g_object_unref (G_OBJECT (info->tag));
5699
5700           g_free (info);
5701           return;
5702         }
5703
5704       list = g_slist_next (list);
5705     }
5706
5707   g_assert_not_reached ();
5708   return;
5709 }
5710
5711 static void
5712 recompute_level_zero_counts (GtkTextBTreeNode *node)
5713 {
5714   GtkTextLine *line;
5715   GtkTextLineSegment *seg;
5716
5717   g_assert (node->level == 0);
5718
5719   line = node->children.line;
5720   while (line != NULL)
5721     {
5722       node->num_children++;
5723       node->num_lines++;
5724
5725       if (line->parent != node)
5726         gtk_text_line_set_parent (line, node);
5727
5728       seg = line->segments;
5729       while (seg != NULL)
5730         {
5731
5732           node->num_chars += seg->char_count;
5733
5734           if (((seg->type != &gtk_text_toggle_on_type)
5735                && (seg->type != &gtk_text_toggle_off_type))
5736               || !(seg->body.toggle.inNodeCounts))
5737             {
5738               ; /* nothing */
5739             }
5740           else
5741             {
5742               GtkTextTagInfo *info;
5743
5744               info = seg->body.toggle.info;
5745
5746               gtk_text_btree_node_adjust_toggle_count (node, info, 1);
5747             }
5748
5749           seg = seg->next;
5750         }
5751
5752       line = line->next;
5753     }
5754 }
5755
5756 static void
5757 recompute_level_nonzero_counts (GtkTextBTreeNode *node)
5758 {
5759   Summary *summary;
5760   GtkTextBTreeNode *child;
5761
5762   g_assert (node->level > 0);
5763
5764   child = node->children.node;
5765   while (child != NULL)
5766     {
5767       node->num_children += 1;
5768       node->num_lines += child->num_lines;
5769       node->num_chars += child->num_chars;
5770
5771       if (child->parent != node)
5772         {
5773           child->parent = node;
5774           gtk_text_btree_node_invalidate_upward (node, NULL);
5775         }
5776
5777       summary = child->summary;
5778       while (summary != NULL)
5779         {
5780           gtk_text_btree_node_adjust_toggle_count (node,
5781                                                    summary->info,
5782                                                    summary->toggle_count);
5783
5784           summary = summary->next;
5785         }
5786
5787       child = child->next;
5788     }
5789 }
5790
5791 /*
5792  *----------------------------------------------------------------------
5793  *
5794  * recompute_node_counts --
5795  *
5796  *      This procedure is called to recompute all the counts in a GtkTextBTreeNode
5797  *      (tags, child information, etc.) by scanning the information in
5798  *      its descendants.  This procedure is called during rebalancing
5799  *      when a GtkTextBTreeNode's child structure has changed.
5800  *
5801  * Results:
5802  *      None.
5803  *
5804  * Side effects:
5805  *      The tag counts for node are modified to reflect its current
5806  *      child structure, as are its num_children, num_lines, num_chars fields.
5807  *      Also, all of the childrens' parent fields are made to point
5808  *      to node.
5809  *
5810  *----------------------------------------------------------------------
5811  */
5812
5813 static void
5814 recompute_node_counts (GtkTextBTree *tree, GtkTextBTreeNode *node)
5815 {
5816   BTreeView *view;
5817   Summary *summary, *summary2;
5818
5819   /*
5820    * Zero out all the existing counts for the GtkTextBTreeNode, but don't delete
5821    * the existing Summary records (most of them will probably be reused).
5822    */
5823
5824   summary = node->summary;
5825   while (summary != NULL)
5826     {
5827       summary->toggle_count = 0;
5828       summary = summary->next;
5829     }
5830
5831   node->num_children = 0;
5832   node->num_lines = 0;
5833   node->num_chars = 0;
5834
5835   /*
5836    * Scan through the children, adding the childrens' tag counts into
5837    * the GtkTextBTreeNode's tag counts and adding new Summary structures if
5838    * necessary.
5839    */
5840
5841   if (node->level == 0)
5842     recompute_level_zero_counts (node);
5843   else
5844     recompute_level_nonzero_counts (node);
5845
5846   view = tree->views;
5847   while (view)
5848     {
5849       gtk_text_btree_node_check_valid (node, view->view_id);
5850       view = view->next;
5851     }
5852   
5853   /*
5854    * Scan through the GtkTextBTreeNode's tag records again and delete any Summary
5855    * records that still have a zero count, or that have all the toggles.
5856    * The GtkTextBTreeNode with the children that account for all the tags toggles
5857    * have no summary information, and they become the tag_root for the tag.
5858    */
5859
5860   summary2 = NULL;
5861   for (summary = node->summary; summary != NULL; )
5862     {
5863       if (summary->toggle_count > 0 &&
5864           summary->toggle_count < summary->info->toggle_count)
5865         {
5866           if (node->level == summary->info->tag_root->level)
5867             {
5868               /*
5869                * The tag's root GtkTextBTreeNode split and some toggles left.
5870                * The tag root must move up a level.
5871                */
5872               summary->info->tag_root = node->parent;
5873             }
5874           summary2 = summary;
5875           summary = summary->next;
5876           continue;
5877         }
5878       if (summary->toggle_count == summary->info->toggle_count)
5879         {
5880           /*
5881            * A GtkTextBTreeNode merge has collected all the toggles under
5882            * one GtkTextBTreeNode.  Push the root down to this level.
5883            */
5884           summary->info->tag_root = node;
5885         }
5886       if (summary2 != NULL)
5887         {
5888           summary2->next = summary->next;
5889           summary_destroy (summary);
5890           summary = summary2->next;
5891         }
5892       else
5893         {
5894           node->summary = summary->next;
5895           summary_destroy (summary);
5896           summary = node->summary;
5897         }
5898     }
5899 }
5900
5901 void
5902 _gtk_change_node_toggle_count (GtkTextBTreeNode *node,
5903                                GtkTextTagInfo   *info,
5904                                gint              delta) /* may be negative */
5905 {
5906   Summary *summary, *prevPtr;
5907   GtkTextBTreeNode *node2Ptr;
5908   int rootLevel;                        /* Level of original tag root */
5909
5910   info->toggle_count += delta;
5911
5912   if (info->tag_root == (GtkTextBTreeNode *) NULL)
5913     {
5914       info->tag_root = node;
5915       return;
5916     }
5917
5918   /*
5919    * Note the level of the existing root for the tag so we can detect
5920    * if it needs to be moved because of the toggle count change.
5921    */
5922
5923   rootLevel = info->tag_root->level;
5924
5925   /*
5926    * Iterate over the GtkTextBTreeNode and its ancestors up to the tag root, adjusting
5927    * summary counts at each GtkTextBTreeNode and moving the tag's root upwards if
5928    * necessary.
5929    */
5930
5931   for ( ; node != info->tag_root; node = node->parent)
5932     {
5933       /*
5934        * See if there's already an entry for this tag for this GtkTextBTreeNode.  If so,
5935        * perhaps all we have to do is adjust its count.
5936        */
5937
5938       for (prevPtr = NULL, summary = node->summary;
5939            summary != NULL;
5940            prevPtr = summary, summary = summary->next)
5941         {
5942           if (summary->info == info)
5943             {
5944               break;
5945             }
5946         }
5947       if (summary != NULL)
5948         {
5949           summary->toggle_count += delta;
5950           if (summary->toggle_count > 0 &&
5951               summary->toggle_count < info->toggle_count)
5952             {
5953               continue;
5954             }
5955           if (summary->toggle_count != 0)
5956             {
5957               /*
5958                * Should never find a GtkTextBTreeNode with max toggle count at this
5959                * point (there shouldn't have been a summary entry in the
5960                * first place).
5961                */
5962
5963               g_error ("%s: bad toggle count (%d) max (%d)",
5964                        G_STRLOC, summary->toggle_count, info->toggle_count);
5965             }
5966
5967           /*
5968            * Zero toggle count;  must remove this tag from the list.
5969            */
5970
5971           if (prevPtr == NULL)
5972             {
5973               node->summary = summary->next;
5974             }
5975           else
5976             {
5977               prevPtr->next = summary->next;
5978             }
5979           summary_destroy (summary);
5980         }
5981       else
5982         {
5983           /*
5984            * This tag isn't currently in the summary information list.
5985            */
5986
5987           if (rootLevel == node->level)
5988             {
5989
5990               /*
5991                * The old tag root is at the same level in the tree as this
5992                * GtkTextBTreeNode, but it isn't at this GtkTextBTreeNode.  Move the tag root up
5993                * a level, in the hopes that it will now cover this GtkTextBTreeNode
5994                * as well as the old root (if not, we'll move it up again
5995                * the next time through the loop).  To push it up one level
5996                * we copy the original toggle count into the summary
5997                * information at the old root and change the root to its
5998                * parent GtkTextBTreeNode.
5999                */
6000
6001               GtkTextBTreeNode *rootnode = info->tag_root;
6002               summary = (Summary *) g_malloc (sizeof (Summary));
6003               summary->info = info;
6004               summary->toggle_count = info->toggle_count - delta;
6005               summary->next = rootnode->summary;
6006               rootnode->summary = summary;
6007               rootnode = rootnode->parent;
6008               rootLevel = rootnode->level;
6009               info->tag_root = rootnode;
6010             }
6011           summary = (Summary *) g_malloc (sizeof (Summary));
6012           summary->info = info;
6013           summary->toggle_count = delta;
6014           summary->next = node->summary;
6015           node->summary = summary;
6016         }
6017     }
6018
6019   /*
6020    * If we've decremented the toggle count, then it may be necessary
6021    * to push the tag root down one or more levels.
6022    */
6023
6024   if (delta >= 0)
6025     {
6026       return;
6027     }
6028   if (info->toggle_count == 0)
6029     {
6030       info->tag_root = (GtkTextBTreeNode *) NULL;
6031       return;
6032     }
6033   node = info->tag_root;
6034   while (node->level > 0)
6035     {
6036       /*
6037        * See if a single child GtkTextBTreeNode accounts for all of the tag's
6038        * toggles.  If so, push the root down one level.
6039        */
6040
6041       for (node2Ptr = node->children.node;
6042            node2Ptr != (GtkTextBTreeNode *)NULL ;
6043            node2Ptr = node2Ptr->next)
6044         {
6045           for (prevPtr = NULL, summary = node2Ptr->summary;
6046                summary != NULL;
6047                prevPtr = summary, summary = summary->next)
6048             {
6049               if (summary->info == info)
6050                 {
6051                   break;
6052                 }
6053             }
6054           if (summary == NULL)
6055             {
6056               continue;
6057             }
6058           if (summary->toggle_count != info->toggle_count)
6059             {
6060               /*
6061                * No GtkTextBTreeNode has all toggles, so the root is still valid.
6062                */
6063
6064               return;
6065             }
6066
6067           /*
6068            * This GtkTextBTreeNode has all the toggles, so push down the root.
6069            */
6070
6071           if (prevPtr == NULL)
6072             {
6073               node2Ptr->summary = summary->next;
6074             }
6075           else
6076             {
6077               prevPtr->next = summary->next;
6078             }
6079           summary_destroy (summary);
6080           info->tag_root = node2Ptr;
6081           break;
6082         }
6083       node = info->tag_root;
6084     }
6085 }
6086
6087 /*
6088  *----------------------------------------------------------------------
6089  *
6090  * inc_count --
6091  *
6092  *      This is a utility procedure used by _gtk_text_btree_get_tags.  It
6093  *      increments the count for a particular tag, adding a new
6094  *      entry for that tag if there wasn't one previously.
6095  *
6096  * Results:
6097  *      None.
6098  *
6099  * Side effects:
6100  *      The information at *tagInfoPtr may be modified, and the arrays
6101  *      may be reallocated to make them larger.
6102  *
6103  *----------------------------------------------------------------------
6104  */
6105
6106 static void
6107 inc_count (GtkTextTag *tag, int inc, TagInfo *tagInfoPtr)
6108 {
6109   GtkTextTag **tag_p;
6110   int count;
6111
6112   for (tag_p = tagInfoPtr->tags, count = tagInfoPtr->numTags;
6113        count > 0; tag_p++, count--)
6114     {
6115       if (*tag_p == tag)
6116         {
6117           tagInfoPtr->counts[tagInfoPtr->numTags-count] += inc;
6118           return;
6119         }
6120     }
6121
6122   /*
6123    * There isn't currently an entry for this tag, so we have to
6124    * make a new one.  If the arrays are full, then enlarge the
6125    * arrays first.
6126    */
6127
6128   if (tagInfoPtr->numTags == tagInfoPtr->arraySize)
6129     {
6130       GtkTextTag **newTags;
6131       int *newCounts, newSize;
6132
6133       newSize = 2*tagInfoPtr->arraySize;
6134       newTags = (GtkTextTag **) g_malloc ((unsigned)
6135                                           (newSize*sizeof (GtkTextTag *)));
6136       memcpy ((void *) newTags, (void *) tagInfoPtr->tags,
6137               tagInfoPtr->arraySize  *sizeof (GtkTextTag *));
6138       g_free ((char *) tagInfoPtr->tags);
6139       tagInfoPtr->tags = newTags;
6140       newCounts = (int *) g_malloc ((unsigned) (newSize*sizeof (int)));
6141       memcpy ((void *) newCounts, (void *) tagInfoPtr->counts,
6142               tagInfoPtr->arraySize  *sizeof (int));
6143       g_free ((char *) tagInfoPtr->counts);
6144       tagInfoPtr->counts = newCounts;
6145       tagInfoPtr->arraySize = newSize;
6146     }
6147
6148   tagInfoPtr->tags[tagInfoPtr->numTags] = tag;
6149   tagInfoPtr->counts[tagInfoPtr->numTags] = inc;
6150   tagInfoPtr->numTags++;
6151 }
6152
6153 static void
6154 gtk_text_btree_link_segment (GtkTextLineSegment *seg,
6155                              const GtkTextIter *iter)
6156 {
6157   GtkTextLineSegment *prev;
6158   GtkTextLine *line;
6159   GtkTextBTree *tree;
6160
6161   line = _gtk_text_iter_get_text_line (iter);
6162   tree = _gtk_text_iter_get_btree (iter);
6163
6164   prev = gtk_text_line_segment_split (iter);
6165   if (prev == NULL)
6166     {
6167       seg->next = line->segments;
6168       line->segments = seg;
6169     }
6170   else
6171     {
6172       seg->next = prev->next;
6173       prev->next = seg;
6174     }
6175   cleanup_line (line);
6176   segments_changed (tree);
6177
6178   if (gtk_debug_flags & GTK_DEBUG_TEXT)
6179     _gtk_text_btree_check (tree);
6180 }
6181
6182 static void
6183 gtk_text_btree_unlink_segment (GtkTextBTree *tree,
6184                                GtkTextLineSegment *seg,
6185                                GtkTextLine *line)
6186 {
6187   GtkTextLineSegment *prev;
6188
6189   if (line->segments == seg)
6190     {
6191       line->segments = seg->next;
6192     }
6193   else
6194     {
6195       for (prev = line->segments; prev->next != seg;
6196            prev = prev->next)
6197         {
6198           /* Empty loop body. */
6199         }
6200       prev->next = seg->next;
6201     }
6202   cleanup_line (line);
6203   segments_changed (tree);
6204 }
6205
6206 /*
6207  * This is here because it requires BTree internals, it logically
6208  * belongs in gtktextsegment.c
6209  */
6210
6211
6212 /*
6213  *--------------------------------------------------------------
6214  *
6215  * _gtk_toggle_segment_check_func --
6216  *
6217  *      This procedure is invoked to perform consistency checks
6218  *      on toggle segments.
6219  *
6220  * Results:
6221  *      None.
6222  *
6223  * Side effects:
6224  *      If a consistency problem is found the procedure g_errors.
6225  *
6226  *--------------------------------------------------------------
6227  */
6228
6229 void
6230 _gtk_toggle_segment_check_func (GtkTextLineSegment *segPtr,
6231                                 GtkTextLine *line)
6232 {
6233   Summary *summary;
6234   int needSummary;
6235
6236   if (segPtr->byte_count != 0)
6237     {
6238       g_error ("toggle_segment_check_func: segment had non-zero size");
6239     }
6240   if (!segPtr->body.toggle.inNodeCounts)
6241     {
6242       g_error ("toggle_segment_check_func: toggle counts not updated in GtkTextBTreeNodes");
6243     }
6244   needSummary = (segPtr->body.toggle.info->tag_root != line->parent);
6245   for (summary = line->parent->summary; ;
6246        summary = summary->next)
6247     {
6248       if (summary == NULL)
6249         {
6250           if (needSummary)
6251             {
6252               g_error ("toggle_segment_check_func: tag not present in GtkTextBTreeNode");
6253             }
6254           else
6255             {
6256               break;
6257             }
6258         }
6259       if (summary->info == segPtr->body.toggle.info)
6260         {
6261           if (!needSummary)
6262             {
6263               g_error ("toggle_segment_check_func: tag present in root GtkTextBTreeNode summary");
6264             }
6265           break;
6266         }
6267     }
6268 }
6269
6270 /*
6271  * Debug
6272  */
6273
6274 static void
6275 gtk_text_btree_node_view_check_consistency (GtkTextBTree     *tree,
6276                                             GtkTextBTreeNode *node,
6277                                             NodeData         *nd)
6278 {
6279   gint width;
6280   gint height;
6281   gboolean valid;
6282   BTreeView *view;
6283   
6284   view = tree->views;
6285
6286   while (view != NULL)
6287     {
6288       if (view->view_id == nd->view_id)
6289         break;
6290
6291       view = view->next;
6292     }
6293
6294   if (view == NULL)
6295     g_error ("Node has data for a view %p no longer attached to the tree",
6296              nd->view_id);
6297   
6298   gtk_text_btree_node_compute_view_aggregates (node, nd->view_id,
6299                                                &width, &height, &valid);
6300   if (nd->width != width ||
6301       nd->height != height ||
6302       !nd->valid != !valid)
6303     {
6304       g_error ("Node aggregates for view %p are invalid:\n"
6305                "Are (%d,%d,%s), should be (%d,%d,%s)",
6306                nd->view_id,
6307                nd->width, nd->height, nd->valid ? "TRUE" : "FALSE",
6308                width, height, valid ? "TRUE" : "FALSE");
6309     }
6310 }
6311
6312 static void
6313 gtk_text_btree_node_check_consistency (GtkTextBTree     *tree,
6314                                        GtkTextBTreeNode *node)
6315 {
6316   GtkTextBTreeNode *childnode;
6317   Summary *summary, *summary2;
6318   GtkTextLine *line;
6319   GtkTextLineSegment *segPtr;
6320   int num_children, num_lines, num_chars, toggle_count, min_children;
6321   GtkTextLineData *ld;
6322   NodeData *nd;
6323
6324   if (node->parent != NULL)
6325     {
6326       min_children = MIN_CHILDREN;
6327     }
6328   else if (node->level > 0)
6329     {
6330       min_children = 2;
6331     }
6332   else  {
6333     min_children = 1;
6334   }
6335   if ((node->num_children < min_children)
6336       || (node->num_children > MAX_CHILDREN))
6337     {
6338       g_error ("gtk_text_btree_node_check_consistency: bad child count (%d)",
6339                node->num_children);
6340     }
6341
6342   nd = node->node_data;
6343   while (nd != NULL)
6344     {
6345       gtk_text_btree_node_view_check_consistency (tree, node, nd);
6346       nd = nd->next;
6347     }
6348
6349   num_children = 0;
6350   num_lines = 0;
6351   num_chars = 0;
6352   if (node->level == 0)
6353     {
6354       for (line = node->children.line; line != NULL;
6355            line = line->next)
6356         {
6357           if (line->parent != node)
6358             {
6359               g_error ("gtk_text_btree_node_check_consistency: line doesn't point to parent");
6360             }
6361           if (line->segments == NULL)
6362             {
6363               g_error ("gtk_text_btree_node_check_consistency: line has no segments");
6364             }
6365
6366           ld = line->views;
6367           while (ld != NULL)
6368             {
6369               /* Just ensuring we don't segv while doing this loop */
6370
6371               ld = ld->next;
6372             }
6373
6374           for (segPtr = line->segments; segPtr != NULL; segPtr = segPtr->next)
6375             {
6376               if (segPtr->type->checkFunc != NULL)
6377                 {
6378                   (*segPtr->type->checkFunc)(segPtr, line);
6379                 }
6380               if ((segPtr->byte_count == 0) && (!segPtr->type->leftGravity)
6381                   && (segPtr->next != NULL)
6382                   && (segPtr->next->byte_count == 0)
6383                   && (segPtr->next->type->leftGravity))
6384                 {
6385                   g_error ("gtk_text_btree_node_check_consistency: wrong segment order for gravity");
6386                 }
6387               if ((segPtr->next == NULL)
6388                   && (segPtr->type != &gtk_text_char_type))
6389                 {
6390                   g_error ("gtk_text_btree_node_check_consistency: line ended with wrong type");
6391                 }
6392
6393               num_chars += segPtr->char_count;
6394             }
6395
6396           num_children++;
6397           num_lines++;
6398         }
6399     }
6400   else
6401     {
6402       for (childnode = node->children.node; childnode != NULL;
6403            childnode = childnode->next)
6404         {
6405           if (childnode->parent != node)
6406             {
6407               g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode doesn't point to parent");
6408             }
6409           if (childnode->level != (node->level-1))
6410             {
6411               g_error ("gtk_text_btree_node_check_consistency: level mismatch (%d %d)",
6412                        node->level, childnode->level);
6413             }
6414           gtk_text_btree_node_check_consistency (tree, childnode);
6415           for (summary = childnode->summary; summary != NULL;
6416                summary = summary->next)
6417             {
6418               for (summary2 = node->summary; ;
6419                    summary2 = summary2->next)
6420                 {
6421                   if (summary2 == NULL)
6422                     {
6423                       if (summary->info->tag_root == node)
6424                         {
6425                           break;
6426                         }
6427                       g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode tag \"%s\" not %s",
6428                                summary->info->tag->name,
6429                                "present in parent summaries");
6430                     }
6431                   if (summary->info == summary2->info)
6432                     {
6433                       break;
6434                     }
6435                 }
6436             }
6437           num_children++;
6438           num_lines += childnode->num_lines;
6439           num_chars += childnode->num_chars;
6440         }
6441     }
6442   if (num_children != node->num_children)
6443     {
6444       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_children (%d %d)",
6445                num_children, node->num_children);
6446     }
6447   if (num_lines != node->num_lines)
6448     {
6449       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_lines (%d %d)",
6450                num_lines, node->num_lines);
6451     }
6452   if (num_chars != node->num_chars)
6453     {
6454       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_chars (%d %d)",
6455                num_chars, node->num_chars);
6456     }
6457
6458   for (summary = node->summary; summary != NULL;
6459        summary = summary->next)
6460     {
6461       if (summary->info->toggle_count == summary->toggle_count)
6462         {
6463           g_error ("gtk_text_btree_node_check_consistency: found unpruned root for \"%s\"",
6464                    summary->info->tag->name);
6465         }
6466       toggle_count = 0;
6467       if (node->level == 0)
6468         {
6469           for (line = node->children.line; line != NULL;
6470                line = line->next)
6471             {
6472               for (segPtr = line->segments; segPtr != NULL;
6473                    segPtr = segPtr->next)
6474                 {
6475                   if ((segPtr->type != &gtk_text_toggle_on_type)
6476                       && (segPtr->type != &gtk_text_toggle_off_type))
6477                     {
6478                       continue;
6479                     }
6480                   if (segPtr->body.toggle.info == summary->info)
6481                     {
6482                       if (!segPtr->body.toggle.inNodeCounts)
6483                         g_error ("Toggle segment not in the node counts");
6484
6485                       toggle_count ++;
6486                     }
6487                 }
6488             }
6489         }
6490       else
6491         {
6492           for (childnode = node->children.node;
6493                childnode != NULL;
6494                childnode = childnode->next)
6495             {
6496               for (summary2 = childnode->summary;
6497                    summary2 != NULL;
6498                    summary2 = summary2->next)
6499                 {
6500                   if (summary2->info == summary->info)
6501                     {
6502                       toggle_count += summary2->toggle_count;
6503                     }
6504                 }
6505             }
6506         }
6507       if (toggle_count != summary->toggle_count)
6508         {
6509           g_error ("gtk_text_btree_node_check_consistency: mismatch in toggle_count (%d %d)",
6510                    toggle_count, summary->toggle_count);
6511         }
6512       for (summary2 = summary->next; summary2 != NULL;
6513            summary2 = summary2->next)
6514         {
6515           if (summary2->info == summary->info)
6516             {
6517               g_error ("gtk_text_btree_node_check_consistency: duplicated GtkTextBTreeNode tag: %s",
6518                        summary->info->tag->name);
6519             }
6520         }
6521     }
6522 }
6523
6524 static void
6525 listify_foreach (GtkTextTag *tag, gpointer user_data)
6526 {
6527   GSList** listp = user_data;
6528
6529   *listp = g_slist_prepend (*listp, tag);
6530 }
6531
6532 static GSList*
6533 list_of_tags (GtkTextTagTable *table)
6534 {
6535   GSList *list = NULL;
6536
6537   gtk_text_tag_table_foreach (table, listify_foreach, &list);
6538
6539   return list;
6540 }
6541
6542 void
6543 _gtk_text_btree_check (GtkTextBTree *tree)
6544 {
6545   Summary *summary;
6546   GtkTextBTreeNode *node;
6547   GtkTextLine *line;
6548   GtkTextLineSegment *seg;
6549   GtkTextTag *tag;
6550   GSList *taglist = NULL;
6551   int count;
6552   GtkTextTagInfo *info;
6553
6554   /*
6555    * Make sure that the tag toggle counts and the tag root pointers are OK.
6556    */
6557   for (taglist = list_of_tags (tree->table);
6558        taglist != NULL ; taglist = taglist->next)
6559     {
6560       tag = taglist->data;
6561       info = gtk_text_btree_get_existing_tag_info (tree, tag);
6562       if (info != NULL)
6563         {
6564           node = info->tag_root;
6565           if (node == NULL)
6566             {
6567               if (info->toggle_count != 0)
6568                 {
6569                   g_error ("_gtk_text_btree_check found \"%s\" with toggles (%d) but no root",
6570                            tag->name, info->toggle_count);
6571                 }
6572               continue;         /* no ranges for the tag */
6573             }
6574           else if (info->toggle_count == 0)
6575             {
6576               g_error ("_gtk_text_btree_check found root for \"%s\" with no toggles",
6577                        tag->name);
6578             }
6579           else if (info->toggle_count & 1)
6580             {
6581               g_error ("_gtk_text_btree_check found odd toggle count for \"%s\" (%d)",
6582                        tag->name, info->toggle_count);
6583             }
6584           for (summary = node->summary; summary != NULL;
6585                summary = summary->next)
6586             {
6587               if (summary->info->tag == tag)
6588                 {
6589                   g_error ("_gtk_text_btree_check found root GtkTextBTreeNode with summary info");
6590                 }
6591             }
6592           count = 0;
6593           if (node->level > 0)
6594             {
6595               for (node = node->children.node ; node != NULL ;
6596                    node = node->next)
6597                 {
6598                   for (summary = node->summary; summary != NULL;
6599                        summary = summary->next)
6600                     {
6601                       if (summary->info->tag == tag)
6602                         {
6603                           count += summary->toggle_count;
6604                         }
6605                     }
6606                 }
6607             }
6608           else
6609             {
6610               GtkTextLineSegmentClass * last = NULL;
6611
6612               for (line = node->children.line ; line != NULL ;
6613                    line = line->next)
6614                 {
6615                   for (seg = line->segments; seg != NULL;
6616                        seg = seg->next)
6617                     {
6618                       if ((seg->type == &gtk_text_toggle_on_type ||
6619                            seg->type == &gtk_text_toggle_off_type) &&
6620                           seg->body.toggle.info->tag == tag)
6621                         {
6622                           if (last == seg->type)
6623                             g_error ("Two consecutive toggles on or off weren't merged");
6624                           if (!seg->body.toggle.inNodeCounts)
6625                             g_error ("Toggle segment not in the node counts");
6626
6627                           last = seg->type;
6628
6629                           count++;
6630                         }
6631                     }
6632                 }
6633             }
6634           if (count != info->toggle_count)
6635             {
6636               g_error ("_gtk_text_btree_check toggle_count (%d) wrong for \"%s\" should be (%d)",
6637                        info->toggle_count, tag->name, count);
6638             }
6639         }
6640     }
6641
6642   g_slist_free (taglist);
6643   taglist = NULL;
6644
6645   /*
6646    * Call a recursive procedure to do the main body of checks.
6647    */
6648
6649   node = tree->root_node;
6650   gtk_text_btree_node_check_consistency (tree, tree->root_node);
6651
6652   /*
6653    * Make sure that there are at least two lines in the text and
6654    * that the last line has no characters except a newline.
6655    */
6656
6657   if (node->num_lines < 2)
6658     {
6659       g_error ("_gtk_text_btree_check: less than 2 lines in tree");
6660     }
6661   if (node->num_chars < 2)
6662     {
6663       g_error ("_gtk_text_btree_check: less than 2 chars in tree");
6664     }
6665   while (node->level > 0)
6666     {
6667       node = node->children.node;
6668       while (node->next != NULL)
6669         {
6670           node = node->next;
6671         }
6672     }
6673   line = node->children.line;
6674   while (line->next != NULL)
6675     {
6676       line = line->next;
6677     }
6678   seg = line->segments;
6679   while ((seg->type == &gtk_text_toggle_off_type)
6680          || (seg->type == &gtk_text_right_mark_type)
6681          || (seg->type == &gtk_text_left_mark_type))
6682     {
6683       /*
6684        * It's OK to toggle a tag off in the last line, but
6685        * not to start a new range.  It's also OK to have marks
6686        * in the last line.
6687        */
6688
6689       seg = seg->next;
6690     }
6691   if (seg->type != &gtk_text_char_type)
6692     {
6693       g_error ("_gtk_text_btree_check: last line has bogus segment type");
6694     }
6695   if (seg->next != NULL)
6696     {
6697       g_error ("_gtk_text_btree_check: last line has too many segments");
6698     }
6699   if (seg->byte_count != 1)
6700     {
6701       g_error ("_gtk_text_btree_check: last line has wrong # characters: %d",
6702                seg->byte_count);
6703     }
6704   if ((seg->body.chars[0] != '\n') || (seg->body.chars[1] != 0))
6705     {
6706       g_error ("_gtk_text_btree_check: last line had bad value: %s",
6707                seg->body.chars);
6708     }
6709 }
6710
6711 void _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line);
6712 void _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment* seg);
6713 void _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent);
6714 void _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent);
6715
6716 void
6717 _gtk_text_btree_spew (GtkTextBTree *tree)
6718 {
6719   GtkTextLine * line;
6720   int real_line;
6721
6722   printf ("%d lines in tree %p\n",
6723           _gtk_text_btree_line_count (tree), tree);
6724
6725   line = _gtk_text_btree_get_line (tree, 0, &real_line);
6726
6727   while (line != NULL)
6728     {
6729       _gtk_text_btree_spew_line (tree, line);
6730       line = _gtk_text_line_next (line);
6731     }
6732
6733   printf ("=================== Tag information\n");
6734
6735   {
6736     GSList * list;
6737
6738     list = tree->tag_infos;
6739
6740     while (list != NULL)
6741       {
6742         GtkTextTagInfo *info;
6743
6744         info = list->data;
6745
6746         printf ("  tag `%s': root at %p, toggle count %d\n",
6747                 info->tag->name, info->tag_root, info->toggle_count);
6748
6749         list = g_slist_next (list);
6750       }
6751
6752     if (tree->tag_infos == NULL)
6753       {
6754         printf ("  (no tags in the tree)\n");
6755       }
6756   }
6757
6758   printf ("=================== Tree nodes\n");
6759
6760   {
6761     _gtk_text_btree_spew_node (tree->root_node, 0);
6762   }
6763 }
6764
6765 void
6766 _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent)
6767 {
6768   gchar * spaces;
6769   GtkTextLineSegment *seg;
6770
6771   spaces = g_strnfill (indent, ' ');
6772
6773   printf ("%sline %p chars %d bytes %d\n",
6774           spaces, line,
6775           _gtk_text_line_char_count (line),
6776           _gtk_text_line_byte_count (line));
6777
6778   seg = line->segments;
6779   while (seg != NULL)
6780     {
6781       if (seg->type == &gtk_text_char_type)
6782         {
6783           gchar* str = g_strndup (seg->body.chars, MIN (seg->byte_count, 10));
6784           gchar* s;
6785           s = str;
6786           while (*s)
6787             {
6788               if (*s == '\n' || *s == '\r')
6789                 *s = '\\';
6790               ++s;
6791             }
6792           printf ("%s chars `%s'...\n", spaces, str);
6793           g_free (str);
6794         }
6795       else if (seg->type == &gtk_text_right_mark_type)
6796         {
6797           printf ("%s right mark `%s' visible: %d\n",
6798                   spaces,
6799                   seg->body.mark.name,
6800                   seg->body.mark.visible);
6801         }
6802       else if (seg->type == &gtk_text_left_mark_type)
6803         {
6804           printf ("%s left mark `%s' visible: %d\n",
6805                   spaces,
6806                   seg->body.mark.name,
6807                   seg->body.mark.visible);
6808         }
6809       else if (seg->type == &gtk_text_toggle_on_type ||
6810                seg->type == &gtk_text_toggle_off_type)
6811         {
6812           printf ("%s tag `%s' %s\n",
6813                   spaces, seg->body.toggle.info->tag->name,
6814                   seg->type == &gtk_text_toggle_off_type ? "off" : "on");
6815         }
6816
6817       seg = seg->next;
6818     }
6819
6820   g_free (spaces);
6821 }
6822
6823 void
6824 _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent)
6825 {
6826   gchar * spaces;
6827   GtkTextBTreeNode *iter;
6828   Summary *s;
6829
6830   spaces = g_strnfill (indent, ' ');
6831
6832   printf ("%snode %p level %d children %d lines %d chars %d\n",
6833           spaces, node, node->level,
6834           node->num_children, node->num_lines, node->num_chars);
6835
6836   s = node->summary;
6837   while (s)
6838     {
6839       printf ("%s %d toggles of `%s' below this node\n",
6840               spaces, s->toggle_count, s->info->tag->name);
6841       s = s->next;
6842     }
6843
6844   g_free (spaces);
6845
6846   if (node->level > 0)
6847     {
6848       iter = node->children.node;
6849       while (iter != NULL)
6850         {
6851           _gtk_text_btree_spew_node (iter, indent + 2);
6852
6853           iter = iter->next;
6854         }
6855     }
6856   else
6857     {
6858       GtkTextLine *line = node->children.line;
6859       while (line != NULL)
6860         {
6861           _gtk_text_btree_spew_line_short (line, indent + 2);
6862
6863           line = line->next;
6864         }
6865     }
6866 }
6867
6868 void
6869 _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line)
6870 {
6871   GtkTextLineSegment * seg;
6872
6873   printf ("%4d| line: %p parent: %p next: %p\n",
6874           _gtk_text_line_get_number (line), line, line->parent, line->next);
6875
6876   seg = line->segments;
6877
6878   while (seg != NULL)
6879     {
6880       _gtk_text_btree_spew_segment (tree, seg);
6881       seg = seg->next;
6882     }
6883 }
6884
6885 void
6886 _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
6887 {
6888   printf ("     segment: %p type: %s bytes: %d chars: %d\n",
6889           seg, seg->type->name, seg->byte_count, seg->char_count);
6890
6891   if (seg->type == &gtk_text_char_type)
6892     {
6893       gchar* str = g_strndup (seg->body.chars, seg->byte_count);
6894       printf ("       `%s'\n", str);
6895       g_free (str);
6896     }
6897   else if (seg->type == &gtk_text_right_mark_type)
6898     {
6899       printf ("       right mark `%s' visible: %d not_deleteable: %d\n",
6900               seg->body.mark.name,
6901               seg->body.mark.visible,
6902               seg->body.mark.not_deleteable);
6903     }
6904   else if (seg->type == &gtk_text_left_mark_type)
6905     {
6906       printf ("       left mark `%s' visible: %d not_deleteable: %d\n",
6907               seg->body.mark.name,
6908               seg->body.mark.visible,
6909               seg->body.mark.not_deleteable);
6910     }
6911   else if (seg->type == &gtk_text_toggle_on_type ||
6912            seg->type == &gtk_text_toggle_off_type)
6913     {
6914       printf ("       tag `%s' priority %d\n",
6915               seg->body.toggle.info->tag->name,
6916               seg->body.toggle.info->tag->priority);
6917     }
6918 }
6919
6920