gtktextiter.c 147 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10
 * 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
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28
#include "config.h"
29 30 31
#include "gtktextiter.h"
#include "gtktextbtree.h"
#include "gtktextiterprivate.h"
32
#include "gtkintl.h"
33
#include "gtkdebug.h"
34

35
#include <string.h>
36

37 38 39 40 41 42 43 44 45 46 47 48

/**
 * SECTION:gtktextiter
 * @Short_description: Text buffer iterator
 * @Title: GtkTextIter
 *
 * You may wish to begin by reading the <link linkend="TextWidget">text widget
 * conceptual overview</link> which gives an overview of all the objects and data
 * types related to the text widget and how they work together.
 */


49 50
#define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1

51 52
typedef struct _GtkTextRealIter GtkTextRealIter;

53
struct G_GNUC_MAY_ALIAS _GtkTextRealIter
54
{
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  /* 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,
74
                                      maybe same as "segment" */
75 76 77 78 79 80 81
  /* 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;
82 83 84 85

  /* padding */
  gint pad1;
  gpointer pad2;
86 87 88 89 90 91
};

/* These "set" functions should not assume any fields
   other than the char stamp and the tree are valid.
*/
static void
92 93
iter_set_common (GtkTextRealIter *iter,
                 GtkTextLine *line)
94 95 96
{
  /* Update segments stamp */
  iter->segments_changed_stamp =
97
    _gtk_text_btree_get_segments_changed_stamp (iter->tree);
98

99 100 101 102 103 104 105 106 107 108 109
  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
110 111 112
iter_set_from_byte_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint byte_offset)
113
{
114
  iter_set_common (iter, line);
115

116 117 118 119 120 121 122 123
  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);
124 125 126
}

static void
127 128 129
iter_set_from_char_offset (GtkTextRealIter *iter,
                           GtkTextLine *line,
                           gint char_offset)
130
{
131
  iter_set_common (iter, line);
132

133 134 135 136 137 138 139 140
  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);
141 142 143
}

static void
144 145 146
iter_set_from_segment (GtkTextRealIter *iter,
                       GtkTextLine *line,
                       GtkTextLineSegment *segment)
147 148 149 150 151 152 153 154 155 156 157 158 159 160
{
  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;
    }

161
  iter_set_from_byte_offset (iter, line, byte_offset);
162 163 164 165
}

/* This function ensures that the segment-dependent information is
   truly computed lazily; often we don't need to do the full make_real
166 167
   work. This ensures the btree and line are valid, but doesn't
   update the segments. */
168
static GtkTextRealIter*
169
gtk_text_iter_make_surreal (const GtkTextIter *_iter)
170 171
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
172

173
  if (iter->chars_changed_stamp !=
174
      _gtk_text_btree_get_chars_changed_stamp (iter->tree))
175 176 177 178 179 180 181 182 183 184 185
    {
      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");
186 187 188 189 190 191 192 193 194
      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 !=
195
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
196 197 198 199 200 201 202
    {
      iter->segment = NULL;
      iter->any_segment = NULL;
      /* set to segfault-causing values. */
      iter->segment_byte_offset = -10000;
      iter->segment_char_offset = -10000;
    }
203

204 205 206 207
  return iter;
}

static GtkTextRealIter*
208
gtk_text_iter_make_real (const GtkTextIter *_iter)
209 210
{
  GtkTextRealIter *iter;
211 212 213

  iter = gtk_text_iter_make_surreal (_iter);

214
  if (iter->segments_changed_stamp !=
215
      _gtk_text_btree_get_segments_changed_stamp (iter->tree))
216 217 218
    {
      if (iter->line_byte_offset >= 0)
        {
219 220 221
          iter_set_from_byte_offset (iter,
                                     iter->line,
                                     iter->line_byte_offset);
222 223 224
        }
      else
        {
225 226 227 228 229
          g_assert (iter->line_char_offset >= 0);

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
230 231 232
        }
    }

233 234 235 236
  g_assert (iter->segment != NULL);
  g_assert (iter->any_segment != NULL);
  g_assert (iter->segment->char_count > 0);

237 238 239 240
  return iter;
}

