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