gtktextiter.c 133 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* GTK - The GIMP Toolkit
 * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 13 14 15 16 17 18 19 20 21 22 23
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
24
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 26
 */

27 28 29 30
#include "gtktextiter.h"
#include "gtktextbtree.h"
#include "gtktextiterprivate.h"
#include "gtkdebug.h"
31
#include <string.h>
32 33
#include <ctype.h>

34 35
#define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1

36 37
typedef struct _GtkTextRealIter GtkTextRealIter;

38 39
struct _GtkTextRealIter
{
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  /* Always-valid information */
  GtkTextBTree *tree;
  GtkTextLine *line;
  /* At least one of these is always valid;
     if invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint line_byte_offset;
  gint line_char_offset;
  /* These two are valid if >= 0 */
  gint cached_char_index;
  gint cached_line_number;
  /* Stamps to detect the buffer changing under us */
  gint chars_changed_stamp;
  gint segments_changed_stamp;
  /* Valid if the segments_changed_stamp is up-to-date */
  GtkTextLineSegment *segment;     /* indexable segment we index */
  GtkTextLineSegment *any_segment; /* first segment in our location,
59
                                      maybe same as "segment" */
60 61 62 63 64 65 66 67 68 69 70 71 72
  /* One of these will always be valid if segments_changed_stamp is
     up-to-date. If invalid, they are -1.

     If the line byte offset is valid, so is the segment byte offset;
     and ditto for char offsets. */
  gint segment_byte_offset;
  gint segment_char_offset;
};

/* These "set" functions should not assume any fields
   other than the char stamp and the tree are valid.
*/
static void
73 74
iter_set_common (GtkTextRealIter *iter,
                 GtkTextLine *line)
75 76 77
{
  /* Update segments stamp */
  iter->segments_changed_stamp =
78
    _gtk_text_btree_get_segments_changed_stamp (iter->tree);
79

80 81 82 83 84 85 86 87 88 89 90
  iter->line = line;

  iter->line_byte_offset = -1;
  iter->line_char_offset = -1;
  iter->segment_byte_offset = -1;
  iter->segment_char_offset = -1;
  iter->cached_char_index = -1;
  iter->cached_line_number = -1;
}

static void
91 92 93
iter_set_from_byte_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint byte_offset)
94
{
95
  iter_set_common (iter, line);
96

97 98 99 100 101 102 103 104
  if (!_gtk_text_line_byte_locate (iter->line,
                                   byte_offset,
                                   &iter->segment,
                                   &iter->any_segment,
                                   &iter->segment_byte_offset,
                                   &iter->line_byte_offset))
    g_error ("Byte index %d is off the end of the line",
             byte_offset);
105 106 107
}

static void
108 109 110
iter_set_from_char_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint char_offset)
111
{
112
  iter_set_common (iter, line);
113

114 115 116 117 118 119 120 121
  if (!_gtk_text_line_char_locate (iter->line,
                                   char_offset,
                                   &iter->segment,
                                   &iter->any_segment,
                                   &iter->segment_char_offset,
                                   &iter->line_char_offset))
    g_error ("Char offset %d is off the end of the line",
             char_offset);
122 123 124
}

static void
125 126 127
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
  GtkTextLineSegment *seg;
  gint byte_offset;

  /* This could theoretically be optimized by computing all the iter
     fields in this same loop, but I'm skipping it for now. */
  byte_offset = 0;
  seg = line->segments;
  while (seg != segment)
    {
      byte_offset += seg->byte_count;
      seg = seg->next;
    }

Havoc Pennington's avatar
Havoc Pennington committed
142
  iter_set_from_byte_offset (iter, line, byte_offset);
143 144 145 146
}

/* This function ensures that the segment-dependent information is
   truly computed lazily; often we don't need to do the full make_real
147 148
   work. This ensures the btree and line are valid, but doesn't
   update the segments. */
149
static GtkTextRealIter*
150
gtk_text_iter_make_surreal (const GtkTextIter *_iter)
151 152
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
153

