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