gtktextiter.c 155 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19 20 21
 */

/*
 * 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
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 24
 */

25
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
26
#include "config.h"
27 28 29
#include "gtktextiter.h"
#include "gtktextbtree.h"
#include "gtktextiterprivate.h"
30
#include "gtkintl.h"
31
#include "gtkdebug.h"
32

33
#include <string.h>
34

35 36 37 38 39 40 41 42 43 44 45 46

/**
 * 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.
 */


47 48
#define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1

49 50
typedef struct _GtkTextRealIter GtkTextRealIter;

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

  /* padding */
  gint pad1;
  gpointer pad2;
84 85 86 87 88 89
};

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

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

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

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

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

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

159
  iter_set_from_byte_offset (iter, line, byte_offset);
160 161 162 163
}

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

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

202 203 204 205
  return iter;
}

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

  iter = gtk_text_iter_make_surreal (_iter);

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

          iter_set_from_char_offset (iter,
                                     iter->line,
                                     iter->line_char_offset);
228 229 230
        }
    }

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

235 236 237 238
  return iter;
}

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

244 245
  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (tree != NULL, NULL);
246 247 248 249

  iter->tree = tree;

  iter->chars_changed_stamp =
250
    _gtk_text_btree_get_chars_changed_stamp (iter->tree);
251

252 253 254 255
  return iter;
}

static GtkTextRealIter*
256 257 258 259
iter_init_from_segment (GtkTextIter *iter,
                        GtkTextBTree *tree,
                        GtkTextLine *line,
                        GtkTextLineSegment *segment)
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_segment (real, line, segment);

269 270 271 272
  return real;
}

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

280 281 282 283 284 285
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

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

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

304 305 306 307 308 309
  g_return_val_if_fail (line != NULL, NULL);

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

310 311 312 313
  return real;
}

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

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

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

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

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

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

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

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

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

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

391 392 393
  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_surreal (iter);
394 395 396 397

  if (real == NULL)
    return NULL;

398 399
  check_invariants (iter);

400
  return _gtk_text_btree_get_buffer (real->tree);
401 402
}

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

419 420
  g_return_val_if_fail (iter != NULL, NULL);

421
  new_iter = g_slice_new (GtkTextIter);
422 423

  *new_iter = *iter;
424

425 426 427
  return new_iter;
}

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

442
  g_slice_free (GtkTextIter, iter);
443 444
}

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
/**
 * gtk_text_iter_assign:
 * @iter: a #GtkTextIter
 * @other: another #GtkTextIter
 *
 * Assigns the value of @other to @iter.  This function
 * is not useful in applications, because iterators can be assigned
 * with <literal>GtkTextIter i = j;</literal>. The
 * function is used by language bindings.
 *
 * Since: 3.2
 **/
void
gtk_text_iter_assign (GtkTextIter       *iter,
                      const GtkTextIter *other)
{
  g_return_if_fail (iter != NULL);
  g_return_if_fail (other != NULL);

  *iter = *other;
}

467 468 469
G_DEFINE_BOXED_TYPE (GtkTextIter, gtk_text_iter,
                     gtk_text_iter_copy,
                     gtk_text_iter_free)
470

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

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

  real = gtk_text_iter_make_real (iter);
479 480 481 482

  if (real == NULL)
    return NULL;

483 484 485 486
  check_invariants (iter);

  g_assert (real->segment != NULL);

487 488 489 490
  return real->segment;
}

GtkTextLineSegment*
491
_gtk_text_iter_get_any_segment (const GtkTextIter *iter)
492 493 494
{
  GtkTextRealIter *real;

495
  g_return_val_if_fail (iter != NULL, NULL);
496 497

  real = gtk_text_iter_make_real (iter);
498 499 500 501

  if (real == NULL)
    return NULL;

502 503 504 505
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

506 507 508 509
  return real->any_segment;
}

gint
510
_gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
511 512 513
{
  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_real (iter);
517 518 519 520

  if (real == NULL)
    return 0;

521 522 523
  ensure_byte_offsets (real);

  check_invariants (iter);
524 525 526 527 528

  return real->segment_byte_offset;
}

gint
529
_gtk_text_iter_get_segment_char (const GtkTextIter *iter)
530 531 532
{
  GtkTextRealIter *real;

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

  real = gtk_text_iter_make_real (iter);
536 537 538 539

  if (real == NULL)
    return 0;

540 541 542
  ensure_char_offsets (real);

  check_invariants (iter);
543 544 545 546 547 548 549

  return real->segment_char_offset;
}