static GtkTextRealIter*
241 242
iter_init_common (GtkTextIter *_iter,
                  GtkTextBTree *tree)
243 244 245
{
  GtkTextRealIter *iter = (GtkTextRealIter*)_iter;

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

  iter->tree = tree;

  iter->chars_changed_stamp =
252
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
253

254 255 256 257
  return iter;
}

static GtkTextRealIter*
258 259 260 261
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
262 263 264
{
  GtkTextRealIter *real;

265 266 267 268 269 270
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

271 272 273 274
  return real;
}

static GtkTextRealIter*
275 276 277 278
iter_init_from_byte_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_byte_offset)
279 280 281
{
  GtkTextRealIter *real;

282 283 284 285 286 287
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

288 289 290 291 292 293 294
  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);
  
295 296 297 298
  return real;
}

static GtkTextRealIter*
299 300 301 302
iter_init_from_char_offset (GtkTextIter *iter,
                            GtkTextBTree *tree,
                            GtkTextLine *line,
                            gint line_char_offset)
303 304 305
{
  GtkTextRealIter *real;

306 307 308 309 310 311
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

312 313 314 315
  return real;
}

static inline void
316
invalidate_char_index (GtkTextRealIter *iter)
317 318 319 320 321
{
  iter->cached_char_index = -1;
}

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

static inline void
329
adjust_line_number (GtkTextRealIter *iter, gint count)
330 331 332 333 334 335
{
  if (iter->cached_line_number >= 0)
    iter->cached_line_number += count;
}

static inline void
336
ensure_char_offsets (GtkTextRealIter *iter)
337 338 339
{
  if (iter->line_char_offset < 0)
    {
340
      g_assert (iter->line_byte_offset >= 0);
341

342
      _gtk_text_line_byte_to_char_offsets (iter->line,
343 344 345
                                          iter->line_byte_offset,
                                          &iter->line_char_offset,
                                          &iter->segment_char_offset);
346 347 348 349
    }
}

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

356
      _gtk_text_line_char_to_byte_offsets (iter->line,
357 358 359
                                          iter->line_char_offset,
                                          &iter->line_byte_offset,
                                          &iter->segment_byte_offset);
360 361 362
    }
}

363 364 365 366 367 368
static inline gboolean
is_segment_start (GtkTextRealIter *real)
{
  return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
}

369
#ifdef G_ENABLE_DEBUG
370
static void
371
check_invariants (const GtkTextIter *iter)
372 373
{
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
374
    _gtk_text_iter_check (iter);
375 376
}
#else
Matthias Clasen's avatar
Matthias Clasen committed
377
#define check_invariants(x)
378 379
#endif

380 381 382
/**
 * gtk_text_iter_get_buffer:
 * @iter: an iterator
383
 *
384
 * Returns the #GtkTextBuffer this iterator is associated with.
385
 *
386
 * Return value: (transfer none): the buffer
387
 **/
388
GtkTextBuffer*
389
gtk_text_iter_get_buffer (const GtkTextIter *iter)
390 391 392
{
  GtkTextRealIter *real;

393 394 395
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
396 397 398 399

  if (real == NULL)
    return NULL;

400 401
  check_invariants (iter);

402
  return _gtk_text_btree_get_buffer (real->tree);
403 404
}

405 406 407
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
408
 *
409
 * Creates a dynamically-allocated copy of an iterator. This function
410 411 412
 * 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.
413 414
 *
 * Return value: a copy of the @iter, free with gtk_text_iter_free ()
415
 **/
