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