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