/* This function does not require a still-valid
   iterator */
GtkTextLine*
550
_gtk_text_iter_get_text_line (const GtkTextIter *iter)
551 552 553
{
  const GtkTextRealIter *real;

554
  g_return_val_if_fail (iter != NULL, NULL);
555

556 557 558 559 560 561 562 563
  real = (const GtkTextRealIter*)iter;

  return real->line;
}

/* This function does not require a still-valid
   iterator */
GtkTextBTree*
564
_gtk_text_iter_get_btree (const GtkTextIter *iter)
565 566 567
{
  const GtkTextRealIter *real;

568
  g_return_val_if_fail (iter != NULL, NULL);
569

570 571 572 573 574 575 576 577 578
  real = (const GtkTextRealIter*)iter;

  return real->tree;
}

/*
 * Conversions
 */

579 580 581
/**
 * gtk_text_iter_get_offset:
 * @iter: an iterator
582
 *
583 584 585
 * 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.
586
 * Use gtk_text_buffer_get_iter_at_offset () to convert an
587
 * offset back into an iterator.
588
 *
589 590
 * Return value: a character offset
 **/
591
gint
592
gtk_text_iter_get_offset (const GtkTextIter *iter)
593 594 595
{
  GtkTextRealIter *real;

596 597 598
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
599 600 601 602

  if (real == NULL)
    return 0;

603 604
  check_invariants (iter);
  
605 606
  if (real->cached_char_index < 0)
    {
607 608
      ensure_char_offsets (real);
      
609
      real->cached_char_index =
610
        _gtk_text_line_char_index (real->line);
611 612 613
      real->cached_char_index += real->line_char_offset;
    }

614 615
  check_invariants (iter);

616 617 618
  return real->cached_char_index;
}

619 620 621
/**
 * gtk_text_iter_get_line:
 * @iter: an iterator
622
 *
623 624 625
 * Returns the line number containing the iterator. Lines in
 * a #GtkTextBuffer are numbered beginning with 0 for the first
 * line in the buffer.
626
 *
627 628
 * Return value: a line number
 **/
629
gint
630
gtk_text_iter_get_line (const GtkTextIter *iter)
631 632 633
{
  GtkTextRealIter *real;

634 635 636
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
637 638 639 640 641 642

  if (real == NULL)
    return 0;

  if (real->cached_line_number < 0)
    real->cached_line_number =
643
      _gtk_text_line_get_number (real->line);
644 645

  check_invariants (iter);
646 647 648 649

  return real->cached_line_number;
}

650 651 652
/**
 * gtk_text_iter_get_line_offset:
 * @iter: an iterator
653
 *
654 655 656
 * 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.
657
 *
658 659
 * Return value: offset from start of line
 **/
660
gint
661
gtk_text_iter_get_line_offset (const GtkTextIter *iter)
662 663 664
{
  GtkTextRealIter *real;

665 666 667
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
668 669 670 671

  if (real == NULL)
    return 0;

672 673 674
  ensure_char_offsets (real);

  check_invariants (iter);
675 676 677 678

  return real->line_char_offset;
}

679 680 681
/**
 * gtk_text_iter_get_line_index:
 * @iter: an iterator
682
 *
683 684 685 686 687
 * 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.
688
 *
689 690
 * Return value: distance from start of line, in bytes
 **/
691
gint
692
gtk_text_iter_get_line_index (const GtkTextIter *iter)
693 694
{
  GtkTextRealIter *real;
695
  
696 697 698
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_surreal (iter);
699 700 701 702

  if (real == NULL)
    return 0;

703 704 705
  ensure_byte_offsets (real);

  check_invariants (iter);
706 707 708 709

  return real->line_byte_offset;
}

710 711 712 713 714 715 716 717 718 719 720
/**
 * 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 
 **/
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
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);
739
  
740 741
  vis_offset = real->line_char_offset;

742 743
  g_assert (vis_offset >= 0);
  
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
  _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;
}

774 775 776 777 778 779 780 781 782 783 784 785

/**
 * 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
 **/
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
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;

801
  ensure_byte_offsets (real);
802 803 804 805 806

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

807 808
  g_assert (vis_offset >= 0);
  
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
  _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;
}