154
  if (iter->chars_changed_stamp !=
155
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
156 157 158 159 160 161 162 163 164 165 166
    {
      g_warning ("Invalid text buffer iterator: either the iterator "
                 "is uninitialized, or the characters/pixbufs/widgets "
                 "in the buffer have been modified since the iterator "
                 "was created.\nYou must use marks, character numbers, "
                 "or line numbers to preserve a position across buffer "
                 "modifications.\nYou can apply tags and insert marks "
                 "without invalidating your iterators,\n"
                 "but any mutation that affects 'indexable' buffer contents "
                 "(contents that can be referred to by character offset)\n"
                 "will invalidate all outstanding iterators");
167 168 169 170 171 172 173 174 175
      return NULL;
    }

  /* We don't update the segments information since we are becoming
     only surreal. However we do invalidate the segments information
     if appropriate, to be sure we segfault if we try to use it and we
     should have used make_real. */

  if (iter->segments_changed_stamp !=
176
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
177 178 179 180 181 182 183
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
184

185 186 187 188
  return iter;
}

static GtkTextRealIter*
189
gtk_text_iter_make_real (const GtkTextIter *_iter)
190 191
{
  GtkTextRealIter *iter;
192 193 194

  iter = gtk_text_iter_make_surreal (_iter);

195
  if (iter->segments_changed_stamp !=
196
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
197 198 199
    {
      if (iter->line_byte_offset >= 0)
        {
200 201 202
          iter_set_from_byte_offset (iter,
                                     iter->line,
                                     iter->line_byte_offset);
203 204 205
        }
      else
        {
206 207 208 209 210
          g_assert (iter->line_char_offset >= 0);

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
211 212 213
        }
    }

214 215 216 217
  g_assert (iter->segment != NULL);
  g_assert (iter->any_segment != NULL);
  g_assert (iter->segment->char_count > 0);

218 219 220 221
  return iter;
}

static GtkTextRealIter*
222 223
iter_init_common (GtkTextIter *_iter,
                  GtkTextBTree *tree)
224 225 226
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;

227 228
  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (tree != NULL, NULL);
229 230 231 232

  iter->tree = tree;

  iter->chars_changed_stamp =
233
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
234

235 236 237 238
  return iter;
}

static GtkTextRealIter*
239 240 241 242
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
243 244 245
{
  GtkTextRealIter *real;

246 247 248 249 250 251
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

252 253 254 255
  return real;
}

static GtkTextRealIter*
256 257 258 259
iter_init_from_byte_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_byte_offset)
260 261 262
{
  GtkTextRealIter *real;

263 264 265 266 267 268
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

269 270 271 272 273 274 275
  if (real->segment->type == &gtk_text_char_type &&
      (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
    g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
               "character; this will crash the text buffer. "
               "Byte indexes must refer to the start of a character.",
               line_byte_offset);
  
276 277 278 279
  return real;
}

static GtkTextRealIter*
280 281 282 283
iter_init_from_char_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_char_offset)
284 285 286
{
  GtkTextRealIter *real;

287 288 289 290 291 292
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

293 294 295 296
  return real;
}

static inline void
297
invalidate_segment (GtkTextRealIter *iter)
298 299 300 301 302
{
  iter->segments_changed_stamp -= 1;
}

static inline void
303
invalidate_char_index (GtkTextRealIter *iter)
304 305 306 307 308
{
  iter->cached_char_index = -1;
}

static inline void
309
invalidate_line_number (GtkTextRealIter *iter)
310 311 312 313 314
{
  iter->cached_line_number = -1;
}

static inline void
315
adjust_char_index (GtkTextRealIter *iter, gint count)
316 317 318 319 320 321
{
  if (iter->cached_char_index >= 0)
    iter->cached_char_index += count;
}

static inline void
322
adjust_line_number (GtkTextRealIter *iter, gint count)
323 324 325 326 327 328
{
  if (iter->cached_line_number >= 0)
    iter->cached_line_number += count;
}

static inline void
329
adjust_char_offsets (GtkTextRealIter *iter, gint count)
330 331 332 333
{
  if (iter->line_char_offset >= 0)
    {
      iter->line_char_offset += count;
334
      g_assert (iter->segment_char_offset >= 0);
335 336 337 338 339
      iter->segment_char_offset += count;
    }
}

