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