diff options
-rw-r--r-- | ChangeLog | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 48 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 48 | ||||
-rw-r--r-- | gtk/gtktextbtree.c | 43 | ||||
-rw-r--r-- | gtk/gtktextbuffer.c | 500 | ||||
-rw-r--r-- | gtk/gtktextbuffer.h | 51 | ||||
-rw-r--r-- | gtk/gtktextiter.c | 93 | ||||
-rw-r--r-- | gtk/gtktextmark.c | 208 | ||||
-rw-r--r-- | gtk/gtktextmark.h | 2 | ||||
-rw-r--r-- | gtk/gtktextsegment.h | 55 | ||||
-rw-r--r-- | gtk/gtktextview.c | 10 | ||||
-rw-r--r-- | gtk/testtext.c | 34 | ||||
-rw-r--r-- | tests/testtext.c | 34 |
17 files changed, 1047 insertions, 319 deletions
@@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 0b50514e9..7442c4411 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,51 @@ +2000-09-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextbtree.c (gtk_text_btree_get_selection_bounds): Handle + NULL start/end pointers + + * gtk/gtktextbuffer.c: Write some docs + (gtk_text_buffer_get_selection_bounds): Allow start/end to be + NULL, so you can just check whether there's a selection. + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): No need to + cleanup_line or segments_changed ourselves, it gets done + in unlink_segment + + * gtk/gtktextmark.h: + s/gtk_text_mark_deleted/gtk_text_mark_get_deleted/ + + * gtk/gtktextsegment.h: Clean up some indentation and naming mess + + * gtk/gtktextmark.c: delete some more old Tk cruft + + * gtk/gtktextbuffer.c (gtk_text_buffer_delete_mark): add ref to + mark before removing it, so we can emit MARK_DELETED with a valid + pointer. + (gtk_text_buffer_mark_set): hold ref across signal emission + + * gtk/gtktextbtree.c (gtk_text_btree_remove_mark): improve + whining about attempts to delete special marks + + * gtk/gtktextbuffer.c (_gtk_text_buffer_spew): Prepend with + underscore, since it's internal. + + * gtk/gtktextbuffer.h: Remove find_string prototype, this is + now implemented in terms of iterators in gtktextiter.h + + * gtk/gtktextbuffer.c (gtk_text_buffer_set_text): + New function, destructively sets contents of buffer. Also + a convenient way to clear the buffer by setting text to "" + + * gtk/gtktextiter.c (gtk_text_iter_make_surreal): reformat + multiline string literal + + * gtk/testtext.c (text_changed_callback): Redraw line numbers if + text changes. + + * gtk/gtktextiter.c (forward_char): Return FALSE if new location + is not dereferenceable + (gtk_text_iter_forward_lines): fix return value + 2000-09-29 Havoc Pennington <hp@redhat.com> * gtk/gtktexttag.c (gtk_text_tag_set_priority): fix indentation diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 468d5ccaa..7b5985433 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -2472,16 +2472,31 @@ gtk_text_btree_get_selection_bounds (GtkTextBTree *tree, GtkTextIter *start, GtkTextIter *end) { - gtk_text_btree_get_iter_at_mark (tree, start, + GtkTextIter tmp_start, tmp_end; + + gtk_text_btree_get_iter_at_mark (tree, &tmp_start, (GtkTextMark*)tree->insert_mark); - gtk_text_btree_get_iter_at_mark (tree, end, + gtk_text_btree_get_iter_at_mark (tree, &tmp_end, (GtkTextMark*)tree->selection_bound_mark); - if (gtk_text_iter_equal(start, end)) - return FALSE; + if (gtk_text_iter_equal(&tmp_start, &tmp_end)) + { + if (start) + *start = tmp_start; + + if (end) + *end = tmp_end; + } else { - gtk_text_iter_reorder(start, end); + gtk_text_iter_reorder(&tmp_start, &tmp_end); + + if (start) + *start = tmp_start; + + if (end) + *end = tmp_end; + return TRUE; } } @@ -2523,27 +2538,25 @@ gtk_text_btree_remove_mark (GtkTextBTree *tree, { GtkTextLineSegment *segment = (GtkTextLineSegment*) mark; - g_return_if_fail(segment != NULL); - g_return_if_fail(segment != tree->selection_bound_mark); - g_return_if_fail(segment != tree->insert_mark); - g_return_if_fail(tree != NULL); + g_return_if_fail (segment != NULL); + g_return_if_fail (tree != NULL); if (segment->body.mark.not_deleteable) { g_warning("Can't delete special mark `%s'", segment->body.mark.name); return; } + + /* This calls cleanup_line and segments_changed */ + gtk_text_btree_unlink_segment (tree, segment, segment->body.mark.line); - gtk_text_btree_unlink_segment(tree, segment, segment->body.mark.line); - /* FIXME should probably cleanup_line but Tk didn't */ if (segment->body.mark.name) - g_hash_table_remove(tree->mark_table, segment->body.mark.name); - mark_segment_unref(segment); + g_hash_table_remove (tree->mark_table, segment->body.mark.name); + + mark_segment_unref (segment); segment->body.mark.tree = NULL; segment->body.mark.line = NULL; - - segments_changed(tree); } gboolean diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 6358e94fe..a83345b3c 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -348,6 +348,48 @@ gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer) return get_table (buffer); } +/** + * gtk_text_buffer_set_text: + * @buffer: a #GtkTextBuffer + * @text: UTF-8 text to insert + * @len: length of @text in bytes + * + * Deletes current contents of @buffer, and inserts @text instead. If + * @text doesn't end with a newline, a newline is added; + * #GtkTextBuffer contents must always end with a newline. If @text + * ends with a newline, the new buffer contents will be exactly + * @text. If @len is -1, @text must be nul-terminated. + **/ +void +gtk_text_buffer_set_text (GtkTextBuffer *buffer, + const gchar *text, + gint len) +{ + GtkTextIter start, end; + + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (text != NULL); + + if (len < 0) + len = strlen (text); + + /* Chop newline, since the buffer will already have one + * in it. + */ + if (len > 0 && text[len-1] == '\n') + len -= 1; + + gtk_text_buffer_get_bounds (buffer, &start, &end); + + gtk_text_buffer_delete (buffer, &start, &end); + + if (len > 0) + { + gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); + gtk_text_buffer_insert (buffer, &start, text, len); + } +} + /* * Insertion */ @@ -510,6 +552,178 @@ gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, default_editable); } + +/** + * gtk_text_buffer_insert_range: + * @buffer: a #GtkTextBuffer + * @iter: a position in @buffer + * @start: a position in a #GtkTextBuffer + * @end: another position in the same buffer as @start + * + * Copies text, tags, and pixbufs between @start and @end (the order + * of @start and @end doesn't matter) and inserts the copy at @iter. + * Used instead of simply getting/inserting text because it preserves + * images and tags. If @start and @end are in a different buffer + * from @buffer, the two buffers must share the same tag table. + * + * Implemented via multiple emissions of the insert_text and + * apply_tag signals, so expect those. + **/ +void +gtk_text_buffer_insert_range (GtkTextBuffer *buffer, + GtkTextIter *iter, + const GtkTextIter *start, + const GtkTextIter *end) +{ + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + g_return_if_fail (iter != NULL); + g_return_if_fail (start != NULL); + g_return_if_fail (end != NULL); + g_return_if_fail (gtk_text_iter_get_buffer (start) != + gtk_text_iter_get_buffer (end)); + g_return_if_fail (gtk_text_iter_get_buffer (start)->tag_table != + buffer->tag_table); + + /* FIXME */ +} + +gboolean +gtk_text_buffer_insert_range_interactive (GtkTextBuffer *buffer, + GtkTextIter *iter, + const GtkTextIter *start, + const GtkTextIter *end, + gboolean default_editable) +{ + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (start != NULL, FALSE); + g_return_val_if_fail (end != NULL, FALSE); + g_return_val_if_fail (gtk_text_iter_get_buffer (start) != + gtk_text_iter_get_buffer (end), FALSE); + g_return_val_if_fail (gtk_text_iter_get_buffer (start)->tag_table != + buffer->tag_table, FALSE); + + + /* FIXME */ + + return FALSE; +} + +/** + * gtk_text_buffer_insert_with_tags: + * @buffer: a #GtkTextBuffer + * @iter: an iterator in @buffer + * @text: UTF-8 text + * @len: length of @text, or -1 + * @first_tag: first tag to apply to @text + * @Varargs: NULL-terminated list of tags to apply + * + * Inserts @text into @buffer at @iter, applying the list of tags to + * the newly-inserted text. The last tag specified must be NULL to + * terminate the list. Equivalent to calling gtk_text_buffer_insert(), + * then gtk_text_buffer_apply_tag() on the inserted text; + * gtk_text_buffer_insert_with_tags() is just a convenience function. + **/ +void +gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + GtkTextTag *first_tag, + ...) +{ + gint start_offset; + GtkTextIter start; + va_list args; + GtkTextTag *tag; + + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (iter != NULL); + g_return_if_fail (text != NULL); + + start_offset = gtk_text_iter_get_offset (iter); + + gtk_text_buffer_insert (buffer, iter, text, len); + + if (first_tag == NULL) + return; + + gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); + + va_start (args, first_tag); + tag = first_tag; + while (tag) + { + gtk_text_buffer_apply_tag (buffer, tag, &start, iter); + + tag = va_arg (args, GtkTextTag*); + } + + va_end (args); +} + +/** + * gtk_text_buffer_insert_with_tags_by_name: + * @buffer: a #GtkTextBuffer + * @iter: position in @buffer + * @text: UTF-8 text + * @len: length of @text, or -1 + * @first_tag_name: name of a tag to apply to @text + * @Varargs: more tag names + * + * Same as gtk_text_buffer_insert_with_tags(), but allows you + * to pass in tag names instead of tag objects. + **/ +void +gtk_text_buffer_insert_with_tags_by_name (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + const gchar *first_tag_name, + ...) +{ + gint start_offset; + GtkTextIter start; + va_list args; + const gchar *tag_name; + + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (iter != NULL); + g_return_if_fail (text != NULL); + + start_offset = gtk_text_iter_get_offset (iter); + + gtk_text_buffer_insert (buffer, iter, text, len); + + if (first_tag_name == NULL) + return; + + gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); + + va_start (args, first_tag_name); + tag_name = first_tag_name; + while (tag_name) + { + GtkTextTag *tag; + + tag = gtk_text_tag_table_lookup (buffer->tag_table, + tag_name); + + if (tag == NULL) + { + g_warning ("%s: no tag with name '%s'!", G_STRLOC, tag_name); + return; + } + + gtk_text_buffer_apply_tag (buffer, tag, &start, iter); + + tag_name = va_arg (args, const gchar*); + } + + va_end (args); +} + + /* * Deletion */ @@ -535,10 +749,10 @@ gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer, } static void -gtk_text_buffer_emit_delete(GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - gboolean interactive) +gtk_text_buffer_emit_delete (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end, + gboolean interactive) { g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); g_return_if_fail(start != NULL); @@ -549,11 +763,14 @@ gtk_text_buffer_emit_delete(GtkTextBuffer *buffer, gtk_text_iter_reorder (start, end); - /* FIXME if the final newline is in the deletion range, - * shorten the range. (i.e. if end is the end iterator, - * move it backward by one) + /* Somewhat annoyingly, if you try to delete the final newline + * the BTree will put it back; which means you can't deduce the + * final contents of the buffer purely by monitoring insert/delete + * signals on the buffer. But if you delete the final newline, any + * tags on the newline will go away, oddly. See comment in + * gtktextbtree.c. This is all sort of annoying, but really hard + * to fix. */ - gtk_signal_emit(GTK_OBJECT(buffer), signals[DELETE_TEXT], start, end, @@ -822,11 +1039,15 @@ gtk_text_buffer_mark_set (GtkTextBuffer *buffer, override the default handler or stop the emission; that is, this signal is purely for notification, and not to allow users to modify the default behavior. */ + + gtk_text_mark_ref (mark); + gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_SET], location, mark); + gtk_text_mark_unref (mark); } /** @@ -841,15 +1062,15 @@ gtk_text_buffer_mark_set (GtkTextBuffer *buffer, * * Move the mark to the given position, if not @should_exist, create the mark. * - * Return value: + * Return value: mark **/ static GtkTextMark* -gtk_text_buffer_set_mark(GtkTextBuffer *buffer, - GtkTextMark *existing_mark, - const gchar *mark_name, - const GtkTextIter *iter, - gboolean left_gravity, - gboolean should_exist) +gtk_text_buffer_set_mark (GtkTextBuffer *buffer, + GtkTextMark *existing_mark, + const gchar *mark_name, + const GtkTextIter *iter, + gboolean left_gravity, + gboolean should_exist) { GtkTextIter location; GtkTextMark *mark; @@ -862,14 +1083,14 @@ gtk_text_buffer_set_mark(GtkTextBuffer *buffer, should_exist); if (gtk_text_btree_mark_is_insert(get_btree (buffer), mark) || - gtk_text_btree_mark_is_selection_bound(get_btree (buffer), mark)) + gtk_text_btree_mark_is_selection_bound (get_btree (buffer), mark)) { - gtk_text_buffer_update_primary_selection(buffer); + gtk_text_buffer_update_primary_selection (buffer); } - gtk_text_btree_get_iter_at_mark(get_btree (buffer), - &location, - mark); + gtk_text_btree_get_iter_at_mark (get_btree (buffer), + &location, + mark); gtk_text_buffer_mark_set (buffer, &location, mark); @@ -895,7 +1116,11 @@ gtk_text_buffer_set_mark(GtkTextBuffer *buffer, * * The caller of this function does <emphasis>not</emphasis> own a reference * to the returned #GtkTextMark, so you can ignore the return value - * if you like. + * if you like. Marks are owned by the buffer and go away when the + * buffer does. + * + * Emits the "mark_set" signal as notification of the mark's initial + * placement. * * Return value: the new #GtkTextMark object **/ @@ -905,90 +1130,219 @@ gtk_text_buffer_create_mark(GtkTextBuffer *buffer, const GtkTextIter *where, gboolean left_gravity) { - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); + g_return_val_if_fail (GTK_IS_TEXT_BUFFER(buffer), NULL); - return gtk_text_buffer_set_mark(buffer, NULL, mark_name, where, - left_gravity, FALSE); + return gtk_text_buffer_set_mark (buffer, NULL, mark_name, where, + left_gravity, FALSE); } /** * gtk_text_buffer_move_mark: - * @buffer: - * @mark: - * @where: - * + * @buffer: a #GtkTextBuffer + * @mark: a #GtkTextMark + * @where: new location for @mark in @buffer * + * Moves @mark to the new location @where. Emits the "mark_set" signal + * as notification of the move. **/ void -gtk_text_buffer_move_mark(GtkTextBuffer *buffer, - GtkTextMark *mark, - const GtkTextIter *where) +gtk_text_buffer_move_mark (GtkTextBuffer *buffer, + GtkTextMark *mark, + const GtkTextIter *where) { g_return_if_fail (mark != NULL); - g_return_if_fail (!gtk_text_mark_deleted (mark)); - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (!gtk_text_mark_get_deleted (mark)); + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE); + gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, TRUE); } +/** + * gtk_text_buffer_get_iter_at_mark: + * @buffer: a #GtkTextBuffer + * @iter: iterator to initialize + * @mark: a #GtkTextMark in @buffer + * + * Initializes @iter with the current position of @mark. + **/ void -gtk_text_buffer_get_iter_at_mark(GtkTextBuffer *buffer, - GtkTextIter *iter, - GtkTextMark *mark) +gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer, + GtkTextIter *iter, + GtkTextMark *mark) { g_return_if_fail (mark != NULL); - g_return_if_fail (!gtk_text_mark_deleted (mark)); - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (!gtk_text_mark_get_deleted (mark)); + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_btree_get_iter_at_mark(get_btree (buffer), - iter, - mark); + gtk_text_btree_get_iter_at_mark (get_btree (buffer), + iter, + mark); } +/** + * gtk_text_buffer_delete_mark: + * @buffer: a #GtkTextBuffer + * @mark: a #GtkTextMark in @buffer + * + * Deletes @mark, so that it's no longer located anywhere in the + * buffer. Removes the reference the buffer holds to the mark, so if + * you haven't called gtk_text_mark_ref() the mark will be freed. Even + * if the mark isn't freed, most operations on @mark become + * invalid. There is no way to undelete a + * mark. gtk_text_mark_get_deleted() will return TRUE after this + * function has been called on a mark; gtk_text_mark_get_deleted() + * indicates that a mark no longer belongs to a buffer. The "mark_deleted" + * signal will be emitted as notification after the mark is deleted. + **/ void gtk_text_buffer_delete_mark(GtkTextBuffer *buffer, - GtkTextMark *mark) + GtkTextMark *mark) { g_return_if_fail (mark != NULL); - g_return_if_fail (!gtk_text_mark_deleted (mark)); - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - + g_return_if_fail (!gtk_text_mark_get_deleted (mark)); + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + + gtk_text_mark_ref (mark); + gtk_text_btree_remove_mark (get_btree (buffer), mark); /* See rationale above for MARK_SET on why we emit this after - removing the mark, rather than removing the mark in a default - handler. */ - gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_DELETED], - mark); + * removing the mark, rather than removing the mark in a default + * handler. + */ + gtk_signal_emit (GTK_OBJECT(buffer), signals[MARK_DELETED], + mark); + + gtk_text_mark_unref (mark); } +/** + * gtk_text_buffer_get_mark: + * @buffer: a #GtkTextBuffer + * @name: a mark name + * + * Returns the mark named @name in buffer @buffer, or NULL if no such + * mark exists in the buffer. + * + * Return value: a #GtkTextMark, or NULL + **/ GtkTextMark* gtk_text_buffer_get_mark (GtkTextBuffer *buffer, const gchar *name) { GtkTextMark *mark; - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail (GTK_IS_TEXT_BUFFER(buffer), NULL); + g_return_val_if_fail (name != NULL, NULL); - mark = gtk_text_btree_get_mark_by_name(get_btree (buffer), name); + mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name); return mark; } + +/** + * gtk_text_buffer_move_mark_by_name: + * @buffer: a #GtkTextBuffer + * @name: name of a mark + * @where: new location for mark + * + * Moves the mark named @name (which must exist) to location @where. + * See gtk_text_buffer_move_mark() for details. + **/ +void +gtk_text_buffer_move_mark_by_name (GtkTextBuffer *buffer, + const gchar *name, + const GtkTextIter *where) +{ + GtkTextMark *mark; + + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (name != NULL); + + mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name); + + if (mark == NULL) + { + g_warning ("%s: no mark named '%s'", G_STRLOC, name); + return; + } + + gtk_text_buffer_move_mark (buffer, mark, where); +} + +/** + * gtk_text_buffer_delete_mark_by_name: + * @buffer: a #GtkTextBuffer + * @name: name of a mark in @buffer + * + * Deletes the mark named @name; the mark must exist. See + * gtk_text_buffer_delete_mark() for details. + **/ +void +gtk_text_buffer_delete_mark_by_name (GtkTextBuffer *buffer, + const gchar *name) +{ + GtkTextMark *mark; + + g_return_if_fail (GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail (name != NULL); + + mark = gtk_text_btree_get_mark_by_name (get_btree (buffer), name); + + if (mark == NULL) + { + g_warning ("%s: no mark named '%s'", G_STRLOC, name); + return; + } + + gtk_text_buffer_delete_mark (buffer, mark); +} + +/** + * gtk_text_buffer_get_insert: + * @buffer: a #GtkTextBuffer + * + * Returns the mark that represents the cursor (insertion point). + * Equivalent to calling gtk_text_buffer_get_mark() to get the mark + * name "insert," but very slightly more efficient, and involves less + * typing. + * + * Return value: insertion point mark + **/ GtkTextMark* gtk_text_buffer_get_insert (GtkTextBuffer *buffer) { g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); + /* FIXME use struct member in btree */ return gtk_text_buffer_get_mark (buffer, "insert"); } +/** + * gtk_text_buffer_get_selection_bound: + * @buffer: a #GtkTextBuffer + * + * Returns the mark that represents the selection bound. Equivalent + * to calling gtk_text_buffer_get_mark() to get the mark name + * "selection_bound," but very slightly more efficient, and involves + * less typing. + * + * The currently-selected text in @buffer is the region between the + * "selection_bound" and "insert" marks. If "selection_bound" and + * "insert" are in the same place, then there is no current selection. + * gtk_text_buffer_get_selection_bounds() is another convenient function + * for handling the selection, if you just want to know whether there's a + * selection and what its bounds are. + * + * Return value: selection bound mark + **/ GtkTextMark* gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer) { g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); + /* FIXME use struct member in btree */ return gtk_text_buffer_get_mark (buffer, "selection_bound"); } @@ -1000,9 +1354,10 @@ gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer) * This function moves the "insert" and "selection_bound" marks * simultaneously. If you move them to the same place in two steps * with gtk_text_buffer_move_mark(), you will temporarily select a - * region in between their old and new locations, which marks part of - * the buffer invalid and can be inefficient. This function moves - * them as a unit, which can be optimized. + * region in between their old and new locations, which can be pretty + * inefficient since the temporarily-selected region will force stuff + * to be recalculated. This function moves them as a unit, which can + * be optimized. **/ void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, @@ -1017,7 +1372,7 @@ gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, if (gtk_text_iter_is_last (&real)) gtk_text_iter_prev_char (&real); - gtk_text_btree_place_cursor(get_btree (buffer), &real); + gtk_text_btree_place_cursor (get_btree (buffer), &real); gtk_text_buffer_mark_set (buffer, &real, gtk_text_buffer_get_mark (buffer, "insert")); @@ -1384,7 +1739,7 @@ clipboard_received (GtkClipboard *clipboard, GtkTextMark *paste_point_override; paste_point_override = gtk_text_buffer_get_mark (buffer, - "__paste_point_override"); + "gtk_paste_point_override"); if (paste_point_override != NULL) { @@ -1392,7 +1747,7 @@ clipboard_received (GtkClipboard *clipboard, paste_point_override); gtk_text_buffer_delete_mark(buffer, gtk_text_buffer_get_mark (buffer, - "__paste_point_override")); + "gtk_paste_point_override")); } else { @@ -1503,7 +1858,7 @@ gtk_text_buffer_paste_primary (GtkTextBuffer *buffer, { if (override_location != NULL) gtk_text_buffer_create_mark(buffer, - "__paste_point_override", + "gtk_paste_point_override", override_location, FALSE); paste (buffer, FALSE, TRUE, default_editable); @@ -1580,7 +1935,8 @@ cut_or_copy(GtkTextBuffer *buffer, if (delete_region_after) { if (interactive) - gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); + gtk_text_buffer_delete_interactive (buffer, &start, &end, + default_editable); else gtk_text_buffer_delete (buffer, &start, &end); } @@ -1601,12 +1957,26 @@ gtk_text_buffer_copy_clipboard (GtkTextBuffer *buffer) } +/** + * gtk_text_buffer_get_selection_bounds: + * @buffer: a #GtkTextBuffer + * @start: iterator to initialize with selection start + * @end: iterator to initialize with selection end + * + * Returns %TRUE if some text is selected; places the bounds + * of the selection in @start and @end (if the selection has length 0, + * then @start and @end are filled in with the same value). + * @start and @end will be in ascending order. If @start and @end are + * NULL, then they are not filled in, but the return value still indicates + * whether text is selected. + * + * Return value: whether the selection has nonzero length + **/ gboolean gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end) { - g_return_val_if_fail (buffer != NULL, FALSE); g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end); @@ -1618,8 +1988,12 @@ gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, */ void -gtk_text_buffer_spew(GtkTextBuffer *buffer) +_gtk_text_buffer_spew(GtkTextBuffer *buffer) { gtk_text_btree_spew(get_btree (buffer)); } + + + + diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h index 836010eeb..ef50bb96c 100644 --- a/gtk/gtktextbuffer.h +++ b/gtk/gtktextbuffer.h @@ -91,6 +91,11 @@ gint gtk_text_buffer_get_char_count (GtkTextBuffer *buffer); GtkTextTagTable* gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer); +/* Delete whole buffer, then insert */ +void gtk_text_buffer_set_text (GtkTextBuffer *buffer, + const gchar *text, + gint len); + /* Insert into the buffer */ void gtk_text_buffer_insert (GtkTextBuffer *buffer, GtkTextIter *iter, @@ -110,6 +115,29 @@ gboolean gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, gint len, gboolean default_editable); +void gtk_text_buffer_insert_range (GtkTextBuffer *buffer, + GtkTextIter *iter, + const GtkTextIter *start, + const GtkTextIter *end); +gboolean gtk_text_buffer_insert_range_interactive (GtkTextBuffer *buffer, + GtkTextIter *iter, + const GtkTextIter *start, + const GtkTextIter *end, + gboolean default_editable); + +void gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + GtkTextTag *first_tag, + ...); + +void gtk_text_buffer_insert_with_tags_by_name (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + const gchar *first_tag_name, + ...); /* Delete from the buffer */ void gtk_text_buffer_delete (GtkTextBuffer *buffer, @@ -151,6 +179,12 @@ void gtk_text_buffer_delete_mark (GtkTextBuffer *buffer, GtkTextMark* gtk_text_buffer_get_mark (GtkTextBuffer *buffer, const gchar *name); +void gtk_text_buffer_move_mark_by_name (GtkTextBuffer *buffer, + const gchar *name, + const GtkTextIter *where); +void gtk_text_buffer_delete_mark_by_name (GtkTextBuffer *buffer, + const gchar *name); + GtkTextMark* gtk_text_buffer_get_insert (GtkTextBuffer *buffer); GtkTextMark* gtk_text_buffer_get_selection_bound (GtkTextBuffer *buffer); @@ -242,23 +276,8 @@ gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer, gboolean interactive, gboolean default_editable); -/* This function is not implemented. */ -gboolean gtk_text_buffer_find_string(GtkTextBuffer *buffer, - GtkTextIter *iter, - const gchar *str, - const GtkTextIter *start, - const GtkTextIter *end); - -#if 0 -/* Waiting on glib 1.4 regexp facility */ -gboolean gtk_text_buffer_find_regexp(GtkTextBuffer *buffer, - GRegexp *regexp, - const GtkTextIter *start, - const GtkTextIter *end); -#endif - /* INTERNAL private stuff */ -void gtk_text_buffer_spew (GtkTextBuffer *buffer); +void _gtk_text_buffer_spew (GtkTextBuffer *buffer); GtkTextBTree* _gtk_text_buffer_get_btree (GtkTextBuffer *buffer); diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c index cad7b9cf5..bc44e02ac 100644 --- a/gtk/gtktextiter.c +++ b/gtk/gtktextiter.c @@ -125,7 +125,13 @@ gtk_text_iter_make_surreal(const GtkTextIter *_iter) if (iter->chars_changed_stamp != gtk_text_btree_get_chars_changed_stamp(iter->tree)) { - g_warning("Invalid text buffer iterator: either the iterator is uninitialized, or the characters/pixmaps/widgets in the buffer have been modified since the iterator was created.\nYou must use marks, character numbers, or line numbers to preserve a position across buffer modifications.\nYou can apply tags and insert marks without invalidating your iterators, however."); + g_warning("Invalid text buffer iterator: either the iterator " + "is uninitialized, or the characters/pixbufs/widgets " + "in the buffer have been modified since the iterator " + "was created.\nYou must use marks, character numbers, " + "or line numbers to preserve a position across buffer " + "modifications.\nYou can apply tags and insert marks " + "without invalidating your iterators, however."); return NULL; } @@ -335,7 +341,7 @@ static void check_invariants(const GtkTextIter *iter) { if (gtk_debug_flags & GTK_DEBUG_TEXT) - gtk_text_iter_check(iter); + gtk_text_iter_check (iter); } #else #define check_invariants(x) @@ -1410,6 +1416,9 @@ forward_line_leaving_caches_unmodified(GtkTextRealIter *real) } } +/* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS + * DEREFERENCEABLE) + */ static gboolean forward_char(GtkTextRealIter *real) { @@ -1459,11 +1468,10 @@ forward_char(GtkTextRealIter *real) check_invariants((GtkTextIter*)real); - /* FIXME we don't currently return FALSE if - * we moved onto the end iterator - */ - - return TRUE; + if (gtk_text_iter_is_last ((GtkTextIter*)real)) + return FALSE; + else + return TRUE; } } @@ -1653,14 +1661,12 @@ gtk_text_iter_prev_char(GtkTextIter *iter) * * Moves @count characters if possible (if @count would move past the * start or end of the buffer, moves to the start or end of the - * buffer). If @count is positive, the return value indicates whether - * @iter was moved to a dereferenceable location (FALSE is returned if - * @iter was moved to the non-dereferenceable end iterator). If @count - * is negative, the return value indicates whether @iter was already - * at character offset 0. If @count is 0, the function does nothing - * and returns FALSE. - * - * Return value: whether @iter moved or is dereferenceable + * buffer). The return value indicates whether the new position of + * @iter is different from its original position, and dereferenceable + * (the last iterator in the buffer is not dereferenceable). If @count + * is 0, the function does nothing and returns FALSE. + * + * Return value: whether @iter moved and is dereferenceable **/ gboolean gtk_text_iter_forward_chars(GtkTextIter *iter, gint count) @@ -1724,14 +1730,12 @@ gtk_text_iter_forward_chars(GtkTextIter *iter, gint count) * * Moves @count characters backward, if possible (if @count would move * past the start or end of the buffer, moves to the start or end of - * the buffer). If @count is negative, the return value indicates - * whether @iter was moved to a dereferenceable location (FALSE is - * returned if @iter was moved to the non-dereferenceable end - * iterator). If @count is positive, the return value indicates - * whether @iter was already at character offset 0. If @count is 0, + * the buffer). The return value indicates whether the iterator moved + * onto a dereferenceable position; if the iterator didn't move, or + * moved onto the end iterator, then FALSE is returned. If @count is 0, * the function does nothing and returns FALSE. * - * Return value: whether @iter moved or is dereferenceable + * Return value: whether @iter moved and is dereferenceable * **/ gboolean @@ -1748,7 +1752,7 @@ gtk_text_iter_backward_chars(GtkTextIter *iter, gint count) else if (count == 0) return FALSE; else if (count < 0) - return gtk_text_iter_forward_chars(iter, 0 - count); + return gtk_text_iter_forward_chars (iter, 0 - count); ensure_char_offsets(real); check_invariants(iter); @@ -1818,7 +1822,8 @@ gtk_text_iter_backward_chars(GtkTextIter *iter, gint count) * * Moves @iter to the start of the next line. Returns TRUE if there * was a next line to move to, and FALSE if @iter was simply moved to - * the end of the buffer and is now not dereferenceable. + * the end of the buffer and is now not dereferenceable, or if @iter was + * already at the end of the buffer. * * Return value: whether @iter can be dereferenced **/ @@ -1863,7 +1868,9 @@ gtk_text_iter_forward_line(GtkTextIter *iter) * @iter could be moved; i.e. if @iter was at character offset 0, this * function returns FALSE. Therefore if @iter was already on line 0, * but not at the start of the line, @iter is snapped to the start of - * the line and the function returns TRUE. + * the line and the function returns TRUE. (Note that this implies that + * in a loop calling this function, the line number may not change on + * every iteration, if your first iteration is on line 0.) * * Return value: whether @iter moved **/ @@ -1921,7 +1928,8 @@ gtk_text_iter_backward_line(GtkTextIter *iter) of the first line and return TRUE, so TRUE means the iterator changed, not that the line changed; this is maybe a bit weird. I'm not sure there's an obvious right thing - to do though. */ + to do though. + */ check_invariants(iter); @@ -1932,13 +1940,13 @@ gboolean gtk_text_iter_forward_lines(GtkTextIter *iter, gint count) { if (count < 0) - return gtk_text_iter_backward_lines(iter, 0 - count); + return gtk_text_iter_backward_lines (iter, 0 - count); else if (count == 0) return FALSE; else if (count == 1) { check_invariants(iter); - return gtk_text_iter_forward_line(iter); + return gtk_text_iter_forward_line (iter); } else { @@ -1950,10 +1958,10 @@ gtk_text_iter_forward_lines(GtkTextIter *iter, gint count) check_invariants(iter); - /* FIXME this needs to return FALSE if we moved onto the - * end iterator. - */ - return (gtk_text_iter_get_line(iter) != old_line); + /* return whether it moved, and is dereferenceable. */ + return + (gtk_text_iter_get_line (iter) != old_line) && + !gtk_text_iter_is_last (iter); } } @@ -2149,7 +2157,7 @@ gtk_text_iter_forward_word_ends(GtkTextIter *iter, gboolean gtk_text_iter_backward_word_starts(GtkTextIter *iter, - gint count) + gint count) { g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(count > 0, FALSE); @@ -2169,7 +2177,7 @@ gtk_text_iter_backward_word_starts(GtkTextIter *iter, void gtk_text_iter_set_line_offset(GtkTextIter *iter, - gint char_on_line) + gint char_on_line) { GtkTextRealIter *real; @@ -2295,6 +2303,19 @@ gtk_text_iter_forward_to_newline(GtkTextIter *iter) } } +/** + * gtk_text_iter_forward_to_tag_toggle: + * @iter: a #GtkTextIter + * @tag: a #GtkTextTag, or NULL + * + * Moves forward to the next toggle (on or off) of the + * #GtkTextTag @tag, or to the next toggle of any tag if + * @tag is NULL. If no matching tag toggles are found, + * returns FALSE, otherwise TRUE. Does not return toggles + * located at @iter, only toggles after @iter. + * + * Return value: whether we found a tag toggle after @iter + **/ gboolean gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, GtkTextTag *tag) @@ -2314,7 +2335,7 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, current_line = real->line; next_line = gtk_text_line_next_could_contain_tag(current_line, - real->tree, tag); + real->tree, tag); while (gtk_text_iter_forward_indexable_segment(iter)) { @@ -2344,7 +2365,7 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, { /* If there's a toggle here, it isn't indexable so any_segment can't be the indexable segment. */ - g_assert(real->any_segment != real->segment); + g_assert (real->any_segment != real->segment); return TRUE; } } @@ -2354,7 +2375,7 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, { /* If there's a toggle here, it isn't indexable so any_segment can't be the indexable segment. */ - g_assert(real->any_segment != real->segment); + g_assert (real->any_segment != real->segment); return TRUE; } diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c index 4a53161ed..6cf14624a 100644 --- a/gtk/gtktextmark.c +++ b/gtk/gtktextmark.c @@ -59,7 +59,7 @@ gtk_text_mark_unref (GtkTextMark *mark) } gboolean -gtk_text_mark_deleted (GtkTextMark *mark) +gtk_text_mark_get_deleted (GtkTextMark *mark) { GtkTextLineSegment *seg; @@ -79,14 +79,14 @@ gtk_text_mark_deleted (GtkTextMark *mark) GtkTextLineSegment* -mark_segment_new(GtkTextBTree *tree, - gboolean left_gravity, - const gchar *name) +mark_segment_new (GtkTextBTree *tree, + gboolean left_gravity, + const gchar *name) { GtkTextLineSegment *mark; - mark = (GtkTextLineSegment *) g_malloc0(MSEG_SIZE); - mark->body.mark.name = g_strdup(name); + mark = (GtkTextLineSegment *) g_malloc0 (MSEG_SIZE); + mark->body.mark.name = g_strdup (name); if (left_gravity) mark->type = >k_text_left_mark_type; @@ -111,10 +111,10 @@ mark_segment_new(GtkTextBTree *tree, void mark_segment_ref(GtkTextLineSegment *mark) { - g_return_if_fail(mark != NULL); - g_return_if_fail(mark->type == >k_text_right_mark_type || - mark->type == >k_text_left_mark_type); - g_return_if_fail(mark->body.mark.refcount > 0); + g_return_if_fail (mark != NULL); + g_return_if_fail (mark->type == >k_text_right_mark_type || + mark->type == >k_text_left_mark_type); + g_return_if_fail (mark->body.mark.refcount > 0); mark->body.mark.refcount += 1; } @@ -122,10 +122,10 @@ mark_segment_ref(GtkTextLineSegment *mark) void mark_segment_unref(GtkTextLineSegment *mark) { - g_return_if_fail(mark != NULL); - g_return_if_fail(mark->type == >k_text_right_mark_type || - mark->type == >k_text_left_mark_type); - g_return_if_fail(mark->body.mark.refcount > 0); + g_return_if_fail (mark != NULL); + g_return_if_fail (mark->type == >k_text_right_mark_type || + mark->type == >k_text_left_mark_type); + g_return_if_fail (mark->body.mark.refcount > 0); mark->body.mark.refcount -= 1; @@ -137,17 +137,15 @@ mark_segment_unref(GtkTextLineSegment *mark) } } -/* - * Forward references for procedures defined in this file: - */ -static int mark_segment_delete_func (GtkTextLineSegment *segPtr, - GtkTextLine *line, - int treeGone); -static GtkTextLineSegment *mark_segment_cleanup_func (GtkTextLineSegment *segPtr, - GtkTextLine *line); -static void mark_segment_check_func (GtkTextLineSegment *segPtr, - GtkTextLine *line); +static int mark_segment_delete_func (GtkTextLineSegment *segPtr, + GtkTextLine *line, + int treeGone); +static GtkTextLineSegment *mark_segment_cleanup_func (GtkTextLineSegment *segPtr, + GtkTextLine *line); +static void mark_segment_check_func (GtkTextLineSegment *segPtr, + GtkTextLine *line); + /* * The following structures declare the "mark" segment types. @@ -157,26 +155,25 @@ static void mark_segment_check_func (GtkTextLineSegment *segPtr, */ GtkTextLineSegmentClass gtk_text_right_mark_type = { - "mark", /* name */ + "mark", /* name */ FALSE, /* leftGravity */ - (GtkTextLineSegmentSplitFunc) NULL, /* splitFunc */ + NULL, /* splitFunc */ mark_segment_delete_func, /* deleteFunc */ mark_segment_cleanup_func, /* cleanupFunc */ - (GtkTextLineSegmentLineChangeFunc) NULL, /* lineChangeFunc */ + NULL, /* lineChangeFunc */ mark_segment_check_func /* checkFunc */ }; GtkTextLineSegmentClass gtk_text_left_mark_type = { - "mark", /* name */ + "mark", /* name */ TRUE, /* leftGravity */ - (GtkTextLineSegmentSplitFunc) NULL, /* splitFunc */ + NULL, /* splitFunc */ mark_segment_delete_func, /* deleteFunc */ mark_segment_cleanup_func, /* cleanupFunc */ - (GtkTextLineSegmentLineChangeFunc) NULL, /* lineChangeFunc */ + NULL, /* lineChangeFunc */ mark_segment_check_func /* checkFunc */ }; - /* *-------------------------------------------------------------- * @@ -195,18 +192,14 @@ GtkTextLineSegmentClass gtk_text_left_mark_type = { *-------------------------------------------------------------- */ - /* ARGSUSED */ -static int -mark_segment_delete_func(segPtr, line, treeGone) - GtkTextLineSegment *segPtr; /* Segment being deleted. */ - GtkTextLine *line; /* Line containing segment. */ - int treeGone; /* Non-zero means the entire tree is - * being deleted, so everything must - * get cleaned up. */ +static gboolean +mark_segment_delete_func (GtkTextLineSegment *segPtr, + GtkTextLine *line, + gboolean tree_gone) { - return 1; + return TRUE; } - + /* *-------------------------------------------------------------- * @@ -225,112 +218,14 @@ mark_segment_delete_func(segPtr, line, treeGone) */ static GtkTextLineSegment * -mark_segment_cleanup_func(markPtr, line) - GtkTextLineSegment *markPtr; /* Mark segment that's being moved. */ - GtkTextLine *line; /* Line that now contains segment. */ -{ - markPtr->body.mark.line = line; - return markPtr; -} - -#if 0 - - -/* - *-------------------------------------------------------------- - * - * GtkTextInsertDisplayFunc -- - * - * This procedure is called to display the insertion - * cursor. - * - * Results: - * None. - * - * Side effects: - * Graphics are drawn. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -GtkTextInsertDisplayFunc(chunkPtr, x, y, height, baseline, display, dst, screenY) - GtkTextDisplayChunk *chunkPtr; /* Chunk that is to be drawn. */ - int x; /* X-position in dst at which to - * draw this chunk (may differ from - * the x-position in the chunk because - * of scrolling). */ - int y; /* Y-position at which to draw this - * chunk in dst (x-position is in - * the chunk itself). */ - int height; /* Total height of line. */ - int baseline; /* Offset of baseline from y. */ - Display *display; /* Display to use for drawing. */ - Drawable dst; /* Pixmap or window in which to draw - * chunk. */ - int screenY; /* Y-coordinate in text window that - * corresponds to y. */ +mark_segment_cleanup_func(GtkTextLineSegment *seg, + GtkTextLine *line) { - GtkTextView *tkxt = (GtkTextView *) chunkPtr->clientData; - int halfWidth = tkxt->insertWidth/2; - - if ((x + halfWidth) < 0) { - /* - * The insertion cursor is off-screen. Just return. - */ - - return; - } - - /* - * As a special hack to keep the cursor visible on mono displays - * (or anywhere else that the selection and insertion cursors - * have the same color) write the default background in the cursor - * area (instead of nothing) when the cursor isn't on. Otherwise - * the selection might hide the cursor. - */ - - if (tkxt->flags & INSERT_ON) { - Tk_Fill3DRectangle(tkxt->tkwin, dst, tkxt->insertBorder, - x - tkxt->insertWidth/2, y, tkxt->insertWidth, - height, tkxt->insertBorderWidth, TK_RELIEF_RAISED); - } else if (tkxt->selBorder == tkxt->insertBorder) { - Tk_Fill3DRectangle(tkxt->tkwin, dst, tkxt->border, - x - tkxt->insertWidth/2, y, tkxt->insertWidth, - height, 0, TK_RELIEF_FLAT); - } + /* not sure why Tk did this here and not in LineChangeFunc */ + seg->body.mark.line = line; + return seg; } - -/* - *-------------------------------------------------------------- - * - * InsertUndisplayFunc -- - * - * This procedure is called when the insertion cursor is no - * longer at a visible point on the display. It does nothing - * right now. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - /* ARGSUSED */ -static void -InsertUndisplayFunc(tkxt, chunkPtr) - GtkTextView *tkxt; /* Overall information about text - * widget. */ - GtkTextDisplayChunk *chunkPtr; /* Chunk that is about to be freed. */ -{ - return; -} - -#endif /* *-------------------------------------------------------------- * @@ -350,26 +245,9 @@ InsertUndisplayFunc(tkxt, chunkPtr) */ static void -mark_segment_check_func(markPtr, line) - GtkTextLineSegment *markPtr; /* Segment to check. */ - GtkTextLine *line; /* Line containing segment. */ +mark_segment_check_func(GtkTextLineSegment *seg, + GtkTextLine *line) { - if (markPtr->body.mark.line != line) - g_error("mark_segment_check_func: markPtr->body.mark.line bogus"); - - /* No longer do this because we don't have access to btree - struct members */ -#if 0 - /* - * Make sure that the mark is still present in the text's mark - * hash table. - */ - for (hPtr = Tcl_FirstHashEntry(&markPtr->body.mark.tkxt->markTable, - &search); hPtr != markPtr->body.mark.hPtr; - hPtr = Tcl_NextHashEntry(&search)) { - if (hPtr == NULL) { - panic("mark_segment_check_func couldn't find hash table entry for mark"); - } - } -#endif + if (seg->body.mark.line != line) + g_error("mark_segment_check_func: seg->body.mark.line bogus"); } diff --git a/gtk/gtktextmark.h b/gtk/gtktextmark.h index feab32378..f2a0b5b79 100644 --- a/gtk/gtktextmark.h +++ b/gtk/gtktextmark.h @@ -16,7 +16,7 @@ gboolean gtk_text_mark_is_visible (GtkTextMark *mark); const char * gtk_text_mark_get_name (GtkTextMark *mark); GtkTextMark *gtk_text_mark_ref (GtkTextMark *mark); void gtk_text_mark_unref (GtkTextMark *mark); -gboolean gtk_text_mark_deleted (GtkTextMark *mark); +gboolean gtk_text_mark_get_deleted (GtkTextMark *mark); #ifdef __cplusplus diff --git a/gtk/gtktextsegment.h b/gtk/gtktextsegment.h index 844663d43..0dfd05630 100644 --- a/gtk/gtktextsegment.h +++ b/gtk/gtktextsegment.h @@ -39,17 +39,36 @@ struct _GtkTextToggleBody { /* Class struct for segments */ -typedef GtkTextLineSegment *(* GtkTextLineSegmentSplitFunc) (GtkTextLineSegment *segPtr, - int index); -typedef gboolean (* GtkTextViewSegDeleteFunc) (GtkTextLineSegment *segPtr, - GtkTextLine *line, - gboolean treeGone); -typedef GtkTextLineSegment *(* GtkTextViewSegCleanupFunc) (GtkTextLineSegment *segPtr, - GtkTextLine *line); -typedef void (* GtkTextLineSegmentLineChangeFunc) (GtkTextLineSegment *segPtr, - GtkTextLine *line); -typedef void (* GtkTextViewSegCheckFunc) (GtkTextLineSegment *segPtr, - GtkTextLine *line); +/* Split seg at index, returning list of two new segments, and freeing seg */ +typedef GtkTextLineSegment* (*GtkTextSegSplitFunc) (GtkTextLineSegment *seg, + gint index); + +/* Delete seg which is contained in line; if tree_gone, the tree is being + * freed in its entirety, which may matter for some reason (?) + * Return TRUE if the segment is not deleteable, e.g. a mark. + */ +typedef gboolean (*GtkTextSegDeleteFunc) (GtkTextLineSegment *seg, + GtkTextLine *line, + gboolean tree_gone); + +/* Called after segment structure of line changes, so segments can + * cleanup (e.g. merge with adjacent segments). Returns a segment list + * to replace the original segment list with. The line argument is + * the current line. + */ +typedef GtkTextLineSegment* (*GtkTextSegCleanupFunc) (GtkTextLineSegment *seg, + GtkTextLine *line); + +/* Called when a segment moves from one line to another. CleanupFunc is also + * called in that case, so many segments just use CleanupFunc, I'm not sure + * what's up with that (this function may not be needed...) + */ +typedef void (*GtkTextSegLineChangeFunc) (GtkTextLineSegment *seg, + GtkTextLine *line); + +/* Called to do debug checks on the segment. */ +typedef void (*GtkTextSegCheckFunc) (GtkTextLineSegment *seg, + GtkTextLine *line); struct _GtkTextLineSegmentClass { char *name; /* Name of this kind of segment. */ @@ -58,17 +77,17 @@ struct _GtkTextLineSegmentClass { * attach to character to its left * or right? 1 means left, 0 means * right. */ - GtkTextLineSegmentSplitFunc splitFunc; /* Procedure to split large segment + GtkTextSegSplitFunc splitFunc; /* Procedure to split large segment * into two smaller ones. */ - GtkTextViewSegDeleteFunc deleteFunc; /* Procedure to call to delete + GtkTextSegDeleteFunc deleteFunc; /* Procedure to call to delete * segment. */ - GtkTextViewSegCleanupFunc cleanupFunc; /* After any change to a line, this + GtkTextSegCleanupFunc cleanupFunc; /* After any change to a line, this * procedure is invoked for all * segments left in the line to * perform any cleanup they wish * (e.g. joining neighboring * segments). */ - GtkTextLineSegmentLineChangeFunc lineChangeFunc; + GtkTextSegLineChangeFunc lineChangeFunc; /* Invoked when a segment is about * to be moved from its current line * to an earlier line because of @@ -77,7 +96,7 @@ struct _GtkTextLineSegmentClass { * CleanupFunc will be invoked after * the deletion is finished. */ - GtkTextViewSegCheckFunc checkFunc; /* Called during consistency checks + GtkTextSegCheckFunc checkFunc; /* Called during consistency checks * to check internal consistency of * segment. */ }; @@ -88,9 +107,9 @@ struct _GtkTextLineSegmentClass { struct _GtkTextLineSegment { GtkTextLineSegmentClass *type; /* Pointer to record describing - * segment's type. */ + * segment's type. */ GtkTextLineSegment *next; /* Next in list of segments for this - * line, or NULL for end of list. */ + * line, or NULL for end of list. */ int char_count; /* # of chars of index space occupied */ diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 3e198bed6..fffa2bca3 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -721,7 +721,7 @@ gtk_text_view_set_buffer (GtkTextView *text_view, gtk_text_buffer_get_iter_at_offset (text_view->buffer, &start, 0); text_view->dnd_mark = gtk_text_buffer_create_mark (text_view->buffer, - "__drag_target", + "gtk_drag_target", &start, FALSE); text_view->first_para_mark = gtk_text_buffer_create_mark (text_view->buffer, @@ -1866,7 +1866,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) /* debug hack */ if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0) - gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer); + _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer); else if (event->button == 3) gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout); @@ -3116,7 +3116,7 @@ gtk_text_view_drag_motion (GtkWidget *widget, gtk_text_buffer_move_mark (text_view->buffer, gtk_text_buffer_get_mark (text_view->buffer, - "__drag_target"), + "gtk_drag_target"), &newplace); { @@ -3130,7 +3130,7 @@ gtk_text_view_drag_motion (GtkWidget *widget, gtk_text_view_scroll_to_mark_adjusted (text_view, gtk_text_buffer_get_mark (text_view->buffer, - "__drag_target"), + "gtk_drag_target"), margin, 1.0); } @@ -3176,7 +3176,7 @@ gtk_text_view_drag_data_received (GtkWidget *widget, text_view = GTK_TEXT_VIEW (widget); drag_target_mark = gtk_text_buffer_get_mark (text_view->buffer, - "__drag_target"); + "gtk_drag_target"); if (drag_target_mark == NULL) return; diff --git a/gtk/testtext.c b/gtk/testtext.c index b787efe17..16e7172b7 100644 --- a/gtk/testtext.c +++ b/gtk/testtext.c @@ -1433,6 +1433,35 @@ cursor_set_callback (GtkTextBuffer *buffer, } } + +static void +text_changed_callback (GtkTextBuffer *buffer, + gpointer user_data) +{ + GtkTextView *text_view; + + /* Redraw line number windows if the buffer changes + * and the widget is mapped (windows may not exist otherwise) + */ + + text_view = GTK_TEXT_VIEW (user_data); + + if (GTK_WIDGET_MAPPED (text_view)) + { + GdkWindow *line_window; + + line_window = gtk_text_view_get_window (text_view, + GTK_TEXT_WINDOW_LEFT); + + gdk_window_invalidate_rect (line_window, NULL, FALSE); + + line_window = gtk_text_view_get_window (text_view, + GTK_TEXT_WINDOW_RIGHT); + + gdk_window_invalidate_rect (line_window, NULL, FALSE); + } +} + static gint tab_stops_expose (GtkWidget *widget, GdkEventExpose *event, @@ -1783,6 +1812,11 @@ create_view (Buffer *buffer) "expose_event", GTK_SIGNAL_FUNC (line_numbers_expose), NULL); + + gtk_signal_connect (GTK_OBJECT (view->buffer->buffer), + "changed", + GTK_SIGNAL_FUNC (text_changed_callback), + view->text_view); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (sw), view->text_view); diff --git a/tests/testtext.c b/tests/testtext.c index b787efe17..16e7172b7 100644 --- a/tests/testtext.c +++ b/tests/testtext.c @@ -1433,6 +1433,35 @@ cursor_set_callback (GtkTextBuffer *buffer, } } + +static void +text_changed_callback (GtkTextBuffer *buffer, + gpointer user_data) +{ + GtkTextView *text_view; + + /* Redraw line number windows if the buffer changes + * and the widget is mapped (windows may not exist otherwise) + */ + + text_view = GTK_TEXT_VIEW (user_data); + + if (GTK_WIDGET_MAPPED (text_view)) + { + GdkWindow *line_window; + + line_window = gtk_text_view_get_window (text_view, + GTK_TEXT_WINDOW_LEFT); + + gdk_window_invalidate_rect (line_window, NULL, FALSE); + + line_window = gtk_text_view_get_window (text_view, + GTK_TEXT_WINDOW_RIGHT); + + gdk_window_invalidate_rect (line_window, NULL, FALSE); + } +} + static gint tab_stops_expose (GtkWidget *widget, GdkEventExpose *event, @@ -1783,6 +1812,11 @@ create_view (Buffer *buffer) "expose_event", GTK_SIGNAL_FUNC (line_numbers_expose), NULL); + + gtk_signal_connect (GTK_OBJECT (view->buffer->buffer), + "changed", + GTK_SIGNAL_FUNC (text_changed_callback), + view->text_view); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (sw), view->text_view); |