]> Pileus Git - ~andy/gtk/blob - gtk/gtktextiter.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~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: (out): 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                              gboolean     skip_decomp)
4388 {
4389
4390   gint i;
4391
4392   g_return_if_fail (count >= 0);
4393
4394   i = count;
4395
4396   while (i > 0)
4397     {
4398       gboolean ignored = FALSE;
4399
4400       /* minimal workaround to avoid the infinite loop of bug #168247. */
4401        if (gtk_text_iter_is_end (iter))
4402          return;
4403
4404       if (skip_nontext &&
4405           gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4406         ignored = TRUE;
4407
4408       if (!ignored &&
4409           skip_invisible &&
4410           _gtk_text_btree_char_is_invisible (iter))
4411         ignored = TRUE;
4412
4413       if (!ignored && skip_decomp)
4414         {
4415           /* being UTF8 correct sucks: this accounts for extra
4416              offsets coming from canonical decompositions of
4417              UTF8 characters (e.g. accented characters) which
4418              g_utf8_normalize() performs */
4419           gchar *normal;
4420           gchar *casefold;
4421           gchar buffer[6];
4422           gint buffer_len;
4423
4424           buffer_len = g_unichar_to_utf8 (gtk_text_iter_get_char (iter), buffer);
4425           casefold = g_utf8_casefold (buffer, buffer_len);
4426           normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4427           i -= (g_utf8_strlen (normal, -1) - 1);
4428           g_free (normal);
4429           g_free (casefold);
4430         }
4431
4432       gtk_text_iter_forward_char (iter);
4433
4434       if (!ignored)
4435         --i;
4436     }
4437 }
4438
4439 static const gchar *
4440 pointer_from_offset_skipping_decomp (const gchar *str,
4441                                      gint         offset)
4442 {
4443   gchar *casefold, *normal;
4444   const gchar *p, *q;
4445
4446   p = str;
4447
4448   while (offset > 0)
4449     {
4450       q = g_utf8_next_char (p);
4451       casefold = g_utf8_casefold (p, q - p);
4452       normal = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4453       offset -= g_utf8_strlen (normal, -1);
4454       g_free (casefold);
4455       g_free (normal);
4456       p = q;
4457     }
4458
4459   return p;
4460 }
4461
4462 static gboolean
4463 exact_prefix_cmp (const gchar *string,
4464                   const gchar *prefix,
4465                   guint        prefix_len)
4466 {
4467   GUnicodeType type;
4468
4469   if (strncmp (string, prefix, prefix_len) != 0)
4470     return FALSE;
4471   if (string[prefix_len] == '\0')
4472     return TRUE;
4473
4474   type = g_unichar_type (g_utf8_get_char (string + prefix_len));
4475
4476   /* If string contains prefix, check that prefix is not followed
4477    * by a unicode mark symbol, e.g. that trailing 'a' in prefix
4478    * is not part of two-char a-with-hat symbol in string. */
4479   return type != G_UNICODE_SPACING_MARK &&
4480          type != G_UNICODE_ENCLOSING_MARK &&
4481          type != G_UNICODE_NON_SPACING_MARK;
4482 }
4483
4484 static const gchar *
4485 utf8_strcasestr (const gchar *haystack,
4486                  const gchar *needle)
4487 {
4488   gsize needle_len;
4489   gsize haystack_len;
4490   const gchar *ret = NULL;
4491   gchar *p;
4492   gchar *casefold;
4493   gchar *caseless_haystack;
4494   gint i;
4495
4496   g_return_val_if_fail (haystack != NULL, NULL);
4497   g_return_val_if_fail (needle != NULL, NULL);
4498
4499   casefold = g_utf8_casefold (haystack, -1);
4500   caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4501   g_free (casefold);
4502
4503   needle_len = g_utf8_strlen (needle, -1);
4504   haystack_len = g_utf8_strlen (caseless_haystack, -1);
4505
4506   if (needle_len == 0)
4507     {
4508       ret = (gchar *)haystack;
4509       goto finally;
4510     }
4511
4512   if (haystack_len < needle_len)
4513     {
4514       ret = NULL;
4515       goto finally;
4516     }
4517
4518   p = (gchar *)caseless_haystack;
4519   needle_len = strlen (needle);
4520   i = 0;
4521
4522   while (*p)
4523     {
4524       if (exact_prefix_cmp (p, needle, needle_len))
4525         {
4526           ret = pointer_from_offset_skipping_decomp (haystack, i);
4527           goto finally;
4528         }
4529
4530       p = g_utf8_next_char (p);
4531       i++;
4532     }
4533
4534 finally:
4535   g_free (caseless_haystack);
4536
4537   return ret;
4538 }
4539
4540 static const gchar *
4541 utf8_strrcasestr (const gchar *haystack,
4542                   const gchar *needle)
4543 {
4544   gsize needle_len;
4545   gsize haystack_len;
4546   const gchar *ret = NULL;
4547   gchar *p;
4548   gchar *casefold;
4549   gchar *caseless_haystack;
4550   gint i;
4551
4552   g_return_val_if_fail (haystack != NULL, NULL);
4553   g_return_val_if_fail (needle != NULL, NULL);
4554
4555   casefold = g_utf8_casefold (haystack, -1);
4556   caseless_haystack = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4557   g_free (casefold);
4558
4559   needle_len = g_utf8_strlen (needle, -1);
4560   haystack_len = g_utf8_strlen (caseless_haystack, -1);
4561
4562   if (needle_len == 0)
4563     {
4564       ret = (gchar *)haystack;
4565       goto finally;
4566     }
4567
4568   if (haystack_len < needle_len)
4569     {
4570       ret = NULL;
4571       goto finally;
4572     }
4573
4574   i = haystack_len - needle_len;
4575   p = g_utf8_offset_to_pointer (caseless_haystack, i);
4576   needle_len = strlen (needle);
4577
4578   while (p >= caseless_haystack)
4579     {
4580       if (exact_prefix_cmp (p, needle, needle_len))
4581         {
4582           ret = pointer_from_offset_skipping_decomp (haystack, i);
4583           goto finally;
4584         }
4585
4586       p = g_utf8_prev_char (p);
4587       i--;
4588     }
4589
4590 finally:
4591   g_free (caseless_haystack);
4592
4593   return ret;
4594 }
4595
4596 /* normalizes caseless strings and returns true if @s2 matches
4597    the start of @s1 */
4598 static gboolean
4599 utf8_caselessnmatch (const gchar *s1,
4600                      const gchar *s2,
4601                      gssize       n1,
4602                      gssize       n2)
4603 {
4604   gchar *casefold;
4605   gchar *normalized_s1;
4606   gchar *normalized_s2;
4607   gint len_s1;
4608   gint len_s2;
4609   gboolean ret = FALSE;
4610
4611   g_return_val_if_fail (s1 != NULL, FALSE);
4612   g_return_val_if_fail (s2 != NULL, FALSE);
4613   g_return_val_if_fail (n1 > 0, FALSE);
4614   g_return_val_if_fail (n2 > 0, FALSE);
4615
4616   casefold = g_utf8_casefold (s1, n1);
4617   normalized_s1 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4618   g_free (casefold);
4619
4620   casefold = g_utf8_casefold (s2, n2);
4621   normalized_s2 = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4622   g_free (casefold);
4623
4624   len_s1 = strlen (normalized_s1);
4625   len_s2 = strlen (normalized_s2);
4626
4627   if (len_s1 >= len_s2)
4628     ret = (strncmp (normalized_s1, normalized_s2, len_s2) == 0);
4629
4630   g_free (normalized_s1);
4631   g_free (normalized_s2);
4632
4633   return ret;
4634 }
4635
4636 static gboolean
4637 lines_match (const GtkTextIter *start,
4638              const gchar **lines,
4639              gboolean visible_only,
4640              gboolean slice,
4641              gboolean case_insensitive,
4642              GtkTextIter *match_start,
4643              GtkTextIter *match_end)
4644 {
4645   GtkTextIter next;
4646   gchar *line_text;
4647   const gchar *found;
4648   gint offset;
4649
4650   if (*lines == NULL || **lines == '\0')
4651     {
4652       if (match_start)
4653         *match_start = *start;
4654
4655       if (match_end)
4656         *match_end = *start;
4657       return TRUE;
4658     }
4659
4660   next = *start;
4661   gtk_text_iter_forward_line (&next);
4662
4663   /* No more text in buffer, but *lines is nonempty */
4664   if (gtk_text_iter_equal (start, &next))
4665     {
4666       return FALSE;
4667     }
4668
4669   if (slice)
4670     {
4671       if (visible_only)
4672         line_text = gtk_text_iter_get_visible_slice (start, &next);
4673       else
4674         line_text = gtk_text_iter_get_slice (start, &next);
4675     }
4676   else
4677     {
4678       if (visible_only)
4679         line_text = gtk_text_iter_get_visible_text (start, &next);
4680       else
4681         line_text = gtk_text_iter_get_text (start, &next);
4682     }
4683
4684   if (match_start) /* if this is the first line we're matching */
4685     {
4686       if (!case_insensitive)
4687         found = strstr (line_text, *lines);
4688       else
4689         found = utf8_strcasestr (line_text, *lines);
4690     }
4691   else
4692     {
4693       /* If it's not the first line, we have to match from the
4694        * start of the line.
4695        */
4696       if ((!case_insensitive &&
4697            (strncmp (line_text, *lines, strlen (*lines)) == 0)) ||
4698           (case_insensitive &&
4699            utf8_caselessnmatch (line_text, *lines, strlen (line_text),
4700                                 strlen (*lines))))
4701         {
4702           found = line_text;
4703         }
4704       else
4705         found = NULL;
4706     }
4707
4708   if (found == NULL)
4709     {
4710       g_free (line_text);
4711       return FALSE;
4712     }
4713
4714   /* Get offset to start of search string */
4715   offset = g_utf8_strlen (line_text, found - line_text);
4716
4717   next = *start;
4718
4719   /* If match start needs to be returned, set it to the
4720    * start of the search string.
4721    */
4722   forward_chars_with_skipping (&next, offset,
4723                                visible_only, !slice, FALSE);
4724   if (match_start)
4725     *match_start = next;
4726
4727   /* Go to end of search string */
4728   forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1),
4729                                visible_only, !slice, TRUE);
4730
4731   g_free (line_text);
4732
4733   ++lines;
4734
4735   if (match_end)
4736     *match_end = next;
4737
4738   /* pass NULL for match_start, since we don't need to find the
4739    * start again.
4740    */
4741   return lines_match (&next, lines, visible_only, slice, case_insensitive, NULL, match_end);
4742 }
4743
4744 /* strsplit () that retains the delimiter as part of the string. */
4745 static gchar **
4746 strbreakup (const char *string,
4747             const char *delimiter,
4748             gint        max_tokens,
4749             gint       *num_strings,
4750             gboolean    case_insensitive)
4751 {
4752   GSList *string_list = NULL, *slist;
4753   gchar **str_array, *s;
4754   gchar *casefold, *new_string;
4755   guint i, n = 1;
4756
4757   g_return_val_if_fail (string != NULL, NULL);
4758   g_return_val_if_fail (delimiter != NULL, NULL);
4759
4760   if (max_tokens < 1)
4761     max_tokens = G_MAXINT;
4762
4763   s = strstr (string, delimiter);
4764   if (s)
4765     {
4766       guint delimiter_len = strlen (delimiter);
4767
4768       do
4769         {
4770           guint len;
4771
4772           len = s - string + delimiter_len;
4773           new_string = g_new (gchar, len + 1);
4774           strncpy (new_string, string, len);
4775           new_string[len] = 0;
4776
4777           if (case_insensitive)
4778             {
4779               casefold = g_utf8_casefold (new_string, -1);
4780               g_free (new_string);
4781               new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4782               g_free (casefold);
4783             }
4784
4785           string_list = g_slist_prepend (string_list, new_string);
4786           n++;
4787           string = s + delimiter_len;
4788           s = strstr (string, delimiter);
4789         }
4790       while (--max_tokens && s);
4791     }
4792   if (*string)
4793     {
4794       n++;
4795
4796       if (case_insensitive)
4797         {
4798           casefold = g_utf8_casefold (string, -1);
4799           new_string = g_utf8_normalize (casefold, -1, G_NORMALIZE_NFD);
4800           g_free (casefold);
4801         }
4802       else
4803         new_string = g_strdup (string);
4804
4805       string_list = g_slist_prepend (string_list, new_string);
4806     }
4807
4808   str_array = g_new (gchar*, n);
4809
4810   i = n - 1;
4811
4812   str_array[i--] = NULL;
4813   for (slist = string_list; slist; slist = slist->next)
4814     str_array[i--] = slist->data;
4815
4816   g_slist_free (string_list);
4817
4818   if (num_strings != NULL)
4819     *num_strings = n - 1;
4820
4821   return str_array;
4822 }
4823
4824 /**
4825  * gtk_text_iter_forward_search:
4826  * @iter: start of search
4827  * @str: a search string
4828  * @flags: flags affecting how the search is done
4829  * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
4830  * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
4831  * @limit: (allow-none): bound for the search, or %NULL for the end of the buffer
4832  *
4833  * Searches forward for @str. Any match is returned by setting
4834  * @match_start to the first character of the match and @match_end to the
4835  * first character after the match. The search will not continue past
4836  * @limit. Note that a search is a linear or O(n) operation, so you
4837  * may wish to use @limit to avoid locking up your UI on large
4838  * buffers.
4839  * 
4840  * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4841  * have invisible text interspersed in @str. i.e. @str will be a
4842  * possibly-noncontiguous subsequence of the matched range. similarly,
4843  * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4844  * pixbufs or child widgets mixed inside the matched range. If these
4845  * flags are not given, the match must be exact; the special 0xFFFC
4846  * character in @str will match embedded pixbufs or child widgets.
4847  * If you specify the #GTK_TEXT_SEARCH_CASE_INSENSITIVE flag, the text will
4848  * be matched regardless of what case it is in.
4849  *
4850  * Return value: whether a match was found
4851  **/
4852 gboolean
4853 gtk_text_iter_forward_search (const GtkTextIter *iter,
4854                               const gchar       *str,
4855                               GtkTextSearchFlags flags,
4856                               GtkTextIter       *match_start,
4857                               GtkTextIter       *match_end,
4858                               const GtkTextIter *limit)
4859 {
4860   gchar **lines = NULL;
4861   GtkTextIter match;
4862   gboolean retval = FALSE;
4863   GtkTextIter search;
4864   gboolean visible_only;
4865   gboolean slice;
4866   gboolean case_insensitive;
4867
4868   g_return_val_if_fail (iter != NULL, FALSE);
4869   g_return_val_if_fail (str != NULL, FALSE);
4870
4871   if (limit &&
4872       gtk_text_iter_compare (iter, limit) >= 0)
4873     return FALSE;
4874   
4875   if (*str == '\0')
4876     {
4877       /* If we can move one char, return the empty string there */
4878       match = *iter;
4879       
4880       if (gtk_text_iter_forward_char (&match))
4881         {
4882           if (limit &&
4883               gtk_text_iter_equal (&match, limit))
4884             return FALSE;
4885           
4886           if (match_start)
4887             *match_start = match;
4888           if (match_end)
4889             *match_end = match;
4890           return TRUE;
4891         }
4892       else
4893         return FALSE;
4894     }
4895
4896   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4897   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4898   case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
4899
4900   /* locate all lines */
4901
4902   lines = strbreakup (str, "\n", -1, NULL, case_insensitive);
4903
4904   search = *iter;
4905
4906   do
4907     {
4908       /* This loop has an inefficient worst-case, where
4909        * gtk_text_iter_get_text () is called repeatedly on
4910        * a single line.
4911        */
4912       GtkTextIter end;
4913
4914       if (limit &&
4915           gtk_text_iter_compare (&search, limit) >= 0)
4916         break;
4917       
4918       if (lines_match (&search, (const gchar**)lines,
4919                        visible_only, slice, case_insensitive, &match, &end))
4920         {
4921           if (limit == NULL ||
4922               (limit &&
4923                gtk_text_iter_compare (&end, limit) <= 0))
4924             {
4925               retval = TRUE;
4926               
4927               if (match_start)
4928                 *match_start = match;
4929               
4930               if (match_end)
4931                 *match_end = end;
4932             }
4933           
4934           break;
4935         }
4936     }
4937   while (gtk_text_iter_forward_line (&search));
4938
4939   g_strfreev ((gchar**)lines);
4940
4941   return retval;
4942 }
4943
4944 static gboolean
4945 vectors_equal_ignoring_trailing (gchar    **vec1,
4946                                  gchar    **vec2,
4947                                  gboolean   case_insensitive)
4948 {
4949   /* Ignores trailing chars in vec2's last line */
4950
4951   gchar **i1, **i2;
4952
4953   i1 = vec1;
4954   i2 = vec2;
4955
4956   while (*i1 && *i2)
4957     {
4958       gint len1;
4959       gint len2;
4960
4961       if (!case_insensitive)
4962         {
4963           if (strcmp (*i1, *i2) != 0)
4964             {
4965               if (*(i2 + 1) == NULL) /* if this is the last line */
4966                 {
4967                   len1 = strlen (*i1);
4968                   len2 = strlen (*i2);
4969
4970                   if (len2 >= len1 &&
4971                       strncmp (*i1, *i2, len1) == 0)
4972                     {
4973                       /* We matched ignoring the trailing stuff in vec2 */
4974                       return TRUE;
4975                     }
4976                   else
4977                     {
4978                       return FALSE;
4979                     }
4980                 }
4981               else
4982                 {
4983                   return FALSE;
4984                 }
4985             }
4986         }
4987       else
4988         {
4989           len1 = strlen (*i1);
4990           len2 = strlen (*i2);
4991
4992           if (!utf8_caselessnmatch (*i1, *i2, len1, len2))
4993             {
4994               if (*(i2 + 1) == NULL) /* if this is the last line */
4995                 {
4996                   if (utf8_caselessnmatch (*i2, *i1, len2, len1))
4997                     {
4998                       /* We matched ignoring the trailing stuff in vec2 */
4999                       return TRUE;
5000                     }
5001                   else
5002                     {
5003                       return FALSE;
5004                     }
5005                 }
5006               else
5007                 {
5008                   return FALSE;
5009                 }
5010             }
5011         }
5012
5013       ++i1;
5014       ++i2;
5015     }
5016
5017   if (*i1 || *i2)
5018     return FALSE;
5019   else
5020     return TRUE;
5021 }
5022
5023 typedef struct _LinesWindow LinesWindow;
5024
5025 struct _LinesWindow
5026 {
5027   gint n_lines;
5028   gchar **lines;
5029
5030   GtkTextIter first_line_start;
5031   GtkTextIter first_line_end;
5032
5033   guint slice : 1;
5034   guint visible_only : 1;
5035 };
5036
5037 static void
5038 lines_window_init (LinesWindow       *win,
5039                    const GtkTextIter *start)
5040 {
5041   gint i;
5042   GtkTextIter line_start;
5043   GtkTextIter line_end;
5044
5045   /* If we start on line 1, there are 2 lines to search (0 and 1), so
5046    * n_lines can be 2.
5047    */
5048   if (gtk_text_iter_is_start (start) ||
5049       gtk_text_iter_get_line (start) + 1 < win->n_lines)
5050     {
5051       /* Already at the end, or not enough lines to match */
5052       win->lines = g_new0 (gchar*, 1);
5053       *win->lines = NULL;
5054       return;
5055     }
5056
5057   line_start = *start;
5058   line_end = *start;
5059
5060   /* Move to start iter to start of line */
5061   gtk_text_iter_set_line_offset (&line_start, 0);
5062
5063   if (gtk_text_iter_equal (&line_start, &line_end))
5064     {
5065       /* we were already at the start; so go back one line */
5066       gtk_text_iter_backward_line (&line_start);
5067     }
5068
5069   win->first_line_start = line_start;
5070   win->first_line_end = line_end;
5071
5072   win->lines = g_new0 (gchar*, win->n_lines + 1);
5073
5074   i = win->n_lines - 1;
5075   while (i >= 0)
5076     {
5077       gchar *line_text;
5078
5079       if (win->slice)
5080         {
5081           if (win->visible_only)
5082             line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
5083           else
5084             line_text = gtk_text_iter_get_slice (&line_start, &line_end);
5085         }
5086       else
5087         {
5088           if (win->visible_only)
5089             line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
5090           else
5091             line_text = gtk_text_iter_get_text (&line_start, &line_end);
5092         }
5093
5094       win->lines[i] = line_text;
5095       win->first_line_start = line_start;
5096       win->first_line_end = line_end;
5097
5098       line_end = line_start;
5099       gtk_text_iter_backward_line (&line_start);
5100
5101       --i;
5102     }
5103 }
5104
5105 static gboolean
5106 lines_window_back (LinesWindow *win)
5107 {
5108   GtkTextIter new_start;
5109   gchar *line_text;
5110
5111   new_start = win->first_line_start;
5112
5113   if (!gtk_text_iter_backward_line (&new_start))
5114     return FALSE;
5115   else
5116     {
5117       win->first_line_start = new_start;
5118       win->first_line_end = new_start;
5119
5120       gtk_text_iter_forward_line (&win->first_line_end);
5121     }
5122
5123   if (win->slice)
5124     {
5125       if (win->visible_only)
5126         line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
5127                                                      &win->first_line_end);
5128       else
5129         line_text = gtk_text_iter_get_slice (&win->first_line_start,
5130                                              &win->first_line_end);
5131     }
5132   else
5133     {
5134       if (win->visible_only)
5135         line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
5136                                                     &win->first_line_end);
5137       else
5138         line_text = gtk_text_iter_get_text (&win->first_line_start,
5139                                             &win->first_line_end);
5140     }
5141
5142   /* Move lines to make room for first line. */
5143   g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
5144
5145   *win->lines = line_text;
5146
5147   /* Free old last line and NULL-terminate */
5148   g_free (win->lines[win->n_lines]);
5149   win->lines[win->n_lines] = NULL;
5150
5151   return TRUE;
5152 }
5153
5154 static void
5155 lines_window_free (LinesWindow *win)
5156 {
5157   g_strfreev (win->lines);
5158 }
5159
5160 /**
5161  * gtk_text_iter_backward_search:
5162  * @iter: a #GtkTextIter where the search begins
5163  * @str: search string
5164  * @flags: bitmask of flags affecting the search
5165  * @match_start: (out caller-allocates) (allow-none): return location for start of match, or %NULL
5166  * @match_end: (out caller-allocates) (allow-none): return location for end of match, or %NULL
5167  * @limit: (allow-none): location of last possible @match_start, or %NULL for start of buffer
5168  *
5169  * Same as gtk_text_iter_forward_search(), but moves backward.
5170  *
5171  * Return value: whether a match was found
5172  **/
5173 gboolean
5174 gtk_text_iter_backward_search (const GtkTextIter *iter,
5175                                const gchar       *str,
5176                                GtkTextSearchFlags flags,
5177                                GtkTextIter       *match_start,
5178                                GtkTextIter       *match_end,
5179                                const GtkTextIter *limit)
5180 {
5181   gchar **lines = NULL;
5182   gchar **l;
5183   gint n_lines;
5184   LinesWindow win;
5185   gboolean retval = FALSE;
5186   gboolean visible_only;
5187   gboolean slice;
5188   gboolean case_insensitive;
5189   
5190   g_return_val_if_fail (iter != NULL, FALSE);
5191   g_return_val_if_fail (str != NULL, FALSE);
5192
5193   if (limit &&
5194       gtk_text_iter_compare (limit, iter) > 0)
5195     return FALSE;
5196   
5197   if (*str == '\0')
5198     {
5199       /* If we can move one char, return the empty string there */
5200       GtkTextIter match = *iter;
5201
5202       if (limit && gtk_text_iter_equal (limit, &match))
5203         return FALSE;
5204       
5205       if (gtk_text_iter_backward_char (&match))
5206         {
5207           if (match_start)
5208             *match_start = match;
5209           if (match_end)
5210             *match_end = match;
5211           return TRUE;
5212         }
5213       else
5214         return FALSE;
5215     }
5216
5217   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
5218   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
5219   case_insensitive = (flags & GTK_TEXT_SEARCH_CASE_INSENSITIVE) != 0;
5220
5221   /* locate all lines */
5222
5223   lines = strbreakup (str, "\n", -1, &n_lines, case_insensitive);
5224
5225   win.n_lines = n_lines;
5226   win.slice = slice;
5227   win.visible_only = visible_only;
5228
5229   lines_window_init (&win, iter);
5230
5231   if (*win.lines == NULL)
5232     goto out;
5233
5234   do
5235     {
5236       const gchar *first_line_match;
5237
5238       if (limit &&
5239           gtk_text_iter_compare (limit, &win.first_line_end) > 0)
5240         {
5241           /* We're now before the search limit, abort. */
5242           goto out;
5243         }
5244       
5245       /* If there are multiple lines, the first line will
5246        * end in '\n', so this will only match at the
5247        * end of the first line, which is correct.
5248        */
5249       if (!case_insensitive)
5250         first_line_match = g_strrstr (*win.lines, *lines);
5251       else
5252         first_line_match = utf8_strrcasestr (*win.lines, *lines);
5253
5254       if (first_line_match &&
5255           vectors_equal_ignoring_trailing (lines + 1, win.lines + 1,
5256                                            case_insensitive))
5257         {
5258           /* Match! */
5259           gint offset;
5260           GtkTextIter next;
5261           GtkTextIter start_tmp;
5262           
5263           /* Offset to start of search string */
5264           offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5265
5266           next = win.first_line_start;
5267           start_tmp = next;
5268           forward_chars_with_skipping (&start_tmp, offset,
5269                                        visible_only, !slice, FALSE);
5270
5271           if (limit &&
5272               gtk_text_iter_compare (limit, &start_tmp) > 0)
5273             goto out; /* match was bogus */
5274           
5275           if (match_start)
5276             *match_start = start_tmp;
5277
5278           /* Go to end of search string */
5279           l = lines;
5280           while (*l)
5281             {
5282               offset += g_utf8_strlen (*l, -1);
5283               ++l;
5284             }
5285
5286           forward_chars_with_skipping (&next, offset,
5287                                        visible_only, !slice, TRUE);
5288
5289           if (match_end)
5290             *match_end = next;
5291
5292           retval = TRUE;
5293           goto out;
5294         }
5295     }
5296   while (lines_window_back (&win));
5297
5298  out:
5299   lines_window_free (&win);
5300   g_strfreev (lines);
5301   
5302   return retval;
5303 }
5304
5305 /*
5306  * Comparisons
5307  */
5308
5309 /**
5310  * gtk_text_iter_equal:
5311  * @lhs: a #GtkTextIter
5312  * @rhs: another #GtkTextIter
5313  * 
5314  * Tests whether two iterators are equal, using the fastest possible
5315  * mechanism. This function is very fast; you can expect it to perform
5316  * better than e.g. getting the character offset for each iterator and
5317  * comparing the offsets yourself. Also, it's a bit faster than
5318  * gtk_text_iter_compare().
5319  * 
5320  * Return value: %TRUE if the iterators point to the same place in the buffer
5321  **/
5322 gboolean
5323 gtk_text_iter_equal (const GtkTextIter *lhs,
5324                      const GtkTextIter *rhs)
5325 {
5326   GtkTextRealIter *real_lhs;
5327   GtkTextRealIter *real_rhs;
5328
5329   real_lhs = (GtkTextRealIter*)lhs;
5330   real_rhs = (GtkTextRealIter*)rhs;
5331
5332   check_invariants (lhs);
5333   check_invariants (rhs);
5334
5335   if (real_lhs->line != real_rhs->line)
5336     return FALSE;
5337   else if (real_lhs->line_byte_offset >= 0 &&
5338            real_rhs->line_byte_offset >= 0)
5339     return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5340   else
5341     {
5342       /* the ensure_char_offsets () calls do nothing if the char offsets
5343          are already up-to-date. */
5344       ensure_char_offsets (real_lhs);
5345       ensure_char_offsets (real_rhs);
5346       return real_lhs->line_char_offset == real_rhs->line_char_offset;
5347     }
5348 }
5349
5350 /**
5351  * gtk_text_iter_compare:
5352  * @lhs: a #GtkTextIter
5353  * @rhs: another #GtkTextIter
5354  * 
5355  * A qsort()-style function that returns negative if @lhs is less than
5356  * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5357  * Ordering is in character offset order, i.e. the first character in the buffer
5358  * is less than the second character in the buffer.
5359  * 
5360  * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5361  **/
5362 gint
5363 gtk_text_iter_compare (const GtkTextIter *lhs,
5364                        const GtkTextIter *rhs)
5365 {
5366   GtkTextRealIter *real_lhs;
5367   GtkTextRealIter *real_rhs;
5368
5369   real_lhs = gtk_text_iter_make_surreal (lhs);
5370   real_rhs = gtk_text_iter_make_surreal (rhs);
5371
5372   if (real_lhs == NULL ||
5373       real_rhs == NULL)
5374     return -1; /* why not */
5375
5376   check_invariants (lhs);
5377   check_invariants (rhs);
5378   
5379   if (real_lhs->line == real_rhs->line)
5380     {
5381       gint left_index, right_index;
5382
5383       if (real_lhs->line_byte_offset >= 0 &&
5384           real_rhs->line_byte_offset >= 0)
5385         {
5386           left_index = real_lhs->line_byte_offset;
5387           right_index = real_rhs->line_byte_offset;
5388         }
5389       else
5390         {
5391           /* the ensure_char_offsets () calls do nothing if
5392              the offsets are already up-to-date. */
5393           ensure_char_offsets (real_lhs);
5394           ensure_char_offsets (real_rhs);
5395           left_index = real_lhs->line_char_offset;
5396           right_index = real_rhs->line_char_offset;
5397         }
5398
5399       if (left_index < right_index)
5400         return -1;
5401       else if (left_index > right_index)
5402         return 1;
5403       else
5404         return 0;
5405     }
5406   else
5407     {
5408       gint line1, line2;
5409
5410       line1 = gtk_text_iter_get_line (lhs);
5411       line2 = gtk_text_iter_get_line (rhs);
5412       if (line1 < line2)
5413         return -1;
5414       else if (line1 > line2)
5415         return 1;
5416       else
5417         return 0;
5418     }
5419 }
5420
5421 /**
5422  * gtk_text_iter_in_range:
5423  * @iter: a #GtkTextIter
5424  * @start: start of range
5425  * @end: end of range
5426  * 
5427  * Checks whether @iter falls in the range [@start, @end).
5428  * @start and @end must be in ascending order.
5429  * 
5430  * Return value: %TRUE if @iter is in the range
5431  **/
5432 gboolean
5433 gtk_text_iter_in_range (const GtkTextIter *iter,
5434                         const GtkTextIter *start,
5435                         const GtkTextIter *end)
5436 {
5437   g_return_val_if_fail (iter != NULL, FALSE);
5438   g_return_val_if_fail (start != NULL, FALSE);
5439   g_return_val_if_fail (end != NULL, FALSE);
5440   g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5441   
5442   return gtk_text_iter_compare (iter, start) >= 0 &&
5443     gtk_text_iter_compare (iter, end) < 0;
5444 }
5445
5446 /**
5447  * gtk_text_iter_order:
5448  * @first: a #GtkTextIter
5449  * @second: another #GtkTextIter
5450  *
5451  * Swaps the value of @first and @second if @second comes before
5452  * @first in the buffer. That is, ensures that @first and @second are
5453  * in sequence. Most text buffer functions that take a range call this
5454  * automatically on your behalf, so there's no real reason to call it yourself
5455  * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5456  * that expect a pre-sorted range.
5457  * 
5458  **/
5459 void
5460 gtk_text_iter_order (GtkTextIter *first,
5461                      GtkTextIter *second)
5462 {
5463   g_return_if_fail (first != NULL);
5464   g_return_if_fail (second != NULL);
5465
5466   if (gtk_text_iter_compare (first, second) > 0)
5467     {
5468       GtkTextIter tmp;
5469
5470       tmp = *first;
5471       *first = *second;
5472       *second = tmp;
5473     }
5474 }
5475
5476 /*
5477  * Init iterators from the BTree
5478  */
5479
5480 void
5481 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5482                                   GtkTextIter *iter,
5483                                   gint char_index)
5484 {
5485   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5486   gint real_char_index;
5487   gint line_start;
5488   GtkTextLine *line;
5489
5490   g_return_if_fail (iter != NULL);
5491   g_return_if_fail (tree != NULL);
5492
5493   line = _gtk_text_btree_get_line_at_char (tree, char_index,
5494                                            &line_start, &real_char_index);
5495
5496   iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5497
5498   real->cached_char_index = real_char_index;
5499
5500   check_invariants (iter);
5501 }
5502
5503 void
5504 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5505                                        GtkTextIter  *iter,
5506                                        gint          line_number,
5507                                        gint          char_on_line)
5508 {
5509   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5510   GtkTextLine *line;
5511   gint real_line;
5512
5513   g_return_if_fail (iter != NULL);
5514   g_return_if_fail (tree != NULL);
5515
5516   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5517   
5518   iter_init_from_char_offset (iter, tree, line, char_on_line);
5519
5520   /* We might as well cache this, since we know it. */
5521   real->cached_line_number = real_line;
5522
5523   check_invariants (iter);
5524 }
5525
5526 void
5527 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree   *tree,
5528                                        GtkTextIter    *iter,
5529                                        gint            line_number,
5530                                        gint            byte_index)
5531 {
5532   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5533   GtkTextLine *line;
5534   gint real_line;
5535
5536   g_return_if_fail (iter != NULL);
5537   g_return_if_fail (tree != NULL);
5538
5539   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5540
5541   iter_init_from_byte_offset (iter, tree, line, byte_index);
5542
5543   /* We might as well cache this, since we know it. */
5544   real->cached_line_number = real_line;
5545
5546   check_invariants (iter);
5547 }
5548
5549 void
5550 _gtk_text_btree_get_iter_at_line      (GtkTextBTree   *tree,
5551                                        GtkTextIter    *iter,
5552                                        GtkTextLine    *line,
5553                                        gint            byte_offset)
5554 {
5555   g_return_if_fail (iter != NULL);
5556   g_return_if_fail (tree != NULL);
5557   g_return_if_fail (line != NULL);
5558
5559   iter_init_from_byte_offset (iter, tree, line, byte_offset);
5560
5561   check_invariants (iter);
5562 }
5563
5564 gboolean
5565 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree   *tree,
5566                                           GtkTextIter    *iter,
5567                                           GtkTextTag     *tag)
5568 {
5569   GtkTextLine *line;
5570
5571   g_return_val_if_fail (iter != NULL, FALSE);
5572   g_return_val_if_fail (tree != NULL, FALSE);
5573
5574   line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5575
5576   if (line == NULL)
5577     {
5578       /* Set iter to last in tree */
5579       _gtk_text_btree_get_end_iter (tree, iter);
5580       check_invariants (iter);
5581       return FALSE;
5582     }
5583   else
5584     {
5585       iter_init_from_byte_offset (iter, tree, line, 0);
5586
5587       if (!gtk_text_iter_toggles_tag (iter, tag))
5588         gtk_text_iter_forward_to_tag_toggle (iter, tag);
5589
5590       check_invariants (iter);
5591       return TRUE;
5592     }
5593 }
5594
5595 gboolean
5596 _gtk_text_btree_get_iter_at_last_toggle  (GtkTextBTree   *tree,
5597                                           GtkTextIter    *iter,
5598                                           GtkTextTag     *tag)
5599 {
5600   g_return_val_if_fail (iter != NULL, FALSE);
5601   g_return_val_if_fail (tree != NULL, FALSE);
5602
5603   _gtk_text_btree_get_end_iter (tree, iter);
5604   gtk_text_iter_backward_to_tag_toggle (iter, tag);
5605   check_invariants (iter);
5606   
5607   return TRUE;
5608 }
5609
5610 gboolean
5611 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5612                                        GtkTextIter *iter,
5613                                        const gchar *mark_name)
5614 {
5615   GtkTextMark *mark;
5616
5617   g_return_val_if_fail (iter != NULL, FALSE);
5618   g_return_val_if_fail (tree != NULL, FALSE);
5619
5620   mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5621
5622   if (mark == NULL)
5623     return FALSE;
5624   else
5625     {
5626       _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5627       check_invariants (iter);
5628       return TRUE;
5629     }
5630 }
5631
5632 void
5633 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5634                                   GtkTextIter *iter,
5635                                   GtkTextMark *mark)
5636 {
5637   GtkTextLineSegment *seg;
5638
5639   g_return_if_fail (iter != NULL);
5640   g_return_if_fail (tree != NULL);
5641   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5642
5643   seg = mark->segment;
5644
5645   iter_init_from_segment (iter, tree,
5646                           seg->body.mark.line, seg);
5647   g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5648   check_invariants (iter);
5649 }
5650
5651 void
5652 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree       *tree,
5653                                           GtkTextIter        *iter,
5654                                           GtkTextChildAnchor *anchor)
5655 {
5656   GtkTextLineSegment *seg;
5657
5658   g_return_if_fail (iter != NULL);
5659   g_return_if_fail (tree != NULL);
5660   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5661   
5662   seg = anchor->segment;  
5663
5664   g_assert (seg->body.child.line != NULL);
5665   
5666   iter_init_from_segment (iter, tree,
5667                           seg->body.child.line, seg);
5668   g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5669   check_invariants (iter);
5670 }
5671
5672 void
5673 _gtk_text_btree_get_end_iter         (GtkTextBTree   *tree,
5674                                       GtkTextIter    *iter)
5675 {
5676   g_return_if_fail (iter != NULL);
5677   g_return_if_fail (tree != NULL);
5678
5679   _gtk_text_btree_get_iter_at_char (tree,
5680                                    iter,
5681                                    _gtk_text_btree_char_count (tree));
5682   check_invariants (iter);
5683 }
5684
5685 void
5686 _gtk_text_iter_check (const GtkTextIter *iter)
5687 {
5688   const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5689   gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5690   GtkTextLineSegment *byte_segment = NULL;
5691   GtkTextLineSegment *byte_any_segment = NULL;
5692   GtkTextLineSegment *char_segment = NULL;
5693   GtkTextLineSegment *char_any_segment = NULL;
5694   gboolean segments_updated;
5695
5696   /* This function checks our class invariants for the Iter class. */
5697
5698   g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5699
5700   if (real->chars_changed_stamp !=
5701       _gtk_text_btree_get_chars_changed_stamp (real->tree))
5702     g_error ("iterator check failed: invalid iterator");
5703
5704   if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5705     g_error ("iterator check failed: both char and byte offsets are invalid");
5706
5707   segments_updated = (real->segments_changed_stamp ==
5708                       _gtk_text_btree_get_segments_changed_stamp (real->tree));
5709
5710 #if 0
5711   printf ("checking iter, segments %s updated, byte %d char %d\n",
5712           segments_updated ? "are" : "aren't",
5713           real->line_byte_offset,
5714           real->line_char_offset);
5715 #endif
5716
5717   if (segments_updated)
5718     {
5719       if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5720         g_error ("iterator check failed: both char and byte segment offsets are invalid");
5721
5722       if (real->segment->char_count == 0)
5723         g_error ("iterator check failed: segment is not indexable.");
5724
5725       if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5726         g_error ("segment char offset is not properly up-to-date");
5727
5728       if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5729         g_error ("segment byte offset is not properly up-to-date");
5730
5731       if (real->segment_byte_offset >= 0 &&
5732           real->segment_byte_offset >= real->segment->byte_count)
5733         g_error ("segment byte offset is too large.");
5734
5735       if (real->segment_char_offset >= 0 &&
5736           real->segment_char_offset >= real->segment->char_count)
5737         g_error ("segment char offset is too large.");
5738     }
5739
5740   if (real->line_byte_offset >= 0)
5741     {
5742       _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5743                                   &byte_segment, &byte_any_segment,
5744                                   &seg_byte_offset, &line_byte_offset);
5745
5746       if (line_byte_offset != real->line_byte_offset)
5747         g_error ("wrong byte offset was stored in iterator");
5748
5749       if (segments_updated)
5750         {
5751           if (real->segment != byte_segment)
5752             g_error ("wrong segment was stored in iterator");
5753
5754           if (real->any_segment != byte_any_segment)
5755             g_error ("wrong any_segment was stored in iterator");
5756
5757           if (seg_byte_offset != real->segment_byte_offset)
5758             g_error ("wrong segment byte offset was stored in iterator");
5759
5760           if (byte_segment->type == &gtk_text_char_type)
5761             {
5762               const gchar *p;
5763               p = byte_segment->body.chars + seg_byte_offset;
5764               
5765               if (!gtk_text_byte_begins_utf8_char (p))
5766                 g_error ("broken iterator byte index pointed into the middle of a character");
5767             }
5768         }
5769     }
5770
5771   if (real->line_char_offset >= 0)
5772     {
5773       _gtk_text_line_char_locate (real->line, real->line_char_offset,
5774                                   &char_segment, &char_any_segment,
5775                                   &seg_char_offset, &line_char_offset);
5776
5777       if (line_char_offset != real->line_char_offset)
5778         g_error ("wrong char offset was stored in iterator");
5779
5780       if (segments_updated)
5781         {          
5782           if (real->segment != char_segment)
5783             g_error ("wrong segment was stored in iterator");
5784
5785           if (real->any_segment != char_any_segment)
5786             g_error ("wrong any_segment was stored in iterator");
5787
5788           if (seg_char_offset != real->segment_char_offset)
5789             g_error ("wrong segment char offset was stored in iterator");
5790
5791           if (char_segment->type == &gtk_text_char_type)
5792             {
5793               const gchar *p;
5794               p = g_utf8_offset_to_pointer (char_segment->body.chars,
5795                                             seg_char_offset);
5796
5797               /* hmm, not likely to happen eh */
5798               if (!gtk_text_byte_begins_utf8_char (p))
5799                 g_error ("broken iterator char offset pointed into the middle of a character");
5800             }
5801         }
5802     }
5803
5804   if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5805     {
5806       if (byte_segment != char_segment)
5807         g_error ("char and byte offsets did not point to the same segment");
5808
5809       if (byte_any_segment != char_any_segment)
5810         g_error ("char and byte offsets did not point to the same any segment");
5811
5812       /* Make sure the segment offsets are equivalent, if it's a char
5813          segment. */
5814       if (char_segment->type == &gtk_text_char_type)
5815         {
5816           gint byte_offset = 0;
5817           gint char_offset = 0;
5818           while (char_offset < seg_char_offset)
5819             {
5820               const char * start = char_segment->body.chars + byte_offset;
5821               byte_offset += g_utf8_next_char (start) - start;
5822               char_offset += 1;
5823             }
5824
5825           if (byte_offset != seg_byte_offset)
5826             g_error ("byte offset did not correspond to char offset");
5827
5828           char_offset =
5829             g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5830
5831           if (char_offset != seg_char_offset)
5832             g_error ("char offset did not correspond to byte offset");
5833
5834           if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5835             g_error ("byte index for iterator does not index the start of a character");
5836         }
5837     }
5838
5839   if (real->cached_line_number >= 0)
5840     {
5841       gint should_be;
5842
5843       should_be = _gtk_text_line_get_number (real->line);
5844       if (real->cached_line_number != should_be)
5845         g_error ("wrong line number was cached");
5846     }
5847
5848   if (real->cached_char_index >= 0)
5849     {
5850       if (real->line_char_offset >= 0) /* only way we can check it
5851                                           efficiently, not a real
5852                                           invariant. */
5853         {
5854           gint char_index;
5855
5856           char_index = _gtk_text_line_char_index (real->line);
5857           char_index += real->line_char_offset;
5858
5859           if (real->cached_char_index != char_index)
5860             g_error ("wrong char index was cached");
5861         }
5862     }
5863
5864   if (_gtk_text_line_is_last (real->line, real->tree))
5865     g_error ("Iterator was on last line (past the end iterator)");
5866 }