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