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