static inline void
340
adjust_byte_offsets (GtkTextRealIter *iter, gint count)
341 342 343 344
{
  if (iter->line_byte_offset >= 0)
    {
      iter->line_byte_offset += count;
345
      g_assert (iter->segment_byte_offset >= 0);
346 347 348 349 350
      iter->segment_byte_offset += count;
    }
}

static inline void
351
ensure_char_offsets (GtkTextRealIter *iter)
352 353 354
{
  if (iter->line_char_offset < 0)
    {
355
      g_assert (iter->line_byte_offset >= 0);
356

357
      _gtk_text_line_byte_to_char_offsets (iter->line,
358 359 360
                                          iter->line_byte_offset,
                                          &iter->line_char_offset,
                                          &iter->segment_char_offset);
361 362 363 364
    }
}

static inline void
365
ensure_byte_offsets (GtkTextRealIter *iter)
366 367 368
{
  if (iter->line_byte_offset < 0)
    {
369
      g_assert (iter->line_char_offset >= 0);
370

371
      _gtk_text_line_char_to_byte_offsets (iter->line,
372 373 374
                                          iter->line_char_offset,
                                          &iter->line_byte_offset,
                                          &iter->segment_byte_offset);
375 376 377
    }
}

378 379 380 381 382 383
static inline gboolean
is_segment_start (GtkTextRealIter *real)
{
  return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
}

384 385
#if 1
static void
386
check_invariants (const GtkTextIter *iter)
387 388
{
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
389
    _gtk_text_iter_check (iter);
390 391
}
#else
392
#define check_invariants (x)
393 394
#endif

395 396 397
/**
 * gtk_text_iter_get_buffer:
 * @iter: an iterator
398
 *
399
 * Return the #GtkTextBuffer this iterator is associated with
400
 *
401 402
 * Return value: the buffer
 **/
403
GtkTextBuffer*
404
gtk_text_iter_get_buffer (const GtkTextIter *iter)
405 406 407
{
  GtkTextRealIter *real;

408 409 410
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
411 412 413 414

  if (real == NULL)
    return NULL;

415 416
  check_invariants (iter);

417
  return _gtk_text_btree_get_buffer (real->tree);
418 419
}

420 421 422
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
423
 *
424 425 426 427
 * Create a dynamically-allocated copy of an iterator. This function
 * is not useful in applications, because iterators can be copied with a
 * simple assignment (<literal>GtkTextIter i = j;</literal>). The
 * function is used by language bindings.
428 429
 *
 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
430
 **/
431
GtkTextIter*
432
gtk_text_iter_copy (const GtkTextIter *iter)
433 434 435
{
  GtkTextIter *new_iter;

436 437 438
  g_return_val_if_fail (iter != NULL, NULL);

  new_iter = g_new (GtkTextIter, 1);
439 440

  *new_iter = *iter;
441

442 443 444
  return new_iter;
}

445 446 447 448 449 450 451 452
/**
 * gtk_text_iter_free:
 * @iter: a dynamically-allocated iterator
 *
 * Free an iterator allocated on the heap. This function
 * is intended for use in language bindings, and is not
 * especially useful for applications, because iterators can
 * simply be allocated on the stack.
453
 *
454
 **/
455
void
456
gtk_text_iter_free (GtkTextIter *iter)
457
{
458
  g_return_if_fail (iter != NULL);
459

460
  g_free (iter);
461 462 463
}

GtkTextLineSegment*
464
_gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
465 466 467
{
  GtkTextRealIter *real;

468 469 470
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
471 472 473 474

  if (real == NULL)
    return NULL;

475 476 477 478
  check_invariants (iter);

  g_assert (real->segment != NULL);

479 480 481 482
  return real->segment;
}

GtkTextLineSegment*
483
_gtk_text_iter_get_any_segment (const GtkTextIter *iter)
484 485 486
{
  GtkTextRealIter *real;

487 488 489
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
490 491 492 493

  if (real == NULL)
    return NULL;

494 495 496 497
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

498 499 500 501
  return real->any_segment;
}

