]> Pileus Git - ~andy/gtk/blob - gtk/gtktextiter.c
Trivial cleanups (bug #107664)
[~andy/gtk] / gtk / gtktextiter.c
1 /* GTK - The GIMP Toolkit
2  * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include "gtktextiter.h"
29 #include "gtktextbtree.h"
30 #include "gtktextiterprivate.h"
31 #include "gtkdebug.h"
32 #include <string.h>
33
34 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
35
36 typedef struct _GtkTextRealIter GtkTextRealIter;
37
38 struct _GtkTextRealIter
39 {
40   /* Always-valid information */
41   GtkTextBTree *tree;
42   GtkTextLine *line;
43   /* At least one of these is always valid;
44      if invalid, they are -1.
45
46      If the line byte offset is valid, so is the segment byte offset;
47      and ditto for char offsets. */
48   gint line_byte_offset;
49   gint line_char_offset;
50   /* These two are valid if >= 0 */
51   gint cached_char_index;
52   gint cached_line_number;
53   /* Stamps to detect the buffer changing under us */
54   gint chars_changed_stamp;
55   gint segments_changed_stamp;
56   /* Valid if the segments_changed_stamp is up-to-date */
57   GtkTextLineSegment *segment;     /* indexable segment we index */
58   GtkTextLineSegment *any_segment; /* first segment in our location,
59                                       maybe same as "segment" */
60   /* One of these will always be valid if segments_changed_stamp is
61      up-to-date. If invalid, they are -1.
62
63      If the line byte offset is valid, so is the segment byte offset;
64      and ditto for char offsets. */
65   gint segment_byte_offset;
66   gint segment_char_offset;
67
68   /* padding */
69   gint pad1;
70   gpointer pad2;
71 };
72
73 /* These "set" functions should not assume any fields
74    other than the char stamp and the tree are valid.
75 */
76 static void
77 iter_set_common (GtkTextRealIter *iter,
78                  GtkTextLine *line)
79 {
80   /* Update segments stamp */
81   iter->segments_changed_stamp =
82     _gtk_text_btree_get_segments_changed_stamp (iter->tree);
83
84   iter->line = line;
85
86   iter->line_byte_offset = -1;
87   iter->line_char_offset = -1;
88   iter->segment_byte_offset = -1;
89   iter->segment_char_offset = -1;
90   iter->cached_char_index = -1;
91   iter->cached_line_number = -1;
92 }
93
94 static void
95 iter_set_from_byte_offset (GtkTextRealIter *iter,
96                            GtkTextLine *line,
97                            gint byte_offset)
98 {
99   iter_set_common (iter, line);
100
101   if (!_gtk_text_line_byte_locate (iter->line,
102                                    byte_offset,
103                                    &iter->segment,
104                                    &iter->any_segment,
105                                    &iter->segment_byte_offset,
106                                    &iter->line_byte_offset))
107     g_error ("Byte index %d is off the end of the line",
108              byte_offset);
109 }
110
111 static void
112 iter_set_from_char_offset (GtkTextRealIter *iter,
113                            GtkTextLine *line,
114                            gint char_offset)
115 {
116   iter_set_common (iter, line);
117
118   if (!_gtk_text_line_char_locate (iter->line,
119                                    char_offset,
120                                    &iter->segment,
121                                    &iter->any_segment,
122                                    &iter->segment_char_offset,
123                                    &iter->line_char_offset))
124     g_error ("Char offset %d is off the end of the line",
125              char_offset);
126 }
127
128 static void
129 iter_set_from_segment (GtkTextRealIter *iter,
130                        GtkTextLine *line,
131                        GtkTextLineSegment *segment)
132 {
133   GtkTextLineSegment *seg;
134   gint byte_offset;
135
136   /* This could theoretically be optimized by computing all the iter
137      fields in this same loop, but I'm skipping it for now. */
138   byte_offset = 0;
139   seg = line->segments;
140   while (seg != segment)
141     {
142       byte_offset += seg->byte_count;
143       seg = seg->next;
144     }
145
146   iter_set_from_byte_offset (iter, line, byte_offset);
147 }
148
149 /* This function ensures that the segment-dependent information is
150    truly computed lazily; often we don't need to do the full make_real
151    work. This ensures the btree and line are valid, but doesn't
152    update the segments. */
153 static GtkTextRealIter*
154 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
155 {
156   GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
157
158   if (iter->chars_changed_stamp !=
159       _gtk_text_btree_get_chars_changed_stamp (iter->tree))
160     {
161       g_warning ("Invalid text buffer iterator: either the iterator "
162                  "is uninitialized, or the characters/pixbufs/widgets "
163                  "in the buffer have been modified since the iterator "
164                  "was created.\nYou must use marks, character numbers, "
165                  "or line numbers to preserve a position across buffer "
166                  "modifications.\nYou can apply tags and insert marks "
167                  "without invalidating your iterators,\n"
168                  "but any mutation that affects 'indexable' buffer contents "
169                  "(contents that can be referred to by character offset)\n"
170                  "will invalidate all outstanding iterators");
171       return NULL;
172     }
173
174   /* We don't update the segments information since we are becoming
175      only surreal. However we do invalidate the segments information
176      if appropriate, to be sure we segfault if we try to use it and we
177      should have used make_real. */
178
179   if (iter->segments_changed_stamp !=
180       _gtk_text_btree_get_segments_changed_stamp (iter->tree))
181     {
182       iter->segment = NULL;
183       iter->any_segment = NULL;
184       /* set to segfault-causing values. */
185       iter->segment_byte_offset = -10000;
186       iter->segment_char_offset = -10000;
187     }
188
189   return iter;
190 }
191
192 static GtkTextRealIter*
193 gtk_text_iter_make_real (const GtkTextIter *_iter)
194 {
195   GtkTextRealIter *iter;
196
197   iter = gtk_text_iter_make_surreal (_iter);
198
199   if (iter->segments_changed_stamp !=
200       _gtk_text_btree_get_segments_changed_stamp (iter->tree))
201     {
202       if (iter->line_byte_offset >= 0)
203         {
204           iter_set_from_byte_offset (iter,
205                                      iter->line,
206                                      iter->line_byte_offset);
207         }
208       else
209         {
210           g_assert (iter->line_char_offset >= 0);
211
212           iter_set_from_char_offset (iter,
213                                      iter->line,
214                                      iter->line_char_offset);
215         }
216     }
217
218   g_assert (iter->segment != NULL);
219   g_assert (iter->any_segment != NULL);
220   g_assert (iter->segment->char_count > 0);
221
222   return iter;
223 }
224
225 static GtkTextRealIter*
226 iter_init_common (GtkTextIter *_iter,
227                   GtkTextBTree *tree)
228 {
229   GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
230
231   g_return_val_if_fail (iter != NULL, NULL);
232   g_return_val_if_fail (tree != NULL, NULL);
233
234   iter->tree = tree;
235
236   iter->chars_changed_stamp =
237     _gtk_text_btree_get_chars_changed_stamp (iter->tree);
238
239   return iter;
240 }
241
242 static GtkTextRealIter*
243 iter_init_from_segment (GtkTextIter *iter,
244                         GtkTextBTree *tree,
245                         GtkTextLine *line,
246                         GtkTextLineSegment *segment)
247 {
248   GtkTextRealIter *real;
249
250   g_return_val_if_fail (line != NULL, NULL);
251
252   real = iter_init_common (iter, tree);
253
254   iter_set_from_segment (real, line, segment);
255
256   return real;
257 }
258
259 static GtkTextRealIter*
260 iter_init_from_byte_offset (GtkTextIter *iter,
261                             GtkTextBTree *tree,
262                             GtkTextLine *line,
263                             gint line_byte_offset)
264 {
265   GtkTextRealIter *real;
266
267   g_return_val_if_fail (line != NULL, NULL);
268
269   real = iter_init_common (iter, tree);
270
271   iter_set_from_byte_offset (real, line, line_byte_offset);
272
273   if (real->segment->type == &gtk_text_char_type &&
274       (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
275     g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
276                "character; this will crash the text buffer. "
277                "Byte indexes must refer to the start of a character.",
278                line_byte_offset);
279   
280   return real;
281 }
282
283 static GtkTextRealIter*
284 iter_init_from_char_offset (GtkTextIter *iter,
285                             GtkTextBTree *tree,
286                             GtkTextLine *line,
287                             gint line_char_offset)
288 {
289   GtkTextRealIter *real;
290
291   g_return_val_if_fail (line != NULL, NULL);
292
293   real = iter_init_common (iter, tree);
294
295   iter_set_from_char_offset (real, line, line_char_offset);
296
297   return real;
298 }
299
300 static inline void
301 invalidate_segment (GtkTextRealIter *iter)
302 {
303   iter->segments_changed_stamp -= 1;
304 }
305
306 static inline void
307 invalidate_char_index (GtkTextRealIter *iter)
308 {
309   iter->cached_char_index = -1;
310 }
311
312 static inline void
313 invalidate_line_number (GtkTextRealIter *iter)
314 {
315   iter->cached_line_number = -1;
316 }
317
318 static inline void
319 adjust_char_index (GtkTextRealIter *iter, gint count)
320 {
321   if (iter->cached_char_index >= 0)
322     iter->cached_char_index += count;
323 }
324
325 static inline void
326 adjust_line_number (GtkTextRealIter *iter, gint count)
327 {
328   if (iter->cached_line_number >= 0)
329     iter->cached_line_number += count;
330 }
331
332 static inline void
333 adjust_char_offsets (GtkTextRealIter *iter, gint count)
334 {
335   if (iter->line_char_offset >= 0)
336     {
337       iter->line_char_offset += count;
338       g_assert (iter->segment_char_offset >= 0);
339       iter->segment_char_offset += count;
340     }
341 }
342
343 static inline void
344 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
345 {
346   if (iter->line_byte_offset >= 0)
347     {
348       iter->line_byte_offset += count;
349       g_assert (iter->segment_byte_offset >= 0);
350       iter->segment_byte_offset += count;
351     }
352 }
353
354 static inline void
355 ensure_char_offsets (GtkTextRealIter *iter)
356 {
357   if (iter->line_char_offset < 0)
358     {
359       g_assert (iter->line_byte_offset >= 0);
360
361       _gtk_text_line_byte_to_char_offsets (iter->line,
362                                           iter->line_byte_offset,
363                                           &iter->line_char_offset,
364                                           &iter->segment_char_offset);
365     }
366 }
367
368 static inline void
369 ensure_byte_offsets (GtkTextRealIter *iter)
370 {
371   if (iter->line_byte_offset < 0)
372     {
373       g_assert (iter->line_char_offset >= 0);
374
375       _gtk_text_line_char_to_byte_offsets (iter->line,
376                                           iter->line_char_offset,
377                                           &iter->line_byte_offset,
378                                           &iter->segment_byte_offset);
379     }
380 }
381
382 static inline gboolean
383 is_segment_start (GtkTextRealIter *real)
384 {
385   return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
386 }
387
388 #if 1
389 static void
390 check_invariants (const GtkTextIter *iter)
391 {
392   if (gtk_debug_flags & GTK_DEBUG_TEXT)
393     _gtk_text_iter_check (iter);
394 }
395 #else
396 #define check_invariants (x)
397 #endif
398
399 /**
400  * gtk_text_iter_get_buffer:
401  * @iter: an iterator
402  *
403  * Returns the #GtkTextBuffer this iterator is associated with.
404  *
405  * Return value: the buffer
406  **/
407 GtkTextBuffer*
408 gtk_text_iter_get_buffer (const GtkTextIter *iter)
409 {
410   GtkTextRealIter *real;
411
412   g_return_val_if_fail (iter != NULL, NULL);
413
414   real = gtk_text_iter_make_surreal (iter);
415
416   if (real == NULL)
417     return NULL;
418
419   check_invariants (iter);
420
421   return _gtk_text_btree_get_buffer (real->tree);
422 }
423
424 /**
425  * gtk_text_iter_copy:
426  * @iter: an iterator
427  *
428  * Creates a dynamically-allocated copy of an iterator. This function
429  * is not useful in applications, because iterators can be copied with a
430  * simple assignment (<literal>GtkTextIter i = j;</literal>). The
431  * function is used by language bindings.
432  *
433  * Return value: a copy of the @iter, free with gtk_text_iter_free ()
434  **/
435 GtkTextIter*
436 gtk_text_iter_copy (const GtkTextIter *iter)
437 {
438   GtkTextIter *new_iter;
439
440   g_return_val_if_fail (iter != NULL, NULL);
441
442   new_iter = g_new (GtkTextIter, 1);
443
444   *new_iter = *iter;
445
446   return new_iter;
447 }
448
449 /**
450  * gtk_text_iter_free:
451  * @iter: a dynamically-allocated iterator
452  *
453  * Free an iterator allocated on the heap. This function
454  * is intended for use in language bindings, and is not
455  * especially useful for applications, because iterators can
456  * simply be allocated on the stack.
457  **/
458 void
459 gtk_text_iter_free (GtkTextIter *iter)
460 {
461   g_return_if_fail (iter != NULL);
462
463   g_free (iter);
464 }
465
466 GType
467 gtk_text_iter_get_type (void)
468 {
469   static GType our_type = 0;
470   
471   if (our_type == 0)
472     our_type = g_boxed_type_register_static ("GtkTextIter",
473                                              (GBoxedCopyFunc) gtk_text_iter_copy,
474                                              (GBoxedFreeFunc) gtk_text_iter_free);
475
476   return our_type;
477 }
478
479 GtkTextLineSegment*
480 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
481 {
482   GtkTextRealIter *real;
483
484   g_return_val_if_fail (iter != NULL, NULL);
485
486   real = gtk_text_iter_make_real (iter);
487
488   if (real == NULL)
489     return NULL;
490
491   check_invariants (iter);
492
493   g_assert (real->segment != NULL);
494
495   return real->segment;
496 }
497
498 GtkTextLineSegment*
499 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
500 {
501   GtkTextRealIter *real;
502
503   g_return_val_if_fail (iter != NULL, NULL);
504
505   real = gtk_text_iter_make_real (iter);
506
507   if (real == NULL)
508     return NULL;
509
510   check_invariants (iter);
511
512   g_assert (real->any_segment != NULL);
513
514   return real->any_segment;
515 }
516
517 gint
518 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
519 {
520   GtkTextRealIter *real;
521
522   g_return_val_if_fail (iter != NULL, NULL);
523
524   real = gtk_text_iter_make_real (iter);
525
526   if (real == NULL)
527     return 0;
528
529   ensure_byte_offsets (real);
530
531   check_invariants (iter);
532
533   return real->segment_byte_offset;
534 }
535
536 gint
537 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
538 {
539   GtkTextRealIter *real;
540
541   g_return_val_if_fail (iter != NULL, NULL);
542
543   real = gtk_text_iter_make_real (iter);
544
545   if (real == NULL)
546     return 0;
547
548   ensure_char_offsets (real);
549
550   check_invariants (iter);
551
552   return real->segment_char_offset;
553 }
554
555 /* This function does not require a still-valid
556    iterator */
557 GtkTextLine*
558 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
559 {
560   const GtkTextRealIter *real;
561
562   g_return_val_if_fail (iter != NULL, NULL);
563
564   real = (const GtkTextRealIter*)iter;
565
566   return real->line;
567 }
568
569 /* This function does not require a still-valid
570    iterator */
571 GtkTextBTree*
572 _gtk_text_iter_get_btree (const GtkTextIter *iter)
573 {
574   const GtkTextRealIter *real;
575
576   g_return_val_if_fail (iter != NULL, NULL);
577
578   real = (const GtkTextRealIter*)iter;
579
580   return real->tree;
581 }
582
583 /*
584  * Conversions
585  */
586
587 /**
588  * gtk_text_iter_get_offset:
589  * @iter: an iterator
590  *
591  * Returns the character offset of an iterator.
592  * Each character in a #GtkTextBuffer has an offset,
593  * starting with 0 for the first character in the buffer.
594  * Use gtk_text_buffer_get_iter_at_offset () to convert an
595  * offset back into an iterator.
596  *
597  * Return value: a character offset
598  **/
599 gint
600 gtk_text_iter_get_offset (const GtkTextIter *iter)
601 {
602   GtkTextRealIter *real;
603
604   g_return_val_if_fail (iter != NULL, 0);
605
606   real = gtk_text_iter_make_surreal (iter);
607
608   if (real == NULL)
609     return 0;
610
611   check_invariants (iter);
612   
613   if (real->cached_char_index < 0)
614     {
615       ensure_char_offsets (real);
616       
617       real->cached_char_index =
618         _gtk_text_line_char_index (real->line);
619       real->cached_char_index += real->line_char_offset;
620     }
621
622   check_invariants (iter);
623
624   return real->cached_char_index;
625 }
626
627 /**
628  * gtk_text_iter_get_line:
629  * @iter: an iterator
630  *
631  * Returns the line number containing the iterator. Lines in
632  * a #GtkTextBuffer are numbered beginning with 0 for the first
633  * line in the buffer.
634  *
635  * Return value: a line number
636  **/
637 gint
638 gtk_text_iter_get_line (const GtkTextIter *iter)
639 {
640   GtkTextRealIter *real;
641
642   g_return_val_if_fail (iter != NULL, 0);
643
644   real = gtk_text_iter_make_surreal (iter);
645
646   if (real == NULL)
647     return 0;
648
649   if (real->cached_line_number < 0)
650     real->cached_line_number =
651       _gtk_text_line_get_number (real->line);
652
653   check_invariants (iter);
654
655   return real->cached_line_number;
656 }
657
658 /**
659  * gtk_text_iter_get_line_offset:
660  * @iter: an iterator
661  *
662  * Returns the character offset of the iterator,
663  * counting from the start of a newline-terminated line.
664  * The first character on the line has offset 0.
665  *
666  * Return value: offset from start of line
667  **/
668 gint
669 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
670 {
671   GtkTextRealIter *real;
672
673   g_return_val_if_fail (iter != NULL, 0);
674
675   real = gtk_text_iter_make_surreal (iter);
676
677   if (real == NULL)
678     return 0;
679
680   ensure_char_offsets (real);
681
682   check_invariants (iter);
683
684   return real->line_char_offset;
685 }
686
687 /**
688  * gtk_text_iter_get_line_index:
689  * @iter: an iterator
690  *
691  * Returns the byte index of the iterator, counting
692  * from the start of a newline-terminated line.
693  * Remember that #GtkTextBuffer encodes text in
694  * UTF-8, and that characters can require a variable
695  * number of bytes to represent.
696  *
697  * Return value: distance from start of line, in bytes
698  **/
699 gint
700 gtk_text_iter_get_line_index (const GtkTextIter *iter)
701 {
702   GtkTextRealIter *real;
703   
704   g_return_val_if_fail (iter != NULL, 0);
705
706   real = gtk_text_iter_make_surreal (iter);
707
708   if (real == NULL)
709     return 0;
710
711   ensure_byte_offsets (real);
712
713   check_invariants (iter);
714
715   return real->line_byte_offset;
716 }
717
718 /**
719  * gtk_text_iter_get_visible_line_offset:
720  * @iter: a #GtkTextIter
721  * 
722  * Returns the offset in characters from the start of the
723  * line to the given @iter, not counting characters that
724  * are invisible due to tags with the "invisible" flag
725  * toggled on.
726  * 
727  * Return value: offset in visible characters from the start of the line 
728  **/
729 gint
730 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
731 {
732   GtkTextRealIter *real;
733   gint vis_offset;
734   GtkTextLineSegment *seg;
735   GtkTextIter pos;
736   
737   g_return_val_if_fail (iter != NULL, 0);
738
739   real = gtk_text_iter_make_real (iter);
740
741   if (real == NULL)
742     return 0;
743
744   ensure_char_offsets (real);
745
746   check_invariants (iter);
747   
748   vis_offset = real->line_char_offset;
749
750   g_assert (vis_offset >= 0);
751   
752   _gtk_text_btree_get_iter_at_line (real->tree,
753                                     &pos,
754                                     real->line,
755                                     0);
756
757   seg = _gtk_text_iter_get_indexable_segment (&pos);
758
759   while (seg != real->segment)
760     {
761       /* This is a pretty expensive call, making the
762        * whole function pretty lame; we could keep track
763        * of current invisibility state by looking at toggle
764        * segments as we loop, and then call this function
765        * only once per line, in order to speed up the loop
766        * quite a lot.
767        */
768       if (_gtk_text_btree_char_is_invisible (&pos))
769         vis_offset -= seg->char_count;
770
771       _gtk_text_iter_forward_indexable_segment (&pos);
772
773       seg = _gtk_text_iter_get_indexable_segment (&pos);
774     }
775
776   if (_gtk_text_btree_char_is_invisible (&pos))
777     vis_offset -= real->segment_char_offset;
778   
779   return vis_offset;
780 }
781
782
783 /**
784  * gtk_text_iter_get_visible_line_index:
785  * @iter: a #GtkTextIter
786  * 
787  * Returns the number of bytes from the start of the
788  * line to the given @iter, not counting bytes that
789  * are invisible due to tags with the "invisible" flag
790  * toggled on.
791  * 
792  * Return value: byte index of @iter with respect to the start of the line
793  **/
794 gint
795 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
796 {
797   GtkTextRealIter *real;
798   gint vis_offset;
799   GtkTextLineSegment *seg;
800   GtkTextIter pos;
801   
802   g_return_val_if_fail (iter != NULL, 0);
803
804   real = gtk_text_iter_make_real (iter);
805
806   if (real == NULL)
807     return 0;
808
809   ensure_byte_offsets (real);
810
811   check_invariants (iter);
812
813   vis_offset = real->line_byte_offset;
814
815   g_assert (vis_offset >= 0);
816   
817   _gtk_text_btree_get_iter_at_line (real->tree,
818                                     &pos,
819                                     real->line,
820                                     0);
821
822   seg = _gtk_text_iter_get_indexable_segment (&pos);
823
824   while (seg != real->segment)
825     {
826       /* This is a pretty expensive call, making the
827        * whole function pretty lame; we could keep track
828        * of current invisibility state by looking at toggle
829        * segments as we loop, and then call this function
830        * only once per line, in order to speed up the loop
831        * quite a lot.
832        */
833       if (_gtk_text_btree_char_is_invisible (&pos))
834         vis_offset -= seg->byte_count;
835
836       _gtk_text_iter_forward_indexable_segment (&pos);
837
838       seg = _gtk_text_iter_get_indexable_segment (&pos);
839     }
840
841   if (_gtk_text_btree_char_is_invisible (&pos))
842     vis_offset -= real->segment_byte_offset;
843   
844   return vis_offset;
845 }
846
847 /*
848  * Dereferencing
849  */
850
851 /**
852  * gtk_text_iter_get_char:
853  * @iter: an iterator
854  *
855  * Returns the Unicode character at this iterator.  (Equivalent to
856  * operator* on a C++ iterator.)  If the element at this iterator is a
857  * non-character element, such as an image embedded in the buffer, the
858  * Unicode "unknown" character 0xFFFC is returned. If invoked on
859  * the end iterator, zero is returned; zero is not a valid Unicode character.
860  * So you can write a loop which ends when gtk_text_iter_get_char ()
861  * returns 0.
862  *
863  * Return value: a Unicode character, or 0 if @iter is not dereferenceable
864  **/
865 gunichar
866 gtk_text_iter_get_char (const GtkTextIter *iter)
867 {
868   GtkTextRealIter *real;
869
870   g_return_val_if_fail (iter != NULL, 0);
871
872   real = gtk_text_iter_make_real (iter);
873
874   if (real == NULL)
875     return 0;
876
877   check_invariants (iter);
878
879   if (gtk_text_iter_is_end (iter))
880     return 0;
881   else if (real->segment->type == &gtk_text_char_type)
882     {
883       ensure_byte_offsets (real);
884       
885       return g_utf8_get_char (real->segment->body.chars +
886                               real->segment_byte_offset);
887     }
888   else
889     {
890       /* Unicode "unknown character" 0xFFFC */
891       return GTK_TEXT_UNKNOWN_CHAR;
892     }
893 }
894
895 /**
896  * gtk_text_iter_get_slice:
897  * @start: iterator at start of a range
898  * @end: iterator at end of a range
899  *
900  * Returns the text in the given range. A "slice" is an array of
901  * characters encoded in UTF-8 format, including the Unicode "unknown"
902  * character 0xFFFC for iterable non-character elements in the buffer,
903  * such as images.  Because images are encoded in the slice, byte and
904  * character offsets in the returned array will correspond to byte
905  * offsets in the text buffer. Note that 0xFFFC can occur in normal
906  * text as well, so it is not a reliable indicator that a pixbuf or
907  * widget is in the buffer.
908  *
909  * Return value: slice of text from the buffer
910  **/
911 gchar*
912 gtk_text_iter_get_slice       (const GtkTextIter *start,
913                                const GtkTextIter *end)
914 {
915   g_return_val_if_fail (start != NULL, NULL);
916   g_return_val_if_fail (end != NULL, NULL);
917
918   check_invariants (start);
919   check_invariants (end);
920
921   return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
922 }
923
924 /**
925  * gtk_text_iter_get_text:
926  * @start: iterator at start of a range
927  * @end: iterator at end of a range
928  *
929  * Returns <emphasis>text</emphasis> in the given range.  If the range
930  * contains non-text elements such as images, the character and byte
931  * offsets in the returned string will not correspond to character and
932  * byte offsets in the buffer. If you want offsets to correspond, see
933  * gtk_text_iter_get_slice ().
934  *
935  * Return value: array of characters from the buffer
936  **/
937 gchar*
938 gtk_text_iter_get_text       (const GtkTextIter *start,
939                               const GtkTextIter *end)
940 {
941   g_return_val_if_fail (start != NULL, NULL);
942   g_return_val_if_fail (end != NULL, NULL);
943
944   check_invariants (start);
945   check_invariants (end);
946
947   return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
948 }
949
950 /**
951  * gtk_text_iter_get_visible_slice:
952  * @start: iterator at start of range
953  * @end: iterator at end of range
954  *
955  * Like gtk_text_iter_get_slice (), but invisible text is not included.
956  * Invisible text is usually invisible because a #GtkTextTag with the
957  * "invisible" attribute turned on has been applied to it.
958  *
959  * Return value: slice of text from the buffer
960  **/
961 gchar*
962 gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
963                                  const GtkTextIter  *end)
964 {
965   g_return_val_if_fail (start != NULL, NULL);
966   g_return_val_if_fail (end != NULL, NULL);
967
968   check_invariants (start);
969   check_invariants (end);
970
971   return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
972 }
973
974 /**
975  * gtk_text_iter_get_visible_text:
976  * @start: iterator at start of range
977  * @end: iterator at end of range
978  *
979  * Like gtk_text_iter_get_text (), but invisible text is not included.
980  * Invisible text is usually invisible because a #GtkTextTag with the
981  * "invisible" attribute turned on has been applied to it.
982  *
983  * Return value: string containing visible text in the range
984  **/
985 gchar*
986 gtk_text_iter_get_visible_text (const GtkTextIter  *start,
987                                 const GtkTextIter  *end)
988 {
989   g_return_val_if_fail (start != NULL, NULL);
990   g_return_val_if_fail (end != NULL, NULL);
991
992   check_invariants (start);
993   check_invariants (end);
994
995   return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
996 }
997
998 /**
999  * gtk_text_iter_get_pixbuf:
1000  * @iter: an iterator
1001  *
1002  * If the element at @iter is a pixbuf, the pixbuf is returned
1003  * (with no new reference count added). Otherwise,
1004  * %NULL is returned.
1005  *
1006  * Return value: the pixbuf at @iter
1007  **/
1008 GdkPixbuf*
1009 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1010 {
1011   GtkTextRealIter *real;
1012
1013   g_return_val_if_fail (iter != NULL, NULL);
1014
1015   real = gtk_text_iter_make_real (iter);
1016
1017   if (real == NULL)
1018     return NULL;
1019
1020   check_invariants (iter);
1021
1022   if (real->segment->type != &gtk_text_pixbuf_type)
1023     return NULL;
1024   else
1025     return real->segment->body.pixbuf.pixbuf;
1026 }
1027
1028 /**
1029  * gtk_text_iter_get_child_anchor:
1030  * @iter: an iterator
1031  *
1032  * If the location at @iter contains a child anchor, the
1033  * anchor is returned (with no new reference count added). Otherwise,
1034  * %NULL is returned.
1035  *
1036  * Return value: the anchor at @iter
1037  **/
1038 GtkTextChildAnchor*
1039 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1040 {
1041   GtkTextRealIter *real;
1042
1043   g_return_val_if_fail (iter != NULL, NULL);
1044
1045   real = gtk_text_iter_make_real (iter);
1046
1047   if (real == NULL)
1048     return NULL;
1049
1050   check_invariants (iter);
1051
1052   if (real->segment->type != &gtk_text_child_type)
1053     return NULL;
1054   else
1055     return real->segment->body.child.obj;
1056 }
1057
1058 /**
1059  * gtk_text_iter_get_marks:
1060  * @iter: an iterator
1061  *
1062  * Returns a list of all #GtkTextMark at this location. Because marks
1063  * are not iterable (they don't take up any "space" in the buffer,
1064  * they are just marks in between iterable locations), multiple marks
1065  * can exist in the same place. The returned list is not in any
1066  * meaningful order.
1067  *
1068  * Return value: list of #GtkTextMark
1069  **/
1070 GSList*
1071 gtk_text_iter_get_marks (const GtkTextIter *iter)
1072 {
1073   GtkTextRealIter *real;
1074   GtkTextLineSegment *seg;
1075   GSList *retval;
1076
1077   g_return_val_if_fail (iter != NULL, NULL);
1078
1079   real = gtk_text_iter_make_real (iter);
1080
1081   if (real == NULL)
1082     return NULL;
1083
1084   check_invariants (iter);
1085
1086   retval = NULL;
1087   seg = real->any_segment;
1088   while (seg != real->segment)
1089     {
1090       if (seg->type == &gtk_text_left_mark_type ||
1091           seg->type == &gtk_text_right_mark_type)
1092         retval = g_slist_prepend (retval, seg->body.mark.obj);
1093
1094       seg = seg->next;
1095     }
1096
1097   /* The returned list isn't guaranteed to be in any special order,
1098      and it isn't. */
1099   return retval;
1100 }
1101
1102 /**
1103  * gtk_text_iter_get_toggled_tags:
1104  * @iter: an iterator
1105  * @toggled_on: %TRUE to get toggled-on tags
1106  *
1107  * Returns a list of #GtkTextTag that are toggled on or off at this
1108  * point.  (If @toggled_on is %TRUE, the list contains tags that are
1109  * toggled on.) If a tag is toggled on at @iter, then some non-empty
1110  * range of characters following @iter has that tag applied to it.  If
1111  * a tag is toggled off, then some non-empty range following @iter
1112  * does <emphasis>not</emphasis> have the tag applied to it.
1113  *
1114  * Return value: tags toggled at this point
1115  **/
1116 GSList*
1117 gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
1118                                  gboolean            toggled_on)
1119 {
1120   GtkTextRealIter *real;
1121   GtkTextLineSegment *seg;
1122   GSList *retval;
1123
1124   g_return_val_if_fail (iter != NULL, NULL);
1125
1126   real = gtk_text_iter_make_real (iter);
1127
1128   if (real == NULL)
1129     return NULL;
1130
1131   check_invariants (iter);
1132
1133   retval = NULL;
1134   seg = real->any_segment;
1135   while (seg != real->segment)
1136     {
1137       if (toggled_on)
1138         {
1139           if (seg->type == &gtk_text_toggle_on_type)
1140             {
1141               retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1142             }
1143         }
1144       else
1145         {
1146           if (seg->type == &gtk_text_toggle_off_type)
1147             {
1148               retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1149             }
1150         }
1151
1152       seg = seg->next;
1153     }
1154
1155   /* The returned list isn't guaranteed to be in any special order,
1156      and it isn't. */
1157   return retval;
1158 }
1159
1160 /**
1161  * gtk_text_iter_begins_tag:
1162  * @iter: an iterator
1163  * @tag: a #GtkTextTag, or %NULL
1164  *
1165  * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1166  * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1167  * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1168  * <emphasis>start</emphasis> of the tagged range;
1169  * gtk_text_iter_has_tag () tells you whether an iterator is
1170  * <emphasis>within</emphasis> a tagged range.
1171  *
1172  * Return value: whether @iter is the start of a range tagged with @tag
1173  **/
1174 gboolean
1175 gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1176                              GtkTextTag         *tag)
1177 {
1178   GtkTextRealIter *real;
1179   GtkTextLineSegment *seg;
1180
1181   g_return_val_if_fail (iter != NULL, FALSE);
1182
1183   real = gtk_text_iter_make_real (iter);
1184
1185   if (real == NULL)
1186     return FALSE;
1187
1188   check_invariants (iter);
1189
1190   seg = real->any_segment;
1191   while (seg != real->segment)
1192     {
1193       if (seg->type == &gtk_text_toggle_on_type)
1194         {
1195           if (tag == NULL ||
1196               seg->body.toggle.info->tag == tag)
1197             return TRUE;
1198         }
1199
1200       seg = seg->next;
1201     }
1202
1203   return FALSE;
1204 }
1205
1206 /**
1207  * gtk_text_iter_ends_tag:
1208  * @iter: an iterator
1209  * @tag: a #GtkTextTag, or %NULL
1210  *
1211  * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1212  * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1213  * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1214  * <emphasis>end</emphasis> of the tagged range;
1215  * gtk_text_iter_has_tag () tells you whether an iterator is
1216  * <emphasis>within</emphasis> a tagged range.
1217  *
1218  * Return value: whether @iter is the end of a range tagged with @tag
1219  *
1220  **/
1221 gboolean
1222 gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1223                           GtkTextTag         *tag)
1224 {
1225   GtkTextRealIter *real;
1226   GtkTextLineSegment *seg;
1227
1228   g_return_val_if_fail (iter != NULL, FALSE);
1229
1230   real = gtk_text_iter_make_real (iter);
1231
1232   if (real == NULL)
1233     return FALSE;
1234
1235   check_invariants (iter);
1236
1237   seg = real->any_segment;
1238   while (seg != real->segment)
1239     {
1240       if (seg->type == &gtk_text_toggle_off_type)
1241         {
1242           if (tag == NULL ||
1243               seg->body.toggle.info->tag == tag)
1244             return TRUE;
1245         }
1246
1247       seg = seg->next;
1248     }
1249
1250   return FALSE;
1251 }
1252
1253 /**
1254  * gtk_text_iter_toggles_tag:
1255  * @iter: an iterator
1256  * @tag: a #GtkTextTag, or %NULL
1257  *
1258  * This is equivalent to (gtk_text_iter_begins_tag () ||
1259  * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1260  * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1261  *
1262  * Return value: whether @tag is toggled on or off at @iter
1263  **/
1264 gboolean
1265 gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
1266                            GtkTextTag         *tag)
1267 {
1268   GtkTextRealIter *real;
1269   GtkTextLineSegment *seg;
1270
1271   g_return_val_if_fail (iter != NULL, FALSE);
1272
1273   real = gtk_text_iter_make_real (iter);
1274
1275   if (real == NULL)
1276     return FALSE;
1277
1278   check_invariants (iter);
1279
1280   seg = real->any_segment;
1281   while (seg != real->segment)
1282     {
1283       if ( (seg->type == &gtk_text_toggle_off_type ||
1284             seg->type == &gtk_text_toggle_on_type) &&
1285            (tag == NULL ||
1286             seg->body.toggle.info->tag == tag) )
1287         return TRUE;
1288
1289       seg = seg->next;
1290     }
1291
1292   return FALSE;
1293 }
1294
1295 /**
1296  * gtk_text_iter_has_tag:
1297  * @iter: an iterator
1298  * @tag: a #GtkTextTag
1299  *
1300  * Returns %TRUE if @iter is within a range tagged with @tag.
1301  *
1302  * Return value: whether @iter is tagged with @tag
1303  **/
1304 gboolean
1305 gtk_text_iter_has_tag (const GtkTextIter   *iter,
1306                        GtkTextTag          *tag)
1307 {
1308   GtkTextRealIter *real;
1309
1310   g_return_val_if_fail (iter != NULL, FALSE);
1311   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1312
1313   real = gtk_text_iter_make_surreal (iter);
1314
1315   if (real == NULL)
1316     return FALSE;
1317
1318   check_invariants (iter);
1319
1320   if (real->line_byte_offset >= 0)
1321     {
1322       return _gtk_text_line_byte_has_tag (real->line, real->tree,
1323                                           real->line_byte_offset, tag);
1324     }
1325   else
1326     {
1327       g_assert (real->line_char_offset >= 0);
1328       return _gtk_text_line_char_has_tag (real->line, real->tree,
1329                                           real->line_char_offset, tag);
1330     }
1331 }
1332
1333 /**
1334  * gtk_text_iter_get_tags:
1335  * @iter: a #GtkTextIter
1336  * 
1337  * Returns a list of tags that apply to @iter, in ascending order of
1338  * priority (highest-priority tags are last). The #GtkTextTag in the
1339  * list don't have a reference added, but you have to free the list
1340  * itself.
1341  * 
1342  * Return value: list of #GtkTextTag
1343  **/
1344 GSList*
1345 gtk_text_iter_get_tags (const GtkTextIter *iter)
1346 {
1347   GtkTextTag** tags;
1348   gint tag_count = 0;
1349   gint i;
1350   GSList *retval;
1351   
1352   g_return_val_if_fail (iter != NULL, NULL);
1353   
1354   /* Get the tags at this spot */
1355   tags = _gtk_text_btree_get_tags (iter, &tag_count);
1356
1357   /* No tags, use default style */
1358   if (tags == NULL || tag_count == 0)
1359     {
1360       if (tags)
1361         g_free (tags);
1362
1363       return NULL;
1364     }
1365
1366   /* Sort tags in ascending order of priority */
1367   _gtk_text_tag_array_sort (tags, tag_count);
1368
1369   retval = NULL;
1370   i = 0;
1371   while (i < tag_count)
1372     {
1373       retval = g_slist_prepend (retval, tags[i]);
1374       ++i;
1375     }
1376   
1377   g_free (tags);
1378
1379   /* Return tags in ascending order of priority */
1380   return g_slist_reverse (retval);
1381 }
1382
1383 /**
1384  * gtk_text_iter_editable:
1385  * @iter: an iterator
1386  * @default_setting: %TRUE if text is editable by default
1387  *
1388  * Returns whether the character at @iter is within an editable region
1389  * of text.  Non-editable text is "locked" and can't be changed by the
1390  * user via #GtkTextView. This function is simply a convenience
1391  * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1392  * to this text affect editability, @default_setting will be returned.
1393  *
1394  * You don't want to use this function to decide whether text can be
1395  * inserted at @iter, because for insertion you don't want to know
1396  * whether the char at @iter is inside an editable range, you want to
1397  * know whether a new character inserted at @iter would be inside an
1398  * editable range. Use gtk_text_iter_can_insert() to handle this
1399  * case.
1400  * 
1401  * Return value: whether @iter is inside an editable range
1402  **/
1403 gboolean
1404 gtk_text_iter_editable (const GtkTextIter *iter,
1405                         gboolean           default_setting)
1406 {
1407   GtkTextAttributes *values;
1408   gboolean retval;
1409
1410   g_return_val_if_fail (iter != NULL, FALSE);
1411   
1412   values = gtk_text_attributes_new ();
1413
1414   values->editable = default_setting;
1415
1416   gtk_text_iter_get_attributes (iter, values);
1417
1418   retval = values->editable;
1419
1420   gtk_text_attributes_unref (values);
1421
1422   return retval;
1423 }
1424
1425 /**
1426  * gtk_text_iter_can_insert:
1427  * @iter: an iterator
1428  * @default_editability: %TRUE if text is editable by default
1429  * 
1430  * Considering the default editability of the buffer, and tags that
1431  * affect editability, determines whether text inserted at @iter would
1432  * be editable. If text inserted at @iter would be editable then the
1433  * user should be allowed to insert text at @iter.
1434  * gtk_text_buffer_insert_interactive() uses this function to decide
1435  * whether insertions are allowed at a given position.
1436  * 
1437  * Return value: whether text inserted at @iter would be editable
1438  **/
1439 gboolean
1440 gtk_text_iter_can_insert (const GtkTextIter *iter,
1441                           gboolean           default_editability)
1442 {
1443   g_return_val_if_fail (iter != NULL, FALSE);
1444   
1445   if (gtk_text_iter_editable (iter, default_editability))
1446     return TRUE;
1447   /* If at start/end of buffer, default editability is used */
1448   else if ((gtk_text_iter_is_start (iter) ||
1449             gtk_text_iter_is_end (iter)) &&
1450            default_editability)
1451     return TRUE;
1452   else
1453     {
1454       /* if iter isn't editable, and the char before iter is,
1455        * then iter is the first char in an editable region
1456        * and thus insertion at iter results in editable text.
1457        */
1458       GtkTextIter prev = *iter;
1459       gtk_text_iter_backward_char (&prev);
1460       return gtk_text_iter_editable (&prev, default_editability);
1461     }
1462 }
1463
1464
1465 /**
1466  * gtk_text_iter_get_language:
1467  * @iter: an iterator
1468  *
1469  * A convenience wrapper around gtk_text_iter_get_attributes (),
1470  * which returns the language in effect at @iter. If no tags affecting
1471  * language apply to @iter, the return value is identical to that of
1472  * gtk_get_default_language ().
1473  *
1474  * Return value: language in effect at @iter
1475  **/
1476 PangoLanguage *
1477 gtk_text_iter_get_language (const GtkTextIter *iter)
1478 {
1479   GtkTextAttributes *values;
1480   PangoLanguage *retval;
1481   
1482   values = gtk_text_attributes_new ();
1483
1484   gtk_text_iter_get_attributes (iter, values);
1485
1486   retval = values->language;
1487
1488   gtk_text_attributes_unref (values);
1489
1490   return retval;
1491 }
1492
1493 /**
1494  * gtk_text_iter_starts_line:
1495  * @iter: an iterator
1496  *
1497  * Returns %TRUE if @iter begins a paragraph,
1498  * i.e. if gtk_text_iter_get_line_offset () would return 0.
1499  * However this function is potentially more efficient than
1500  * gtk_text_iter_get_line_offset () because it doesn't have to compute
1501  * the offset, it just has to see whether it's 0.
1502  *
1503  * Return value: whether @iter begins a line
1504  **/
1505 gboolean
1506 gtk_text_iter_starts_line (const GtkTextIter   *iter)
1507 {
1508   GtkTextRealIter *real;
1509
1510   g_return_val_if_fail (iter != NULL, FALSE);
1511
1512   real = gtk_text_iter_make_surreal (iter);
1513
1514   if (real == NULL)
1515     return FALSE;
1516
1517   check_invariants (iter);
1518
1519   if (real->line_byte_offset >= 0)
1520     {
1521       return (real->line_byte_offset == 0);
1522     }
1523   else
1524     {
1525       g_assert (real->line_char_offset >= 0);
1526       return (real->line_char_offset == 0);
1527     }
1528 }
1529
1530 /**
1531  * gtk_text_iter_ends_line:
1532  * @iter: an iterator
1533  *
1534  * Returns %TRUE if @iter points to the start of the paragraph
1535  * delimiter characters for a line (delimiters will be either a
1536  * newline, a carriage return, a carriage return followed by a
1537  * newline, or a Unicode paragraph separator character). Note that an
1538  * iterator pointing to the \n of a \r\n pair will not be counted as
1539  * the end of a line, the line ends before the \r. The end iterator is
1540  * considered to be at the end of a line, even though there are no
1541  * paragraph delimiter chars there.
1542  *
1543  * Return value: whether @iter is at the end of a line
1544  **/
1545 gboolean
1546 gtk_text_iter_ends_line (const GtkTextIter   *iter)
1547 {
1548   GtkTextRealIter *real;
1549   gunichar wc;
1550   
1551   g_return_val_if_fail (iter != NULL, FALSE);
1552
1553   real = gtk_text_iter_make_real (iter);
1554   
1555   check_invariants (iter);
1556
1557   /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1558    * Unicode 3.0; update this if that changes.
1559    */
1560 #define PARAGRAPH_SEPARATOR 0x2029
1561
1562   wc = gtk_text_iter_get_char (iter);
1563   
1564   if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1565     return TRUE;
1566   else if (wc == '\n')
1567     {
1568       /* need to determine if a \r precedes the \n, in which case
1569        * we aren't the end of the line
1570        */
1571       GtkTextIter tmp = *iter;
1572       if (!gtk_text_iter_backward_char (&tmp))
1573         return TRUE;
1574
1575       return gtk_text_iter_get_char (&tmp) != '\r';
1576     }
1577   else
1578     return FALSE;
1579 }
1580
1581 /**
1582  * gtk_text_iter_is_end:
1583  * @iter: an iterator
1584  *
1585  * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1586  * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1587  * the most efficient way to check whether an iterator is the end
1588  * iterator.
1589  *
1590  * Return value: whether @iter is the end iterator
1591  **/
1592 gboolean
1593 gtk_text_iter_is_end (const GtkTextIter *iter)
1594 {
1595   GtkTextRealIter *real;
1596
1597   g_return_val_if_fail (iter != NULL, FALSE);
1598
1599   real = gtk_text_iter_make_surreal (iter);
1600
1601   if (real == NULL)
1602     return FALSE;
1603
1604   check_invariants (iter);
1605
1606   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1607     return FALSE;
1608
1609   /* Now we need the segments validated */
1610   real = gtk_text_iter_make_real (iter);
1611
1612   if (real == NULL)
1613     return FALSE;
1614   
1615   return _gtk_text_btree_is_end (real->tree, real->line,
1616                                  real->segment,
1617                                  real->segment_byte_offset,
1618                                  real->segment_char_offset);
1619 }
1620
1621 /**
1622  * gtk_text_iter_is_start:
1623  * @iter: an iterator
1624  *
1625  * Returns %TRUE if @iter is the first iterator in the buffer, that is
1626  * if @iter has a character offset of 0.
1627  *
1628  * Return value: whether @iter is the first in the buffer
1629  **/
1630 gboolean
1631 gtk_text_iter_is_start (const GtkTextIter *iter)
1632 {
1633   return gtk_text_iter_get_offset (iter) == 0;
1634 }
1635
1636 /**
1637  * gtk_text_iter_get_chars_in_line:
1638  * @iter: an iterator
1639  *
1640  * Returns the number of characters in the line containing @iter,
1641  * including the paragraph delimiters.
1642  *
1643  * Return value: number of characters in the line
1644  **/
1645 gint
1646 gtk_text_iter_get_chars_in_line (const GtkTextIter   *iter)
1647 {
1648   GtkTextRealIter *real;
1649   gint count;
1650   GtkTextLineSegment *seg;
1651
1652   g_return_val_if_fail (iter != NULL, FALSE);
1653
1654   real = gtk_text_iter_make_surreal (iter);
1655
1656   if (real == NULL)
1657     return 0;
1658
1659   check_invariants (iter);
1660
1661   if (real->line_char_offset >= 0)
1662     {
1663       /* We can start at the segments we've already found. */
1664       count = real->line_char_offset - real->segment_char_offset;
1665       seg = _gtk_text_iter_get_indexable_segment (iter);
1666     }
1667   else
1668     {
1669       /* count whole line. */
1670       seg = real->line->segments;
1671       count = 0;
1672     }
1673
1674
1675   while (seg != NULL)
1676     {
1677       count += seg->char_count;
1678
1679       seg = seg->next;
1680     }
1681
1682   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1683     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1684   
1685   return count;
1686 }
1687
1688 /**
1689  * gtk_text_iter_get_bytes_in_line:
1690  * @iter: an iterator
1691  *
1692  * Returns the number of bytes in the line containing @iter,
1693  * including the paragraph delimiters.
1694  *
1695  * Return value: number of bytes in the line
1696  **/
1697 gint
1698 gtk_text_iter_get_bytes_in_line (const GtkTextIter   *iter)
1699 {
1700   GtkTextRealIter *real;
1701   gint count;
1702   GtkTextLineSegment *seg;
1703
1704   g_return_val_if_fail (iter != NULL, FALSE);
1705
1706   real = gtk_text_iter_make_surreal (iter);
1707
1708   if (real == NULL)
1709     return 0;
1710
1711   check_invariants (iter);
1712
1713   if (real->line_byte_offset >= 0)
1714     {
1715       /* We can start at the segments we've already found. */
1716       count = real->line_byte_offset - real->segment_byte_offset;
1717       seg = _gtk_text_iter_get_indexable_segment (iter);
1718     }
1719   else
1720     {
1721       /* count whole line. */
1722       seg = real->line->segments;
1723       count = 0;
1724     }
1725
1726   while (seg != NULL)
1727     {
1728       count += seg->byte_count;
1729
1730       seg = seg->next;
1731     }
1732
1733   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1734     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1735   
1736   return count;
1737 }
1738
1739 /**
1740  * gtk_text_iter_get_attributes:
1741  * @iter: an iterator
1742  * @values: a #GtkTextAttributes to be filled in
1743  *
1744  * Computes the effect of any tags applied to this spot in the
1745  * text. The @values parameter should be initialized to the default
1746  * settings you wish to use if no tags are in effect. You'd typically
1747  * obtain the defaults from gtk_text_view_get_default_attributes().
1748  *
1749  * gtk_text_iter_get_attributes () will modify @values, applying the
1750  * effects of any tags present at @iter. If any tags affected @values,
1751  * the function returns %TRUE.
1752  *
1753  * Return value: %TRUE if @values was modified
1754  **/
1755 gboolean
1756 gtk_text_iter_get_attributes (const GtkTextIter  *iter,
1757                               GtkTextAttributes  *values)
1758 {
1759   GtkTextTag** tags;
1760   gint tag_count = 0;
1761
1762   /* Get the tags at this spot */
1763   tags = _gtk_text_btree_get_tags (iter, &tag_count);
1764
1765   /* No tags, use default style */
1766   if (tags == NULL || tag_count == 0)
1767     {
1768       if (tags)
1769         g_free (tags);
1770
1771       return FALSE;
1772     }
1773
1774   /* Sort tags in ascending order of priority */
1775   _gtk_text_tag_array_sort (tags, tag_count);
1776
1777   _gtk_text_attributes_fill_from_tags (values,
1778                                        tags,
1779                                        tag_count);
1780
1781   g_free (tags);
1782
1783   return TRUE;
1784 }
1785
1786 /*
1787  * Increments/decrements
1788  */
1789
1790 /* The return value of this indicates WHETHER WE MOVED.
1791  * The return value of public functions indicates
1792  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1793  *
1794  * This function will not change the iterator if
1795  * it's already on the last (end iter) line, i.e. it
1796  * won't move to the end of the last line.
1797  */
1798 static gboolean
1799 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1800 {
1801   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1802     {
1803       GtkTextLine *new_line;
1804       
1805       new_line = _gtk_text_line_next (real->line);
1806       g_assert (new_line);
1807       g_assert (new_line != real->line);
1808       g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1809       
1810       real->line = new_line;
1811
1812       real->line_byte_offset = 0;
1813       real->line_char_offset = 0;
1814
1815       real->segment_byte_offset = 0;
1816       real->segment_char_offset = 0;
1817
1818       /* Find first segments in new line */
1819       real->any_segment = real->line->segments;
1820       real->segment = real->any_segment;
1821       while (real->segment->char_count == 0)
1822         real->segment = real->segment->next;
1823
1824       return TRUE;
1825     }
1826   else
1827     {
1828       /* There is no way to move forward a line; we were already at
1829        * the line containing the end iterator.
1830        * However we may not be at the end iterator itself.
1831        */
1832       
1833       return FALSE;
1834     }
1835 }
1836
1837 #if 0
1838 /* The return value of this indicates WHETHER WE MOVED.
1839  * The return value of public functions indicates
1840  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1841  *
1842  * This function is currently unused, thus it is #if-0-ed. It is
1843  * left here, since it's non-trivial code that might be useful in
1844  * the future.
1845  */
1846 static gboolean
1847 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1848 {
1849   GtkTextLine *new_line;
1850
1851   new_line = _gtk_text_line_previous (real->line);
1852
1853   g_assert (new_line != real->line);
1854
1855   if (new_line != NULL)
1856     {
1857       real->line = new_line;
1858
1859       real->line_byte_offset = 0;
1860       real->line_char_offset = 0;
1861
1862       real->segment_byte_offset = 0;
1863       real->segment_char_offset = 0;
1864
1865       /* Find first segments in new line */
1866       real->any_segment = real->line->segments;
1867       real->segment = real->any_segment;
1868       while (real->segment->char_count == 0)
1869         real->segment = real->segment->next;
1870
1871       return TRUE;
1872     }
1873   else
1874     {
1875       /* There is no way to move backward; we were already
1876          at the first line. */
1877
1878       /* We leave real->line as-is */
1879
1880       /* Note that we didn't clamp to the start of the first line. */
1881
1882       return FALSE;
1883     }
1884 }
1885 #endif 
1886
1887 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1888  * DEREFERENCEABLE)
1889  */
1890 static gboolean
1891 forward_char (GtkTextRealIter *real)
1892 {
1893   GtkTextIter *iter = (GtkTextIter*)real;
1894
1895   check_invariants ((GtkTextIter*)real);
1896
1897   ensure_char_offsets (real);
1898
1899   if ( (real->segment_char_offset + 1) == real->segment->char_count)
1900     {
1901       /* Need to move to the next segment; if no next segment,
1902          need to move to next line. */
1903       return _gtk_text_iter_forward_indexable_segment (iter);
1904     }
1905   else
1906     {
1907       /* Just moving within a segment. Keep byte count
1908          up-to-date, if it was already up-to-date. */
1909
1910       g_assert (real->segment->type == &gtk_text_char_type);
1911
1912       if (real->line_byte_offset >= 0)
1913         {
1914           gint bytes;
1915           const char * start =
1916             real->segment->body.chars + real->segment_byte_offset;
1917
1918           bytes = g_utf8_next_char (start) - start;
1919
1920           real->line_byte_offset += bytes;
1921           real->segment_byte_offset += bytes;
1922
1923           g_assert (real->segment_byte_offset < real->segment->byte_count);
1924         }
1925
1926       real->line_char_offset += 1;
1927       real->segment_char_offset += 1;
1928
1929       adjust_char_index (real, 1);
1930
1931       g_assert (real->segment_char_offset < real->segment->char_count);
1932
1933       /* We moved into the middle of a segment, so the any_segment
1934          must now be the segment we're in the middle of. */
1935       real->any_segment = real->segment;
1936
1937       check_invariants ((GtkTextIter*)real);
1938
1939       if (gtk_text_iter_is_end ((GtkTextIter*)real))
1940         return FALSE;
1941       else
1942         return TRUE;
1943     }
1944 }
1945
1946 gboolean
1947 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1948 {
1949   /* Need to move to the next segment; if no next segment,
1950      need to move to next line. */
1951   GtkTextLineSegment *seg;
1952   GtkTextLineSegment *any_seg;
1953   GtkTextRealIter *real;
1954   gint chars_skipped;
1955   gint bytes_skipped;
1956
1957   g_return_val_if_fail (iter != NULL, FALSE);
1958
1959   real = gtk_text_iter_make_real (iter);
1960
1961   if (real == NULL)
1962     return FALSE;
1963
1964   check_invariants (iter);
1965
1966   if (real->line_char_offset >= 0)
1967     {
1968       chars_skipped = real->segment->char_count - real->segment_char_offset;
1969       g_assert (chars_skipped > 0);
1970     }
1971   else
1972     chars_skipped = 0;
1973
1974   if (real->line_byte_offset >= 0)
1975     {
1976       bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1977       g_assert (bytes_skipped > 0);
1978     }
1979   else
1980     bytes_skipped = 0;
1981
1982   /* Get first segment of any kind */
1983   any_seg = real->segment->next;
1984   /* skip non-indexable segments, if any */
1985   seg = any_seg;
1986   while (seg != NULL && seg->char_count == 0)
1987     seg = seg->next;
1988
1989   if (seg != NULL)
1990     {
1991       real->any_segment = any_seg;
1992       real->segment = seg;
1993
1994       if (real->line_byte_offset >= 0)
1995         {
1996           g_assert (bytes_skipped > 0);
1997           real->segment_byte_offset = 0;
1998           real->line_byte_offset += bytes_skipped;
1999         }
2000
2001       if (real->line_char_offset >= 0)
2002         {
2003           g_assert (chars_skipped > 0);
2004           real->segment_char_offset = 0;
2005           real->line_char_offset += chars_skipped;
2006           adjust_char_index (real, chars_skipped);
2007         }
2008
2009       check_invariants (iter);
2010
2011       return !gtk_text_iter_is_end (iter);
2012     }
2013   else
2014     {
2015       /* End of the line */
2016       if (forward_line_leaving_caches_unmodified (real))
2017         {
2018           adjust_line_number (real, 1);
2019           if (real->line_char_offset >= 0)
2020             adjust_char_index (real, chars_skipped);
2021
2022           g_assert (real->line_byte_offset == 0);
2023           g_assert (real->line_char_offset == 0);
2024           g_assert (real->segment_byte_offset == 0);
2025           g_assert (real->segment_char_offset == 0);
2026           g_assert (gtk_text_iter_starts_line (iter));
2027
2028           check_invariants (iter);
2029
2030           return !gtk_text_iter_is_end (iter);
2031         }
2032       else
2033         {
2034           /* End of buffer, but iter is still at start of last segment,
2035            * not at the end iterator. We put it on the end iterator.
2036            */
2037           
2038           check_invariants (iter);
2039
2040           g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2041           g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2042
2043           gtk_text_iter_forward_to_line_end (iter);
2044
2045           g_assert (gtk_text_iter_is_end (iter));
2046           
2047           return FALSE;
2048         }
2049     }
2050 }
2051
2052 static gboolean
2053 at_last_indexable_segment (GtkTextRealIter *real)
2054 {
2055   GtkTextLineSegment *seg;
2056
2057   /* Return TRUE if there are no indexable segments after
2058    * this iterator.
2059    */
2060
2061   seg = real->segment->next;
2062   while (seg)
2063     {
2064       if (seg->char_count > 0)
2065         return FALSE;
2066       seg = seg->next;
2067     }
2068   return TRUE;
2069 }
2070
2071 /* Goes back to the start of the next segment, even if
2072  * we're not at the start of the current segment (always
2073  * ends up on a different segment if it returns TRUE)
2074  */
2075 gboolean
2076 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2077 {
2078   /* Move to the start of the previous segment; if no previous
2079    * segment, to the last segment in the previous line. This is
2080    * inherently a bit inefficient due to the singly-linked list and
2081    * tree nodes, but we can't afford the RAM for doubly-linked.
2082    */
2083   GtkTextRealIter *real;
2084   GtkTextLineSegment *seg;
2085   GtkTextLineSegment *any_seg;
2086   GtkTextLineSegment *prev_seg;
2087   GtkTextLineSegment *prev_any_seg;
2088   gint bytes_skipped;
2089   gint chars_skipped;
2090
2091   g_return_val_if_fail (iter != NULL, FALSE);
2092
2093   real = gtk_text_iter_make_real (iter);
2094
2095   if (real == NULL)
2096     return FALSE;
2097
2098   check_invariants (iter);
2099
2100   /* Find first segments in line */
2101   any_seg = real->line->segments;
2102   seg = any_seg;
2103   while (seg->char_count == 0)
2104     seg = seg->next;
2105
2106   if (seg == real->segment)
2107     {
2108       /* Could probably do this case faster by hand-coding the
2109        * iteration.
2110        */
2111
2112       /* We were already at the start of a line;
2113        * go back to the previous line.
2114        */
2115       if (gtk_text_iter_backward_line (iter))
2116         {
2117           /* Go forward to last indexable segment in line. */
2118           while (!at_last_indexable_segment (real))
2119             _gtk_text_iter_forward_indexable_segment (iter);
2120
2121           check_invariants (iter);
2122
2123           return TRUE;
2124         }
2125       else
2126         return FALSE; /* We were at the start of the first line. */
2127     }
2128
2129   /* We must be in the middle of a line; so find the indexable
2130    * segment just before our current segment.
2131    */
2132   g_assert (seg != real->segment);
2133   do
2134     {
2135       prev_seg = seg;
2136       prev_any_seg = any_seg;
2137
2138       any_seg = seg->next;
2139       seg = any_seg;
2140       while (seg->char_count == 0)
2141         seg = seg->next;
2142     }
2143   while (seg != real->segment);
2144
2145   g_assert (prev_seg != NULL);
2146   g_assert (prev_any_seg != NULL);
2147   g_assert (prev_seg->char_count > 0);
2148
2149   /* We skipped the entire previous segment, plus any
2150    * chars we were into the current segment.
2151    */
2152   if (real->segment_byte_offset >= 0)
2153     bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2154   else
2155     bytes_skipped = -1;
2156
2157   if (real->segment_char_offset >= 0)
2158     chars_skipped = prev_seg->char_count + real->segment_char_offset;
2159   else
2160     chars_skipped = -1;
2161
2162   real->segment = prev_seg;
2163   real->any_segment = prev_any_seg;
2164   real->segment_byte_offset = 0;
2165   real->segment_char_offset = 0;
2166
2167   if (bytes_skipped >= 0)
2168     {
2169       if (real->line_byte_offset >= 0)
2170         {
2171           real->line_byte_offset -= bytes_skipped;
2172           g_assert (real->line_byte_offset >= 0);
2173         }
2174     }
2175   else
2176     real->line_byte_offset = -1;
2177
2178   if (chars_skipped >= 0)
2179     {
2180       if (real->line_char_offset >= 0)
2181         {
2182           real->line_char_offset -= chars_skipped;
2183           g_assert (real->line_char_offset >= 0);
2184         }
2185
2186       if (real->cached_char_index >= 0)
2187         {
2188           real->cached_char_index -= chars_skipped;
2189           g_assert (real->cached_char_index >= 0);
2190         }
2191     }
2192   else
2193     {
2194       real->line_char_offset = -1;
2195       real->cached_char_index = -1;
2196     }
2197
2198   /* line number is unchanged. */
2199
2200   check_invariants (iter);
2201
2202   return TRUE;
2203 }
2204
2205 /**
2206  * gtk_text_iter_forward_char:
2207  * @iter: an iterator
2208  *
2209  * Moves @iter forward by one character offset. Note that images
2210  * embedded in the buffer occupy 1 character slot, so
2211  * gtk_text_iter_forward_char () may actually move onto an image instead
2212  * of a character, if you have images in your buffer.  If @iter is the
2213  * end iterator or one character before it, @iter will now point at
2214  * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2215  * convenience when writing loops.
2216  *
2217  * Return value: whether @iter moved and is dereferenceable
2218  **/
2219 gboolean
2220 gtk_text_iter_forward_char (GtkTextIter *iter)
2221 {
2222   GtkTextRealIter *real;
2223
2224   g_return_val_if_fail (iter != NULL, FALSE);
2225
2226   real = gtk_text_iter_make_real (iter);
2227
2228   if (real == NULL)
2229     return FALSE;
2230   else
2231     {
2232       check_invariants (iter);
2233       return forward_char (real);
2234     }
2235 }
2236
2237 /**
2238  * gtk_text_iter_backward_char:
2239  * @iter: an iterator
2240  *
2241  * Moves backward by one character offset. Returns %TRUE if movement
2242  * was possible; if @iter was the first in the buffer (character
2243  * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2244  * writing loops.
2245  *
2246  * Return value: whether movement was possible
2247  **/
2248 gboolean
2249 gtk_text_iter_backward_char (GtkTextIter *iter)
2250 {
2251   g_return_val_if_fail (iter != NULL, FALSE);
2252
2253   check_invariants (iter);
2254
2255   return gtk_text_iter_backward_chars (iter, 1);
2256 }
2257
2258 /*
2259   Definitely we should try to linear scan as often as possible for
2260   movement within a single line, because we can't use the BTree to
2261   speed within-line searches up; for movement between lines, we would
2262   like to avoid the linear scan probably.
2263
2264   Instead of using this constant, it might be nice to cache the line
2265   length in the iterator and linear scan if motion is within a single
2266   line.
2267
2268   I guess you'd have to profile the various approaches.
2269 */
2270 #define MAX_LINEAR_SCAN 150
2271
2272
2273 /**
2274  * gtk_text_iter_forward_chars:
2275  * @iter: an iterator
2276  * @count: number of characters to move, may be negative
2277  *
2278  * Moves @count characters if possible (if @count would move past the
2279  * start or end of the buffer, moves to the start or end of the
2280  * buffer). The return value indicates whether the new position of
2281  * @iter is different from its original position, and dereferenceable
2282  * (the last iterator in the buffer is not dereferenceable). If @count
2283  * is 0, the function does nothing and returns %FALSE.
2284  *
2285  * Return value: whether @iter moved and is dereferenceable
2286  **/
2287 gboolean
2288 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2289 {
2290   GtkTextRealIter *real;
2291
2292   g_return_val_if_fail (iter != NULL, FALSE);
2293
2294   FIX_OVERFLOWS (count);
2295   
2296   real = gtk_text_iter_make_real (iter);
2297
2298   if (real == NULL)
2299     return FALSE;
2300   else if (count == 0)
2301     return FALSE;
2302   else if (count < 0)
2303     return gtk_text_iter_backward_chars (iter, 0 - count);
2304   else if (count < MAX_LINEAR_SCAN)
2305     {
2306       check_invariants (iter);
2307
2308       while (count > 1)
2309         {
2310           if (!forward_char (real))
2311             return FALSE;
2312           --count;
2313         }
2314
2315       return forward_char (real);
2316     }
2317   else
2318     {
2319       gint current_char_index;
2320       gint new_char_index;
2321
2322       check_invariants (iter);
2323
2324       current_char_index = gtk_text_iter_get_offset (iter);
2325
2326       if (current_char_index == _gtk_text_btree_char_count (real->tree))
2327         return FALSE; /* can't move forward */
2328
2329       new_char_index = current_char_index + count;
2330       gtk_text_iter_set_offset (iter, new_char_index);
2331
2332       check_invariants (iter);
2333
2334       /* Return FALSE if we're on the non-dereferenceable end
2335        * iterator.
2336        */
2337       if (gtk_text_iter_is_end (iter))
2338         return FALSE;
2339       else
2340         return TRUE;
2341     }
2342 }
2343
2344 /**
2345  * gtk_text_iter_backward_chars:
2346  * @iter: an iterator
2347  * @count: number of characters to move
2348  *
2349  * Moves @count characters backward, if possible (if @count would move
2350  * past the start or end of the buffer, moves to the start or end of
2351  * the buffer).  The return value indicates whether the iterator moved
2352  * onto a dereferenceable position; if the iterator didn't move, or
2353  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2354  * the function does nothing and returns %FALSE.
2355  *
2356  * Return value: whether @iter moved and is dereferenceable
2357  *
2358  **/
2359 gboolean
2360 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2361 {
2362   GtkTextRealIter *real;
2363
2364   g_return_val_if_fail (iter != NULL, FALSE);
2365
2366   FIX_OVERFLOWS (count);
2367   
2368   real = gtk_text_iter_make_real (iter);
2369
2370   if (real == NULL)
2371     return FALSE;
2372   else if (count == 0)
2373     return FALSE;
2374   else if (count < 0)
2375     return gtk_text_iter_forward_chars (iter, 0 - count);
2376
2377   ensure_char_offsets (real);
2378   check_invariants (iter);
2379
2380   /* <, not <=, because if count == segment_char_offset
2381    * we're going to the front of the segment and the any_segment
2382    * might change
2383    */
2384   if (count < real->segment_char_offset)
2385     {
2386       /* Optimize the within-segment case */
2387       g_assert (real->segment->char_count > 0);
2388       g_assert (real->segment->type == &gtk_text_char_type);
2389
2390       real->segment_char_offset -= count;
2391       g_assert (real->segment_char_offset >= 0);
2392
2393       if (real->line_byte_offset >= 0)
2394         {
2395           gint new_byte_offset;
2396           gint i;
2397
2398           new_byte_offset = 0;
2399           i = 0;
2400           while (i < real->segment_char_offset)
2401             {
2402               const char * start = real->segment->body.chars + new_byte_offset;
2403               new_byte_offset += g_utf8_next_char (start) - start;
2404
2405               ++i;
2406             }
2407
2408           real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2409           real->segment_byte_offset = new_byte_offset;
2410         }
2411
2412       real->line_char_offset -= count;
2413
2414       adjust_char_index (real, 0 - count);
2415
2416       check_invariants (iter);
2417
2418       return TRUE;
2419     }
2420   else
2421     {
2422       /* We need to go back into previous segments. For now,
2423        * just keep this really simple. FIXME
2424        * use backward_indexable_segment.
2425        */
2426       if (TRUE || count > MAX_LINEAR_SCAN)
2427         {
2428           gint current_char_index;
2429           gint new_char_index;
2430
2431           current_char_index = gtk_text_iter_get_offset (iter);
2432
2433           if (current_char_index == 0)
2434             return FALSE; /* can't move backward */
2435
2436           new_char_index = current_char_index - count;
2437           if (new_char_index < 0)
2438             new_char_index = 0;
2439
2440           gtk_text_iter_set_offset (iter, new_char_index);
2441
2442           check_invariants (iter);
2443
2444           return TRUE;
2445         }
2446       else
2447         {
2448           /* FIXME backward_indexable_segment here */
2449
2450           return FALSE;
2451         }
2452     }
2453 }
2454
2455 #if 0
2456
2457 /* These two can't be implemented efficiently (always have to use
2458  * a linear scan, since that's the only way to find all the non-text
2459  * segments)
2460  */
2461
2462 /**
2463  * gtk_text_iter_forward_text_chars:
2464  * @iter: a #GtkTextIter
2465  * @count: number of chars to move
2466  *
2467  * Moves forward by @count text characters (pixbufs, widgets,
2468  * etc. do not count as characters for this). Equivalent to moving
2469  * through the results of gtk_text_iter_get_text (), rather than
2470  * gtk_text_iter_get_slice ().
2471  *
2472  * Return value: whether @iter moved and is dereferenceable
2473  **/
2474 gboolean
2475 gtk_text_iter_forward_text_chars  (GtkTextIter *iter,
2476                                    gint         count)
2477 {
2478
2479
2480
2481 }
2482
2483 /**
2484  * gtk_text_iter_forward_text_chars:
2485  * @iter: a #GtkTextIter
2486  * @count: number of chars to move
2487  *
2488  * Moves backward by @count text characters (pixbufs, widgets,
2489  * etc. do not count as characters for this). Equivalent to moving
2490  * through the results of gtk_text_iter_get_text (), rather than
2491  * gtk_text_iter_get_slice ().
2492  *
2493  * Return value: whether @iter moved and is dereferenceable
2494  **/
2495 gboolean
2496 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2497                                    gint         count)
2498 {
2499
2500
2501 }
2502 #endif
2503
2504 /**
2505  * gtk_text_iter_forward_line:
2506  * @iter: an iterator
2507  *
2508  * Moves @iter to the start of the next line. Returns %TRUE if there
2509  * was a next line to move to, and %FALSE if @iter was simply moved to
2510  * the end of the buffer and is now not dereferenceable, or if @iter was
2511  * already at the end of the buffer.
2512  *
2513  * Return value: whether @iter can be dereferenced
2514  **/
2515 gboolean
2516 gtk_text_iter_forward_line (GtkTextIter *iter)
2517 {
2518   GtkTextRealIter *real;
2519
2520   g_return_val_if_fail (iter != NULL, FALSE);
2521   
2522   real = gtk_text_iter_make_real (iter);
2523
2524   if (real == NULL)
2525     return FALSE;
2526
2527   check_invariants (iter);
2528
2529   if (forward_line_leaving_caches_unmodified (real))
2530     {
2531       invalidate_char_index (real);
2532       adjust_line_number (real, 1);
2533
2534       check_invariants (iter);
2535
2536       if (gtk_text_iter_is_end (iter))
2537         return FALSE;
2538       else
2539         return TRUE;
2540     }
2541   else
2542     {
2543       /* On the last line, move to end of it */
2544       
2545       if (!gtk_text_iter_is_end (iter))
2546         gtk_text_iter_forward_to_end (iter);
2547       
2548       check_invariants (iter);
2549       return FALSE;
2550     }
2551 }
2552
2553 /**
2554  * gtk_text_iter_backward_line:
2555  * @iter: an iterator
2556  *
2557  * Moves @iter to the start of the previous line. Returns %TRUE if
2558  * @iter could be moved; i.e. if @iter was at character offset 0, this
2559  * function returns %FALSE. Therefore if @iter was already on line 0,
2560  * but not at the start of the line, @iter is snapped to the start of
2561  * the line and the function returns %TRUE. (Note that this implies that
2562  * in a loop calling this function, the line number may not change on
2563  * every iteration, if your first iteration is on line 0.)
2564  *
2565  * Return value: whether @iter moved
2566  **/
2567 gboolean
2568 gtk_text_iter_backward_line (GtkTextIter *iter)
2569 {
2570   GtkTextLine *new_line;
2571   GtkTextRealIter *real;
2572   gboolean offset_will_change;
2573   gint offset;
2574
2575   g_return_val_if_fail (iter != NULL, FALSE);
2576
2577   real = gtk_text_iter_make_real (iter);
2578
2579   if (real == NULL)
2580     return FALSE;
2581
2582   check_invariants (iter);
2583
2584   new_line = _gtk_text_line_previous (real->line);
2585
2586   offset_will_change = FALSE;
2587   if (real->line_char_offset > 0)
2588     offset_will_change = TRUE;
2589
2590   if (new_line != NULL)
2591     {
2592       real->line = new_line;
2593
2594       adjust_line_number (real, -1);
2595     }
2596   else
2597     {
2598       if (!offset_will_change)
2599         return FALSE;
2600     }
2601
2602   invalidate_char_index (real);
2603
2604   real->line_byte_offset = 0;
2605   real->line_char_offset = 0;
2606
2607   real->segment_byte_offset = 0;
2608   real->segment_char_offset = 0;
2609
2610   /* Find first segment in line */
2611   real->any_segment = real->line->segments;
2612   real->segment = _gtk_text_line_byte_to_segment (real->line,
2613                                                   0, &offset);
2614
2615   g_assert (offset == 0);
2616
2617   /* Note that if we are on the first line, we snap to the start of
2618    * the first line and return TRUE, so TRUE means the iterator
2619    * changed, not that the line changed; this is maybe a bit
2620    * weird. I'm not sure there's an obvious right thing to do though.
2621    */
2622
2623   check_invariants (iter);
2624
2625   return TRUE;
2626 }
2627
2628
2629 /**
2630  * gtk_text_iter_forward_lines:
2631  * @iter: a #GtkTextIter
2632  * @count: number of lines to move forward
2633  *
2634  * Moves @count lines forward, if possible (if @count would move
2635  * past the start or end of the buffer, moves to the start or end of
2636  * the buffer).  The return value indicates whether the iterator moved
2637  * onto a dereferenceable position; if the iterator didn't move, or
2638  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2639  * the function does nothing and returns %FALSE. If @count is negative,
2640  * moves backward by 0 - @count lines.
2641  *
2642  * Return value: whether @iter moved and is dereferenceable
2643  **/
2644 gboolean
2645 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2646 {
2647   FIX_OVERFLOWS (count);
2648   
2649   if (count < 0)
2650     return gtk_text_iter_backward_lines (iter, 0 - count);
2651   else if (count == 0)
2652     return FALSE;
2653   else if (count == 1)
2654     {
2655       check_invariants (iter);
2656       return gtk_text_iter_forward_line (iter);
2657     }
2658   else
2659     {
2660       gint old_line;
2661
2662       if (gtk_text_iter_is_end (iter))
2663         return FALSE;
2664       
2665       old_line = gtk_text_iter_get_line (iter);
2666
2667       gtk_text_iter_set_line (iter, old_line + count);
2668
2669       if ((gtk_text_iter_get_line (iter) - old_line) < count)
2670         {
2671           /* count went past the last line, so move to end of last line */
2672           if (!gtk_text_iter_is_end (iter))
2673             gtk_text_iter_forward_to_end (iter);
2674         }
2675       
2676       return !gtk_text_iter_is_end (iter);
2677     }
2678 }
2679
2680 /**
2681  * gtk_text_iter_backward_lines:
2682  * @iter: a #GtkTextIter
2683  * @count: number of lines to move backward
2684  *
2685  * Moves @count lines backward, if possible (if @count would move
2686  * past the start or end of the buffer, moves to the start or end of
2687  * the buffer).  The return value indicates whether the iterator moved
2688  * onto a dereferenceable position; if the iterator didn't move, or
2689  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2690  * the function does nothing and returns %FALSE. If @count is negative,
2691  * moves forward by 0 - @count lines.
2692  *
2693  * Return value: whether @iter moved and is dereferenceable
2694  **/
2695 gboolean
2696 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2697 {
2698   FIX_OVERFLOWS (count);
2699   
2700   if (count < 0)
2701     return gtk_text_iter_forward_lines (iter, 0 - count);
2702   else if (count == 0)
2703     return FALSE;
2704   else if (count == 1)
2705     {
2706       return gtk_text_iter_backward_line (iter);
2707     }
2708   else
2709     {
2710       gint old_line;
2711
2712       old_line = gtk_text_iter_get_line (iter);
2713
2714       gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2715
2716       return (gtk_text_iter_get_line (iter) != old_line);
2717     }
2718 }
2719
2720 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2721                                       gint                offset,
2722                                       gint                min_offset,
2723                                       gint                len,
2724                                       gint               *found_offset,
2725                                       gboolean            already_moved_initially);
2726
2727 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2728                                       gint                offset,
2729                                       gint                min_offset,
2730                                       gint                len);
2731
2732 /* Word funcs */
2733
2734 static gboolean
2735 find_word_end_func (const PangoLogAttr *attrs,
2736                     gint          offset,
2737                     gint          min_offset,
2738                     gint          len,
2739                     gint         *found_offset,
2740                     gboolean      already_moved_initially)
2741 {
2742   if (!already_moved_initially)
2743     ++offset;
2744
2745   /* Find end of next word */
2746   while (offset < min_offset + len &&
2747          !attrs[offset].is_word_end)
2748     ++offset;
2749
2750   *found_offset = offset;
2751
2752   return offset < min_offset + len;
2753 }
2754
2755 static gboolean
2756 is_word_end_func (const PangoLogAttr *attrs,
2757                   gint          offset,
2758                   gint          min_offset,
2759                   gint          len)
2760 {
2761   return attrs[offset].is_word_end;
2762 }
2763
2764 static gboolean
2765 find_word_start_func (const PangoLogAttr *attrs,
2766                       gint          offset,
2767                       gint          min_offset,
2768                       gint          len,
2769                       gint         *found_offset,
2770                       gboolean      already_moved_initially)
2771 {
2772   if (!already_moved_initially)
2773     --offset;
2774
2775   /* Find start of prev word */
2776   while (offset >= min_offset &&
2777          !attrs[offset].is_word_start)
2778     --offset;
2779
2780   *found_offset = offset;
2781
2782   return offset >= min_offset;
2783 }
2784
2785 static gboolean
2786 is_word_start_func (const PangoLogAttr *attrs,
2787                     gint          offset,
2788                     gint          min_offset,
2789                     gint          len)
2790 {
2791   return attrs[offset].is_word_start;
2792 }
2793
2794 static gboolean
2795 inside_word_func (const PangoLogAttr *attrs,
2796                   gint          offset,
2797                   gint          min_offset,
2798                   gint          len)
2799 {
2800   /* Find next word start or end */
2801   while (offset >= min_offset &&
2802          !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2803     --offset;
2804
2805   return attrs[offset].is_word_start;
2806 }
2807
2808 /* Sentence funcs */
2809
2810 static gboolean
2811 find_sentence_end_func (const PangoLogAttr *attrs,
2812                         gint          offset,
2813                         gint          min_offset,
2814                         gint          len,
2815                         gint         *found_offset,
2816                         gboolean      already_moved_initially)
2817 {
2818   if (!already_moved_initially)
2819     ++offset;
2820
2821   /* Find end of next sentence */
2822   while (offset < min_offset + len &&
2823          !attrs[offset].is_sentence_end)
2824     ++offset;
2825
2826   *found_offset = offset;
2827
2828   return offset < min_offset + len;
2829 }
2830
2831 static gboolean
2832 is_sentence_end_func (const PangoLogAttr *attrs,
2833                       gint          offset,
2834                       gint          min_offset,
2835                       gint          len)
2836 {
2837   return attrs[offset].is_sentence_end;
2838 }
2839
2840 static gboolean
2841 find_sentence_start_func (const PangoLogAttr *attrs,
2842                           gint          offset,
2843                           gint          min_offset,
2844                           gint          len,
2845                           gint         *found_offset,
2846                           gboolean      already_moved_initially)
2847 {
2848   if (!already_moved_initially)
2849     --offset;
2850
2851   /* Find start of prev sentence */
2852   while (offset >= min_offset &&
2853          !attrs[offset].is_sentence_start)
2854     --offset;
2855
2856   *found_offset = offset;
2857
2858   return offset >= min_offset;
2859 }
2860
2861 static gboolean
2862 is_sentence_start_func (const PangoLogAttr *attrs,
2863                         gint          offset,
2864                         gint          min_offset,
2865                         gint          len)
2866 {
2867   return attrs[offset].is_sentence_start;
2868 }
2869
2870 static gboolean
2871 inside_sentence_func (const PangoLogAttr *attrs,
2872                       gint          offset,
2873                       gint          min_offset,
2874                       gint          len)
2875 {
2876   /* Find next sentence start or end */
2877   while (offset >= min_offset &&
2878          !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2879     --offset;
2880
2881   return attrs[offset].is_sentence_start;
2882 }
2883
2884 static gboolean
2885 test_log_attrs (const GtkTextIter *iter,
2886                 TestLogAttrFunc    func)
2887 {
2888   gint char_len;
2889   const PangoLogAttr *attrs;
2890   int offset;
2891   gboolean result = FALSE;
2892
2893   g_return_val_if_fail (iter != NULL, FALSE);
2894
2895   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2896                                                iter, &char_len);
2897
2898   offset = gtk_text_iter_get_line_offset (iter);
2899
2900   /* char_len may be 0 and attrs will be NULL if so, if
2901    * iter is the end iter and the last line is empty.
2902    * 
2903    * offset may be equal to char_len, since attrs contains an entry
2904    * for one past the end
2905    */
2906   
2907   if (attrs && offset <= char_len)
2908     result = (* func) (attrs, offset, 0, char_len);
2909
2910   return result;
2911 }
2912
2913 static gboolean
2914 find_line_log_attrs (const GtkTextIter *iter,
2915                      FindLogAttrFunc    func,
2916                      gint              *found_offset,
2917                      gboolean           already_moved_initially)
2918 {
2919   gint char_len;
2920   const PangoLogAttr *attrs;
2921   int offset;
2922   gboolean result = FALSE;
2923
2924   g_return_val_if_fail (iter != NULL, FALSE);
2925   
2926   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2927                                                iter, &char_len);      
2928
2929   offset = gtk_text_iter_get_line_offset (iter);
2930   
2931   /* char_len may be 0 and attrs will be NULL if so, if
2932    * iter is the end iter and the last line is empty
2933    */
2934   
2935   if (attrs)
2936     result = (* func) (attrs, offset, 0, char_len, found_offset,
2937                        already_moved_initially);
2938
2939   return result;
2940 }
2941
2942 /* FIXME this function is very, very gratuitously slow */
2943 static gboolean
2944 find_by_log_attrs (GtkTextIter    *iter,
2945                    FindLogAttrFunc func,
2946                    gboolean        forward,
2947                    gboolean        already_moved_initially)
2948 {
2949   GtkTextIter orig;
2950   gint offset = 0;
2951   gboolean found = FALSE;
2952
2953   g_return_val_if_fail (iter != NULL, FALSE);
2954
2955   orig = *iter;
2956   
2957   found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2958   
2959   if (!found)
2960     {
2961       if (forward)
2962         {
2963           if (gtk_text_iter_forward_line (iter))
2964             return find_by_log_attrs (iter, func, forward,
2965                                       TRUE);
2966           else
2967             return FALSE;
2968         }
2969       else
2970         {                    
2971           /* go to end of previous line. need to check that
2972            * line is > 0 because backward_line snaps to start of
2973            * line 0 if it's on line 0
2974            */
2975           if (gtk_text_iter_get_line (iter) > 0 && 
2976               gtk_text_iter_backward_line (iter))
2977             {
2978               if (!gtk_text_iter_ends_line (iter))
2979                 gtk_text_iter_forward_to_line_end (iter);
2980               
2981               return find_by_log_attrs (iter, func, forward,
2982                                         TRUE);
2983             }
2984           else
2985             return FALSE;
2986         }
2987     }
2988   else
2989     {      
2990       gtk_text_iter_set_line_offset (iter, offset);
2991
2992       return
2993         (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2994         !gtk_text_iter_is_end (iter);
2995     }
2996 }
2997
2998 static gboolean 
2999 find_visible_by_log_attrs (GtkTextIter    *iter,
3000                            FindLogAttrFunc func,
3001                            gboolean        forward,
3002                            gboolean        already_moved_initially)
3003 {
3004   GtkTextIter pos;
3005
3006   g_return_val_if_fail (iter != NULL, FALSE);
3007   
3008   pos = *iter;
3009   
3010   while (find_by_log_attrs (&pos, func, forward, already_moved_initially)) 
3011     {
3012       if (!_gtk_text_btree_char_is_invisible (&pos)) 
3013         {
3014           *iter = pos;
3015           return TRUE;
3016         }
3017   }
3018
3019   return FALSE;
3020 }
3021
3022 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3023 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3024                                   
3025 static gboolean 
3026 move_multiple_steps (GtkTextIter *iter, 
3027                      gint count,
3028                      OneStepFunc step_forward,
3029                      MultipleStepFunc n_steps_backward)
3030 {
3031   g_return_val_if_fail (iter != NULL, FALSE);
3032
3033   FIX_OVERFLOWS (count);
3034   
3035   if (count == 0)
3036     return FALSE;
3037   
3038   if (count < 0)
3039     return n_steps_backward (iter, -count);
3040   
3041   if (!step_forward (iter))
3042     return FALSE;
3043   --count;
3044
3045   while (count > 0)
3046     {
3047       if (!step_forward (iter))
3048         break;
3049       --count;
3050     }
3051   
3052   return !gtk_text_iter_is_end (iter);  
3053 }
3054                
3055
3056 /**
3057  * gtk_text_iter_forward_word_end:
3058  * @iter: a #GtkTextIter
3059  * 
3060  * Moves forward to the next word end. (If @iter is currently on a
3061  * word end, moves forward to the next one after that.) Word breaks
3062  * are determined by Pango and should be correct for nearly any
3063  * language (if not, the correct fix would be to the Pango word break
3064  * algorithms).
3065  * 
3066  * Return value: %TRUE if @iter moved and is not the end iterator 
3067  **/
3068 gboolean
3069 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3070 {
3071   return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3072 }
3073
3074 /**
3075  * gtk_text_iter_backward_word_start:
3076  * @iter: a #GtkTextIter
3077  * 
3078  * Moves backward to the previous word start. (If @iter is currently on a
3079  * word start, moves backward to the next one after that.) Word breaks
3080  * are determined by Pango and should be correct for nearly any
3081  * language (if not, the correct fix would be to the Pango word break
3082  * algorithms).
3083  * 
3084  * Return value: %TRUE if @iter moved and is not the end iterator 
3085  **/
3086 gboolean
3087 gtk_text_iter_backward_word_start (GtkTextIter      *iter)
3088 {
3089   return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3090 }
3091
3092 /* FIXME a loop around a truly slow function means
3093  * a truly spectacularly slow function.
3094  */
3095
3096 /**
3097  * gtk_text_iter_forward_word_ends:
3098  * @iter: a #GtkTextIter
3099  * @count: number of times to move
3100  * 
3101  * Calls gtk_text_iter_forward_word_end() up to @count times.
3102  *
3103  * Return value: %TRUE if @iter moved and is not the end iterator 
3104  **/
3105 gboolean
3106 gtk_text_iter_forward_word_ends (GtkTextIter      *iter,
3107                                  gint              count)
3108 {
3109   return move_multiple_steps (iter, count, 
3110                               gtk_text_iter_forward_word_end,
3111                               gtk_text_iter_backward_word_starts);
3112 }
3113
3114 /**
3115  * gtk_text_iter_backward_word_starts
3116  * @iter: a #GtkTextIter
3117  * @count: number of times to move
3118  * 
3119  * Calls gtk_text_iter_backward_word_start() up to @count times.
3120  *
3121  * Return value: %TRUE if @iter moved and is not the end iterator 
3122  **/
3123 gboolean
3124 gtk_text_iter_backward_word_starts (GtkTextIter      *iter,
3125                                     gint               count)
3126 {
3127   return move_multiple_steps (iter, count, 
3128                               gtk_text_iter_backward_word_start,
3129                               gtk_text_iter_forward_word_ends);
3130 }
3131
3132 /**
3133  * gtk_text_iter_forward_visible_word_end:
3134  * @iter: a #GtkTextIter
3135  * 
3136  * Moves forward to the next visible word end. (If @iter is currently on a
3137  * word end, moves forward to the next one after that.) Word breaks
3138  * are determined by Pango and should be correct for nearly any
3139  * language (if not, the correct fix would be to the Pango word break
3140  * algorithms).
3141  * 
3142  * Return value: %TRUE if @iter moved and is not the end iterator 
3143  *
3144  * Since: 2.4
3145  **/
3146 gboolean
3147 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3148 {
3149   return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3150 }
3151
3152 /**
3153  * gtk_text_iter_backward_visible_word_start:
3154  * @iter: a #GtkTextIter
3155  * 
3156  * Moves backward to the previous visible word start. (If @iter is currently 
3157  * on a word start, moves backward to the next one after that.) Word breaks
3158  * are determined by Pango and should be correct for nearly any
3159  * language (if not, the correct fix would be to the Pango word break
3160  * algorithms).
3161  * 
3162  * Return value: %TRUE if @iter moved and is not the end iterator 
3163  * 
3164  * Since: 2.4
3165  **/
3166 gboolean
3167 gtk_text_iter_backward_visible_word_start (GtkTextIter      *iter)
3168 {
3169   return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3170 }
3171
3172 /**
3173  * gtk_text_iter_forward_visible_word_ends:
3174  * @iter: a #GtkTextIter
3175  * @count: number of times to move
3176  * 
3177  * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3178  *
3179  * Return value: %TRUE if @iter moved and is not the end iterator 
3180  *
3181  * Since: 2.4
3182  **/
3183 gboolean
3184 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3185                                          gint         count)
3186 {
3187   return move_multiple_steps (iter, count, 
3188                               gtk_text_iter_forward_visible_word_end,
3189                               gtk_text_iter_backward_visible_word_starts);
3190 }
3191
3192 /**
3193  * gtk_text_iter_backward_visible_word_starts
3194  * @iter: a #GtkTextIter
3195  * @count: number of times to move
3196  * 
3197  * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3198  *
3199  * Return value: %TRUE if @iter moved and is not the end iterator 
3200  * 
3201  * Since: 2.4
3202  **/
3203 gboolean
3204 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3205                                             gint         count)
3206 {
3207   return move_multiple_steps (iter, count, 
3208                               gtk_text_iter_backward_visible_word_start,
3209                               gtk_text_iter_forward_visible_word_ends);
3210 }
3211
3212 /**
3213  * gtk_text_iter_starts_word:
3214  * @iter: a #GtkTextIter
3215  * 
3216  * Determines whether @iter begins a natural-language word.  Word
3217  * breaks are determined by Pango and should be correct for nearly any
3218  * language (if not, the correct fix would be to the Pango word break
3219  * algorithms).
3220  *
3221  * Return value: %TRUE if @iter is at the start of a word
3222  **/
3223 gboolean
3224 gtk_text_iter_starts_word (const GtkTextIter *iter)
3225 {
3226   return test_log_attrs (iter, is_word_start_func);
3227 }
3228
3229 /**
3230  * gtk_text_iter_ends_word:
3231  * @iter: a #GtkTextIter
3232  * 
3233  * Determines whether @iter ends a natural-language word.  Word breaks
3234  * are determined by Pango and should be correct for nearly any
3235  * language (if not, the correct fix would be to the Pango word break
3236  * algorithms).
3237  *
3238  * Return value: %TRUE if @iter is at the end of a word
3239  **/
3240 gboolean
3241 gtk_text_iter_ends_word (const GtkTextIter *iter)
3242 {
3243   return test_log_attrs (iter, is_word_end_func);
3244 }
3245
3246 /**
3247  * gtk_text_iter_inside_word:
3248  * @iter: a #GtkTextIter
3249  * 
3250  * Determines whether @iter is inside a natural-language word (as
3251  * opposed to say inside some whitespace).  Word breaks are determined
3252  * by Pango and should be correct for nearly any language (if not, the
3253  * correct fix would be to the Pango word break algorithms).
3254  * 
3255  * Return value: %TRUE if @iter is inside a word
3256  **/
3257 gboolean
3258 gtk_text_iter_inside_word (const GtkTextIter *iter)
3259 {
3260   return test_log_attrs (iter, inside_word_func);
3261 }
3262
3263 /**
3264  * gtk_text_iter_starts_sentence:
3265  * @iter: a #GtkTextIter
3266  * 
3267  * Determines whether @iter begins a sentence.  Sentence boundaries are
3268  * determined by Pango and should be correct for nearly any language
3269  * (if not, the correct fix would be to the Pango text boundary
3270  * algorithms).
3271  * 
3272  * Return value: %TRUE if @iter is at the start of a sentence.
3273  **/
3274 gboolean
3275 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3276 {
3277   return test_log_attrs (iter, is_sentence_start_func);
3278 }
3279
3280 /**
3281  * gtk_text_iter_ends_sentence:
3282  * @iter: a #GtkTextIter
3283  * 
3284  * Determines whether @iter ends a sentence.  Sentence boundaries are
3285  * determined by Pango and should be correct for nearly any language
3286  * (if not, the correct fix would be to the Pango text boundary
3287  * algorithms).
3288  * 
3289  * Return value: %TRUE if @iter is at the end of a sentence.
3290  **/
3291 gboolean
3292 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3293 {
3294   return test_log_attrs (iter, is_sentence_end_func);
3295 }
3296
3297 /**
3298  * gtk_text_iter_inside_sentence:
3299  * @iter: a #GtkTextIter
3300  * 
3301  * Determines whether @iter is inside a sentence (as opposed to in
3302  * between two sentences, e.g. after a period and before the first
3303  * letter of the next sentence).  Sentence boundaries are determined
3304  * by Pango and should be correct for nearly any language (if not, the
3305  * correct fix would be to the Pango text boundary algorithms).
3306  * 
3307  * Return value: %TRUE if @iter is inside a sentence.
3308  **/
3309 gboolean
3310 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3311 {
3312   return test_log_attrs (iter, inside_sentence_func);
3313 }
3314
3315 /**
3316  * gtk_text_iter_forward_sentence_end:
3317  * @iter: a #GtkTextIter
3318  * 
3319  * Moves forward to the next sentence end. (If @iter is at the end of
3320  * a sentence, moves to the next end of sentence.)  Sentence
3321  * boundaries are determined by Pango and should be correct for nearly
3322  * any language (if not, the correct fix would be to the Pango text
3323  * boundary algorithms).
3324  * 
3325  * Return value: %TRUE if @iter moved and is not the end iterator
3326  **/
3327 gboolean
3328 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3329 {
3330   return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3331 }
3332
3333 /**
3334  * gtk_text_iter_backward_sentence_start:
3335  * @iter: a #GtkTextIter
3336  * 
3337  * Moves backward to the previous sentence start; if @iter is already at
3338  * the start of a sentence, moves backward to the next one.  Sentence
3339  * boundaries are determined by Pango and should be correct for nearly
3340  * any language (if not, the correct fix would be to the Pango text
3341  * boundary algorithms).
3342  * 
3343  * Return value: %TRUE if @iter moved and is not the end iterator
3344  **/
3345 gboolean
3346 gtk_text_iter_backward_sentence_start (GtkTextIter      *iter)
3347 {
3348   return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3349 }
3350
3351 /* FIXME a loop around a truly slow function means
3352  * a truly spectacularly slow function.
3353  */
3354 /**
3355  * gtk_text_iter_forward_sentence_ends:
3356  * @iter: a #GtkTextIter
3357  * @count: number of sentences to move
3358  * 
3359  * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3360  * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3361  * negative, moves backward instead of forward.
3362  * 
3363  * Return value: %TRUE if @iter moved and is not the end iterator
3364  **/
3365 gboolean
3366 gtk_text_iter_forward_sentence_ends (GtkTextIter      *iter,
3367                                      gint              count)
3368 {
3369   return move_multiple_steps (iter, count, 
3370                               gtk_text_iter_forward_sentence_end,
3371                               gtk_text_iter_backward_sentence_starts);
3372 }
3373
3374 /**
3375  * gtk_text_iter_backward_sentence_starts:
3376  * @iter: a #GtkTextIter
3377  * @count: number of sentences to move
3378  * 
3379  * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3380  * or until it returns %FALSE. If @count is negative, moves forward
3381  * instead of backward.
3382  * 
3383  * Return value: %TRUE if @iter moved and is not the end iterator
3384  **/
3385 gboolean
3386 gtk_text_iter_backward_sentence_starts (GtkTextIter      *iter,
3387                                         gint               count)
3388 {
3389   return move_multiple_steps (iter, count, 
3390                               gtk_text_iter_backward_sentence_start,
3391                               gtk_text_iter_forward_sentence_ends);
3392 }
3393
3394 static gboolean
3395 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3396                               gint          offset,
3397                               gint          min_offset,
3398                               gint          len,
3399                               gint         *found_offset,
3400                               gboolean      already_moved_initially)
3401 {
3402   if (!already_moved_initially)
3403     ++offset;
3404
3405   while (offset < (min_offset + len) &&
3406          !attrs[offset].is_cursor_position)
3407     ++offset;
3408
3409   *found_offset = offset;
3410
3411   return offset < (min_offset + len);
3412 }
3413
3414 static gboolean
3415 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3416                                gint          offset,
3417                                gint          min_offset,
3418                                gint          len,
3419                                gint         *found_offset,
3420                                gboolean      already_moved_initially)
3421 {  
3422   if (!already_moved_initially)
3423     --offset;
3424
3425   while (offset > min_offset &&
3426          !attrs[offset].is_cursor_position)
3427     --offset;
3428
3429   *found_offset = offset;
3430   
3431   return offset >= min_offset;
3432 }
3433
3434 static gboolean
3435 is_cursor_pos_func (const PangoLogAttr *attrs,
3436                     gint          offset,
3437                     gint          min_offset,
3438                     gint          len)
3439 {
3440   return attrs[offset].is_cursor_position;
3441 }
3442
3443 /**
3444  * gtk_text_iter_forward_cursor_position:
3445  * @iter: a #GtkTextIter
3446  * 
3447  * Moves @iter forward by a single cursor position. Cursor positions
3448  * are (unsurprisingly) positions where the cursor can appear. Perhaps
3449  * surprisingly, there may not be a cursor position between all
3450  * characters. The most common example for European languages would be
3451  * a carriage return/newline sequence. For some Unicode characters,
3452  * the equivalent of say the letter "a" with an accent mark will be
3453  * represented as two characters, first the letter then a "combining
3454  * mark" that causes the accent to be rendered; so the cursor can't go
3455  * between those two characters. See also the #PangoLogAttr structure and
3456  * pango_break() function.
3457  * 
3458  * Return value: %TRUE if we moved and the new position is dereferenceable
3459  **/
3460 gboolean
3461 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3462 {
3463   return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3464 }
3465
3466 /**
3467  * gtk_text_iter_backward_cursor_position:
3468  * @iter: a #GtkTextIter
3469  * 
3470  * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3471  * 
3472  * Return value: %TRUE if we moved
3473  **/
3474 gboolean
3475 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3476 {
3477   return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3478 }
3479
3480 /**
3481  * gtk_text_iter_forward_cursor_positions:
3482  * @iter: a #GtkTextIter
3483  * @count: number of positions to move
3484  * 
3485  * Moves up to @count cursor positions. See
3486  * gtk_text_iter_forward_cursor_position() for details.
3487  * 
3488  * Return value: %TRUE if we moved and the new position is dereferenceable
3489  **/
3490 gboolean
3491 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3492                                         gint         count)
3493 {
3494   return move_multiple_steps (iter, count, 
3495                               gtk_text_iter_forward_cursor_position,
3496                               gtk_text_iter_backward_cursor_positions);
3497 }
3498
3499 /**
3500  * gtk_text_iter_backward_cursor_positions:
3501  * @iter: a #GtkTextIter
3502  * @count: number of positions to move
3503  *
3504  * Moves up to @count cursor positions. See
3505  * gtk_text_iter_forward_cursor_position() for details.
3506  * 
3507  * Return value: %TRUE if we moved and the new position is dereferenceable
3508  **/
3509 gboolean
3510 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3511                                          gint         count)
3512 {
3513   return move_multiple_steps (iter, count, 
3514                               gtk_text_iter_backward_cursor_position,
3515                               gtk_text_iter_forward_cursor_positions);
3516 }
3517
3518 /**
3519  * gtk_text_iter_forward_visible_cursor_position:
3520  * @iter: a #GtkTextIter
3521  * 
3522  * Moves @iter forward to the next visible cursor position. See 
3523  * gtk_text_iter_forward_cursor_position() for details.
3524  * 
3525  * Return value: %TRUE if we moved and the new position is dereferenceable
3526  * 
3527  * Since: 2.4
3528  **/
3529 gboolean
3530 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3531 {
3532   return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3533 }
3534
3535 /**
3536  * gtk_text_iter_backward_visible_cursor_position:
3537  * @iter: a #GtkTextIter
3538  * 
3539  * Moves @iter forward to the previous visible cursor position. See 
3540  * gtk_text_iter_backward_cursor_position() for details.
3541  * 
3542  * Return value: %TRUE if we moved and the new position is dereferenceable
3543  * 
3544  * Since: 2.4
3545  **/
3546 gboolean
3547 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3548 {
3549   return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3550 }
3551
3552 /**
3553  * gtk_text_iter_forward_visible_cursor_positions:
3554  * @iter: a #GtkTextIter
3555  * @count: number of positions to move
3556  * 
3557  * Moves up to @count visible cursor positions. See
3558  * gtk_text_iter_forward_cursor_position() for details.
3559  * 
3560  * Return value: %TRUE if we moved and the new position is dereferenceable
3561  * 
3562  * Since: 2.4
3563  **/
3564 gboolean
3565 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3566                                                 gint         count)
3567 {
3568   return move_multiple_steps (iter, count, 
3569                               gtk_text_iter_forward_visible_cursor_position,
3570                               gtk_text_iter_backward_visible_cursor_positions);
3571 }
3572
3573 /**
3574  * gtk_text_iter_backward_visible_cursor_positions:
3575  * @iter: a #GtkTextIter
3576  * @count: number of positions to move
3577  *
3578  * Moves up to @count visible cursor positions. See
3579  * gtk_text_iter_forward_cursor_position() for details.
3580  * 
3581  * Return value: %TRUE if we moved and the new position is dereferenceable
3582  * 
3583  * Since: 2.4
3584  **/
3585 gboolean
3586 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3587                                                  gint         count)
3588 {
3589   return move_multiple_steps (iter, count, 
3590                               gtk_text_iter_backward_visible_cursor_position,
3591                               gtk_text_iter_forward_visible_cursor_positions);
3592 }
3593
3594 /**
3595  * gtk_text_iter_is_cursor_position:
3596  * @iter: a #GtkTextIter
3597  * 
3598  * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3599  * pango_break() for details on what a cursor position is.
3600  * 
3601  * Return value: %TRUE if the cursor can be placed at @iter
3602  **/
3603 gboolean
3604 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3605 {
3606   return test_log_attrs (iter, is_cursor_pos_func);
3607 }
3608
3609 /**
3610  * gtk_text_iter_set_line_offset:
3611  * @iter: a #GtkTextIter 
3612  * @char_on_line: a character offset relative to the start of @iter's current line
3613  * 
3614  * Moves @iter within a line, to a new <emphasis>character</emphasis>
3615  * (not byte) offset. The given character offset must be less than or
3616  * equal to the number of characters in the line; if equal, @iter
3617  * moves to the start of the next line. See
3618  * gtk_text_iter_set_line_index() if you have a byte index rather than
3619  * a character offset.
3620  *
3621  **/
3622 void
3623 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3624                                gint         char_on_line)
3625 {
3626   GtkTextRealIter *real;
3627   gint chars_in_line;
3628   
3629   g_return_if_fail (iter != NULL);
3630
3631   real = gtk_text_iter_make_surreal (iter);
3632
3633   if (real == NULL)
3634     return;
3635   
3636   check_invariants (iter);
3637
3638   chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3639
3640   g_return_if_fail (char_on_line <= chars_in_line);
3641
3642   if (char_on_line < chars_in_line)
3643     iter_set_from_char_offset (real, real->line, char_on_line);
3644   else
3645     gtk_text_iter_forward_line (iter); /* set to start of next line */
3646   
3647   check_invariants (iter);
3648 }
3649
3650 /**
3651  * gtk_text_iter_set_line_index:
3652  * @iter: a #GtkTextIter
3653  * @byte_on_line: a byte index relative to the start of @iter's current line
3654  *
3655  * Same as gtk_text_iter_set_line_offset(), but works with a
3656  * <emphasis>byte</emphasis> index. The given byte index must be at
3657  * the start of a character, it can't be in the middle of a UTF-8
3658  * encoded character.
3659  * 
3660  **/
3661 void
3662 gtk_text_iter_set_line_index (GtkTextIter *iter,
3663                               gint         byte_on_line)
3664 {
3665   GtkTextRealIter *real;
3666   gint bytes_in_line;
3667   
3668   g_return_if_fail (iter != NULL);
3669
3670   real = gtk_text_iter_make_surreal (iter);
3671
3672   if (real == NULL)
3673     return;
3674
3675   check_invariants (iter);
3676
3677   bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3678
3679   g_return_if_fail (byte_on_line <= bytes_in_line);
3680   
3681   if (byte_on_line < bytes_in_line)
3682     iter_set_from_byte_offset (real, real->line, byte_on_line);
3683   else
3684     gtk_text_iter_forward_line (iter);
3685
3686   if (real->segment->type == &gtk_text_char_type &&
3687       (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3688     g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3689                "character; this will crash the text buffer. "
3690                "Byte indexes must refer to the start of a character.",
3691                G_STRLOC, byte_on_line);
3692
3693   check_invariants (iter);
3694 }
3695
3696
3697 /**
3698  * gtk_text_iter_set_visible_line_offset:
3699  * @iter: a #GtkTextIter
3700  * @char_on_line: a character offset
3701  * 
3702  * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3703  * characters, i.e. text with a tag making it invisible is not
3704  * counted in the offset.
3705  **/
3706 void
3707 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3708                                        gint         char_on_line)
3709 {
3710   gint chars_seen = 0;
3711   GtkTextIter pos;
3712
3713   g_return_if_fail (iter != NULL);
3714   
3715   pos = *iter;
3716
3717   /* For now we use a ludicrously slow implementation */
3718   while (chars_seen < char_on_line)
3719     {
3720       if (!_gtk_text_btree_char_is_invisible (&pos))
3721         ++chars_seen;
3722
3723       if (!gtk_text_iter_forward_char (&pos))
3724         break;
3725
3726       if (chars_seen == char_on_line)
3727         break;
3728     }
3729   
3730   if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3731     *iter = pos;
3732   else
3733     gtk_text_iter_forward_line (iter);
3734 }
3735
3736 static gint
3737 bytes_in_char (GtkTextIter *iter)
3738 {
3739   return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3740 }
3741
3742 /**
3743  * gtk_text_iter_set_visible_line_index:
3744  * @iter: a #GtkTextIter
3745  * @byte_on_line: a byte index
3746  * 
3747  * Like gtk_text_iter_set_line_index(), but the index is in visible
3748  * bytes, i.e. text with a tag making it invisible is not counted
3749  * in the index.
3750  **/
3751 void
3752 gtk_text_iter_set_visible_line_index  (GtkTextIter *iter,
3753                                        gint         byte_on_line)
3754 {
3755   gint bytes_seen = 0;
3756   gint skipped = 0;
3757   GtkTextIter pos;
3758
3759   g_return_if_fail (iter != NULL);
3760   
3761   pos = *iter;
3762
3763   /* For now we use a ludicrously slow implementation */
3764   while (bytes_seen < byte_on_line)
3765     {
3766       if (!_gtk_text_btree_char_is_invisible (&pos))
3767         bytes_seen += bytes_in_char (&pos);
3768       else skipped++;
3769
3770       if (!gtk_text_iter_forward_char (&pos))
3771         break;
3772
3773       if (bytes_seen >= byte_on_line)
3774         break;
3775     }
3776
3777   if (bytes_seen > byte_on_line)
3778     g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3779                "character; this will crash the text buffer. "
3780                "Byte indexes must refer to the start of a character.",
3781                G_STRLOC, byte_on_line);
3782   
3783   if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3784     *iter = pos;
3785   else
3786     gtk_text_iter_forward_line (iter);
3787 }
3788
3789 /**
3790  * gtk_text_iter_set_line:
3791  * @iter: a #GtkTextIter
3792  * @line_number: line number (counted from 0)
3793  *
3794  * Moves iterator @iter to the start of the line @line_number.  If
3795  * @line_number is negative or larger than the number of lines in the
3796  * buffer, moves @iter to the start of the last line in the buffer.
3797  * 
3798  **/
3799 void
3800 gtk_text_iter_set_line (GtkTextIter *iter,
3801                         gint         line_number)
3802 {
3803   GtkTextLine *line;
3804   gint real_line;
3805   GtkTextRealIter *real;
3806
3807   g_return_if_fail (iter != NULL);
3808
3809   real = gtk_text_iter_make_surreal (iter);
3810
3811   if (real == NULL)
3812     return;
3813
3814   check_invariants (iter);
3815
3816   line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3817
3818   iter_set_from_char_offset (real, line, 0);
3819
3820   /* We might as well cache this, since we know it. */
3821   real->cached_line_number = real_line;
3822
3823   check_invariants (iter);
3824 }
3825
3826 /**
3827  * gtk_text_iter_set_offset:
3828  * @iter: a #GtkTextIter
3829  * @char_offset: a character number
3830  *
3831  * Sets @iter to point to @char_offset. @char_offset counts from the start
3832  * of the entire text buffer, starting with 0.
3833  **/
3834 void
3835 gtk_text_iter_set_offset (GtkTextIter *iter,
3836                           gint         char_offset)
3837 {
3838   GtkTextLine *line;
3839   GtkTextRealIter *real;
3840   gint line_start;
3841   gint real_char_index;
3842
3843   g_return_if_fail (iter != NULL);
3844
3845   real = gtk_text_iter_make_surreal (iter);
3846
3847   if (real == NULL)
3848     return;
3849
3850   check_invariants (iter);
3851
3852   if (real->cached_char_index >= 0 &&
3853       real->cached_char_index == char_offset)
3854     return;
3855
3856   line = _gtk_text_btree_get_line_at_char (real->tree,
3857                                            char_offset,
3858                                            &line_start,
3859                                            &real_char_index);
3860
3861   iter_set_from_char_offset (real, line, real_char_index - line_start);
3862
3863   /* Go ahead and cache this since we have it. */
3864   real->cached_char_index = real_char_index;
3865
3866   check_invariants (iter);
3867 }
3868
3869 /**
3870  * gtk_text_iter_forward_to_end:
3871  * @iter: a #GtkTextIter
3872  *
3873  * Moves @iter forward to the "end iterator," which points one past the last
3874  * valid character in the buffer. gtk_text_iter_get_char() called on the
3875  * end iterator returns 0, which is convenient for writing loops.
3876  **/
3877 void
3878 gtk_text_iter_forward_to_end  (GtkTextIter *iter)
3879 {
3880   GtkTextBuffer *buffer;
3881   GtkTextRealIter *real;
3882
3883   g_return_if_fail (iter != NULL);
3884
3885   real = gtk_text_iter_make_surreal (iter);
3886
3887   if (real == NULL)
3888     return;
3889
3890   buffer = _gtk_text_btree_get_buffer (real->tree);
3891
3892   gtk_text_buffer_get_end_iter (buffer, iter);
3893 }
3894
3895 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3896  * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3897  * If all else fails we could cache the para delimiter pos in the iter.
3898  * I think forward_to_line_end() actually gets called fairly often.
3899  */
3900 static int
3901 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3902 {
3903   GtkTextIter end;
3904   end = *iter;
3905
3906   if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3907                                         _gtk_text_iter_get_btree (&end)))
3908     {
3909       gtk_text_iter_forward_to_end (&end);
3910     }
3911   else
3912     {
3913       /* if we aren't on the last line, go forward to start of next line, then scan
3914        * back for the delimiters on the previous line
3915        */
3916       gtk_text_iter_forward_line (&end);
3917       gtk_text_iter_backward_char (&end);
3918       while (!gtk_text_iter_ends_line (&end))
3919         gtk_text_iter_backward_char (&end);
3920     }
3921
3922   return gtk_text_iter_get_line_offset (&end);
3923 }
3924
3925 /**
3926  * gtk_text_iter_forward_to_line_end:
3927  * @iter: a #GtkTextIter
3928  * 
3929  * Moves the iterator to point to the paragraph delimiter characters,
3930  * which will be either a newline, a carriage return, a carriage
3931  * return/newline in sequence, or the Unicode paragraph separator
3932  * character. If the iterator is already at the paragraph delimiter
3933  * characters, moves to the paragraph delimiter characters for the
3934  * next line. If @iter is on the last line in the buffer, which does
3935  * not end in paragraph delimiters, moves to the end iterator (end of
3936  * the last line), and returns %FALSE.
3937  * 
3938  * Return value: %TRUE if we moved and the new location is not the end iterator
3939  **/
3940 gboolean
3941 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3942 {
3943   gint current_offset;
3944   gint new_offset;
3945
3946   
3947   g_return_val_if_fail (iter != NULL, FALSE);
3948
3949   current_offset = gtk_text_iter_get_line_offset (iter);
3950   new_offset = find_paragraph_delimiter_for_line (iter);
3951   
3952   if (current_offset < new_offset)
3953     {
3954       /* Move to end of this line. */
3955       gtk_text_iter_set_line_offset (iter, new_offset);
3956       return !gtk_text_iter_is_end (iter);
3957     }
3958   else
3959     {
3960       /* Move to end of next line. */
3961       if (gtk_text_iter_forward_line (iter))
3962         {
3963           /* We don't want to move past all
3964            * empty lines.
3965            */
3966           if (!gtk_text_iter_ends_line (iter))
3967             gtk_text_iter_forward_to_line_end (iter);
3968           return !gtk_text_iter_is_end (iter);
3969         }
3970       else
3971         return FALSE;
3972     }
3973 }
3974
3975 /**
3976  * gtk_text_iter_forward_to_tag_toggle:
3977  * @iter: a #GtkTextIter
3978  * @tag: a #GtkTextTag, or %NULL
3979  *
3980  * Moves forward to the next toggle (on or off) of the
3981  * #GtkTextTag @tag, or to the next toggle of any tag if
3982  * @tag is %NULL. If no matching tag toggles are found,
3983  * returns %FALSE, otherwise %TRUE. Does not return toggles
3984  * located at @iter, only toggles after @iter. Sets @iter to
3985  * the location of the toggle, or to the end of the buffer
3986  * if no toggle is found.
3987  *
3988  * Return value: whether we found a tag toggle after @iter
3989  **/
3990 gboolean
3991 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3992                                      GtkTextTag  *tag)
3993 {
3994   GtkTextLine *next_line;
3995   GtkTextLine *current_line;
3996   GtkTextRealIter *real;
3997
3998   g_return_val_if_fail (iter != NULL, FALSE);
3999
4000   real = gtk_text_iter_make_real (iter);
4001
4002   if (real == NULL)
4003     return FALSE;
4004
4005   check_invariants (iter);
4006
4007   current_line = real->line;
4008   next_line = _gtk_text_line_next_could_contain_tag (current_line,
4009                                                      real->tree, tag);
4010
4011   while (_gtk_text_iter_forward_indexable_segment (iter))
4012     {
4013       /* If we went forward to a line that couldn't contain a toggle
4014          for the tag, then skip forward to a line that could contain
4015          it. This potentially skips huge hunks of the tree, so we
4016          aren't a purely linear search. */
4017       if (real->line != current_line)
4018         {
4019           if (next_line == NULL)
4020             {
4021               /* End of search. Set to end of buffer. */
4022               _gtk_text_btree_get_end_iter (real->tree, iter);
4023               return FALSE;
4024             }
4025
4026           if (real->line != next_line)
4027             iter_set_from_byte_offset (real, next_line, 0);
4028
4029           current_line = real->line;
4030           next_line = _gtk_text_line_next_could_contain_tag (current_line,
4031                                                              real->tree,
4032                                                              tag);
4033         }
4034
4035       if (gtk_text_iter_toggles_tag (iter, tag))
4036         {
4037           /* If there's a toggle here, it isn't indexable so
4038              any_segment can't be the indexable segment. */
4039           g_assert (real->any_segment != real->segment);
4040           return TRUE;
4041         }
4042     }
4043
4044   /* Check end iterator for tags */
4045   if (gtk_text_iter_toggles_tag (iter, tag))
4046     {
4047       /* If there's a toggle here, it isn't indexable so
4048          any_segment can't be the indexable segment. */
4049       g_assert (real->any_segment != real->segment);
4050       return TRUE;
4051     }
4052
4053   /* Reached end of buffer */
4054   return FALSE;
4055 }
4056
4057 /**
4058  * gtk_text_iter_backward_to_tag_toggle:
4059  * @iter: a #GtkTextIter
4060  * @tag: a #GtkTextTag, or %NULL
4061  *
4062  * Moves backward to the next toggle (on or off) of the
4063  * #GtkTextTag @tag, or to the next toggle of any tag if
4064  * @tag is %NULL. If no matching tag toggles are found,
4065  * returns %FALSE, otherwise %TRUE. Does not return toggles
4066  * located at @iter, only toggles before @iter. Sets @iter
4067  * to the location of the toggle, or the start of the buffer
4068  * if no toggle is found.
4069  *
4070  * Return value: whether we found a tag toggle before @iter
4071  **/
4072 gboolean
4073 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4074                                       GtkTextTag  *tag)
4075 {
4076   GtkTextLine *prev_line;
4077   GtkTextLine *current_line;
4078   GtkTextRealIter *real;
4079
4080   g_return_val_if_fail (iter != NULL, FALSE);
4081
4082   real = gtk_text_iter_make_real (iter);
4083
4084   if (real == NULL)
4085     return FALSE;
4086
4087   check_invariants (iter);
4088
4089   current_line = real->line;
4090   prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4091                                                         real->tree, tag);
4092
4093
4094   /* If we're at segment start, go to the previous segment;
4095    * if mid-segment, snap to start of current segment.
4096    */
4097   if (is_segment_start (real))
4098     {
4099       if (!_gtk_text_iter_backward_indexable_segment (iter))
4100         return FALSE;
4101     }
4102   else
4103     {
4104       ensure_char_offsets (real);
4105
4106       if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4107         return FALSE;
4108     }
4109
4110   do
4111     {
4112       /* If we went backward to a line that couldn't contain a toggle
4113        * for the tag, then skip backward further to a line that
4114        * could contain it. This potentially skips huge hunks of the
4115        * tree, so we aren't a purely linear search.
4116        */
4117       if (real->line != current_line)
4118         {
4119           if (prev_line == NULL)
4120             {
4121               /* End of search. Set to start of buffer. */
4122               _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4123               return FALSE;
4124             }
4125
4126           if (real->line != prev_line)
4127             {
4128               /* Set to last segment in prev_line (could do this
4129                * more quickly)
4130                */
4131               iter_set_from_byte_offset (real, prev_line, 0);
4132
4133               while (!at_last_indexable_segment (real))
4134                 _gtk_text_iter_forward_indexable_segment (iter);
4135             }
4136
4137           current_line = real->line;
4138           prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4139                                                                 real->tree,
4140                                                                 tag);
4141         }
4142
4143       if (gtk_text_iter_toggles_tag (iter, tag))
4144         {
4145           /* If there's a toggle here, it isn't indexable so
4146            * any_segment can't be the indexable segment.
4147            */
4148           g_assert (real->any_segment != real->segment);
4149           return TRUE;
4150         }
4151     }
4152   while (_gtk_text_iter_backward_indexable_segment (iter));
4153
4154   /* Reached front of buffer */
4155   return FALSE;
4156 }
4157
4158 static gboolean
4159 matches_pred (GtkTextIter *iter,
4160               GtkTextCharPredicate pred,
4161               gpointer user_data)
4162 {
4163   gint ch;
4164
4165   ch = gtk_text_iter_get_char (iter);
4166
4167   return (*pred) (ch, user_data);
4168 }
4169
4170 /**
4171  * gtk_text_iter_forward_find_char:
4172  * @iter: a #GtkTextIter
4173  * @pred: a function to be called on each character
4174  * @user_data: user data for @pred
4175  * @limit: search limit, or %NULL for none 
4176  * 
4177  * Advances @iter, calling @pred on each character. If
4178  * @pred returns %TRUE, returns %TRUE and stops scanning.
4179  * If @pred never returns %TRUE, @iter is set to @limit if
4180  * @limit is non-%NULL, otherwise to the end iterator.
4181  * 
4182  * Return value: whether a match was found
4183  **/
4184 gboolean
4185 gtk_text_iter_forward_find_char (GtkTextIter         *iter,
4186                                  GtkTextCharPredicate pred,
4187                                  gpointer             user_data,
4188                                  const GtkTextIter   *limit)
4189 {
4190   g_return_val_if_fail (iter != NULL, FALSE);
4191   g_return_val_if_fail (pred != NULL, FALSE);
4192
4193   if (limit &&
4194       gtk_text_iter_compare (iter, limit) >= 0)
4195     return FALSE;
4196   
4197   while ((limit == NULL ||
4198           !gtk_text_iter_equal (limit, iter)) &&
4199          gtk_text_iter_forward_char (iter))
4200     {      
4201       if (matches_pred (iter, pred, user_data))
4202         return TRUE;
4203     }
4204
4205   return FALSE;
4206 }
4207
4208 /**
4209  * gtk_text_iter_backward_find_char:
4210  * @iter: a #GtkTextIter
4211  * @pred: function to be called on each character
4212  * @user_data: user data for @pred
4213  * @limit: search limit, or %NULL for none
4214  * 
4215  * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4216  * 
4217  * Return value: whether a match was found
4218  **/
4219 gboolean
4220 gtk_text_iter_backward_find_char (GtkTextIter         *iter,
4221                                   GtkTextCharPredicate pred,
4222                                   gpointer             user_data,
4223                                   const GtkTextIter   *limit)
4224 {
4225   g_return_val_if_fail (iter != NULL, FALSE);
4226   g_return_val_if_fail (pred != NULL, FALSE);
4227
4228   if (limit &&
4229       gtk_text_iter_compare (iter, limit) <= 0)
4230     return FALSE;
4231   
4232   while ((limit == NULL ||
4233           !gtk_text_iter_equal (limit, iter)) &&
4234          gtk_text_iter_backward_char (iter))
4235     {
4236       if (matches_pred (iter, pred, user_data))
4237         return TRUE;
4238     }
4239
4240   return FALSE;
4241 }
4242
4243 static void
4244 forward_chars_with_skipping (GtkTextIter *iter,
4245                              gint         count,
4246                              gboolean     skip_invisible,
4247                              gboolean     skip_nontext)
4248 {
4249
4250   gint i;
4251
4252   g_return_if_fail (count >= 0);
4253
4254   i = count;
4255
4256   while (i > 0)
4257     {
4258       gboolean ignored = FALSE;
4259
4260       if (skip_nontext &&
4261           gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4262         ignored = TRUE;
4263
4264       if (!ignored &&
4265           skip_invisible &&
4266           _gtk_text_btree_char_is_invisible (iter))
4267         ignored = TRUE;
4268
4269       gtk_text_iter_forward_char (iter);
4270
4271       if (!ignored)
4272         --i;
4273     }
4274 }
4275
4276 static gboolean
4277 lines_match (const GtkTextIter *start,
4278              const gchar **lines,
4279              gboolean visible_only,
4280              gboolean slice,
4281              GtkTextIter *match_start,
4282              GtkTextIter *match_end)
4283 {
4284   GtkTextIter next;
4285   gchar *line_text;
4286   const gchar *found;
4287   gint offset;
4288
4289   if (*lines == NULL || **lines == '\0')
4290     {
4291       if (match_start)
4292         *match_start = *start;
4293
4294       if (match_end)
4295         *match_end = *start;
4296       return TRUE;
4297     }
4298
4299   next = *start;
4300   gtk_text_iter_forward_line (&next);
4301
4302   /* No more text in buffer, but *lines is nonempty */
4303   if (gtk_text_iter_equal (start, &next))
4304     {
4305       return FALSE;
4306     }
4307
4308   if (slice)
4309     {
4310       if (visible_only)
4311         line_text = gtk_text_iter_get_visible_slice (start, &next);
4312       else
4313         line_text = gtk_text_iter_get_slice (start, &next);
4314     }
4315   else
4316     {
4317       if (visible_only)
4318         line_text = gtk_text_iter_get_visible_text (start, &next);
4319       else
4320         line_text = gtk_text_iter_get_text (start, &next);
4321     }
4322
4323   if (match_start) /* if this is the first line we're matching */
4324     found = strstr (line_text, *lines);
4325   else
4326     {
4327       /* If it's not the first line, we have to match from the
4328        * start of the line.
4329        */
4330       if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4331         found = line_text;
4332       else
4333         found = NULL;
4334     }
4335
4336   if (found == NULL)
4337     {
4338       g_free (line_text);
4339       return FALSE;
4340     }
4341
4342   /* Get offset to start of search string */
4343   offset = g_utf8_strlen (line_text, found - line_text);
4344
4345   next = *start;
4346
4347   /* If match start needs to be returned, set it to the
4348    * start of the search string.
4349    */
4350   if (match_start)
4351     {
4352       *match_start = next;
4353
4354       forward_chars_with_skipping (match_start, offset,
4355                                    visible_only, !slice);
4356     }
4357
4358   /* Go to end of search string */
4359   offset += g_utf8_strlen (*lines, -1);
4360
4361   forward_chars_with_skipping (&next, offset,
4362                                visible_only, !slice);
4363
4364   g_free (line_text);
4365
4366   ++lines;
4367
4368   if (match_end)
4369     *match_end = next;
4370
4371   /* pass NULL for match_start, since we don't need to find the
4372    * start again.
4373    */
4374   return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4375 }
4376
4377 /* strsplit () that retains the delimiter as part of the string. */
4378 static gchar **
4379 strbreakup (const char *string,
4380             const char *delimiter,
4381             gint        max_tokens)
4382 {
4383   GSList *string_list = NULL, *slist;
4384   gchar **str_array, *s;
4385   guint i, n = 1;
4386
4387   g_return_val_if_fail (string != NULL, NULL);
4388   g_return_val_if_fail (delimiter != NULL, NULL);
4389
4390   if (max_tokens < 1)
4391     max_tokens = G_MAXINT;
4392
4393   s = strstr (string, delimiter);
4394   if (s)
4395     {
4396       guint delimiter_len = strlen (delimiter);
4397
4398       do
4399         {
4400           guint len;
4401           gchar *new_string;
4402
4403           len = s - string + delimiter_len;
4404           new_string = g_new (gchar, len + 1);
4405           strncpy (new_string, string, len);
4406           new_string[len] = 0;
4407           string_list = g_slist_prepend (string_list, new_string);
4408           n++;
4409           string = s + delimiter_len;
4410           s = strstr (string, delimiter);
4411         }
4412       while (--max_tokens && s);
4413     }
4414   if (*string)
4415     {
4416       n++;
4417       string_list = g_slist_prepend (string_list, g_strdup (string));
4418     }
4419
4420   str_array = g_new (gchar*, n);
4421
4422   i = n - 1;
4423
4424   str_array[i--] = NULL;
4425   for (slist = string_list; slist; slist = slist->next)
4426     str_array[i--] = slist->data;
4427
4428   g_slist_free (string_list);
4429
4430   return str_array;
4431 }
4432
4433 /**
4434  * gtk_text_iter_forward_search:
4435  * @iter: start of search
4436  * @str: a search string
4437  * @flags: flags affecting how the search is done
4438  * @match_start: return location for start of match, or %NULL
4439  * @match_end: return location for end of match, or %NULL
4440  * @limit: bound for the search, or %NULL for the end of the buffer
4441  * 
4442  * Searches forward for @str. Any match is returned by setting 
4443  * @match_start to the first character of the match and @match_end to the 
4444  * first character after the match. The search will not continue past
4445  * @limit. Note that a search is a linear or O(n) operation, so you
4446  * may wish to use @limit to avoid locking up your UI on large
4447  * buffers.
4448  * 
4449  * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4450  * have invisible text interspersed in @str. i.e. @str will be a
4451  * possibly-noncontiguous subsequence of the matched range. similarly,
4452  * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4453  * pixbufs or child widgets mixed inside the matched range. If these
4454  * flags are not given, the match must be exact; the special 0xFFFC
4455  * character in @str will match embedded pixbufs or child widgets.
4456  *
4457  * Return value: whether a match was found
4458  **/
4459 gboolean
4460 gtk_text_iter_forward_search (const GtkTextIter *iter,
4461                               const gchar       *str,
4462                               GtkTextSearchFlags flags,
4463                               GtkTextIter       *match_start,
4464                               GtkTextIter       *match_end,
4465                               const GtkTextIter *limit)
4466 {
4467   gchar **lines = NULL;
4468   GtkTextIter match;
4469   gboolean retval = FALSE;
4470   GtkTextIter search;
4471   gboolean visible_only;
4472   gboolean slice;
4473   
4474   g_return_val_if_fail (iter != NULL, FALSE);
4475   g_return_val_if_fail (str != NULL, FALSE);
4476
4477   if (limit &&
4478       gtk_text_iter_compare (iter, limit) >= 0)
4479     return FALSE;
4480   
4481   if (*str == '\0')
4482     {
4483       /* If we can move one char, return the empty string there */
4484       match = *iter;
4485       
4486       if (gtk_text_iter_forward_char (&match))
4487         {
4488           if (limit &&
4489               gtk_text_iter_equal (&match, limit))
4490             return FALSE;
4491           
4492           if (match_start)
4493             *match_start = match;
4494           if (match_end)
4495             *match_end = match;
4496           return TRUE;
4497         }
4498       else
4499         return FALSE;
4500     }
4501
4502   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4503   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4504   
4505   /* locate all lines */
4506
4507   lines = strbreakup (str, "\n", -1);
4508
4509   search = *iter;
4510
4511   do
4512     {
4513       /* This loop has an inefficient worst-case, where
4514        * gtk_text_iter_get_text () is called repeatedly on
4515        * a single line.
4516        */
4517       GtkTextIter end;
4518
4519       if (limit &&
4520           gtk_text_iter_compare (&search, limit) >= 0)
4521         break;
4522       
4523       if (lines_match (&search, (const gchar**)lines,
4524                        visible_only, slice, &match, &end))
4525         {
4526           if (limit == NULL ||
4527               (limit &&
4528                gtk_text_iter_compare (&end, limit) < 0))
4529             {
4530               retval = TRUE;
4531               
4532               if (match_start)
4533                 *match_start = match;
4534               
4535               if (match_end)
4536                 *match_end = end;
4537             }
4538           
4539           break;
4540         }
4541     }
4542   while (gtk_text_iter_forward_line (&search));
4543
4544   g_strfreev ((gchar**)lines);
4545
4546   return retval;
4547 }
4548
4549 static gboolean
4550 vectors_equal_ignoring_trailing (gchar **vec1,
4551                                  gchar **vec2)
4552 {
4553   /* Ignores trailing chars in vec2's last line */
4554
4555   gchar **i1, **i2;
4556
4557   i1 = vec1;
4558   i2 = vec2;
4559
4560   while (*i1 && *i2)
4561     {
4562       if (strcmp (*i1, *i2) != 0)
4563         {
4564           if (*(i2 + 1) == NULL) /* if this is the last line */
4565             {
4566               gint len1 = strlen (*i1);
4567               gint len2 = strlen (*i2);
4568
4569               if (len2 >= len1 &&
4570                   strncmp (*i1, *i2, len1) == 0)
4571                 {
4572                   /* We matched ignoring the trailing stuff in vec2 */
4573                   return TRUE;
4574                 }
4575               else
4576                 {
4577                   return FALSE;
4578                 }
4579             }
4580           else
4581             {
4582               return FALSE;
4583             }
4584         }
4585       ++i1;
4586       ++i2;
4587     }
4588
4589   if (*i1 || *i2)
4590     {
4591       return FALSE;
4592     }
4593   else
4594     return TRUE;
4595 }
4596
4597 typedef struct _LinesWindow LinesWindow;
4598
4599 struct _LinesWindow
4600 {
4601   gint n_lines;
4602   gchar **lines;
4603   GtkTextIter first_line_start;
4604   GtkTextIter first_line_end;
4605   gboolean slice;
4606   gboolean visible_only;
4607 };
4608
4609 static void
4610 lines_window_init (LinesWindow       *win,
4611                    const GtkTextIter *start)
4612 {
4613   gint i;
4614   GtkTextIter line_start;
4615   GtkTextIter line_end;
4616
4617   /* If we start on line 1, there are 2 lines to search (0 and 1), so
4618    * n_lines can be 2.
4619    */
4620   if (gtk_text_iter_is_start (start) ||
4621       gtk_text_iter_get_line (start) + 1 < win->n_lines)
4622     {
4623       /* Already at the end, or not enough lines to match */
4624       win->lines = g_new0 (gchar*, 1);
4625       *win->lines = NULL;
4626       return;
4627     }
4628
4629   line_start = *start;
4630   line_end = *start;
4631
4632   /* Move to start iter to start of line */
4633   gtk_text_iter_set_line_offset (&line_start, 0);
4634
4635   if (gtk_text_iter_equal (&line_start, &line_end))
4636     {
4637       /* we were already at the start; so go back one line */
4638       gtk_text_iter_backward_line (&line_start);
4639     }
4640
4641   win->first_line_start = line_start;
4642   win->first_line_end = line_end;
4643
4644   win->lines = g_new0 (gchar*, win->n_lines + 1);
4645
4646   i = win->n_lines - 1;
4647   while (i >= 0)
4648     {
4649       gchar *line_text;
4650
4651       if (win->slice)
4652         {
4653           if (win->visible_only)
4654             line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4655           else
4656             line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4657         }
4658       else
4659         {
4660           if (win->visible_only)
4661             line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4662           else
4663             line_text = gtk_text_iter_get_text (&line_start, &line_end);
4664         }
4665
4666       win->lines[i] = line_text;
4667
4668       line_end = line_start;
4669       gtk_text_iter_backward_line (&line_start);
4670
4671       --i;
4672     }
4673 }
4674
4675 static gboolean
4676 lines_window_back (LinesWindow *win)
4677 {
4678   GtkTextIter new_start;
4679   gchar *line_text;
4680
4681   new_start = win->first_line_start;
4682
4683   if (!gtk_text_iter_backward_line (&new_start))
4684     return FALSE;
4685   else
4686     {
4687       win->first_line_start = new_start;
4688       win->first_line_end = new_start;
4689
4690       gtk_text_iter_forward_line (&win->first_line_end);
4691     }
4692
4693   if (win->slice)
4694     {
4695       if (win->visible_only)
4696         line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4697                                                      &win->first_line_end);
4698       else
4699         line_text = gtk_text_iter_get_slice (&win->first_line_start,
4700                                              &win->first_line_end);
4701     }
4702   else
4703     {
4704       if (win->visible_only)
4705         line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4706                                                     &win->first_line_end);
4707       else
4708         line_text = gtk_text_iter_get_text (&win->first_line_start,
4709                                             &win->first_line_end);
4710     }
4711
4712   /* Move lines to make room for first line. */
4713   g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4714
4715   *win->lines = line_text;
4716
4717   /* Free old last line and NULL-terminate */
4718   g_free (win->lines[win->n_lines]);
4719   win->lines[win->n_lines] = NULL;
4720
4721   return TRUE;
4722 }
4723
4724 static void
4725 lines_window_free (LinesWindow *win)
4726 {
4727   g_strfreev (win->lines);
4728 }
4729
4730 /**
4731  * gtk_text_iter_backward_search:
4732  * @iter: a #GtkTextIter where the search begins
4733  * @str: search string
4734  * @flags: bitmask of flags affecting the search
4735  * @match_start: return location for start of match, or %NULL
4736  * @match_end: return location for end of match, or %NULL
4737  * @limit: location of last possible @match_start, or %NULL for start of buffer
4738  * 
4739  * Same as gtk_text_iter_forward_search(), but moves backward.
4740  * 
4741  * Return value: whether a match was found
4742  **/
4743 gboolean
4744 gtk_text_iter_backward_search (const GtkTextIter *iter,
4745                                const gchar       *str,
4746                                GtkTextSearchFlags flags,
4747                                GtkTextIter       *match_start,
4748                                GtkTextIter       *match_end,
4749                                const GtkTextIter *limit)
4750 {
4751   gchar **lines = NULL;
4752   gchar **l;
4753   gint n_lines;
4754   LinesWindow win;
4755   gboolean retval = FALSE;
4756   gboolean visible_only;
4757   gboolean slice;
4758   
4759   g_return_val_if_fail (iter != NULL, FALSE);
4760   g_return_val_if_fail (str != NULL, FALSE);
4761
4762   if (limit &&
4763       gtk_text_iter_compare (limit, iter) > 0)
4764     return FALSE;
4765   
4766   if (*str == '\0')
4767     {
4768       /* If we can move one char, return the empty string there */
4769       GtkTextIter match = *iter;
4770
4771       if (limit && gtk_text_iter_equal (limit, &match))
4772         return FALSE;
4773       
4774       if (gtk_text_iter_backward_char (&match))
4775         {
4776           if (match_start)
4777             *match_start = match;
4778           if (match_end)
4779             *match_end = match;
4780           return TRUE;
4781         }
4782       else
4783         return FALSE;
4784     }
4785
4786   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4787   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4788   
4789   /* locate all lines */
4790
4791   lines = strbreakup (str, "\n", -1);
4792
4793   l = lines;
4794   n_lines = 0;
4795   while (*l)
4796     {
4797       ++n_lines;
4798       ++l;
4799     }
4800
4801   win.n_lines = n_lines;
4802   win.slice = slice;
4803   win.visible_only = visible_only;
4804
4805   lines_window_init (&win, iter);
4806
4807   if (*win.lines == NULL)
4808     goto out;
4809
4810   do
4811     {
4812       gchar *first_line_match;
4813
4814       if (limit &&
4815           gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4816         {
4817           /* We're now before the search limit, abort. */
4818           goto out;
4819         }
4820       
4821       /* If there are multiple lines, the first line will
4822        * end in '\n', so this will only match at the
4823        * end of the first line, which is correct.
4824        */
4825       first_line_match = g_strrstr (*win.lines, *lines);
4826
4827       if (first_line_match &&
4828           vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4829         {
4830           /* Match! */
4831           gint offset;
4832           GtkTextIter next;
4833           GtkTextIter start_tmp;
4834           
4835           /* Offset to start of search string */
4836           offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4837
4838           next = win.first_line_start;
4839           start_tmp = next;
4840           forward_chars_with_skipping (&start_tmp, offset,
4841                                        visible_only, !slice);
4842
4843           if (limit &&
4844               gtk_text_iter_compare (limit, &start_tmp) > 0)
4845             goto out; /* match was bogus */
4846           
4847           if (match_start)
4848             *match_start = start_tmp;
4849
4850           /* Go to end of search string */
4851           l = lines;
4852           while (*l)
4853             {
4854               offset += g_utf8_strlen (*l, -1);
4855               ++l;
4856             }
4857
4858           forward_chars_with_skipping (&next, offset,
4859                                        visible_only, !slice);
4860
4861           if (match_end)
4862             *match_end = next;
4863
4864           retval = TRUE;
4865           goto out;
4866         }
4867     }
4868   while (lines_window_back (&win));
4869
4870  out:
4871   lines_window_free (&win);
4872   g_strfreev (lines);
4873   
4874   return retval;
4875 }
4876
4877 /*
4878  * Comparisons
4879  */
4880
4881 /**
4882  * gtk_text_iter_equal:
4883  * @lhs: a #GtkTextIter
4884  * @rhs: another #GtkTextIter
4885  * 
4886  * Tests whether two iterators are equal, using the fastest possible
4887  * mechanism. This function is very fast; you can expect it to perform
4888  * better than e.g. getting the character offset for each iterator and
4889  * comparing the offsets yourself. Also, it's a bit faster than
4890  * gtk_text_iter_compare().
4891  * 
4892  * Return value: %TRUE if the iterators point to the same place in the buffer
4893  **/
4894 gboolean
4895 gtk_text_iter_equal (const GtkTextIter *lhs,
4896                      const GtkTextIter *rhs)
4897 {
4898   GtkTextRealIter *real_lhs;
4899   GtkTextRealIter *real_rhs;
4900
4901   real_lhs = (GtkTextRealIter*)lhs;
4902   real_rhs = (GtkTextRealIter*)rhs;
4903
4904   check_invariants (lhs);
4905   check_invariants (rhs);
4906
4907   if (real_lhs->line != real_rhs->line)
4908     return FALSE;
4909   else if (real_lhs->line_byte_offset >= 0 &&
4910            real_rhs->line_byte_offset >= 0)
4911     return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4912   else
4913     {
4914       /* the ensure_char_offsets () calls do nothing if the char offsets
4915          are already up-to-date. */
4916       ensure_char_offsets (real_lhs);
4917       ensure_char_offsets (real_rhs);
4918       return real_lhs->line_char_offset == real_rhs->line_char_offset;
4919     }
4920 }
4921
4922 /**
4923  * gtk_text_iter_compare:
4924  * @lhs: a #GtkTextIter
4925  * @rhs: another #GtkTextIter
4926  * 
4927  * A qsort()-style function that returns negative if @lhs is less than
4928  * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4929  * Ordering is in character offset order, i.e. the first character in the buffer
4930  * is less than the second character in the buffer.
4931  * 
4932  * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4933  **/
4934 gint
4935 gtk_text_iter_compare (const GtkTextIter *lhs,
4936                        const GtkTextIter *rhs)
4937 {
4938   GtkTextRealIter *real_lhs;
4939   GtkTextRealIter *real_rhs;
4940
4941   real_lhs = gtk_text_iter_make_surreal (lhs);
4942   real_rhs = gtk_text_iter_make_surreal (rhs);
4943
4944   if (real_lhs == NULL ||
4945       real_rhs == NULL)
4946     return -1; /* why not */
4947
4948   check_invariants (lhs);
4949   check_invariants (rhs);
4950   
4951   if (real_lhs->line == real_rhs->line)
4952     {
4953       gint left_index, right_index;
4954
4955       if (real_lhs->line_byte_offset >= 0 &&
4956           real_rhs->line_byte_offset >= 0)
4957         {
4958           left_index = real_lhs->line_byte_offset;
4959           right_index = real_rhs->line_byte_offset;
4960         }
4961       else
4962         {
4963           /* the ensure_char_offsets () calls do nothing if
4964              the offsets are already up-to-date. */
4965           ensure_char_offsets (real_lhs);
4966           ensure_char_offsets (real_rhs);
4967           left_index = real_lhs->line_char_offset;
4968           right_index = real_rhs->line_char_offset;
4969         }
4970
4971       if (left_index < right_index)
4972         return -1;
4973       else if (left_index > right_index)
4974         return 1;
4975       else
4976         return 0;
4977     }
4978   else
4979     {
4980       gint line1, line2;
4981
4982       line1 = gtk_text_iter_get_line (lhs);
4983       line2 = gtk_text_iter_get_line (rhs);
4984       if (line1 < line2)
4985         return -1;
4986       else if (line1 > line2)
4987         return 1;
4988       else
4989         return 0;
4990     }
4991 }
4992
4993 /**
4994  * gtk_text_iter_in_range:
4995  * @iter: a #GtkTextIter
4996  * @start: start of range
4997  * @end: end of range
4998  * 
4999  * Checks whether @iter falls in the range [@start, @end).
5000  * @start and @end must be in ascending order.
5001  * 
5002  * Return value: %TRUE if @iter is in the range
5003  **/
5004 gboolean
5005 gtk_text_iter_in_range (const GtkTextIter *iter,
5006                         const GtkTextIter *start,
5007                         const GtkTextIter *end)
5008 {
5009   g_return_val_if_fail (iter != NULL, FALSE);
5010   g_return_val_if_fail (start != NULL, FALSE);
5011   g_return_val_if_fail (end != NULL, FALSE);
5012   g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5013   
5014   return gtk_text_iter_compare (iter, start) >= 0 &&
5015     gtk_text_iter_compare (iter, end) < 0;
5016 }
5017
5018 /**
5019  * gtk_text_iter_order:
5020  * @first: a #GtkTextIter
5021  * @second: another #GtkTextIter
5022  *
5023  * Swaps the value of @first and @second if @second comes before
5024  * @first in the buffer. That is, ensures that @first and @second are
5025  * in sequence. Most text buffer functions that take a range call this
5026  * automatically on your behalf, so there's no real reason to call it yourself
5027  * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5028  * that expect a pre-sorted range.
5029  * 
5030  **/
5031 void
5032 gtk_text_iter_order (GtkTextIter *first,
5033                      GtkTextIter *second)
5034 {
5035   g_return_if_fail (first != NULL);
5036   g_return_if_fail (second != NULL);
5037
5038   if (gtk_text_iter_compare (first, second) > 0)
5039     {
5040       GtkTextIter tmp;
5041
5042       tmp = *first;
5043       *first = *second;
5044       *second = tmp;
5045     }
5046 }
5047
5048 /*
5049  * Init iterators from the BTree
5050  */
5051
5052 void
5053 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5054                                   GtkTextIter *iter,
5055                                   gint char_index)
5056 {
5057   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5058   gint real_char_index;
5059   gint line_start;
5060   GtkTextLine *line;
5061
5062   g_return_if_fail (iter != NULL);
5063   g_return_if_fail (tree != NULL);
5064
5065   line = _gtk_text_btree_get_line_at_char (tree, char_index,
5066                                            &line_start, &real_char_index);
5067
5068   iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5069
5070   real->cached_char_index = real_char_index;
5071
5072   check_invariants (iter);
5073 }
5074
5075 void
5076 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5077                                        GtkTextIter  *iter,
5078                                        gint          line_number,
5079                                        gint          char_on_line)
5080 {
5081   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5082   GtkTextLine *line;
5083   gint real_line;
5084
5085   g_return_if_fail (iter != NULL);
5086   g_return_if_fail (tree != NULL);
5087
5088   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5089   
5090   iter_init_from_char_offset (iter, tree, line, char_on_line);
5091
5092   /* We might as well cache this, since we know it. */
5093   real->cached_line_number = real_line;
5094
5095   check_invariants (iter);
5096 }
5097
5098 void
5099 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree   *tree,
5100                                        GtkTextIter    *iter,
5101                                        gint            line_number,
5102                                        gint            byte_index)
5103 {
5104   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5105   GtkTextLine *line;
5106   gint real_line;
5107
5108   g_return_if_fail (iter != NULL);
5109   g_return_if_fail (tree != NULL);
5110
5111   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5112
5113   iter_init_from_byte_offset (iter, tree, line, byte_index);
5114
5115   /* We might as well cache this, since we know it. */
5116   real->cached_line_number = real_line;
5117
5118   check_invariants (iter);
5119 }
5120
5121 void
5122 _gtk_text_btree_get_iter_at_line      (GtkTextBTree   *tree,
5123                                        GtkTextIter    *iter,
5124                                        GtkTextLine    *line,
5125                                        gint            byte_offset)
5126 {
5127   g_return_if_fail (iter != NULL);
5128   g_return_if_fail (tree != NULL);
5129   g_return_if_fail (line != NULL);
5130
5131   iter_init_from_byte_offset (iter, tree, line, byte_offset);
5132
5133   check_invariants (iter);
5134 }
5135
5136 gboolean
5137 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree   *tree,
5138                                           GtkTextIter    *iter,
5139                                           GtkTextTag     *tag)
5140 {
5141   GtkTextLine *line;
5142
5143   g_return_val_if_fail (iter != NULL, FALSE);
5144   g_return_val_if_fail (tree != NULL, FALSE);
5145
5146   line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5147
5148   if (line == NULL)
5149     {
5150       /* Set iter to last in tree */
5151       _gtk_text_btree_get_end_iter (tree, iter);
5152       check_invariants (iter);
5153       return FALSE;
5154     }
5155   else
5156     {
5157       iter_init_from_byte_offset (iter, tree, line, 0);
5158
5159       if (!gtk_text_iter_toggles_tag (iter, tag))
5160         gtk_text_iter_forward_to_tag_toggle (iter, tag);
5161
5162       check_invariants (iter);
5163       return TRUE;
5164     }
5165 }
5166
5167 gboolean
5168 _gtk_text_btree_get_iter_at_last_toggle  (GtkTextBTree   *tree,
5169                                           GtkTextIter    *iter,
5170                                           GtkTextTag     *tag)
5171 {
5172   g_return_val_if_fail (iter != NULL, FALSE);
5173   g_return_val_if_fail (tree != NULL, FALSE);
5174
5175   _gtk_text_btree_get_end_iter (tree, iter);
5176   gtk_text_iter_backward_to_tag_toggle (iter, tag);
5177   check_invariants (iter);
5178   
5179   return TRUE;
5180 }
5181
5182 gboolean
5183 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5184                                        GtkTextIter *iter,
5185                                        const gchar *mark_name)
5186 {
5187   GtkTextMark *mark;
5188
5189   g_return_val_if_fail (iter != NULL, FALSE);
5190   g_return_val_if_fail (tree != NULL, FALSE);
5191
5192   mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5193
5194   if (mark == NULL)
5195     return FALSE;
5196   else
5197     {
5198       _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5199       check_invariants (iter);
5200       return TRUE;
5201     }
5202 }
5203
5204 void
5205 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5206                                   GtkTextIter *iter,
5207                                   GtkTextMark *mark)
5208 {
5209   GtkTextLineSegment *seg;
5210
5211   g_return_if_fail (iter != NULL);
5212   g_return_if_fail (tree != NULL);
5213   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5214
5215   seg = mark->segment;
5216
5217   iter_init_from_segment (iter, tree,
5218                           seg->body.mark.line, seg);
5219   g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5220   check_invariants (iter);
5221 }
5222
5223 void
5224 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree       *tree,
5225                                           GtkTextIter        *iter,
5226                                           GtkTextChildAnchor *anchor)
5227 {
5228   GtkTextLineSegment *seg;
5229
5230   g_return_if_fail (iter != NULL);
5231   g_return_if_fail (tree != NULL);
5232   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5233   
5234   seg = anchor->segment;  
5235
5236   g_assert (seg->body.child.line != NULL);
5237   
5238   iter_init_from_segment (iter, tree,
5239                           seg->body.child.line, seg);
5240   g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5241   check_invariants (iter);
5242 }
5243
5244 void
5245 _gtk_text_btree_get_end_iter         (GtkTextBTree   *tree,
5246                                       GtkTextIter    *iter)
5247 {
5248   g_return_if_fail (iter != NULL);
5249   g_return_if_fail (tree != NULL);
5250
5251   _gtk_text_btree_get_iter_at_char (tree,
5252                                    iter,
5253                                    _gtk_text_btree_char_count (tree));
5254   check_invariants (iter);
5255 }
5256
5257 void
5258 _gtk_text_iter_check (const GtkTextIter *iter)
5259 {
5260   const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5261   gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5262   GtkTextLineSegment *byte_segment = NULL;
5263   GtkTextLineSegment *byte_any_segment = NULL;
5264   GtkTextLineSegment *char_segment = NULL;
5265   GtkTextLineSegment *char_any_segment = NULL;
5266   gboolean segments_updated;
5267
5268   /* This function checks our class invariants for the Iter class. */
5269
5270   g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5271
5272   if (real->chars_changed_stamp !=
5273       _gtk_text_btree_get_chars_changed_stamp (real->tree))
5274     g_error ("iterator check failed: invalid iterator");
5275
5276   if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5277     g_error ("iterator check failed: both char and byte offsets are invalid");
5278
5279   segments_updated = (real->segments_changed_stamp ==
5280                       _gtk_text_btree_get_segments_changed_stamp (real->tree));
5281
5282 #if 0
5283   printf ("checking iter, segments %s updated, byte %d char %d\n",
5284           segments_updated ? "are" : "aren't",
5285           real->line_byte_offset,
5286           real->line_char_offset);
5287 #endif
5288
5289   if (segments_updated)
5290     {
5291       if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5292         g_error ("iterator check failed: both char and byte segment offsets are invalid");
5293
5294       if (real->segment->char_count == 0)
5295         g_error ("iterator check failed: segment is not indexable.");
5296
5297       if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5298         g_error ("segment char offset is not properly up-to-date");
5299
5300       if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5301         g_error ("segment byte offset is not properly up-to-date");
5302
5303       if (real->segment_byte_offset >= 0 &&
5304           real->segment_byte_offset >= real->segment->byte_count)
5305         g_error ("segment byte offset is too large.");
5306
5307       if (real->segment_char_offset >= 0 &&
5308           real->segment_char_offset >= real->segment->char_count)
5309         g_error ("segment char offset is too large.");
5310     }
5311
5312   if (real->line_byte_offset >= 0)
5313     {
5314       _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5315                                   &byte_segment, &byte_any_segment,
5316                                   &seg_byte_offset, &line_byte_offset);
5317
5318       if (line_byte_offset != real->line_byte_offset)
5319         g_error ("wrong byte offset was stored in iterator");
5320
5321       if (segments_updated)
5322         {
5323           if (real->segment != byte_segment)
5324             g_error ("wrong segment was stored in iterator");
5325
5326           if (real->any_segment != byte_any_segment)
5327             g_error ("wrong any_segment was stored in iterator");
5328
5329           if (seg_byte_offset != real->segment_byte_offset)
5330             g_error ("wrong segment byte offset was stored in iterator");
5331
5332           if (byte_segment->type == &gtk_text_char_type)
5333             {
5334               const gchar *p;
5335               p = byte_segment->body.chars + seg_byte_offset;
5336               
5337               if (!gtk_text_byte_begins_utf8_char (p))
5338                 g_error ("broken iterator byte index pointed into the middle of a character");
5339             }
5340         }
5341     }
5342
5343   if (real->line_char_offset >= 0)
5344     {
5345       _gtk_text_line_char_locate (real->line, real->line_char_offset,
5346                                   &char_segment, &char_any_segment,
5347                                   &seg_char_offset, &line_char_offset);
5348
5349       if (line_char_offset != real->line_char_offset)
5350         g_error ("wrong char offset was stored in iterator");
5351
5352       if (segments_updated)
5353         {          
5354           if (real->segment != char_segment)
5355             g_error ("wrong segment was stored in iterator");
5356
5357           if (real->any_segment != char_any_segment)
5358             g_error ("wrong any_segment was stored in iterator");
5359
5360           if (seg_char_offset != real->segment_char_offset)
5361             g_error ("wrong segment char offset was stored in iterator");
5362
5363           if (char_segment->type == &gtk_text_char_type)
5364             {
5365               const gchar *p;
5366               p = g_utf8_offset_to_pointer (char_segment->body.chars,
5367                                             seg_char_offset);
5368
5369               /* hmm, not likely to happen eh */
5370               if (!gtk_text_byte_begins_utf8_char (p))
5371                 g_error ("broken iterator char offset pointed into the middle of a character");
5372             }
5373         }
5374     }
5375
5376   if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5377     {
5378       if (byte_segment != char_segment)
5379         g_error ("char and byte offsets did not point to the same segment");
5380
5381       if (byte_any_segment != char_any_segment)
5382         g_error ("char and byte offsets did not point to the same any segment");
5383
5384       /* Make sure the segment offsets are equivalent, if it's a char
5385          segment. */
5386       if (char_segment->type == &gtk_text_char_type)
5387         {
5388           gint byte_offset = 0;
5389           gint char_offset = 0;
5390           while (char_offset < seg_char_offset)
5391             {
5392               const char * start = char_segment->body.chars + byte_offset;
5393               byte_offset += g_utf8_next_char (start) - start;
5394               char_offset += 1;
5395             }
5396
5397           if (byte_offset != seg_byte_offset)
5398             g_error ("byte offset did not correspond to char offset");
5399
5400           char_offset =
5401             g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5402
5403           if (char_offset != seg_char_offset)
5404             g_error ("char offset did not correspond to byte offset");
5405
5406           if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5407             g_error ("byte index for iterator does not index the start of a character");
5408         }
5409     }
5410
5411   if (real->cached_line_number >= 0)
5412     {
5413       gint should_be;
5414
5415       should_be = _gtk_text_line_get_number (real->line);
5416       if (real->cached_line_number != should_be)
5417         g_error ("wrong line number was cached");
5418     }
5419
5420   if (real->cached_char_index >= 0)
5421     {
5422       if (real->line_char_offset >= 0) /* only way we can check it
5423                                           efficiently, not a real
5424                                           invariant. */
5425         {
5426           gint char_index;
5427
5428           char_index = _gtk_text_line_char_index (real->line);
5429           char_index += real->line_char_offset;
5430
5431           if (real->cached_char_index != char_index)
5432             g_error ("wrong char index was cached");
5433         }
5434     }
5435
5436   if (_gtk_text_line_is_last (real->line, real->tree))
5437     g_error ("Iterator was on last line (past the end iterator)");
5438 }
5439