416
GtkTextIter*
417
gtk_text_iter_copy (const GtkTextIter *iter)
418 419 420
{
  GtkTextIter *new_iter;

421 422
  g_return_val_if_fail (iter != NULL, NULL);

423
  new_iter = g_slice_new (GtkTextIter);
424 425

  *new_iter = *iter;
426

427 428 429
  return new_iter;
}

430 431 432 433 434 435 436 437 438
/**
 * 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.
 **/
439
void
440
gtk_text_iter_free (GtkTextIter *iter)
441
{
442
  g_return_if_fail (iter != NULL);
443

444
  g_slice_free (GtkTextIter, iter);
445 446
}

447 448 449
G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
                     gtk_text_iter_copy,
                     gtk_text_iter_free)
450

451
GtkTextLineSegment*
452
_gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
453 454 455
{
  GtkTextRealIter *real;

456
  g_return_val_if_fail (iter != NULL, NULL);
457 458

  real = gtk_text_iter_make_real (iter);
459 460 461 462

  if (real == NULL)
    return NULL;

463 464 465 466
  check_invariants (iter);

  g_assert (real->segment != NULL);

467 468 469 470
  return real->segment;
}

GtkTextLineSegment*
471
_gtk_text_iter_get_any_segment (const GtkTextIter *iter)
472 473 474
{
  GtkTextRealIter *real;

475
  g_return_val_if_fail (iter != NULL, NULL);
476 477

  real = gtk_text_iter_make_real (iter);
478 479 480 481

  if (real == NULL)
    return NULL;

482 483 484 485
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

486 487 488 489
  return real->any_segment;
}

gint
490
_gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
491 492 493
{
  GtkTextRealIter *real;

494
  g_return_val_if_fail (iter != NULL, 0);
495 496

  real = gtk_text_iter_make_real (iter);
497 498 499 500

  if (real == NULL)
    return 0;

501 502 503
  ensure_byte_offsets (real);

  check_invariants (iter);
504 505 506 507 508

  return real->segment_byte_offset;
}

gint
509
_gtk_text_iter_get_segment_char (const GtkTextIter *iter)
510 511 512
{
  GtkTextRealIter *real;

513
  g_return_val_if_fail (iter != NULL, 0);
514 515

  real = gtk_text_iter_make_real (iter);
516 517 518 519

  if (real == NULL)
    return 0;

520 521 522
  ensure_char_offsets (real);

  check_invariants (iter);
523 524 525 526 527 528 529

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
530
_gtk_text_iter_get_text_line (const GtkTextIter *iter)
531 532 533
{
  const GtkTextRealIter *real;

534
  g_return_val_if_fail (iter != NULL, NULL);
535

536 537 538 539 540 541 542 543
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
544
_gtk_text_iter_get_btree (const GtkTextIter *iter)
545 546 547
{
  const GtkTextRealIter *real;

548
  g_return_val_if_fail (iter != NULL, NULL);
549

550 551 552 553 554 555 556 557 558
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

559 560 561
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
562
 *
563 564 565
 * 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.
566
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
567
 * offset back into an iterator.
568
 *
569 570
 * Return value: a character offset
 **/
571
gint
572
gtk_text_iter_get_offset (const GtkTextIter *iter)
573 574 575
{
  GtkTextRealIter *real;

576 577 578
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
579 580 581 582

  if (real == NULL)
    return 0;

583 584
  check_invariants (iter);
  
585 586
  if (real->cached_char_index < 0)
    {
587 588
      ensure_char_offsets (real);
      
589
      real->cached_char_index =
590
        _gtk_text_line_char_index (real->line);
591 592 593
      real->cached_char_index += real->line_char_offset;
    }

594 595
  check_invariants (iter);

596 597 598
  return real->cached_char_index;
}

599 600 601
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
602
 *
603 604 605
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
606
 *
607 608
 * Return value: a line number
 **/
609
gint
610
gtk_text_iter_get_line (const GtkTextIter *iter)
611 612 613
{
  GtkTextRealIter *real;

614 615 616
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
617 618 619 620 621 622

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
623
      _gtk_text_line_get_number (real->line);
624 625

  check_invariants (iter);
626 627 628 629

  return real->cached_line_number;
}

630 631 632
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
633
 *
634 635 636
 * 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.
637
 *
638 639
 * Return value: offset from start of line
 **/
640
gint
641
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
642 643 644
{
  GtkTextRealIter *real;

645 646 647
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
648 649 650 651

  if (real == NULL)
    return 0;

652 653 654
  ensure_char_offsets (real);

  check_invariants (iter);
655 656 657 658

  return real->line_char_offset;
}

659 660 661
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
662
 *
663 664 665 666 667
 * 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.
668
 *
669 670
 * Return value: distance from start of line, in bytes
 **/
671
gint
672
gtk_text_iter_get_line_index (const GtkTextIter *iter)
673 674
{
  GtkTextRealIter *real;
675
  
676 677 678
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
679 680 681 682

  if (real == NULL)
    return 0;

683 684 685
  ensure_byte_offsets (real);

  check_invariants (iter);
686 687 688 689

  return real->line_byte_offset;
}

690 691 692 693 694 695 696 697 698 699 700
/**
 * 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 
 **/
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
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);
719
  
720 721
  vis_offset = real->line_char_offset;

722 723
  g_assert (vis_offset >= 0);
  
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
  _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;
}

754 755 756 757 758 759 760 761 762 763 764 765

/**
 * 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
 **/
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
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;

781
  ensure_byte_offsets (real);
782 783 784 785 786

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

787 788
  g_assert (vis_offset >= 0);
  
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
  _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;
}