gint
502
_gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
503 504 505
{
  GtkTextRealIter *real;

506 507 508
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
509 510 511 512

  if (real == NULL)
    return 0;

513 514 515
  ensure_byte_offsets (real);

  check_invariants (iter);
516 517 518 519 520

  return real->segment_byte_offset;
}

gint
521
_gtk_text_iter_get_segment_char (const GtkTextIter *iter)
522 523 524
{
  GtkTextRealIter *real;

525 526 527
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
528 529 530 531

  if (real == NULL)
    return 0;

532 533 534
  ensure_char_offsets (real);

  check_invariants (iter);
535 536 537 538 539 540 541

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
542
_gtk_text_iter_get_text_line (const GtkTextIter *iter)
543 544 545
{
  const GtkTextRealIter *real;

546 547
  g_return_val_if_fail (iter != NULL, 0);

548 549 550 551 552 553 554 555
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
556
_gtk_text_iter_get_btree (const GtkTextIter *iter)
557 558 559
{
  const GtkTextRealIter *real;

560 561
  g_return_val_if_fail (iter != NULL, 0);

562 563 564 565 566 567 568 569 570
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

571 572 573
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
574
 *
575 576 577
 * Returns the character offset of an iterator.
 * Each character in a #GtkTextBuffer has an offset,
 * starting with 0 for the first character in the buffer.
578
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
579
 * offset back into an iterator.
580
 *
581 582
 * Return value: a character offset
 **/
583
gint
584
gtk_text_iter_get_offset (const GtkTextIter *iter)
585 586 587
{
  GtkTextRealIter *real;

588 589 590
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
591 592 593 594

  if (real == NULL)
    return 0;

595 596
  check_invariants (iter);
  
597 598
  if (real->cached_char_index < 0)
    {
599 600
      ensure_char_offsets (real);
      
601
      real->cached_char_index =
602
        _gtk_text_line_char_index (real->line);
603 604 605
      real->cached_char_index += real->line_char_offset;
    }

606 607
  check_invariants (iter);

608 609 610
  return real->cached_char_index;
}

611 612 613
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
614
 *
615 616 617
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
618
 *
619 620
 * Return value: a line number
 **/
621
gint
622
gtk_text_iter_get_line (const GtkTextIter *iter)
623 624 625
{
  GtkTextRealIter *real;

626 627 628
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
629 630 631 632 633 634

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
635
      _gtk_text_line_get_number (real->line);
636 637

  check_invariants (iter);
638 639 640 641

  return real->cached_line_number;
}

642 643 644
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
645
 *
646 647 648
 * Returns the character offset of the iterator,
 * counting from the start of a newline-terminated line.
 * The first character on the line has offset 0.
649
 *
650 651
 * Return value: offset from start of line
 **/
652
gint
653
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
654 655 656
{
  GtkTextRealIter *real;

657 658 659
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
660 661 662 663

  if (real == NULL)
    return 0;

664 665 666
  ensure_char_offsets (real);

  check_invariants (iter);
667 668 669 670

  return real->line_char_offset;
}

671 672 673
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
674
 *
675 676 677 678 679
 * Returns the byte index of the iterator, counting
 * from the start of a newline-terminated line.
 * Remember that #GtkTextBuffer encodes text in
 * UTF-8, and that characters can require a variable
 * number of bytes to represent.
680
 *
681 682
 * Return value: distance from start of line, in bytes
 **/
683
gint
Havoc Pennington's avatar
Havoc Pennington committed
684
gtk_text_iter_get_line_index (const GtkTextIter *iter)
685 686
{
  GtkTextRealIter *real;
687
  
688 689 690
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
691 692 693 694

  if (real == NULL)
    return 0;

695 696 697
  ensure_byte_offsets (real);

  check_invariants (iter);
698 699 700 701

  return real->line_byte_offset;
}

702 703 704 705 706 707 708 709 710 711 712
/**
 * gtk_text_iter_get_visible_line_offset:
 * @iter: a #GtkTextIter
 * 
 * Returns the offset in characters from the start of the
 * line to the given @iter, not counting characters that
 * are invisible due to tags with the "invisible" flag
 * toggled on.
 * 
 * Return value: offset in visible characters from the start of the line 
 **/
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
gint
gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  gint vis_offset;
  GtkTextLineSegment *seg;
  GtkTextIter pos;
  
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return 0;

  ensure_char_offsets (real);

  check_invariants (iter);

  vis_offset = real->line_char_offset;

  _gtk_text_btree_get_iter_at_line (real->tree,
                                    &pos,
                                    real->line,
                                    0);

  seg = _gtk_text_iter_get_indexable_segment (&pos);

  while (seg != real->segment)
    {
      /* This is a pretty expensive call, making the
       * whole function pretty lame; we could keep track
       * of current invisibility state by looking at toggle
       * segments as we loop, and then call this function
       * only once per line, in order to speed up the loop
       * quite a lot.
       */
      if (_gtk_text_btree_char_is_invisible (&pos))
        vis_offset -= seg->char_count;

      _gtk_text_iter_forward_indexable_segment (&pos);

      seg = _gtk_text_iter_get_indexable_segment (&pos);
    }

  if (_gtk_text_btree_char_is_invisible (&pos))
    vis_offset -= real->segment_char_offset;
  
  return vis_offset;
}

764 765 766 767 768 769 770 771 772 773 774 775

/**
 * gtk_text_iter_get_visible_line_index:
 * @iter: a #GtkTextIter
 * 
 * Returns the number of bytes from the start of the
 * line to the given @iter, not counting bytes that
 * are invisible due to tags with the "invisible" flag
 * toggled on.
 * 
 * Return value: byte index of @iter with respect to the start of the line
 **/
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
gint
gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  gint vis_offset;
  GtkTextLineSegment *seg;
  GtkTextIter pos;
  
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return 0;

  ensure_char_offsets (real);

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

  _gtk_text_btree_get_iter_at_line (real->tree,
                                    &pos,
                                    real->line,
                                    0);

  seg = _gtk_text_iter_get_indexable_segment (&pos);

  while (seg != real->segment)
    {
      /* This is a pretty expensive call, making the
       * whole function pretty lame; we could keep track
       * of current invisibility state by looking at toggle
       * segments as we loop, and then call this function
       * only once per line, in order to speed up the loop
       * quite a lot.
       */
      if (_gtk_text_btree_char_is_invisible (&pos))
        vis_offset -= seg->byte_count;

      _gtk_text_iter_forward_indexable_segment (&pos);

      seg = _gtk_text_iter_get_indexable_segment (&pos);
    }

  if (_gtk_text_btree_char_is_invisible (&pos))
    vis_offset -= real->segment_byte_offset;
  
  return vis_offset;
}

827 828 829 830
/*
 * Dereferencing
 */

831 832 833
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
834
 *
835 836 837
 * Returns the Unicode character at this iterator.  (Equivalent to
 * operator* on a C++ iterator.)  If the iterator points at a
 * non-character element, such as an image embedded in the buffer, the
Havoc Pennington's avatar
Havoc Pennington committed
838
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
839
 * the end iterator, zero is returned; zero is not a valid Unicode character.
840
 * So you can write a loop which ends when gtk_text_iter_get_char ()
841
 * returns 0.
842
 *
843
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
844
 **/
845
gunichar
846
gtk_text_iter_get_char (const GtkTextIter *iter)
847 848 849
{
  GtkTextRealIter *real;

850 851 852
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
853 854 855 856

  if (real == NULL)
    return 0;

857
  check_invariants (iter);
858

859
  if (gtk_text_iter_is_end (iter))
860 861
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
862
    {
863
      ensure_byte_offsets (real);
864
      
865 866
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
867 868 869
    }
  else
    {
Havoc Pennington's avatar
Havoc Pennington committed
870 871
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
872 873 874
    }
}

875 876 877 878
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
879
 *
880 881
 * Returns the text in the given range. A "slice" is an array of
 * characters encoded in UTF-8 format, including the Unicode "unknown"
Havoc Pennington's avatar
Havoc Pennington committed
882
 * character 0xFFFC for iterable non-character elements in the buffer,
883 884
 * such as images.  Because images are encoded in the slice, byte and
 * character offsets in the returned array will correspond to byte
Havoc Pennington's avatar
Havoc Pennington committed
885
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
886 887
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
888
 *
889 890
 * Return value: slice of text from the buffer
 **/
891 892
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
893
                               const GtkTextIter *end)