839 840 841 842
/*
 * Dereferencing
 */

843 844 845
/**
 * gtk_text_iter_get_char:
 * @iter: an iterator
846
 *
847
 * Returns the Unicode character at this iterator.  (Equivalent to
848
 * operator* on a C++ iterator.)  If the element at this iterator is a
849
 * non-character element, such as an image embedded in the buffer, the
850
 * Unicode "unknown" character 0xFFFC is returned. If invoked on
851
 * the end iterator, zero is returned; zero is not a valid Unicode character.
852
 * So you can write a loop which ends when gtk_text_iter_get_char ()
853
 * returns 0.
854
 *
855
 * Return value: a Unicode character, or 0 if @iter is not dereferenceable
856
 **/
857
gunichar
858
gtk_text_iter_get_char (const GtkTextIter *iter)
859 860 861
{
  GtkTextRealIter *real;

862 863 864
  g_return_val_if_fail (iter != NULL, 0);

  real = gtk_text_iter_make_real (iter);
865 866 867 868

  if (real == NULL)
    return 0;

869
  check_invariants (iter);
870

871
  if (gtk_text_iter_is_end (iter))
872 873
    return 0;
  else if (real->segment->type == &gtk_text_char_type)
874
    {
875
      ensure_byte_offsets (real);
876
      
877 878
      return g_utf8_get_char (real->segment->body.chars +
                              real->segment_byte_offset);
879 880 881
    }
  else
    {
882 883
      /* Unicode "unknown character" 0xFFFC */
      return GTK_TEXT_UNKNOWN_CHAR;
884 885 886
    }
}

887 888 889 890
/**
 * gtk_text_iter_get_slice:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
891
 *
892 893
 * Returns the text in the given range. A "slice" is an array of
 * characters encoded in UTF-8 format, including the Unicode "unknown"
894
 * character 0xFFFC for iterable non-character elements in the buffer,
895 896
 * such as images.  Because images are encoded in the slice, byte and
 * character offsets in the returned array will correspond to byte
897
 * offsets in the text buffer. Note that 0xFFFC can occur in normal
898 899
 * text as well, so it is not a reliable indicator that a pixbuf or
 * widget is in the buffer.
900
 *
901 902
 * Return value: slice of text from the buffer
 **/
903 904
gchar*
gtk_text_iter_get_slice       (const GtkTextIter *start,
905
                               const GtkTextIter *end)
906
{
907 908 909 910 911
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
912

913
  return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
914 915
}

916 917 918 919
/**
 * gtk_text_iter_get_text:
 * @start: iterator at start of a range
 * @end: iterator at end of a range
920
 *
921 922 923 924
 * 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
925 926
 * gtk_text_iter_get_slice ().
 *
927 928
 * Return value: array of characters from the buffer
 **/
929 930
gchar*
gtk_text_iter_get_text       (const GtkTextIter *start,
931
                              const GtkTextIter *end)
932
{
933 934 935 936 937
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);
938

939
  return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
940 941
}

942 943 944 945
/**
 * gtk_text_iter_get_visible_slice:
 * @start: iterator at start of range
 * @end: iterator at end of range
946 947
 *
 * Like gtk_text_iter_get_slice (), but invisible text is not included.
948 949
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
950
 *
951 952
 * Return value: slice of text from the buffer
 **/
953 954
gchar*
gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
955
                                 const GtkTextIter  *end)
956
{
957 958
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);
959

960 961 962
  check_invariants (start);
  check_invariants (end);

963
  return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
964 965
}

966 967 968 969
/**
 * gtk_text_iter_get_visible_text:
 * @start: iterator at start of range
 * @end: iterator at end of range
970 971
 *
 * Like gtk_text_iter_get_text (), but invisible text is not included.
972 973
 * Invisible text is usually invisible because a #GtkTextTag with the
 * "invisible" attribute turned on has been applied to it.
974
 *
975 976
 * Return value: string containing visible text in the range
 **/
977 978
gchar*
gtk_text_iter_get_visible_text (const GtkTextIter  *start,
979
                                const GtkTextIter  *end)
980
{
981 982 983 984 985 986
  g_return_val_if_fail (start != NULL, NULL);
  g_return_val_if_fail (end != NULL, NULL);

  check_invariants (start);
  check_invariants (end);

987
  return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
988 989
}

