1 /* gtktextbuffer.c - the "model" in the MVC text widget architecture
2 * Copyright (c) 2000 Red Hat, Inc.
3 * Developed by Havoc Pennington
6 #include "gtkinvisible.h"
7 #include "gtkselection.h"
9 #include "gtktextbuffer.h"
10 #include "gtktextbtree.h"
11 #include "gtktextiterprivate.h"
37 static void gtk_text_buffer_init (GtkTextBuffer *tkxt_buffer);
38 static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
39 static void gtk_text_buffer_destroy (GtkObject *object);
40 static void gtk_text_buffer_finalize (GObject *object);
43 static void gtk_text_buffer_update_primary_selection (GtkTextBuffer *buffer);
44 static void gtk_text_buffer_update_clipboard_selection (GtkTextBuffer *buffer);
45 static void gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
49 static void gtk_text_buffer_real_delete_text (GtkTextBuffer *buffer,
52 static void gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
54 const GtkTextIter *start_char,
55 const GtkTextIter *end_char);
56 static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
58 const GtkTextIter *start_char,
59 const GtkTextIter *end_char);
62 void gtk_marshal_NONE__INT_POINTER_INT (GtkObject *object,
67 static GdkAtom clipboard_atom = GDK_NONE;
68 static GdkAtom text_atom = GDK_NONE;
69 static GdkAtom ctext_atom = GDK_NONE;
70 static GdkAtom utf8_atom = GDK_NONE;
72 static GtkObjectClass *parent_class = NULL;
73 static guint signals[LAST_SIGNAL] = { 0 };
76 gtk_text_buffer_get_type (void)
78 static GtkType our_type = 0;
82 static const GtkTypeInfo our_info =
85 sizeof (GtkTextBuffer),
86 sizeof (GtkTextBufferClass),
87 (GtkClassInitFunc) gtk_text_buffer_class_init,
88 (GtkObjectInitFunc) gtk_text_buffer_init,
89 /* reserved_1 */ NULL,
90 /* reserved_2 */ NULL,
91 (GtkClassInitFunc) NULL
94 our_type = gtk_type_unique (GTK_TYPE_OBJECT, &our_info);
101 gtk_text_buffer_class_init (GtkTextBufferClass *klass)
103 GtkObjectClass *object_class = (GtkObjectClass*) klass;
104 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
106 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
108 signals[INSERT_TEXT] =
109 gtk_signal_new ("insert_text",
111 GTK_CLASS_TYPE (object_class),
112 GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text),
113 gtk_marshal_NONE__INT_POINTER_INT,
120 signals[DELETE_TEXT] =
121 gtk_signal_new ("delete_text",
123 GTK_CLASS_TYPE (object_class),
124 GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text),
125 gtk_marshal_NONE__INT_INT,
132 gtk_signal_new ("changed",
134 GTK_CLASS_TYPE (object_class),
135 GTK_SIGNAL_OFFSET (GtkTextBufferClass, changed),
136 gtk_marshal_NONE__NONE,
140 signals[MODIFIED_CHANGED] =
141 gtk_signal_new ("modified_changed",
143 GTK_CLASS_TYPE (object_class),
144 GTK_SIGNAL_OFFSET (GtkTextBufferClass, modified_changed),
145 gtk_marshal_NONE__NONE,
150 gtk_signal_new ("mark_set",
152 GTK_CLASS_TYPE (object_class),
153 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_set),
154 gtk_marshal_NONE__POINTER_POINTER,
160 signals[MARK_DELETED] =
161 gtk_signal_new ("mark_deleted",
163 GTK_CLASS_TYPE (object_class),
164 GTK_SIGNAL_OFFSET (GtkTextBufferClass, mark_deleted),
165 gtk_marshal_NONE__POINTER,
171 gtk_signal_new ("apply_tag",
173 GTK_CLASS_TYPE (object_class),
174 GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag),
175 gtk_marshal_NONE__POINTER_INT_INT,
182 signals[REMOVE_TAG] =
183 gtk_signal_new ("remove_tag",
185 GTK_CLASS_TYPE (object_class),
186 GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag),
187 gtk_marshal_NONE__POINTER_INT_INT,
194 gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
196 object_class->destroy = gtk_text_buffer_destroy;
198 gobject_class->finalize = gtk_text_buffer_finalize;
200 klass->insert_text = gtk_text_buffer_real_insert_text;
201 klass->delete_text = gtk_text_buffer_real_delete_text;
202 klass->apply_tag = gtk_text_buffer_real_apply_tag;
203 klass->remove_tag = gtk_text_buffer_real_remove_tag;
207 typedef gint (*GtkSignal_NONE__INT_POINTER_INT) (GtkObject *object,
214 gtk_marshal_NONE__INT_POINTER_INT (GtkObject *object,
219 GtkSignal_NONE__INT_POINTER_INT rfunc;
221 rfunc = (GtkSignal_NONE__INT_POINTER_INT) func;
224 GTK_VALUE_INT (args[0]),
225 GTK_VALUE_POINTER (args[1]),
226 GTK_VALUE_INT (args[2]),
231 gtk_text_buffer_init (GtkTextBuffer *buffer)
233 static const GtkTargetEntry targets[] = {
234 { "STRING", 0, TARGET_STRING },
235 { "TEXT", 0, TARGET_TEXT },
236 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
237 { "UTF8_STRING", 0, TARGET_UTF8_STRING }
239 static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
242 clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
245 text_atom = gdk_atom_intern ("TEXT", FALSE);
248 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
251 utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
253 buffer->selection_widget = gtk_invisible_new();
255 gtk_selection_add_targets (buffer->selection_widget,
256 GDK_SELECTION_PRIMARY,
258 gtk_selection_add_targets (buffer->selection_widget,
264 gtk_text_buffer_new (GtkTextTagTable *table)
266 GtkTextBuffer *text_buffer;
268 /* This is broken, need construct_only argument for the tag table
269 so language bindings can set it.
272 text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ()));
275 text_buffer->tag_table = table;
277 text_buffer->tag_table = gtk_text_tag_table_new();
279 gtk_object_ref (GTK_OBJECT(text_buffer->tag_table));
280 gtk_object_sink (GTK_OBJECT(text_buffer->tag_table));
282 text_buffer->tree = gtk_text_btree_new(text_buffer->tag_table,
289 gtk_text_buffer_destroy (GtkObject *object)
291 GtkTextBuffer *buffer;
293 buffer = GTK_TEXT_BUFFER (object);
295 gtk_widget_destroy(buffer->selection_widget);
296 buffer->selection_widget = NULL;
298 gtk_object_unref(GTK_OBJECT(buffer->tag_table));
299 buffer->tag_table = NULL;
301 gtk_text_btree_unref(buffer->tree);
304 (* parent_class->destroy) (object);
308 gtk_text_buffer_finalize (GObject *object)
310 GtkTextBuffer *tkxt_buffer;
312 tkxt_buffer = GTK_TEXT_BUFFER (object);
314 G_OBJECT_CLASS (parent_class)->finalize (object);
322 gtk_text_buffer_real_insert_text(GtkTextBuffer *buffer,
327 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
328 g_return_if_fail(iter != NULL);
330 gtk_text_btree_insert(iter, text, len);
332 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
334 gtk_text_buffer_set_modified(buffer, TRUE);
338 gtk_text_buffer_emit_insert(GtkTextBuffer *buffer,
343 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
344 g_return_if_fail(iter != NULL);
345 g_return_if_fail(text != NULL);
352 gtk_signal_emit(GTK_OBJECT(buffer), signals[INSERT_TEXT],
358 gtk_text_buffer_insert (GtkTextBuffer *buffer,
363 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
364 g_return_if_fail(iter != NULL);
365 g_return_if_fail(text != NULL);
367 gtk_text_buffer_emit_insert(buffer, iter, text, len);
371 gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer,
377 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
378 g_return_if_fail(text != NULL);
380 gtk_text_buffer_get_iter_at_mark(buffer, &iter,
381 gtk_text_buffer_get_mark (buffer,
384 gtk_text_buffer_insert(buffer, &iter, text, len);
388 gtk_text_buffer_insert_at_char (GtkTextBuffer *buffer,
395 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
396 g_return_if_fail(text != NULL);
398 gtk_text_buffer_get_iter_at_char(buffer, &iter, char_pos);
400 gtk_text_buffer_insert(buffer, &iter, text, len);
404 gtk_text_buffer_insert_after_line(GtkTextBuffer *buffer,
405 gint after_this_line,
411 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
412 g_return_if_fail(text != NULL);
414 gtk_text_buffer_get_iter_at_line(buffer,
418 /* Start of the next line */
419 gtk_text_iter_forward_line(&line);
421 gtk_text_buffer_insert(buffer, &line, text, len);
429 gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer,
433 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
434 g_return_if_fail(start != NULL);
435 g_return_if_fail(end != NULL);
437 gtk_text_btree_delete(start, end);
439 /* may have deleted the selection... */
440 gtk_text_buffer_update_primary_selection(buffer);
442 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
444 gtk_text_buffer_set_modified(buffer, TRUE);
448 gtk_text_buffer_emit_delete(GtkTextBuffer *buffer,
452 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
453 g_return_if_fail(start != NULL);
454 g_return_if_fail(end != NULL);
456 if (gtk_text_iter_equal(start, end))
459 gtk_signal_emit(GTK_OBJECT(buffer),
460 signals[DELETE_TEXT],
465 gtk_text_buffer_delete (GtkTextBuffer *buffer,
469 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
470 g_return_if_fail(start != NULL);
471 g_return_if_fail(end != NULL);
473 gtk_text_buffer_emit_delete(buffer, start, end);
477 gtk_text_buffer_delete_chars (GtkTextBuffer *buffer,
484 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
486 if (start_char == end_char)
489 gtk_text_buffer_get_iter_at_char(buffer, &start, start_char);
490 gtk_text_buffer_get_iter_at_char(buffer, &end, end_char);
492 gtk_text_buffer_emit_delete(buffer, &start, &end);
496 gtk_text_buffer_delete_lines(GtkTextBuffer *buffer,
503 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
505 if (start_line == end_line)
508 /* start of the start line */
509 gtk_text_buffer_get_iter_at_line(buffer, &start, start_line);
511 /* start of the end line; note that we don't delete the end_line, we
512 want to delete up to the start of it */
513 gtk_text_buffer_get_iter_at_line(buffer, &end, end_line);
515 gtk_text_buffer_delete (buffer, &start, &end);
519 gtk_text_buffer_delete_from_line(GtkTextBuffer *buffer,
521 gint start_char, gint end_char)
526 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
528 if (start_char == end_char)
531 gtk_text_buffer_get_iter_at_line_char(buffer, &start, line, start_char);
532 gtk_text_buffer_get_iter_at_line_char(buffer, &end, line, end_char);
534 gtk_text_buffer_delete(buffer, &start, &end);
538 * Extracting textual buffer contents
542 gtk_text_buffer_get_text (GtkTextBuffer *buffer,
543 const GtkTextIter *start,
544 const GtkTextIter *end,
545 gboolean include_hidden_chars)
547 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
548 g_return_val_if_fail(start != NULL, NULL);
549 g_return_val_if_fail(end != NULL, NULL);
551 if (include_hidden_chars)
552 return gtk_text_iter_get_text(start, end);
554 return gtk_text_iter_get_visible_text(start, end);
558 gtk_text_buffer_get_text_chars (GtkTextBuffer *buffer,
561 gboolean include_hidden_chars)
566 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
568 if (start_char == end_char)
571 gtk_text_buffer_get_iter_at_char (buffer, &start, start_char);
572 gtk_text_buffer_get_iter_at_char (buffer, &end, end_char);
574 return gtk_text_buffer_get_text(buffer, &start, &end,
575 include_hidden_chars);
579 gtk_text_buffer_get_text_from_line (GtkTextBuffer *buffer,
583 gboolean include_hidden_chars)
588 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
590 if (start_char == end_char)
593 gtk_text_buffer_get_iter_at_line_char (buffer, &start, line, start_char);
594 gtk_text_buffer_get_iter_at_line_char (buffer, &end, line, end_char);
596 return gtk_text_buffer_get_text(buffer, &start, &end,
597 include_hidden_chars);
601 gtk_text_buffer_get_slice (GtkTextBuffer *buffer,
602 const GtkTextIter *start,
603 const GtkTextIter *end,
604 gboolean include_hidden_chars)
606 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
607 g_return_val_if_fail(start != NULL, NULL);
608 g_return_val_if_fail(end != NULL, NULL);
610 if (include_hidden_chars)
611 return gtk_text_iter_get_slice(start, end);
613 return gtk_text_iter_get_visible_slice(start, end);
617 gtk_text_buffer_get_slice_chars (GtkTextBuffer *buffer,
620 gboolean include_hidden_chars)
625 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
627 if (start_char == end_char)
630 gtk_text_buffer_get_iter_at_char (buffer, &start, start_char);
631 gtk_text_buffer_get_iter_at_char (buffer, &end, end_char);
633 return gtk_text_buffer_get_slice(buffer, &start, &end,
634 include_hidden_chars);
638 gtk_text_buffer_get_slice_from_line (GtkTextBuffer *buffer,
642 gboolean include_hidden_chars)
647 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
649 if (start_char == end_char)
652 gtk_text_buffer_get_iter_at_line_char (buffer, &start, line, start_char);
653 gtk_text_buffer_get_iter_at_line_char (buffer, &end, line, end_char);
655 return gtk_text_buffer_get_slice(buffer, &start, &end,
656 include_hidden_chars);
664 gtk_text_buffer_insert_pixmap (GtkTextBuffer *buffer,
669 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
670 g_return_if_fail(iter != NULL);
671 g_return_if_fail(pixmap != NULL);
673 gtk_text_btree_insert_pixmap(iter, pixmap, mask);
675 /* FIXME pixmap-specific signal like insert_text */
677 gtk_signal_emit(GTK_OBJECT(buffer), signals[CHANGED]);
679 gtk_text_buffer_set_modified(buffer, TRUE);
683 gtk_text_buffer_insert_pixmap_at_char (GtkTextBuffer *buffer,
690 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
691 g_return_if_fail(pixmap != NULL);
693 gtk_text_buffer_get_iter_at_char(buffer, &iter, char_pos);
695 gtk_text_buffer_insert_pixmap(buffer, &iter, pixmap, mask);
703 gtk_text_buffer_mark_set (GtkTextBuffer *buffer,
704 const GtkTextIter *location,
707 /* IMO this should NOT work like insert_text and delete_text,
708 where the real action happens in the default handler.
710 The reason is that the default handler would be _required_,
711 i.e. the whole widget would start breaking and segfaulting
712 if the default handler didn't get run. So you can't really
713 override the default handler or stop the emission; that is,
714 this signal is purely for notification, and not to allow users
715 to modify the default behavior. */
716 gtk_signal_emit(GTK_OBJECT(buffer),
724 * gtk_text_buffer_set_mark:
725 * @buffer: a #GtkTextBuffer
726 * @mark_name: name of the mark
727 * @iter: location for the mark.
728 * @left_gravity: if the mark is created by this function, gravity for the new
730 * @should_exist: if %TRUE, warn if the mark does not exist, and return
733 * Move the mark to the given position, if not @should_exist, create the mark.
738 gtk_text_buffer_set_mark(GtkTextBuffer *buffer,
739 GtkTextMark *existing_mark,
740 const gchar *mark_name,
741 const GtkTextIter *iter,
742 gboolean left_gravity,
743 gboolean should_exist)
745 GtkTextIter location;
748 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
750 mark = gtk_text_btree_set_mark(buffer->tree,
757 if (gtk_text_btree_mark_is_insert(buffer->tree, mark) ||
758 gtk_text_btree_mark_is_selection_bound(buffer->tree, mark))
760 gtk_text_buffer_update_primary_selection(buffer);
763 gtk_text_btree_get_iter_at_mark(buffer->tree,
767 gtk_text_buffer_mark_set (buffer, &location, mark);
769 return (GtkTextMark*)mark;
773 gtk_text_buffer_create_mark(GtkTextBuffer *buffer,
774 const gchar *mark_name,
775 const GtkTextIter *where,
776 gboolean left_gravity)
778 return gtk_text_buffer_set_mark(buffer, NULL, mark_name, where,
779 left_gravity, FALSE);
783 gtk_text_buffer_move_mark(GtkTextBuffer *buffer,
785 const GtkTextIter *where)
787 g_return_if_fail (mark != NULL);
789 gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE);
793 gtk_text_buffer_get_iter_at_mark(GtkTextBuffer *buffer,
797 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
799 gtk_text_btree_get_iter_at_mark(buffer->tree,
805 gtk_text_buffer_delete_mark(GtkTextBuffer *buffer,
808 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
810 gtk_text_btree_remove_mark (buffer->tree, mark);
812 /* See rationale above for MARK_SET on why we emit this after
813 removing the mark, rather than removing the mark in a default
815 gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_DELETED],
820 gtk_text_buffer_get_mark (GtkTextBuffer *buffer,
825 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
826 g_return_val_if_fail(name != NULL, NULL);
828 mark = gtk_text_btree_get_mark_by_name(buffer->tree, name);
834 gtk_text_buffer_place_cursor (GtkTextBuffer *buffer,
835 const GtkTextIter *where)
837 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
839 gtk_text_btree_place_cursor(buffer->tree, where);
840 gtk_text_buffer_mark_set (buffer, where,
841 gtk_text_buffer_get_mark (buffer,
843 gtk_text_buffer_mark_set (buffer, where,
844 gtk_text_buffer_get_mark (buffer,
853 gtk_text_buffer_create_tag(GtkTextBuffer *buffer,
854 const gchar *tag_name)
858 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL);
859 g_return_val_if_fail(tag_name != NULL, NULL);
861 tag = gtk_text_tag_new(tag_name);
863 gtk_text_tag_table_add(buffer->tag_table, tag);
869 gtk_text_buffer_real_apply_tag (GtkTextBuffer *buffer,
871 const GtkTextIter *start,
872 const GtkTextIter *end)
874 gtk_text_btree_tag(start, end, tag, TRUE);
878 gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer,
880 const GtkTextIter *start,
881 const GtkTextIter *end)
883 gtk_text_btree_tag(start, end, tag, FALSE);
888 gtk_text_buffer_emit_tag(GtkTextBuffer *buffer,
891 const GtkTextIter *start,
892 const GtkTextIter *end)
896 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
897 g_return_if_fail(name != NULL);
898 g_return_if_fail(start != NULL);
899 g_return_if_fail(end != NULL);
901 tag = gtk_text_tag_table_lookup(buffer->tag_table,
906 g_warning("Unknown tag `%s'", name);
911 gtk_signal_emit(GTK_OBJECT(buffer), signals[APPLY_TAG],
914 gtk_signal_emit(GTK_OBJECT(buffer), signals[REMOVE_TAG],
920 gtk_text_buffer_apply_tag(GtkTextBuffer *buffer,
922 const GtkTextIter *start,
923 const GtkTextIter *end)
925 gtk_text_buffer_emit_tag(buffer, name, TRUE, start, end);
929 gtk_text_buffer_remove_tag(GtkTextBuffer *buffer,
931 const GtkTextIter *start,
932 const GtkTextIter *end)
935 gtk_text_buffer_emit_tag(buffer, name, FALSE, start, end);
939 gtk_text_buffer_apply_tag_to_chars(GtkTextBuffer *buffer,
941 gint start_char, gint end_char)
946 gtk_text_buffer_get_iter_at_char(buffer, &start, start_char);
947 gtk_text_buffer_get_iter_at_char(buffer, &end, end_char);
949 gtk_text_buffer_apply_tag(buffer, name, &start, &end);
953 gtk_text_buffer_remove_tag_from_chars(GtkTextBuffer *buffer,
955 gint start_char, gint end_char)
960 gtk_text_buffer_get_iter_at_char(buffer, &start, start_char);
961 gtk_text_buffer_get_iter_at_char(buffer, &end, end_char);
963 gtk_text_buffer_remove_tag(buffer, name, &start, &end);
967 * Obtain various iterators
971 gtk_text_buffer_get_iter_at_line_char (GtkTextBuffer *buffer,
976 g_return_if_fail(iter != NULL);
977 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
979 gtk_text_btree_get_iter_at_line_char(buffer->tree,
980 iter, line_number, char_number);
984 gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer,
988 g_return_if_fail(iter != NULL);
989 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
991 gtk_text_buffer_get_iter_at_line_char(buffer, iter, line_number, 0);
995 gtk_text_buffer_get_iter_at_char (GtkTextBuffer *buffer,
999 g_return_if_fail(iter != NULL);
1000 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1002 gtk_text_btree_get_iter_at_char(buffer->tree, iter, char_index);
1006 gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer,
1009 g_return_if_fail(iter != NULL);
1010 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1012 gtk_text_btree_get_last_iter(buffer->tree, iter);
1016 gtk_text_buffer_get_bounds (GtkTextBuffer *buffer,
1020 g_return_if_fail(start != NULL);
1021 g_return_if_fail(end != NULL);
1022 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1024 gtk_text_btree_get_iter_at_char(buffer->tree, start, 0);
1025 gtk_text_btree_get_last_iter(buffer->tree, end);
1030 gtk_text_buffer_get_iter_from_string(GtkTextBuffer *buffer,
1032 const gchar *index_string)
1034 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
1036 return gtk_text_btree_get_iter_from_string(buffer->tree,
1046 gtk_text_buffer_modified (GtkTextBuffer *buffer)
1048 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE);
1050 return buffer->modified;
1054 gtk_text_buffer_set_modified (GtkTextBuffer *buffer,
1057 gboolean fixed_setting;
1059 g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
1061 fixed_setting = setting != FALSE;
1063 if (buffer->modified == fixed_setting)
1067 buffer->modified = fixed_setting;
1068 gtk_signal_emit(GTK_OBJECT(buffer), signals[MODIFIED_CHANGED]);
1078 set_clipboard_contents_nocopy(GtkTextBuffer *buffer,
1081 if (text && *text == '\0')
1087 if (buffer->clipboard_text != NULL)
1088 g_free(buffer->clipboard_text);
1090 buffer->clipboard_text = text;
1092 gtk_text_buffer_update_clipboard_selection(buffer);
1096 gtk_text_buffer_set_clipboard_contents (GtkTextBuffer *buffer,
1099 set_clipboard_contents_nocopy(buffer, text ? g_strdup(text) : NULL);
1103 gtk_text_buffer_get_clipboard_contents (GtkTextBuffer *buffer)
1105 return buffer->clipboard_text;
1109 * Assorted other stuff
1113 gtk_text_buffer_get_line_count(GtkTextBuffer *buffer)
1115 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1117 return gtk_text_btree_line_count(buffer->tree);
1121 gtk_text_buffer_get_char_count(GtkTextBuffer *buffer)
1123 g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0);
1125 return gtk_text_btree_char_count(buffer->tree);
1129 gtk_text_buffer_get_tags (GtkTextBuffer *buffer,
1130 const GtkTextIter *iter)
1132 GSList *retval = NULL;
1136 tags = gtk_text_btree_get_tags(iter, &count);
1142 gtk_text_tag_array_sort(tags, count);
1147 retval = g_slist_prepend(retval, tags[i]);
1151 retval = g_slist_reverse(retval);
1165 have_primary_x_selection(GtkWidget *widget)
1167 return (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) ==
1172 request_primary_x_selection(GtkWidget *widget, guint32 time)
1174 return gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, time);
1178 release_primary_x_selection(GtkWidget *widget, guint32 time)
1180 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) ==
1183 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
1192 have_clipboard_x_selection(GtkWidget *widget)
1194 return (gdk_selection_owner_get (clipboard_atom) ==
1199 request_clipboard_x_selection(GtkWidget *widget, guint32 time)
1201 return gtk_selection_owner_set (widget, clipboard_atom, time);
1205 release_clipboard_x_selection(GtkWidget *widget, guint32 time)
1207 if (gdk_selection_owner_get (clipboard_atom) ==
1210 gtk_selection_owner_set (NULL, clipboard_atom, time);
1217 /* Called when we lose the selection */
1219 selection_clear_event(GtkWidget *widget, GdkEventSelection *event,
1222 GtkTextBuffer *buffer;
1224 buffer = GTK_TEXT_BUFFER(data);
1226 /* Let the selection handling code know that the selection
1227 * has been changed, since we've overriden the default handler */
1228 if (!gtk_selection_clear (widget, event))
1231 buffer->have_selection = FALSE;
1233 if (event->selection == GDK_SELECTION_PRIMARY)
1235 /* Move selection_bound to the insertion point */
1237 GtkTextIter selection_bound;
1239 gtk_text_buffer_get_iter_at_mark(buffer, &insert,
1240 gtk_text_buffer_get_mark (buffer, "insert"));
1241 gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound,
1242 gtk_text_buffer_get_mark (buffer, "selection_bound"));
1244 if (!gtk_text_iter_equal(&insert, &selection_bound))
1245 gtk_text_buffer_move_mark(buffer,
1246 gtk_text_buffer_get_mark (buffer, "selection_bound"),
1249 else if (event->selection == clipboard_atom)
1251 gtk_text_buffer_set_clipboard_contents(buffer, NULL);
1257 /* Called when we have the selection and someone else wants our
1258 data in order to paste it */
1260 selection_get (GtkWidget *widget,
1261 GtkSelectionData *selection_data,
1266 GtkTextBuffer *buffer;
1270 buffer = GTK_TEXT_BUFFER(data);
1272 if (selection_data->selection == GDK_SELECTION_PRIMARY)
1277 if (gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1279 /* Extract the selected text */
1280 str = gtk_text_iter_get_visible_text(&start, &end);
1282 length = strlen(str);
1291 cstr = gtk_text_buffer_get_clipboard_contents(buffer);
1296 str = g_strdup(cstr);
1298 length = strlen (str);
1303 if (info == TARGET_UTF8_STRING)
1306 gtk_selection_data_set (selection_data,
1308 8*sizeof(gchar), (guchar *)str, length);
1311 else if (info == TARGET_STRING ||
1312 info == TARGET_TEXT)
1316 latin1 = gtk_text_utf_to_latin1(str, length);
1318 gtk_selection_data_set (selection_data,
1319 GDK_SELECTION_TYPE_STRING,
1320 8*sizeof(gchar), latin1, strlen(latin1));
1323 else if (info == TARGET_COMPOUND_TEXT)
1325 /* FIXME convert UTF8 directly to current locale, not via
1334 latin1 = gtk_text_utf_to_latin1(str, length);
1336 gdk_string_to_compound_text (latin1, &encoding, &format, &text, &new_length);
1337 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
1338 gdk_free_compound_text (text);
1347 /* Called when we request a paste and receive the data */
1349 selection_received (GtkWidget *widget,
1350 GtkSelectionData *selection_data,
1354 GtkTextBuffer *buffer;
1356 GtkTextIter insert_point;
1357 GtkTextMark *paste_point_override;
1358 enum {INVALID, STRING, CTEXT, UTF8} type;
1360 g_return_if_fail (widget != NULL);
1362 buffer = GTK_TEXT_BUFFER(data);
1364 if (selection_data->type == GDK_TARGET_STRING)
1366 else if (selection_data->type == ctext_atom)
1368 else if (selection_data->type == utf8_atom)
1373 if (type == INVALID || selection_data->length < 0)
1375 /* If we asked for UTF8 and didn't get it, try text; if we asked
1376 for text and didn't get it, try string. If we asked for
1377 anything else and didn't get it, give up. */
1378 if (selection_data->target == utf8_atom)
1379 gtk_selection_convert (widget, selection_data->selection,
1380 GDK_TARGET_STRING, time);
1384 paste_point_override = gtk_text_buffer_get_mark (buffer,
1385 "__paste_point_override");
1387 if (paste_point_override != NULL)
1389 gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1390 paste_point_override);
1391 gtk_text_buffer_delete_mark(buffer,
1392 gtk_text_buffer_get_mark (buffer,
1393 "__paste_point_override"));
1397 gtk_text_buffer_get_iter_at_mark(buffer, &insert_point,
1398 gtk_text_buffer_get_mark (buffer,
1404 if ((TRUE/* Text is selected FIXME */) &&
1405 (!buffer->have_selection ||
1406 (selection_data->selection == clipboard_atom)))
1410 if (buffer->have_selection)
1412 /* FIXME Delete currently-selected chars but don't give up X
1413 selection since we'll use the newly-pasted stuff as
1414 a new X selection */
1418 ; /* FIXME Delete selected chars and give up X selection */
1427 utf = gtk_text_latin1_to_utf((const gchar*)selection_data->data,
1428 selection_data->length);
1429 gtk_text_buffer_insert (buffer, &insert_point,
1436 gtk_text_buffer_insert (buffer, &insert_point,
1437 (const gchar *)selection_data->data,
1438 selection_data->length);
1447 count = gdk_text_property_to_text_list (selection_data->type,
1448 selection_data->format,
1449 selection_data->data,
1450 selection_data->length,
1452 for (i=0; i<count; i++)
1454 /* FIXME this is broken, it assumes the CTEXT is latin1
1455 when it probably isn't. */
1458 utf = gtk_text_latin1_to_utf(list[i], strlen(list[i]));
1460 gtk_text_buffer_insert(buffer, &insert_point, utf, -1);
1466 gdk_free_text_list (list);
1470 case INVALID: /* quiet compiler */
1475 ; /* FIXME Select the region of text we just inserted */
1480 ensure_handlers(GtkTextBuffer *buffer)
1482 if (!buffer->selection_handlers_installed)
1484 buffer->selection_handlers_installed = TRUE;
1486 gtk_signal_connect(GTK_OBJECT(buffer->selection_widget),
1487 "selection_clear_event",
1488 GTK_SIGNAL_FUNC(selection_clear_event),
1491 gtk_signal_connect(GTK_OBJECT(buffer->selection_widget),
1492 "selection_received",
1493 GTK_SIGNAL_FUNC(selection_received),
1496 gtk_signal_connect(GTK_OBJECT(buffer->selection_widget),
1498 GTK_SIGNAL_FUNC(selection_get),
1503 /* FIXME GDK_CURRENT_TIME should probably go away and we should
1504 figure out how to get the events in here */
1506 gtk_text_buffer_update_primary_selection(GtkTextBuffer *buffer)
1511 ensure_handlers(buffer);
1513 /* Determine whether we have a selection and adjust X selection
1516 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1518 release_primary_x_selection(buffer->selection_widget, GDK_CURRENT_TIME);
1519 buffer->have_selection = FALSE;
1523 /* Even if we already have the selection, we need to update our
1525 buffer->have_selection = FALSE;
1526 request_primary_x_selection(buffer->selection_widget, GDK_CURRENT_TIME);
1527 if (have_primary_x_selection(buffer->selection_widget))
1528 buffer->have_selection = TRUE;
1533 gtk_text_buffer_update_clipboard_selection(GtkTextBuffer *buffer)
1535 if (buffer->clipboard_text == NULL ||
1536 buffer->clipboard_text[0] == '\0')
1538 release_clipboard_x_selection(buffer->selection_widget, GDK_CURRENT_TIME);
1542 /* Even if we already have the selection, we need to update our
1544 request_clipboard_x_selection(buffer->selection_widget, GDK_CURRENT_TIME);
1549 paste(GtkTextBuffer *buffer, GdkAtom selection, guint32 time)
1551 ensure_handlers(buffer);
1553 gtk_selection_convert (buffer->selection_widget, selection,
1558 gtk_text_buffer_paste_primary_selection(GtkTextBuffer *buffer,
1559 GtkTextIter *override_location,
1562 if (override_location != NULL)
1563 gtk_text_buffer_create_mark(buffer,
1564 "__paste_point_override",
1565 override_location, FALSE);
1567 paste(buffer, GDK_SELECTION_PRIMARY, time);
1571 gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer,
1574 paste(buffer, clipboard_atom, time);
1578 gtk_text_buffer_delete_selection (GtkTextBuffer *buffer)
1583 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1585 return FALSE; /* No selection */
1589 gtk_text_buffer_delete(buffer, &start, &end);
1590 gtk_text_buffer_update_primary_selection(buffer);
1591 return TRUE; /* We deleted stuff */
1596 cut_or_copy(GtkTextBuffer *buffer,
1598 gboolean delete_region_after)
1600 /* We prefer to cut the selected region between selection_bound and
1601 insertion point. If that region is empty, then we cut the region
1602 between the "anchor" and the insertion point (this is for C-space
1603 and M-w and other Emacs-style copy/yank keys). Note that insert
1604 and selection_bound are guaranteed to exist, but the anchor only
1605 exists sometimes. */
1609 if (!gtk_text_buffer_get_selection_bounds(buffer, &start, &end))
1611 /* Let's try the anchor thing */
1612 GtkTextMark * anchor = gtk_text_buffer_get_mark (buffer, "anchor");
1618 gtk_text_buffer_get_iter_at_mark(buffer, &end, anchor);
1619 gtk_text_iter_reorder(&start, &end);
1623 if (!gtk_text_iter_equal(&start, &end))
1627 text = gtk_text_iter_get_visible_text(&start, &end);
1629 set_clipboard_contents_nocopy(buffer, text);
1631 if (delete_region_after)
1632 gtk_text_buffer_delete(buffer, &start, &end);
1637 gtk_text_buffer_cut (GtkTextBuffer *buffer,
1640 cut_or_copy(buffer, time, TRUE);
1644 gtk_text_buffer_copy (GtkTextBuffer *buffer,
1647 cut_or_copy(buffer, time, FALSE);
1652 gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer,
1656 g_return_val_if_fail (buffer != NULL, FALSE);
1657 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
1659 return gtk_text_btree_get_selection_bounds (buffer->tree, start, end);
1668 gtk_text_buffer_spew(GtkTextBuffer *buffer)
1670 gtk_text_btree_spew(buffer->tree);