894
{
895 896 897 898 899
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
900

901
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
902 903
}

904 905 906 907
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
908
 *
909 910 911 912
 * Returns <emphasis>text</emphasis> in the given range.  If the range
 * contains non-text elements such as images, the character and byte
 * offsets in the returned string will not correspond to character and
 * byte offsets in the buffer. If you want offsets to correspond, see
913 914
 * gtk_text_iter_get_slice ().
 *
915 916
 * Return value: array of characters from the buffer
 **/
917 918
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
919
                              const GtkTextIter *end)
920
{
921 922 923 924 925
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
926

927
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
928 929
}

930 931 932 933
/**
 * gtk_text_iter_get_visible_slice:
 * @start: iterator at start of range
 * @end: iterator at end of range
934 935
 *
 * Like gtk_text_iter_get_slice (), but invisible text is not included.
936 937
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
938
 *
939 940
 * Return value: slice of text from the buffer
 **/
941 942
gchar*
gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
943
                                 const GtkTextIter  *end)
944
{
945 946
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);
947

948 949 950
  check_invariants (start);
  check_invariants (end);

951
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
952 953
}

954 955 956 957
/**
 * gtk_text_iter_get_visible_text:
 * @start: iterator at start of range
 * @end: iterator at end of range
958 959
 *
 * Like gtk_text_iter_get_text (), but invisible text is not included.
960 961
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
962
 *
963 964
 * Return value: string containing visible text in the range
 **/