819 820 821 822
/*
 * Dereferencing
 */

823 824 825
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
826
 *
827
 * Returns the Unicode character at this iterator.  (Equivalent to
828
 * operator* on a C++ iterator.)  If the element at this iterator is a
829
 * non-character element, such as an image embedded in the buffer, the
830
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
831
 * the end iterator, zero is returned; zero is not a valid Unicode character.
832
 * So you can write a loop which ends when gtk_text_iter_get_char ()
833
 * returns 0.
834
 *
835
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
836
 **/
837
gunichar
838
gtk_text_iter_get_char (const GtkTextIter *iter)
839 840 841
{
  GtkTextRealIter *real;

842 843 844
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
845 846 847 848

  if (real == NULL)
    return 0;

849
  check_invariants (iter);
850

851
  if (gtk_text_iter_is_end (iter))
852 853
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
854
    {
855
      ensure_byte_offsets (real);
856
      
857 858
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
859 860 861
    }
  else
    {
862 863
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
864 865 866
    }
}

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

  check_invariants (start);
  check_invariants (end);
892

893
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
894 895
}

896 897 898 899
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
900
 *
901 902 903 904
 * 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
905 906
 * gtk_text_iter_get_slice ().
 *
907 908
 * Return value: array of characters from the buffer
 **/
909 910
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
911
                              const GtkTextIter *end)
912
{
913 914 915 916 917
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
918

919
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
920 921
}

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

940 941 942
  check_invariants (start);
  check_invariants (end);

943
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
944 945
}

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

  check_invariants (start);
  check_invariants (end);

967
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
968 969
}

970
/**
Havoc Pennington's avatar
Havoc Pennington committed
971
 * gtk_text_iter_get_pixbuf:
972
 * @iter: an iterator
973
 *
974 975
 * If the element at @iter is a pixbuf, the pixbuf is returned
 * (with no new reference count added). Otherwise,
976
 * %NULL is returned.
977
 *
978
 * Return value: (transfer none): the pixbuf at @iter
979
 **/
