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

/**
 * SECTION:gtktextiter
 * @Short_description: Text buffer iterator
 * @Title: GtkTextIter
 *
41 42 43
 * You may wish to begin by reading the
 * [text widget conceptual overview][TextWidget]
 * which gives an overview of all the objects and data
44 45 46 47
 * types related to the text widget and how they work together.
 */


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

50 51
typedef struct _GtkTextRealIter GtkTextRealIter;

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

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

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

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

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

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

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

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

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

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

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

203 204 205 206
  return iter;
}

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

  iter = gtk_text_iter_make_surreal (_iter);

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

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

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

236 237 238 239
  return iter;
}

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

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

  iter->tree = tree;

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

253 254 255 256
  return iter;
}

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_segment (real, line, segment);

270 271 272 273
  return real;
}

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_byte_offset (real, line, line_byte_offset);

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

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

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

  real = iter_init_common (iter, tree);

  iter_set_from_char_offset (real, line, line_char_offset);

311 312 313 314
  return real;
}

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

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

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

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

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

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

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

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

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

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

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

  real = gtk_text_iter_make_surreal (iter);
395 396 397 398

  if (real == NULL)
    return NULL;

399 400
  check_invariants (iter);

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

404 405 406
/**
 * gtk_text_iter_copy:
 * @iter: an iterator
407
 *
408
 * Creates a dynamically-allocated copy of an iterator. This function
409
 * is not useful in applications, because iterators can be copied with a
410
 * simple assignment (`GtkTextIter i = j;`). The
411
 * function is used by language bindings.
412
 *
413
 * Returns: a copy of the @iter, free with gtk_text_iter_free ()
414
 **/
415
GtkTextIter*
416
gtk_text_iter_copy (const GtkTextIter *iter)
417 418 419
{
  GtkTextIter *new_iter;

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

422
  new_iter = g_slice_new (GtkTextIter);
423 424

  *new_iter = *iter;
425

426 427 428
  return new_iter;
}

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

443
  g_slice_free (GtkTextIter, iter);
444 445
}

446 447 448 449 450 451 452
/**
 * 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
453
 * with `GtkTextIter i = j;`. The
454 455 456 457 458 459 460 461 462 463 464 465 466 467
 * 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;
}

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

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

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

  real = gtk_text_iter_make_real (iter);
480 481 482 483

  if (real == NULL)
    return NULL;

484 485 486 487
  check_invariants (iter);

  g_assert (real->segment != NULL);

488 489 490 491
  return real->segment;
}

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

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

  real = gtk_text_iter_make_real (iter);
499 500 501 502

  if (real == NULL)
    return NULL;

503 504 505 506
  check_invariants (iter);

  g_assert (real->any_segment != NULL);

507 508 509 510
  return real->any_segment;
}

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

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

  real = gtk_text_iter_make_real (iter);
518 519 520 521

  if (real == NULL)
    return 0;

522 523 524
  ensure_byte_offsets (real);

  check_invariants (iter);
525 526 527 528 529

  return real->segment_byte_offset;
}

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

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

  real = gtk_text_iter_make_real (iter);
537 538 539 540

  if (real == NULL)
    return 0;

541 542 543
  ensure_char_offsets (real);

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

  return real->segment_char_offset;
}

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

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

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

  return real->line;
}

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

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

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

  return real->tree;
}

/*
 * Conversions
 */

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

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

  real = gtk_text_iter_make_surreal (iter);
600 601 602 603

  if (real == NULL)
    return 0;

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

615 616
  check_invariants (iter);

617 618 619
  return real->cached_char_index;
}

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

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

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

  if (real == NULL)
    return 0;

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

  check_invariants (iter);
647 648 649 650

  return real->cached_line_number;
}

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

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

  real = gtk_text_iter_make_surreal (iter);
669 670 671 672

  if (real == NULL)
    return 0;

673 674 675
  ensure_char_offsets (real);

  check_invariants (iter);