965 966
gchar*
gtk_text_iter_get_visible_text (const GtkTextIter  *start,
967
                                const GtkTextIter  *end)
968
{
969 970 971 972 973 974
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);

975
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
976 977
}

978
/**
Havoc Pennington's avatar
Havoc Pennington committed
979
 * gtk_text_iter_get_pixbuf:
980
 * @iter: an iterator
981
 *
Havoc Pennington's avatar
Havoc Pennington committed
982 983 984
 * If the location pointed to by @iter contains a pixbuf, the pixbuf
 * is returned (with no new reference count added). Otherwise,
 * NULL is returned.
985
 *
Havoc Pennington's avatar
Havoc Pennington committed
986
 * Return value: the pixbuf at @iter
987
 **/
Havoc Pennington's avatar
Havoc Pennington committed
988 989
GdkPixbuf*
gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
990 991 992
{
  GtkTextRealIter *real;

993
  g_return_val_if_fail (iter != NULL, NULL);
994 995

  real = gtk_text_iter_make_real (iter);
996 997

  if (real == NULL)
998
    return NULL;
999 1000 1001

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
1002
  if (real->segment->type != &gtk_text_pixbuf_type)
1003
    return NULL;
1004
  else
Havoc Pennington's avatar
Havoc Pennington committed
1005
    return real->segment->body.pixbuf.pixbuf;
1006 1007
}

1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
/**
 * gtk_text_iter_get_child_anchor:
 * @iter: an iterator
 *
 * If the location pointed to by @iter contains a child anchor, the
 * anchor is returned (with no new reference count added). Otherwise,
 * NULL is returned.
 *
 * Return value: the anchor at @iter
 **/
GtkTextChildAnchor*
gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
{
  GtkTextRealIter *real;

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);

  if (real == NULL)
    return NULL;

  check_invariants (iter);

  if (real->segment->type != &gtk_text_child_type)
    return NULL;
  else
    return real->segment->body.child.obj;
}

1038 1039 1040
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
1041
 *
1042 1043 1044 1045 1046
 * Returns a list of all #GtkTextMark at this location. Because marks
 * are not iterable (they don't take up any "space" in the buffer,
 * they are just marks in between iterable locations), multiple marks
 * can exist in the same place. The returned list is not in any
 * meaningful order.
1047
 *
1048 1049
 * Return value: list of #GtkTextMark
 **/
1050 1051 1052 1053 1054 1055
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;