1 /* gtktextbuffer.c - the "model" in the MVC text widget architecture
2 * Copyright (c) 2000 Red Hat, Inc.
3 * Developed by Havoc Pennington
8 #include "gtkclipboard.h"
9 #include "gtkinvisible.h"
10 #include "gtksignal.h"
11 #include "gtktextbuffer.h"
12 #include "gtktextbtree.h"
13 #include "gtktextiterprivate.h"
16 typedef struct _ClipboardRequest ClipboardRequest;
18 struct _ClipboardRequest
20 GtkTextBuffer *buffer;
22 gboolean default_editable;
23 gboolean is_clipboard;
50 static void gtk_text_buffer_init (GtkTextBuffer *tkxt_buffer);
51 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
52 static void gtk_text_buffer_destroy (GtkObject *object);
53 static void gtk_text_buffer_finalize (GObject *object);
56 static void gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer);
57 static void gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
61 gboolean interactive);
62 static void gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
65 gboolean interactive);
66 static void gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
68 const GtkTextIter *start_char,
69 const GtkTextIter *end_char);
70 static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
72 const GtkTextIter *start_char,
73 const GtkTextIter *end_char);
75 static GtkTextBTree* get_btree (GtkTextBuffer *buffer);
77 void gtk_marshal_NONE__INT_POINTER_INT (GtkObject *object,
82 static GtkObjectClass *parent_class = NULL;
83 static guint signals[LAST_SIGNAL] = { 0 };
86 gtk_text_buffer_get_type (void)
88 static GtkType our_type = 0;
92 static const GtkTypeInfo our_info =
95 sizeof (GtkTextBuffer),
96 sizeof (GtkTextBufferClass),
97 (GtkClassInitFunc) gtk_text_buffer_class_init,
98 (GtkObjectInitFunc) gtk_text_buffer_init,
99 /* reserved_1 */ NULL,
100 /* reserved_2 */ NULL,
101 (GtkClassInitFunc) NULL
104 our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
111 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
113 GtkObjectClass *object_class = (GtkObjectClass*) klass;
114 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
116 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
118 signals[INSERT_TEXT] =
119 gtk_signal_new ("insert_text",
121 GTK_CLASS_TYPE (object_class),
122 GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
123 gtk_marshal_NONE__POINTER_POINTER_INT_INT,
131 signals[DELETE_TEXT] =
132 gtk_signal_new ("delete_text",
134 GTK_CLASS_TYPE (object_class),
135 GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
136 gtk_marshal_NONE__POINTER_POINTER_INT,
144 gtk_signal_new ("changed",
146 GTK_CLASS_TYPE (object_class),
147 GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
148 gtk_marshal_NONE__NONE,
152 signals[MODIFIED_CHANGED] =
153 gtk_signal_new ("modified_changed",
155 GTK_CLASS_TYPE (object_class),
156 GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
157 gtk_marshal_NONE__NONE,
162 gtk_signal_new ("mark_set",
164 GTK_CLASS_TYPE (object_class),
165 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
166 gtk_marshal_NONE__POINTER_POINTER,
172 signals[MARK_DELETED] =
173 gtk_signal_new ("mark_deleted",
175 GTK_CLASS_TYPE (object_class),
176 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
177 gtk_marshal_NONE__POINTER,
183 gtk_signal_new ("apply_tag",
185 GTK_CLASS_TYPE (object_class),
186 GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
187 gtk_marshal_NONE__POINTER_POINTER_POINTER,
194 signals[REMOVE_TAG] =
195 gtk_signal_new ("remove_tag",
197 GTK_CLASS_TYPE (object_class),
198 GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
199 gtk_marshal_NONE__POINTER_POINTER_POINTER,
206 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
208 object_class->destroy = gtk_text_buffer_destroy;
210 gobject_class->finalize = gtk_text_buffer_finalize;
212 klass->insert_text = gtk_text_buffer_real_insert_text;
213 klass->delete_text = gtk_text_buffer_real_delete_text;
214 klass->apply_tag = gtk_text_buffer_real_apply_tag;
215 klass->remove_tag = gtk_text_buffer_real_remove_tag;
219 typedef gint (*GtkSignal_NONE__INT_POINTER_INT) (GtkObject *object,
226 gtk_marshal_NONE__INT_POINTER_INT (GtkObject *object,
231 GtkSignal_NONE__INT_POINTER_INT rfunc;
233 rfunc = (GtkSignal_NONE__INT_POINTER_INT) func;
236 GTK_VALUE_INT (args[0]),
237 GTK_VALUE_POINTER (args[1]),
238 GTK_VALUE_INT (args[2]),
243 gtk_text_buffer_init (GtkTextBuffer *buffer)
248 * gtk_text_buffer_new:
249 * @table: a tag table, or NULL to create a new one
251 * Creates a new text buffer.
253 * Return value: a new text buffer
256 gtk_text_buffer_new (GtkTextTagTable *table)
258 GtkTextBuffer *text_buffer;
260 text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
264 text_buffer->tag_table = table;
266 gtk_object_ref (GTK_OBJECT(text_buffer->tag_table));
267 gtk_object_sink (GTK_OBJECT(text_buffer->tag_table));
274 gtk_text_buffer_destroy (GtkObject *object)
276 GtkTextBuffer *buffer;
278 buffer = GTK_TEXT_BUFFER (object);
280 if (buffer->tag_table)
282 gtk_object_unref(GTK_OBJECT(buffer->tag_table));
283 buffer->tag_table = NULL;
288 gtk_text_btree_unref(buffer->btree);
289 buffer->btree = NULL;
292 (* parent_class->destroy) (object);
296 gtk_text_buffer_finalize (GObject *object)
298 GtkTextBuffer *tkxt_buffer;
300 tkxt_buffer = GTK_TEXT_BUFFER (object);
302 G_OBJECT_CLASS (parent_class)->finalize (object);
305 static GtkTextTagTable*
306 get_table (GtkTextBuffer *buffer)
308 if (buffer->tag_table == NULL)
310 buffer->tag_table = gtk_text_tag_table_new ();
312 gtk_object_ref (GTK_OBJECT(buffer->tag_table));
313 gtk_object_sink (GTK_OBJECT(buffer->tag_table));
316 return buffer->tag_table;
320 get_btree (GtkTextBuffer *buffer)
322 if (buffer->btree == NULL)
323 buffer->btree = gtk_text_btree_new(gtk_text_buffer_get_tag_table (buffer),
326 return buffer->btree;
330 _gtk_text_buffer_get_btree (GtkTextBuffer *buffer)
332 return get_btree (buffer);
336 * gtk_text_buffer_get_tag_table:
337 * @buffer: a #GtkTextBuffer
339 * Get the #GtkTextTagTable associated with this buffer.
341 * Return value: the buffer's tag table
344 gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer)
346 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
348 return get_table (buffer);
356 gtk_text_buffer_real_insert_text(GtkTextBuffer *buffer,
360 gboolean interactive)
362 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
363 g_return_if_fail(iter != NULL);
365 gtk_text_btree_insert(iter, text, len);
367 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
369 gtk_text_buffer_set_modified(buffer, TRUE);
373 gtk_text_buffer_emit_insert(GtkTextBuffer *buffer,
377 gboolean interactive)
379 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
380 g_return_if_fail(iter != NULL);
381 g_return_if_fail(text != NULL);
388 gtk_signal_emit(GTK_OBJECT(buffer), signals[INSERT_TEXT],
389 iter, text, len, interactive);
394 * gtk_text_buffer_insert:
395 * @buffer: a #GtkTextBuffer
396 * @iter: a position in the buffer
397 * @text: UTF-8 format text to insert
398 * @len: length of text in bytes, or -1
400 * Inserts @len bytes of @text at position @iter. If @len is -1,
401 * @text must be nul-terminated and will be inserted in its
402 * entirety. Emits the "insert_text" signal; insertion actually occurs
403 * in the default handler for the signal. @iter is invalidated when
404 * insertion occurs (because the buffer contents change), but the
405 * default signal handler revalidates it to point to the end of the
410 gtk_text_buffer_insert (GtkTextBuffer *buffer,
415 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
416 g_return_if_fail(iter != NULL);
417 g_return_if_fail(text != NULL);
419 gtk_text_buffer_emit_insert(buffer, iter, text, len, FALSE);
423 * gtk_text_buffer_insert_at_cursor:
424 * @buffer: a #GtkTextBuffer
425 * @text: some text in UTF-8 format
426 * @len: length of text, in bytes
428 * Simply calls gtk_text_buffer_insert(), using the current
429 * cursor position as the insertion point.
432 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
438 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
439 g_return_if_fail(text != NULL);
441 gtk_text_buffer_get_iter_at_mark(buffer, &iter,
442 gtk_text_buffer_get_mark (buffer,
445 gtk_text_buffer_insert(buffer, &iter, text, len);
449 * gtk_text_buffer_insert_interactive:
450 * @buffer: a #GtkTextBuffer
451 * @iter: a position in @buffer
452 * @text: some UTF-8 text
453 * @len: length of text in bytes, or -1
454 * @default_editable: default editability of buffer
456 * Like gtk_text_buffer_insert(), but the insertion will not occur if
457 * @iter is at a non-editable location in the buffer. Usually you
458 * want to prevent insertions at ineditable locations if the insertion
459 * results from a user action (is interactive).
461 * Return value: whether text was actually inserted
464 gtk_text_buffer_insert_interactive(GtkTextBuffer *buffer,
468 gboolean default_editable)
470 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
471 g_return_val_if_fail(text != NULL, FALSE);
473 if (gtk_text_iter_editable (iter, default_editable))
475 gtk_text_buffer_emit_insert (buffer, iter, text, len, TRUE);
483 * gtk_text_buffer_insert_interactive_at_cursor:
484 * @buffer: a #GtkTextBuffer
485 * @text: text in UTF-8 format
486 * @len: length of text in bytes, or -1
487 * @default_editable: default editability of buffer
489 * Calls gtk_text_buffer_insert_interactive() at the cursor
492 * Return value: whether text was actually inserted
495 gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer,
498 gboolean default_editable)
502 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
503 g_return_val_if_fail(text != NULL, FALSE);
505 gtk_text_buffer_get_iter_at_mark(buffer, &iter,
506 gtk_text_buffer_get_mark (buffer,
509 return gtk_text_buffer_insert_interactive (buffer, &iter, text, len,
518 gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer,
521 gboolean interactive)
523 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
524 g_return_if_fail(start != NULL);
525 g_return_if_fail(end != NULL);
527 gtk_text_btree_delete(start, end);
529 /* may have deleted the selection... */
530 gtk_text_buffer_update_primary_selection(buffer);
532 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
534 gtk_text_buffer_set_modified(buffer, TRUE);
538 gtk_text_buffer_emit_delete(GtkTextBuffer *buffer,
541 gboolean interactive)
543 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
544 g_return_if_fail(start != NULL);
545 g_return_if_fail(end != NULL);
547 if (gtk_text_iter_equal(start, end))
550 gtk_text_iter_reorder (start, end);
552 /* FIXME if the final newline is in the deletion range,
553 * shorten the range. (i.e. if end is the end iterator,
554 * move it backward by one)
557 gtk_signal_emit(GTK_OBJECT(buffer),
558 signals[DELETE_TEXT],
564 * gtk_text_buffer_delete:
565 * @buffer: a #GtkTextBuffer
566 * @start: a position in @buffer
567 * @end: another position in @buffer
569 * Deletes text between @start and @end. The order of @start and @end
570 * is not actually relevant; gtk_text_buffer_delete() will reorder
571 * them. This function actually emits the "delete_text" signal, and
572 * the default handler of that signal deletes the text. Because the
573 * buffer is modified, all outstanding iterators become invalid after
574 * calling this function; however, the @start and @end will be
575 * re-initialized to point to the location where text was deleted.
577 * Note that the final newline in the buffer may not be deleted; a
578 * #GtkTextBuffer always contains at least one newline. You can
579 * safely include the final newline in the range [@start,@end) but it
580 * won't be affected by the deletion.
584 gtk_text_buffer_delete (GtkTextBuffer *buffer,
588 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
589 g_return_if_fail(start != NULL);
590 g_return_if_fail(end != NULL);
592 gtk_text_buffer_emit_delete(buffer, start, end, FALSE);
596 * gtk_text_buffer_delete_interactive:
597 * @buffer: a #GtkTextBuffer
598 * @start_iter: start of range to delete
599 * @end_iter: end of range
600 * @default_editable: whether the buffer is editable by default
602 * Deletes all <emphasis>editable</emphasis> text in the given range.
603 * Calls gtk_text_buffer_delete() for each editable sub-range of
606 * Return value: whether some text was actually deleted
609 gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer,
610 GtkTextIter *start_iter,
611 GtkTextIter *end_iter,
612 gboolean default_editable)
614 GtkTextMark *end_mark;
615 GtkTextMark *start_mark;
617 gboolean current_state;
618 gboolean deleted_stuff = FALSE;
620 /* Delete all editable text in the range start_iter, end_iter */
622 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
623 g_return_val_if_fail (start_iter != NULL, FALSE);
624 g_return_val_if_fail (end_iter != NULL, FALSE);
626 gtk_text_iter_reorder (start_iter, end_iter);
628 start_mark = gtk_text_buffer_create_mark (buffer, NULL,
630 end_mark = gtk_text_buffer_create_mark (buffer, NULL,
634 current_state = gtk_text_iter_editable (&iter, default_editable);
639 gboolean done = FALSE;
642 gtk_text_iter_forward_to_tag_toggle (&iter, NULL);
644 gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark);
646 if (gtk_text_iter_compare (&iter, &end) >= 0)
649 iter = end; /* clamp to the last boundary */
652 new_state = gtk_text_iter_editable (&iter, default_editable);
654 if (current_state == new_state)
660 /* We're ending an editable region. Delete said region. */
663 gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
665 gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
667 deleted_stuff = TRUE;
676 if (current_state && !new_state)
678 /* End of an editable region. Delete it. */
681 gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark);
683 gtk_text_buffer_emit_delete (buffer, &start, &iter, TRUE);
685 current_state = FALSE;
686 deleted_stuff = TRUE;
690 /* We are at the start of an editable region. We won't be deleting
691 * the previous region. Move start mark to start of this region.
694 g_assert (!current_state && new_state);
696 gtk_text_buffer_move_mark (buffer, start_mark,
700 current_state = TRUE;
708 gtk_text_buffer_delete_mark (buffer, start_mark);
709 gtk_text_buffer_delete_mark (buffer, end_mark);
711 return deleted_stuff;
715 * Extracting textual buffer contents
719 * gtk_text_buffer_get_text:
720 * @buffer: a #GtkTextBuffer
721 * @start: start of a range
722 * @end: end of a range
723 * @include_hidden_chars: whether to include invisible text
725 * Returns the text in the range [@start,@end). Excludes undisplayed
726 * text (text marked with tags that set the invisibility attribute) if
727 * @include_hidden_chars is FALSE. Does not include characters
728 * representing embedded images, so byte and character indexes into
729 * the returned string do <emphasis>not</emphasis> correspond to byte
730 * and character indexes into the buffer. Contrast with
731 * gtk_text_buffer_get_slice().
733 * Return value: an allocated UTF-8 string
736 gtk_text_buffer_get_text (GtkTextBuffer *buffer,
737 const GtkTextIter *start,
738 const GtkTextIter *end,
739 gboolean include_hidden_chars)
741 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
742 g_return_val_if_fail(start != NULL, NULL);
743 g_return_val_if_fail(end != NULL, NULL);
745 if (include_hidden_chars)
746 return gtk_text_iter_get_text(start, end);
748 return gtk_text_iter_get_visible_text(start, end);
752 * gtk_text_buffer_get_slice:
753 * @buffer: a #GtkTextBuffer
754 * @start: start of a range
755 * @end: end of a range
756 * @include_hidden_chars: whether to include invisible text
758 * Returns the text in the range [@start,@end). Excludes undisplayed
759 * text (text marked with tags that set the invisibility attribute) if
760 * @include_hidden_chars is FALSE. The returned string includes a
761 * 0xFFFD character whenever the buffer contains
762 * embedded images, so byte and character indexes into
763 * the returned string <emphasis>do</emphasis> correspond to byte
764 * and character indexes into the buffer. Contrast with
765 * gtk_text_buffer_get_text().
767 * Return value: an allocated UTF-8 string
770 gtk_text_buffer_get_slice (GtkTextBuffer *buffer,
771 const GtkTextIter *start,
772 const GtkTextIter *end,
773 gboolean include_hidden_chars)
775 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
776 g_return_val_if_fail(start != NULL, NULL);
777 g_return_val_if_fail(end != NULL, NULL);
779 if (include_hidden_chars)
780 return gtk_text_iter_get_slice(start, end);
782 return gtk_text_iter_get_visible_slice(start, end);
790 gtk_text_buffer_insert_pixmap (GtkTextBuffer *buffer,
795 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
796 g_return_if_fail(iter != NULL);
797 g_return_if_fail(pixmap != NULL);
799 gtk_text_btree_insert_pixmap(iter, pixmap, mask);
801 /* FIXME pixmap-specific signal like insert_text */
803 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
805 gtk_text_buffer_set_modified(buffer, TRUE);
813 gtk_text_buffer_mark_set (GtkTextBuffer *buffer,
814 const GtkTextIter *location,
817 /* IMO this should NOT work like insert_text and delete_text,
818 where the real action happens in the default handler.
820 The reason is that the default handler would be _required_,
821 i.e. the whole widget would start breaking and segfaulting
822 if the default handler didn't get run. So you can't really
823 override the default handler or stop the emission; that is,
824 this signal is purely for notification, and not to allow users
825 to modify the default behavior. */
826 gtk_signal_emit(GTK_OBJECT(buffer),
834 * gtk_text_buffer_set_mark:
835 * @buffer: a #GtkTextBuffer
836 * @mark_name: name of the mark
837 * @iter: location for the mark.
838 * @left_gravity: if the mark is created by this function, gravity for the new
840 * @should_exist: if %TRUE, warn if the mark does not exist, and return
843 * Move the mark to the given position, if not @should_exist, create the mark.
848 gtk_text_buffer_set_mark(GtkTextBuffer *buffer,
849 GtkTextMark *existing_mark,
850 const gchar *mark_name,
851 const GtkTextIter *iter,
852 gboolean left_gravity,
853 gboolean should_exist)
855 GtkTextIter location;
858 mark = gtk_text_btree_set_mark(get_btree (buffer),
865 if (gtk_text_btree_mark_is_insert(get_btree (buffer), mark) ||
866 gtk_text_btree_mark_is_selection_bound(get_btree (buffer), mark))
868 gtk_text_buffer_update_primary_selection(buffer);
871 gtk_text_btree_get_iter_at_mark(get_btree (buffer),
875 gtk_text_buffer_mark_set (buffer, &location, mark);
877 return (GtkTextMark*)mark;
881 * gtk_text_buffer_create_mark:
882 * @buffer: a #GtkTextBuffer
883 * @mark_name: name for mark, or %NULL
884 * @where: location to place mark
885 * @left_gravity: whether the mark has left gravity
887 * Creates a mark at position @where. If @mark_name is %NULL, the mark
888 * is anonymous; otherwise, the mark can be retrieved by name using
889 * gtk_text_buffer_get_mark(). If a mark has left gravity, and text is
890 * inserted at the mark's current location, the mark will be moved to
891 * the left of the newly-inserted text. If the mark has right gravity
892 * (@left_gravity = %FALSE), the mark will end up on the right of
893 * newly-inserted text. The standard left-to-right cursor is a mark
894 * with right gravity (when you type, the cursor stays on the right
895 * side of the text you're typing).
897 * The caller of this function does <emphasis>not</emphasis> own a reference
898 * to the returned #GtkTextMark, so you can ignore the return value
901 * Return value: the new #GtkTextMark object
904 gtk_text_buffer_create_mark(GtkTextBuffer *buffer,
905 const gchar *mark_name,
906 const GtkTextIter *where,
907 gboolean left_gravity)
909 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
911 return gtk_text_buffer_set_mark(buffer, NULL, mark_name, where,
912 left_gravity, FALSE);
916 * gtk_text_buffer_move_mark:
924 gtk_text_buffer_move_mark(GtkTextBuffer *buffer,
926 const GtkTextIter *where)
928 g_return_if_fail (mark != NULL);
929 g_return_if_fail (!gtk_text_mark_deleted (mark));
930 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
932 gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE);
936 gtk_text_buffer_get_iter_at_mark(GtkTextBuffer *buffer,
940 g_return_if_fail (mark != NULL);
941 g_return_if_fail (!gtk_text_mark_deleted (mark));
942 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
944 gtk_text_btree_get_iter_at_mark(get_btree (buffer),
950 gtk_text_buffer_delete_mark(GtkTextBuffer *buffer,
953 g_return_if_fail (mark != NULL);
954 g_return_if_fail (!gtk_text_mark_deleted (mark));
955 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
957 gtk_text_btree_remove_mark (get_btree (buffer), mark);
959 /* See rationale above for MARK_SET on why we emit this after
960 removing the mark, rather than removing the mark in a default
962 gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_DELETED],
967 gtk_text_buffer_get_mark (GtkTextBuffer *buffer,
972 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
973 g_return_val_if_fail(name != NULL, NULL);
975 mark = gtk_text_btree_get_mark_by_name(get_btree (buffer), name);
981 * gtk_text_buffer_place_cursor:
982 * @buffer: a #GtkTextBuffer
983 * @where: where to put the cursor
985 * This function moves the "insert" and "selection_bound" marks
986 * simultaneously. If you move them to the same place in two steps
987 * with gtk_text_buffer_move_mark(), you will temporarily select a
988 * region in between their old and new locations, which marks part of
989 * the buffer invalid and can be inefficient. This function moves
990 * them as a unit, which can be optimized.
993 gtk_text_buffer_place_cursor (GtkTextBuffer *buffer,
994 const GtkTextIter *where)
998 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1002 if (gtk_text_iter_is_last (&real))
1003 gtk_text_iter_prev_char (&real);
1005 gtk_text_btree_place_cursor(get_btree (buffer), &real);
1006 gtk_text_buffer_mark_set (buffer, &real,
1007 gtk_text_buffer_get_mark (buffer,
1009 gtk_text_buffer_mark_set (buffer, &real,
1010 gtk_text_buffer_get_mark (buffer,
1011 "selection_bound"));
1019 * gtk_text_buffer_create_tag:
1020 * @buffer: a #GtkTextBuffer
1021 * @tag_name: name of the new tag, or %NULL
1023 * Creates a tag and adds it to the tag table for @buffer.
1024 * Equivalent to calling gtk_text_tag_new() and then adding the
1025 * tag to the buffer's tag table. The returned tag has its refcount
1026 * incremented, as if you'd called gtk_text_tag_new().
1028 * If @tag_name is %NULL, the tag is anonymous.
1030 * Return value: a new tag
1033 gtk_text_buffer_create_tag(GtkTextBuffer *buffer,
1034 const gchar *tag_name)
1038 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
1040 tag = gtk_text_tag_new(tag_name);
1042 gtk_text_tag_table_add(get_table (buffer), tag);
1048 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
1050 const GtkTextIter *start,
1051 const GtkTextIter *end)
1053 gtk_text_btree_tag(start, end, tag, TRUE);
1057 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
1059 const GtkTextIter *start,
1060 const GtkTextIter *end)
1062 gtk_text_btree_tag(start, end, tag, FALSE);
1067 gtk_text_buffer_emit_tag(GtkTextBuffer *buffer,
1070 const GtkTextIter *start,
1071 const GtkTextIter *end)
1073 g_return_if_fail(tag != NULL);
1076 gtk_signal_emit(GTK_OBJECT(buffer), signals[APPLY_TAG],
1079 gtk_signal_emit(GTK_OBJECT(buffer), signals[REMOVE_TAG],
1085 gtk_text_buffer_apply_tag(GtkTextBuffer *buffer,
1087 const GtkTextIter *start,
1088 const GtkTextIter *end)
1090 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1091 g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1092 g_return_if_fail(start != NULL);
1093 g_return_if_fail(end != NULL);
1095 gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1099 gtk_text_buffer_remove_tag(GtkTextBuffer *buffer,
1101 const GtkTextIter *start,
1102 const GtkTextIter *end)
1105 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1106 g_return_if_fail(GTK_IS_TEXT_TAG (tag));
1107 g_return_if_fail(start != NULL);
1108 g_return_if_fail(end != NULL);
1110 gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1115 gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer,
1117 const GtkTextIter *start,
1118 const GtkTextIter *end)
1122 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1123 g_return_if_fail(name != NULL);
1124 g_return_if_fail(start != NULL);
1125 g_return_if_fail(end != NULL);
1127 tag = gtk_text_tag_table_lookup(get_table (buffer),
1132 g_warning("Unknown tag `%s'", name);
1136 gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end);
1140 gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
1142 const GtkTextIter *start,
1143 const GtkTextIter *end)
1147 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1148 g_return_if_fail(name != NULL);
1149 g_return_if_fail(start != NULL);
1150 g_return_if_fail(end != NULL);
1152 tag = gtk_text_tag_table_lookup(get_table (buffer),
1157 g_warning("Unknown tag `%s'", name);
1161 gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end);
1166 * Obtain various iterators
1170 gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
1175 g_return_if_fail(iter != NULL);
1176 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1178 gtk_text_btree_get_iter_at_line_char(get_btree (buffer),
1179 iter, line_number, char_offset);
1183 gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer,
1187 g_return_if_fail(iter != NULL);
1188 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1190 gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0);
1194 gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buffer,
1198 g_return_if_fail(iter != NULL);
1199 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1201 gtk_text_btree_get_iter_at_char(get_btree (buffer), iter, char_offset);
1205 gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer,
1208 g_return_if_fail(iter != NULL);
1209 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1211 gtk_text_btree_get_last_iter(get_btree (buffer), iter);
1215 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1219 g_return_if_fail(start != NULL);
1220 g_return_if_fail(end != NULL);
1221 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1223 gtk_text_btree_get_iter_at_char(get_btree (buffer), start, 0);
1224 gtk_text_btree_get_last_iter(get_btree (buffer), end);
1232 gtk_text_buffer_modified (GtkTextBuffer *buffer)
1234 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
1236 return buffer->modified;
1240 gtk_text_buffer_set_modified (GtkTextBuffer *buffer,
1243 gboolean fixed_setting;
1245 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1247 fixed_setting = setting != FALSE;
1249 if (buffer->modified == fixed_setting)
1253 buffer->modified = fixed_setting;
1254 gtk_signal_emit(GTK_OBJECT(buffer), signals[MODIFIED_CHANGED]);
1260 * Assorted other stuff
1264 gtk_text_buffer_get_line_count(GtkTextBuffer *buffer)
1266 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1268 return gtk_text_btree_line_count(get_btree (buffer));
1272 gtk_text_buffer_get_char_count(GtkTextBuffer *buffer)
1274 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1276 return gtk_text_btree_char_count(get_btree (buffer));
1280 gtk_text_buffer_get_tags (GtkTextBuffer *buffer,
1281 const GtkTextIter *iter)
1283 GSList *retval = NULL;
1287 tags = gtk_text_btree_get_tags(iter, &count);
1293 gtk_text_tag_array_sort(tags, count);
1298 retval = g_slist_prepend(retval, tags[i]);
1302 retval = g_slist_reverse(retval);
1311 /* Called when we lose the primary selection.
1314 clipboard_clear_cb (GtkClipboard *clipboard,
1317 /* Move selection_bound to the insertion point */
1319 GtkTextIter selection_bound;
1320 GtkTextBuffer *buffer = GTK_TEXT_BUFFER (data);
1322 gtk_text_buffer_get_iter_at_mark(buffer, &insert,
1323 gtk_text_buffer_get_mark (buffer, "insert"));
1324 gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound,
1325 gtk_text_buffer_get_mark (buffer, "selection_bound"));
1327 if (!gtk_text_iter_equal(&insert, &selection_bound))
1328 gtk_text_buffer_move_mark(buffer,
1329 gtk_text_buffer_get_mark (buffer, "selection_bound"),
1333 /* Called when we have the primary selection and someone else wants our
1334 * data in order to paste it.
1337 clipboard_get_cb (GtkClipboard *clipboard,
1338 GtkSelectionData *selection_data,
1342 GtkTextBuffer *buffer = GTK_TEXT_BUFFER(data);
1344 GtkTextIter start, end;
1346 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1348 /* Extract the selected text */
1349 str = gtk_text_iter_get_visible_text(&start, &end);
1350 gtk_selection_data_set_text (selection_data, str);
1355 /* Called when we request a paste and receive the data
1358 clipboard_received (GtkClipboard *clipboard,
1362 ClipboardRequest *request_data = data;
1363 GtkTextBuffer *buffer = request_data->buffer;
1368 GtkTextIter insert_point;
1369 GtkTextMark *paste_point_override;
1371 paste_point_override = gtk_text_buffer_get_mark (buffer,
1372 "__paste_point_override");
1374 if (paste_point_override != NULL)
1376 gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1377 paste_point_override);
1378 gtk_text_buffer_delete_mark(buffer,
1379 gtk_text_buffer_get_mark (buffer,
1380 "__paste_point_override"));
1384 gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1385 gtk_text_buffer_get_mark (buffer,
1391 /* FIXME ALL OF THIS - I think that the "best method" is that when pasting
1392 * with the cursor inside the selection area, you replace the selection
1393 * with the new text, otherwise, you simply insert the new text at
1394 * the point where the click occured, unselecting any selected text.
1396 * This probably is best implemented as a "replace_selection" flag in
1400 if ((TRUE/* Text is selected FIXME */) &&
1401 (!buffer->have_selection || request_data->is_clipboard))
1405 if (buffer->have_selection)
1407 /* FIXME Delete currently-selected chars but don't give up X
1408 selection since we'll use the newly-pasted stuff as
1409 a new X selection */
1413 ; /* FIXME Delete selected chars and give up X selection */
1418 if (request_data->interactive)
1419 gtk_text_buffer_insert_interactive (buffer, &insert_point,
1420 str, -1, request_data->default_editable);
1422 gtk_text_buffer_insert (buffer, &insert_point,
1426 ; /* FIXME Select the region of text we just inserted */
1429 g_object_unref (G_OBJECT (buffer));
1430 g_free (request_data);
1434 gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer)
1436 static const GtkTargetEntry targets[] = {
1437 { "STRING", 0, TARGET_STRING },
1438 { "TEXT", 0, TARGET_TEXT },
1439 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
1440 { "UTF8_STRING", 0, TARGET_UTF8_STRING }
1446 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
1448 /* Determine whether we have a selection and adjust X selection
1452 if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
1454 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (buffer))
1455 gtk_clipboard_clear (clipboard);
1459 /* Even if we already have the selection, we need to update our
1462 if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
1463 clipboard_get_cb, clipboard_clear_cb, G_OBJECT (buffer)))
1464 clipboard_clear_cb (clipboard, buffer);
1469 paste (GtkTextBuffer *buffer,
1470 gboolean is_clipboard,
1471 gboolean interactive,
1472 gboolean default_editable)
1474 ClipboardRequest *data = g_new (ClipboardRequest, 1);
1476 data->buffer = buffer;
1477 g_object_ref (G_OBJECT (buffer));
1478 data->interactive = interactive;
1479 data->default_editable = default_editable;
1481 gtk_clipboard_request_text (gtk_clipboard_get (is_clipboard ? GDK_NONE : GDK_SELECTION_PRIMARY),
1482 clipboard_received, data);
1486 gtk_text_buffer_paste_primary (GtkTextBuffer *buffer,
1487 GtkTextIter *override_location,
1488 gboolean default_editable)
1490 if (override_location != NULL)
1491 gtk_text_buffer_create_mark(buffer,
1492 "__paste_point_override",
1493 override_location, FALSE);
1495 paste (buffer, FALSE, TRUE, default_editable);
1499 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
1500 gboolean default_editable)
1502 paste (buffer, TRUE, TRUE, default_editable);
1506 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
1507 gboolean interactive,
1508 gboolean default_editable)
1513 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1515 return FALSE; /* No selection */
1520 gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
1522 gtk_text_buffer_delete (buffer, &start, &end);
1524 return TRUE; /* We deleted stuff */
1529 cut_or_copy(GtkTextBuffer *buffer,
1530 gboolean delete_region_after,
1531 gboolean interactive,
1532 gboolean default_editable)
1534 /* We prefer to cut the selected region between selection_bound and
1535 insertion point. If that region is empty, then we cut the region
1536 between the "anchor" and the insertion point (this is for C-space
1537 and M-w and other Emacs-style copy/yank keys). Note that insert
1538 and selection_bound are guaranteed to exist, but the anchor only
1539 exists sometimes. */
1543 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1545 /* Let's try the anchor thing */
1546 GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
1552 gtk_text_buffer_get_iter_at_mark(buffer, &end, anchor);
1553 gtk_text_iter_reorder(&start, &end);
1557 if (!gtk_text_iter_equal(&start, &end))
1559 GtkClipboard *clipboard = gtk_clipboard_get (GDK_NONE);
1562 text = gtk_text_iter_get_visible_text (&start, &end);
1563 gtk_clipboard_set_text (clipboard, text, -1);
1566 if (delete_region_after)
1569 gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
1571 gtk_text_buffer_delete (buffer, &start, &end);
1577 gtk_text_buffer_cut_clipboard (GtkTextBuffer *buffer,
1578 gboolean default_editable)
1580 cut_or_copy (buffer, TRUE, TRUE, default_editable);
1584 gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer)
1586 cut_or_copy (buffer, FALSE, TRUE, TRUE);
1591 gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer,
1595 g_return_val_if_fail (buffer != NULL, FALSE);
1596 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1598 return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end);
1607 gtk_text_buffer_spew(GtkTextBuffer *buffer)
1609 gtk_text_btree_spew(get_btree (buffer));