Havoc Pennington's avatar
Havoc Pennington committed
980 981
GdkPixbuf*
gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
982 983 984
{
  GtkTextRealIter *real;

985
  g_return_val_if_fail (iter != NULL, NULL);
986 987

  real = gtk_text_iter_make_real (iter);
988 989

  if (real == NULL)
990
    return NULL;
991 992 993

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
994
  if (real->segment->type != &gtk_text_pixbuf_type)
995
    return NULL;
996
  else
Havoc Pennington's avatar
Havoc Pennington committed
997
    return real->segment->body.pixbuf.pixbuf;
998 999
}

1000 1001 1002 1003
/**
 * gtk_text_iter_get_child_anchor:
 * @iter: an iterator
 *
1004
 * If the location at @iter contains a child anchor, the
1005
 * anchor is returned (with no new reference count added). Otherwise,
1006
 * %NULL is returned.
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
 *
 * 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;
}

1030 1031 1032
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
1033
 *
1034 1035 1036 1037 1038
 * 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.
1039
 *
1040
 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1041
 **/
1042 1043 1044 1045 1046 1047
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1048 1049 1050 1051

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1052 1053 1054 1055

  if (real == NULL)
    return NULL;

1056 1057
  check_invariants (iter);

1058 1059 1060 1061 1062 1063
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_left_mark_type ||
          seg->type == &gtk_text_right_mark_type)
1064
        retval = g_slist_prepend (retval, seg->body.mark.obj);
1065

1066 1067 1068 1069 1070 1071 1072 1073
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

1074 1075 1076
/**
 * gtk_text_iter_get_toggled_tags:
 * @iter: an iterator
1077
 * @toggled_on: %TRUE to get toggled-on tags
1078
 *
1079
 * Returns a list of #GtkTextTag that are toggled on or off at this
1080
 * point.  (If @toggled_on is %TRUE, the list contains tags that are
1081 1082 1083 1084
 * toggled on.) If a tag is toggled on at @iter, then some non-empty
 * range of characters following @iter has that tag applied to it.  If
 * a tag is toggled off, then some non-empty range following @iter
 * does <emphasis>not</emphasis> have the tag applied to it.
1085
 *
1086
 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1087
 **/
1088 1089
GSList*
gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
1090
                                 gboolean            toggled_on)
1091 1092 1093 1094
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1095 1096 1097 1098

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1099 1100 1101 1102

  if (real == NULL)
    return NULL;

1103 1104
  check_invariants (iter);

1105 1106 1107 1108 1109 1110 1111 1112
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (toggled_on)
        {
          if (seg->type == &gtk_text_toggle_on_type)
            {
1113
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1114 1115 1116 1117 1118 1119
            }
        }
      else
        {
          if (seg->type == &gtk_text_toggle_off_type)
            {
1120
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1121 1122
            }
        }
1123

1124 1125 1126 1127 1128 1129 1130 1131
      seg = seg->next;
    }

  /* The returned list isn't guaranteed to be in any special order,
     and it isn't. */
  return retval;
}

1132 1133 1134
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
1135
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1136
 *
1137 1138 1139
 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
 * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
 * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1140
 * <emphasis>start</emphasis> of the tagged range;
1141
 * gtk_text_iter_has_tag () tells you whether an iterator is
1142
 * <emphasis>within</emphasis> a tagged range.
1143
 *
1144 1145
 * Return value: whether @iter is the start of a range tagged with @tag
 **/
1146 1147
gboolean
gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1148
                             GtkTextTag         *tag)
1149 1150 1151
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1152 1153 1154 1155

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1156 1157 1158 1159

  if (real == NULL)
    return FALSE;

1160 1161
  check_invariants (iter);

1162 1163 1164 1165 1166 1167 1168 1169 1170
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_on_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1171

1172 1173 1174 1175 1176 1177
      seg = seg->next;
    }

  return FALSE;
}

1178 1179 1180
/**
 * gtk_text_iter_ends_tag:
 * @iter: an iterator
1181
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1182
 *
1183 1184 1185
 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
 * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
 * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1186
 * <emphasis>end</emphasis> of the tagged range;
1187
 * gtk_text_iter_has_tag () tells you whether an iterator is
1188
 * <emphasis>within</emphasis> a tagged range.
1189
 *
1190
 * Return value: whether @iter is the end of a range tagged with @tag
1191
 *
1192
 **/
