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