990
/**
Havoc Pennington's avatar
Havoc Pennington committed
991
 * gtk_text_iter_get_pixbuf:
992
 * @iter: an iterator
993
 *
994 995
 * If the element at @iter is a pixbuf, the pixbuf is returned
 * (with no new reference count added). Otherwise,
996
 * %NULL is returned.
997
 *
998
 * Return value: (transfer none): the pixbuf at @iter
999
 **/
Havoc Pennington's avatar
Havoc Pennington committed
1000 1001
GdkPixbuf*
gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1002 1003 1004
{
  GtkTextRealIter *real;

1005
  g_return_val_if_fail (iter != NULL, NULL);
1006 1007

  real = gtk_text_iter_make_real (iter);
1008 1009

  if (real == NULL)
1010
    return NULL;
1011 1012 1013

  check_invariants (iter);

Havoc Pennington's avatar
Havoc Pennington committed
1014
  if (real->segment->type != &gtk_text_pixbuf_type)
1015
    return NULL;
1016
  else
Havoc Pennington's avatar
Havoc Pennington committed
1017
    return real->segment->body.pixbuf.pixbuf;
1018 1019
}

1020 1021 1022 1023
/**
 * gtk_text_iter_get_child_anchor:
 * @iter: an iterator
 *
1024
 * If the location at @iter contains a child anchor, the
1025
 * anchor is returned (with no new reference count added). Otherwise,
1026
 * %NULL is returned.
1027
 *
1028
 * Return value: (transfer none): the anchor at @iter
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
 **/
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;
}

1050 1051 1052
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
1053
 *
1054 1055 1056 1057 1058
 * 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.
1059
 *
1060
 * Return value: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1061
 **/
1062 1063 1064 1065 1066 1067
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1068 1069 1070 1071

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1072 1073 1074 1075

  if (real == NULL)
    return NULL;

1076 1077
  check_invariants (iter);

1078 1079 1080 1081 1082 1083
  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)
1084
        retval = g_slist_prepend (retval, seg->body.mark.obj);
1085

1086 1087 1088 1089 1090 1091 1092 1093
      seg = seg->next;
    }

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

1094 1095 1096
/**
 * gtk_text_iter_get_toggled_tags:
 * @iter: an iterator
1097
 * @toggled_on: %TRUE to get toggled-on tags
1098
 *
1099
 * Returns a list of #GtkTextTag that are toggled on or off at this
1100
 * point.  (If @toggled_on is %TRUE, the list contains tags that are
1101 1102 1103 1104
 * 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.
1105
 *
1106
 * Return value: (element-type GtkTextTag) (transfer container): tags toggled at this point
1107
 **/
1108 1109
GSList*
gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
1110
                                 gboolean            toggled_on)
1111 1112 1113 1114
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1115 1116 1117 1118

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1119 1120 1121 1122

  if (real == NULL)
    return NULL;

1123 1124
  check_invariants (iter);

1125 1126 1127 1128 1129 1130 1131 1132
  retval = NULL;
  seg = real->any_segment;
  while (seg != real->segment)
    {
      if (toggled_on)
        {
          if (seg->type == &gtk_text_toggle_on_type)
            {
1133
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1134 1135 1136 1137 1138 1139
            }
        }
      else
        {
          if (seg->type == &gtk_text_toggle_off_type)
            {
1140
              retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1141 1142
            }
        }
1143

1144 1145 1146 1147 1148 1149 1150 1151
      seg = seg->next;
    }

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

1152 1153 1154
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
1155
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1156
 *
1157 1158 1159
 * 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
1160
 * <emphasis>start</emphasis> of the tagged range;
1161
 * gtk_text_iter_has_tag () tells you whether an iterator is
1162
 * <emphasis>within</emphasis> a tagged range.
1163
 *
1164 1165
 * Return value: whether @iter is the start of a range tagged with @tag
 **/
1166 1167
gboolean
gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1168
                             GtkTextTag         *tag)
1169 1170 1171
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1172 1173 1174 1175

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1176 1177 1178 1179

  if (real == NULL)
    return FALSE;

1180 1181
  check_invariants (iter);

1182 1183 1184 1185 1186 1187 1188 1189 1190
  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;
        }
1191

1192 1193 1194 1195 1196 1197
      seg = seg->next;
    }

  return FALSE;
}