1193 1194
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1195
                          GtkTextTag         *tag)
1196 1197 1198
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1199 1200 1201 1202

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1203 1204 1205 1206

  if (real == NULL)
    return FALSE;

1207 1208
  check_invariants (iter);

1209 1210 1211 1212 1213 1214 1215 1216 1217
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (seg->type == &gtk_text_toggle_off_type)
        {
          if (tag == NULL ||
              seg->body.toggle.info->tag == tag)
            return TRUE;
        }
1218

1219 1220 1221 1222 1223 1224
      seg = seg->next;
    }

  return FALSE;
}

1225 1226 1227
/**
 * gtk_text_iter_toggles_tag:
 * @iter: an iterator
1228
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1229 1230 1231
 *
 * This is equivalent to (gtk_text_iter_begins_tag () ||
 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1232
 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1233
 *
1234 1235
 * Return value: whether @tag is toggled on or off at @iter
 **/
1236
gboolean
1237 1238
gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
                           GtkTextTag         *tag)
1239 1240 1241
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1242 1243 1244 1245

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1246 1247 1248 1249

  if (real == NULL)
    return FALSE;

1250 1251
  check_invariants (iter);

1252 1253 1254 1255 1256 1257 1258 1259
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if ( (seg->type == &gtk_text_toggle_off_type ||
            seg->type == &gtk_text_toggle_on_type) &&
           (tag == NULL ||
            seg->body.toggle.info->tag == tag) )
        return TRUE;
1260

1261 1262 1263 1264 1265 1266
      seg = seg->next;
    }

  return FALSE;
}

1267 1268 1269 1270
/**
 * gtk_text_iter_has_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag
1271
 *
1272
 * Returns %TRUE if @iter is within a range tagged with @tag.
1273
 *
1274 1275
 * Return value: whether @iter is tagged with @tag
 **/
1276
gboolean
1277 1278
gtk_text_iter_has_tag (const GtkTextIter   *iter,
                       GtkTextTag          *tag)
1279 1280
{
  GtkTextRealIter *real;
1281 1282 1283 1284 1285

  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);

  real = gtk_text_iter_make_surreal (iter);
1286 1287

  if (real == NULL)
1288 1289 1290
    return FALSE;

  check_invariants (iter);
1291 1292 1293

  if (real->line_byte_offset >= 0)
    {
1294
      return _gtk_text_line_byte_has_tag (real->line, real->tree,
1295
                                          real->line_byte_offset, tag);
1296 1297 1298
    }
  else
    {
1299
      g_assert (real->line_char_offset >= 0);
1300
      return _gtk_text_line_char_has_tag (real->line, real->tree,
1301
                                          real->line_char_offset, tag);
1302 1303 1304
    }
}

1305 1306 1307 1308 1309 1310 1311 1312
/**
 * gtk_text_iter_get_tags:
 * @iter: a #GtkTextIter
 * 
 * Returns a list of tags that apply to @iter, in ascending order of
 * priority (highest-priority tags are last). The #GtkTextTag in the
 * list don't have a reference added, but you have to free the list
 * itself.
1313 1314
 *
 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
 **/
GSList*
gtk_text_iter_get_tags (const GtkTextIter *iter)
{
  GtkTextTag** tags;
  gint tag_count = 0;
  gint i;
  GSList *retval;
  
  g_return_val_if_fail (iter != NULL, NULL);
  
  /* Get the tags at this spot */
1327
  tags = _gtk_text_btree_get_tags (iter, &tag_count);
1328 1329 1330 1331

  /* No tags, use default style */
  if (tags == NULL || tag_count == 0)
    {
1332
      g_free (tags);
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350

      return NULL;
    }

  retval = NULL;
  i = 0;
  while (i < tag_count)
    {
      retval = g_slist_prepend (retval, tags[i]);
      ++i;
    }
  
  g_free (tags);

  /* Return tags in ascending order of priority */
  return g_slist_reverse (retval);
}

