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