]> Pileus Git - ~andy/gtk/blob - gtk/gtktextbtree.c
492bcae8306b82ea9c4d7fa91771bdb4898c461b
[~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   tree->views = view;
1399
1400   /* The last line in the buffer has identity values for the per-view
1401    * data so that we can avoid special case checks for it in a large
1402    * number of loops
1403    */
1404   last_line = get_last_line (tree);
1405
1406   line_data = g_new (GtkTextLineData, 1);
1407   line_data->view_id = layout;
1408   line_data->next = NULL;
1409   line_data->width = 0;
1410   line_data->height = 0;
1411   line_data->valid = TRUE;
1412
1413   _gtk_text_line_add_data (last_line, line_data);
1414 }
1415
1416 void
1417 _gtk_text_btree_remove_view (GtkTextBTree *tree,
1418                              gpointer      view_id)
1419 {
1420   BTreeView *view;
1421   GtkTextLine *last_line;
1422   GtkTextLineData *line_data;
1423
1424   g_return_if_fail (tree != NULL);
1425   
1426   view = tree->views;
1427
1428   while (view != NULL)
1429     {
1430       if (view->view_id == view_id)
1431         break;
1432
1433       view = view->next;
1434     }
1435
1436   g_return_if_fail (view != NULL);
1437
1438   if (view->next)
1439     view->next->prev = view->prev;
1440
1441   if (view->prev)
1442     view->prev->next = view->next;
1443
1444   if (view == tree->views)
1445     tree->views = view->next;
1446
1447   /* Remove the line data for the last line which we added ourselves.
1448    * (Do this first, so that we don't try to call the view's line data destructor on it.)
1449    */
1450   last_line = get_last_line (tree);
1451   line_data = _gtk_text_line_remove_data (last_line, view_id);
1452   g_free (line_data);
1453
1454   gtk_text_btree_node_remove_view (view, tree->root_node, view_id);
1455
1456   g_free (view);
1457 }
1458
1459 void
1460 _gtk_text_btree_invalidate_region (GtkTextBTree *tree,
1461                                   const GtkTextIter *start,
1462                                   const GtkTextIter *end)
1463 {
1464   BTreeView *view;
1465
1466   view = tree->views;
1467
1468   while (view != NULL)
1469     {
1470       gtk_text_layout_invalidate (view->layout, start, end);
1471
1472       view = view->next;
1473     }
1474 }
1475
1476 void
1477 _gtk_text_btree_get_view_size (GtkTextBTree *tree,
1478                               gpointer view_id,
1479                               gint *width,
1480                               gint *height)
1481 {
1482   g_return_if_fail (tree != NULL);
1483   g_return_if_fail (view_id != NULL);
1484
1485   gtk_text_btree_node_get_size (tree->root_node, view_id,
1486                                 width, height);
1487 }
1488
1489 /*
1490  * Tag
1491  */
1492
1493 typedef struct {
1494   GtkTextIter *iters;
1495   guint count;
1496   guint alloced;
1497 } IterStack;
1498
1499 static IterStack*
1500 iter_stack_new (void)
1501 {
1502   IterStack *stack;
1503   stack = g_new (IterStack, 1);
1504   stack->iters = NULL;
1505   stack->count = 0;
1506   stack->alloced = 0;
1507   return stack;
1508 }
1509
1510 static void
1511 iter_stack_push (IterStack *stack, const GtkTextIter *iter)
1512 {
1513   stack->count += 1;
1514   if (stack->count > stack->alloced)
1515     {
1516       stack->alloced = stack->count*2;
1517       stack->iters = g_realloc (stack->iters,
1518                                 stack->alloced*sizeof (GtkTextIter));
1519     }
1520   stack->iters[stack->count-1] = *iter;
1521 }
1522
1523 static gboolean
1524 iter_stack_pop (IterStack *stack, GtkTextIter *iter)
1525 {
1526   if (stack->count == 0)
1527     return FALSE;
1528   else
1529     {
1530       stack->count -= 1;
1531       *iter = stack->iters[stack->count];
1532       return TRUE;
1533     }
1534 }
1535
1536 static void
1537 iter_stack_free (IterStack *stack)
1538 {
1539   g_free (stack->iters);
1540   g_free (stack);
1541 }
1542
1543 static void
1544 iter_stack_invert (IterStack *stack)
1545 {
1546   if (stack->count > 0)
1547     {
1548       guint i = 0;
1549       guint j = stack->count - 1;
1550       while (i < j)
1551         {
1552           GtkTextIter tmp;
1553
1554           tmp = stack->iters[i];
1555           stack->iters[i] = stack->iters[j];
1556           stack->iters[j] = tmp;
1557
1558           ++i;
1559           --j;
1560         }
1561     }
1562 }
1563
1564 static void
1565 queue_tag_redisplay (GtkTextBTree      *tree,
1566                      GtkTextTag        *tag,
1567                      const GtkTextIter *start,
1568                      const GtkTextIter *end)
1569 {
1570   if (_gtk_text_tag_affects_size (tag))
1571     {
1572       _gtk_text_btree_invalidate_region (tree, start, end);
1573     }
1574   else if (_gtk_text_tag_affects_nonsize_appearance (tag))
1575     {
1576       /* We only need to queue a redraw, not a relayout */
1577       redisplay_region (tree, start, end);
1578     }
1579
1580   /* We don't need to do anything if the tag doesn't affect display */
1581 }
1582
1583 void
1584 _gtk_text_btree_tag (const GtkTextIter *start_orig,
1585                      const GtkTextIter *end_orig,
1586                      GtkTextTag        *tag,
1587                      gboolean           add)
1588 {
1589   GtkTextLineSegment *seg, *prev;
1590   GtkTextLine *cleanupline;
1591   gboolean toggled_on;
1592   GtkTextLine *start_line;
1593   GtkTextLine *end_line;
1594   GtkTextIter iter;
1595   GtkTextIter start, end;
1596   GtkTextBTree *tree;
1597   IterStack *stack;
1598   GtkTextTagInfo *info;
1599
1600   g_return_if_fail (start_orig != NULL);
1601   g_return_if_fail (end_orig != NULL);
1602   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1603   g_return_if_fail (_gtk_text_iter_get_btree (start_orig) ==
1604                     _gtk_text_iter_get_btree (end_orig));
1605   g_return_if_fail (tag->table == _gtk_text_iter_get_btree (start_orig)->table);
1606   
1607 #if 0
1608   printf ("%s tag %s from %d to %d\n",
1609           add ? "Adding" : "Removing",
1610           tag->name,
1611           gtk_text_buffer_get_offset (start_orig),
1612           gtk_text_buffer_get_offset (end_orig));
1613 #endif
1614
1615   if (gtk_text_iter_equal (start_orig, end_orig))
1616     return;
1617
1618   start = *start_orig;
1619   end = *end_orig;
1620
1621   gtk_text_iter_order (&start, &end);
1622
1623   tree = _gtk_text_iter_get_btree (&start);
1624
1625   queue_tag_redisplay (tree, tag, &start, &end);
1626
1627   info = gtk_text_btree_get_tag_info (tree, tag);
1628
1629   start_line = _gtk_text_iter_get_text_line (&start);
1630   end_line = _gtk_text_iter_get_text_line (&end);
1631
1632   /* Find all tag toggles in the region; we are going to delete them.
1633      We need to find them in advance, because
1634      forward_find_tag_toggle () won't work once we start playing around
1635      with the tree. */
1636   stack = iter_stack_new ();
1637   iter = start;
1638
1639   /* forward_to_tag_toggle() skips a toggle at the start iterator,
1640    * which is deliberate - we don't want to delete a toggle at the
1641    * start.
1642    */
1643   while (gtk_text_iter_forward_to_tag_toggle (&iter, tag))
1644     {
1645       if (gtk_text_iter_compare (&iter, &end) >= 0)
1646         break;
1647       else
1648         iter_stack_push (stack, &iter);
1649     }
1650
1651   /* We need to traverse the toggles in order. */
1652   iter_stack_invert (stack);
1653
1654   /*
1655    * See whether the tag is present at the start of the range.  If
1656    * the state doesn't already match what we want then add a toggle
1657    * there.
1658    */
1659
1660   toggled_on = gtk_text_iter_has_tag (&start, tag);
1661   if ( (add && !toggled_on) ||
1662        (!add && toggled_on) )
1663     {
1664       /* This could create a second toggle at the start position;
1665          cleanup_line () will remove it if so. */
1666       seg = _gtk_toggle_segment_new (info, add);
1667
1668       prev = gtk_text_line_segment_split (&start);
1669       if (prev == NULL)
1670         {
1671           seg->next = start_line->segments;
1672           start_line->segments = seg;
1673         }
1674       else
1675         {
1676           seg->next = prev->next;
1677           prev->next = seg;
1678         }
1679
1680       /* cleanup_line adds the new toggle to the node counts. */
1681 #if 0
1682       printf ("added toggle at start\n");
1683 #endif
1684       /* we should probably call segments_changed, but in theory
1685          any still-cached segments in the iters we are about to
1686          use are still valid, since they're in front
1687          of this spot. */
1688     }
1689
1690   /*
1691    *
1692    * Scan the range of characters and delete any internal tag
1693    * transitions.  Keep track of what the old state was at the end
1694    * of the range, and add a toggle there if it's needed.
1695    *
1696    */
1697
1698   cleanupline = start_line;
1699   while (iter_stack_pop (stack, &iter))
1700     {
1701       GtkTextLineSegment *indexable_seg;
1702       GtkTextLine *line;
1703
1704       line = _gtk_text_iter_get_text_line (&iter);
1705       seg = _gtk_text_iter_get_any_segment (&iter);
1706       indexable_seg = _gtk_text_iter_get_indexable_segment (&iter);
1707
1708       g_assert (seg != NULL);
1709       g_assert (indexable_seg != NULL);
1710       g_assert (seg != indexable_seg);
1711
1712       prev = line->segments;
1713
1714       /* Find the segment that actually toggles this tag. */
1715       while (seg != indexable_seg)
1716         {
1717           g_assert (seg != NULL);
1718           g_assert (indexable_seg != NULL);
1719           g_assert (seg != indexable_seg);
1720
1721           if ( (seg->type == &gtk_text_toggle_on_type ||
1722                 seg->type == &gtk_text_toggle_off_type) &&
1723                (seg->body.toggle.info == info) )
1724             break;
1725           else
1726             seg = seg->next;
1727         }
1728
1729       g_assert (seg != NULL);
1730       g_assert (indexable_seg != NULL);
1731
1732       g_assert (seg != indexable_seg); /* If this happens, then
1733                                           forward_to_tag_toggle was
1734                                           full of shit. */
1735       g_assert (seg->body.toggle.info->tag == tag);
1736
1737       /* If this happens, when previously tagging we didn't merge
1738          overlapping tags. */
1739       g_assert ( (toggled_on && seg->type == &gtk_text_toggle_off_type) ||
1740                  (!toggled_on && seg->type == &gtk_text_toggle_on_type) );
1741
1742       toggled_on = !toggled_on;
1743
1744 #if 0
1745       printf ("deleting %s toggle\n",
1746               seg->type == &gtk_text_toggle_on_type ? "on" : "off");
1747 #endif
1748       /* Remove toggle segment from the list. */
1749       if (prev == seg)
1750         {
1751           line->segments = seg->next;
1752         }
1753       else
1754         {
1755           while (prev->next != seg)
1756             {
1757               prev = prev->next;
1758             }
1759           prev->next = seg->next;
1760         }
1761
1762       /* Inform iterators we've hosed them. This actually reflects a
1763          bit of inefficiency; if you have the same tag toggled on and
1764          off a lot in a single line, we keep having the rescan from
1765          the front of the line. Of course we have to do that to get
1766          "prev" anyway, but here we are doing it an additional
1767          time. FIXME */
1768       segments_changed (tree);
1769
1770       /* Update node counts */
1771       if (seg->body.toggle.inNodeCounts)
1772         {
1773           _gtk_change_node_toggle_count (line->parent,
1774                                          info, -1);
1775           seg->body.toggle.inNodeCounts = FALSE;
1776         }
1777
1778       g_free (seg);
1779
1780       /* We only clean up lines when we're done with them, saves some
1781          gratuitous line-segment-traversals */
1782
1783       if (cleanupline != line)
1784         {
1785           cleanup_line (cleanupline);
1786           cleanupline = line;
1787         }
1788     }
1789
1790   iter_stack_free (stack);
1791
1792   /* toggled_on now reflects the toggle state _just before_ the
1793      end iterator. The end iterator could already have a toggle
1794      on or a toggle off. */
1795   if ( (add && !toggled_on) ||
1796        (!add && toggled_on) )
1797     {
1798       /* This could create a second toggle at the start position;
1799          cleanup_line () will remove it if so. */
1800
1801       seg = _gtk_toggle_segment_new (info, !add);
1802
1803       prev = gtk_text_line_segment_split (&end);
1804       if (prev == NULL)
1805         {
1806           seg->next = end_line->segments;
1807           end_line->segments = seg;
1808         }
1809       else
1810         {
1811           seg->next = prev->next;
1812           prev->next = seg;
1813         }
1814       /* cleanup_line adds the new toggle to the node counts. */
1815       g_assert (seg->body.toggle.inNodeCounts == FALSE);
1816 #if 0
1817       printf ("added toggle at end\n");
1818 #endif
1819     }
1820
1821   /*
1822    * Cleanup cleanupline and the last line of the range, if
1823    * these are different.
1824    */
1825
1826   cleanup_line (cleanupline);
1827   if (cleanupline != end_line)
1828     {
1829       cleanup_line (end_line);
1830     }
1831
1832   segments_changed (tree);
1833
1834   if (gtk_debug_flags & GTK_DEBUG_TEXT)
1835     _gtk_text_btree_check (tree);
1836 }
1837
1838
1839 /*
1840  * "Getters"
1841  */
1842
1843 GtkTextLine*
1844 _gtk_text_btree_get_line (GtkTextBTree *tree,
1845                          gint  line_number,
1846                          gint *real_line_number)
1847 {
1848   GtkTextBTreeNode *node;
1849   GtkTextLine *line;
1850   int lines_left;
1851   int line_count;
1852
1853   line_count = _gtk_text_btree_line_count (tree);
1854
1855   if (line_number < 0)
1856     {
1857       line_number = line_count;
1858     }
1859   else if (line_number > line_count)
1860     {
1861       line_number = line_count;
1862     }
1863
1864   if (real_line_number)
1865     *real_line_number = line_number;
1866
1867   node = tree->root_node;
1868   lines_left = line_number;
1869
1870   /*
1871    * Work down through levels of the tree until a GtkTextBTreeNode is found at
1872    * level 0.
1873    */
1874
1875   while (node->level != 0)
1876     {
1877       for (node = node->children.node;
1878            node->num_lines <= lines_left;
1879            node = node->next)
1880         {
1881 #if 0
1882           if (node == NULL)
1883             {
1884               g_error ("gtk_text_btree_find_line ran out of GtkTextBTreeNodes");
1885             }
1886 #endif
1887           lines_left -= node->num_lines;
1888         }
1889     }
1890
1891   /*
1892    * Work through the lines attached to the level-0 GtkTextBTreeNode.
1893    */
1894
1895   for (line = node->children.line; lines_left > 0;
1896        line = line->next)
1897     {
1898 #if 0
1899       if (line == NULL)
1900         {
1901           g_error ("gtk_text_btree_find_line ran out of lines");
1902         }
1903 #endif
1904       lines_left -= 1;
1905     }
1906   return line;
1907 }
1908
1909 GtkTextLine*
1910 _gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
1911                                  gint                char_index,
1912                                  gint               *line_start_index,
1913                                  gint               *real_char_index)
1914 {
1915   GtkTextBTreeNode *node;
1916   GtkTextLine *line;
1917   GtkTextLineSegment *seg;
1918   int chars_left;
1919   int chars_in_line;
1920   int bytes_in_line;
1921
1922   node = tree->root_node;
1923
1924   /* Clamp to valid indexes (-1 is magic for "highest index") */
1925   if (char_index < 0 || char_index >= node->num_chars)
1926     {
1927       char_index = node->num_chars - 1;
1928     }
1929
1930   *real_char_index = char_index;
1931
1932   /*
1933    * Work down through levels of the tree until a GtkTextBTreeNode is found at
1934    * level 0.
1935    */
1936
1937   chars_left = char_index;
1938   while (node->level != 0)
1939     {
1940       for (node = node->children.node;
1941            chars_left >= node->num_chars;
1942            node = node->next)
1943         {
1944           chars_left -= node->num_chars;
1945
1946           g_assert (chars_left >= 0);
1947         }
1948     }
1949
1950   if (chars_left == 0)
1951     {
1952       /* Start of a line */
1953
1954       *line_start_index = char_index;
1955       return node->children.line;
1956     }
1957
1958   /*
1959    * Work through the lines attached to the level-0 GtkTextBTreeNode.
1960    */
1961
1962   chars_in_line = 0;
1963   bytes_in_line = 0;
1964   seg = NULL;
1965   for (line = node->children.line; line != NULL; line = line->next)
1966     {
1967       seg = line->segments;
1968       while (seg != NULL)
1969         {
1970           if (chars_in_line + seg->char_count > chars_left)
1971             goto found; /* found our line/segment */
1972
1973           chars_in_line += seg->char_count;
1974
1975           seg = seg->next;
1976         }
1977
1978       chars_left -= chars_in_line;
1979
1980       chars_in_line = 0;
1981       seg = NULL;
1982     }
1983
1984  found:
1985
1986   g_assert (line != NULL); /* hosage, ran out of lines */
1987   g_assert (seg != NULL);
1988
1989   *line_start_index = char_index - chars_left;
1990   return line;
1991 }
1992
1993 GtkTextTag**
1994 _gtk_text_btree_get_tags (const GtkTextIter *iter,
1995                          gint *num_tags)
1996 {
1997   GtkTextBTreeNode *node;
1998   GtkTextLine *siblingline;
1999   GtkTextLineSegment *seg;
2000   int src, dst, index;
2001   TagInfo tagInfo;
2002   GtkTextLine *line;
2003   GtkTextBTree *tree;
2004   gint byte_index;
2005
2006 #define NUM_TAG_INFOS 10
2007
2008   line = _gtk_text_iter_get_text_line (iter);
2009   tree = _gtk_text_iter_get_btree (iter);
2010   byte_index = gtk_text_iter_get_line_index (iter);
2011
2012   tagInfo.numTags = 0;
2013   tagInfo.arraySize = NUM_TAG_INFOS;
2014   tagInfo.tags = g_new (GtkTextTag*, NUM_TAG_INFOS);
2015   tagInfo.counts = g_new (int, NUM_TAG_INFOS);
2016
2017   /*
2018    * Record tag toggles within the line of indexPtr but preceding
2019    * indexPtr. Note that if this loop segfaults, your
2020    * byte_index probably points past the sum of all
2021    * seg->byte_count */
2022
2023   for (index = 0, seg = line->segments;
2024        (index + seg->byte_count) <= byte_index;
2025        index += seg->byte_count, seg = seg->next)
2026     {
2027       if ((seg->type == &gtk_text_toggle_on_type)
2028           || (seg->type == &gtk_text_toggle_off_type))
2029         {
2030           inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2031         }
2032     }
2033
2034   /*
2035    * Record toggles for tags in lines that are predecessors of
2036    * line but under the same level-0 GtkTextBTreeNode.
2037    */
2038
2039   for (siblingline = line->parent->children.line;
2040        siblingline != line;
2041        siblingline = siblingline->next)
2042     {
2043       for (seg = siblingline->segments; seg != NULL;
2044            seg = seg->next)
2045         {
2046           if ((seg->type == &gtk_text_toggle_on_type)
2047               || (seg->type == &gtk_text_toggle_off_type))
2048             {
2049               inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
2050             }
2051         }
2052     }
2053
2054   /*
2055    * For each GtkTextBTreeNode in the ancestry of this line, record tag
2056    * toggles for all siblings that precede that GtkTextBTreeNode.
2057    */
2058
2059   for (node = line->parent; node->parent != NULL;
2060        node = node->parent)
2061     {
2062       GtkTextBTreeNode *siblingPtr;
2063       Summary *summary;
2064
2065       for (siblingPtr = node->parent->children.node;
2066            siblingPtr != node; siblingPtr = siblingPtr->next)
2067         {
2068           for (summary = siblingPtr->summary; summary != NULL;
2069                summary = summary->next)
2070             {
2071               if (summary->toggle_count & 1)
2072                 {
2073                   inc_count (summary->info->tag, summary->toggle_count,
2074                              &tagInfo);
2075                 }
2076             }
2077         }
2078     }
2079
2080   /*
2081    * Go through the tag information and squash out all of the tags
2082    * that have even toggle counts (these tags exist before the point
2083    * of interest, but not at the desired character itself).
2084    */
2085
2086   for (src = 0, dst = 0; src < tagInfo.numTags; src++)
2087     {
2088       if (tagInfo.counts[src] & 1)
2089         {
2090           g_assert (GTK_IS_TEXT_TAG (tagInfo.tags[src]));
2091           tagInfo.tags[dst] = tagInfo.tags[src];
2092           dst++;
2093         }
2094     }
2095
2096   *num_tags = dst;
2097   g_free (tagInfo.counts);
2098   if (dst == 0)
2099     {
2100       g_free (tagInfo.tags);
2101       return NULL;
2102     }
2103   return tagInfo.tags;
2104 }
2105
2106 static void
2107 copy_segment (GString *string,
2108               gboolean include_hidden,
2109               gboolean include_nonchars,
2110               const GtkTextIter *start,
2111               const GtkTextIter *end)
2112 {
2113   GtkTextLineSegment *end_seg;
2114   GtkTextLineSegment *seg;
2115
2116   if (gtk_text_iter_equal (start, end))
2117     return;
2118
2119   seg = _gtk_text_iter_get_indexable_segment (start);
2120   end_seg = _gtk_text_iter_get_indexable_segment (end);
2121
2122   if (seg->type == &gtk_text_char_type)
2123     {
2124       gboolean copy = TRUE;
2125       gint copy_bytes = 0;
2126       gint copy_start = 0;
2127
2128       /* Don't copy if we're invisible; segments are invisible/not
2129          as a whole, no need to check each char */
2130       if (!include_hidden &&
2131           _gtk_text_btree_char_is_invisible (start))
2132         {
2133           copy = FALSE;
2134           /* printf (" <invisible>\n"); */
2135         }
2136
2137       copy_start = _gtk_text_iter_get_segment_byte (start);
2138
2139       if (seg == end_seg)
2140         {
2141           /* End is in the same segment; need to copy fewer bytes. */
2142           gint end_byte = _gtk_text_iter_get_segment_byte (end);
2143
2144           copy_bytes = end_byte - copy_start;
2145         }
2146       else
2147         copy_bytes = seg->byte_count - copy_start;
2148
2149       g_assert (copy_bytes != 0); /* Due to iter equality check at
2150                                      front of this function. */
2151
2152       if (copy)
2153         {
2154           g_assert ((copy_start + copy_bytes) <= seg->byte_count);
2155
2156           g_string_append_len (string,
2157                                seg->body.chars + copy_start,
2158                                copy_bytes);
2159         }
2160
2161       /* printf ("  :%s\n", string->str); */
2162     }
2163   else if (seg->type == &gtk_text_pixbuf_type ||
2164            seg->type == &gtk_text_child_type)
2165     {
2166       gboolean copy = TRUE;
2167
2168       if (!include_nonchars)
2169         {
2170           copy = FALSE;
2171         }
2172       else if (!include_hidden &&
2173                _gtk_text_btree_char_is_invisible (start))
2174         {
2175           copy = FALSE;
2176         }
2177
2178       if (copy)
2179         {
2180           g_string_append_len (string,
2181                                gtk_text_unknown_char_utf8,
2182                                3);
2183
2184         }
2185     }
2186 }
2187
2188 gchar*
2189 _gtk_text_btree_get_text (const GtkTextIter *start_orig,
2190                          const GtkTextIter *end_orig,
2191                          gboolean include_hidden,
2192                          gboolean include_nonchars)
2193 {
2194   GtkTextLineSegment *seg;
2195   GtkTextLineSegment *end_seg;
2196   GString *retval;
2197   GtkTextBTree *tree;
2198   gchar *str;
2199   GtkTextIter iter;
2200   GtkTextIter start;
2201   GtkTextIter end;
2202
2203   g_return_val_if_fail (start_orig != NULL, NULL);
2204   g_return_val_if_fail (end_orig != NULL, NULL);
2205   g_return_val_if_fail (_gtk_text_iter_get_btree (start_orig) ==
2206                         _gtk_text_iter_get_btree (end_orig), NULL);
2207
2208   start = *start_orig;
2209   end = *end_orig;
2210
2211   gtk_text_iter_order (&start, &end);
2212
2213   retval = g_string_new ("");
2214
2215   tree = _gtk_text_iter_get_btree (&start);
2216
2217   end_seg = _gtk_text_iter_get_indexable_segment (&end);
2218   iter = start;
2219   seg = _gtk_text_iter_get_indexable_segment (&iter);
2220   while (seg != end_seg)
2221     {
2222       copy_segment (retval, include_hidden, include_nonchars,
2223                     &iter, &end);
2224
2225       _gtk_text_iter_forward_indexable_segment (&iter);
2226
2227       seg = _gtk_text_iter_get_indexable_segment (&iter);
2228     }
2229
2230   copy_segment (retval, include_hidden, include_nonchars, &iter, &end);
2231
2232   str = retval->str;
2233   g_string_free (retval, FALSE);
2234   return str;
2235 }
2236
2237 gint
2238 _gtk_text_btree_line_count (GtkTextBTree *tree)
2239 {
2240   /* Subtract bogus line at the end; we return a count
2241      of usable lines. */
2242   return tree->root_node->num_lines - 1;
2243 }
2244
2245 gint
2246 _gtk_text_btree_char_count (GtkTextBTree *tree)
2247 {
2248   /* Exclude newline in bogus last line */
2249   return tree->root_node->num_chars - 1;
2250 }
2251
2252 #define LOTSA_TAGS 1000
2253 gboolean
2254 _gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
2255 {
2256   gboolean invisible = FALSE;  /* if nobody says otherwise, it's visible */
2257
2258   int deftagCnts[LOTSA_TAGS];
2259   int *tagCnts = deftagCnts;
2260   GtkTextTag *deftags[LOTSA_TAGS];
2261   GtkTextTag **tags = deftags;
2262   int numTags;
2263   GtkTextBTreeNode *node;
2264   GtkTextLine *siblingline;
2265   GtkTextLineSegment *seg;
2266   GtkTextTag *tag;
2267   int i, index;
2268   GtkTextLine *line;
2269   GtkTextBTree *tree;
2270   gint byte_index;
2271
2272   line = _gtk_text_iter_get_text_line (iter);
2273   tree = _gtk_text_iter_get_btree (iter);
2274   byte_index = gtk_text_iter_get_line_index (iter);
2275
2276   numTags = gtk_text_tag_table_get_size (tree->table);
2277
2278   /* almost always avoid malloc, so stay out of system calls */
2279   if (LOTSA_TAGS < numTags)
2280     {
2281       tagCnts = g_new (int, numTags);
2282       tags = g_new (GtkTextTag*, numTags);
2283     }
2284
2285   for (i=0; i<numTags; i++)
2286     {
2287       tagCnts[i] = 0;
2288     }
2289
2290   /*
2291    * Record tag toggles within the line of indexPtr but preceding
2292    * indexPtr.
2293    */
2294
2295   for (index = 0, seg = line->segments;
2296        (index + seg->byte_count) <= byte_index; /* segfault here means invalid index */
2297        index += seg->byte_count, seg = seg->next)
2298     {
2299       if ((seg->type == &gtk_text_toggle_on_type)
2300           || (seg->type == &gtk_text_toggle_off_type))
2301         {
2302           tag = seg->body.toggle.info->tag;
2303           if (tag->invisible_set && tag->values->invisible)
2304             {
2305               tags[tag->priority] = tag;
2306               tagCnts[tag->priority]++;
2307             }
2308         }
2309     }
2310
2311   /*
2312    * Record toggles for tags in lines that are predecessors of
2313    * line but under the same level-0 GtkTextBTreeNode.
2314    */
2315
2316   for (siblingline = line->parent->children.line;
2317        siblingline != line;
2318        siblingline = siblingline->next)
2319     {
2320       for (seg = siblingline->segments; seg != NULL;
2321            seg = seg->next)
2322         {
2323           if ((seg->type == &gtk_text_toggle_on_type)
2324               || (seg->type == &gtk_text_toggle_off_type))
2325             {
2326               tag = seg->body.toggle.info->tag;
2327               if (tag->invisible_set && tag->values->invisible)
2328                 {
2329                   tags[tag->priority] = tag;
2330                   tagCnts[tag->priority]++;
2331                 }
2332             }
2333         }
2334     }
2335
2336   /*
2337    * For each GtkTextBTreeNode in the ancestry of this line, record tag toggles
2338    * for all siblings that precede that GtkTextBTreeNode.
2339    */
2340
2341   for (node = line->parent; node->parent != NULL;
2342        node = node->parent)
2343     {
2344       GtkTextBTreeNode *siblingPtr;
2345       Summary *summary;
2346
2347       for (siblingPtr = node->parent->children.node;
2348            siblingPtr != node; siblingPtr = siblingPtr->next)
2349         {
2350           for (summary = siblingPtr->summary; summary != NULL;
2351                summary = summary->next)
2352             {
2353               if (summary->toggle_count & 1)
2354                 {
2355                   tag = summary->info->tag;
2356                   if (tag->invisible_set && tag->values->invisible)
2357                     {
2358                       tags[tag->priority] = tag;
2359                       tagCnts[tag->priority] += summary->toggle_count;
2360                     }
2361                 }
2362             }
2363         }
2364     }
2365
2366   /*
2367    * Now traverse from highest priority to lowest,
2368    * take invisible value from first odd count (= on)
2369    */
2370
2371   for (i = numTags-1; i >=0; i--)
2372     {
2373       if (tagCnts[i] & 1)
2374         {
2375           /* FIXME not sure this should be if 0 */
2376 #if 0
2377 #ifndef ALWAYS_SHOW_SELECTION
2378           /* who would make the selection invisible? */
2379           if ((tag == tkxt->seltag)
2380               && !(tkxt->flags & GOT_FOCUS))
2381             {
2382               continue;
2383             }
2384 #endif
2385 #endif
2386           invisible = tags[i]->values->invisible;
2387           break;
2388         }
2389     }
2390
2391   if (LOTSA_TAGS < numTags)
2392     {
2393       g_free (tagCnts);
2394       g_free (tags);
2395     }
2396
2397   return invisible;
2398 }
2399
2400
2401 /*
2402  * Manipulate marks
2403  */
2404
2405 static void
2406 redisplay_region (GtkTextBTree      *tree,
2407                   const GtkTextIter *start,
2408                   const GtkTextIter *end)
2409 {
2410   BTreeView *view;
2411   GtkTextLine *start_line, *end_line;
2412
2413   if (gtk_text_iter_compare (start, end) > 0)
2414     {
2415       const GtkTextIter *tmp = start;
2416       start = end;
2417       end = tmp;
2418     }
2419
2420   start_line = _gtk_text_iter_get_text_line (start);
2421   end_line = _gtk_text_iter_get_text_line (end);
2422
2423   view = tree->views;
2424   while (view != NULL)
2425     {
2426       gint start_y, end_y;
2427       GtkTextLineData *ld;
2428
2429       start_y = _gtk_text_btree_find_line_top (tree, start_line, view->view_id);
2430
2431       if (end_line == start_line)
2432         end_y = start_y;
2433       else
2434         end_y = _gtk_text_btree_find_line_top (tree, end_line, view->view_id);
2435
2436       ld = _gtk_text_line_get_data (end_line, view->view_id);
2437       if (ld)
2438         end_y += ld->height;
2439
2440       gtk_text_layout_changed (view->layout, start_y,
2441                                end_y - start_y,
2442                                end_y - start_y);
2443
2444       view = view->next;
2445     }
2446 }
2447
2448 static void
2449 redisplay_mark (GtkTextLineSegment *mark)
2450 {
2451   GtkTextIter iter;
2452   GtkTextIter end;
2453
2454   _gtk_text_btree_get_iter_at_mark (mark->body.mark.tree,
2455                                    &iter,
2456                                    mark->body.mark.obj);
2457
2458   end = iter;
2459   gtk_text_iter_forward_char (&end);
2460
2461   _gtk_text_btree_invalidate_region (mark->body.mark.tree,
2462                                     &iter, &end);
2463 }
2464
2465 static void
2466 redisplay_mark_if_visible (GtkTextLineSegment *mark)
2467 {
2468   if (!mark->body.mark.visible)
2469     return;
2470   else
2471     redisplay_mark (mark);
2472 }
2473
2474 static void
2475 ensure_not_off_end (GtkTextBTree *tree,
2476                     GtkTextLineSegment *mark,
2477                     GtkTextIter *iter)
2478 {
2479   if (gtk_text_iter_get_line (iter) ==
2480       _gtk_text_btree_line_count (tree))
2481     gtk_text_iter_backward_char (iter);
2482 }
2483
2484 static GtkTextLineSegment*
2485 real_set_mark (GtkTextBTree      *tree,
2486                GtkTextMark       *existing_mark,
2487                const gchar       *name,
2488                gboolean           left_gravity,
2489                const GtkTextIter *where,
2490                gboolean           should_exist,
2491                gboolean           redraw_selections)
2492 {
2493   GtkTextLineSegment *mark;
2494   GtkTextIter iter;
2495
2496   g_return_val_if_fail (tree != NULL, NULL);
2497   g_return_val_if_fail (where != NULL, NULL);
2498   g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
2499
2500   if (existing_mark)
2501     mark = existing_mark->segment;
2502   else if (name != NULL)
2503     mark = g_hash_table_lookup (tree->mark_table,
2504                                 name);
2505   else
2506     mark = NULL;
2507
2508   if (should_exist && mark == NULL)
2509     {
2510       g_warning ("No mark `%s' exists!", name);
2511       return NULL;
2512     }
2513
2514   /* OK if !should_exist and it does already exist, in that case
2515    * we just move it.
2516    */
2517   
2518   iter = *where;
2519
2520   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2521     _gtk_text_iter_check (&iter);
2522   
2523   if (mark != NULL)
2524     {
2525       if (redraw_selections &&
2526           (mark == tree->insert_mark->segment ||
2527            mark == tree->selection_bound_mark->segment))
2528         {
2529           GtkTextIter old_pos;
2530
2531           _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
2532                                            mark->body.mark.obj);
2533           redisplay_region (tree, &old_pos, where);
2534         }
2535
2536       /*
2537        * don't let visible marks be after the final newline of the
2538        *  file.
2539        */
2540
2541       if (mark->body.mark.visible)
2542         {
2543           ensure_not_off_end (tree, mark, &iter);
2544         }
2545
2546       /* Redraw the mark's old location. */
2547       redisplay_mark_if_visible (mark);
2548
2549       /* Unlink mark from its current location.
2550          This could hose our iterator... */
2551       gtk_text_btree_unlink_segment (tree, mark,
2552                                      mark->body.mark.line);
2553       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2554       g_assert (mark->body.mark.line == _gtk_text_iter_get_text_line (&iter));
2555
2556       segments_changed (tree); /* make sure the iterator recomputes its
2557                                   segment */
2558     }
2559   else
2560     {
2561       mark = _gtk_mark_segment_new (tree,
2562                                     left_gravity,
2563                                     name);
2564
2565       mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
2566
2567       if (mark->body.mark.name)
2568         g_hash_table_insert (tree->mark_table,
2569                              mark->body.mark.name,
2570                              mark);
2571     }
2572
2573   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2574     _gtk_text_iter_check (&iter);
2575   
2576   /* Link mark into new location */
2577   gtk_text_btree_link_segment (mark, &iter);
2578
2579   /* Invalidate some iterators. */
2580   segments_changed (tree);
2581
2582   /*
2583    * update the screen at the mark's new location.
2584    */
2585
2586   redisplay_mark_if_visible (mark);
2587
2588   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2589     _gtk_text_iter_check (&iter);
2590
2591   if (gtk_debug_flags & GTK_DEBUG_TEXT)
2592     _gtk_text_btree_check (tree);
2593   
2594   return mark;
2595 }
2596
2597
2598 GtkTextMark*
2599 _gtk_text_btree_set_mark (GtkTextBTree *tree,
2600                          GtkTextMark  *existing_mark,
2601                          const gchar *name,
2602                          gboolean left_gravity,
2603                          const GtkTextIter *iter,
2604                          gboolean should_exist)
2605 {
2606   GtkTextLineSegment *seg;
2607
2608   seg = real_set_mark (tree, existing_mark,
2609                        name, left_gravity, iter, should_exist,
2610                        TRUE);
2611
2612   return seg ? seg->body.mark.obj : NULL;
2613 }
2614
2615 gboolean
2616 _gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
2617                                      GtkTextIter  *start,
2618                                      GtkTextIter  *end)
2619 {
2620   GtkTextIter tmp_start, tmp_end;
2621
2622   _gtk_text_btree_get_iter_at_mark (tree, &tmp_start,
2623                                    tree->insert_mark);
2624   _gtk_text_btree_get_iter_at_mark (tree, &tmp_end,
2625                                    tree->selection_bound_mark);
2626
2627   if (gtk_text_iter_equal (&tmp_start, &tmp_end))
2628     {
2629       if (start)
2630         *start = tmp_start;
2631
2632       if (end)
2633         *end = tmp_end;
2634
2635       return FALSE;
2636     }
2637   else
2638     {
2639       gtk_text_iter_order (&tmp_start, &tmp_end);
2640
2641       if (start)
2642         *start = tmp_start;
2643
2644       if (end)
2645         *end = tmp_end;
2646
2647       return TRUE;
2648     }
2649 }
2650
2651 void
2652 _gtk_text_btree_place_cursor (GtkTextBTree      *tree,
2653                              const GtkTextIter *iter)
2654 {
2655   GtkTextIter start, end;
2656
2657   if (_gtk_text_btree_get_selection_bounds (tree, &start, &end))
2658     redisplay_region (tree, &start, &end);
2659
2660   /* Move insert AND selection_bound before we redisplay */
2661   real_set_mark (tree, tree->insert_mark,
2662                  "insert", FALSE, iter, TRUE, FALSE);
2663   real_set_mark (tree, tree->selection_bound_mark,
2664                  "selection_bound", FALSE, iter, TRUE, FALSE);
2665 }
2666
2667 void
2668 _gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
2669                                     const gchar *name)
2670 {
2671   GtkTextMark *mark;
2672
2673   g_return_if_fail (tree != NULL);
2674   g_return_if_fail (name != NULL);
2675
2676   mark = g_hash_table_lookup (tree->mark_table,
2677                               name);
2678
2679   _gtk_text_btree_remove_mark (tree, mark);
2680 }
2681
2682 void
2683 _gtk_text_btree_remove_mark (GtkTextBTree *tree,
2684                             GtkTextMark *mark)
2685 {
2686   GtkTextLineSegment *segment;
2687
2688   g_return_if_fail (mark != NULL);
2689   g_return_if_fail (tree != NULL);
2690
2691   segment = mark->segment;
2692
2693   if (segment->body.mark.not_deleteable)
2694     {
2695       g_warning ("Can't delete special mark `%s'", segment->body.mark.name);
2696       return;
2697     }
2698
2699   /* This calls cleanup_line and segments_changed */
2700   gtk_text_btree_unlink_segment (tree, segment, segment->body.mark.line);
2701
2702   if (segment->body.mark.name)
2703     g_hash_table_remove (tree->mark_table, segment->body.mark.name);
2704
2705   /* Remove the ref on the mark that belonged to the segment. */
2706   g_object_unref (G_OBJECT (mark));
2707
2708   segment->body.mark.tree = NULL;
2709   segment->body.mark.line = NULL;
2710 }
2711
2712 gboolean
2713 _gtk_text_btree_mark_is_insert (GtkTextBTree *tree,
2714                                GtkTextMark *segment)
2715 {
2716   return segment == tree->insert_mark;
2717 }
2718
2719 gboolean
2720 _gtk_text_btree_mark_is_selection_bound (GtkTextBTree *tree,
2721                                         GtkTextMark *segment)
2722 {
2723   return segment == tree->selection_bound_mark;
2724 }
2725
2726 GtkTextMark*
2727 _gtk_text_btree_get_mark_by_name (GtkTextBTree *tree,
2728                                  const gchar *name)
2729 {
2730   GtkTextLineSegment *seg;
2731
2732   g_return_val_if_fail (tree != NULL, NULL);
2733   g_return_val_if_fail (name != NULL, NULL);
2734
2735   seg = g_hash_table_lookup (tree->mark_table, name);
2736
2737   return seg ? seg->body.mark.obj : NULL;
2738 }
2739
2740 /**
2741  * gtk_text_mark_set_visible:
2742  * @mark: a #GtkTextMark
2743  * @setting: visibility of mark
2744  * 
2745  * Sets the visibility of @mark; the insertion point is normally
2746  * visible, i.e. you can see it as a vertical bar. Also, the text
2747  * widget uses a visible mark to indicate where a drop will occur when
2748  * dragging-and-dropping text. Most other marks are not visible.
2749  * Marks are not visible by default.
2750  * 
2751  **/
2752 void
2753 gtk_text_mark_set_visible (GtkTextMark       *mark,
2754                            gboolean           setting)
2755 {
2756   GtkTextLineSegment *seg;
2757
2758   g_return_if_fail (mark != NULL);
2759
2760   seg = mark->segment;
2761
2762   if (seg->body.mark.visible == setting)
2763     return;
2764   else
2765     {
2766       seg->body.mark.visible = setting;
2767
2768       redisplay_mark (seg);
2769     }
2770 }
2771
2772 GtkTextLine*
2773 _gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree,
2774                                         GtkTextTag *tag)
2775 {
2776   GtkTextBTreeNode *node;
2777   GtkTextTagInfo *info;
2778
2779   g_return_val_if_fail (tree != NULL, NULL);
2780
2781   if (tag != NULL)
2782     {
2783       info = gtk_text_btree_get_existing_tag_info (tree, tag);
2784
2785       if (info == NULL)
2786         return NULL;
2787
2788       if (info->tag_root == NULL)
2789         return NULL;
2790
2791       node = info->tag_root;
2792
2793       /* We know the tag root has instances of the given
2794          tag below it */
2795
2796     continue_outer_loop:
2797       g_assert (node != NULL);
2798       while (node->level > 0)
2799         {
2800           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
2801           node = node->children.node;
2802           while (node != NULL)
2803             {
2804               if (gtk_text_btree_node_has_tag (node, tag))
2805                 goto continue_outer_loop;
2806
2807               node = node->next;
2808             }
2809           g_assert (node != NULL);
2810         }
2811
2812       g_assert (node != NULL); /* The tag summaries said some node had
2813                                   tag toggles... */
2814
2815       g_assert (node->level == 0);
2816
2817       return node->children.line;
2818     }
2819   else
2820     {
2821       /* Looking for any tag at all (tag == NULL).
2822          Unfortunately this can't be done in a simple and efficient way
2823          right now; so I'm just going to return the
2824          first line in the btree. FIXME */
2825       return _gtk_text_btree_get_line (tree, 0, NULL);
2826     }
2827 }
2828
2829 GtkTextLine*
2830 _gtk_text_btree_last_could_contain_tag (GtkTextBTree *tree,
2831                                        GtkTextTag *tag)
2832 {
2833   GtkTextBTreeNode *node;
2834   GtkTextBTreeNode *last_node;
2835   GtkTextLine *line;
2836   GtkTextTagInfo *info;
2837
2838   g_return_val_if_fail (tree != NULL, NULL);
2839
2840   if (tag != NULL)
2841     {
2842       info = gtk_text_btree_get_existing_tag_info (tree, tag);
2843
2844       if (info->tag_root == NULL)
2845         return NULL;
2846
2847       node = info->tag_root;
2848       /* We know the tag root has instances of the given
2849          tag below it */
2850
2851       while (node->level > 0)
2852         {
2853           g_assert (node != NULL); /* Failure probably means bad tag summaries. */
2854           last_node = NULL;
2855           node = node->children.node;
2856           while (node != NULL)
2857             {
2858               if (gtk_text_btree_node_has_tag (node, tag))
2859                 last_node = node;
2860               node = node->next;
2861             }
2862
2863           node = last_node;
2864         }
2865
2866       g_assert (node != NULL); /* The tag summaries said some node had
2867                                   tag toggles... */
2868
2869       g_assert (node->level == 0);
2870
2871       /* Find the last line in this node */
2872       line = node->children.line;
2873       while (line->next != NULL)
2874         line = line->next;
2875
2876       return line;
2877     }
2878   else
2879     {
2880       /* This search can't be done efficiently at the moment,
2881          at least not without complexity.
2882          So, we just return the last line.
2883       */
2884       return _gtk_text_btree_get_line (tree, -1, NULL);
2885     }
2886 }
2887
2888
2889 /*
2890  * Lines
2891  */
2892
2893 gint
2894 _gtk_text_line_get_number (GtkTextLine *line)
2895 {
2896   GtkTextLine *line2;
2897   GtkTextBTreeNode *node, *parent, *node2;
2898   int index;
2899
2900   /*
2901    * First count how many lines precede this one in its level-0
2902    * GtkTextBTreeNode.
2903    */
2904
2905   node = line->parent;
2906   index = 0;
2907   for (line2 = node->children.line; line2 != line;
2908        line2 = line2->next)
2909     {
2910       if (line2 == NULL)
2911         {
2912           g_error ("gtk_text_btree_line_number couldn't find line");
2913         }
2914       index += 1;
2915     }
2916
2917   /*
2918    * Now work up through the levels of the tree one at a time,
2919    * counting how many lines are in GtkTextBTreeNodes preceding the current
2920    * GtkTextBTreeNode.
2921    */
2922
2923   for (parent = node->parent ; parent != NULL;
2924        node = parent, parent = parent->parent)
2925     {
2926       for (node2 = parent->children.node; node2 != node;
2927            node2 = node2->next)
2928         {
2929           if (node2 == NULL)
2930             {
2931               g_error ("gtk_text_btree_line_number couldn't find GtkTextBTreeNode");
2932             }
2933           index += node2->num_lines;
2934         }
2935     }
2936   return index;
2937 }
2938
2939 static GtkTextLineSegment*
2940 find_toggle_segment_before_char (GtkTextLine *line,
2941                                  gint char_in_line,
2942                                  GtkTextTag *tag)
2943 {
2944   GtkTextLineSegment *seg;
2945   GtkTextLineSegment *toggle_seg;
2946   int index;
2947
2948   toggle_seg = NULL;
2949   index = 0;
2950   seg = line->segments;
2951   while ( (index + seg->char_count) <= char_in_line )
2952     {
2953       if (((seg->type == &gtk_text_toggle_on_type)
2954            || (seg->type == &gtk_text_toggle_off_type))
2955           && (seg->body.toggle.info->tag == tag))
2956         toggle_seg = seg;
2957
2958       index += seg->char_count;
2959       seg = seg->next;
2960     }
2961
2962   return toggle_seg;
2963 }
2964
2965 static GtkTextLineSegment*
2966 find_toggle_segment_before_byte (GtkTextLine *line,
2967                                  gint byte_in_line,
2968                                  GtkTextTag *tag)
2969 {
2970   GtkTextLineSegment *seg;
2971   GtkTextLineSegment *toggle_seg;
2972   int index;
2973
2974   toggle_seg = NULL;
2975   index = 0;
2976   seg = line->segments;
2977   while ( (index + seg->byte_count) <= byte_in_line )
2978     {
2979       if (((seg->type == &gtk_text_toggle_on_type)
2980            || (seg->type == &gtk_text_toggle_off_type))
2981           && (seg->body.toggle.info->tag == tag))
2982         toggle_seg = seg;
2983
2984       index += seg->byte_count;
2985       seg = seg->next;
2986     }
2987
2988   return toggle_seg;
2989 }
2990
2991 static gboolean
2992 find_toggle_outside_current_line (GtkTextLine *line,
2993                                   GtkTextBTree *tree,
2994                                   GtkTextTag *tag)
2995 {
2996   GtkTextBTreeNode *node;
2997   GtkTextLine *sibling_line;
2998   GtkTextLineSegment *seg;
2999   GtkTextLineSegment *toggle_seg;
3000   int toggles;
3001   GtkTextTagInfo *info = NULL;
3002
3003   /*
3004    * No toggle in this line.  Look for toggles for the tag in lines
3005    * that are predecessors of line but under the same
3006    * level-0 GtkTextBTreeNode.
3007    */
3008   toggle_seg = NULL;
3009   sibling_line = line->parent->children.line;
3010   while (sibling_line != line)
3011     {
3012       seg = sibling_line->segments;
3013       while (seg != NULL)
3014         {
3015           if (((seg->type == &gtk_text_toggle_on_type)
3016                || (seg->type == &gtk_text_toggle_off_type))
3017               && (seg->body.toggle.info->tag == tag))
3018             toggle_seg = seg;
3019
3020           seg = seg->next;
3021         }
3022
3023       sibling_line = sibling_line->next;
3024     }
3025
3026   if (toggle_seg != NULL)
3027     return (toggle_seg->type == &gtk_text_toggle_on_type);
3028
3029   /*
3030    * No toggle in this GtkTextBTreeNode.  Scan upwards through the ancestors of
3031    * this GtkTextBTreeNode, counting the number of toggles of the given tag in
3032    * siblings that precede that GtkTextBTreeNode.
3033    */
3034
3035   info = gtk_text_btree_get_existing_tag_info (tree, tag);
3036
3037   if (info == NULL)
3038     return FALSE;
3039
3040   toggles = 0;
3041   node = line->parent;
3042   while (node->parent != NULL)
3043     {
3044       GtkTextBTreeNode *sibling_node;
3045
3046       sibling_node = node->parent->children.node;
3047       while (sibling_node != node)
3048         {
3049           Summary *summary;
3050
3051           summary = sibling_node->summary;
3052           while (summary != NULL)
3053             {
3054               if (summary->info == info)
3055                 toggles += summary->toggle_count;
3056
3057               summary = summary->next;
3058             }
3059
3060           sibling_node = sibling_node->next;
3061         }
3062
3063       if (node == info->tag_root)
3064         break;
3065
3066       node = node->parent;
3067     }
3068
3069   /*
3070    * An odd number of toggles means that the tag is present at the
3071    * given point.
3072    */
3073
3074   return (toggles & 1) != 0;
3075 }
3076
3077 /* FIXME this function is far too slow, for no good reason. */
3078 gboolean
3079 _gtk_text_line_char_has_tag (GtkTextLine *line,
3080                             GtkTextBTree *tree,
3081                             gint char_in_line,
3082                             GtkTextTag *tag)
3083 {
3084   GtkTextLineSegment *toggle_seg;
3085
3086   g_return_val_if_fail (line != NULL, FALSE);
3087
3088   /*
3089    * Check for toggles for the tag in the line but before
3090    * the char.  If there is one, its type indicates whether or
3091    * not the character is tagged.
3092    */
3093
3094   toggle_seg = find_toggle_segment_before_char (line, char_in_line, tag);
3095
3096   if (toggle_seg != NULL)
3097     return (toggle_seg->type == &gtk_text_toggle_on_type);
3098   else
3099     return find_toggle_outside_current_line (line, tree, tag);
3100 }
3101
3102 gboolean
3103 _gtk_text_line_byte_has_tag (GtkTextLine *line,
3104                             GtkTextBTree *tree,
3105                             gint byte_in_line,
3106                             GtkTextTag *tag)
3107 {
3108   GtkTextLineSegment *toggle_seg;
3109
3110   g_return_val_if_fail (line != NULL, FALSE);
3111
3112   /*
3113    * Check for toggles for the tag in the line but before
3114    * the char.  If there is one, its type indicates whether or
3115    * not the character is tagged.
3116    */
3117
3118   toggle_seg = find_toggle_segment_before_byte (line, byte_in_line, tag);
3119
3120   if (toggle_seg != NULL)
3121     return (toggle_seg->type == &gtk_text_toggle_on_type);
3122   else
3123     return find_toggle_outside_current_line (line, tree, tag);
3124 }
3125
3126 gboolean
3127 _gtk_text_line_is_last (GtkTextLine *line,
3128                        GtkTextBTree *tree)
3129 {
3130   return line == get_last_line (tree);
3131 }
3132
3133 GtkTextLine*
3134 _gtk_text_line_next (GtkTextLine *line)
3135 {
3136   GtkTextBTreeNode *node;
3137
3138   if (line->next != NULL)
3139     return line->next;
3140   else
3141     {
3142       /*
3143        * This was the last line associated with the particular parent
3144        * GtkTextBTreeNode.  Search up the tree for the next GtkTextBTreeNode,
3145        * then search down from that GtkTextBTreeNode to find the first
3146        * line.
3147        */
3148
3149       node = line->parent;
3150       while (node != NULL && node->next == NULL)
3151         node = node->parent;
3152
3153       if (node == NULL)
3154         return NULL;
3155
3156       node = node->next;
3157       while (node->level > 0)
3158         {
3159           node = node->children.node;
3160         }
3161
3162       g_assert (node->children.line != line);
3163
3164       return node->children.line;
3165     }
3166 }
3167
3168 GtkTextLine*
3169 _gtk_text_line_previous (GtkTextLine *line)
3170 {
3171   GtkTextBTreeNode *node;
3172   GtkTextBTreeNode *node2;
3173   GtkTextLine *prev;
3174
3175   /*
3176    * Find the line under this GtkTextBTreeNode just before the starting line.
3177    */
3178   prev = line->parent->children.line;        /* First line at leaf */
3179   while (prev != line)
3180     {
3181       if (prev->next == line)
3182         return prev;
3183
3184       prev = prev->next;
3185
3186       if (prev == NULL)
3187         g_error ("gtk_text_btree_previous_line ran out of lines");
3188     }
3189
3190   /*
3191    * This was the first line associated with the particular parent
3192    * GtkTextBTreeNode.  Search up the tree for the previous GtkTextBTreeNode,
3193    * then search down from that GtkTextBTreeNode to find its last line.
3194    */
3195   for (node = line->parent; ; node = node->parent)
3196     {
3197       if (node == NULL || node->parent == NULL)
3198         return NULL;
3199       else if (node != node->parent->children.node)
3200         break;
3201     }
3202
3203   for (node2 = node->parent->children.node; ;
3204        node2 = node2->children.node)
3205     {
3206       while (node2->next != node)
3207         node2 = node2->next;
3208
3209       if (node2->level == 0)
3210         break;
3211
3212       node = NULL;
3213     }
3214
3215   for (prev = node2->children.line ; ; prev = prev->next)
3216     {
3217       if (prev->next == NULL)
3218         return prev;
3219     }
3220
3221   g_assert_not_reached ();
3222   return NULL;
3223 }
3224
3225 void
3226 _gtk_text_line_add_data (GtkTextLine     *line,
3227                         GtkTextLineData *data)
3228 {
3229   g_return_if_fail (line != NULL);
3230   g_return_if_fail (data != NULL);
3231   g_return_if_fail (data->view_id != NULL);
3232
3233   if (line->views)
3234     {
3235       data->next = line->views;
3236       line->views = data;
3237     }
3238   else
3239     {
3240       line->views = data;
3241     }
3242 }
3243
3244 gpointer
3245 _gtk_text_line_remove_data (GtkTextLine *line,
3246                            gpointer view_id)
3247 {
3248   GtkTextLineData *prev;
3249   GtkTextLineData *iter;
3250
3251   g_return_val_if_fail (line != NULL, NULL);
3252   g_return_val_if_fail (view_id != NULL, NULL);
3253
3254   prev = NULL;
3255   iter = line->views;
3256   while (iter != NULL)
3257     {
3258       if (iter->view_id == view_id)
3259         break;
3260       prev = iter;
3261       iter = iter->next;
3262     }
3263
3264   if (iter)
3265     {
3266       if (prev)
3267         prev->next = iter->next;
3268       else
3269         line->views = iter->next;
3270
3271       return iter;
3272     }
3273   else
3274     return NULL;
3275 }
3276
3277 gpointer
3278 _gtk_text_line_get_data (GtkTextLine *line,
3279                         gpointer view_id)
3280 {
3281   GtkTextLineData *iter;
3282
3283   g_return_val_if_fail (line != NULL, NULL);
3284   g_return_val_if_fail (view_id != NULL, NULL);
3285
3286   iter = line->views;
3287   while (iter != NULL)
3288     {
3289       if (iter->view_id == view_id)
3290         break;
3291       iter = iter->next;
3292     }
3293
3294   return iter;
3295 }
3296
3297 void
3298 _gtk_text_line_invalidate_wrap (GtkTextLine *line,
3299                                 GtkTextLineData *ld)
3300 {
3301   /* For now this is totally unoptimized. FIXME?
3302
3303      We could probably optimize the case where the width removed
3304      is less than the max width for the parent node,
3305      and the case where the height is unchanged when we re-wrap.
3306   */
3307   
3308   g_return_if_fail (ld != NULL);
3309   
3310   ld->valid = FALSE;
3311   gtk_text_btree_node_invalidate_upward (line->parent, ld->view_id);
3312 }
3313
3314 gint
3315 _gtk_text_line_char_count (GtkTextLine *line)
3316 {
3317   GtkTextLineSegment *seg;
3318   gint size;
3319
3320   size = 0;
3321   seg = line->segments;
3322   while (seg != NULL)
3323     {
3324       size += seg->char_count;
3325       seg = seg->next;
3326     }
3327   return size;
3328 }
3329
3330 gint
3331 _gtk_text_line_byte_count (GtkTextLine *line)
3332 {
3333   GtkTextLineSegment *seg;
3334   gint size;
3335
3336   size = 0;
3337   seg = line->segments;
3338   while (seg != NULL)
3339     {
3340       size += seg->byte_count;
3341       seg = seg->next;
3342     }
3343
3344   return size;
3345 }
3346
3347 gint
3348 _gtk_text_line_char_index (GtkTextLine *target_line)
3349 {
3350   GSList *node_stack = NULL;
3351   GtkTextBTreeNode *iter;
3352   GtkTextLine *line;
3353   gint num_chars;
3354
3355   /* Push all our parent nodes onto a stack */
3356   iter = target_line->parent;
3357
3358   g_assert (iter != NULL);
3359
3360   while (iter != NULL)
3361     {
3362       node_stack = g_slist_prepend (node_stack, iter);
3363
3364       iter = iter->parent;
3365     }
3366
3367   /* Check that we have the root node on top of the stack. */
3368   g_assert (node_stack != NULL &&
3369             node_stack->data != NULL &&
3370             ((GtkTextBTreeNode*)node_stack->data)->parent == NULL);
3371
3372   /* Add up chars in all nodes before the nodes in our stack.
3373    */
3374
3375   num_chars = 0;
3376   iter = node_stack->data;
3377   while (iter != NULL)
3378     {
3379       GtkTextBTreeNode *child_iter;
3380       GtkTextBTreeNode *next_node;
3381
3382       next_node = node_stack->next ?
3383         node_stack->next->data : NULL;
3384       node_stack = g_slist_remove (node_stack, node_stack->data);
3385
3386       if (iter->level == 0)
3387         {
3388           /* stack should be empty when we're on the last node */
3389           g_assert (node_stack == NULL);
3390           break; /* Our children are now lines */
3391         }
3392
3393       g_assert (next_node != NULL);
3394       g_assert (iter != NULL);
3395       g_assert (next_node->parent == iter);
3396
3397       /* Add up chars before us in the tree */
3398       child_iter = iter->children.node;
3399       while (child_iter != next_node)
3400         {
3401           g_assert (child_iter != NULL);
3402
3403           num_chars += child_iter->num_chars;
3404
3405           child_iter = child_iter->next;
3406         }
3407
3408       iter = next_node;
3409     }
3410
3411   g_assert (iter != NULL);
3412   g_assert (iter == target_line->parent);
3413
3414   /* Since we don't store char counts in lines, only in segments, we
3415      have to iterate over the lines adding up segment char counts
3416      until we find our line.  */
3417   line = iter->children.line;
3418   while (line != target_line)
3419     {
3420       g_assert (line != NULL);
3421
3422       num_chars += _gtk_text_line_char_count (line);
3423
3424       line = line->next;
3425     }
3426
3427   g_assert (line == target_line);
3428
3429   return num_chars;
3430 }
3431
3432 GtkTextLineSegment*
3433 _gtk_text_line_byte_to_segment (GtkTextLine *line,
3434                                gint byte_offset,
3435                                gint *seg_offset)
3436 {
3437   GtkTextLineSegment *seg;
3438   int offset;
3439
3440   g_return_val_if_fail (line != NULL, NULL);
3441
3442   offset = byte_offset;
3443   seg = line->segments;
3444
3445   while (offset >= seg->byte_count)
3446     {
3447       g_assert (seg != NULL); /* means an invalid byte index */
3448       offset -= seg->byte_count;
3449       seg = seg->next;
3450     }
3451
3452   if (seg_offset)
3453     *seg_offset = offset;
3454
3455   return seg;
3456 }
3457
3458 GtkTextLineSegment*
3459 _gtk_text_line_char_to_segment (GtkTextLine *line,
3460                                gint char_offset,
3461                                gint *seg_offset)
3462 {
3463   GtkTextLineSegment *seg;
3464   int offset;
3465
3466   g_return_val_if_fail (line != NULL, NULL);
3467
3468   offset = char_offset;
3469   seg = line->segments;
3470
3471   while (offset >= seg->char_count)
3472     {
3473       g_assert (seg != NULL); /* means an invalid char index */
3474       offset -= seg->char_count;
3475       seg = seg->next;
3476     }
3477
3478   if (seg_offset)
3479     *seg_offset = offset;
3480
3481   return seg;
3482 }
3483
3484 GtkTextLineSegment*
3485 _gtk_text_line_byte_to_any_segment (GtkTextLine *line,
3486                                    gint byte_offset,
3487                                    gint *seg_offset)
3488 {
3489   GtkTextLineSegment *seg;
3490   int offset;
3491
3492   g_return_val_if_fail (line != NULL, NULL);
3493
3494   offset = byte_offset;
3495   seg = line->segments;
3496
3497   while (offset > 0 && offset >= seg->byte_count)
3498     {
3499       g_assert (seg != NULL); /* means an invalid byte index */
3500       offset -= seg->byte_count;
3501       seg = seg->next;
3502     }
3503
3504   if (seg_offset)
3505     *seg_offset = offset;
3506
3507   return seg;
3508 }
3509
3510 GtkTextLineSegment*
3511 _gtk_text_line_char_to_any_segment (GtkTextLine *line,
3512                                    gint char_offset,
3513                                    gint *seg_offset)
3514 {
3515   GtkTextLineSegment *seg;
3516   int offset;
3517
3518   g_return_val_if_fail (line != NULL, NULL);
3519
3520   offset = char_offset;
3521   seg = line->segments;
3522
3523   while (offset > 0 && offset >= seg->char_count)
3524     {
3525       g_assert (seg != NULL); /* means an invalid byte index */
3526       offset -= seg->char_count;
3527       seg = seg->next;
3528     }
3529
3530   if (seg_offset)
3531     *seg_offset = offset;
3532
3533   return seg;
3534 }
3535
3536 gint
3537 _gtk_text_line_byte_to_char (GtkTextLine *line,
3538                             gint byte_offset)
3539 {
3540   gint char_offset;
3541   GtkTextLineSegment *seg;
3542
3543   g_return_val_if_fail (line != NULL, 0);
3544   g_return_val_if_fail (byte_offset >= 0, 0);
3545
3546   char_offset = 0;
3547   seg = line->segments;
3548   while (byte_offset >= seg->byte_count) /* while (we need to go farther than
3549                                             the next segment) */
3550     {
3551       g_assert (seg != NULL); /* our byte_index was bogus if this happens */
3552
3553       byte_offset -= seg->byte_count;
3554       char_offset += seg->char_count;
3555
3556       seg = seg->next;
3557     }
3558
3559   g_assert (seg != NULL);
3560
3561   /* Now byte_offset is the offset into the current segment,
3562      and char_offset is the start of the current segment.
3563      Optimize the case where no chars use > 1 byte */
3564   if (seg->byte_count == seg->char_count)
3565     return char_offset + byte_offset;
3566   else
3567     {
3568       if (seg->type == &gtk_text_char_type)
3569         return char_offset + g_utf8_strlen (seg->body.chars, byte_offset);
3570       else
3571         {
3572           g_assert (seg->char_count == 1);
3573           g_assert (byte_offset == 0);
3574
3575           return char_offset;
3576         }
3577     }
3578 }
3579
3580 gint
3581 _gtk_text_line_char_to_byte (GtkTextLine *line,
3582                             gint         char_offset)
3583 {
3584   g_warning ("FIXME not implemented");
3585
3586   return 0;
3587 }
3588
3589 /* FIXME sync with char_locate (or figure out a clean
3590    way to merge the two functions) */
3591 gboolean
3592 _gtk_text_line_byte_locate (GtkTextLine *line,
3593                             gint byte_offset,
3594                             GtkTextLineSegment **segment,
3595                             GtkTextLineSegment **any_segment,
3596                             gint *seg_byte_offset,
3597                             gint *line_byte_offset)
3598 {
3599   GtkTextLineSegment *seg;
3600   GtkTextLineSegment *after_prev_indexable;
3601   GtkTextLineSegment *after_last_indexable;
3602   GtkTextLineSegment *last_indexable;
3603   gint offset;
3604   gint bytes_in_line;
3605
3606   g_return_val_if_fail (line != NULL, FALSE);
3607   g_return_val_if_fail (byte_offset >= 0, FALSE);
3608
3609   *segment = NULL;
3610   *any_segment = NULL;
3611   bytes_in_line = 0;
3612
3613   offset = byte_offset;
3614
3615   last_indexable = NULL;
3616   after_last_indexable = line->segments;
3617   after_prev_indexable = line->segments;
3618   seg = line->segments;
3619
3620   /* The loop ends when we're inside a segment;
3621      last_indexable refers to the last segment
3622      we passed entirely. */
3623   while (seg && offset >= seg->byte_count)
3624     {
3625       if (seg->char_count > 0)
3626         {
3627           offset -= seg->byte_count;
3628           bytes_in_line += seg->byte_count;
3629           last_indexable = seg;
3630           after_prev_indexable = after_last_indexable;
3631           after_last_indexable = last_indexable->next;
3632         }
3633
3634       seg = seg->next;
3635     }
3636
3637   if (seg == NULL)
3638     {
3639       /* We went off the end of the line */
3640       if (offset != 0)
3641         g_warning ("%s: byte index off the end of the line", G_STRLOC);
3642
3643       return FALSE;
3644     }
3645   else
3646     {
3647       *segment = seg;
3648       if (after_last_indexable != NULL)
3649         *any_segment = after_last_indexable;
3650       else
3651         *any_segment = *segment;
3652     }
3653
3654   /* Override any_segment if we're in the middle of a segment. */
3655   if (offset > 0)
3656     *any_segment = *segment;
3657
3658   *seg_byte_offset = offset;
3659
3660   g_assert (*segment != NULL);
3661   g_assert (*any_segment != NULL);
3662   g_assert (*seg_byte_offset < (*segment)->byte_count);
3663
3664   *line_byte_offset = bytes_in_line + *seg_byte_offset;
3665
3666   return TRUE;
3667 }
3668
3669 /* FIXME sync with byte_locate (or figure out a clean
3670    way to merge the two functions) */
3671 gboolean
3672 _gtk_text_line_char_locate     (GtkTextLine     *line,
3673                                 gint              char_offset,
3674                                 GtkTextLineSegment **segment,
3675                                 GtkTextLineSegment **any_segment,
3676                                 gint             *seg_char_offset,
3677                                 gint             *line_char_offset)
3678 {
3679   GtkTextLineSegment *seg;
3680   GtkTextLineSegment *after_prev_indexable;
3681   GtkTextLineSegment *after_last_indexable;
3682   GtkTextLineSegment *last_indexable;
3683   gint offset;
3684   gint chars_in_line;
3685
3686   g_return_val_if_fail (line != NULL, FALSE);
3687   g_return_val_if_fail (char_offset >= 0, FALSE);
3688   
3689   *segment = NULL;
3690   *any_segment = NULL;
3691   chars_in_line = 0;
3692
3693   offset = char_offset;
3694
3695   last_indexable = NULL;
3696   after_last_indexable = line->segments;
3697   after_prev_indexable = line->segments;
3698   seg = line->segments;
3699
3700   /* The loop ends when we're inside a segment;
3701      last_indexable refers to the last segment
3702      we passed entirely. */
3703   while (seg && offset >= seg->char_count)
3704     {
3705       if (seg->char_count > 0)
3706         {
3707           offset -= seg->char_count;
3708           chars_in_line += seg->char_count;
3709           last_indexable = seg;
3710           after_prev_indexable = after_last_indexable;
3711           after_last_indexable = last_indexable->next;
3712         }
3713
3714       seg = seg->next;
3715     }
3716
3717   if (seg == NULL)
3718     {
3719       /* end of the line */
3720       if (offset != 0)
3721         g_warning ("%s: char offset off the end of the line", G_STRLOC);
3722
3723       return FALSE;
3724     }
3725   else
3726     {
3727       *segment = seg;
3728       if (after_last_indexable != NULL)
3729         *any_segment = after_last_indexable;
3730       else
3731         *any_segment = *segment;
3732     }
3733
3734   /* Override any_segment if we're in the middle of a segment. */
3735   if (offset > 0)
3736     *any_segment = *segment;
3737
3738   *seg_char_offset = offset;
3739
3740   g_assert (*segment != NULL);
3741   g_assert (*any_segment != NULL);
3742   g_assert (*seg_char_offset < (*segment)->char_count);
3743
3744   *line_char_offset = chars_in_line + *seg_char_offset;
3745
3746   return TRUE;
3747 }
3748
3749 void
3750 _gtk_text_line_byte_to_char_offsets (GtkTextLine *line,
3751                                     gint byte_offset,
3752                                     gint *line_char_offset,
3753                                     gint *seg_char_offset)
3754 {
3755   GtkTextLineSegment *seg;
3756   int offset;
3757
3758   g_return_if_fail (line != NULL);
3759   g_return_if_fail (byte_offset >= 0);
3760
3761   *line_char_offset = 0;
3762
3763   offset = byte_offset;
3764   seg = line->segments;
3765
3766   while (offset >= seg->byte_count)
3767     {
3768       offset -= seg->byte_count;
3769       *line_char_offset += seg->char_count;
3770       seg = seg->next;
3771       g_assert (seg != NULL); /* means an invalid char offset */
3772     }
3773
3774   g_assert (seg->char_count > 0); /* indexable. */
3775
3776   /* offset is now the number of bytes into the current segment we
3777    * want to go. Count chars into the current segment.
3778    */
3779
3780   if (seg->type == &gtk_text_char_type)
3781     {
3782       *seg_char_offset = g_utf8_strlen (seg->body.chars, offset);
3783
3784       g_assert (*seg_char_offset < seg->char_count);
3785
3786       *line_char_offset += *seg_char_offset;
3787     }
3788   else
3789     {
3790       g_assert (offset == 0);
3791       *seg_char_offset = 0;
3792     }
3793 }
3794
3795 void
3796 _gtk_text_line_char_to_byte_offsets (GtkTextLine *line,
3797                                     gint char_offset,
3798                                     gint *line_byte_offset,
3799                                     gint *seg_byte_offset)
3800 {
3801   GtkTextLineSegment *seg;
3802   int offset;
3803
3804   g_return_if_fail (line != NULL);
3805   g_return_if_fail (char_offset >= 0);
3806
3807   *line_byte_offset = 0;
3808
3809   offset = char_offset;
3810   seg = line->segments;
3811
3812   while (offset >= seg->char_count)
3813     {
3814       offset -= seg->char_count;
3815       *line_byte_offset += seg->byte_count;
3816       seg = seg->next;
3817       g_assert (seg != NULL); /* means an invalid char offset */
3818     }
3819
3820   g_assert (seg->char_count > 0); /* indexable. */
3821
3822   /* offset is now the number of chars into the current segment we
3823      want to go. Count bytes into the current segment. */
3824
3825   if (seg->type == &gtk_text_char_type)
3826     {
3827       *seg_byte_offset = 0;
3828       while (offset > 0)
3829         {
3830           gint bytes;
3831           const char * start = seg->body.chars + *seg_byte_offset;
3832
3833           bytes = g_utf8_next_char (start) - start;
3834           *seg_byte_offset += bytes;
3835           offset -= 1;
3836         }
3837
3838       g_assert (*seg_byte_offset < seg->byte_count);
3839
3840       *line_byte_offset += *seg_byte_offset;
3841     }
3842   else
3843     {
3844       g_assert (offset == 0);
3845       *seg_byte_offset = 0;
3846     }
3847 }
3848
3849 static gint
3850 node_compare (GtkTextBTreeNode *lhs,
3851               GtkTextBTreeNode *rhs)
3852 {
3853   GtkTextBTreeNode *iter;
3854   GtkTextBTreeNode *node;
3855   GtkTextBTreeNode *common_parent;
3856   GtkTextBTreeNode *parent_of_lower;
3857   GtkTextBTreeNode *parent_of_higher;
3858   gboolean lhs_is_lower;
3859   GtkTextBTreeNode *lower;
3860   GtkTextBTreeNode *higher;
3861
3862   /* This function assumes that lhs and rhs are not underneath each
3863    * other.
3864    */
3865
3866   if (lhs == rhs)
3867     return 0;
3868
3869   if (lhs->level < rhs->level)
3870     {
3871       lhs_is_lower = TRUE;
3872       lower = lhs;
3873       higher = rhs;
3874     }
3875   else
3876     {
3877       lhs_is_lower = FALSE;
3878       lower = rhs;
3879       higher = lhs;
3880     }
3881
3882   /* Algorithm: find common parent of lhs/rhs. Save the child nodes
3883    * of the common parent we used to reach the common parent; the
3884    * ordering of these child nodes in the child list is the ordering
3885    * of lhs and rhs.
3886    */
3887
3888   /* Get on the same level (may be on same level already) */
3889   node = lower;
3890   while (node->level < higher->level)
3891     node = node->parent;
3892
3893   g_assert (node->level == higher->level);
3894
3895   g_assert (node != higher); /* Happens if lower is underneath higher */
3896
3897   /* Go up until we have two children with a common parent.
3898    */
3899   parent_of_lower = node;
3900   parent_of_higher = higher;
3901
3902   while (parent_of_lower->parent != parent_of_higher->parent)
3903     {
3904       parent_of_lower = parent_of_lower->parent;
3905       parent_of_higher = parent_of_higher->parent;
3906     }
3907
3908   g_assert (parent_of_lower->parent == parent_of_higher->parent);
3909
3910   common_parent = parent_of_lower->parent;
3911
3912   g_assert (common_parent != NULL);
3913
3914   /* See which is first in the list of common_parent's children */
3915   iter = common_parent->children.node;
3916   while (iter != NULL)
3917     {
3918       if (iter == parent_of_higher)
3919         {
3920           /* higher is less than lower */
3921
3922           if (lhs_is_lower)
3923             return 1; /* lhs > rhs */
3924           else
3925             return -1;
3926         }
3927       else if (iter == parent_of_lower)
3928         {
3929           /* lower is less than higher */
3930
3931           if (lhs_is_lower)
3932             return -1; /* lhs < rhs */
3933           else
3934             return 1;
3935         }
3936
3937       iter = iter->next;
3938     }
3939
3940   g_assert_not_reached ();
3941   return 0;
3942 }
3943
3944 /* remember that tag == NULL means "any tag" */
3945 GtkTextLine*
3946 _gtk_text_line_next_could_contain_tag (GtkTextLine *line,
3947                                       GtkTextBTree *tree,
3948                                       GtkTextTag  *tag)
3949 {
3950   GtkTextBTreeNode *node;
3951   GtkTextTagInfo *info;
3952   gboolean below_tag_root;
3953
3954   g_return_val_if_fail (line != NULL, NULL);
3955
3956   if (gtk_debug_flags & GTK_DEBUG_TEXT)
3957     _gtk_text_btree_check (tree);
3958
3959   if (tag == NULL)
3960     {
3961       /* Right now we can only offer linear-search if the user wants
3962        * to know about any tag toggle at all.
3963        */
3964       return _gtk_text_line_next (line);
3965     }
3966
3967   /* Our tag summaries only have node precision, not line
3968      precision. This means that if any line under a node could contain a
3969      tag, then any of the others could also contain a tag.
3970
3971      In the future we could have some mechanism to keep track of how
3972      many toggles we've found under a node so far, since we have a
3973      count of toggles under the node. But for now I'm going with KISS.
3974   */
3975
3976   /* return same-node line, if any. */
3977   if (line->next)
3978     return line->next;
3979
3980   info = gtk_text_btree_get_existing_tag_info (tree, tag);
3981   if (info == NULL)
3982     return NULL;
3983
3984   if (info->tag_root == NULL)
3985     return NULL;
3986
3987   if (info->tag_root == line->parent)
3988     return NULL; /* we were at the last line under the tag root */
3989
3990   /* We need to go up out of this node, and on to the next one with
3991      toggles for the target tag. If we're below the tag root, we need to
3992      find the next node below the tag root that has tag summaries. If
3993      we're not below the tag root, we need to see if the tag root is
3994      after us in the tree, and if so, return the first line underneath
3995      the tag root. */
3996
3997   node = line->parent;
3998   below_tag_root = FALSE;
3999   while (node != NULL)
4000     {
4001       if (node == info->tag_root)
4002         {
4003           below_tag_root = TRUE;
4004           break;
4005         }
4006
4007       node = node->parent;
4008     }
4009
4010   if (below_tag_root)
4011     {
4012       node = line->parent;
4013       while (node != info->tag_root)
4014         {
4015           if (node->next == NULL)
4016             node = node->parent;
4017           else
4018             {
4019               node = node->next;
4020
4021               if (gtk_text_btree_node_has_tag (node, tag))
4022                 goto found;
4023             }
4024         }
4025       return NULL;
4026     }
4027   else
4028     {
4029       gint ordering;
4030
4031       ordering = node_compare (line->parent, info->tag_root);
4032
4033       if (ordering < 0)
4034         {
4035           /* Tag root is ahead of us, so search there. */
4036           node = info->tag_root;
4037           goto found;
4038         }
4039       else
4040         {
4041           /* Tag root is after us, so no more lines that
4042            * could contain the tag.
4043            */
4044           return NULL;
4045         }
4046
4047       g_assert_not_reached ();
4048     }
4049
4050  found:
4051
4052   g_assert (node != NULL);
4053
4054   /* We have to find the first sub-node of this node that contains
4055    * the target tag.
4056    */
4057
4058   while (node->level > 0)
4059     {
4060       g_assert (node != NULL); /* If this fails, it likely means an
4061                                   incorrect tag summary led us on a
4062                                   wild goose chase down this branch of
4063                                   the tree. */
4064       node = node->children.node;
4065       while (node != NULL)
4066         {
4067           if (gtk_text_btree_node_has_tag (node, tag))
4068             break;
4069           node = node->next;
4070         }
4071     }
4072
4073   g_assert (node != NULL);
4074   g_assert (node->level == 0);
4075
4076   return node->children.line;
4077 }
4078
4079 static GtkTextLine*
4080 prev_line_under_node (GtkTextBTreeNode *node,
4081                       GtkTextLine      *line)
4082 {
4083   GtkTextLine *prev;
4084
4085   prev = node->children.line;
4086
4087   g_assert (prev);
4088
4089   if (prev != line)
4090     {
4091       while (prev->next != line)
4092         prev = prev->next;
4093
4094       return prev;
4095     }
4096
4097   return NULL;
4098 }
4099
4100 GtkTextLine*
4101 _gtk_text_line_previous_could_contain_tag (GtkTextLine  *line,
4102                                           GtkTextBTree *tree,
4103                                           GtkTextTag   *tag)
4104 {
4105   GtkTextBTreeNode *node;
4106   GtkTextBTreeNode *found_node = NULL;
4107   GtkTextTagInfo *info;
4108   gboolean below_tag_root;
4109   GtkTextLine *prev;
4110   GtkTextBTreeNode *line_ancestor;
4111   GtkTextBTreeNode *line_ancestor_parent;
4112
4113   /* See next_could_contain_tag () for more extensive comments
4114    * on what's going on here.
4115    */
4116
4117   g_return_val_if_fail (line != NULL, NULL);
4118
4119   if (gtk_debug_flags & GTK_DEBUG_TEXT)
4120     _gtk_text_btree_check (tree);
4121
4122   if (tag == NULL)
4123     {
4124       /* Right now we can only offer linear-search if the user wants
4125        * to know about any tag toggle at all.
4126        */
4127       return _gtk_text_line_previous (line);
4128     }
4129
4130   /* Return same-node line, if any. */
4131   prev = prev_line_under_node (line->parent, line);
4132   if (prev)
4133     return prev;
4134
4135   info = gtk_text_btree_get_existing_tag_info (tree, tag);
4136   if (info == NULL)
4137     return NULL;
4138
4139   if (info->tag_root == NULL)
4140     return NULL;
4141
4142   if (info->tag_root == line->parent)
4143     return NULL; /* we were at the first line under the tag root */
4144
4145   /* Are we below the tag root */
4146   node = line->parent;
4147   below_tag_root = FALSE;
4148   while (node != NULL)
4149     {
4150       if (node == info->tag_root)
4151         {
4152           below_tag_root = TRUE;
4153           break;
4154         }
4155
4156       node = node->parent;
4157     }
4158
4159   if (below_tag_root)
4160     {
4161       /* Look for a previous node under this tag root that has our
4162        * tag.
4163        */
4164
4165       /* this assertion holds because line->parent is not the
4166        * tag root, we are below the tag root, and the tag
4167        * root exists.
4168        */
4169       g_assert (line->parent->parent != NULL);
4170
4171       line_ancestor = line->parent;
4172       line_ancestor_parent = line->parent->parent;
4173
4174       node = line_ancestor_parent->children.node;
4175       while (node != line_ancestor &&
4176              line_ancestor != info->tag_root)
4177         {
4178           GSList *child_nodes = NULL;
4179           GSList *tmp;
4180
4181           /* Create reverse-order list of nodes before
4182            * line_ancestor
4183            */
4184           while (node != line_ancestor
4185                  && node != NULL)
4186             {
4187               child_nodes = g_slist_prepend (child_nodes, node);
4188
4189               node = node->next;
4190             }
4191
4192           /* Try to find a node with our tag on it in the list */
4193           tmp = child_nodes;
4194           while (tmp != NULL)
4195             {
4196               GtkTextBTreeNode *this_node = tmp->data;
4197
4198               g_assert (this_node != line_ancestor);
4199
4200               if (gtk_text_btree_node_has_tag (this_node, tag))
4201                 {
4202                   found_node = this_node;
4203                   g_slist_free (child_nodes);
4204                   goto found;
4205                 }
4206
4207               tmp = g_slist_next (tmp);
4208             }
4209
4210           g_slist_free (child_nodes);
4211
4212           /* Didn't find anything on this level; go up one level. */
4213           line_ancestor = line_ancestor_parent;
4214           line_ancestor_parent = line_ancestor->parent;
4215
4216           node = line_ancestor_parent->children.node;
4217         }
4218
4219       /* No dice. */
4220       return NULL;
4221     }
4222   else
4223     {
4224       gint ordering;
4225
4226       ordering = node_compare (line->parent, info->tag_root);
4227
4228       if (ordering < 0)
4229         {
4230           /* Tag root is ahead of us, so no more lines
4231            * with this tag.
4232            */
4233           return NULL;
4234         }
4235       else
4236         {
4237           /* Tag root is after us, so grab last tagged
4238            * line underneath the tag root.
4239            */
4240           found_node = info->tag_root;
4241           goto found;
4242         }
4243
4244       g_assert_not_reached ();
4245     }
4246
4247  found:
4248
4249   g_assert (found_node != NULL);
4250
4251   /* We have to find the last sub-node of this node that contains
4252    * the target tag.
4253    */
4254   node = found_node;
4255
4256   while (node->level > 0)
4257     {
4258       GSList *child_nodes = NULL;
4259       GSList *iter;
4260       g_assert (node != NULL); /* If this fails, it likely means an
4261                                   incorrect tag summary led us on a
4262                                   wild goose chase down this branch of
4263                                   the tree. */
4264
4265       node = node->children.node;
4266       while (node != NULL)
4267         {
4268           child_nodes = g_slist_prepend (child_nodes, node);
4269           node = node->next;
4270         }
4271
4272       node = NULL; /* detect failure to find a child node. */
4273
4274       iter = child_nodes;
4275       while (iter != NULL)
4276         {
4277           if (gtk_text_btree_node_has_tag (iter->data, tag))
4278             {
4279               /* recurse into this node. */
4280               node = iter->data;
4281               break;
4282             }
4283
4284           iter = g_slist_next (iter);
4285         }
4286
4287       g_slist_free (child_nodes);
4288
4289       g_assert (node != NULL);
4290     }
4291
4292   g_assert (node != NULL);
4293   g_assert (node->level == 0);
4294
4295   /* this assertion is correct, but slow. */
4296   /* g_assert (node_compare (node, line->parent) < 0); */
4297
4298   /* Return last line in this node. */
4299
4300   prev = node->children.line;
4301   while (prev->next)
4302     prev = prev->next;
4303
4304   return prev;
4305 }
4306
4307 /*
4308  * Non-public function implementations
4309  */
4310
4311 static void
4312 summary_list_destroy (Summary *summary)
4313 {
4314   Summary *next;
4315   while (summary != NULL)
4316     {
4317       next = summary->next;
4318       summary_destroy (summary);
4319       summary = next;
4320     }
4321 }
4322
4323 static GtkTextLine*
4324 get_last_line (GtkTextBTree *tree)
4325 {
4326   if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
4327     {
4328       gint n_lines;
4329       GtkTextLine *line;
4330       gint real_line;
4331
4332       n_lines = _gtk_text_btree_line_count (tree);
4333
4334       g_assert (n_lines >= 1); /* num_lines doesn't return bogus last line. */
4335
4336       line = _gtk_text_btree_get_line (tree, n_lines, &real_line);
4337
4338       tree->end_iter_line_stamp = tree->chars_changed_stamp;
4339       tree->end_iter_line = line;
4340     }
4341
4342   return tree->end_iter_line;
4343 }
4344
4345 /*
4346  * Lines
4347  */
4348
4349 static GtkTextLine*
4350 gtk_text_line_new (void)
4351 {
4352   GtkTextLine *line;
4353
4354   line = g_new0(GtkTextLine, 1);
4355
4356   return line;
4357 }
4358
4359 static void
4360 gtk_text_line_destroy (GtkTextBTree *tree, GtkTextLine *line)
4361 {
4362   GtkTextLineData *ld;
4363   GtkTextLineData *next;
4364
4365   g_return_if_fail (line != NULL);
4366
4367   ld = line->views;
4368   while (ld != NULL)
4369     {
4370       BTreeView *view;
4371
4372       view = gtk_text_btree_get_view (tree, ld->view_id);
4373
4374       g_assert (view != NULL);
4375
4376       next = ld->next;
4377       gtk_text_layout_free_line_data (view->layout, line, ld);
4378
4379       ld = next;
4380     }
4381
4382   g_free (line);
4383 }
4384
4385 static void
4386 gtk_text_line_set_parent (GtkTextLine *line,
4387                           GtkTextBTreeNode *node)
4388 {
4389   if (line->parent == node)
4390     return;
4391   line->parent = node;
4392   gtk_text_btree_node_invalidate_upward (node, NULL);
4393 }
4394
4395 static void
4396 cleanup_line (GtkTextLine *line)
4397 {
4398   GtkTextLineSegment *seg, **prev_p;
4399   gboolean changed;
4400
4401   /*
4402    * Make a pass over all of the segments in the line, giving each
4403    * a chance to clean itself up.  This could potentially change
4404    * the structure of the line, e.g. by merging two segments
4405    * together or having two segments cancel themselves;  if so,
4406    * then repeat the whole process again, since the first structure
4407    * change might make other structure changes possible.  Repeat
4408    * until eventually there are no changes.
4409    */
4410
4411   changed = TRUE;
4412   while (changed)
4413     {
4414       changed = FALSE;
4415       for (prev_p = &line->segments, seg = *prev_p;
4416            seg != NULL;
4417            prev_p = &(*prev_p)->next, seg = *prev_p)
4418         {
4419           if (seg->type->cleanupFunc != NULL)
4420             {
4421               *prev_p = (*seg->type->cleanupFunc)(seg, line);
4422               if (seg != *prev_p)
4423                 changed = TRUE;
4424             }
4425         }
4426     }
4427 }
4428
4429 /*
4430  * Nodes
4431  */
4432
4433 static NodeData*
4434 node_data_new (gpointer view_id)
4435 {
4436   NodeData *nd;
4437   
4438   nd = g_new (NodeData, 1);
4439
4440   nd->view_id = view_id;
4441   nd->next = NULL;
4442   nd->width = 0;
4443   nd->height = 0;
4444   nd->valid = FALSE;
4445
4446   return nd;
4447 }
4448
4449 static void
4450 node_data_destroy (NodeData *nd)
4451 {
4452   g_free (nd);
4453 }
4454
4455 static void
4456 node_data_list_destroy (NodeData *nd)
4457 {
4458   NodeData *iter;
4459   NodeData *next;
4460
4461   iter = nd;
4462   while (iter != NULL)
4463     {
4464       next = iter->next;
4465       node_data_destroy (iter);
4466       iter = next;
4467     }
4468 }
4469
4470 static NodeData*
4471 node_data_find (NodeData *nd, gpointer view_id)
4472 {
4473   while (nd != NULL)
4474     {
4475       if (nd->view_id == view_id)
4476         break;
4477       nd = nd->next;
4478     }
4479   return nd;
4480 }
4481
4482 static void
4483 summary_destroy (Summary *summary)
4484 {
4485   /* Fill with error-triggering garbage */
4486   summary->info = (void*)0x1;
4487   summary->toggle_count = 567;
4488   summary->next = (void*)0x1;
4489   g_free (summary);
4490 }
4491
4492 static GtkTextBTreeNode*
4493 gtk_text_btree_node_new (void)
4494 {
4495   GtkTextBTreeNode *node;
4496
4497   node = g_new (GtkTextBTreeNode, 1);
4498
4499   node->node_data = NULL;
4500
4501   return node;
4502 }
4503
4504 static void
4505 gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode  *node,
4506                                          GtkTextTagInfo  *info,
4507                                          gint adjust)
4508 {
4509   Summary *summary;
4510
4511   summary = node->summary;
4512   while (summary != NULL)
4513     {
4514       if (summary->info == info)
4515         {
4516           summary->toggle_count += adjust;
4517           break;
4518         }
4519
4520       summary = summary->next;
4521     }
4522
4523   if (summary == NULL)
4524     {
4525       /* didn't find a summary for our tag. */
4526       g_return_if_fail (adjust > 0);
4527       summary = g_new (Summary, 1);
4528       summary->info = info;
4529       summary->toggle_count = adjust;
4530       summary->next = node->summary;
4531       node->summary = summary;
4532     }
4533 }
4534
4535 /* Note that the tag root and above do not have summaries
4536    for the tag; only nodes below the tag root have
4537    the summaries. */
4538 static gboolean
4539 gtk_text_btree_node_has_tag (GtkTextBTreeNode *node, GtkTextTag *tag)
4540 {
4541   Summary *summary;
4542
4543   summary = node->summary;
4544   while (summary != NULL)
4545     {
4546       if (tag == NULL ||
4547           summary->info->tag == tag)
4548         return TRUE;
4549
4550       summary = summary->next;
4551     }
4552
4553   return FALSE;
4554 }
4555
4556 /* Add node and all children to the damage region. */
4557 static void
4558 gtk_text_btree_node_invalidate_downward (GtkTextBTreeNode *node)
4559 {
4560   NodeData *nd;
4561
4562   nd = node->node_data;
4563   while (nd != NULL)
4564     {
4565       nd->valid = FALSE;
4566       nd = nd->next;
4567     }
4568
4569   if (node->level == 0)
4570     {
4571       GtkTextLine *line;
4572
4573       line = node->children.line;
4574       while (line != NULL)
4575         {
4576           GtkTextLineData *ld;
4577
4578           ld = line->views;
4579           while (ld != NULL)
4580             {
4581               ld->valid = FALSE;
4582               ld = ld->next;
4583             }
4584
4585           line = line->next;
4586         }
4587     }
4588   else
4589     {
4590       GtkTextBTreeNode *child;
4591
4592       child = node->children.node;
4593
4594       while (child != NULL)
4595         {
4596           gtk_text_btree_node_invalidate_downward (child);
4597
4598           child = child->next;
4599         }
4600     }
4601 }
4602
4603 static void
4604 gtk_text_btree_node_invalidate_upward (GtkTextBTreeNode *node, gpointer view_id)
4605 {
4606   GtkTextBTreeNode *iter;
4607
4608   iter = node;
4609   while (iter != NULL)
4610     {
4611       NodeData *nd;
4612
4613       if (view_id)
4614         {
4615           nd = node_data_find (iter->node_data, view_id);
4616
4617           if (nd == NULL || !nd->valid)
4618             break; /* Once a node is invalid, we know its parents are as well. */
4619
4620           nd->valid = FALSE;
4621         }
4622       else
4623         {
4624           gboolean should_continue = FALSE;
4625
4626           nd = iter->node_data;
4627           while (nd != NULL)
4628             {
4629               if (nd->valid)
4630                 {
4631                   should_continue = TRUE;
4632                   nd->valid = FALSE;
4633                 }
4634
4635               nd = nd->next;
4636             }
4637
4638           if (!should_continue)
4639             break; /* This node was totally invalidated, so are its
4640                       parents */
4641         }
4642
4643       iter = iter->parent;
4644     }
4645 }
4646
4647
4648 /**
4649  * _gtk_text_btree_is_valid:
4650  * @tree: a #GtkTextBTree
4651  * @view_id: ID for the view
4652  *
4653  * Check to see if the entire #GtkTextBTree is valid or not for
4654  * the given view.
4655  *
4656  * Return value: %TRUE if the entire #GtkTextBTree is valid
4657  **/
4658 gboolean
4659 _gtk_text_btree_is_valid (GtkTextBTree *tree,
4660                          gpointer      view_id)
4661 {
4662   NodeData *nd;
4663   g_return_val_if_fail (tree != NULL, FALSE);
4664
4665   nd = node_data_find (tree->root_node->node_data, view_id);
4666   return (nd && nd->valid);
4667 }
4668
4669 typedef struct _ValidateState ValidateState;
4670
4671 struct _ValidateState
4672 {
4673   gint remaining_pixels;
4674   gboolean in_validation;
4675   gint y;
4676   gint old_height;
4677   gint new_height;
4678 };
4679
4680 static void
4681 gtk_text_btree_node_validate (BTreeView         *view,
4682                               GtkTextBTreeNode  *node,
4683                               gpointer           view_id,
4684                               ValidateState     *state)
4685 {
4686   gint node_valid = TRUE;
4687   gint node_width = 0;
4688   gint node_height = 0;
4689
4690   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
4691   g_return_if_fail (!nd->valid);
4692
4693   if (node->level == 0)
4694     {
4695       GtkTextLine *line = node->children.line;
4696       GtkTextLineData *ld;
4697
4698       /* Iterate over leading valid lines */
4699       while (line != NULL)
4700         {
4701           ld = _gtk_text_line_get_data (line, view_id);
4702
4703           if (!ld || !ld->valid)
4704             break;
4705           else if (state->in_validation)
4706             {
4707               state->in_validation = FALSE;
4708               return;
4709             }
4710           else
4711             {
4712               state->y += ld->height;
4713               node_width = MAX (ld->width, node_width);
4714               node_height += ld->height;
4715             }
4716
4717           line = line->next;
4718         }
4719
4720       state->in_validation = TRUE;
4721
4722       /* Iterate over invalid lines */
4723       while (line != NULL)
4724         {
4725           ld = _gtk_text_line_get_data (line, view_id);
4726
4727           if (ld && ld->valid)
4728             break;
4729           else
4730             {
4731               if (ld)
4732                 state->old_height += ld->height;
4733               ld = gtk_text_layout_wrap (view->layout, line, ld);
4734               state->new_height += ld->height;
4735
4736               node_width = MAX (ld->width, node_width);
4737               node_height += ld->height;
4738
4739               state->remaining_pixels -= ld->height;
4740               if (state->remaining_pixels <= 0)
4741                 {
4742                   line = line->next;
4743                   break;
4744                 }
4745             }
4746
4747           line = line->next;
4748         }
4749
4750       /* Iterate over the remaining lines */
4751       while (line != NULL)
4752         {
4753           ld = _gtk_text_line_get_data (line, view_id);
4754           state->in_validation = FALSE;
4755
4756           if (!ld || !ld->valid)
4757             node_valid = FALSE;
4758
4759           if (ld)
4760             {
4761               node_width = MAX (ld->width, node_width);
4762               node_height += ld->height;
4763             }
4764
4765           line = line->next;
4766         }
4767     }
4768   else
4769     {
4770       GtkTextBTreeNode *child;
4771       NodeData *child_nd;
4772
4773       child = node->children.node;
4774
4775       /* Iterate over leading valid nodes */
4776       while (child)
4777         {
4778           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4779
4780           if (!child_nd->valid)
4781             break;
4782           else if (state->in_validation)
4783             {
4784               state->in_validation = FALSE;
4785               return;
4786             }
4787           else
4788             {
4789               state->y += child_nd->height;
4790               node_width = MAX (node_width, child_nd->width);
4791               node_height += child_nd->height;
4792             }
4793
4794           child = child->next;
4795         }
4796
4797       /* Iterate over invalid nodes */
4798       while (child)
4799         {
4800           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4801
4802           if (child_nd->valid)
4803             break;
4804           else
4805             {
4806               gtk_text_btree_node_validate (view, child, view_id, state);
4807
4808               if (!child_nd->valid)
4809                 node_valid = FALSE;
4810               node_width = MAX (node_width, child_nd->width);
4811               node_height += child_nd->height;
4812
4813               if (!state->in_validation || state->remaining_pixels <= 0)
4814                 {
4815                   child = child->next;
4816                   break;
4817                 }
4818             }
4819
4820           child = child->next;
4821         }
4822
4823       /* Iterate over the remaining lines */
4824       while (child)
4825         {
4826           child_nd = gtk_text_btree_node_ensure_data (child, view_id);
4827           state->in_validation = FALSE;
4828
4829           if (!child_nd->valid)
4830             node_valid = FALSE;
4831
4832           node_width = MAX (child_nd->width, node_width);
4833           node_height += child_nd->height;
4834
4835           child = child->next;
4836         }
4837     }
4838
4839   nd->width = node_width;
4840   nd->height = node_height;
4841   nd->valid = node_valid;
4842 }
4843
4844 /**
4845  * _gtk_text_btree_validate:
4846  * @tree: a #GtkTextBTree
4847  * @view_id: view id
4848  * @max_pixels: the maximum number of pixels to validate. (No more
4849  *              than one paragraph beyond this limit will be validated)
4850  * @y: location to store starting y coordinate of validated region
4851  * @old_height: location to store old height of validated region
4852  * @new_height: location to store new height of validated region
4853  *
4854  * Validate a single contiguous invalid region of a #GtkTextBTree for
4855  * a given view.
4856  *
4857  * Return value: %TRUE if a region has been validated, %FALSE if the
4858  * entire tree was already valid.
4859  **/
4860 gboolean
4861 _gtk_text_btree_validate (GtkTextBTree *tree,
4862                          gpointer      view_id,
4863                          gint          max_pixels,
4864                          gint         *y,
4865                          gint         *old_height,
4866                          gint         *new_height)
4867 {
4868   BTreeView *view;
4869
4870   g_return_val_if_fail (tree != NULL, FALSE);
4871
4872   view = gtk_text_btree_get_view (tree, view_id);
4873   g_return_val_if_fail (view != NULL, FALSE);
4874
4875   if (!_gtk_text_btree_is_valid (tree, view_id))
4876     {
4877       ValidateState state;
4878
4879       state.remaining_pixels = max_pixels;
4880       state.in_validation = FALSE;
4881       state.y = 0;
4882       state.old_height = 0;
4883       state.new_height = 0;
4884
4885       gtk_text_btree_node_validate (view,
4886                                     tree->root_node,
4887                                     view_id, &state);
4888
4889       if (y)
4890         *y = state.y;
4891       if (old_height)
4892         *old_height = state.old_height;
4893       if (new_height)
4894         *new_height = state.new_height;
4895
4896       if (gtk_debug_flags & GTK_DEBUG_TEXT)
4897         _gtk_text_btree_check (tree);
4898
4899       return TRUE;
4900     }
4901   else
4902     return FALSE;
4903 }
4904
4905 static void
4906 gtk_text_btree_node_compute_view_aggregates (GtkTextBTreeNode *node,
4907                                              gpointer          view_id,
4908                                              gint             *width_out,
4909                                              gint             *height_out,
4910                                              gboolean         *valid_out)
4911 {
4912   gint width = 0;
4913   gint height = 0;
4914   gboolean valid = TRUE;
4915
4916   if (node->level == 0)
4917     {
4918       GtkTextLine *line = node->children.line;
4919
4920       while (line != NULL)
4921         {
4922           GtkTextLineData *ld = _gtk_text_line_get_data (line, view_id);
4923
4924           if (!ld || !ld->valid)
4925             valid = FALSE;
4926
4927           if (ld)
4928             {
4929               width = MAX (ld->width, width);
4930               height += ld->height;
4931             }
4932
4933           line = line->next;
4934         }
4935     }
4936   else
4937     {
4938       GtkTextBTreeNode *child = node->children.node;
4939
4940       while (child)
4941         {
4942           NodeData *child_nd = node_data_find (child->node_data, view_id);
4943
4944           if (!child_nd || !child_nd->valid)
4945             valid = FALSE;
4946
4947           if (child_nd)
4948             {
4949               width = MAX (child_nd->width, width);
4950               height += child_nd->height;
4951             }
4952
4953           child = child->next;
4954         }
4955     }
4956
4957   *width_out = width;
4958   *height_out = height;
4959   *valid_out = valid;
4960 }
4961
4962
4963 /* Recompute the validity and size of the view data for a given
4964  * view at this node from the immediate children of the node
4965  */
4966 static NodeData *
4967 gtk_text_btree_node_check_valid (GtkTextBTreeNode *node,
4968                                  gpointer          view_id)
4969 {
4970   NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
4971   gboolean valid;
4972   gint width;
4973   gint height;
4974
4975   gtk_text_btree_node_compute_view_aggregates (node, view_id,
4976                                                &width, &height, &valid);
4977   nd->width = width;
4978   nd->height = height;
4979   nd->valid = valid;
4980
4981   return nd;
4982 }
4983
4984 static void
4985 gtk_text_btree_node_check_valid_upward (GtkTextBTreeNode *node,
4986                                         gpointer          view_id)
4987 {
4988   while (node)
4989     {
4990       gtk_text_btree_node_check_valid (node, view_id);
4991       node = node->parent;
4992     }
4993 }
4994
4995 static NodeData *
4996 gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
4997                                           gpointer          view_id)
4998 {
4999   if (node->level == 0)
5000     {
5001       return gtk_text_btree_node_check_valid (node, view_id);
5002     }
5003   else
5004     {
5005       GtkTextBTreeNode *child = node->children.node;
5006
5007       NodeData *nd = gtk_text_btree_node_ensure_data (node, view_id);
5008
5009       nd->valid = TRUE;
5010       nd->width = 0;
5011       nd->height = 0;
5012
5013       while (child)
5014         {
5015           NodeData *child_nd = gtk_text_btree_node_check_valid_downward (child, view_id);
5016
5017           if (!child_nd->valid)
5018             nd->valid = FALSE;
5019           nd->width = MAX (child_nd->width, nd->width);
5020           nd->height += child_nd->height;
5021
5022           child = child->next;
5023         }
5024       return nd;
5025     }
5026 }
5027
5028
5029
5030 /**
5031  * _gtk_text_btree_validate_line:
5032  * @tree: a #GtkTextBTree
5033  * @line: line to validate
5034  * @view_id: view ID for the view to validate
5035  *
5036  * Revalidate a single line of the btree for the given view, propagate
5037  * results up through the entire tree.
5038  **/
5039 void
5040 _gtk_text_btree_validate_line (GtkTextBTree     *tree,
5041                                GtkTextLine      *line,
5042                                gpointer          view_id)
5043 {
5044   GtkTextLineData *ld;
5045   BTreeView *view;
5046
5047   g_return_if_fail (tree != NULL);
5048   g_return_if_fail (line != NULL);
5049
5050   view = gtk_text_btree_get_view (tree, view_id);
5051   g_return_if_fail (view != NULL);
5052   
5053   ld = _gtk_text_line_get_data (line, view_id);
5054   if (!ld || !ld->valid)
5055     {
5056       ld = gtk_text_layout_wrap (view->layout, line, ld);
5057       
5058       gtk_text_btree_node_check_valid_upward (line->parent, view_id);
5059     }
5060 }
5061
5062 static void
5063 gtk_text_btree_node_remove_view (BTreeView *view, GtkTextBTreeNode *node, gpointer view_id)
5064 {
5065   if (node->level == 0)
5066     {
5067       GtkTextLine *line;
5068
5069       line = node->children.line;
5070       while (line != NULL)
5071         {
5072           GtkTextLineData *ld;
5073
5074           ld = _gtk_text_line_remove_data (line, view_id);
5075
5076           if (ld)
5077             gtk_text_layout_free_line_data (view->layout, line, ld);
5078
5079           line = line->next;
5080         }
5081     }
5082   else
5083     {
5084       GtkTextBTreeNode *child;
5085
5086       child = node->children.node;
5087
5088       while (child != NULL)
5089         {
5090           /* recurse */
5091           gtk_text_btree_node_remove_view (view, child, view_id);
5092
5093           child = child->next;
5094         }
5095     }
5096
5097   gtk_text_btree_node_remove_data (node, view_id);
5098 }
5099
5100 static void
5101 gtk_text_btree_node_destroy (GtkTextBTree *tree, GtkTextBTreeNode *node)
5102 {
5103   if (node->level == 0)
5104     {
5105       GtkTextLine *line;
5106       GtkTextLineSegment *seg;
5107
5108       while (node->children.line != NULL)
5109         {
5110           line = node->children.line;
5111           node->children.line = line->next;
5112           while (line->segments != NULL)
5113             {
5114               seg = line->segments;
5115               line->segments = seg->next;
5116
5117               if (GTK_IS_TEXT_MARK_SEGMENT (seg))
5118                 {
5119                   /* Set the mark as deleted */
5120                   seg->body.mark.tree = NULL;
5121                   seg->body.mark.line = NULL;
5122                 }
5123
5124               (*seg->type->deleteFunc) (seg, line, 1);
5125             }
5126           gtk_text_line_destroy (tree, line);
5127         }
5128     }
5129   else
5130     {
5131       GtkTextBTreeNode *childPtr;
5132
5133       while (node->children.node != NULL)
5134         {
5135           childPtr = node->children.node;
5136           node->children.node = childPtr->next;
5137           gtk_text_btree_node_destroy (tree, childPtr);
5138         }
5139     }
5140
5141   gtk_text_btree_node_free_empty (tree, node);
5142 }
5143
5144 static void
5145 gtk_text_btree_node_free_empty (GtkTextBTree *tree,
5146                                 GtkTextBTreeNode *node)
5147 {
5148   g_return_if_fail ((node->level > 0 && node->children.node == NULL) ||
5149                     (node->level == 0 && node->children.line == NULL));
5150
5151   summary_list_destroy (node->summary);
5152   node_data_list_destroy (node->node_data);
5153   g_free (node);
5154 }
5155
5156 static NodeData*
5157 gtk_text_btree_node_ensure_data (GtkTextBTreeNode *node, gpointer view_id)
5158 {
5159   NodeData *nd;
5160
5161   nd = node->node_data;
5162   while (nd != NULL)
5163     {
5164       if (nd->view_id == view_id)
5165         break;
5166
5167       nd = nd->next;
5168     }
5169
5170   if (nd == NULL)
5171     {
5172       nd = node_data_new (view_id);
5173       
5174       if (node->node_data)
5175         nd->next = node->node_data;
5176       
5177       node->node_data = nd;
5178     }
5179
5180   return nd;
5181 }
5182
5183 static void
5184 gtk_text_btree_node_remove_data (GtkTextBTreeNode *node, gpointer view_id)
5185 {
5186   NodeData *nd;
5187   NodeData *prev;
5188
5189   prev = NULL;
5190   nd = node->node_data;
5191   while (nd != NULL)
5192     {
5193       if (nd->view_id == view_id)
5194         break;
5195
5196       prev = nd;
5197       nd = nd->next;
5198     }
5199
5200   if (nd == NULL)
5201     return;
5202
5203   if (prev != NULL)
5204     prev->next = nd->next;
5205
5206   if (node->node_data == nd)
5207     node->node_data = nd->next;
5208
5209   nd->next = NULL;
5210
5211   node_data_destroy (nd);
5212 }
5213
5214 static void
5215 gtk_text_btree_node_get_size (GtkTextBTreeNode *node, gpointer view_id,
5216                               gint *width, gint *height)
5217 {
5218   NodeData *nd;
5219
5220   g_return_if_fail (width != NULL);
5221   g_return_if_fail (height != NULL);
5222
5223   nd = gtk_text_btree_node_ensure_data (node, view_id);
5224
5225   if (width)
5226     *width = nd->width;
5227   if (height)
5228     *height = nd->height;
5229 }
5230
5231 /* Find the closest common ancestor of the two nodes. FIXME: The interface
5232  * here isn't quite right, since for a lot of operations we want to
5233  * know which children of the common parent correspond to the two nodes
5234  * (e.g., when computing the order of two iters)
5235  */
5236 static GtkTextBTreeNode *
5237 gtk_text_btree_node_common_parent (GtkTextBTreeNode *node1,
5238                                    GtkTextBTreeNode *node2)
5239 {
5240   while (node1->level < node2->level)
5241     node1 = node1->parent;
5242   while (node2->level < node1->level)
5243     node2 = node2->parent;
5244   while (node1 != node2)
5245     {
5246       node1 = node1->parent;
5247       node2 = node2->parent;
5248     }
5249
5250   return node1;
5251 }
5252
5253 /*
5254  * BTree
5255  */
5256
5257 static BTreeView*
5258 gtk_text_btree_get_view (GtkTextBTree *tree, gpointer view_id)
5259 {
5260   BTreeView *view;
5261
5262   view = tree->views;
5263   while (view != NULL)
5264     {
5265       if (view->view_id == view_id)
5266         break;
5267       view = view->next;
5268     }
5269
5270   return view;
5271 }
5272
5273 static void
5274 get_tree_bounds (GtkTextBTree *tree,
5275                  GtkTextIter *start,
5276                  GtkTextIter *end)
5277 {
5278   _gtk_text_btree_get_iter_at_line_char (tree, start, 0, 0);
5279   _gtk_text_btree_get_end_iter (tree, end);
5280 }
5281
5282 static void
5283 tag_changed_cb (GtkTextTagTable *table,
5284                 GtkTextTag      *tag,
5285                 gboolean         size_changed,
5286                 GtkTextBTree    *tree)
5287 {
5288   if (size_changed)
5289     {
5290       /* We need to queue a relayout on all regions that are tagged with
5291        * this tag.
5292        */
5293
5294       GtkTextIter start;
5295       GtkTextIter end;
5296
5297       if (_gtk_text_btree_get_iter_at_first_toggle (tree, &start, tag))
5298         {
5299           /* Must be a last toggle if there was a first one. */
5300           _gtk_text_btree_get_iter_at_last_toggle (tree, &end, tag);
5301           _gtk_text_btree_invalidate_region (tree,
5302                                             &start, &end);
5303
5304         }
5305     }
5306   else
5307     {
5308       /* We only need to queue a redraw, not a relayout */
5309       BTreeView *view;
5310
5311       view = tree->views;
5312
5313       while (view != NULL)
5314         {
5315           gint width, height;
5316
5317           _gtk_text_btree_get_view_size (tree, view->view_id, &width, &height);
5318           gtk_text_layout_changed (view->layout, 0, height, height);
5319
5320           view = view->next;
5321         }
5322     }
5323 }
5324
5325 static void
5326 tag_removed_cb (GtkTextTagTable *table,
5327                 GtkTextTag *tag,
5328                 GtkTextBTree *tree)
5329 {
5330   /* Remove the tag from the tree */
5331
5332   GtkTextIter start;
5333   GtkTextIter end;
5334
5335   get_tree_bounds (tree, &start, &end);
5336
5337   _gtk_text_btree_tag (&start, &end, tag, FALSE);
5338   gtk_text_btree_remove_tag_info (tree, tag);
5339 }
5340
5341
5342 /* Rebalance the out-of-whack node "node" */
5343 static void
5344 gtk_text_btree_rebalance (GtkTextBTree *tree,
5345                           GtkTextBTreeNode *node)
5346 {
5347   /*
5348    * Loop over the entire ancestral chain of the GtkTextBTreeNode, working
5349    * up through the tree one GtkTextBTreeNode at a time until the root
5350    * GtkTextBTreeNode has been processed.
5351    */
5352
5353   while (node != NULL)
5354     {
5355       GtkTextBTreeNode *new_node, *child;
5356       GtkTextLine *line;
5357       int i;
5358
5359       /*
5360        * Check to see if the GtkTextBTreeNode has too many children.  If it does,
5361        * then split off all but the first MIN_CHILDREN into a separate
5362        * GtkTextBTreeNode following the original one.  Then repeat until the
5363        * GtkTextBTreeNode has a decent size.
5364        */
5365
5366       if (node->num_children > MAX_CHILDREN)
5367         {
5368           while (1)
5369             {
5370               /*
5371                * If the GtkTextBTreeNode being split is the root
5372                * GtkTextBTreeNode, then make a new root GtkTextBTreeNode above
5373                * it first.
5374                */
5375
5376               if (node->parent == NULL)
5377                 {
5378                   new_node = gtk_text_btree_node_new ();
5379                   new_node->parent = NULL;
5380                   new_node->next = NULL;
5381                   new_node->summary = NULL;
5382                   new_node->level = node->level + 1;
5383                   new_node->children.node = node;
5384                   recompute_node_counts (tree, new_node);
5385                   tree->root_node = new_node;
5386                 }
5387               new_node = gtk_text_btree_node_new ();
5388               new_node->parent = node->parent;
5389               new_node->next = node->next;
5390               node->next = new_node;
5391               new_node->summary = NULL;
5392               new_node->level = node->level;
5393               new_node->num_children = node->num_children - MIN_CHILDREN;
5394               if (node->level == 0)
5395                 {
5396                   for (i = MIN_CHILDREN-1,
5397                          line = node->children.line;
5398                        i > 0; i--, line = line->next)
5399                     {
5400                       /* Empty loop body. */
5401                     }
5402                   new_node->children.line = line->next;
5403                   line->next = NULL;
5404                 }
5405               else
5406                 {
5407                   for (i = MIN_CHILDREN-1,
5408                          child = node->children.node;
5409                        i > 0; i--, child = child->next)
5410                     {
5411                       /* Empty loop body. */
5412                     }
5413                   new_node->children.node = child->next;
5414                   child->next = NULL;
5415                 }
5416               recompute_node_counts (tree, node);
5417               node->parent->num_children++;
5418               node = new_node;
5419               if (node->num_children <= MAX_CHILDREN)
5420                 {
5421                   recompute_node_counts (tree, node);
5422                   break;
5423                 }
5424             }
5425         }
5426
5427       while (node->num_children < MIN_CHILDREN)
5428         {
5429           GtkTextBTreeNode *other;
5430           GtkTextBTreeNode *halfwaynode = NULL; /* Initialization needed only */
5431           GtkTextLine *halfwayline = NULL; /* to prevent cc warnings. */
5432           int total_children, first_children, i;
5433
5434           /*
5435            * Too few children for this GtkTextBTreeNode.  If this is the root then,
5436            * it's OK for it to have less than MIN_CHILDREN children
5437            * as long as it's got at least two.  If it has only one
5438            * (and isn't at level 0), then chop the root GtkTextBTreeNode out of
5439            * the tree and use its child as the new root.
5440            */
5441
5442           if (node->parent == NULL)
5443             {
5444               if ((node->num_children == 1) && (node->level > 0))
5445                 {
5446                   tree->root_node = node->children.node;
5447                   tree->root_node->parent = NULL;
5448
5449                   node->children.node = NULL;
5450                   gtk_text_btree_node_free_empty (tree, node);
5451                 }
5452               return;
5453             }
5454
5455           /*
5456            * Not the root.  Make sure that there are siblings to
5457            * balance with.
5458            */
5459
5460           if (node->parent->num_children < 2)
5461             {
5462               gtk_text_btree_rebalance (tree, node->parent);
5463               continue;
5464             }
5465
5466           /*
5467            * Find a sibling neighbor to borrow from, and arrange for
5468            * node to be the earlier of the pair.
5469            */
5470
5471           if (node->next == NULL)
5472             {
5473               for (other = node->parent->children.node;
5474                    other->next != node;
5475                    other = other->next)
5476                 {
5477                   /* Empty loop body. */
5478                 }
5479               node = other;
5480             }
5481           other = node->next;
5482
5483           /*
5484            * We're going to either merge the two siblings together
5485            * into one GtkTextBTreeNode or redivide the children among them to
5486            * balance their loads.  As preparation, join their two
5487            * child lists into a single list and remember the half-way
5488            * point in the list.
5489            */
5490
5491           total_children = node->num_children + other->num_children;
5492           first_children = total_children/2;
5493           if (node->children.node == NULL)
5494             {
5495               node->children = other->children;
5496               other->children.node = NULL;
5497               other->children.line = NULL;
5498             }
5499           if (node->level == 0)
5500             {
5501               GtkTextLine *line;
5502
5503               for (line = node->children.line, i = 1;
5504                    line->next != NULL;
5505                    line = line->next, i++)
5506                 {
5507                   if (i == first_children)
5508                     {
5509                       halfwayline = line;
5510                     }
5511                 }
5512               line->next = other->children.line;
5513               while (i <= first_children)
5514                 {
5515                   halfwayline = line;
5516                   line = line->next;
5517                   i++;
5518                 }
5519             }
5520           else
5521             {
5522               GtkTextBTreeNode *child;
5523
5524               for (child = node->children.node, i = 1;
5525                    child->next != NULL;
5526                    child = child->next, i++)
5527                 {
5528                   if (i <= first_children)
5529                     {
5530                       if (i == first_children)
5531                         {
5532                           halfwaynode = child;
5533                         }
5534                     }
5535                 }
5536               child->next = other->children.node;
5537               while (i <= first_children)
5538                 {
5539                   halfwaynode = child;
5540                   child = child->next;
5541                   i++;
5542                 }
5543             }
5544
5545           /*
5546            * If the two siblings can simply be merged together, do it.
5547            */
5548
5549           if (total_children <= MAX_CHILDREN)
5550             {
5551               recompute_node_counts (tree, node);
5552               node->next = other->next;
5553               node->parent->num_children--;
5554
5555               other->children.node = NULL;
5556               other->children.line = NULL;
5557               gtk_text_btree_node_free_empty (tree, other);
5558               continue;
5559             }
5560
5561           /*
5562            * The siblings can't be merged, so just divide their
5563            * children evenly between them.
5564            */
5565
5566           if (node->level == 0)
5567             {
5568               other->children.line = halfwayline->next;
5569               halfwayline->next = NULL;
5570             }
5571           else
5572             {
5573               other->children.node = halfwaynode->next;
5574               halfwaynode->next = NULL;
5575             }
5576
5577           recompute_node_counts (tree, node);
5578           recompute_node_counts (tree, other);
5579         }
5580
5581       node = node->parent;
5582     }
5583 }
5584
5585 static void
5586 post_insert_fixup (GtkTextBTree *tree,
5587                    GtkTextLine *line,
5588                    gint line_count_delta,
5589                    gint char_count_delta)
5590
5591 {
5592   GtkTextBTreeNode *node;
5593
5594   /*
5595    * Increment the line counts in all the parent GtkTextBTreeNodes of the insertion
5596    * point, then rebalance the tree if necessary.
5597    */
5598
5599   for (node = line->parent ; node != NULL;
5600        node = node->parent)
5601     {
5602       node->num_lines += line_count_delta;
5603       node->num_chars += char_count_delta;
5604     }
5605   node = line->parent;
5606   node->num_children += line_count_delta;
5607
5608   if (node->num_children > MAX_CHILDREN)
5609     {
5610       gtk_text_btree_rebalance (tree, node);
5611     }
5612
5613   if (gtk_debug_flags & GTK_DEBUG_TEXT)
5614     _gtk_text_btree_check (tree);
5615 }
5616
5617 static GtkTextTagInfo*
5618 gtk_text_btree_get_existing_tag_info (GtkTextBTree *tree,
5619                                       GtkTextTag   *tag)
5620 {
5621   GtkTextTagInfo *info;
5622   GSList *list;
5623
5624
5625   list = tree->tag_infos;
5626   while (list != NULL)
5627     {
5628       info = list->data;
5629       if (info->tag == tag)
5630         return info;
5631
5632       list = g_slist_next (list);
5633     }
5634
5635   return NULL;
5636 }
5637
5638 static GtkTextTagInfo*
5639 gtk_text_btree_get_tag_info (GtkTextBTree *tree,
5640                              GtkTextTag   *tag)
5641 {
5642   GtkTextTagInfo *info;
5643
5644   info = gtk_text_btree_get_existing_tag_info (tree, tag);
5645
5646   if (info == NULL)
5647     {
5648       /* didn't find it, create. */
5649
5650       info = g_new (GtkTextTagInfo, 1);
5651
5652       info->tag = tag;
5653       g_object_ref (G_OBJECT (tag));
5654       info->tag_root = NULL;
5655       info->toggle_count = 0;
5656
5657       tree->tag_infos = g_slist_prepend (tree->tag_infos, info);
5658     }
5659
5660   return info;
5661 }
5662
5663 static void
5664 gtk_text_btree_remove_tag_info (GtkTextBTree *tree,
5665                                 GtkTextTag   *tag)
5666 {
5667   GtkTextTagInfo *info;
5668   GSList *list;
5669   GSList *prev;
5670
5671   prev = NULL;
5672   list = tree->tag_infos;
5673   while (list != NULL)
5674     {
5675       info = list->data;
5676       if (info->tag == tag)
5677         {
5678           if (prev != NULL)
5679             {
5680               prev->next = list->next;
5681             }
5682           else
5683             {
5684               tree->tag_infos = list->next;
5685             }
5686           list->next = NULL;
5687           g_slist_free (list);
5688
5689           g_object_unref (G_OBJECT (info->tag));
5690
5691           g_free (info);
5692           return;
5693         }
5694
5695       list = g_slist_next (list);
5696     }
5697
5698   g_assert_not_reached ();
5699   return;
5700 }
5701
5702 static void
5703 recompute_level_zero_counts (GtkTextBTreeNode *node)
5704 {
5705   GtkTextLine *line;
5706   GtkTextLineSegment *seg;
5707
5708   g_assert (node->level == 0);
5709
5710   line = node->children.line;
5711   while (line != NULL)
5712     {
5713       node->num_children++;
5714       node->num_lines++;
5715
5716       if (line->parent != node)
5717         gtk_text_line_set_parent (line, node);
5718
5719       seg = line->segments;
5720       while (seg != NULL)
5721         {
5722
5723           node->num_chars += seg->char_count;
5724
5725           if (((seg->type != &gtk_text_toggle_on_type)
5726                && (seg->type != &gtk_text_toggle_off_type))
5727               || !(seg->body.toggle.inNodeCounts))
5728             {
5729               ; /* nothing */
5730             }
5731           else
5732             {
5733               GtkTextTagInfo *info;
5734
5735               info = seg->body.toggle.info;
5736
5737               gtk_text_btree_node_adjust_toggle_count (node, info, 1);
5738             }
5739
5740           seg = seg->next;
5741         }
5742
5743       line = line->next;
5744     }
5745 }
5746
5747 static void
5748 recompute_level_nonzero_counts (GtkTextBTreeNode *node)
5749 {
5750   Summary *summary;
5751   GtkTextBTreeNode *child;
5752
5753   g_assert (node->level > 0);
5754
5755   child = node->children.node;
5756   while (child != NULL)
5757     {
5758       node->num_children += 1;
5759       node->num_lines += child->num_lines;
5760       node->num_chars += child->num_chars;
5761
5762       if (child->parent != node)
5763         {
5764           child->parent = node;
5765           gtk_text_btree_node_invalidate_upward (node, NULL);
5766         }
5767
5768       summary = child->summary;
5769       while (summary != NULL)
5770         {
5771           gtk_text_btree_node_adjust_toggle_count (node,
5772                                                    summary->info,
5773                                                    summary->toggle_count);
5774
5775           summary = summary->next;
5776         }
5777
5778       child = child->next;
5779     }
5780 }
5781
5782 /*
5783  *----------------------------------------------------------------------
5784  *
5785  * recompute_node_counts --
5786  *
5787  *      This procedure is called to recompute all the counts in a GtkTextBTreeNode
5788  *      (tags, child information, etc.) by scanning the information in
5789  *      its descendants.  This procedure is called during rebalancing
5790  *      when a GtkTextBTreeNode's child structure has changed.
5791  *
5792  * Results:
5793  *      None.
5794  *
5795  * Side effects:
5796  *      The tag counts for node are modified to reflect its current
5797  *      child structure, as are its num_children, num_lines, num_chars fields.
5798  *      Also, all of the childrens' parent fields are made to point
5799  *      to node.
5800  *
5801  *----------------------------------------------------------------------
5802  */
5803
5804 static void
5805 recompute_node_counts (GtkTextBTree *tree, GtkTextBTreeNode *node)
5806 {
5807   BTreeView *view;
5808   Summary *summary, *summary2;
5809
5810   /*
5811    * Zero out all the existing counts for the GtkTextBTreeNode, but don't delete
5812    * the existing Summary records (most of them will probably be reused).
5813    */
5814
5815   summary = node->summary;
5816   while (summary != NULL)
5817     {
5818       summary->toggle_count = 0;
5819       summary = summary->next;
5820     }
5821
5822   node->num_children = 0;
5823   node->num_lines = 0;
5824   node->num_chars = 0;
5825
5826   /*
5827    * Scan through the children, adding the childrens' tag counts into
5828    * the GtkTextBTreeNode's tag counts and adding new Summary structures if
5829    * necessary.
5830    */
5831
5832   if (node->level == 0)
5833     recompute_level_zero_counts (node);
5834   else
5835     recompute_level_nonzero_counts (node);
5836
5837   view = tree->views;
5838   while (view)
5839     {
5840       gtk_text_btree_node_check_valid (node, view->view_id);
5841       view = view->next;
5842     }
5843   
5844   /*
5845    * Scan through the GtkTextBTreeNode's tag records again and delete any Summary
5846    * records that still have a zero count, or that have all the toggles.
5847    * The GtkTextBTreeNode with the children that account for all the tags toggles
5848    * have no summary information, and they become the tag_root for the tag.
5849    */
5850
5851   summary2 = NULL;
5852   for (summary = node->summary; summary != NULL; )
5853     {
5854       if (summary->toggle_count > 0 &&
5855           summary->toggle_count < summary->info->toggle_count)
5856         {
5857           if (node->level == summary->info->tag_root->level)
5858             {
5859               /*
5860                * The tag's root GtkTextBTreeNode split and some toggles left.
5861                * The tag root must move up a level.
5862                */
5863               summary->info->tag_root = node->parent;
5864             }
5865           summary2 = summary;
5866           summary = summary->next;
5867           continue;
5868         }
5869       if (summary->toggle_count == summary->info->toggle_count)
5870         {
5871           /*
5872            * A GtkTextBTreeNode merge has collected all the toggles under
5873            * one GtkTextBTreeNode.  Push the root down to this level.
5874            */
5875           summary->info->tag_root = node;
5876         }
5877       if (summary2 != NULL)
5878         {
5879           summary2->next = summary->next;
5880           summary_destroy (summary);
5881           summary = summary2->next;
5882         }
5883       else
5884         {
5885           node->summary = summary->next;
5886           summary_destroy (summary);
5887           summary = node->summary;
5888         }
5889     }
5890 }
5891
5892 void
5893 _gtk_change_node_toggle_count (GtkTextBTreeNode *node,
5894                                GtkTextTagInfo   *info,
5895                                gint              delta) /* may be negative */
5896 {
5897   Summary *summary, *prevPtr;
5898   GtkTextBTreeNode *node2Ptr;
5899   int rootLevel;                        /* Level of original tag root */
5900
5901   info->toggle_count += delta;
5902
5903   if (info->tag_root == (GtkTextBTreeNode *) NULL)
5904     {
5905       info->tag_root = node;
5906       return;
5907     }
5908
5909   /*
5910    * Note the level of the existing root for the tag so we can detect
5911    * if it needs to be moved because of the toggle count change.
5912    */
5913
5914   rootLevel = info->tag_root->level;
5915
5916   /*
5917    * Iterate over the GtkTextBTreeNode and its ancestors up to the tag root, adjusting
5918    * summary counts at each GtkTextBTreeNode and moving the tag's root upwards if
5919    * necessary.
5920    */
5921
5922   for ( ; node != info->tag_root; node = node->parent)
5923     {
5924       /*
5925        * See if there's already an entry for this tag for this GtkTextBTreeNode.  If so,
5926        * perhaps all we have to do is adjust its count.
5927        */
5928
5929       for (prevPtr = NULL, summary = node->summary;
5930            summary != NULL;
5931            prevPtr = summary, summary = summary->next)
5932         {
5933           if (summary->info == info)
5934             {
5935               break;
5936             }
5937         }
5938       if (summary != NULL)
5939         {
5940           summary->toggle_count += delta;
5941           if (summary->toggle_count > 0 &&
5942               summary->toggle_count < info->toggle_count)
5943             {
5944               continue;
5945             }
5946           if (summary->toggle_count != 0)
5947             {
5948               /*
5949                * Should never find a GtkTextBTreeNode with max toggle count at this
5950                * point (there shouldn't have been a summary entry in the
5951                * first place).
5952                */
5953
5954               g_error ("%s: bad toggle count (%d) max (%d)",
5955                        G_STRLOC, summary->toggle_count, info->toggle_count);
5956             }
5957
5958           /*
5959            * Zero toggle count;  must remove this tag from the list.
5960            */
5961
5962           if (prevPtr == NULL)
5963             {
5964               node->summary = summary->next;
5965             }
5966           else
5967             {
5968               prevPtr->next = summary->next;
5969             }
5970           summary_destroy (summary);
5971         }
5972       else
5973         {
5974           /*
5975            * This tag isn't currently in the summary information list.
5976            */
5977
5978           if (rootLevel == node->level)
5979             {
5980
5981               /*
5982                * The old tag root is at the same level in the tree as this
5983                * GtkTextBTreeNode, but it isn't at this GtkTextBTreeNode.  Move the tag root up
5984                * a level, in the hopes that it will now cover this GtkTextBTreeNode
5985                * as well as the old root (if not, we'll move it up again
5986                * the next time through the loop).  To push it up one level
5987                * we copy the original toggle count into the summary
5988                * information at the old root and change the root to its
5989                * parent GtkTextBTreeNode.
5990                */
5991
5992               GtkTextBTreeNode *rootnode = info->tag_root;
5993               summary = (Summary *) g_malloc (sizeof (Summary));
5994               summary->info = info;
5995               summary->toggle_count = info->toggle_count - delta;
5996               summary->next = rootnode->summary;
5997               rootnode->summary = summary;
5998               rootnode = rootnode->parent;
5999               rootLevel = rootnode->level;
6000               info->tag_root = rootnode;
6001             }
6002           summary = (Summary *) g_malloc (sizeof (Summary));
6003           summary->info = info;
6004           summary->toggle_count = delta;
6005           summary->next = node->summary;
6006           node->summary = summary;
6007         }
6008     }
6009
6010   /*
6011    * If we've decremented the toggle count, then it may be necessary
6012    * to push the tag root down one or more levels.
6013    */
6014
6015   if (delta >= 0)
6016     {
6017       return;
6018     }
6019   if (info->toggle_count == 0)
6020     {
6021       info->tag_root = (GtkTextBTreeNode *) NULL;
6022       return;
6023     }
6024   node = info->tag_root;
6025   while (node->level > 0)
6026     {
6027       /*
6028        * See if a single child GtkTextBTreeNode accounts for all of the tag's
6029        * toggles.  If so, push the root down one level.
6030        */
6031
6032       for (node2Ptr = node->children.node;
6033            node2Ptr != (GtkTextBTreeNode *)NULL ;
6034            node2Ptr = node2Ptr->next)
6035         {
6036           for (prevPtr = NULL, summary = node2Ptr->summary;
6037                summary != NULL;
6038                prevPtr = summary, summary = summary->next)
6039             {
6040               if (summary->info == info)
6041                 {
6042                   break;
6043                 }
6044             }
6045           if (summary == NULL)
6046             {
6047               continue;
6048             }
6049           if (summary->toggle_count != info->toggle_count)
6050             {
6051               /*
6052                * No GtkTextBTreeNode has all toggles, so the root is still valid.
6053                */
6054
6055               return;
6056             }
6057
6058           /*
6059            * This GtkTextBTreeNode has all the toggles, so push down the root.
6060            */
6061
6062           if (prevPtr == NULL)
6063             {
6064               node2Ptr->summary = summary->next;
6065             }
6066           else
6067             {
6068               prevPtr->next = summary->next;
6069             }
6070           summary_destroy (summary);
6071           info->tag_root = node2Ptr;
6072           break;
6073         }
6074       node = info->tag_root;
6075     }
6076 }
6077
6078 /*
6079  *----------------------------------------------------------------------
6080  *
6081  * inc_count --
6082  *
6083  *      This is a utility procedure used by _gtk_text_btree_get_tags.  It
6084  *      increments the count for a particular tag, adding a new
6085  *      entry for that tag if there wasn't one previously.
6086  *
6087  * Results:
6088  *      None.
6089  *
6090  * Side effects:
6091  *      The information at *tagInfoPtr may be modified, and the arrays
6092  *      may be reallocated to make them larger.
6093  *
6094  *----------------------------------------------------------------------
6095  */
6096
6097 static void
6098 inc_count (GtkTextTag *tag, int inc, TagInfo *tagInfoPtr)
6099 {
6100   GtkTextTag **tag_p;
6101   int count;
6102
6103   for (tag_p = tagInfoPtr->tags, count = tagInfoPtr->numTags;
6104        count > 0; tag_p++, count--)
6105     {
6106       if (*tag_p == tag)
6107         {
6108           tagInfoPtr->counts[tagInfoPtr->numTags-count] += inc;
6109           return;
6110         }
6111     }
6112
6113   /*
6114    * There isn't currently an entry for this tag, so we have to
6115    * make a new one.  If the arrays are full, then enlarge the
6116    * arrays first.
6117    */
6118
6119   if (tagInfoPtr->numTags == tagInfoPtr->arraySize)
6120     {
6121       GtkTextTag **newTags;
6122       int *newCounts, newSize;
6123
6124       newSize = 2*tagInfoPtr->arraySize;
6125       newTags = (GtkTextTag **) g_malloc ((unsigned)
6126                                           (newSize*sizeof (GtkTextTag *)));
6127       memcpy ((void *) newTags, (void *) tagInfoPtr->tags,
6128               tagInfoPtr->arraySize  *sizeof (GtkTextTag *));
6129       g_free ((char *) tagInfoPtr->tags);
6130       tagInfoPtr->tags = newTags;
6131       newCounts = (int *) g_malloc ((unsigned) (newSize*sizeof (int)));
6132       memcpy ((void *) newCounts, (void *) tagInfoPtr->counts,
6133               tagInfoPtr->arraySize  *sizeof (int));
6134       g_free ((char *) tagInfoPtr->counts);
6135       tagInfoPtr->counts = newCounts;
6136       tagInfoPtr->arraySize = newSize;
6137     }
6138
6139   tagInfoPtr->tags[tagInfoPtr->numTags] = tag;
6140   tagInfoPtr->counts[tagInfoPtr->numTags] = inc;
6141   tagInfoPtr->numTags++;
6142 }
6143
6144 static void
6145 gtk_text_btree_link_segment (GtkTextLineSegment *seg,
6146                              const GtkTextIter *iter)
6147 {
6148   GtkTextLineSegment *prev;
6149   GtkTextLine *line;
6150   GtkTextBTree *tree;
6151
6152   line = _gtk_text_iter_get_text_line (iter);
6153   tree = _gtk_text_iter_get_btree (iter);
6154
6155   prev = gtk_text_line_segment_split (iter);
6156   if (prev == NULL)
6157     {
6158       seg->next = line->segments;
6159       line->segments = seg;
6160     }
6161   else
6162     {
6163       seg->next = prev->next;
6164       prev->next = seg;
6165     }
6166   cleanup_line (line);
6167   segments_changed (tree);
6168
6169   if (gtk_debug_flags & GTK_DEBUG_TEXT)
6170     _gtk_text_btree_check (tree);
6171 }
6172
6173 static void
6174 gtk_text_btree_unlink_segment (GtkTextBTree *tree,
6175                                GtkTextLineSegment *seg,
6176                                GtkTextLine *line)
6177 {
6178   GtkTextLineSegment *prev;
6179
6180   if (line->segments == seg)
6181     {
6182       line->segments = seg->next;
6183     }
6184   else
6185     {
6186       for (prev = line->segments; prev->next != seg;
6187            prev = prev->next)
6188         {
6189           /* Empty loop body. */
6190         }
6191       prev->next = seg->next;
6192     }
6193   cleanup_line (line);
6194   segments_changed (tree);
6195 }
6196
6197 /*
6198  * This is here because it requires BTree internals, it logically
6199  * belongs in gtktextsegment.c
6200  */
6201
6202
6203 /*
6204  *--------------------------------------------------------------
6205  *
6206  * _gtk_toggle_segment_check_func --
6207  *
6208  *      This procedure is invoked to perform consistency checks
6209  *      on toggle segments.
6210  *
6211  * Results:
6212  *      None.
6213  *
6214  * Side effects:
6215  *      If a consistency problem is found the procedure g_errors.
6216  *
6217  *--------------------------------------------------------------
6218  */
6219
6220 void
6221 _gtk_toggle_segment_check_func (GtkTextLineSegment *segPtr,
6222                                 GtkTextLine *line)
6223 {
6224   Summary *summary;
6225   int needSummary;
6226
6227   if (segPtr->byte_count != 0)
6228     {
6229       g_error ("toggle_segment_check_func: segment had non-zero size");
6230     }
6231   if (!segPtr->body.toggle.inNodeCounts)
6232     {
6233       g_error ("toggle_segment_check_func: toggle counts not updated in GtkTextBTreeNodes");
6234     }
6235   needSummary = (segPtr->body.toggle.info->tag_root != line->parent);
6236   for (summary = line->parent->summary; ;
6237        summary = summary->next)
6238     {
6239       if (summary == NULL)
6240         {
6241           if (needSummary)
6242             {
6243               g_error ("toggle_segment_check_func: tag not present in GtkTextBTreeNode");
6244             }
6245           else
6246             {
6247               break;
6248             }
6249         }
6250       if (summary->info == segPtr->body.toggle.info)
6251         {
6252           if (!needSummary)
6253             {
6254               g_error ("toggle_segment_check_func: tag present in root GtkTextBTreeNode summary");
6255             }
6256           break;
6257         }
6258     }
6259 }
6260
6261 /*
6262  * Debug
6263  */
6264
6265 static void
6266 gtk_text_btree_node_view_check_consistency (GtkTextBTree     *tree,
6267                                             GtkTextBTreeNode *node,
6268                                             NodeData         *nd)
6269 {
6270   gint width;
6271   gint height;
6272   gboolean valid;
6273   BTreeView *view;
6274   
6275   view = tree->views;
6276
6277   while (view != NULL)
6278     {
6279       if (view->view_id == nd->view_id)
6280         break;
6281
6282       view = view->next;
6283     }
6284
6285   if (view == NULL)
6286     g_error ("Node has data for a view %p no longer attached to the tree",
6287              nd->view_id);
6288   
6289   gtk_text_btree_node_compute_view_aggregates (node, nd->view_id,
6290                                                &width, &height, &valid);
6291   if (nd->width != width ||
6292       nd->height != height ||
6293       !nd->valid != !valid)
6294     {
6295       g_error ("Node aggregates for view %p are invalid:\n"
6296                "Are (%d,%d,%s), should be (%d,%d,%s)",
6297                nd->view_id,
6298                nd->width, nd->height, nd->valid ? "TRUE" : "FALSE",
6299                width, height, valid ? "TRUE" : "FALSE");
6300     }
6301 }
6302
6303 static void
6304 gtk_text_btree_node_check_consistency (GtkTextBTree     *tree,
6305                                        GtkTextBTreeNode *node)
6306 {
6307   GtkTextBTreeNode *childnode;
6308   Summary *summary, *summary2;
6309   GtkTextLine *line;
6310   GtkTextLineSegment *segPtr;
6311   int num_children, num_lines, num_chars, toggle_count, min_children;
6312   GtkTextLineData *ld;
6313   NodeData *nd;
6314
6315   if (node->parent != NULL)
6316     {
6317       min_children = MIN_CHILDREN;
6318     }
6319   else if (node->level > 0)
6320     {
6321       min_children = 2;
6322     }
6323   else  {
6324     min_children = 1;
6325   }
6326   if ((node->num_children < min_children)
6327       || (node->num_children > MAX_CHILDREN))
6328     {
6329       g_error ("gtk_text_btree_node_check_consistency: bad child count (%d)",
6330                node->num_children);
6331     }
6332
6333   nd = node->node_data;
6334   while (nd != NULL)
6335     {
6336       gtk_text_btree_node_view_check_consistency (tree, node, nd);
6337       nd = nd->next;
6338     }
6339
6340   num_children = 0;
6341   num_lines = 0;
6342   num_chars = 0;
6343   if (node->level == 0)
6344     {
6345       for (line = node->children.line; line != NULL;
6346            line = line->next)
6347         {
6348           if (line->parent != node)
6349             {
6350               g_error ("gtk_text_btree_node_check_consistency: line doesn't point to parent");
6351             }
6352           if (line->segments == NULL)
6353             {
6354               g_error ("gtk_text_btree_node_check_consistency: line has no segments");
6355             }
6356
6357           ld = line->views;
6358           while (ld != NULL)
6359             {
6360               /* Just ensuring we don't segv while doing this loop */
6361
6362               ld = ld->next;
6363             }
6364
6365           for (segPtr = line->segments; segPtr != NULL; segPtr = segPtr->next)
6366             {
6367               if (segPtr->type->checkFunc != NULL)
6368                 {
6369                   (*segPtr->type->checkFunc)(segPtr, line);
6370                 }
6371               if ((segPtr->byte_count == 0) && (!segPtr->type->leftGravity)
6372                   && (segPtr->next != NULL)
6373                   && (segPtr->next->byte_count == 0)
6374                   && (segPtr->next->type->leftGravity))
6375                 {
6376                   g_error ("gtk_text_btree_node_check_consistency: wrong segment order for gravity");
6377                 }
6378               if ((segPtr->next == NULL)
6379                   && (segPtr->type != &gtk_text_char_type))
6380                 {
6381                   g_error ("gtk_text_btree_node_check_consistency: line ended with wrong type");
6382                 }
6383
6384               num_chars += segPtr->char_count;
6385             }
6386
6387           num_children++;
6388           num_lines++;
6389         }
6390     }
6391   else
6392     {
6393       for (childnode = node->children.node; childnode != NULL;
6394            childnode = childnode->next)
6395         {
6396           if (childnode->parent != node)
6397             {
6398               g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode doesn't point to parent");
6399             }
6400           if (childnode->level != (node->level-1))
6401             {
6402               g_error ("gtk_text_btree_node_check_consistency: level mismatch (%d %d)",
6403                        node->level, childnode->level);
6404             }
6405           gtk_text_btree_node_check_consistency (tree, childnode);
6406           for (summary = childnode->summary; summary != NULL;
6407                summary = summary->next)
6408             {
6409               for (summary2 = node->summary; ;
6410                    summary2 = summary2->next)
6411                 {
6412                   if (summary2 == NULL)
6413                     {
6414                       if (summary->info->tag_root == node)
6415                         {
6416                           break;
6417                         }
6418                       g_error ("gtk_text_btree_node_check_consistency: GtkTextBTreeNode tag \"%s\" not %s",
6419                                summary->info->tag->name,
6420                                "present in parent summaries");
6421                     }
6422                   if (summary->info == summary2->info)
6423                     {
6424                       break;
6425                     }
6426                 }
6427             }
6428           num_children++;
6429           num_lines += childnode->num_lines;
6430           num_chars += childnode->num_chars;
6431         }
6432     }
6433   if (num_children != node->num_children)
6434     {
6435       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_children (%d %d)",
6436                num_children, node->num_children);
6437     }
6438   if (num_lines != node->num_lines)
6439     {
6440       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_lines (%d %d)",
6441                num_lines, node->num_lines);
6442     }
6443   if (num_chars != node->num_chars)
6444     {
6445       g_error ("gtk_text_btree_node_check_consistency: mismatch in num_chars (%d %d)",
6446                num_chars, node->num_chars);
6447     }
6448
6449   for (summary = node->summary; summary != NULL;
6450        summary = summary->next)
6451     {
6452       if (summary->info->toggle_count == summary->toggle_count)
6453         {
6454           g_error ("gtk_text_btree_node_check_consistency: found unpruned root for \"%s\"",
6455                    summary->info->tag->name);
6456         }
6457       toggle_count = 0;
6458       if (node->level == 0)
6459         {
6460           for (line = node->children.line; line != NULL;
6461                line = line->next)
6462             {
6463               for (segPtr = line->segments; segPtr != NULL;
6464                    segPtr = segPtr->next)
6465                 {
6466                   if ((segPtr->type != &gtk_text_toggle_on_type)
6467                       && (segPtr->type != &gtk_text_toggle_off_type))
6468                     {
6469                       continue;
6470                     }
6471                   if (segPtr->body.toggle.info == summary->info)
6472                     {
6473                       if (!segPtr->body.toggle.inNodeCounts)
6474                         g_error ("Toggle segment not in the node counts");
6475
6476                       toggle_count ++;
6477                     }
6478                 }
6479             }
6480         }
6481       else
6482         {
6483           for (childnode = node->children.node;
6484                childnode != NULL;
6485                childnode = childnode->next)
6486             {
6487               for (summary2 = childnode->summary;
6488                    summary2 != NULL;
6489                    summary2 = summary2->next)
6490                 {
6491                   if (summary2->info == summary->info)
6492                     {
6493                       toggle_count += summary2->toggle_count;
6494                     }
6495                 }
6496             }
6497         }
6498       if (toggle_count != summary->toggle_count)
6499         {
6500           g_error ("gtk_text_btree_node_check_consistency: mismatch in toggle_count (%d %d)",
6501                    toggle_count, summary->toggle_count);
6502         }
6503       for (summary2 = summary->next; summary2 != NULL;
6504            summary2 = summary2->next)
6505         {
6506           if (summary2->info == summary->info)
6507             {
6508               g_error ("gtk_text_btree_node_check_consistency: duplicated GtkTextBTreeNode tag: %s",
6509                        summary->info->tag->name);
6510             }
6511         }
6512     }
6513 }
6514
6515 static void
6516 listify_foreach (GtkTextTag *tag, gpointer user_data)
6517 {
6518   GSList** listp = user_data;
6519
6520   *listp = g_slist_prepend (*listp, tag);
6521 }
6522
6523 static GSList*
6524 list_of_tags (GtkTextTagTable *table)
6525 {
6526   GSList *list = NULL;
6527
6528   gtk_text_tag_table_foreach (table, listify_foreach, &list);
6529
6530   return list;
6531 }
6532
6533 void
6534 _gtk_text_btree_check (GtkTextBTree *tree)
6535 {
6536   Summary *summary;
6537   GtkTextBTreeNode *node;
6538   GtkTextLine *line;
6539   GtkTextLineSegment *seg;
6540   GtkTextTag *tag;
6541   GSList *taglist = NULL;
6542   int count;
6543   GtkTextTagInfo *info;
6544
6545   /*
6546    * Make sure that the tag toggle counts and the tag root pointers are OK.
6547    */
6548   for (taglist = list_of_tags (tree->table);
6549        taglist != NULL ; taglist = taglist->next)
6550     {
6551       tag = taglist->data;
6552       info = gtk_text_btree_get_existing_tag_info (tree, tag);
6553       if (info != NULL)
6554         {
6555           node = info->tag_root;
6556           if (node == NULL)
6557             {
6558               if (info->toggle_count != 0)
6559                 {
6560                   g_error ("_gtk_text_btree_check found \"%s\" with toggles (%d) but no root",
6561                            tag->name, info->toggle_count);
6562                 }
6563               continue;         /* no ranges for the tag */
6564             }
6565           else if (info->toggle_count == 0)
6566             {
6567               g_error ("_gtk_text_btree_check found root for \"%s\" with no toggles",
6568                        tag->name);
6569             }
6570           else if (info->toggle_count & 1)
6571             {
6572               g_error ("_gtk_text_btree_check found odd toggle count for \"%s\" (%d)",
6573                        tag->name, info->toggle_count);
6574             }
6575           for (summary = node->summary; summary != NULL;
6576                summary = summary->next)
6577             {
6578               if (summary->info->tag == tag)
6579                 {
6580                   g_error ("_gtk_text_btree_check found root GtkTextBTreeNode with summary info");
6581                 }
6582             }
6583           count = 0;
6584           if (node->level > 0)
6585             {
6586               for (node = node->children.node ; node != NULL ;
6587                    node = node->next)
6588                 {
6589                   for (summary = node->summary; summary != NULL;
6590                        summary = summary->next)
6591                     {
6592                       if (summary->info->tag == tag)
6593                         {
6594                           count += summary->toggle_count;
6595                         }
6596                     }
6597                 }
6598             }
6599           else
6600             {
6601               GtkTextLineSegmentClass * last = NULL;
6602
6603               for (line = node->children.line ; line != NULL ;
6604                    line = line->next)
6605                 {
6606                   for (seg = line->segments; seg != NULL;
6607                        seg = seg->next)
6608                     {
6609                       if ((seg->type == &gtk_text_toggle_on_type ||
6610                            seg->type == &gtk_text_toggle_off_type) &&
6611                           seg->body.toggle.info->tag == tag)
6612                         {
6613                           if (last == seg->type)
6614                             g_error ("Two consecutive toggles on or off weren't merged");
6615                           if (!seg->body.toggle.inNodeCounts)
6616                             g_error ("Toggle segment not in the node counts");
6617
6618                           last = seg->type;
6619
6620                           count++;
6621                         }
6622                     }
6623                 }
6624             }
6625           if (count != info->toggle_count)
6626             {
6627               g_error ("_gtk_text_btree_check toggle_count (%d) wrong for \"%s\" should be (%d)",
6628                        info->toggle_count, tag->name, count);
6629             }
6630         }
6631     }
6632
6633   g_slist_free (taglist);
6634   taglist = NULL;
6635
6636   /*
6637    * Call a recursive procedure to do the main body of checks.
6638    */
6639
6640   node = tree->root_node;
6641   gtk_text_btree_node_check_consistency (tree, tree->root_node);
6642
6643   /*
6644    * Make sure that there are at least two lines in the text and
6645    * that the last line has no characters except a newline.
6646    */
6647
6648   if (node->num_lines < 2)
6649     {
6650       g_error ("_gtk_text_btree_check: less than 2 lines in tree");
6651     }
6652   if (node->num_chars < 2)
6653     {
6654       g_error ("_gtk_text_btree_check: less than 2 chars in tree");
6655     }
6656   while (node->level > 0)
6657     {
6658       node = node->children.node;
6659       while (node->next != NULL)
6660         {
6661           node = node->next;
6662         }
6663     }
6664   line = node->children.line;
6665   while (line->next != NULL)
6666     {
6667       line = line->next;
6668     }
6669   seg = line->segments;
6670   while ((seg->type == &gtk_text_toggle_off_type)
6671          || (seg->type == &gtk_text_right_mark_type)
6672          || (seg->type == &gtk_text_left_mark_type))
6673     {
6674       /*
6675        * It's OK to toggle a tag off in the last line, but
6676        * not to start a new range.  It's also OK to have marks
6677        * in the last line.
6678        */
6679
6680       seg = seg->next;
6681     }
6682   if (seg->type != &gtk_text_char_type)
6683     {
6684       g_error ("_gtk_text_btree_check: last line has bogus segment type");
6685     }
6686   if (seg->next != NULL)
6687     {
6688       g_error ("_gtk_text_btree_check: last line has too many segments");
6689     }
6690   if (seg->byte_count != 1)
6691     {
6692       g_error ("_gtk_text_btree_check: last line has wrong # characters: %d",
6693                seg->byte_count);
6694     }
6695   if ((seg->body.chars[0] != '\n') || (seg->body.chars[1] != 0))
6696     {
6697       g_error ("_gtk_text_btree_check: last line had bad value: %s",
6698                seg->body.chars);
6699     }
6700 }
6701
6702 void _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line);
6703 void _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment* seg);
6704 void _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent);
6705 void _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent);
6706
6707 void
6708 _gtk_text_btree_spew (GtkTextBTree *tree)
6709 {
6710   GtkTextLine * line;
6711   int real_line;
6712
6713   printf ("%d lines in tree %p\n",
6714           _gtk_text_btree_line_count (tree), tree);
6715
6716   line = _gtk_text_btree_get_line (tree, 0, &real_line);
6717
6718   while (line != NULL)
6719     {
6720       _gtk_text_btree_spew_line (tree, line);
6721       line = _gtk_text_line_next (line);
6722     }
6723
6724   printf ("=================== Tag information\n");
6725
6726   {
6727     GSList * list;
6728
6729     list = tree->tag_infos;
6730
6731     while (list != NULL)
6732       {
6733         GtkTextTagInfo *info;
6734
6735         info = list->data;
6736
6737         printf ("  tag `%s': root at %p, toggle count %d\n",
6738                 info->tag->name, info->tag_root, info->toggle_count);
6739
6740         list = g_slist_next (list);
6741       }
6742
6743     if (tree->tag_infos == NULL)
6744       {
6745         printf ("  (no tags in the tree)\n");
6746       }
6747   }
6748
6749   printf ("=================== Tree nodes\n");
6750
6751   {
6752     _gtk_text_btree_spew_node (tree->root_node, 0);
6753   }
6754 }
6755
6756 void
6757 _gtk_text_btree_spew_line_short (GtkTextLine *line, int indent)
6758 {
6759   gchar * spaces;
6760   GtkTextLineSegment *seg;
6761
6762   spaces = g_strnfill (indent, ' ');
6763
6764   printf ("%sline %p chars %d bytes %d\n",
6765           spaces, line,
6766           _gtk_text_line_char_count (line),
6767           _gtk_text_line_byte_count (line));
6768
6769   seg = line->segments;
6770   while (seg != NULL)
6771     {
6772       if (seg->type == &gtk_text_char_type)
6773         {
6774           gchar* str = g_strndup (seg->body.chars, MIN (seg->byte_count, 10));
6775           gchar* s;
6776           s = str;
6777           while (*s)
6778             {
6779               if (*s == '\n' || *s == '\r')
6780                 *s = '\\';
6781               ++s;
6782             }
6783           printf ("%s chars `%s'...\n", spaces, str);
6784           g_free (str);
6785         }
6786       else if (seg->type == &gtk_text_right_mark_type)
6787         {
6788           printf ("%s right mark `%s' visible: %d\n",
6789                   spaces,
6790                   seg->body.mark.name,
6791                   seg->body.mark.visible);
6792         }
6793       else if (seg->type == &gtk_text_left_mark_type)
6794         {
6795           printf ("%s left mark `%s' visible: %d\n",
6796                   spaces,
6797                   seg->body.mark.name,
6798                   seg->body.mark.visible);
6799         }
6800       else if (seg->type == &gtk_text_toggle_on_type ||
6801                seg->type == &gtk_text_toggle_off_type)
6802         {
6803           printf ("%s tag `%s' %s\n",
6804                   spaces, seg->body.toggle.info->tag->name,
6805                   seg->type == &gtk_text_toggle_off_type ? "off" : "on");
6806         }
6807
6808       seg = seg->next;
6809     }
6810
6811   g_free (spaces);
6812 }
6813
6814 void
6815 _gtk_text_btree_spew_node (GtkTextBTreeNode *node, int indent)
6816 {
6817   gchar * spaces;
6818   GtkTextBTreeNode *iter;
6819   Summary *s;
6820
6821   spaces = g_strnfill (indent, ' ');
6822
6823   printf ("%snode %p level %d children %d lines %d chars %d\n",
6824           spaces, node, node->level,
6825           node->num_children, node->num_lines, node->num_chars);
6826
6827   s = node->summary;
6828   while (s)
6829     {
6830       printf ("%s %d toggles of `%s' below this node\n",
6831               spaces, s->toggle_count, s->info->tag->name);
6832       s = s->next;
6833     }
6834
6835   g_free (spaces);
6836
6837   if (node->level > 0)
6838     {
6839       iter = node->children.node;
6840       while (iter != NULL)
6841         {
6842           _gtk_text_btree_spew_node (iter, indent + 2);
6843
6844           iter = iter->next;
6845         }
6846     }
6847   else
6848     {
6849       GtkTextLine *line = node->children.line;
6850       while (line != NULL)
6851         {
6852           _gtk_text_btree_spew_line_short (line, indent + 2);
6853
6854           line = line->next;
6855         }
6856     }
6857 }
6858
6859 void
6860 _gtk_text_btree_spew_line (GtkTextBTree* tree, GtkTextLine* line)
6861 {
6862   GtkTextLineSegment * seg;
6863
6864   printf ("%4d| line: %p parent: %p next: %p\n",
6865           _gtk_text_line_get_number (line), line, line->parent, line->next);
6866
6867   seg = line->segments;
6868
6869   while (seg != NULL)
6870     {
6871       _gtk_text_btree_spew_segment (tree, seg);
6872       seg = seg->next;
6873     }
6874 }
6875
6876 void
6877 _gtk_text_btree_spew_segment (GtkTextBTree* tree, GtkTextLineSegment * seg)
6878 {
6879   printf ("     segment: %p type: %s bytes: %d chars: %d\n",
6880           seg, seg->type->name, seg->byte_count, seg->char_count);
6881
6882   if (seg->type == &gtk_text_char_type)
6883     {
6884       gchar* str = g_strndup (seg->body.chars, seg->byte_count);
6885       printf ("       `%s'\n", str);
6886       g_free (str);
6887     }
6888   else if (seg->type == &gtk_text_right_mark_type)
6889     {
6890       printf ("       right mark `%s' visible: %d not_deleteable: %d\n",
6891               seg->body.mark.name,
6892               seg->body.mark.visible,
6893               seg->body.mark.not_deleteable);
6894     }
6895   else if (seg->type == &gtk_text_left_mark_type)
6896     {
6897       printf ("       left mark `%s' visible: %d not_deleteable: %d\n",
6898               seg->body.mark.name,
6899               seg->body.mark.visible,
6900               seg->body.mark.not_deleteable);
6901     }
6902   else if (seg->type == &gtk_text_toggle_on_type ||
6903            seg->type == &gtk_text_toggle_off_type)
6904     {
6905       printf ("       tag `%s' priority %d\n",
6906               seg->body.toggle.info->tag->name,
6907               seg->body.toggle.info->tag->priority);
6908     }
6909 }
6910
6911