676 677 678 679

  return real->line_char_offset;
}

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

  real = gtk_text_iter_make_surreal (iter);
700 701 702 703

  if (real == NULL)
    return 0;

704 705 706
  ensure_byte_offsets (real);

  check_invariants (iter);
707 708 709 710

  return real->line_byte_offset;
}

711 712 713 714 715 716
/**
 * 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
717
 * are invisible due to tags with the “invisible” flag
718 719
 * toggled on.
 * 
720
 * Returns: 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 739
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);
740
  
741 742
  vis_offset = real->line_char_offset;

743 744
  g_assert (vis_offset >= 0);
  
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 774
  _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;
}

775 776 777 778 779 780 781

/**
 * 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
782
 * are invisible due to tags with the “invisible” flag
783 784
 * toggled on.
 * 
785
 * Returns: 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 801
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;

802
  ensure_byte_offsets (real);
803 804 805 806 807

  check_invariants (iter);

  vis_offset = real->line_byte_offset;

808 809
  g_assert (vis_offset >= 0);
  
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 839
  _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;
}

840 841 842 843
/*
 * Dereferencing
 */

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

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

  real = gtk_text_iter_make_real (iter);
866 867 868 869

  if (real == NULL)
    return 0;

870
  check_invariants (iter);
871

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

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

  check_invariants (start);
  check_invariants (end);
913

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

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

  check_invariants (start);
  check_invariants (end);
939

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

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

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

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

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

  check_invariants (start);
  check_invariants (end);

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

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

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

  real = gtk_text_iter_make_real (iter);
1009 1010

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

  check_invariants (iter);

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

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

1051 1052 1053
/**
 * gtk_text_iter_get_marks:
 * @iter: an iterator
1054
 *
1055
 * Returns a list of all #GtkTextMark at this location. Because marks
1056
 * are not iterable (they don’t take up any "space" in the buffer,
1057 1058 1059
 * 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.
1060
 *
1061
 * Returns: (element-type GtkTextMark) (transfer container): list of #GtkTextMark
1062
 **/
1063 1064 1065 1066 1067 1068
GSList*
gtk_text_iter_get_marks (const GtkTextIter *iter)
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
  GSList *retval;
1069 1070 1071 1072

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1073 1074 1075 1076

  if (real == NULL)
    return NULL;

1077 1078
  check_invariants (iter);

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

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

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

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

  g_return_val_if_fail (iter != NULL, NULL);

  real = gtk_text_iter_make_real (iter);
1120 1121 1122 1123

  if (real == NULL)
    return NULL;

1124 1125
  check_invariants (iter);

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

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

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

1153 1154 1155
/**
 * gtk_text_iter_begins_tag:
 * @iter: an iterator
1156
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1157
 *
1158
 * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1159 1160 1161 1162
 * is %NULL, returns %TRUE if any tag is toggled on at this point.
 *
 * Note that if gtk_text_iter_begins_tag() returns %TRUE, it means that @iter is
 * at the beginning of the tagged range, and that the
1163
 * character at @iter is inside the tagged range. In other
1164 1165 1166
 * words, unlike gtk_text_iter_ends_tag(), if gtk_text_iter_begins_tag() returns
 * %TRUE, gtk_text_iter_has_tag() will also return %TRUE for the same
 * parameters.
1167
 *
1168
 * Returns: whether @iter is the start of a range tagged with @tag
1169
 **/
1170 1171
gboolean
gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1172
                             GtkTextTag         *tag)
1173 1174 1175
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1176 1177 1178 1179

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1180 1181 1182 1183

  if (real == NULL)
    return FALSE;

1184 1185
  check_invariants (iter);

1186 1187 1188 1189 1190 1191 1192 1193 1194
  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;
        }
1195

1196 1197 1198 1199 1200 1201
      seg = seg->next;
    }

  return FALSE;
}

