1 /* GTK - The GIMP Toolkit
2 * gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtkclipboard.h"
31 #include "gtkinvisible.h"
32 #include "gtksignal.h"
33 #include "gtktextbuffer.h"
34 #include "gtktextbtree.h"
35 #include "gtktextiterprivate.h"
38 typedef struct _ClipboardRequest ClipboardRequest;
40 struct _ClipboardRequest
42 GtkTextBuffer *buffer;
44 gboolean default_editable;
45 gboolean is_clipboard;
46 gboolean replace_selection;
71 TARGET_TEXT_BUFFER_CONTENTS
74 static void gtk_text_buffer_init (GtkTextBuffer *tkxt_buffer);
75 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
76 static void gtk_text_buffer_finalize (GObject *object);
79 static void gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer);
80 static void gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
84 gboolean interactive);
85 static void gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
88 gboolean interactive);
89 static void gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
91 const GtkTextIter *start_char,
92 const GtkTextIter *end_char);
93 static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
95 const GtkTextIter *start_char,
96 const GtkTextIter *end_char);
97 static void gtk_text_buffer_real_changed (GtkTextBuffer *buffer);
99 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
100 static void free_log_attr_cache (GtkTextLogAttrCache *cache);
102 static GtkObjectClass *parent_class = NULL;
103 static guint signals[LAST_SIGNAL] = { 0 };
106 gtk_text_buffer_get_type (void)
108 static GtkType our_type = 0;
112 static const GtkTypeInfo our_info =
115 sizeof (GtkTextBuffer),
116 sizeof (GtkTextBufferClass),
117 (GtkClassInitFunc) gtk_text_buffer_class_init,
118 (GtkObjectInitFunc) gtk_text_buffer_init,
119 /* reserved_1 */ NULL,
120 /* reserved_2 */ NULL,
121 (GtkClassInitFunc) NULL
124 our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
131 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
133 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
134 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
136 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
138 gobject_class->finalize = gtk_text_buffer_finalize;
140 klass->insert_text = gtk_text_buffer_real_insert_text;
141 klass->delete_text = gtk_text_buffer_real_delete_text;
142 klass->apply_tag = gtk_text_buffer_real_apply_tag;
143 klass->remove_tag = gtk_text_buffer_real_remove_tag;
144 klass->changed = gtk_text_buffer_real_changed;
146 signals[INSERT_TEXT] =
147 gtk_signal_new ("insert_text",
149 GTK_CLASS_TYPE (object_class),
150 GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
151 gtk_marshal_VOID__BOXED_STRING_INT_BOOLEAN,
164 signals[DELETE_TEXT] =
165 gtk_signal_new ("delete_text",
167 GTK_CLASS_TYPE (object_class),
168 GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
169 gtk_marshal_VOID__BOXED_BOXED_BOOLEAN,
182 gtk_signal_new ("changed",
184 GTK_CLASS_TYPE (object_class),
185 GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
186 gtk_marshal_VOID__VOID,
190 signals[MODIFIED_CHANGED] =
191 gtk_signal_new ("modified_changed",
193 GTK_CLASS_TYPE (object_class),
194 GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
195 gtk_marshal_VOID__VOID,
200 gtk_signal_new ("mark_set",
202 GTK_CLASS_TYPE (object_class),
203 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
204 gtk_marshal_VOID__BOXED_OBJECT,
210 signals[MARK_DELETED] =
211 gtk_signal_new ("mark_deleted",
213 GTK_CLASS_TYPE (object_class),
214 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
215 gtk_marshal_VOID__OBJECT,
221 gtk_signal_new ("apply_tag",
223 GTK_CLASS_TYPE (object_class),
224 GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
225 gtk_marshal_VOID__OBJECT_BOXED_BOXED,
232 signals[REMOVE_TAG] =
233 gtk_signal_new ("remove_tag",
235 GTK_CLASS_TYPE (object_class),
236 GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
237 gtk_marshal_VOID__OBJECT_BOXED_BOXED,
246 gtk_text_buffer_init (GtkTextBuffer *buffer)
248 buffer->clipboard_contents = NULL;
252 * gtk_text_buffer_new:
253 * @table: a tag table, or NULL to create a new one
255 * Creates a new text buffer.
257 * Return value: a new text buffer
260 gtk_text_buffer_new (GtkTextTagTable *table)
262 GtkTextBuffer *text_buffer;
264 text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
268 text_buffer->tag_table = table;
270 gtk_object_ref (GTK_OBJECT (text_buffer->tag_table));
271 gtk_object_sink (GTK_OBJECT (text_buffer->tag_table));
274 gtk_object_ref (GTK_OBJECT (text_buffer));
275 gtk_object_sink (GTK_OBJECT (text_buffer));
281 gtk_text_buffer_finalize (GObject *object)
283 GtkTextBuffer *buffer;
285 buffer = GTK_TEXT_BUFFER (object);
287 if (buffer->clipboard_contents)
289 g_object_unref (G_OBJECT (buffer->clipboard_contents));
290 buffer->clipboard_contents = NULL;
293 if (buffer->tag_table)
295 gtk_object_unref (GTK_OBJECT (buffer->tag_table));
296 buffer->tag_table = NULL;
301 _gtk_text_btree_unref (buffer->btree);
302 buffer->btree = NULL;
305 if (buffer->log_attr_cache)
306 free_log_attr_cache (buffer->log_attr_cache);
308 buffer->log_attr_cache = NULL;
310 G_OBJECT_CLASS (parent_class)->finalize (object);
313 static GtkTextTagTable*
314 get_table (GtkTextBuffer *buffer)
316 if (buffer->tag_table == NULL)
318 buffer->tag_table = gtk_text_tag_table_new ();
320 gtk_object_ref (GTK_OBJECT (buffer->tag_table));
321 gtk_object_sink (GTK_OBJECT (buffer->tag_table));
324 return buffer->tag_table;
328 get_btree (GtkTextBuffer *buffer)
330 if (buffer->btree == NULL)
331 buffer->btree = _gtk_text_btree_new (gtk_text_buffer_get_tag_table (buffer),
334 return buffer->btree;
338 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
340 return get_btree (buffer);
344 * gtk_text_buffer_get_tag_table:
345 * @buffer: a #GtkTextBuffer
347 * Get the #GtkTextTagTable associated with this buffer.
349 * Return value: the buffer's tag table
352 gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer)
354 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
356 return get_table (buffer);
360 * gtk_text_buffer_set_text:
361 * @buffer: a #GtkTextBuffer
362 * @text: UTF-8 text to insert
363 * @len: length of @text in bytes
365 * Deletes current contents of @buffer, and inserts @text instead. If
366 * @text doesn't end with a newline, a newline is added;
367 * #GtkTextBuffer contents must always end with a newline. If @text
368 * ends with a newline, the new buffer contents will be exactly
369 * @text. If @len is -1, @text must be nul-terminated.
372 gtk_text_buffer_set_text (GtkTextBuffer *buffer,
376 GtkTextIter start, end;
378 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
379 g_return_if_fail (text != NULL);
384 /* Chop newline, since the buffer will already have one
387 if (len > 0 && text[len-1] == '\n')
390 gtk_text_buffer_get_bounds (buffer, &start, &end);
392 gtk_text_buffer_delete (buffer, &start, &end);
396 gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
397 gtk_text_buffer_insert (buffer, &start, text, len);
407 gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
411 gboolean interactive)
413 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
414 g_return_if_fail (iter != NULL);
416 _gtk_text_btree_insert (iter, text, len);
418 gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
422 gtk_text_buffer_emit_insert (GtkTextBuffer *buffer,
426 gboolean interactive)
428 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
429 g_return_if_fail (iter != NULL);
430 g_return_if_fail (text != NULL);
435 g_assert (g_utf8_validate (text, len, NULL));
439 gtk_signal_emit (GTK_OBJECT (buffer), signals[INSERT_TEXT],
440 iter, text, len, interactive);
445 * gtk_text_buffer_insert:
446 * @buffer: a #GtkTextBuffer
447 * @iter: a position in the buffer
448 * @text: UTF-8 format text to insert
449 * @len: length of text in bytes, or -1
451 * Inserts @len bytes of @text at position @iter. If @len is -1,
452 * @text must be nul-terminated and will be inserted in its
453 * entirety. Emits the "insert_text" signal; insertion actually occurs
454 * in the default handler for the signal. @iter is invalidated when
455 * insertion occurs (because the buffer contents change), but the
456 * default signal handler revalidates it to point to the end of the
461 gtk_text_buffer_insert (GtkTextBuffer *buffer,
466 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
467 g_return_if_fail (iter != NULL);
468 g_return_if_fail (text != NULL);
470 gtk_text_buffer_emit_insert (buffer, iter, text, len, FALSE);
474 * gtk_text_buffer_insert_at_cursor:
475 * @buffer: a #GtkTextBuffer
476 * @text: some text in UTF-8 format
477 * @len: length of text, in bytes
479 * Simply calls gtk_text_buffer_insert (), using the current
480 * cursor position as the insertion point.
483 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
489 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
490 g_return_if_fail (text != NULL);
492 gtk_text_buffer_get_iter_at_mark (buffer, &iter,
493 gtk_text_buffer_get_mark (buffer,
496 gtk_text_buffer_insert (buffer, &iter, text, len);
500 * gtk_text_buffer_insert_interactive:
501 * @buffer: a #GtkTextBuffer
502 * @iter: a position in @buffer
503 * @text: some UTF-8 text
504 * @len: length of text in bytes, or -1
505 * @default_editable: default editability of buffer
507 * Like gtk_text_buffer_insert (), but the insertion will not occur if
508 * @iter is at a non-editable location in the buffer. Usually you
509 * want to prevent insertions at ineditable locations if the insertion
510 * results from a user action (is interactive).
512 * @default_editable indicates the editability of text that doesn't
513 * have a tag affecting editability applied to it. Typically the
514 * result of gtk_text_view_get_editable() is appropriate here.
516 * Return value: whether text was actually inserted
519 gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer,
523 gboolean default_editable)
525 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
526 g_return_val_if_fail (text != NULL, FALSE);
528 if (gtk_text_iter_editable (iter, default_editable))
530 gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
538 * gtk_text_buffer_insert_interactive_at_cursor:
539 * @buffer: a #GtkTextBuffer
540 * @text: text in UTF-8 format
541 * @len: length of text in bytes, or -1
542 * @default_editable: default editability of buffer
544 * Calls gtk_text_buffer_insert_interactive () at the cursor
547 * @default_editable indicates the editability of text that doesn't
548 * have a tag affecting editability applied to it. Typically the
549 * result of gtk_text_view_get_editable() is appropriate here.
551 * Return value: whether text was actually inserted
554 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
557 gboolean default_editable)
561 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
562 g_return_val_if_fail (text != NULL, FALSE);
564 gtk_text_buffer_get_iter_at_mark (buffer, &iter,
565 gtk_text_buffer_get_mark (buffer,
568 return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
573 possibly_not_text (gunichar ch,
576 return ch == GTK_TEXT_UNKNOWN_CHAR;
580 insert_text_range (GtkTextBuffer *buffer,
582 const GtkTextIter *orig_start,
583 const GtkTextIter *orig_end,
584 gboolean interactive)
588 text = gtk_text_iter_get_text (orig_start, orig_end);
590 gtk_text_buffer_emit_insert (buffer, iter, text, -1, interactive);
595 typedef struct _Range Range;
598 GtkTextBuffer *buffer;
599 GtkTextMark *start_mark;
600 GtkTextMark *end_mark;
601 GtkTextMark *whole_end_mark;
602 GtkTextIter *range_start;
603 GtkTextIter *range_end;
604 GtkTextIter *whole_end;
608 save_range (GtkTextIter *range_start,
609 GtkTextIter *range_end,
610 GtkTextIter *whole_end)
614 r = g_new (Range, 1);
616 r->buffer = gtk_text_iter_get_buffer (range_start);
617 g_object_ref (G_OBJECT (r->buffer));
620 gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
625 gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
631 gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (range_start),
636 r->range_start = range_start;
637 r->range_end = range_end;
638 r->whole_end = whole_end;
644 restore_range (Range *r)
646 gtk_text_buffer_get_iter_at_mark (r->buffer,
650 gtk_text_buffer_get_iter_at_mark (r->buffer,
654 gtk_text_buffer_get_iter_at_mark (r->buffer,
658 gtk_text_buffer_delete_mark (r->buffer, r->start_mark);
659 gtk_text_buffer_delete_mark (r->buffer, r->end_mark);
660 gtk_text_buffer_delete_mark (r->buffer, r->whole_end_mark);
662 g_object_unref (G_OBJECT (r->buffer));
667 insert_range_untagged (GtkTextBuffer *buffer,
669 const GtkTextIter *orig_start,
670 const GtkTextIter *orig_end,
671 gboolean interactive)
673 GtkTextIter range_start;
674 GtkTextIter range_end;
675 GtkTextIter start, end;
676 GtkTextBuffer *src_buffer;
679 if (gtk_text_iter_equal (orig_start, orig_end))
685 src_buffer = gtk_text_iter_get_buffer (&start);
692 if (gtk_text_iter_equal (&range_start, &range_end))
694 /* Figure out how to move forward */
696 g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
698 if (gtk_text_iter_equal (&range_end, &end))
700 /* nothing left to do */
703 else if (gtk_text_iter_get_char (&range_end) == GTK_TEXT_UNKNOWN_CHAR)
705 GdkPixbuf *pixbuf = NULL;
706 GtkTextChildAnchor *anchor = NULL;
707 pixbuf = gtk_text_iter_get_pixbuf (&range_end);
708 anchor = gtk_text_iter_get_child_anchor (&range_end);
712 r = save_range (&range_start,
716 gtk_text_buffer_insert_pixbuf (buffer,
723 gtk_text_iter_forward_char (&range_end);
725 range_start = range_end;
729 /* Just skip anchors */
731 gtk_text_iter_forward_char (&range_end);
732 range_start = range_end;
736 /* The GTK_TEXT_UNKNOWN_CHAR was in a text segment, so
739 gtk_text_iter_forward_find_char (&range_end,
740 possibly_not_text, NULL,
743 g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
748 /* Text segment starts here, so forward search to
749 * find its possible endpoint
751 gtk_text_iter_forward_find_char (&range_end,
752 possibly_not_text, NULL,
755 g_assert (gtk_text_iter_compare (&range_end, &end) <= 0);
760 r = save_range (&range_start,
764 insert_text_range (buffer,
773 range_start = range_end;
779 gtk_text_buffer_real_insert_range (GtkTextBuffer *buffer,
781 const GtkTextIter *orig_start,
782 const GtkTextIter *orig_end,
783 gboolean interactive)
785 /* Find each range of uniformly-tagged text, insert it,
786 * then apply the tags.
788 GtkTextIter start = *orig_start;
789 GtkTextIter end = *orig_end;
790 GtkTextIter range_start;
791 GtkTextIter range_end;
792 GtkTextBuffer *src_buffer;
795 if (gtk_text_iter_equal (orig_start, orig_end))
798 src_buffer = gtk_text_iter_get_buffer (orig_start);
800 gtk_text_iter_reorder (&start, &end);
808 GtkTextIter start_iter;
812 if (gtk_text_iter_equal (&range_start, &end))
813 break; /* All done */
815 g_assert (gtk_text_iter_compare (&range_start, &end) < 0);
817 gtk_text_iter_forward_to_tag_toggle (&range_end, NULL);
819 g_assert (!gtk_text_iter_equal (&range_start, &range_end));
821 /* Clamp to the end iterator */
822 if (gtk_text_iter_compare (&range_end, &end) > 0)
825 /* We have a range with unique tags; insert it, and
828 start_offset = gtk_text_iter_get_offset (iter);
830 r = save_range (&range_start, &range_end, &end);
832 insert_range_untagged (buffer, iter, &range_start, &range_end, interactive);
837 gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
839 tags = gtk_text_iter_get_tags (&range_start);
841 while (tmp_list != NULL)
843 gtk_text_buffer_apply_tag (buffer,
848 tmp_list = g_slist_next (tmp_list);
852 range_start = range_end;
857 * gtk_text_buffer_insert_range:
858 * @buffer: a #GtkTextBuffer
859 * @iter: a position in @buffer
860 * @start: a position in a #GtkTextBuffer
861 * @end: another position in the same buffer as @start
863 * Copies text, tags, and pixbufs between @start and @end (the order
864 * of @start and @end doesn't matter) and inserts the copy at @iter.
865 * Used instead of simply getting/inserting text because it preserves
866 * images and tags. If @start and @end are in a different buffer from
867 * @buffer, the two buffers must share the same tag table.
869 * Implemented via emissions of the insert_text and apply_tag signals,
873 gtk_text_buffer_insert_range (GtkTextBuffer *buffer,
875 const GtkTextIter *start,
876 const GtkTextIter *end)
878 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
879 g_return_if_fail (iter != NULL);
880 g_return_if_fail (start != NULL);
881 g_return_if_fail (end != NULL);
882 g_return_if_fail (gtk_text_iter_get_buffer (start) ==
883 gtk_text_iter_get_buffer (end));
884 g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
887 gtk_text_buffer_real_insert_range (buffer, iter, start, end, FALSE);
891 * gtk_text_buffer_insert_range_interactive:
892 * @buffer: a #GtkTextBuffer
893 * @iter: a position in @buffer
894 * @start: a position in a #GtkTextBuffer
895 * @end: another position in the same buffer as @start
896 * @default_editable: default editability of the buffer
898 * Same as gtk_text_buffer_insert_range(), but does nothing if the
899 * insertion point isn't editable. The @default_editable parameter
900 * indicates whether the text is editable at @iter if no tags
901 * enclosing @iter affect editability. Typically the result of
902 * gtk_text_view_get_editable() is appropriate here.
904 * Returns: whether an insertion was possible at @iter
907 gtk_text_buffer_insert_range_interactive (GtkTextBuffer *buffer,
909 const GtkTextIter *start,
910 const GtkTextIter *end,
911 gboolean default_editable)
913 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
914 g_return_val_if_fail (iter != NULL, FALSE);
915 g_return_val_if_fail (start != NULL, FALSE);
916 g_return_val_if_fail (end != NULL, FALSE);
917 g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
918 gtk_text_iter_get_buffer (end), FALSE);
919 g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table ==
920 buffer->tag_table, FALSE);
923 if (gtk_text_iter_editable (iter, default_editable))
925 gtk_text_buffer_real_insert_range (buffer, iter, start, end, TRUE);
933 * gtk_text_buffer_insert_with_tags:
934 * @buffer: a #GtkTextBuffer
935 * @iter: an iterator in @buffer
937 * @len: length of @text, or -1
938 * @first_tag: first tag to apply to @text
939 * @Varargs: NULL-terminated list of tags to apply
941 * Inserts @text into @buffer at @iter, applying the list of tags to
942 * the newly-inserted text. The last tag specified must be NULL to
943 * terminate the list. Equivalent to calling gtk_text_buffer_insert (),
944 * then gtk_text_buffer_apply_tag () on the inserted text;
945 * gtk_text_buffer_insert_with_tags () is just a convenience function.
948 gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
952 GtkTextTag *first_tag,
960 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
961 g_return_if_fail (iter != NULL);
962 g_return_if_fail (text != NULL);
964 start_offset = gtk_text_iter_get_offset (iter);
966 gtk_text_buffer_insert (buffer, iter, text, len);
968 if (first_tag == NULL)
971 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
973 va_start (args, first_tag);
977 gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
979 tag = va_arg (args, GtkTextTag*);
986 * gtk_text_buffer_insert_with_tags_by_name:
987 * @buffer: a #GtkTextBuffer
988 * @iter: position in @buffer
990 * @len: length of @text, or -1
991 * @first_tag_name: name of a tag to apply to @text
992 * @Varargs: more tag names
994 * Same as gtk_text_buffer_insert_with_tags (), but allows you
995 * to pass in tag names instead of tag objects.
998 gtk_text_buffer_insert_with_tags_by_name (GtkTextBuffer *buffer,
1002 const gchar *first_tag_name,
1008 const gchar *tag_name;
1010 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1011 g_return_if_fail (iter != NULL);
1012 g_return_if_fail (text != NULL);
1014 start_offset = gtk_text_iter_get_offset (iter);
1016 gtk_text_buffer_insert (buffer, iter, text, len);
1018 if (first_tag_name == NULL)
1021 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
1023 va_start (args, first_tag_name);
1024 tag_name = first_tag_name;
1029 tag = gtk_text_tag_table_lookup (buffer->tag_table,
1034 g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name);
1038 gtk_text_buffer_apply_tag (buffer, tag, &start, iter);
1040 tag_name = va_arg (args, const gchar*);
1052 gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
1055 gboolean interactive)
1057 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1058 g_return_if_fail (start != NULL);
1059 g_return_if_fail (end != NULL);
1061 _gtk_text_btree_delete (start, end);
1063 /* may have deleted the selection... */
1064 gtk_text_buffer_update_primary_selection (buffer);
1066 gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1070 gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
1073 gboolean interactive)
1075 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1076 g_return_if_fail (start != NULL);
1077 g_return_if_fail (end != NULL);
1079 if (gtk_text_iter_equal (start, end))
1082 gtk_text_iter_reorder (start, end);
1084 /* Somewhat annoyingly, if you try to delete the final newline
1085 * the BTree will put it back; which means you can't deduce the
1086 * final contents of the buffer purely by monitoring insert/delete
1087 * signals on the buffer. But if you delete the final newline, any
1088 * tags on the newline will go away, oddly. See comment in
1089 * gtktextbtree.c. This is all sort of annoying, but really hard
1092 gtk_signal_emit (GTK_OBJECT (buffer),
1093 signals[DELETE_TEXT],
1099 * gtk_text_buffer_delete:
1100 * @buffer: a #GtkTextBuffer
1101 * @start: a position in @buffer
1102 * @end: another position in @buffer
1104 * Deletes text between @start and @end. The order of @start and @end
1105 * is not actually relevant; gtk_text_buffer_delete () will reorder
1106 * them. This function actually emits the "delete_text" signal, and
1107 * the default handler of that signal deletes the text. Because the
1108 * buffer is modified, all outstanding iterators become invalid after
1109 * calling this function; however, the @start and @end will be
1110 * re-initialized to point to the location where text was deleted.
1112 * Note that the final newline in the buffer may not be deleted; a
1113 * #GtkTextBuffer always contains at least one newline. You can
1114 * safely include the final newline in the range [@start,@end) but it
1115 * won't be affected by the deletion.
1119 gtk_text_buffer_delete (GtkTextBuffer *buffer,
1123 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1124 g_return_if_fail (start != NULL);
1125 g_return_if_fail (end != NULL);
1127 gtk_text_buffer_emit_delete (buffer, start, end, FALSE);
1131 * gtk_text_buffer_delete_interactive:
1132 * @buffer: a #GtkTextBuffer
1133 * @start_iter: start of range to delete
1134 * @end_iter: end of range
1135 * @default_editable: whether the buffer is editable by default
1137 * Deletes all <emphasis>editable</emphasis> text in the given range.
1138 * Calls gtk_text_buffer_delete () for each editable sub-range of
1139 * [@start,@end). @start and @end are revalidated to point to
1140 * the location of the last deleted range, or left untouched if
1141 * no text was deleted.
1143 * Return value: whether some text was actually deleted
1146 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
1147 GtkTextIter *start_iter,
1148 GtkTextIter *end_iter,
1149 gboolean default_editable)
1151 GtkTextMark *end_mark;
1152 GtkTextMark *start_mark;
1154 gboolean current_state;
1155 gboolean deleted_stuff = FALSE;
1157 /* Delete all editable text in the range start_iter, end_iter */
1159 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1160 g_return_val_if_fail (start_iter != NULL, FALSE);
1161 g_return_val_if_fail (end_iter != NULL, FALSE);
1163 gtk_text_iter_reorder (start_iter, end_iter);
1165 start_mark = gtk_text_buffer_create_mark (buffer, NULL,
1167 end_mark = gtk_text_buffer_create_mark (buffer, NULL,
1171 current_state = gtk_text_iter_editable (&iter, default_editable);
1176 gboolean done = FALSE;
1179 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
1181 gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
1183 if (gtk_text_iter_compare (&iter, &end) >= 0)
1186 iter = end; /* clamp to the last boundary */
1189 new_state = gtk_text_iter_editable (&iter, default_editable);
1191 if (current_state == new_state)
1197 /* We're ending an editable region. Delete said region. */
1200 gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1202 gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1204 deleted_stuff = TRUE;
1206 /* revalidate user's iterators. */
1207 *start_iter = start;
1217 if (current_state && !new_state)
1219 /* End of an editable region. Delete it. */
1222 gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
1224 gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
1226 current_state = FALSE;
1227 deleted_stuff = TRUE;
1229 /* revalidate user's iterators. */
1230 *start_iter = start;
1235 /* We are at the start of an editable region. We won't be deleting
1236 * the previous region. Move start mark to start of this region.
1239 g_assert (!current_state && new_state);
1241 gtk_text_buffer_move_mark (buffer, start_mark,
1245 current_state = TRUE;
1253 gtk_text_buffer_delete_mark (buffer, start_mark);
1254 gtk_text_buffer_delete_mark (buffer, end_mark);
1256 return deleted_stuff;
1260 * Extracting textual buffer contents
1264 * gtk_text_buffer_get_text:
1265 * @buffer: a #GtkTextBuffer
1266 * @start: start of a range
1267 * @end: end of a range
1268 * @include_hidden_chars: whether to include invisible text
1270 * Returns the text in the range [@start,@end). Excludes undisplayed
1271 * text (text marked with tags that set the invisibility attribute) if
1272 * @include_hidden_chars is FALSE. Does not include characters
1273 * representing embedded images, so byte and character indexes into
1274 * the returned string do <emphasis>not</emphasis> correspond to byte
1275 * and character indexes into the buffer. Contrast with
1276 * gtk_text_buffer_get_slice ().
1278 * Return value: an allocated UTF-8 string
1281 gtk_text_buffer_get_text (GtkTextBuffer *buffer,
1282 const GtkTextIter *start,
1283 const GtkTextIter *end,
1284 gboolean include_hidden_chars)
1286 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1287 g_return_val_if_fail (start != NULL, NULL);
1288 g_return_val_if_fail (end != NULL, NULL);
1290 if (include_hidden_chars)
1291 return gtk_text_iter_get_text (start, end);
1293 return gtk_text_iter_get_visible_text (start, end);
1297 * gtk_text_buffer_get_slice:
1298 * @buffer: a #GtkTextBuffer
1299 * @start: start of a range
1300 * @end: end of a range
1301 * @include_hidden_chars: whether to include invisible text
1303 * Returns the text in the range [@start,@end). Excludes undisplayed
1304 * text (text marked with tags that set the invisibility attribute) if
1305 * @include_hidden_chars is FALSE. The returned string includes a
1306 * 0xFFFC character whenever the buffer contains
1307 * embedded images, so byte and character indexes into
1308 * the returned string <emphasis>do</emphasis> correspond to byte
1309 * and character indexes into the buffer. Contrast with
1310 * gtk_text_buffer_get_text (). Note that 0xFFFC can occur in normal
1311 * text as well, so it is not a reliable indicator that a pixbuf or
1312 * widget is in the buffer.
1314 * Return value: an allocated UTF-8 string
1317 gtk_text_buffer_get_slice (GtkTextBuffer *buffer,
1318 const GtkTextIter *start,
1319 const GtkTextIter *end,
1320 gboolean include_hidden_chars)
1322 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1323 g_return_val_if_fail (start != NULL, NULL);
1324 g_return_val_if_fail (end != NULL, NULL);
1326 if (include_hidden_chars)
1327 return gtk_text_iter_get_slice (start, end);
1329 return gtk_text_iter_get_visible_slice (start, end);
1337 gtk_text_buffer_insert_pixbuf (GtkTextBuffer *buffer,
1341 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1342 g_return_if_fail (iter != NULL);
1343 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1345 _gtk_text_btree_insert_pixbuf (iter, pixbuf);
1347 /* FIXME pixbuf-specific signal like insert_text */
1349 gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1357 gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
1360 GtkTextChildAnchor *anchor;
1362 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1363 g_return_val_if_fail (iter != NULL, NULL);
1365 anchor = _gtk_text_btree_create_child_anchor (iter);
1367 /* FIXME child-anchor-specific signal */
1369 gtk_signal_emit (GTK_OBJECT (buffer), signals[CHANGED]);
1380 gtk_text_buffer_mark_set (GtkTextBuffer *buffer,
1381 const GtkTextIter *location,
1384 /* IMO this should NOT work like insert_text and delete_text,
1385 where the real action happens in the default handler.
1387 The reason is that the default handler would be _required_,
1388 i.e. the whole widget would start breaking and segfaulting
1389 if the default handler didn't get run. So you can't really
1390 override the default handler or stop the emission; that is,
1391 this signal is purely for notification, and not to allow users
1392 to modify the default behavior. */
1394 g_object_ref (G_OBJECT (mark));
1396 gtk_signal_emit (GTK_OBJECT (buffer),
1401 g_object_unref (G_OBJECT (mark));
1405 * gtk_text_buffer_set_mark:
1406 * @buffer: a #GtkTextBuffer
1407 * @mark_name: name of the mark
1408 * @iter: location for the mark.
1409 * @left_gravity: if the mark is created by this function, gravity for the new
1411 * @should_exist: if %TRUE, warn if the mark does not exist, and return
1414 * Move the mark to the given position, if not @should_exist, create the mark.
1416 * Return value: mark
1419 gtk_text_buffer_set_mark (GtkTextBuffer *buffer,
1420 GtkTextMark *existing_mark,
1421 const gchar *mark_name,
1422 const GtkTextIter *iter,
1423 gboolean left_gravity,
1424 gboolean should_exist)
1426 GtkTextIter location;
1429 mark = _gtk_text_btree_set_mark (get_btree (buffer),
1436 if (_gtk_text_btree_mark_is_insert (get_btree (buffer), mark) ||
1437 _gtk_text_btree_mark_is_selection_bound (get_btree (buffer), mark))
1439 gtk_text_buffer_update_primary_selection (buffer);
1442 _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1446 gtk_text_buffer_mark_set (buffer, &location, mark);
1452 * gtk_text_buffer_create_mark:
1453 * @buffer: a #GtkTextBuffer
1454 * @mark_name: name for mark, or %NULL
1455 * @where: location to place mark
1456 * @left_gravity: whether the mark has left gravity
1458 * Creates a mark at position @where. If @mark_name is %NULL, the mark
1459 * is anonymous; otherwise, the mark can be retrieved by name using
1460 * gtk_text_buffer_get_mark (). If a mark has left gravity, and text is
1461 * inserted at the mark's current location, the mark will be moved to
1462 * the left of the newly-inserted text. If the mark has right gravity
1463 * (@left_gravity = %FALSE), the mark will end up on the right of
1464 * newly-inserted text. The standard left-to-right cursor is a mark
1465 * with right gravity (when you type, the cursor stays on the right
1466 * side of the text you're typing).
1468 * The caller of this function does <emphasis>not</emphasis> own a reference
1469 * to the returned #GtkTextMark, so you can ignore the return value
1470 * if you like. Marks are owned by the buffer and go away when the
1473 * Emits the "mark_set" signal as notification of the mark's initial
1476 * Return value: the new #GtkTextMark object
1479 gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
1480 const gchar *mark_name,
1481 const GtkTextIter *where,
1482 gboolean left_gravity)
1484 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1486 return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where,
1487 left_gravity, FALSE);
1491 * gtk_text_buffer_move_mark:
1492 * @buffer: a #GtkTextBuffer
1493 * @mark: a #GtkTextMark
1494 * @where: new location for @mark in @buffer
1496 * Moves @mark to the new location @where. Emits the "mark_set" signal
1497 * as notification of the move.
1500 gtk_text_buffer_move_mark (GtkTextBuffer *buffer,
1502 const GtkTextIter *where)
1504 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1505 g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1506 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1508 gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE);
1512 * gtk_text_buffer_get_iter_at_mark:
1513 * @buffer: a #GtkTextBuffer
1514 * @iter: iterator to initialize
1515 * @mark: a #GtkTextMark in @buffer
1517 * Initializes @iter with the current position of @mark.
1520 gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
1524 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1525 g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1526 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1528 _gtk_text_btree_get_iter_at_mark (get_btree (buffer),
1534 * gtk_text_buffer_delete_mark:
1535 * @buffer: a #GtkTextBuffer
1536 * @mark: a #GtkTextMark in @buffer
1538 * Deletes @mark, so that it's no longer located anywhere in the
1539 * buffer. Removes the reference the buffer holds to the mark, so if
1540 * you haven't called g_object_ref () on the mark, it will be freed. Even
1541 * if the mark isn't freed, most operations on @mark become
1542 * invalid. There is no way to undelete a
1543 * mark. gtk_text_mark_get_deleted () will return TRUE after this
1544 * function has been called on a mark; gtk_text_mark_get_deleted ()
1545 * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
1546 * signal will be emitted as notification after the mark is deleted.
1549 gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
1552 g_return_if_fail (GTK_IS_TEXT_MARK (mark));
1553 g_return_if_fail (!gtk_text_mark_get_deleted (mark));
1554 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1556 g_object_ref (G_OBJECT (mark));
1558 _gtk_text_btree_remove_mark (get_btree (buffer), mark);
1560 /* See rationale above for MARK_SET on why we emit this after
1561 * removing the mark, rather than removing the mark in a default
1564 gtk_signal_emit (GTK_OBJECT (buffer), signals[MARK_DELETED],
1567 g_object_unref (G_OBJECT (mark));
1571 * gtk_text_buffer_get_mark:
1572 * @buffer: a #GtkTextBuffer
1573 * @name: a mark name
1575 * Returns the mark named @name in buffer @buffer, or NULL if no such
1576 * mark exists in the buffer.
1578 * Return value: a #GtkTextMark, or NULL
1581 gtk_text_buffer_get_mark (GtkTextBuffer *buffer,
1586 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1587 g_return_val_if_fail (name != NULL, NULL);
1589 mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1596 * gtk_text_buffer_move_mark_by_name:
1597 * @buffer: a #GtkTextBuffer
1598 * @name: name of a mark
1599 * @where: new location for mark
1601 * Moves the mark named @name (which must exist) to location @where.
1602 * See gtk_text_buffer_move_mark () for details.
1605 gtk_text_buffer_move_mark_by_name (GtkTextBuffer *buffer,
1607 const GtkTextIter *where)
1611 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1612 g_return_if_fail (name != NULL);
1614 mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1618 g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1622 gtk_text_buffer_move_mark (buffer, mark, where);
1626 * gtk_text_buffer_delete_mark_by_name:
1627 * @buffer: a #GtkTextBuffer
1628 * @name: name of a mark in @buffer
1630 * Deletes the mark named @name; the mark must exist. See
1631 * gtk_text_buffer_delete_mark () for details.
1634 gtk_text_buffer_delete_mark_by_name (GtkTextBuffer *buffer,
1639 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1640 g_return_if_fail (name != NULL);
1642 mark = _gtk_text_btree_get_mark_by_name (get_btree (buffer), name);
1646 g_warning ("%s: no mark named '%s'", G_STRLOC, name);
1650 gtk_text_buffer_delete_mark (buffer, mark);
1654 * gtk_text_buffer_get_insert:
1655 * @buffer: a #GtkTextBuffer
1657 * Returns the mark that represents the cursor (insertion point).
1658 * Equivalent to calling gtk_text_buffer_get_mark () to get the mark
1659 * name "insert," but very slightly more efficient, and involves less
1662 * Return value: insertion point mark
1665 gtk_text_buffer_get_insert (GtkTextBuffer *buffer)
1667 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1669 /* FIXME use struct member in btree */
1670 return gtk_text_buffer_get_mark (buffer, "insert");
1674 * gtk_text_buffer_get_selection_bound:
1675 * @buffer: a #GtkTextBuffer
1677 * Returns the mark that represents the selection bound. Equivalent
1678 * to calling gtk_text_buffer_get_mark () to get the mark name
1679 * "selection_bound," but very slightly more efficient, and involves
1682 * The currently-selected text in @buffer is the region between the
1683 * "selection_bound" and "insert" marks. If "selection_bound" and
1684 * "insert" are in the same place, then there is no current selection.
1685 * gtk_text_buffer_get_selection_bounds () is another convenient function
1686 * for handling the selection, if you just want to know whether there's a
1687 * selection and what its bounds are.
1689 * Return value: selection bound mark
1692 gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer)
1694 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1696 /* FIXME use struct member in btree */
1697 return gtk_text_buffer_get_mark (buffer, "selection_bound");
1701 gtk_text_buffer_get_iter_at_child_anchor (GtkTextBuffer *buffer,
1703 GtkTextChildAnchor *anchor)
1705 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1706 g_return_if_fail (iter != NULL);
1707 g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
1708 g_return_if_fail (!gtk_text_child_anchor_get_deleted (anchor));
1710 _gtk_text_btree_get_iter_at_child_anchor (get_btree (buffer),
1716 * gtk_text_buffer_place_cursor:
1717 * @buffer: a #GtkTextBuffer
1718 * @where: where to put the cursor
1720 * This function moves the "insert" and "selection_bound" marks
1721 * simultaneously. If you move them to the same place in two steps
1722 * with gtk_text_buffer_move_mark (), you will temporarily select a
1723 * region in between their old and new locations, which can be pretty
1724 * inefficient since the temporarily-selected region will force stuff
1725 * to be recalculated. This function moves them as a unit, which can
1729 gtk_text_buffer_place_cursor (GtkTextBuffer *buffer,
1730 const GtkTextIter *where)
1734 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1738 if (gtk_text_iter_is_last (&real))
1739 gtk_text_iter_backward_char (&real);
1741 _gtk_text_btree_place_cursor (get_btree (buffer), &real);
1742 gtk_text_buffer_mark_set (buffer, &real,
1743 gtk_text_buffer_get_mark (buffer,
1745 gtk_text_buffer_mark_set (buffer, &real,
1746 gtk_text_buffer_get_mark (buffer,
1747 "selection_bound"));
1755 * gtk_text_buffer_create_tag:
1756 * @buffer: a #GtkTextBuffer
1757 * @tag_name: name of the new tag, or %NULL
1759 * Creates a tag and adds it to the tag table for @buffer.
1760 * Equivalent to calling gtk_text_tag_new () and then adding the
1761 * tag to the buffer's tag table. The returned tag has its refcount
1762 * incremented, as if you'd called gtk_text_tag_new ().
1764 * If @tag_name is %NULL, the tag is anonymous.
1766 * Return value: a new tag
1769 gtk_text_buffer_create_tag (GtkTextBuffer *buffer,
1770 const gchar *tag_name)
1774 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
1776 tag = gtk_text_tag_new (tag_name);
1778 gtk_text_tag_table_add (get_table (buffer), tag);
1784 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1786 const GtkTextIter *start,
1787 const GtkTextIter *end)
1789 _gtk_text_btree_tag (start, end, tag, TRUE);
1793 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1795 const GtkTextIter *start,
1796 const GtkTextIter *end)
1798 _gtk_text_btree_tag (start, end, tag, FALSE);
1802 gtk_text_buffer_real_changed (GtkTextBuffer *buffer)
1804 gtk_text_buffer_set_modified (buffer, TRUE);
1808 gtk_text_buffer_emit_tag (GtkTextBuffer *buffer,
1811 const GtkTextIter *start,
1812 const GtkTextIter *end)
1814 GtkTextIter start_tmp = *start;
1815 GtkTextIter end_tmp = *end;
1817 g_return_if_fail (tag != NULL);
1819 gtk_text_iter_reorder (&start_tmp, &end_tmp);
1822 gtk_signal_emit (GTK_OBJECT (buffer), signals[APPLY_TAG],
1823 tag, &start_tmp, &end_tmp);
1825 gtk_signal_emit (GTK_OBJECT (buffer), signals[REMOVE_TAG],
1826 tag, &start_tmp, &end_tmp);
1831 gtk_text_buffer_apply_tag (GtkTextBuffer *buffer,
1833 const GtkTextIter *start,
1834 const GtkTextIter *end)
1836 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1837 g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1838 g_return_if_fail (start != NULL);
1839 g_return_if_fail (end != NULL);
1841 gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1845 gtk_text_buffer_remove_tag (GtkTextBuffer *buffer,
1847 const GtkTextIter *start,
1848 const GtkTextIter *end)
1851 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1852 g_return_if_fail (GTK_IS_TEXT_TAG (tag));
1853 g_return_if_fail (start != NULL);
1854 g_return_if_fail (end != NULL);
1856 gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1861 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1863 const GtkTextIter *start,
1864 const GtkTextIter *end)
1868 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1869 g_return_if_fail (name != NULL);
1870 g_return_if_fail (start != NULL);
1871 g_return_if_fail (end != NULL);
1873 tag = gtk_text_tag_table_lookup (get_table (buffer),
1878 g_warning ("Unknown tag `%s'", name);
1882 gtk_text_buffer_emit_tag (buffer, tag, TRUE, start, end);
1886 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1888 const GtkTextIter *start,
1889 const GtkTextIter *end)
1893 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1894 g_return_if_fail (name != NULL);
1895 g_return_if_fail (start != NULL);
1896 g_return_if_fail (end != NULL);
1898 tag = gtk_text_tag_table_lookup (get_table (buffer),
1903 g_warning ("Unknown tag `%s'", name);
1907 gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
1912 * Obtain various iterators
1916 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
1921 g_return_if_fail (iter != NULL);
1922 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1924 _gtk_text_btree_get_iter_at_line_char (get_btree (buffer),
1925 iter, line_number, char_offset);
1929 gtk_text_buffer_get_iter_at_line_index (GtkTextBuffer *buffer,
1934 g_return_if_fail (iter != NULL);
1935 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1937 _gtk_text_btree_get_iter_at_line_byte (get_btree (buffer),
1938 iter, line_number, byte_index);
1942 gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer,
1946 g_return_if_fail (iter != NULL);
1947 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1949 gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1953 gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buffer,
1957 g_return_if_fail (iter != NULL);
1958 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1960 _gtk_text_btree_get_iter_at_char (get_btree (buffer), iter, char_offset);
1964 gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer,
1967 g_return_if_fail (iter != NULL);
1968 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1970 _gtk_text_btree_get_last_iter (get_btree (buffer), iter);
1974 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1978 g_return_if_fail (start != NULL);
1979 g_return_if_fail (end != NULL);
1980 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1982 _gtk_text_btree_get_iter_at_char (get_btree (buffer), start, 0);
1983 _gtk_text_btree_get_last_iter (get_btree (buffer), end);
1991 gtk_text_buffer_modified (GtkTextBuffer *buffer)
1993 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1995 return buffer->modified;
1999 gtk_text_buffer_set_modified (GtkTextBuffer *buffer,
2002 gboolean fixed_setting;
2004 g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
2006 fixed_setting = setting != FALSE;
2008 if (buffer->modified == fixed_setting)
2012 buffer->modified = fixed_setting;
2013 gtk_signal_emit (GTK_OBJECT (buffer), signals[MODIFIED_CHANGED]);
2019 * Assorted other stuff
2023 gtk_text_buffer_get_line_count (GtkTextBuffer *buffer)
2025 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2027 return _gtk_text_btree_line_count (get_btree (buffer));
2031 gtk_text_buffer_get_char_count (GtkTextBuffer *buffer)
2033 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), 0);
2035 return _gtk_text_btree_char_count (get_btree (buffer));
2038 /* Called when we lose the primary selection.
2041 clipboard_clear_selection_cb (GtkClipboard *clipboard,
2044 /* Move selection_bound to the insertion point */
2046 GtkTextIter selection_bound;
2047 GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2049 gtk_text_buffer_get_iter_at_mark (buffer, &insert,
2050 gtk_text_buffer_get_mark (buffer, "insert"));
2051 gtk_text_buffer_get_iter_at_mark (buffer, &selection_bound,
2052 gtk_text_buffer_get_mark (buffer, "selection_bound"));
2054 if (!gtk_text_iter_equal (&insert, &selection_bound))
2055 gtk_text_buffer_move_mark (buffer,
2056 gtk_text_buffer_get_mark (buffer, "selection_bound"),
2060 /* Called when we have the primary selection and someone else wants our
2061 * data in order to paste it.
2064 clipboard_get_selection_cb (GtkClipboard *clipboard,
2065 GtkSelectionData *selection_data,
2069 GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2070 GtkTextIter start, end;
2072 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2074 if (selection_data->target ==
2075 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2077 /* Provide the address of the buffer; this will only be
2078 * used within-process
2080 gtk_selection_data_set (selection_data,
2081 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2090 str = gtk_text_iter_get_visible_text (&start, &end);
2091 gtk_selection_data_set_text (selection_data, str);
2097 /* Provide cut/copied data */
2099 clipboard_get_contents_cb (GtkClipboard *clipboard,
2100 GtkSelectionData *selection_data,
2104 GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2105 GtkTextBuffer *contents = buffer->clipboard_contents;
2107 if (selection_data->target ==
2108 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2110 /* Provide the address of the clipboard buffer; this will only
2111 * be used within-process. OK to supply a NULL value for contents.
2113 gtk_selection_data_set (selection_data,
2114 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2121 /* Just provide text from the clipboard buffer */
2122 if (buffer->clipboard_contents)
2125 GtkTextIter start, end;
2127 gtk_text_buffer_get_bounds (contents, &start, &end);
2128 /* strip off the trailing newline, it isn't part of the text that was cut */
2129 gtk_text_iter_backward_char (&end);
2131 str = gtk_text_iter_get_visible_text (&start, &end);
2132 gtk_selection_data_set_text (selection_data, str);
2137 gtk_selection_data_set_text (selection_data, "");
2144 clipboard_clear_contents_cb (GtkClipboard *clipboard,
2147 GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
2149 if (buffer->clipboard_contents)
2151 g_object_unref (G_OBJECT (buffer->clipboard_contents));
2152 buffer->clipboard_contents = NULL;
2157 get_paste_point (GtkTextBuffer *buffer,
2159 gboolean clear_afterward)
2161 GtkTextIter insert_point;
2162 GtkTextMark *paste_point_override;
2164 paste_point_override = gtk_text_buffer_get_mark (buffer,
2165 "gtk_paste_point_override");
2167 if (paste_point_override != NULL)
2169 gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2170 paste_point_override);
2171 if (clear_afterward)
2172 gtk_text_buffer_delete_mark (buffer,
2173 gtk_text_buffer_get_mark (buffer,
2174 "gtk_paste_point_override"));
2178 gtk_text_buffer_get_iter_at_mark (buffer, &insert_point,
2179 gtk_text_buffer_get_mark (buffer,
2183 *iter = insert_point;
2187 pre_paste_prep (ClipboardRequest *request_data,
2188 GtkTextIter *insert_point)
2190 GtkTextBuffer *buffer = request_data->buffer;
2192 get_paste_point (buffer, insert_point, TRUE);
2194 /* If we're going to replace the selection, we insert before it to
2195 * avoid messing it up, then we delete the selection after inserting.
2197 if (request_data->replace_selection)
2199 GtkTextIter start, end;
2201 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2202 *insert_point = start;
2207 post_paste_cleanup (ClipboardRequest *request_data)
2209 if (request_data->replace_selection)
2211 GtkTextIter start, end;
2213 if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
2216 if (request_data->interactive)
2217 gtk_text_buffer_delete_interactive (request_data->buffer,
2220 request_data->default_editable);
2222 gtk_text_buffer_delete (request_data->buffer, &start, &end);
2227 /* Called when we request a paste and receive the text data
2230 clipboard_text_received (GtkClipboard *clipboard,
2234 ClipboardRequest *request_data = data;
2235 GtkTextBuffer *buffer = request_data->buffer;
2239 GtkTextIter insert_point;
2241 pre_paste_prep (request_data, &insert_point);
2243 if (request_data->interactive)
2244 gtk_text_buffer_insert_interactive (buffer, &insert_point,
2245 str, -1, request_data->default_editable);
2247 gtk_text_buffer_insert (buffer, &insert_point,
2250 post_paste_cleanup (request_data);
2253 g_object_unref (G_OBJECT (buffer));
2254 g_free (request_data);
2257 static GtkTextBuffer*
2258 selection_data_get_buffer (GtkSelectionData *selection_data,
2259 ClipboardRequest *request_data)
2262 GtkTextBuffer *src_buffer = NULL;
2264 /* If we can get the owner, the selection is in-process */
2265 owner = gdk_selection_owner_get (selection_data->selection);
2270 if (selection_data->type != gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
2273 if (selection_data->length != sizeof (src_buffer))
2276 memcpy (&src_buffer, selection_data->data, sizeof (src_buffer));
2278 if (src_buffer == NULL)
2281 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (src_buffer), NULL);
2283 if (gtk_text_buffer_get_tag_table (src_buffer) !=
2284 gtk_text_buffer_get_tag_table (request_data->buffer))
2291 /* These are pretty handy functions; maybe something like them
2292 * should be in the public API. Also, there are other places in this
2293 * file where they could be used.
2296 save_iter (const GtkTextIter *iter,
2297 gboolean left_gravity)
2299 return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
2306 restore_iter (const GtkTextIter *iter,
2309 gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
2310 (GtkTextIter*) iter,
2312 gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
2318 paste_from_buffer (ClipboardRequest *request_data,
2319 GtkTextBuffer *src_buffer,
2320 const GtkTextIter *start,
2321 const GtkTextIter *end)
2323 GtkTextIter insert_point;
2325 /* We're about to emit a bunch of signals, so be safe */
2326 g_object_ref (G_OBJECT (src_buffer));
2328 pre_paste_prep (request_data, &insert_point);
2330 if (!gtk_text_iter_equal (start, end))
2332 gtk_text_buffer_real_insert_range (request_data->buffer,
2336 request_data->interactive);
2339 post_paste_cleanup (request_data);
2341 g_object_unref (G_OBJECT (src_buffer));
2345 clipboard_clipboard_buffer_received (GtkClipboard *clipboard,
2346 GtkSelectionData *selection_data,
2349 ClipboardRequest *request_data = data;
2350 GtkTextBuffer *src_buffer;
2352 src_buffer = selection_data_get_buffer (selection_data, request_data);
2356 GtkTextIter start, end;
2358 gtk_text_buffer_get_bounds (src_buffer, &start, &end);
2359 /* There's an extra newline on clipboard_contents */
2360 gtk_text_iter_backward_char (&end);
2362 paste_from_buffer (request_data, src_buffer,
2367 /* Request the text selection instead */
2368 gtk_clipboard_request_text (clipboard,
2369 clipboard_text_received,
2375 clipboard_selection_buffer_received (GtkClipboard *clipboard,
2376 GtkSelectionData *selection_data,
2379 ClipboardRequest *request_data = data;
2380 GtkTextBuffer *src_buffer;
2382 src_buffer = selection_data_get_buffer (selection_data, request_data);
2386 GtkTextIter start, end;
2388 if (gtk_text_buffer_get_selection_bounds (src_buffer, &start, &end))
2389 paste_from_buffer (request_data, src_buffer,
2394 /* Request the text selection instead */
2395 gtk_clipboard_request_text (clipboard,
2396 clipboard_text_received,
2401 static const GtkTargetEntry targets[] = {
2402 { "STRING", 0, TARGET_STRING },
2403 { "TEXT", 0, TARGET_TEXT },
2404 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
2405 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
2406 { "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
2410 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
2415 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
2417 /* Determine whether we have a selection and adjust X selection
2421 if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2423 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
2424 gtk_clipboard_clear (clipboard);
2428 /* Even if we already have the selection, we need to update our
2431 if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2432 clipboard_get_selection_cb,
2433 clipboard_clear_selection_cb,
2435 clipboard_clear_selection_cb (clipboard, buffer);
2440 paste (GtkTextBuffer *buffer,
2441 gboolean is_clipboard,
2442 gboolean interactive,
2443 gboolean default_editable)
2445 ClipboardRequest *data = g_new (ClipboardRequest, 1);
2446 GtkTextIter paste_point;
2447 GtkTextIter start, end;
2449 data->buffer = buffer;
2450 g_object_ref (G_OBJECT (buffer));
2451 data->interactive = interactive;
2452 data->default_editable = default_editable;
2454 /* When pasting with the cursor inside the selection area, you
2455 * replace the selection with the new text, otherwise, you
2456 * simply insert the new text at the point where the click
2457 * occured, unselecting any selected text. The replace_selection
2458 * flag toggles this behavior.
2460 data->replace_selection = FALSE;
2462 get_paste_point (buffer, &paste_point, FALSE);
2463 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
2464 (gtk_text_iter_in_range (&paste_point, &start, &end) ||
2465 gtk_text_iter_equal (&paste_point, &end)))
2466 data->replace_selection = TRUE;
2469 gtk_clipboard_request_contents (gtk_clipboard_get (GDK_NONE),
2471 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2472 clipboard_clipboard_buffer_received, data);
2474 gtk_clipboard_request_contents (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
2476 gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE),
2477 clipboard_selection_buffer_received, data);
2481 gtk_text_buffer_paste_primary (GtkTextBuffer *buffer,
2482 const GtkTextIter *override_location,
2483 gboolean default_editable)
2485 if (override_location != NULL)
2486 gtk_text_buffer_create_mark (buffer,
2487 "gtk_paste_point_override",
2488 override_location, FALSE);
2490 paste (buffer, FALSE, TRUE, default_editable);
2494 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
2495 gboolean default_editable)
2497 paste (buffer, TRUE, TRUE, default_editable);
2501 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
2502 gboolean interactive,
2503 gboolean default_editable)
2508 if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2510 return FALSE; /* No selection */
2515 gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
2517 gtk_text_buffer_delete (buffer, &start, &end);
2519 return TRUE; /* We deleted stuff */
2524 cut_or_copy (GtkTextBuffer *buffer,
2525 gboolean delete_region_after,
2526 gboolean interactive,
2527 gboolean default_editable)
2529 /* We prefer to cut the selected region between selection_bound and
2530 * insertion point. If that region is empty, then we cut the region
2531 * between the "anchor" and the insertion point (this is for
2532 * C-space and M-w and other Emacs-style copy/yank keys). Note that
2533 * insert and selection_bound are guaranteed to exist, but the
2534 * anchor only exists sometimes.
2539 if (buffer->clipboard_contents)
2541 g_object_unref (G_OBJECT (buffer->clipboard_contents));
2542 buffer->clipboard_contents = NULL;
2545 if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
2547 /* Let's try the anchor thing */
2548 GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
2554 gtk_text_buffer_get_iter_at_mark (buffer, &end, anchor);
2555 gtk_text_iter_reorder (&start, &end);
2559 if (!gtk_text_iter_equal (&start, &end))
2561 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
2564 buffer->clipboard_contents =
2565 gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
2567 gtk_text_buffer_get_iter_at_offset (buffer->clipboard_contents,
2570 gtk_text_buffer_insert_range (buffer->clipboard_contents,
2575 if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2576 clipboard_get_contents_cb,
2577 clipboard_clear_contents_cb,
2579 clipboard_clear_contents_cb (clipboard, buffer);
2581 if (delete_region_after)
2584 gtk_text_buffer_delete_interactive (buffer, &start, &end,
2587 gtk_text_buffer_delete (buffer, &start, &end);
2593 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
2594 gboolean default_editable)
2596 cut_or_copy (buffer, TRUE, TRUE, default_editable);
2600 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
2602 cut_or_copy (buffer, FALSE, TRUE, TRUE);
2607 * gtk_text_buffer_get_selection_bounds:
2608 * @buffer: a #GtkTextBuffer
2609 * @start: iterator to initialize with selection start
2610 * @end: iterator to initialize with selection end
2612 * Returns %TRUE if some text is selected; places the bounds
2613 * of the selection in @start and @end (if the selection has length 0,
2614 * then @start and @end are filled in with the same value).
2615 * @start and @end will be in ascending order. If @start and @end are
2616 * NULL, then they are not filled in, but the return value still indicates
2617 * whether text is selected.
2619 * Return value: whether the selection has nonzero length
2622 gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer,
2626 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
2628 return _gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
2632 * Logical attribute cache
2635 #define ATTR_CACHE_SIZE 2
2637 typedef struct _CacheEntry CacheEntry;
2642 PangoLogAttr *attrs;
2646 struct _GtkTextLogAttrCache
2648 gint chars_changed_stamp;
2649 CacheEntry entries[ATTR_CACHE_SIZE];
2653 free_log_attr_cache (GtkTextLogAttrCache *cache)
2656 while (i < ATTR_CACHE_SIZE)
2658 g_free (cache->entries[i].attrs);
2665 clear_log_attr_cache (GtkTextLogAttrCache *cache)
2668 while (i < ATTR_CACHE_SIZE)
2670 g_free (cache->entries[i].attrs);
2671 cache->entries[i].attrs = NULL;
2676 static PangoLogAttr*
2677 compute_log_attrs (const GtkTextIter *iter,
2683 gint char_len, byte_len;
2684 PangoLogAttr *attrs = NULL;
2690 gtk_text_iter_set_line_offset (&start, 0);
2691 gtk_text_iter_forward_line (&end);
2693 paragraph = gtk_text_iter_get_slice (&start, &end);
2694 char_len = g_utf8_strlen (paragraph, -1);
2695 byte_len = strlen (paragraph);
2697 g_assert (char_len > 0);
2700 *char_lenp = char_len;
2702 attrs = g_new (PangoLogAttr, char_len);
2704 lang = gtk_text_iter_get_language (&start);
2706 pango_get_log_attrs (paragraph, byte_len, -1,
2717 /* The return value from this is valid until you call this a second time.
2720 _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer *buffer,
2721 const GtkTextIter *anywhere_in_line,
2725 GtkTextLogAttrCache *cache;
2728 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
2729 g_return_val_if_fail (anywhere_in_line != NULL, NULL);
2730 g_return_val_if_fail (!gtk_text_iter_is_last (anywhere_in_line), NULL);
2732 /* FIXME we also need to recompute log attrs if the language tag at
2733 * the start of a paragraph changes
2736 if (buffer->log_attr_cache == NULL)
2738 buffer->log_attr_cache = g_new0 (GtkTextLogAttrCache, 1);
2739 buffer->log_attr_cache->chars_changed_stamp =
2740 _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer));
2742 else if (buffer->log_attr_cache->chars_changed_stamp !=
2743 _gtk_text_btree_get_chars_changed_stamp (get_btree (buffer)))
2745 clear_log_attr_cache (buffer->log_attr_cache);
2748 cache = buffer->log_attr_cache;
2749 line = gtk_text_iter_get_line (anywhere_in_line);
2752 while (i < ATTR_CACHE_SIZE)
2754 if (cache->entries[i].attrs &&
2755 cache->entries[i].line == line)
2758 *char_len = cache->entries[i].char_len;
2759 return cache->entries[i].attrs;
2764 /* Not in cache; open up the first cache entry */
2765 if (cache->entries[ATTR_CACHE_SIZE-1].attrs)
2766 g_free (cache->entries[ATTR_CACHE_SIZE-1].attrs);
2768 g_memmove (cache->entries + 1, cache->entries,
2769 sizeof (CacheEntry) * (ATTR_CACHE_SIZE - 1));
2771 cache->entries[0].line = line;
2772 cache->entries[0].attrs = compute_log_attrs (anywhere_in_line,
2773 &cache->entries[0].char_len);
2776 *char_len = cache->entries[0].char_len;
2778 return cache->entries[0].attrs;
2786 _gtk_text_buffer_spew (GtkTextBuffer *buffer)
2788 _gtk_text_btree_spew (get_btree (buffer));