1351 1352 1353
/**
 * gtk_text_iter_editable:
 * @iter: an iterator
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
 * @default_setting: %TRUE if text is editable by default
 *
 * Returns whether the character at @iter is within an editable region
 * of text.  Non-editable text is "locked" and can't be changed by the
 * user via #GtkTextView. This function is simply a convenience
 * wrapper around gtk_text_iter_get_attributes (). If no tags applied
 * to this text affect editability, @default_setting will be returned.
 *
 * You don't want to use this function to decide whether text can be
 * inserted at @iter, because for insertion you don't want to know
 * whether the char at @iter is inside an editable range, you want to
 * know whether a new character inserted at @iter would be inside an
 * editable range. Use gtk_text_iter_can_insert() to handle this
 * case.
 * 
1369 1370
 * Return value: whether @iter is inside an editable range
 **/
1371 1372 1373 1374
gboolean
gtk_text_iter_editable (const GtkTextIter *iter,
                        gboolean           default_setting)
{
1375
  GtkTextAttributes *values;
1376
  gboolean retval;
1377

1378 1379
  g_return_val_if_fail (iter != NULL, FALSE);
  
1380
  values = gtk_text_attributes_new ();
1381 1382 1383

  values->editable = default_setting;

1384
  gtk_text_iter_get_attributes (iter, values);
1385 1386

  retval = values->editable;
1387

1388
  gtk_text_attributes_unref (values);
1389 1390 1391 1392

  return retval;
}

1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
/**
 * gtk_text_iter_can_insert:
 * @iter: an iterator
 * @default_editability: %TRUE if text is editable by default
 * 
 * Considering the default editability of the buffer, and tags that
 * affect editability, determines whether text inserted at @iter would
 * be editable. If text inserted at @iter would be editable then the
 * user should be allowed to insert text at @iter.
 * gtk_text_buffer_insert_interactive() uses this function to decide
 * whether insertions are allowed at a given position.
 * 
 * Return value: whether text inserted at @iter would be editable
 **/
gboolean
gtk_text_iter_can_insert (const GtkTextIter *iter,
                          gboolean           default_editability)
{
  g_return_val_if_fail (iter != NULL, FALSE);
  
  if (gtk_text_iter_editable (iter, default_editability))
    return TRUE;
  /* If at start/end of buffer, default editability is used */
  else if ((gtk_text_iter_is_start (iter) ||
            gtk_text_iter_is_end (iter)) &&
           default_editability)
    return TRUE;
  else
    {
      /* if iter isn't editable, and the char before iter is,
       * then iter is the first char in an editable region
       * and thus insertion at iter results in editable text.
       */
      GtkTextIter prev = *iter;
      gtk_text_iter_backward_char (&prev);
      return gtk_text_iter_editable (&prev, default_editability);
    }
}


1433 1434 1435
/**
 * gtk_text_iter_get_language:
 * @iter: an iterator
1436 1437
 *
 * A convenience wrapper around gtk_text_iter_get_attributes (),
1438
 * which returns the language in effect at @iter. If no tags affecting
1439
 * language apply to @iter, the return value is identical to that of
1440 1441
 * gtk_get_default_language ().
 *
1442 1443
 * Return value: language in effect at @iter
 **/
1444
PangoLanguage *
1445 1446
gtk_text_iter_get_language (const GtkTextIter *iter)
{
1447
  GtkTextAttributes *values;
1448 1449
  PangoLanguage *retval;
  
1450
  values = gtk_text_attributes_new ();
1451

1452
  gtk_text_iter_get_attributes (iter, values);
1453

1454
  retval = values->language;
1455