1202 1203 1204
/**
 * gtk_text_iter_ends_tag:
 * @iter: an iterator
1205
 * @tag: (allow-none): a #GtkTextTag, or %NULL
1206
 *
1207
 * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1208
 * is %NULL, returns %TRUE if any tag is toggled off at this point.
1209
 *
1210
 * Note that if gtk_text_iter_ends_tag() returns %TRUE, it means that @iter is
1211 1212
 * at the end of the tagged range, but that the character
 * at @iter is outside the tagged range. In other words,
1213 1214
 * unlike gtk_text_iter_begins_tag(), if gtk_text_iter_ends_tag() returns %TRUE,
 * gtk_text_iter_has_tag() will return %FALSE for the same parameters.
1215
 *
1216
 * Returns: whether @iter is the end of a range tagged with @tag
1217
 **/
1218 1219
gboolean
gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1220
                          GtkTextTag         *tag)
1221 1222 1223
{
  GtkTextRealIter *real;
  GtkTextLineSegment *seg;
1224 1225 1226 1227

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1228 1229 1230 1231

  if (real == NULL)
    return FALSE;

1232 1233
  check_invariants (iter);

1234 1235 1236 1237 1238 1239 1240 1241 1242
  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;
        }
1243

1244 1245 1246 1247 1248 1249
      seg = seg->next;
    }

  return FALSE;
}

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

  g_return_val_if_fail (iter != NULL, FALSE);

  real = gtk_text_iter_make_real (iter);
1271 1272 1273 1274

  if (real == NULL)
    return FALSE;

1275 1276
  check_invariants (iter);

1277 1278 1279 1280 1281 1282 1283 1284
  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;
1285

1286 1287 1288 1289 1290 1291
      seg = seg->next;
    }

  return FALSE;
}

1292 1293 1294 1295
/**
 * gtk_text_iter_has_tag:
 * @iter: an iterator
 * @tag: a #GtkTextTag
1296
 *
1297 1298
 * Returns %TRUE if @iter points to a character that is part of a range tagged
 * with @tag. See also gtk_text_iter_begins_tag() and gtk_text_iter_ends_tag().
1299
 *
1300
 * Returns: whether @iter is tagged with @tag
1301
 **/
1302
gboolean
1303 1304
gtk_text_iter_has_tag (const GtkTextIter   *iter,
                       GtkTextTag          *tag)
1305 1306
{
  GtkTextRealIter *real;
1307 1308 1309 1310 1311

  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);
1312 1313

  if (real == NULL)
1314 1315 1316
    return FALSE;

  check_invariants (iter);
1317 1318 1319

  if (real->line_byte_offset >= 0)
    {
1320
      return _gtk_text_line_byte_has_tag (real->line, real->tree,
1321
                                          real->line_byte_offset, tag);
1322 1323 1324
    }
  else
    {
1325
      g_assert (real->line_char_offset >= 0);
1326
      return _gtk_text_line_char_has_tag (real->line, real->tree,
1327
                                          real->line_char_offset, tag);
1328 1329 1330
    }
}

1331 1332 1333 1334 1335 1336
/**
 * 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
1337
 * list don’t have a reference added, but you have to free the list
1338
 * itself.
1339
 *
1340
 * Returns: (element-type GtkTextTag) (transfer container): list of #GtkTextTag
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
 **/
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 */
1353
  tags = _gtk_text_btree_get_tags (iter, &tag_count);
1354 1355 1356 1357

  /* No tags, use default style */
  if (tags == NULL || tag_count == 0)
    {
1358
      g_free (tags);
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376

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

1377 1378 1379
/**
 * gtk_text_iter_editable:
 * @iter: an iterator
1380 1381 1382
 * @default_setting: %TRUE if text is editable by default
 *
 * Returns whether the character at @iter is within an editable region
1383
 * of text.  Non-editable text is “locked” and can’t be changed by the
1384 1385 1386 1387
 * 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.
 *
1388 1389
 * 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
1390 1391 1392 1393 1394
 * 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.
 * 
1395
 * Returns: whether @iter is inside an editable range