1198 1199 1200
/**
 * gtk_text_iter_ends_tag:
 * @iter: an iterator
1201
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1202
 *
1203 1204 1205
 * 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
1206
 * <emphasis>end</emphasis> of the tagged range;
1207
 * gtk_text_iter_has_tag () tells you whether an iterator is
1208
 * <emphasis>within</emphasis> a tagged range.
1209
 *
1210
 * Return value: whether @iter is the end of a range tagged with @tag
1211
 *
1212
 **/
1213 1214
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1215
                          GtkTextTag         *tag)
1216 1217 1218
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1219 1220 1221 1222

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1223 1224 1225 1226

  if (real == NULL)
    return FALSE;

1227 1228
  check_invariants (iter);

1229 1230 1231 1232 1233 1234 1235 1236 1237
  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;
        }
1238

1239 1240 1241 1242 1243 1244
      seg = seg->next;
    }

  return FALSE;
}

1245 1246 1247
/**
 * gtk_text_iter_toggles_tag:
 * @iter: an iterator
1248
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1249 1250 1251
 *
 * This is equivalent to (gtk_text_iter_begins_tag () ||
 * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1252
 * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1253
 *
1254 1255
 * Return value: whether @tag is toggled on or off at @iter
 **/
1256
gboolean
1257 1258
gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
                           GtkTextTag         *tag)
1259 1260 1261
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1262 1263 1264 1265

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1266 1267 1268 1269

  if (real == NULL)
    return FALSE;

1270 1271
  check_invariants (iter);

1272 1273 1274 1275 1276 1277 1278 1279
  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;
1280

1281 1282 1283 1284 1285 1286
      seg = seg->next;
    }

  return FALSE;
}

1287 1288 1289 1290
/**
 * gtk_text_iter_has_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag
1291
 *
1292
 * Returns %TRUE if @iter is within a range tagged with @tag.
1293
 *
1294 1295
 * Return value: whether @iter is tagged with @tag
 **/
1296
gboolean
1297 1298
gtk_text_iter_has_tag (const GtkTextIter   *iter,
                       GtkTextTag          *tag)
1299 1300
{
  GtkTextRealIter *real;
1301 1302 1303 1304 1305

  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);
1306 1307

  if (real == NULL)
1308 1309 1310
    return FALSE;

  check_invariants (iter);
1311 1312 1313

  if (real->line_byte_offset >= 0)
    {
1314
      return _gtk_text_line_byte_has_tag (real->line, real->tree,
1315
                                          real->line_byte_offset, tag);
1316 1317 1318
    }
  else
    {
1319
      g_assert (real->line_char_offset >= 0);
1320
      return _gtk_text_line_char_has_tag (real->line, real->tree,
1321
                                          real->line_char_offset, tag);
1322 1323 1324
    }
}

1325 1326 1327 1328 1329 1330 1331 1332
/**
 * 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.
1333 1334
 *
 * Return value: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
 **/
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 */
1347
  tags = _gtk_text_btree_get_tags (iter, &tag_count);
1348 1349 1350 1351

  /* No tags, use default style */
  if (tags == NULL || tag_count == 0)
    {
1352
      g_free (tags);
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370

      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);
}

1371 1372 1373
/**
 * gtk_text_iter_editable:
 * @iter: an iterator
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
 * @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.
 * 
1389 1390
 * Return value: whether @iter is inside an editable range
 **/
1391 1392 1393 1394
gboolean
gtk_text_iter_editable (const GtkTextIter *iter,
                        gboolean           default_setting)
{
1395
  GtkTextAttributes *values;
1396
  gboolean retval;
1397

1398 1399
  g_return_val_if_fail (iter != NULL, FALSE);
  
1400
  values = gtk_text_attributes_new ();
1401 1402 1403

  values->editable = default_setting;

1404
  gtk_text_iter_get_attributes (iter, values);
1405 1406

  retval = values->editable;
1407

1408
  gtk_text_attributes_unref (values);
1409 1410 1411 1412

  return retval;
}

1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
/**
 * 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);
    }
}


1453 1454 1455
/**
 * gtk_text_iter_get_language:
 * @iter: an iterator
1456 1457
 *
 * A convenience wrapper around gtk_text_iter_get_attributes (),
1458
 * which returns the language in effect at @iter. If no tags affecting
1459
 * language apply to @iter, the return value is identical to that of
1460 1461
 * gtk_get_default_language ().
 *
1462 1463
 * Return value: language in effect at @iter
 **/
1464
PangoLanguage *
1465