From a4762fbff4739fbf0373c5528eb3a9855aa9299b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 25 Jul 2000 23:59:38 +0000 Subject: update to reflect text widget changes. 2000-07-25 Havoc Pennington * gtk/testtext.c, gtk/testtextbuffer.c: update to reflect text widget changes. * gtk/gtktextview.h: To be consistent with usage of "line" throughout the API to mean "newline-terminated thingy", change MOVEMENT_LINE to be MOVEMENT_WRAPPED_LINE, and MOVEMENT_PARAGRAPH to MOVEMENT_LINE. (GtkTextView): Add flags for default editability, and whether to show the cursor. Add functions to get/set that. Add (gtk_text_view_get_iter_location): new function * gtk/gtktexttypes.h: Move GtkTextLine typedef from here to gtktextlayout.h (g_convert): Add g_convert temporarily, will go in glib in a bit * gtk/gtktexttagtable.h: include gtktexttag.h, and define GtkTextTagTableForeach instead of brokenly using GHFunc. Change gtk_text_tag_table_foreach() so it doesn't use GHFunc. * gtk/gtktexttagprivate.h: Remove GtkTextStyleValues from here, moved to public header. * gtk/gtktexttag.h: Rename the "elide" attribute of tags to "invisible", since "elide" was a bad name. (gtk_text_tag_get_priority): Added (GtkTextStyleValues): put this in public header, along with functions to use it. * gtk/gtktextmarkprivate.h: Include more headers, since we no longer include gtktextbtree.h. * gtk/gtktextmark.h: Add gtk_text_mark_ref, gtk_text_mark_unref, gtk_text_mark_deleted * gtk/gtktextlayout.h: Don't include the "really private" headers, only buffer/iter. Forward declare GtkTextLIne and GtkTextLineData to make this possible. Now we only need to install gtktextlayout.h, not gtktextbtree.h and gtktext*private.h. (However the Makefile.am isn't changed yet because of the logistics of merging gtk-hp-patches piecemeal) * gtk/gtktextiterprivate.h: include btree header, so it compiles; rename gtk_text_iter_get_line to gtk_text_iter_get_text_line since gtk_text_iter_get_line is now used in the public API for a different purpose. * gtk/gtktextiter.h: Clean up function names to be more consistent. Always call char offset "offset" and byte index "index". A "line" is always a line number. (gtk_text_iter_is_last): new function, more efficient than the existing way to check (gtk_text_iter_is_first): new function, also more efficient (gtk_text_iter_up_lines, gtk_text_iter_down_lines): Remove these (gtk_text_iter_next_char, gtk_text_iter_prev_char): Renamed from gtk_text_iter_forward_char, etc. (gtk_text_iter_forward_to_tag_toggle): Renamed from forward_find_tag_toggle, since this isn't a linear search (GtkTextCharPredicate): rename from GtkTextViewCharPredicate (gtk_text_iter_forward_search, gtk_text_iter_backward_search): New functions, search for a buffer substring. * gtk/gtktextbuffer.h: Add fields to store whether a paste is interactive and default editable (since we need to store that info until we receive the selection data). Remove all the _at_char and at_line etc. versions of functions; only have iterator versions. Add _interactive() versions of functions, that consider the editability of text. (FIXME add interactive flag to the insert/delete signals per Darin's suggestion) (gtk_text_buffer_get_tag_table): new function, demand-creates the tag table if necessary Remove declaration of gtk_text_buffer_get_iter_from_string (_gtk_text_buffer_get_btree): private/internal function, added. * gtk/gtktextbtree.h: Remove forward decl of GtkTextLineData. (gtk_text_line_is_last): new function --- gtk/gtktextbtree.c | 132 +++++---- gtk/gtktextbtree.h | 3 +- gtk/gtktextbuffer.c | 676 ++++++++++++++++++++++++--------------------- gtk/gtktextbuffer.h | 159 +++++------ gtk/gtktextdisplay.c | 10 +- gtk/gtktextiter.c | 703 +++++++++++++++++++++++++++++++++++------------ gtk/gtktextiter.h | 127 +++++---- gtk/gtktextiterprivate.h | 5 +- gtk/gtktextlayout.c | 183 +++++++----- gtk/gtktextlayout.h | 14 +- gtk/gtktextmark.c | 35 +++ gtk/gtktextmark.h | 7 +- gtk/gtktextmarkprivate.h | 5 +- gtk/gtktextsegment.c | 4 +- gtk/gtktexttag.c | 22 +- gtk/gtktexttag.h | 97 ++++++- gtk/gtktexttagprivate.h | 93 ------- gtk/gtktexttagtable.c | 85 ++++-- gtk/gtktexttagtable.h | 28 +- gtk/gtktexttypes.c | 89 ++++++ gtk/gtktexttypes.h | 15 +- gtk/gtktextview.c | 352 +++++++++++++++++------- gtk/gtktextview.h | 30 +- gtk/testtext.c | 368 +++++++++++++++++++------ gtk/testtextbuffer.c | 258 ++++++++--------- 25 files changed, 2264 insertions(+), 1236 deletions(-) (limited to 'gtk') diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 8c2b3e00a..e51f2bbd0 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -567,8 +567,8 @@ gtk_text_btree_delete (GtkTextIter *start, gint line1; gint line2; - line1 = gtk_text_iter_get_line_number(start); - line2 = gtk_text_iter_get_line_number(end); + line1 = gtk_text_iter_get_line(start); + line2 = gtk_text_iter_get_line(end); if (line2 == gtk_text_btree_line_count(tree)) { @@ -577,14 +577,14 @@ gtk_text_btree_delete (GtkTextIter *start, GtkTextIter orig_end; orig_end = *end; - gtk_text_iter_backward_char(end); + gtk_text_iter_prev_char(end); --line2; - if (gtk_text_iter_get_line_char(start) == 0 && + if (gtk_text_iter_get_line_offset(start) == 0 && line1 != 0) { - gtk_text_iter_backward_char(start); + gtk_text_iter_prev_char(start); --line1; } @@ -612,10 +612,10 @@ gtk_text_btree_delete (GtkTextIter *start, gtk_text_btree_invalidate_region(tree, start, end); /* Save the byte offset so we can reset the iterators */ - start_byte_offset = gtk_text_iter_get_line_byte(start); + start_byte_offset = gtk_text_iter_get_line_index(start); - start_line = gtk_text_iter_get_line(start); - end_line = gtk_text_iter_get_line(end); + start_line = gtk_text_iter_get_text_line(start); + end_line = gtk_text_iter_get_text_line(end); /* * Split the start and end segments, so we have a place @@ -921,9 +921,9 @@ gtk_text_btree_insert (GtkTextIter *iter, /* extract iterator info */ tree = gtk_text_iter_get_btree(iter); - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); start_line = line; - start_byte_index = gtk_text_iter_get_line_byte(iter); + start_byte_index = gtk_text_iter_get_line_index(iter); /* Get our insertion segment split */ prev_seg = gtk_text_line_segment_split(iter); @@ -1045,9 +1045,9 @@ gtk_text_btree_insert_pixmap (GtkTextIter *iter, GtkTextBTree *tree; gint start_byte_offset; - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); tree = gtk_text_iter_get_btree(iter); - start_byte_offset = gtk_text_iter_get_line_byte(iter); + start_byte_offset = gtk_text_iter_get_line_index(iter); seg = gtk_text_pixmap_segment_new (pixmap, mask); @@ -1073,7 +1073,7 @@ gtk_text_btree_insert_pixmap (GtkTextIter *iter, gtk_text_btree_get_iter_at_line(tree, &start, line, start_byte_offset); *iter = start; - gtk_text_iter_forward_char(iter); /* skip forward past the pixmap */ + gtk_text_iter_next_char(iter); /* skip forward past the pixmap */ gtk_text_btree_invalidate_region(tree, &start, iter); } @@ -1481,8 +1481,8 @@ gtk_text_btree_tag (const GtkTextIter *start_orig, printf("%s tag %s from %d to %d\n", add ? "Adding" : "Removing", tag->name, - gtk_text_iter_get_char_index(start_orig), - gtk_text_iter_get_char_index(end_orig)); + gtk_text_buffer_get_offset(start_orig), + gtk_text_buffer_get_offset(end_orig)); #endif if (gtk_text_iter_equal(start_orig, end_orig)) @@ -1497,8 +1497,8 @@ gtk_text_btree_tag (const GtkTextIter *start_orig, info = gtk_text_btree_get_tag_info(tree, tag); - start_line = gtk_text_iter_get_line(&start); - end_line = gtk_text_iter_get_line(&end); + start_line = gtk_text_iter_get_text_line(&start); + end_line = gtk_text_iter_get_text_line(&end); /* Find all tag toggles in the region; we are going to delete them. We need to find them in advance, because @@ -1507,8 +1507,8 @@ gtk_text_btree_tag (const GtkTextIter *start_orig, stack = iter_stack_new(); iter = start; /* We don't want to delete a toggle that's at the start iterator. */ - gtk_text_iter_forward_char(&iter); - while (gtk_text_iter_forward_find_tag_toggle(&iter, tag)) + gtk_text_iter_next_char(&iter); + while (gtk_text_iter_forward_to_tag_toggle(&iter, tag)) { if (gtk_text_iter_compare(&iter, &end) >= 0) break; @@ -1569,7 +1569,7 @@ gtk_text_btree_tag (const GtkTextIter *start_orig, GtkTextLineSegment *indexable_seg; GtkTextLine *line; - line = gtk_text_iter_get_line(&iter); + line = gtk_text_iter_get_text_line(&iter); seg = gtk_text_iter_get_any_segment(&iter); indexable_seg = gtk_text_iter_get_indexable_segment(&iter); @@ -1873,9 +1873,9 @@ gtk_text_btree_get_tags (const GtkTextIter *iter, #define NUM_TAG_INFOS 10 - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); tree = gtk_text_iter_get_btree(iter); - byte_index = gtk_text_iter_get_line_byte(iter); + byte_index = gtk_text_iter_get_line_index(iter); tagInfo.numTags = 0; tagInfo.arraySize = NUM_TAG_INFOS; @@ -1993,13 +1993,13 @@ copy_segment(GString *string, gint copy_bytes = 0; gint copy_start = 0; - /* Don't copy if we're elided; segments are elided/not + /* Don't copy if we're invisible; segments are invisible/not as a whole, no need to check each char */ if (!include_hidden && gtk_text_btree_char_is_invisible(start)) { copy = FALSE; - /* printf(" \n"); */ + /* printf(" \n"); */ } copy_start = gtk_text_iter_get_segment_byte(start); @@ -2012,7 +2012,7 @@ copy_segment(GString *string, copy_bytes = end_byte - copy_start; } else - copy_bytes = seg->byte_count; + copy_bytes = seg->byte_count - copy_start; g_assert(copy_bytes != 0); /* Due to iter equality check at front of this function. */ @@ -2085,18 +2085,17 @@ gtk_text_btree_get_text (const GtkTextIter *start_orig, iter = start; seg = gtk_text_iter_get_indexable_segment(&iter); while (seg != end_seg) - { + { copy_segment(retval, include_hidden, include_nonchars, &iter, &end); - if (!gtk_text_iter_forward_indexable_segment(&iter)) - g_assert_not_reached(); /* must be able to go forward to - end_seg, if end_seg still exists - and was in front. */ - + gtk_text_iter_forward_indexable_segment(&iter); + seg = gtk_text_iter_get_indexable_segment(&iter); } + copy_segment(retval, include_hidden, include_nonchars, &iter, &end); + str = retval->str; g_string_free(retval, FALSE); return str; @@ -2137,9 +2136,9 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) GtkTextBTree *tree; gint byte_index; - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); tree = gtk_text_iter_get_btree(iter); - byte_index = gtk_text_iter_get_line_byte(iter); + byte_index = gtk_text_iter_get_line_index(iter); numTags = gtk_text_tag_table_size(tree->table); @@ -2168,7 +2167,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) || (seg->type == >k_text_toggle_off_type)) { tag = seg->body.toggle.info->tag; - if (tag->elide_set && tag->values->elide) + if (tag->invisible_set && tag->values->invisible) { tags[tag->priority] = tag; tagCnts[tag->priority]++; @@ -2192,7 +2191,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) || (seg->type == >k_text_toggle_off_type)) { tag = seg->body.toggle.info->tag; - if (tag->elide_set && tag->values->elide) + if (tag->invisible_set && tag->values->invisible) { tags[tag->priority] = tag; tagCnts[tag->priority]++; @@ -2221,7 +2220,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) if (summary->toggle_count & 1) { tag = summary->info->tag; - if (tag->elide_set && tag->values->elide) + if (tag->invisible_set && tag->values->invisible) { tags[tag->priority] = tag; tagCnts[tag->priority] += summary->toggle_count; @@ -2233,7 +2232,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) /* * Now traverse from highest priority to lowest, - * take elided value from first odd count (= on) + * take invisible value from first odd count (= on) */ for (i = numTags-1; i >=0; i--) @@ -2243,7 +2242,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) /* FIXME not sure this should be if 0 */ #if 0 #ifndef ALWAYS_SHOW_SELECTION - /* who would make the selection elided? */ + /* who would make the selection invisible? */ if ((tag == tkxt->seltag) && !(tkxt->flags & GOT_FOCUS)) { @@ -2251,7 +2250,7 @@ gtk_text_btree_char_is_invisible (const GtkTextIter *iter) } #endif #endif - invisible = tags[i]->values->elide; + invisible = tags[i]->values->invisible; break; } } @@ -2285,8 +2284,8 @@ redisplay_region (GtkTextBTree *tree, end = tmp; } - start_line = gtk_text_iter_get_line (start); - end_line = gtk_text_iter_get_line (end); + start_line = gtk_text_iter_get_text_line (start); + end_line = gtk_text_iter_get_text_line (end); view = tree->views; while (view != NULL) @@ -2322,7 +2321,7 @@ redisplay_mark(GtkTextLineSegment *mark) (GtkTextMark*)mark); end = iter; - gtk_text_iter_forward_char(&end); + gtk_text_iter_next_char(&end); gtk_text_btree_invalidate_region(mark->body.mark.tree, &iter, &end); @@ -2342,9 +2341,9 @@ ensure_not_off_end(GtkTextBTree *tree, GtkTextLineSegment *mark, GtkTextIter *iter) { - if (gtk_text_iter_get_line_number(iter) == + if (gtk_text_iter_get_line(iter) == gtk_text_btree_line_count(tree)) - gtk_text_iter_backward_char(iter); + gtk_text_iter_prev_char(iter); } static GtkTextLineSegment* @@ -2411,8 +2410,8 @@ real_set_mark(GtkTextBTree *tree, This could hose our iterator... */ gtk_text_btree_unlink_segment(tree, mark, mark->body.mark.line); - mark->body.mark.line = gtk_text_iter_get_line(&iter); - g_assert(mark->body.mark.line == gtk_text_iter_get_line(&iter)); + mark->body.mark.line = gtk_text_iter_get_text_line(&iter); + g_assert(mark->body.mark.line == gtk_text_iter_get_text_line(&iter)); segments_changed(tree); /* make sure the iterator recomputes its segment */ @@ -2423,7 +2422,7 @@ real_set_mark(GtkTextBTree *tree, left_gravity, name); - mark->body.mark.line = gtk_text_iter_get_line(&iter); + mark->body.mark.line = gtk_text_iter_get_text_line(&iter); if (mark->body.mark.name) g_hash_table_insert(tree->mark_table, @@ -2532,6 +2531,10 @@ gtk_text_btree_remove_mark (GtkTextBTree *tree, if (segment->body.mark.name) 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); } @@ -2602,7 +2605,8 @@ gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree, /* We know the tag root has instances of the given tag below it */ - + + continue_outer_loop: g_assert(node != NULL); while (node->level > 0) { @@ -2611,14 +2615,13 @@ gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree, while (node != NULL) { if (gtk_text_btree_node_has_tag(node, tag)) - goto done; + goto continue_outer_loop; + node = node->next; } g_assert(node != NULL); } - done: - g_assert(node != NULL); /* The tag summaries said some node had tag toggles... */ @@ -2933,6 +2936,23 @@ gtk_text_line_byte_has_tag (GtkTextLine *line, return find_toggle_outside_current_line(line, tree, tag); } +gboolean +gtk_text_line_is_last (GtkTextLine *line) +{ + GtkTextBTreeNode *node; + + if (line->next != NULL) + return FALSE; + else + { + node = line->parent; + while (node != NULL && node->next == NULL) + node = node->parent; + + return node == NULL; + } +} + GtkTextLine* gtk_text_line_next (GtkTextLine *line) { @@ -3802,6 +3822,7 @@ gtk_text_line_next_could_contain_tag(GtkTextLine *line, /* We have to find the first sub-node of this node that contains the target tag. */ + continue_outer_loop: while (node->level > 0) { g_assert(node != NULL); /* If this fails, it likely means an @@ -3812,13 +3833,12 @@ gtk_text_line_next_could_contain_tag(GtkTextLine *line, while (node != NULL) { if (gtk_text_btree_node_has_tag(node, tag)) - goto done; + goto continue_outer_loop; node = node->next; } g_assert(node != NULL); } - done: g_assert(node != NULL); g_assert(node->level == 0); @@ -5649,7 +5669,7 @@ gtk_text_btree_link_segment(GtkTextLineSegment *seg, GtkTextLine *line; GtkTextBTree *tree; - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); tree = gtk_text_iter_get_btree(iter); prev = gtk_text_line_segment_split(iter); @@ -5996,11 +6016,11 @@ gtk_text_btree_node_check_consistency(GtkTextBTreeNode *node) } static void -listify_foreach(gpointer key, gpointer value, gpointer user_data) +listify_foreach(GtkTextTag *tag, gpointer user_data) { GSList** listp = user_data; - *listp = g_slist_prepend(*listp, value); + *listp = g_slist_prepend(*listp, tag); } static GSList* diff --git a/gtk/gtktextbtree.h b/gtk/gtktextbtree.h index 72085302e..aba6d5095 100644 --- a/gtk/gtktextbtree.h +++ b/gtk/gtktextbtree.h @@ -162,8 +162,6 @@ GtkTextLine * gtk_text_btree_last_could_contain_tag (GtkTextBTree * /* Chunk of data associated with a line; views can use this to store info at the line. They should "subclass" the header struct here. */ -typedef struct _GtkTextLineData GtkTextLineData; - struct _GtkTextLineData { gpointer view_id; GtkTextLineData *next; @@ -200,6 +198,7 @@ gboolean gtk_text_line_byte_has_tag (GtkTextLine GtkTextBTree *tree, gint byte_in_line, GtkTextTag *tag); +gboolean gtk_text_line_is_last (GtkTextLine *line); GtkTextLine * gtk_text_line_next (GtkTextLine *line); GtkTextLine * gtk_text_line_previous (GtkTextLine *line); void gtk_text_line_add_data (GtkTextLine *line, diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 75af349bf..6612adf88 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -3,12 +3,15 @@ * Developed by Havoc Pennington */ +#include + #include "gtkinvisible.h" #include "gtkselection.h" #include "gtksignal.h" #include "gtktextbuffer.h" #include "gtktextbtree.h" #include "gtktextiterprivate.h" +#include enum { INSERT_TEXT, @@ -58,6 +61,7 @@ static void gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffe const GtkTextIter *start_char, const GtkTextIter *end_char); +static GtkTextBTree* get_btree (GtkTextBuffer *buffer); void gtk_marshal_NONE__INT_POINTER_INT (GtkObject *object, GtkSignalFunc func, @@ -110,10 +114,10 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass) GTK_RUN_LAST, GTK_CLASS_TYPE (object_class), GTK_SIGNAL_OFFSET (GtkTextBufferClass, insert_text), - gtk_marshal_NONE__INT_POINTER_INT, + gtk_marshal_NONE__POINTER_POINTER_INT, GTK_TYPE_NONE, 3, - GTK_TYPE_INT, + GTK_TYPE_POINTER, GTK_TYPE_POINTER, GTK_TYPE_INT); @@ -122,11 +126,11 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass) GTK_RUN_LAST, GTK_CLASS_TYPE (object_class), GTK_SIGNAL_OFFSET (GtkTextBufferClass, delete_text), - gtk_marshal_NONE__INT_INT, + gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, - GTK_TYPE_INT, - GTK_TYPE_INT); + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); signals[CHANGED] = gtk_signal_new ("changed", @@ -172,24 +176,24 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass) GTK_RUN_LAST, GTK_CLASS_TYPE (object_class), GTK_SIGNAL_OFFSET (GtkTextBufferClass, apply_tag), - gtk_marshal_NONE__POINTER_INT_INT, + gtk_marshal_NONE__POINTER_POINTER_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, - GTK_TYPE_INT, - GTK_TYPE_INT); + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); signals[REMOVE_TAG] = gtk_signal_new ("remove_tag", GTK_RUN_LAST, GTK_CLASS_TYPE (object_class), GTK_SIGNAL_OFFSET (GtkTextBufferClass, remove_tag), - gtk_marshal_NONE__POINTER_INT_INT, + gtk_marshal_NONE__POINTER_POINTER_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, - GTK_TYPE_INT, - GTK_TYPE_INT); + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); @@ -264,23 +268,16 @@ GtkTextBuffer* gtk_text_buffer_new (GtkTextTagTable *table) { GtkTextBuffer *text_buffer; - - /* This is broken, need construct_only argument for the tag table - so language bindings can set it. - */ text_buffer = GTK_TEXT_BUFFER (gtk_type_new (gtk_text_buffer_get_type ())); if (table) - text_buffer->tag_table = table; - else - text_buffer->tag_table = gtk_text_tag_table_new(); - - gtk_object_ref (GTK_OBJECT(text_buffer->tag_table)); - gtk_object_sink (GTK_OBJECT(text_buffer->tag_table)); - - text_buffer->tree = gtk_text_btree_new(text_buffer->tag_table, - text_buffer); + { + text_buffer->tag_table = table; + + gtk_object_ref (GTK_OBJECT(text_buffer->tag_table)); + gtk_object_sink (GTK_OBJECT(text_buffer->tag_table)); + } return text_buffer; } @@ -295,11 +292,17 @@ gtk_text_buffer_destroy (GtkObject *object) gtk_widget_destroy(buffer->selection_widget); buffer->selection_widget = NULL; - gtk_object_unref(GTK_OBJECT(buffer->tag_table)); - buffer->tag_table = NULL; - - gtk_text_btree_unref(buffer->tree); - buffer->tree = NULL; + if (buffer->tag_table) + { + gtk_object_unref(GTK_OBJECT(buffer->tag_table)); + buffer->tag_table = NULL; + } + + if (buffer->btree) + { + gtk_text_btree_unref(buffer->btree); + buffer->btree = NULL; + } (* parent_class->destroy) (object); } @@ -314,6 +317,44 @@ gtk_text_buffer_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static GtkTextTagTable* +get_table (GtkTextBuffer *buffer) +{ + if (buffer->tag_table == NULL) + { + buffer->tag_table = gtk_text_tag_table_new (); + + gtk_object_ref (GTK_OBJECT(buffer->tag_table)); + gtk_object_sink (GTK_OBJECT(buffer->tag_table)); + } + + return buffer->tag_table; +} + +static GtkTextBTree* +get_btree (GtkTextBuffer *buffer) +{ + if (buffer->btree == NULL) + buffer->btree = gtk_text_btree_new(gtk_text_buffer_get_tag_table (buffer), + buffer); + + return buffer->btree; +} + +GtkTextBTree* +_gtk_text_buffer_get_btree (GtkTextBuffer *buffer) +{ + return get_btree (buffer); +} + +GtkTextTagTable* +gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer) +{ + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); + + return get_table (buffer); +} + /* * Insertion */ @@ -384,41 +425,42 @@ gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer, gtk_text_buffer_insert(buffer, &iter, text, len); } -void -gtk_text_buffer_insert_at_char (GtkTextBuffer *buffer, - gint char_pos, - const gchar *text, - gint len) +gboolean +gtk_text_buffer_insert_interactive(GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + gboolean editable_by_default) { - GtkTextIter iter; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - g_return_if_fail(text != NULL); + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail(text != NULL, FALSE); - gtk_text_buffer_get_iter_at_char(buffer, &iter, char_pos); - - gtk_text_buffer_insert(buffer, &iter, text, len); + if (gtk_text_iter_editable (iter, editable_by_default)) + { + gtk_text_buffer_insert (buffer, iter, text, len); + return TRUE; + } + else + return FALSE; } -void -gtk_text_buffer_insert_after_line(GtkTextBuffer *buffer, - gint after_this_line, - const gchar *text, - gint len) +gboolean +gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, + const gchar *text, + gint len, + gboolean default_editable) { - GtkTextIter line; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - g_return_if_fail(text != NULL); - - gtk_text_buffer_get_iter_at_line(buffer, - &line, - after_this_line); + GtkTextIter iter; - /* Start of the next line */ - gtk_text_iter_forward_line(&line); + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail(text != NULL, FALSE); + + gtk_text_buffer_get_iter_at_mark(buffer, &iter, + gtk_text_buffer_get_mark (buffer, + "insert")); - gtk_text_buffer_insert(buffer, &line, text, len); + return gtk_text_buffer_insert_interactive (buffer, &iter, text, len, + default_editable); } /* @@ -433,7 +475,7 @@ gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer, g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); g_return_if_fail(start != NULL); g_return_if_fail(end != NULL); - + gtk_text_btree_delete(start, end); /* may have deleted the selection... */ @@ -456,6 +498,8 @@ gtk_text_buffer_emit_delete(GtkTextBuffer *buffer, if (gtk_text_iter_equal(start, end)) return; + gtk_text_iter_reorder (start, end); + gtk_signal_emit(GTK_OBJECT(buffer), signals[DELETE_TEXT], start, end); @@ -473,65 +517,110 @@ gtk_text_buffer_delete (GtkTextBuffer *buffer, gtk_text_buffer_emit_delete(buffer, start, end); } -void -gtk_text_buffer_delete_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char) +gboolean +gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter, + gboolean default_editable) { - GtkTextIter start; - GtkTextIter end; + GtkTextMark *end_mark; + GtkTextMark *start_mark; + GtkTextIter iter; + gboolean current_state; + gboolean deleted_stuff = FALSE; + + /* Delete all editable text in the range start_iter, end_iter */ - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail (start_iter != NULL, FALSE); + g_return_val_if_fail (end_iter != NULL, FALSE); - if (start_char == end_char) - return; + gtk_text_iter_reorder (start_iter, end_iter); + + start_mark = gtk_text_buffer_create_mark (buffer, NULL, + start_iter, TRUE); + end_mark = gtk_text_buffer_create_mark (buffer, NULL, + end_iter, FALSE); + iter = *start_iter; + + current_state = gtk_text_iter_editable (&iter, default_editable); + + while (TRUE) + { + gboolean new_state; + gboolean done = FALSE; + GtkTextIter end; - gtk_text_buffer_get_iter_at_char(buffer, &start, start_char); - gtk_text_buffer_get_iter_at_char(buffer, &end, end_char); + gtk_text_iter_forward_to_tag_toggle (&iter, NULL); + + gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark); + + if (gtk_text_iter_compare (&iter, &end) >= 0) + { + done = TRUE; + iter = end; /* clamp to the last boundary */ + } - gtk_text_buffer_emit_delete(buffer, &start, &end); -} + new_state = gtk_text_iter_editable (&iter, default_editable); -void -gtk_text_buffer_delete_lines(GtkTextBuffer *buffer, - gint start_line, - gint end_line) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + if (current_state == new_state) + { + if (done) + { + if (current_state) + { + /* We're ending an editable region. Delete said region. */ + GtkTextIter start; + + gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); + + gtk_text_buffer_delete (buffer, &start, &iter); + + deleted_stuff = TRUE; + } + + break; + } + else + continue; + } - if (start_line == end_line) - return; + if (current_state && !new_state) + { + /* End of an editable region. Delete it. */ + GtkTextIter start; + + gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); + + gtk_text_buffer_delete (buffer, &start, &iter); - /* start of the start line */ - gtk_text_buffer_get_iter_at_line(buffer, &start, start_line); - - /* start of the end line; note that we don't delete the end_line, we - want to delete up to the start of it */ - gtk_text_buffer_get_iter_at_line(buffer, &end, end_line); - - gtk_text_buffer_delete (buffer, &start, &end); -} + current_state = FALSE; + deleted_stuff = TRUE; + } + else + { + /* We are at the start of an editable region. We won't be deleting + * the previous region. Move start mark to start of this region. + */ -void -gtk_text_buffer_delete_from_line(GtkTextBuffer *buffer, - gint line, - gint start_char, gint end_char) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - - if (start_char == end_char) - return; + g_assert (!current_state && new_state); + + gtk_text_buffer_move_mark (buffer, start_mark, + &iter); - gtk_text_buffer_get_iter_at_line_char(buffer, &start, line, start_char); - gtk_text_buffer_get_iter_at_line_char(buffer, &end, line, end_char); - gtk_text_buffer_delete(buffer, &start, &end); + current_state = TRUE; + } + + if (done) + break; + } + + + gtk_text_buffer_delete_mark (buffer, start_mark); + gtk_text_buffer_delete_mark (buffer, end_mark); + + return deleted_stuff; } /* @@ -554,49 +643,6 @@ gtk_text_buffer_get_text (GtkTextBuffer *buffer, return gtk_text_iter_get_visible_text(start, end); } -gchar* -gtk_text_buffer_get_text_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char, - gboolean include_hidden_chars) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - - if (start_char == end_char) - return g_strdup(""); - - gtk_text_buffer_get_iter_at_char (buffer, &start, start_char); - gtk_text_buffer_get_iter_at_char (buffer, &end, end_char); - - return gtk_text_buffer_get_text(buffer, &start, &end, - include_hidden_chars); -} - -gchar* -gtk_text_buffer_get_text_from_line (GtkTextBuffer *buffer, - gint line, - gint start_char, - gint end_char, - gboolean include_hidden_chars) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - - if (start_char == end_char) - return g_strdup(""); - - gtk_text_buffer_get_iter_at_line_char (buffer, &start, line, start_char); - gtk_text_buffer_get_iter_at_line_char (buffer, &end, line, end_char); - - return gtk_text_buffer_get_text(buffer, &start, &end, - include_hidden_chars); -} - gchar* gtk_text_buffer_get_slice (GtkTextBuffer *buffer, const GtkTextIter *start, @@ -613,49 +659,6 @@ gtk_text_buffer_get_slice (GtkTextBuffer *buffer, return gtk_text_iter_get_visible_slice(start, end); } -gchar* -gtk_text_buffer_get_slice_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char, - gboolean include_hidden_chars) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - - if (start_char == end_char) - return g_strdup(""); - - gtk_text_buffer_get_iter_at_char (buffer, &start, start_char); - gtk_text_buffer_get_iter_at_char (buffer, &end, end_char); - - return gtk_text_buffer_get_slice(buffer, &start, &end, - include_hidden_chars); -} - -gchar* -gtk_text_buffer_get_slice_from_line (GtkTextBuffer *buffer, - gint line, - gint start_char, - gint end_char, - gboolean include_hidden_chars) -{ - GtkTextIter start; - GtkTextIter end; - - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - - if (start_char == end_char) - return g_strdup(""); - - gtk_text_buffer_get_iter_at_line_char (buffer, &start, line, start_char); - gtk_text_buffer_get_iter_at_line_char (buffer, &end, line, end_char); - - return gtk_text_buffer_get_slice(buffer, &start, &end, - include_hidden_chars); -} - /* * Pixmaps */ @@ -679,22 +682,6 @@ gtk_text_buffer_insert_pixmap (GtkTextBuffer *buffer, gtk_text_buffer_set_modified(buffer, TRUE); } -void -gtk_text_buffer_insert_pixmap_at_char (GtkTextBuffer *buffer, - gint char_pos, - GdkPixmap *pixmap, - GdkBitmap *mask) -{ - GtkTextIter iter; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - g_return_if_fail(pixmap != NULL); - - gtk_text_buffer_get_iter_at_char(buffer, &iter, char_pos); - - gtk_text_buffer_insert_pixmap(buffer, &iter, pixmap, mask); -} - /* * Mark manipulation */ @@ -715,7 +702,7 @@ gtk_text_buffer_mark_set (GtkTextBuffer *buffer, to modify the default behavior. */ gtk_signal_emit(GTK_OBJECT(buffer), signals[MARK_SET], - &location, + location, mark); } @@ -745,22 +732,20 @@ gtk_text_buffer_set_mark(GtkTextBuffer *buffer, GtkTextIter location; GtkTextMark *mark; - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - - mark = gtk_text_btree_set_mark(buffer->tree, + mark = gtk_text_btree_set_mark(get_btree (buffer), existing_mark, mark_name, left_gravity, iter, should_exist); - if (gtk_text_btree_mark_is_insert(buffer->tree, mark) || - gtk_text_btree_mark_is_selection_bound(buffer->tree, mark)) + if (gtk_text_btree_mark_is_insert(get_btree (buffer), mark) || + gtk_text_btree_mark_is_selection_bound(get_btree (buffer), mark)) { gtk_text_buffer_update_primary_selection(buffer); } - gtk_text_btree_get_iter_at_mark(buffer->tree, + gtk_text_btree_get_iter_at_mark(get_btree (buffer), &location, mark); @@ -775,6 +760,8 @@ gtk_text_buffer_create_mark(GtkTextBuffer *buffer, const GtkTextIter *where, gboolean left_gravity) { + 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); } @@ -785,6 +772,8 @@ gtk_text_buffer_move_mark(GtkTextBuffer *buffer, 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)); gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE); } @@ -794,9 +783,11 @@ 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)); - gtk_text_btree_get_iter_at_mark(buffer->tree, + gtk_text_btree_get_iter_at_mark(get_btree (buffer), iter, mark); } @@ -805,9 +796,11 @@ void gtk_text_buffer_delete_mark(GtkTextBuffer *buffer, 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)); - gtk_text_btree_remove_mark (buffer->tree, 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 @@ -825,7 +818,7 @@ gtk_text_buffer_get_mark (GtkTextBuffer *buffer, 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(buffer->tree, name); + mark = gtk_text_btree_get_mark_by_name(get_btree (buffer), name); return mark; } @@ -834,13 +827,20 @@ void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, const GtkTextIter *where) { + GtkTextIter real; + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + + real = *where; + + if (gtk_text_iter_is_last (&real)) + gtk_text_iter_prev_char (&real); - gtk_text_btree_place_cursor(buffer->tree, where); - gtk_text_buffer_mark_set (buffer, where, + gtk_text_btree_place_cursor(get_btree (buffer), &real); + gtk_text_buffer_mark_set (buffer, &real, gtk_text_buffer_get_mark (buffer, "insert")); - gtk_text_buffer_mark_set (buffer, where, + gtk_text_buffer_mark_set (buffer, &real, gtk_text_buffer_get_mark (buffer, "selection_bound")); } @@ -856,11 +856,10 @@ gtk_text_buffer_create_tag(GtkTextBuffer *buffer, GtkTextTag *tag; g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - g_return_val_if_fail(tag_name != NULL, NULL); tag = gtk_text_tag_new(tag_name); - gtk_text_tag_table_add(buffer->tag_table, tag); + gtk_text_tag_table_add(get_table (buffer), tag); return tag; } @@ -886,26 +885,12 @@ gtk_text_buffer_real_remove_tag (GtkTextBuffer *buffer, static void gtk_text_buffer_emit_tag(GtkTextBuffer *buffer, - const gchar *name, + GtkTextTag *tag, gboolean apply, const GtkTextIter *start, const GtkTextIter *end) { - GtkTextTag *tag; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - g_return_if_fail(name != NULL); - g_return_if_fail(start != NULL); - g_return_if_fail(end != NULL); - - tag = gtk_text_tag_table_lookup(buffer->tag_table, - name); - - if (tag == NULL) - { - g_warning("Unknown tag `%s'", name); - return; - } + g_return_if_fail(tag != NULL); if (apply) gtk_signal_emit(GTK_OBJECT(buffer), signals[APPLY_TAG], @@ -918,88 +903,122 @@ gtk_text_buffer_emit_tag(GtkTextBuffer *buffer, void gtk_text_buffer_apply_tag(GtkTextBuffer *buffer, - const gchar *name, + GtkTextTag *tag, const GtkTextIter *start, const GtkTextIter *end) { - gtk_text_buffer_emit_tag(buffer, name, TRUE, start, end); + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail(GTK_IS_TEXT_TAG (tag)); + g_return_if_fail(start != NULL); + g_return_if_fail(end != NULL); + + gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end); } void gtk_text_buffer_remove_tag(GtkTextBuffer *buffer, - const gchar *name, + GtkTextTag *tag, const GtkTextIter *start, const GtkTextIter *end) { - gtk_text_buffer_emit_tag(buffer, name, FALSE, start, end); + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail(GTK_IS_TEXT_TAG (tag)); + g_return_if_fail(start != NULL); + g_return_if_fail(end != NULL); + + gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end); } + void -gtk_text_buffer_apply_tag_to_chars(GtkTextBuffer *buffer, +gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer, const gchar *name, - gint start_char, gint end_char) + const GtkTextIter *start, + const GtkTextIter *end) { - GtkTextIter start; - GtkTextIter end; - - gtk_text_buffer_get_iter_at_char(buffer, &start, start_char); - gtk_text_buffer_get_iter_at_char(buffer, &end, end_char); + GtkTextTag *tag; + + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail(name != NULL); + g_return_if_fail(start != NULL); + g_return_if_fail(end != NULL); - gtk_text_buffer_apply_tag(buffer, name, &start, &end); + tag = gtk_text_tag_table_lookup(get_table (buffer), + name); + + if (tag == NULL) + { + g_warning("Unknown tag `%s'", name); + return; + } + + gtk_text_buffer_emit_tag(buffer, tag, TRUE, start, end); } void -gtk_text_buffer_remove_tag_from_chars(GtkTextBuffer *buffer, - const gchar *name, - gint start_char, gint end_char) +gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer, + const gchar *name, + const GtkTextIter *start, + const GtkTextIter *end) { - GtkTextIter start; - GtkTextIter end; + GtkTextTag *tag; + + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); + g_return_if_fail(name != NULL); + g_return_if_fail(start != NULL); + g_return_if_fail(end != NULL); - gtk_text_buffer_get_iter_at_char(buffer, &start, start_char); - gtk_text_buffer_get_iter_at_char(buffer, &end, end_char); + tag = gtk_text_tag_table_lookup(get_table (buffer), + name); + + if (tag == NULL) + { + g_warning("Unknown tag `%s'", name); + return; + } - gtk_text_buffer_remove_tag(buffer, name, &start, &end); + gtk_text_buffer_emit_tag(buffer, tag, FALSE, start, end); } + /* * Obtain various iterators */ void -gtk_text_buffer_get_iter_at_line_char (GtkTextBuffer *buffer, - GtkTextIter *iter, - gint line_number, - gint char_number) +gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer, + GtkTextIter *iter, + gint line_number, + gint char_offset) { g_return_if_fail(iter != NULL); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_btree_get_iter_at_line_char(buffer->tree, - iter, line_number, char_number); + gtk_text_btree_get_iter_at_line_char(get_btree (buffer), + iter, line_number, char_offset); } void gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer, GtkTextIter *iter, - gint line_number) + gint line_number) { g_return_if_fail(iter != NULL); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_buffer_get_iter_at_line_char(buffer, iter, line_number, 0); + gtk_text_buffer_get_iter_at_line_offset (buffer, iter, line_number, 0); } void -gtk_text_buffer_get_iter_at_char (GtkTextBuffer *buffer, - GtkTextIter *iter, - gint char_index) +gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buffer, + GtkTextIter *iter, + gint char_offset) { g_return_if_fail(iter != NULL); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_btree_get_iter_at_char(buffer->tree, iter, char_index); + gtk_text_btree_get_iter_at_char(get_btree (buffer), iter, char_offset); } void @@ -1009,7 +1028,7 @@ gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer, g_return_if_fail(iter != NULL); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_btree_get_last_iter(buffer->tree, iter); + gtk_text_btree_get_last_iter(get_btree (buffer), iter); } void @@ -1021,21 +1040,8 @@ gtk_text_buffer_get_bounds (GtkTextBuffer *buffer, g_return_if_fail(end != NULL); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - gtk_text_btree_get_iter_at_char(buffer->tree, start, 0); - gtk_text_btree_get_last_iter(buffer->tree, end); -} - - -gboolean -gtk_text_buffer_get_iter_from_string(GtkTextBuffer *buffer, - GtkTextIter *iter, - const gchar *index_string) -{ - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); - - return gtk_text_btree_get_iter_from_string(buffer->tree, - iter, - index_string); + gtk_text_btree_get_iter_at_char(get_btree (buffer), start, 0); + gtk_text_btree_get_last_iter(get_btree (buffer), end); } /* @@ -1114,7 +1120,7 @@ gtk_text_buffer_get_line_count(GtkTextBuffer *buffer) { g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0); - return gtk_text_btree_line_count(buffer->tree); + return gtk_text_btree_line_count(get_btree (buffer)); } gint @@ -1122,7 +1128,7 @@ gtk_text_buffer_get_char_count(GtkTextBuffer *buffer) { g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), 0); - return gtk_text_btree_char_count(buffer->tree); + return gtk_text_btree_char_count(get_btree (buffer)); } GSList* @@ -1426,8 +1432,12 @@ selection_received (GtkWidget *widget, utf = gtk_text_latin1_to_utf((const gchar*)selection_data->data, selection_data->length); - gtk_text_buffer_insert (buffer, &insert_point, - utf, -1); + if (buffer->paste_interactive) + gtk_text_buffer_insert_interactive (buffer, &insert_point, + utf, -1, buffer->paste_default_editable); + else + gtk_text_buffer_insert (buffer, &insert_point, + utf, -1); g_free(utf); } break; @@ -1451,15 +1461,30 @@ selection_received (GtkWidget *widget, &list); for (i=0; ipaste_interactive) + gtk_text_buffer_insert_interactive (buffer, &insert_point, + utf, -1, buffer->paste_default_editable); + else + gtk_text_buffer_insert (buffer, &insert_point, + utf, -1); + + if (free_utf) + g_free(utf); } if (count > 0) @@ -1546,9 +1571,14 @@ gtk_text_buffer_update_clipboard_selection(GtkTextBuffer *buffer) } static void -paste(GtkTextBuffer *buffer, GdkAtom selection, guint32 time) +paste (GtkTextBuffer *buffer, GdkAtom selection, guint32 time, + gboolean interactive, + gboolean default_editable) { ensure_handlers(buffer); + + buffer->paste_interactive = interactive; + buffer->paste_default_editable = default_editable; gtk_selection_convert (buffer->selection_widget, selection, utf8_atom, time); @@ -1557,25 +1587,31 @@ paste(GtkTextBuffer *buffer, GdkAtom selection, guint32 time) void gtk_text_buffer_paste_primary_selection(GtkTextBuffer *buffer, GtkTextIter *override_location, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { if (override_location != NULL) gtk_text_buffer_create_mark(buffer, "__paste_point_override", override_location, FALSE); - paste(buffer, GDK_SELECTION_PRIMARY, time); + paste(buffer, GDK_SELECTION_PRIMARY, time, interactive, default_editable); } void gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { - paste(buffer, clipboard_atom, time); + paste(buffer, clipboard_atom, time, interactive, default_editable); } gboolean -gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) +gtk_text_buffer_delete_selection (GtkTextBuffer *buffer, + gboolean interactive, + gboolean default_editable) { GtkTextIter start; GtkTextIter end; @@ -1586,7 +1622,11 @@ gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) } else { - gtk_text_buffer_delete(buffer, &start, &end); + if (interactive) + gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); + else + gtk_text_buffer_delete (buffer, &start, &end); + gtk_text_buffer_update_primary_selection(buffer); return TRUE; /* We deleted stuff */ } @@ -1595,7 +1635,9 @@ gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) static void cut_or_copy(GtkTextBuffer *buffer, guint32 time, - gboolean delete_region_after) + gboolean delete_region_after, + gboolean interactive, + gboolean default_editable) { /* We prefer to cut the selected region between selection_bound and insertion point. If that region is empty, then we cut the region @@ -1629,22 +1671,29 @@ cut_or_copy(GtkTextBuffer *buffer, set_clipboard_contents_nocopy(buffer, text); if (delete_region_after) - gtk_text_buffer_delete(buffer, &start, &end); + { + if (interactive) + gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); + else + gtk_text_buffer_delete (buffer, &start, &end); + } } } void gtk_text_buffer_cut (GtkTextBuffer *buffer, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { - cut_or_copy(buffer, time, TRUE); + cut_or_copy(buffer, time, TRUE, interactive, default_editable); } void gtk_text_buffer_copy (GtkTextBuffer *buffer, guint32 time) { - cut_or_copy(buffer, time, FALSE); + cut_or_copy(buffer, time, FALSE, FALSE, TRUE); } @@ -1656,7 +1705,7 @@ gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, 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 (buffer->tree, start, end); + return gtk_text_btree_get_selection_bounds (get_btree (buffer), start, end); } @@ -1667,5 +1716,6 @@ gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, void gtk_text_buffer_spew(GtkTextBuffer *buffer) { - gtk_text_btree_spew(buffer->tree); + gtk_text_btree_spew(get_btree (buffer)); } + diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h index a8ef0eb65..3f164c5ae 100644 --- a/gtk/gtktextbuffer.h +++ b/gtk/gtktextbuffer.h @@ -30,7 +30,7 @@ struct _GtkTextBuffer { GtkObject parent_instance; GtkTextTagTable *tag_table; - GtkTextBTree *tree; + GtkTextBTree *btree; /* Text currently pasted to the clipboard */ gchar *clipboard_text; @@ -42,6 +42,8 @@ struct _GtkTextBuffer { GtkWidget *selection_widget; gboolean have_selection; gboolean selection_handlers_installed; + gboolean paste_interactive; + gboolean paste_default_editable; }; struct _GtkTextBufferClass { @@ -95,6 +97,7 @@ gint gtk_text_buffer_get_line_count (GtkTextBuffer *buffer); gint gtk_text_buffer_get_char_count (GtkTextBuffer *buffer); +GtkTextTagTable* gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer); /* Insert into the buffer */ void gtk_text_buffer_insert (GtkTextBuffer *buffer, @@ -104,71 +107,45 @@ void gtk_text_buffer_insert (GtkTextBuffer *buffer, void gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer, const gchar *text, gint len); -void gtk_text_buffer_insert_at_char (GtkTextBuffer *buffer, - gint char_pos, - const gchar *text, - gint len); -void gtk_text_buffer_insert_after_line (GtkTextBuffer *buffer, - gint after_this_line, - const gchar *text, - gint len); +gboolean gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + gboolean default_editable); +gboolean gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, + const gchar *text, + gint len, + gboolean default_editable); /* Delete from the buffer */ +void gtk_text_buffer_delete (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter); +gboolean gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter, + gboolean default_editable); + + -void gtk_text_buffer_delete (GtkTextBuffer *buffer, - GtkTextIter *start_iter, - GtkTextIter *end_iter); -void gtk_text_buffer_delete_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char); -void gtk_text_buffer_delete_lines (GtkTextBuffer *buffer, - gint start_line, - gint end_line); -void gtk_text_buffer_delete_from_line (GtkTextBuffer *buffer, - gint line, - gint start_char, - gint end_char); /* Obtain strings from the buffer */ gchar *gtk_text_buffer_get_text (GtkTextBuffer *buffer, const GtkTextIter *start_iter, const GtkTextIter *end_iter, gboolean include_hidden_chars); -gchar *gtk_text_buffer_get_text_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char, - gboolean include_hidden_chars); -gchar *gtk_text_buffer_get_text_from_line (GtkTextBuffer *buffer, - gint line, - gint start_char, - gint end_char, - gboolean include_hidden_chars); + gchar *gtk_text_buffer_get_slice (GtkTextBuffer *buffer, const GtkTextIter *start_iter, const GtkTextIter *end_iter, gboolean include_hidden_chars); -gchar *gtk_text_buffer_get_slice_chars (GtkTextBuffer *buffer, - gint start_char, - gint end_char, - gboolean include_hidden_chars); -gchar *gtk_text_buffer_get_slice_from_line (GtkTextBuffer *buffer, - gint line, - gint start_char, - gint end_char, - gboolean include_hidden_chars); /* Insert a pixmap */ void gtk_text_buffer_insert_pixmap (GtkTextBuffer *buffer, GtkTextIter *iter, GdkPixmap *pixmap, GdkBitmap *mask); -void gtk_text_buffer_insert_pixmap_at_char (GtkTextBuffer *buffer, - gint char_index, - GdkPixmap *pixmap, - GdkBitmap *mask); - - /* Mark manipulation */ GtkTextMark *gtk_text_buffer_create_mark (GtkTextBuffer *buffer, @@ -191,68 +168,56 @@ void gtk_text_buffer_place_cursor (GtkTextBuffer *buffer, /* Tag manipulation */ -void gtk_text_buffer_apply_tag_to_chars (GtkTextBuffer *buffer, - const gchar *name, - gint start_char, - gint end_char); -void gtk_text_buffer_remove_tag_from_chars (GtkTextBuffer *buffer, - const gchar *name, - gint start_char, - gint end_char); void gtk_text_buffer_apply_tag (GtkTextBuffer *buffer, - const gchar *name, + GtkTextTag *tag, const GtkTextIter *start_index, const GtkTextIter *end_index); void gtk_text_buffer_remove_tag (GtkTextBuffer *buffer, + GtkTextTag *tag, + const GtkTextIter *start_index, + const GtkTextIter *end_index); +void gtk_text_buffer_apply_tag_by_name (GtkTextBuffer *buffer, + const gchar *name, + const GtkTextIter *start_index, + const GtkTextIter *end_index); +void gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer, const gchar *name, const GtkTextIter *start_index, const GtkTextIter *end_index); - /* You can either ignore the return value, or use it to - set the attributes of the tag */ + * set the attributes of the tag. tag_name can be NULL + */ GtkTextTag *gtk_text_buffer_create_tag (GtkTextBuffer *buffer, const gchar *tag_name); /* Obtain iterators pointed at various places, then you can move the iterator around using the GtkTextIter operators */ +void gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer, + GtkTextIter *iter, + gint line_number, + gint char_offset); +void gtk_text_buffer_get_iter_at_offset (GtkTextBuffer *buffer, + GtkTextIter *iter, + gint char_offset); +void gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer, + GtkTextIter *iter, + gint line_number); +void gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer, + GtkTextIter *iter); +void gtk_text_buffer_get_bounds (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end); +void gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer, + GtkTextIter *iter, + GtkTextMark *mark); -void gtk_text_buffer_get_iter_at_line_char (GtkTextBuffer *buffer, - GtkTextIter *iter, - gint line_number, - gint char_number); -void gtk_text_buffer_get_iter_at_char (GtkTextBuffer *buffer, - GtkTextIter *iter, - gint char_index); -void gtk_text_buffer_get_iter_at_line (GtkTextBuffer *buffer, - GtkTextIter *iter, - gint line_number); -void gtk_text_buffer_get_last_iter (GtkTextBuffer *buffer, - GtkTextIter *iter); -void gtk_text_buffer_get_bounds (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end); -void gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer, - GtkTextIter *iter, - GtkTextMark *mark); /* There's no get_first_iter because you just get the iter for line or char 0 */ -/* - Parses a string, read the man page for the Tk text widget; the only - variation from that is we don't support getting the index at a - certain pixel since the buffer has no pixel knowledge. This - function is mostly useful for language bindings I think. -*/ -gboolean gtk_text_buffer_get_iter_from_string (GtkTextBuffer *buffer, - GtkTextIter *iter, - const gchar *iter_string); - - - GSList *gtk_text_buffer_get_tags (GtkTextBuffer *buffer, const GtkTextIter *iter); @@ -269,16 +234,26 @@ void gtk_text_buffer_set_modified (GtkTextBuffer *buffer, void gtk_text_buffer_set_clipboard_contents (GtkTextBuffer *buffer, const gchar *text); const gchar *gtk_text_buffer_get_clipboard_contents (GtkTextBuffer *buffer); + + void gtk_text_buffer_paste_primary_selection (GtkTextBuffer *buffer, GtkTextIter *override_location, - guint32 time); -gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer); + guint32 time, + gboolean interactive, + gboolean default_editable); +gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer, + gboolean interactive, + gboolean default_editable); void gtk_text_buffer_cut (GtkTextBuffer *buffer, - guint32 time); + guint32 time, + gboolean interactive, + gboolean default_editable); void gtk_text_buffer_copy (GtkTextBuffer *buffer, guint32 time); void gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer, - guint32 time); + guint32 time, + gboolean interactive, + gboolean default_editable); gboolean gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end); @@ -302,6 +277,8 @@ gboolean gtk_text_buffer_find_regexp(GtkTextBuffer *buffer, /* INTERNAL private stuff */ void gtk_text_buffer_spew (GtkTextBuffer *buffer); +GtkTextBTree* _gtk_text_buffer_get_btree (GtkTextBuffer *buffer); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c index 8fa44b3ff..0ddcb3789 100644 --- a/gtk/gtktextdisplay.c +++ b/gtk/gtktextdisplay.c @@ -585,21 +585,23 @@ gtk_text_layout_draw (GtkTextLayout *layout, GtkTextIter line_start, line_end; gint byte_count = gtk_text_line_byte_count (line); - gtk_text_btree_get_iter_at_line (layout->buffer->tree, &line_start, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + &line_start, line, 0); - gtk_text_btree_get_iter_at_line (layout->buffer->tree, &line_end, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + &line_end, line, byte_count - 1); if (gtk_text_iter_compare (&selection_start, &line_end) < 0 && gtk_text_iter_compare (&selection_end, &line_start) > 0) { if (gtk_text_iter_compare (&selection_start, &line_start) >= 0) - selection_start_index = gtk_text_iter_get_line_byte (&selection_start); + selection_start_index = gtk_text_iter_get_line_index (&selection_start); else selection_start_index = -1; if (gtk_text_iter_compare (&selection_end, &line_end) <= 0) - selection_end_index = gtk_text_iter_get_line_byte (&selection_end); + selection_end_index = gtk_text_iter_get_line_index (&selection_end); else selection_end_index = byte_count; } diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c index 953045e0b..48e6b17ed 100644 --- a/gtk/gtktextiter.c +++ b/gtk/gtktextiter.c @@ -2,6 +2,7 @@ #include "gtktextbtree.h" #include "gtktextiterprivate.h" #include "gtkdebug.h" +#include #include typedef struct _GtkTextRealIter GtkTextRealIter; @@ -34,9 +35,9 @@ struct _GtkTextRealIter { and ditto for char offsets. */ gint segment_byte_offset; gint segment_char_offset; - /* These are here for binary-compatible expansion space. */ + /* Pads are here for binary-compatible expansion space. */ gpointer pad1; - gint pad2; + guint pad2; }; /* These "set" functions should not assume any fields @@ -114,7 +115,8 @@ iter_set_from_segment(GtkTextRealIter *iter, /* This function ensures that the segment-dependent information is truly computed lazily; often we don't need to do the full make_real - work. */ + work. This ensures the btree and line are valid, but doesn't + update the segments. */ static GtkTextRealIter* gtk_text_iter_make_surreal(const GtkTextIter *_iter) { @@ -308,9 +310,9 @@ ensure_char_offsets(GtkTextRealIter *iter) g_assert(iter->line_byte_offset >= 0); gtk_text_line_byte_to_char_offsets(iter->line, - iter->line_byte_offset, - &iter->line_char_offset, - &iter->segment_char_offset); + iter->line_byte_offset, + &iter->line_char_offset, + &iter->segment_char_offset); } } @@ -322,9 +324,9 @@ ensure_byte_offsets(GtkTextRealIter *iter) g_assert(iter->line_char_offset >= 0); gtk_text_line_char_to_byte_offsets(iter->line, - iter->line_char_offset, - &iter->line_byte_offset, - &iter->segment_byte_offset); + iter->line_char_offset, + &iter->line_byte_offset, + &iter->segment_byte_offset); } } @@ -457,7 +459,7 @@ gtk_text_iter_get_segment_char(const GtkTextIter *iter) /* This function does not require a still-valid iterator */ GtkTextLine* -gtk_text_iter_get_line(const GtkTextIter *iter) +gtk_text_iter_get_text_line(const GtkTextIter *iter) { const GtkTextRealIter *real; @@ -487,7 +489,7 @@ gtk_text_iter_get_btree(const GtkTextIter *iter) */ gint -gtk_text_iter_get_char_index(const GtkTextIter *iter) +gtk_text_iter_get_offset(const GtkTextIter *iter) { GtkTextRealIter *real; @@ -512,7 +514,7 @@ gtk_text_iter_get_char_index(const GtkTextIter *iter) } gint -gtk_text_iter_get_line_number(const GtkTextIter *iter) +gtk_text_iter_get_line(const GtkTextIter *iter) { GtkTextRealIter *real; @@ -533,7 +535,7 @@ gtk_text_iter_get_line_number(const GtkTextIter *iter) } gint -gtk_text_iter_get_line_char(const GtkTextIter *iter) +gtk_text_iter_get_line_offset(const GtkTextIter *iter) { GtkTextRealIter *real; @@ -553,7 +555,7 @@ gtk_text_iter_get_line_char(const GtkTextIter *iter) } gint -gtk_text_iter_get_line_byte(const GtkTextIter *iter) +gtk_text_iter_get_line_index(const GtkTextIter *iter) { GtkTextRealIter *real; @@ -690,6 +692,38 @@ gtk_text_iter_get_pixmap (const GtkTextIter *iter, } } +GSList* +gtk_text_iter_get_marks (const GtkTextIter *iter) +{ + GtkTextRealIter *real; + GtkTextLineSegment *seg; + GSList *retval; + + g_return_val_if_fail(iter != NULL, NULL); + + real = gtk_text_iter_make_real(iter); + + if (real == NULL) + return NULL; + + check_invariants(iter); + + retval = NULL; + seg = real->any_segment; + while (seg != real->segment) + { + if (seg->type == >k_text_left_mark_type || + seg->type == >k_text_right_mark_type) + retval = g_slist_prepend(retval, (GtkTextMark*)seg); + + seg = seg->next; + } + + /* The returned list isn't guaranteed to be in any special order, + and it isn't. */ + return retval; +} + GSList* gtk_text_iter_get_toggled_tags (const GtkTextIter *iter, gboolean toggled_on) @@ -858,6 +892,43 @@ gtk_text_iter_has_tag (const GtkTextIter *iter, } } +gboolean +gtk_text_iter_editable (const GtkTextIter *iter, + gboolean default_setting) +{ + GtkTextStyleValues *values; + gboolean retval; + + values = gtk_text_style_values_new (); + + values->editable = default_setting; + + gtk_text_iter_get_style_values (iter, values); + + retval = values->editable; + + gtk_text_style_values_unref (values); + + return retval; +} + +static gchar* +gtk_text_iter_get_language (const GtkTextIter *iter) +{ + GtkTextStyleValues *values; + gchar *retval; + + values = gtk_text_style_values_new (); + + gtk_text_iter_get_style_values (iter, values); + + retval = g_strdup (values->language); + + gtk_text_style_values_unref (values); + + return retval; +} + gboolean gtk_text_iter_starts_line (const GtkTextIter *iter) { @@ -893,6 +964,29 @@ gtk_text_iter_ends_line (const GtkTextIter *iter) return gtk_text_iter_get_char(iter) == '\n'; } +gboolean +gtk_text_iter_is_last (const GtkTextIter *iter) +{ + GtkTextRealIter *real; + + g_return_val_if_fail(iter != NULL, FALSE); + + real = gtk_text_iter_make_surreal(iter); + + if (real == NULL) + return FALSE; + + check_invariants(iter); + + return gtk_text_line_is_last(real->line); +} + +gboolean +gtk_text_iter_is_first (const GtkTextIter *iter) +{ + return gtk_text_iter_get_offset (iter) == 0; +} + gint gtk_text_iter_get_chars_in_line (const GtkTextIter *iter) { @@ -933,10 +1027,45 @@ gtk_text_iter_get_chars_in_line (const GtkTextIter *iter) return count; } +gboolean +gtk_text_iter_get_style_values (const GtkTextIter *iter, + GtkTextStyleValues *values) +{ + GtkTextTag** tags; + gint tag_count = 0; + + /* Get the tags at this spot */ + tags = gtk_text_btree_get_tags (iter, &tag_count); + + /* No tags, use default style */ + if (tags == NULL || tag_count == 0) + { + if (tags) + g_free (tags); + + return FALSE; + } + + /* Sort tags in ascending order of priority */ + gtk_text_tag_array_sort (tags, tag_count); + + gtk_text_style_values_fill_from_tags (values, + tags, + tag_count); + + g_free (tags); + + return TRUE; +} + /* * Increments/decrements */ +/* The return value of this indicates WHETHER WE MOVED. + * The return value of public functions indicates + * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE) + */ static gboolean forward_line_leaving_caches_unmodified(GtkTextRealIter *real) { @@ -961,7 +1090,7 @@ forward_line_leaving_caches_unmodified(GtkTextRealIter *real) real->segment = real->any_segment; while (real->segment->char_count == 0) real->segment = real->segment->next; - + return TRUE; } else @@ -1126,8 +1255,11 @@ gtk_text_iter_forward_indexable_segment(GtkTextIter *iter) g_assert(gtk_text_iter_starts_line(iter)); check_invariants(iter); - - return TRUE; + + if (gtk_text_iter_is_last (iter)) + return FALSE; + else + return TRUE; } else { @@ -1145,10 +1277,12 @@ gtk_text_iter_backward_indexable_segment(GtkTextIter *iter) { g_warning("FIXME"); + + return FALSE; } gboolean -gtk_text_iter_forward_char(GtkTextIter *iter) +gtk_text_iter_next_char(GtkTextIter *iter) { GtkTextRealIter *real; @@ -1166,7 +1300,7 @@ gtk_text_iter_forward_char(GtkTextIter *iter) } gboolean -gtk_text_iter_backward_char(GtkTextIter *iter) +gtk_text_iter_prev_char(GtkTextIter *iter) { g_return_val_if_fail(iter != NULL, FALSE); @@ -1224,17 +1358,23 @@ gtk_text_iter_forward_chars(GtkTextIter *iter, gint count) check_invariants(iter); - current_char_index = gtk_text_iter_get_char_index(iter); + current_char_index = gtk_text_iter_get_offset(iter); if (current_char_index == gtk_text_btree_char_count(real->tree)) return FALSE; /* can't move forward */ new_char_index = current_char_index + count; - gtk_text_iter_set_char_index(iter, new_char_index); + gtk_text_iter_set_offset(iter, new_char_index); check_invariants(iter); - return TRUE; + /* Return FALSE if we're on the non-dereferenceable end + * iterator. + */ + if (gtk_text_iter_is_last (iter)) + return FALSE; + else + return TRUE; } } @@ -1300,7 +1440,7 @@ gtk_text_iter_backward_chars(GtkTextIter *iter, gint count) gint current_char_index; gint new_char_index; - current_char_index = gtk_text_iter_get_char_index(iter); + current_char_index = gtk_text_iter_get_offset(iter); if (current_char_index == 0) return FALSE; /* can't move backward */ @@ -1308,7 +1448,7 @@ gtk_text_iter_backward_chars(GtkTextIter *iter, gint count) new_char_index = current_char_index - count; if (new_char_index < 0) new_char_index = 0; - gtk_text_iter_set_char_index(iter, new_char_index); + gtk_text_iter_set_offset(iter, new_char_index); check_invariants(iter); @@ -1336,8 +1476,11 @@ gtk_text_iter_forward_line(GtkTextIter *iter) adjust_line_number(real, 1); check_invariants(iter); - - return TRUE; + + if (gtk_text_iter_is_last (iter)) + return FALSE; + else + return TRUE; } else { @@ -1423,13 +1566,13 @@ gtk_text_iter_forward_lines(GtkTextIter *iter, gint count) { gint old_line; - old_line = gtk_text_iter_get_line_number(iter); + old_line = gtk_text_iter_get_line(iter); - gtk_text_iter_set_line_number(iter, old_line + count); + gtk_text_iter_set_line(iter, old_line + count); check_invariants(iter); - return (gtk_text_iter_get_line_number(iter) != old_line); + return (gtk_text_iter_get_line(iter) != old_line); } } @@ -1448,93 +1591,161 @@ gtk_text_iter_backward_lines(GtkTextIter *iter, gint count) { gint old_line; - old_line = gtk_text_iter_get_line_number(iter); + old_line = gtk_text_iter_get_line(iter); - gtk_text_iter_set_line_number(iter, MAX(old_line - count, 0)); + gtk_text_iter_set_line(iter, MAX(old_line - count, 0)); - return (gtk_text_iter_get_line_number(iter) != old_line); + return (gtk_text_iter_get_line(iter) != old_line); } } -static gboolean -is_word_char(gunichar ch, gpointer user_data) -{ - /* will likely need some i18n help FIXME */ - return isalpha(ch); -} +typedef gboolean (* FindLogAttrFunc) (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset); static gboolean -is_not_word_char(gunichar ch, gpointer user_data) +find_word_end_func (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset) { - return !is_word_char(ch, user_data); + ++offset; /* We always go to the NEXT word end */ + + /* Find start of next word */ + while (offset < min_offset + len && + !attrs[offset].is_word_stop) + ++offset; + + /* Find end */ + while (offset < min_offset + len && + !attrs[offset].is_white) + ++offset; + + *found_offset = offset; + + return offset < min_offset + len; } static gboolean -gtk_text_iter_is_in_word(const GtkTextIter *iter) +find_word_start_func (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset) { - gint ch; - - ch = gtk_text_iter_get_char(iter); + --offset; /* We always go to the NEXT word start */ + + /* Find end of prev word */ + while (offset >= min_offset && + attrs[offset].is_white) + --offset; + + /* Find start */ + while (offset >= min_offset && + !attrs[offset].is_word_stop) + --offset; + + *found_offset = offset; - return is_word_char(ch, NULL); + return offset >= min_offset; } -gboolean -gtk_text_iter_forward_word_end(GtkTextIter *iter) -{ - gboolean in_word; +/* FIXME this function is very, very gratuitously slow */ +static gboolean +find_by_log_attrs (GtkTextIter *iter, + FindLogAttrFunc func, + gboolean forward) +{ + GtkTextIter orig; GtkTextIter start; + GtkTextIter end; + gchar *paragraph; + gint char_len, byte_len; + PangoLogAttr *attrs; + int offset; + gboolean found = FALSE; g_return_val_if_fail(iter != NULL, FALSE); + orig = *iter; start = *iter; + end = *iter; + + gtk_text_iter_set_line_offset (&start, 0); + gtk_text_iter_forward_to_newline (&end); - in_word = gtk_text_iter_is_in_word(iter); + paragraph = gtk_text_iter_get_text (&start, &end); + char_len = g_utf8_strlen (paragraph, -1); + byte_len = strlen (paragraph); - if (!in_word) + offset = gtk_text_iter_get_line_offset (iter); + + if (char_len > 0 && offset < char_len) { - if (!gtk_text_iter_forward_find_char(iter, is_word_char, NULL)) - return !gtk_text_iter_equal(iter, &start); - else - in_word = TRUE; - } + gchar *lang; + + attrs = g_new (PangoLogAttr, char_len); + + lang = gtk_text_iter_get_language (iter); - g_assert(in_word); - - gtk_text_iter_forward_find_char(iter, is_not_word_char, NULL); + pango_get_log_attrs (paragraph, byte_len, -1, + lang, + attrs); - return !gtk_text_iter_equal(iter, &start); -} + g_free (lang); -gboolean -gtk_text_iter_backward_word_start(GtkTextIter *iter) -{ - gboolean in_word; - GtkTextIter start; + found = (* func) (attrs, offset, 0, char_len, &offset); + + g_free (attrs); + } - g_return_val_if_fail(iter != NULL, FALSE); - - start = *iter; + g_free (paragraph); - in_word = gtk_text_iter_is_in_word(iter); - - if (!in_word) + if (!found) { - if (!gtk_text_iter_backward_find_char(iter, is_word_char, NULL)) - return !gtk_text_iter_equal(iter, &start); + if (forward) + { + if (gtk_text_iter_forward_line (iter)) + return find_by_log_attrs (iter, func, forward); + else + return FALSE; + } else - in_word = TRUE; + { + if (gtk_text_iter_backward_line (iter)) + return find_by_log_attrs (iter, func, forward); + else + return FALSE; + } } + else + { + gtk_text_iter_set_line_offset (iter, offset); + + return + !gtk_text_iter_equal(iter, &orig) && + !gtk_text_iter_is_last (iter); + } +} - g_assert(in_word); - - gtk_text_iter_backward_find_char(iter, is_not_word_char, NULL); - gtk_text_iter_forward_char(iter); /* point to first char of word, - not first non-word char. */ - - return !gtk_text_iter_equal(iter, &start); +gboolean +gtk_text_iter_forward_word_end(GtkTextIter *iter) +{ + return find_by_log_attrs (iter, find_word_end_func, TRUE); +} + +gboolean +gtk_text_iter_backward_word_start(GtkTextIter *iter) +{ + return find_by_log_attrs (iter, find_word_start_func, FALSE); } +/* FIXME a loop around a truly slow function means + * a truly spectacularly slow function. + */ gboolean gtk_text_iter_forward_word_ends(GtkTextIter *iter, gint count) @@ -1575,64 +1786,8 @@ gtk_text_iter_backward_word_starts(GtkTextIter *iter, return TRUE; } -/* up/down lines maintain the char offset, while forward/backward lines - always sets the char offset to 0. */ -gboolean -gtk_text_iter_up_lines (GtkTextIter *iter, - gint count) -{ - gint char_offset; - - if (count < 0) - return gtk_text_iter_down_lines(iter, 0 - count); - - char_offset = gtk_text_iter_get_line_char(iter); - - if (!gtk_text_iter_backward_line(iter)) - return FALSE; - --count; - - while (count > 0) - { - if (!gtk_text_iter_backward_line(iter)) - break; - --count; - } - - gtk_text_iter_set_line_char(iter, char_offset); - - return TRUE; -} - -gboolean -gtk_text_iter_down_lines (GtkTextIter *iter, - gint count) -{ - gint char_offset; - - if (count < 0) - return gtk_text_iter_up_lines(iter, 0 - count); - - char_offset = gtk_text_iter_get_line_char(iter); - - if (!gtk_text_iter_forward_line(iter)) - return FALSE; - --count; - - while (count > 0) - { - if (!gtk_text_iter_forward_line(iter)) - break; - --count; - } - - gtk_text_iter_set_line_char(iter, char_offset); - - return TRUE; -} - void -gtk_text_iter_set_line_char(GtkTextIter *iter, +gtk_text_iter_set_line_offset(GtkTextIter *iter, gint char_on_line) { GtkTextRealIter *real; @@ -1652,7 +1807,7 @@ gtk_text_iter_set_line_char(GtkTextIter *iter, } void -gtk_text_iter_set_line_number(GtkTextIter *iter, gint line_number) +gtk_text_iter_set_line(GtkTextIter *iter, gint line_number) { GtkTextLine *line; gint real_line; @@ -1678,7 +1833,7 @@ gtk_text_iter_set_line_number(GtkTextIter *iter, gint line_number) } void -gtk_text_iter_set_char_index(GtkTextIter *iter, gint char_index) +gtk_text_iter_set_offset(GtkTextIter *iter, gint char_index) { GtkTextLine *line; GtkTextRealIter *real; @@ -1737,13 +1892,13 @@ gtk_text_iter_forward_to_newline(GtkTextIter *iter) g_return_val_if_fail(iter != NULL, FALSE); - current_offset = gtk_text_iter_get_line_char(iter); + current_offset = gtk_text_iter_get_line_offset(iter); new_offset = gtk_text_iter_get_chars_in_line(iter) - 1; if (current_offset < new_offset) { /* Move to end of this line. */ - gtk_text_iter_set_line_char(iter, new_offset); + gtk_text_iter_set_line_offset(iter, new_offset); return TRUE; } else @@ -1760,8 +1915,8 @@ gtk_text_iter_forward_to_newline(GtkTextIter *iter) } gboolean -gtk_text_iter_forward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag) +gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, + GtkTextTag *tag) { GtkTextLine *next_line; GtkTextLine *current_line; @@ -1813,13 +1968,22 @@ gtk_text_iter_forward_find_tag_toggle (GtkTextIter *iter, } } + /* Check end iterator for tags */ + if (gtk_text_iter_toggles_tag(iter, tag)) + { + /* 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); + return TRUE; + } + /* Reached end of buffer */ return FALSE; } gboolean -gtk_text_iter_backward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag) +gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter, + GtkTextTag *tag) { g_warning("FIXME"); @@ -1827,7 +1991,7 @@ gtk_text_iter_backward_find_tag_toggle (GtkTextIter *iter, static gboolean matches_pred(GtkTextIter *iter, - GtkTextViewCharPredicate pred, + GtkTextCharPredicate pred, gpointer user_data) { gint ch; @@ -1839,13 +2003,13 @@ matches_pred(GtkTextIter *iter, gboolean gtk_text_iter_forward_find_char (GtkTextIter *iter, - GtkTextViewCharPredicate pred, + GtkTextCharPredicate pred, gpointer user_data) { g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(pred != NULL, FALSE); - while (gtk_text_iter_forward_char(iter)) + while (gtk_text_iter_next_char(iter)) { if (matches_pred(iter, pred, user_data)) return TRUE; @@ -1856,13 +2020,13 @@ gtk_text_iter_forward_find_char (GtkTextIter *iter, gboolean gtk_text_iter_backward_find_char (GtkTextIter *iter, - GtkTextViewCharPredicate pred, + GtkTextCharPredicate pred, gpointer user_data) { g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(pred != NULL, FALSE); - while (gtk_text_iter_backward_char(iter)) + while (gtk_text_iter_prev_char(iter)) { if (matches_pred(iter, pred, user_data)) return TRUE; @@ -1871,6 +2035,212 @@ gtk_text_iter_backward_find_char (GtkTextIter *iter, return FALSE; } +static gboolean +lines_match (const GtkTextIter *start, + const gchar **lines, + gboolean visible_only, + gboolean slice, + GtkTextIter *match_start) +{ + GtkTextIter next; + gchar *line_text; + const gchar *found; + gint offset; + + if (*lines == NULL || **lines == '\0') + return TRUE; + + next = *start; + gtk_text_iter_forward_line (&next); + + gtk_text_iter_spew (start, "start"); + gtk_text_iter_spew (&next, "next"); + + /* No more text in buffer, but *lines is nonempty */ + if (gtk_text_iter_equal (start, &next)) + { + return FALSE; + } + + if (slice) + { + if (visible_only) + line_text = gtk_text_iter_get_visible_slice (start, &next); + else + line_text = gtk_text_iter_get_slice (start, &next); + } + else + { + /* FIXME */ + g_warning ("Searching for non-slice text is currently broken (you must include 'unknown char' for pixmaps in order to match them)"); + if (visible_only) + line_text = gtk_text_iter_get_visible_text (start, &next); + else + line_text = gtk_text_iter_get_text (start, &next); + } + + if (match_start) /* if this is the first line we're matching */ + found = strstr (line_text, *lines); + else + { + /* If it's not the first line, we have to match from the + * start of the line. + */ + if (strncmp (line_text, *lines, strlen (*lines)) == 0) + found = line_text; + else + found = NULL; + } + + if (found == NULL) + { + g_free (line_text); + return FALSE; + } + + /* Get offset to start of search string */ + offset = g_utf8_strlen (line_text, found - line_text); + + next = *start; + + /* If match start needs to be returned, set it to the + * start of the search string. + */ + if (match_start) + { + *match_start = next; + gtk_text_iter_forward_chars (match_start, offset); + } + + /* Go to end of search string */ + offset += g_utf8_strlen (*lines, -1); + + gtk_text_iter_forward_chars (&next, offset); + + g_free (line_text); + + ++lines; + + /* pass NULL for match_start, since we don't need to find the + * start again. + */ + return lines_match (&next, lines, visible_only, slice, NULL); +} + +/* strsplit() that retains the delimiter as part of the string. */ +static gchar ** +strbreakup (const char *string, + const char *delimiter, + gint max_tokens) +{ + GSList *string_list = NULL, *slist; + gchar **str_array, *s; + guint i, n = 1; + + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (delimiter != NULL, NULL); + + if (max_tokens < 1) + max_tokens = G_MAXINT; + + s = strstr (string, delimiter); + if (s) + { + guint delimiter_len = strlen (delimiter); + + do + { + guint len; + gchar *new_string; + + len = s - string + delimiter_len; + new_string = g_new (gchar, len + 1); + strncpy (new_string, string, len); + new_string[len] = 0; + string_list = g_slist_prepend (string_list, new_string); + n++; + string = s + delimiter_len; + s = strstr (string, delimiter); + } + while (--max_tokens && s); + } + if (*string) + { + n++; + string_list = g_slist_prepend (string_list, g_strdup (string)); + } + + str_array = g_new (gchar*, n); + + i = n - 1; + + str_array[i--] = NULL; + for (slist = string_list; slist; slist = slist->next) + str_array[i--] = slist->data; + + g_slist_free (string_list); + + return str_array; +} + +gboolean +gtk_text_iter_forward_search (GtkTextIter *iter, + const char *str, + gboolean visible_only, + gboolean slice) +{ + gchar **lines = NULL; + GtkTextIter match; + gboolean retval = FALSE; + GtkTextIter search; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + if (*str == '\0') + return TRUE; /* we found the empty string */ + + /* locate all lines */ + + lines = strbreakup (str, "\n", -1); + + search = *iter; + + do + { + /* This loop has an inefficient worst-case, where + * gtk_text_iter_get_text() is called repeatedly on + * a single line. + */ + if (lines_match (&search, (const gchar**)lines, visible_only, slice, &match)) + { + retval = TRUE; + + *iter = match; + + break; + } + } + while (gtk_text_iter_forward_line (&search)); + + g_strfreev ((gchar**)lines); + + return retval; +} + +gboolean +gtk_text_iter_backward_search (GtkTextIter *iter, + const char *str, + gboolean visible_only, + gboolean slice) +{ + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + + +} + /* * Comparisons */ @@ -1949,8 +2319,8 @@ gtk_text_iter_compare(const GtkTextIter *lhs, const GtkTextIter *rhs) { gint line1, line2; - line1 = gtk_text_iter_get_line_number(lhs); - line2 = gtk_text_iter_get_line_number(rhs); + line1 = gtk_text_iter_get_line(lhs); + line2 = gtk_text_iter_get_line(rhs); if (line1 < line2) return -1; else if (line1 > line2) @@ -2096,7 +2466,7 @@ gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree *tree, else { iter_init_from_byte_offset(iter, tree, line, 0); - gtk_text_iter_forward_find_tag_toggle(iter, tag); + gtk_text_iter_forward_to_tag_toggle(iter, tag); check_invariants(iter); return TRUE; } @@ -2124,23 +2494,12 @@ gtk_text_btree_get_iter_at_last_toggle (GtkTextBTree *tree, else { iter_init_from_byte_offset(iter, tree, line, -1); - gtk_text_iter_backward_find_tag_toggle(iter, tag); + gtk_text_iter_backward_to_tag_toggle(iter, tag); check_invariants(iter); return TRUE; } } -gboolean -gtk_text_btree_get_iter_from_string (GtkTextBTree *tree, - GtkTextIter *iter, - const gchar *string) -{ - g_return_val_if_fail(iter != NULL, FALSE); - g_return_val_if_fail(tree != NULL, FALSE); - - g_warning("FIXME"); -} - gboolean gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree, GtkTextIter *iter, @@ -2176,7 +2535,7 @@ gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree, iter_init_from_segment(iter, tree, seg->body.mark.line, seg); - g_assert(seg->body.mark.line == gtk_text_iter_get_line(iter)); + g_assert(seg->body.mark.line == gtk_text_iter_get_text_line(iter)); check_invariants(iter); } @@ -2207,10 +2566,10 @@ gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc) check_invariants(iter); g_print(" %20s: line %d / char %d / line char %d / line byte %d\n", desc, - gtk_text_iter_get_line_number(iter), - gtk_text_iter_get_char_index(iter), - gtk_text_iter_get_line_char(iter), - gtk_text_iter_get_line_byte(iter)); + gtk_text_iter_get_line(iter), + gtk_text_iter_get_offset(iter), + gtk_text_iter_get_line_offset(iter), + gtk_text_iter_get_line_index(iter)); check_invariants(iter); } } diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h index 2e86e47b0..1114e3226 100644 --- a/gtk/gtktextiter.h +++ b/gtk/gtktextiter.h @@ -28,7 +28,7 @@ struct _GtkTextIter { gpointer dummy8; gint dummy9; gpointer pad1; - gint pad2; + guint pad2; }; @@ -46,10 +46,12 @@ void gtk_text_iter_free (GtkTextIter *iter); /* * Convert to different kinds of index */ -gint gtk_text_iter_get_char_index (const GtkTextIter *iter); -gint gtk_text_iter_get_line_number (const GtkTextIter *iter); -gint gtk_text_iter_get_line_char (const GtkTextIter *iter); -gint gtk_text_iter_get_line_byte (const GtkTextIter *iter); + +gint gtk_text_iter_get_offset (const GtkTextIter *iter); +gint gtk_text_iter_get_line (const GtkTextIter *iter); +gint gtk_text_iter_get_line_offset (const GtkTextIter *iter); +gint gtk_text_iter_get_line_index (const GtkTextIter *iter); + /* * "Dereference" operators @@ -72,19 +74,21 @@ gchar *gtk_text_iter_get_visible_text (const GtkTextIter *start, /* Returns TRUE if the iterator pointed at a pixmap */ gboolean gtk_text_iter_get_pixmap (const GtkTextIter *iter, - GdkPixmap **pixmap, - GdkBitmap **mask); + GdkPixmap **pixmap, + GdkBitmap **mask); + +GSList *gtk_text_iter_get_marks (const GtkTextIter *iter); /* Return list of tags toggled at this point (toggled_on determines whether the list is of on-toggles or off-toggles) */ GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter, - gboolean toggled_on); + gboolean toggled_on); gboolean gtk_text_iter_begins_tag (const GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); gboolean gtk_text_iter_ends_tag (const GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); gboolean gtk_text_iter_toggles_tag (const GtkTextIter *iter, GtkTextTag *tag); @@ -92,78 +96,91 @@ gboolean gtk_text_iter_toggles_tag (const GtkTextIter *iter, gboolean gtk_text_iter_has_tag (const GtkTextIter *iter, GtkTextTag *tag); +gboolean gtk_text_iter_editable (const GtkTextIter *iter, + gboolean default_setting); + gboolean gtk_text_iter_starts_line (const GtkTextIter *iter); gboolean gtk_text_iter_ends_line (const GtkTextIter *iter); gint gtk_text_iter_get_chars_in_line (const GtkTextIter *iter); +gboolean gtk_text_iter_get_style_values (const GtkTextIter *iter, + GtkTextStyleValues *values); + +gboolean gtk_text_iter_is_last (const GtkTextIter *iter); +gboolean gtk_text_iter_is_first (const GtkTextIter *iter); + /* * Moving around the buffer */ -gboolean gtk_text_iter_forward_char (GtkTextIter *iter); -gboolean gtk_text_iter_backward_char (GtkTextIter *iter); -gboolean gtk_text_iter_forward_chars (GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_backward_chars (GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_forward_line (GtkTextIter *iter); -gboolean gtk_text_iter_backward_line (GtkTextIter *iter); -gboolean gtk_text_iter_forward_lines (GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_backward_lines (GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_forward_word_ends(GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_backward_word_starts(GtkTextIter *iter, - gint count); -gboolean gtk_text_iter_forward_word_end(GtkTextIter *iter); -gboolean gtk_text_iter_backward_word_start(GtkTextIter *iter); - -gboolean gtk_text_iter_up_lines (GtkTextIter *iter, - gint count); - -gboolean gtk_text_iter_down_lines (GtkTextIter *iter, - gint count); - -void gtk_text_iter_set_char_index (GtkTextIter *iter, - gint char_index); -void gtk_text_iter_set_line_number (GtkTextIter *iter, - gint line_number); -void gtk_text_iter_set_line_char (GtkTextIter *iter, - gint char_on_line); - -void gtk_text_iter_forward_to_end (GtkTextIter *iter); -gboolean gtk_text_iter_forward_to_newline(GtkTextIter *iter); + +gboolean gtk_text_iter_next_char (GtkTextIter *iter); +gboolean gtk_text_iter_prev_char (GtkTextIter *iter); +gboolean gtk_text_iter_forward_chars (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_backward_chars (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_forward_line (GtkTextIter *iter); +gboolean gtk_text_iter_backward_line (GtkTextIter *iter); +gboolean gtk_text_iter_forward_lines (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_backward_lines (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_forward_word_ends (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_backward_word_starts (GtkTextIter *iter, + gint count); +gboolean gtk_text_iter_forward_word_end (GtkTextIter *iter); +gboolean gtk_text_iter_backward_word_start (GtkTextIter *iter); + +void gtk_text_iter_set_offset (GtkTextIter *iter, + gint char_offset); +void gtk_text_iter_set_line (GtkTextIter *iter, + gint line_number); +void gtk_text_iter_set_line_offset (GtkTextIter *iter, + gint char_on_line); +void gtk_text_iter_forward_to_end (GtkTextIter *iter); +gboolean gtk_text_iter_forward_to_newline (GtkTextIter *iter); /* returns TRUE if a toggle was found; NULL for the tag pointer means "any tag toggle", otherwise the next toggle of the specified tag is located. */ -gboolean gtk_text_iter_forward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag); +gboolean gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter, + GtkTextTag *tag); -gboolean gtk_text_iter_backward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag); +gboolean gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter, + GtkTextTag *tag); -typedef gboolean (* GtkTextViewCharPredicate) (gunichar ch, gpointer user_data); +typedef gboolean (* GtkTextCharPredicate) (gunichar ch, gpointer user_data); gboolean gtk_text_iter_forward_find_char (GtkTextIter *iter, - GtkTextViewCharPredicate pred, + GtkTextCharPredicate pred, gpointer user_data); gboolean gtk_text_iter_backward_find_char (GtkTextIter *iter, - GtkTextViewCharPredicate pred, + GtkTextCharPredicate pred, gpointer user_data); +gboolean gtk_text_iter_forward_search (GtkTextIter *iter, + const char *str, + gboolean visible_only, + gboolean slice); + +gboolean gtk_text_iter_backward_search (GtkTextIter *iter, + const char *str, + gboolean visible_only, + gboolean slice); + /* * Comparisons */ gboolean gtk_text_iter_equal (const GtkTextIter *lhs, - const GtkTextIter *rhs); + const GtkTextIter *rhs); gint gtk_text_iter_compare (const GtkTextIter *lhs, - const GtkTextIter *rhs); + const GtkTextIter *rhs); gboolean gtk_text_iter_in_region (const GtkTextIter *iter, - const GtkTextIter *start, - const GtkTextIter *end); + const GtkTextIter *start, + const GtkTextIter *end); /* Put these two in ascending order */ void gtk_text_iter_reorder (GtkTextIter *first, diff --git a/gtk/gtktextiterprivate.h b/gtk/gtktextiterprivate.h index 6a23a3e8f..0d9104d3e 100644 --- a/gtk/gtktextiterprivate.h +++ b/gtk/gtktextiterprivate.h @@ -7,10 +7,13 @@ extern "C" { #endif /* __cplusplus */ +#include +#include + GtkTextLineSegment *gtk_text_iter_get_indexable_segment(const GtkTextIter *iter); GtkTextLineSegment *gtk_text_iter_get_any_segment(const GtkTextIter *iter); -GtkTextLine *gtk_text_iter_get_line(const GtkTextIter *iter); +GtkTextLine *gtk_text_iter_get_text_line(const GtkTextIter *iter); GtkTextBTree *gtk_text_iter_get_btree(const GtkTextIter *iter); diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 737a83e3b..1fa6c3052 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -246,7 +246,8 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, if (layout->buffer) { - gtk_text_btree_remove_view (layout->buffer->tree, layout); + gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer), + layout); gtk_object_unref (GTK_OBJECT (layout->buffer)); layout->buffer = NULL; @@ -259,7 +260,7 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, gtk_object_sink (GTK_OBJECT (buffer)); gtk_object_ref (GTK_OBJECT (buffer)); - gtk_text_btree_add_view (buffer->tree, layout); + gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout); } } @@ -337,7 +338,8 @@ gtk_text_layout_get_size (GtkTextLayout *layout, g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - gtk_text_btree_get_view_size (layout->buffer->tree, layout, + gtk_text_btree_get_view_size (_gtk_text_buffer_get_btree (layout->buffer), + layout, &w, &h); layout->width = w; @@ -419,7 +421,9 @@ gtk_text_layout_get_lines (GtkTextLayout *layout, retval = NULL; - first_btree_line = gtk_text_btree_find_line_by_y (layout->buffer->tree, layout, top_y, first_line_y); + first_btree_line = + gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), + layout, top_y, first_line_y); if (first_btree_line == NULL) { g_assert (top_y > 0); @@ -428,11 +432,15 @@ gtk_text_layout_get_lines (GtkTextLayout *layout, } /* -1 since bottom_y is one past */ - last_btree_line = gtk_text_btree_find_line_by_y (layout->buffer->tree, layout, bottom_y - 1, NULL); + last_btree_line = + gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), + layout, bottom_y - 1, NULL); if (!last_btree_line) - last_btree_line = gtk_text_btree_get_line (layout->buffer->tree, - gtk_text_btree_line_count (layout->buffer->tree) - 1, NULL); + last_btree_line = + gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer), + gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, + NULL); { GtkTextLineData *ld = gtk_text_line_get_data (last_btree_line, layout); @@ -528,8 +536,8 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout, gtk_text_view_index_spew (end_index, "invalidate end"); #endif - last_line = gtk_text_iter_get_line (end); - line = gtk_text_iter_get_line (start); + last_line = gtk_text_iter_get_text_line (end); + line = gtk_text_iter_get_text_line (start); while (TRUE) { @@ -588,7 +596,8 @@ gtk_text_layout_is_valid (GtkTextLayout *layout) g_return_val_if_fail (layout != NULL, FALSE); g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE); - return gtk_text_btree_is_valid (layout->buffer->tree, layout); + return gtk_text_btree_is_valid (_gtk_text_buffer_get_btree (layout->buffer), + layout); } /** @@ -630,7 +639,7 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout, /* Validate backwards from the anchor line to y0 */ - line = gtk_text_iter_get_line (anchor); + line = gtk_text_iter_get_text_line (anchor); seen = 0; while (line && seen < -y0) { @@ -639,7 +648,8 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout, { gint old_height = line_data ? line_data->height : 0; - gtk_text_btree_validate_line (layout->buffer->tree, line, layout); + gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); line_data = gtk_text_line_get_data (line, layout); delta_height += line_data->height - old_height; @@ -658,7 +668,7 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout, } /* Validate forwards to y1 */ - line = gtk_text_iter_get_line (anchor); + line = gtk_text_iter_get_text_line (anchor); seen = 0; while (line && seen < y1) { @@ -667,7 +677,8 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout, { gint old_height = line_data ? line_data->height : 0; - gtk_text_btree_validate_line (layout->buffer->tree, line, layout); + gtk_text_btree_validate_line (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); line_data = gtk_text_line_get_data (line, layout); delta_height += line_data->height - old_height; @@ -689,7 +700,9 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout, */ if (first_line) { - gint line_top = gtk_text_btree_find_line_top (layout->buffer->tree, first_line, layout); + gint line_top = + gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + first_line, layout); gtk_text_layout_changed (layout, line_top, @@ -717,7 +730,8 @@ gtk_text_layout_validate (GtkTextLayout *layout, g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); while (max_pixels > 0 && - gtk_text_btree_validate (layout->buffer->tree, layout, max_pixels, + gtk_text_btree_validate (_gtk_text_buffer_get_btree (layout->buffer), + layout, max_pixels, &y, &old_height, &new_height)) { max_pixels -= new_height; @@ -859,17 +873,18 @@ totally_invisible_line (GtkTextLayout *layout, int bytes = 0; /* If we have a cached style, then we know it does actually apply - and we can just see if it is elided. */ + and we can just see if it is invisible. */ if (layout->one_style_cache && - !layout->one_style_cache->elide) + !layout->one_style_cache->invisible) return FALSE; /* Without the cache, we check if the first char is visible, if so we are partially visible. Note that we have to check this since - we don't know the current elided/nonelided toggle state; this + we don't know the current invisible/noninvisible toggle state; this function can use the whole btree to get it right. */ else { - gtk_text_btree_get_iter_at_line(layout->buffer->tree, iter, line, 0); + gtk_text_btree_get_iter_at_line(_gtk_text_buffer_get_btree (layout->buffer), + iter, line, 0); if (!gtk_text_btree_char_is_invisible (iter)) return FALSE; @@ -886,16 +901,16 @@ totally_invisible_line (GtkTextLayout *layout, /* Note that these two tests can cause us to bail out when we shouldn't, because a higher-priority tag may override these settings. However the important - thing is to only elide really-elided lines, rather - than to elide all really-elided lines. */ + thing is to only invisible really-invisible lines, rather + than to invisible all really-invisible lines. */ else if (seg->type == >k_text_toggle_on_type) { invalidate_cached_style (layout); /* Bail out if an elision-unsetting tag begins */ - if (seg->body.toggle.info->tag->elide_set && - !seg->body.toggle.info->tag->values->elide) + if (seg->body.toggle.info->tag->invisible_set && + !seg->body.toggle.info->tag->values->invisible) break; } else if (seg->type == >k_text_toggle_off_type) @@ -903,8 +918,8 @@ totally_invisible_line (GtkTextLayout *layout, invalidate_cached_style (layout); /* Bail out if an elision-setting tag ends */ - if (seg->body.toggle.info->tag->elide_set && - seg->body.toggle.info->tag->values->elide) + if (seg->body.toggle.info->tag->invisible_set && + seg->body.toggle.info->tag->values->invisible) break; } @@ -1135,7 +1150,8 @@ add_cursor (GtkTextLayout *layout, /* Hide insertion cursor when we have a selection */ - if (gtk_text_btree_mark_is_insert (layout->buffer->tree, (GtkTextMark*)seg) && + if (gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer), + (GtkTextMark*)seg) && gtk_text_buffer_get_selection_bounds (layout->buffer, &selection_start, &selection_end)) return; @@ -1205,7 +1221,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, display->size_only = size_only; display->line = line; - gtk_text_btree_get_iter_at_line (layout->buffer->tree, &iter, line, 0); + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + &iter, line, 0); /* Special-case optimization for completely * invisible lines; makes it faster to deal @@ -1230,7 +1247,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, if (seg->type == >k_text_char_type || seg->type == >k_text_pixmap_type) { - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), &iter, line, byte_offset); style = get_style (layout, &iter); @@ -1246,12 +1263,12 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, para_values_set = TRUE; } - /* First see if the chunk is elided, and ignore it if so. Tk + /* First see if the chunk is invisible, and ignore it if so. Tk * looked at tabs, wrap mode, etc. before doing this, but * that made no sense to me, so I am just skipping the - * elided chunks + * invisible chunks */ - if (!style->elide) + if (!style->invisible) { if (seg->type == >k_text_char_type) { @@ -1420,13 +1437,16 @@ get_line_at_y (GtkTextLayout *layout, if (y > layout->height) y = layout->height; - *line = gtk_text_btree_find_line_by_y (layout->buffer->tree, layout, y, line_top); + *line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), + layout, y, line_top); if (*line == NULL) { - *line = gtk_text_btree_get_line (layout->buffer->tree, - gtk_text_btree_line_count (layout->buffer->tree) - 1, NULL); + *line = gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer), + gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL); if (line_top) - *line_top = gtk_text_btree_find_line_top (layout->buffer->tree, *line, layout); + *line_top = + gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + *line, layout); } } @@ -1453,7 +1473,8 @@ gtk_text_layout_get_line_at_y (GtkTextLayout *layout, g_return_if_fail (target_iter != NULL); get_line_at_y (layout, y, &line, line_top); - gtk_text_btree_get_iter_at_line (layout->buffer->tree, target_iter, line, 0); + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + target_iter, line, 0); } void @@ -1496,12 +1517,12 @@ gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout, trailing = 0; } - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), target_iter, line, byte_index); while (trailing--) - gtk_text_iter_forward_char (target_iter); + gtk_text_iter_next_char (target_iter); gtk_text_layout_free_line_display (layout, display); } @@ -1538,12 +1559,13 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout *layout, g_return_if_fail (layout != NULL); g_return_if_fail (iter != NULL); - line = gtk_text_iter_get_line (iter); - line_top = gtk_text_btree_find_line_top (layout->buffer->tree, line, layout); + line = gtk_text_iter_get_text_line (iter); + line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); display = gtk_text_layout_get_line_display (layout, line, FALSE); - pango_layout_get_cursor_pos (display->layout, gtk_text_iter_get_line_byte (iter), + pango_layout_get_cursor_pos (display->layout, gtk_text_iter_get_line_index (iter), strong_pos ? &pango_strong_pos : NULL, weak_pos ? &pango_weak_pos : NULL); @@ -1583,10 +1605,11 @@ gtk_text_layout_get_line_y (GtkTextLayout *layout, GtkTextLine *line; g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), 0); - g_return_val_if_fail (gtk_text_iter_get_btree (iter) == layout->buffer->tree, 0); + g_return_val_if_fail (gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer), 0); - line = gtk_text_iter_get_line (iter); - return gtk_text_btree_find_line_top (layout->buffer->tree, line, layout); + line = gtk_text_iter_get_text_line (iter); + return gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); } void @@ -1601,11 +1624,11 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, gint byte_index; g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - g_return_if_fail (gtk_text_iter_get_btree (iter) == layout->buffer->tree); + g_return_if_fail (gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer)); g_return_if_fail (rect != NULL); tree = gtk_text_iter_get_btree (iter); - line = gtk_text_iter_get_line (iter); + line = gtk_text_iter_get_text_line (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); @@ -1628,8 +1651,8 @@ gtk_text_layout_get_iter_location (GtkTextLayout *layout, } else { - byte_index = gtk_text_iter_get_line_byte (iter); - + byte_index = gtk_text_iter_get_line_index (iter); + pango_layout_index_to_pos (display->layout, byte_index, &pango_rect); rect->x = display->x_offset + pango_rect.x / PANGO_SCALE; @@ -1655,12 +1678,17 @@ find_display_line_below (GtkTextLayout *layout, gint line_top; gint found_byte = 0; - line = gtk_text_btree_find_line_by_y (layout->buffer->tree, layout, y, &line_top); + line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), + layout, y, &line_top); if (!line) { - line = gtk_text_btree_get_line (layout->buffer->tree, - gtk_text_btree_line_count (layout->buffer->tree) - 1, NULL); - line_top = gtk_text_btree_find_line_top (layout->buffer->tree, line, layout); + line = + gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer), + gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, + NULL); + line_top = + gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), + line, layout); } while (line && !found_line) @@ -1700,7 +1728,8 @@ find_display_line_below (GtkTextLayout *layout, line = next; } - gtk_text_btree_get_iter_at_line (layout->buffer->tree, iter, found_line, found_byte); + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + iter, found_line, found_byte); } /* Find the iter for the logical beginning of the last display line whose @@ -1717,12 +1746,12 @@ find_display_line_above (GtkTextLayout *layout, gint line_top; gint found_byte = 0; - line = gtk_text_btree_find_line_by_y (layout->buffer->tree, layout, y, &line_top); + line = gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), layout, y, &line_top); if (!line) { - line = gtk_text_btree_get_line (layout->buffer->tree, - gtk_text_btree_line_count (layout->buffer->tree) - 1, NULL); - line_top = gtk_text_btree_find_line_top (layout->buffer->tree, line, layout); + line = gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer), + gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL); + line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout); } while (line && !found_line) @@ -1766,9 +1795,10 @@ find_display_line_above (GtkTextLayout *layout, } if (found_line) - gtk_text_btree_get_iter_at_line (layout->buffer->tree, iter, found_line, found_byte); + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), + iter, found_line, found_byte); else - gtk_text_buffer_get_iter_at_char (layout->buffer, iter, 0); + gtk_text_buffer_get_iter_at_offset (layout->buffer, iter, 0); } /** @@ -1839,8 +1869,8 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); g_return_if_fail (iter != NULL); - line = gtk_text_iter_get_line (iter); - line_byte = gtk_text_iter_get_line_byte (iter); + line = gtk_text_iter_get_text_line (iter); + line_byte = gtk_text_iter_get_line_index (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); @@ -1868,11 +1898,11 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, byte_offset += layout_line->length; } - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, prev_line, byte_offset); } else - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, line, 0); } else @@ -1887,7 +1917,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, if (line_byte < byte_offset + layout_line->length || !tmp_list->next) { - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, line, prev_offset); break; } @@ -1925,8 +1955,8 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); g_return_if_fail (iter != NULL); - line = gtk_text_iter_get_line (iter); - line_byte = gtk_text_iter_get_line_byte (iter); + line = gtk_text_iter_get_text_line (iter); + line_byte = gtk_text_iter_get_line_index (iter); while (line && !found_after) { @@ -1942,7 +1972,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, if (found) { - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, line, byte_offset); found_after = TRUE; @@ -1985,8 +2015,8 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); g_return_if_fail (iter != NULL); - line = gtk_text_iter_get_line (iter); - line_byte = gtk_text_iter_get_line_byte (iter); + line = gtk_text_iter_get_text_line (iter); + line_byte = gtk_text_iter_get_line_index (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); @@ -2024,12 +2054,12 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, x * PANGO_SCALE - x_offset, &byte_index, &trailing); - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, line, byte_index); while (trailing--) - gtk_text_iter_forward_char (iter); + gtk_text_iter_next_char (iter); break; } @@ -2070,9 +2100,10 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, while (count != 0) { - GtkTextLine *line = gtk_text_iter_get_line (iter); - gint line_byte = gtk_text_iter_get_line_byte (iter); + GtkTextLine *line = gtk_text_iter_get_text_line (iter); + gint line_byte = gtk_text_iter_get_line_index (iter); GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE); + int byte_count = gtk_text_line_byte_count (line); int new_index; @@ -2109,11 +2140,11 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, new_index = 0; } - gtk_text_btree_get_iter_at_line (layout->buffer->tree, + gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer), iter, line, new_index); while (new_trailing--) - gtk_text_iter_forward_char (iter); + gtk_text_iter_next_char (iter); } } diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h index 200b13e12..3510e032a 100644 --- a/gtk/gtktextlayout.h +++ b/gtk/gtktextlayout.h @@ -1,10 +1,6 @@ #ifndef GTK_TEXT_LAYOUT_H #define GTK_TEXT_LAYOUT_H -#include -#include -#include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -16,6 +12,15 @@ extern "C" { * to use it. */ +#include +#include + +/* forward declarations that have to be here to avoid including + * gtktextbtree.h + */ +typedef struct _GtkTextLine GtkTextLine; +typedef struct _GtkTextLineData GtkTextLineData; + #define GTK_TYPE_TEXT_LAYOUT (gtk_text_layout_get_type()) #define GTK_TEXT_LAYOUT(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_TEXT_LAYOUT, GtkTextLayout)) #define GTK_TEXT_LAYOUT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_TEXT_LAYOUT, GtkTextLayoutClass)) @@ -23,6 +28,7 @@ extern "C" { #define GTK_IS_TEXT_LAYOUT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TEXT_LAYOUT)) #define GTK_TEXT_LAYOUT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_TEXT_LAYOUT, GtkTextLayoutClass)) +typedef struct _GtkTextLayout GtkTextLayout; typedef struct _GtkTextLayoutClass GtkTextLayoutClass; typedef struct _GtkTextLineDisplay GtkTextLineDisplay; typedef struct _GtkTextCursorDisplay GtkTextCursorDisplay; diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c index 72cb4f1ba..f85ef0a6b 100644 --- a/gtk/gtktextmark.c +++ b/gtk/gtktextmark.c @@ -35,6 +35,41 @@ gtk_text_mark_get_name (GtkTextMark *mark) return g_strdup (seg->body.mark.name); } + +GtkTextMark * +gtk_text_mark_ref (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + seg = (GtkTextLineSegment*)mark; + + mark_segment_ref (seg); + + return mark; +} + +void +gtk_text_mark_unref (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + seg = (GtkTextLineSegment*)mark; + + mark_segment_unref (seg); +} + +gboolean +gtk_text_mark_deleted (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + g_return_val_if_fail (mark != NULL, FALSE); + + seg = (GtkTextLineSegment*)mark; + + return seg->body.mark.tree == NULL; +} + /* * Macro that determines the size of a mark segment: */ diff --git a/gtk/gtktextmark.h b/gtk/gtktextmark.h index 9079e11e4..19cb7a8df 100644 --- a/gtk/gtktextmark.h +++ b/gtk/gtktextmark.h @@ -10,12 +10,17 @@ extern "C" { typedef struct _GtkTextMark GtkTextMark; void gtk_text_mark_set_visible (GtkTextMark *mark, - gboolean setting); + gboolean setting); gboolean gtk_text_mark_is_visible (GtkTextMark *mark); /* Temporarily commented out until memory management behavior is figured out */ /* 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); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktextmarkprivate.h b/gtk/gtktextmarkprivate.h index 08b64fac0..07ebc2aed 100644 --- a/gtk/gtktextmarkprivate.h +++ b/gtk/gtktextmarkprivate.h @@ -1,12 +1,13 @@ #ifndef GTK_TEXT_MARK_PRIVATE_H #define GTK_TEXT_MARK_PRIVATE_H -#include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +#include +#include + #define GTK_IS_TEXT_MARK(mark) (((GtkTextLineSegment*)mark)->type == >k_text_left_mark_type || \ ((GtkTextLineSegment*)mark)->type == >k_text_right_mark_type) diff --git a/gtk/gtktextsegment.c b/gtk/gtktextsegment.c index 38e905865..11313e3bb 100644 --- a/gtk/gtktextsegment.c +++ b/gtk/gtktextsegment.c @@ -97,10 +97,10 @@ gtk_text_line_segment_split(const GtkTextIter *iter) GtkTextLine *line; int count; - line = gtk_text_iter_get_line(iter); + line = gtk_text_iter_get_text_line(iter); tree = gtk_text_iter_get_btree(iter); - count = gtk_text_iter_get_line_byte(iter); + count = gtk_text_iter_get_line_index(iter); prev = NULL; seg = line->segments; diff --git a/gtk/gtktexttag.c b/gtk/gtktexttag.c index f39f7124e..bfecac98b 100644 --- a/gtk/gtktexttag.c +++ b/gtk/gtktexttag.c @@ -52,6 +52,7 @@ #include "gtktexttypes.h" #include "gtktexttagtable.h" #include "gtksignal.h" +#include "gtkmain.h" #include @@ -331,7 +332,7 @@ gtk_text_tag_destroy (GtkObject *object) g_assert(!tkxt_tag->values->realized); if (tkxt_tag->table) - gtk_text_tag_table_remove(tkxt_tag->table, tkxt_tag->name); + gtk_text_tag_table_remove(tkxt_tag->table, tkxt_tag); g_assert(tkxt_tag->table == NULL); @@ -915,17 +916,22 @@ typedef struct { } DeltaData; static void -delta_priority_foreach(gpointer key, gpointer value, gpointer user_data) +delta_priority_foreach(GtkTextTag *tag, gpointer user_data) { - GtkTextTag *tag; DeltaData *dd = user_data; - - tag = GTK_TEXT_TAG(value); if (tag->priority >= dd->low && tag->priority <= dd->high) tag->priority += dd->delta; } +gint +gtk_text_tag_get_priority (GtkTextTag *tag) +{ + g_return_val_if_fail(GTK_IS_TEXT_TAG(tag), 0); + + return tag->priority; +} + void gtk_text_tag_set_priority(GtkTextTag *tag, gint priority) @@ -951,7 +957,7 @@ gtk_text_tag_set_priority(GtkTextTag *tag, } gtk_text_tag_table_foreach(tag->table, delta_priority_foreach, - &dd); + &dd); tag->priority = priority; } @@ -1287,8 +1293,8 @@ gtk_text_style_values_fill_from_tags(GtkTextStyleValues *dest, if (tag->overstrike_set) dest->appearance.overstrike = vals->appearance.overstrike; - if (tag->elide_set) - dest->elide = vals->elide; + if (tag->invisible_set) + dest->invisible = vals->invisible; if (tag->editable_set) dest->editable = vals->editable; diff --git a/gtk/gtktexttag.h b/gtk/gtktexttag.h index 7fac2e185..ef5ee9488 100644 --- a/gtk/gtktexttag.h +++ b/gtk/gtktexttag.h @@ -77,7 +77,7 @@ struct _GtkTextTag { guint underline_set : 1; guint wrap_mode_set : 1; guint bg_full_height_set : 1; - guint elide_set : 1; + guint invisible_set : 1; guint editable_set : 1; guint language_set : 1; guint pad1 : 1; @@ -96,6 +96,7 @@ struct _GtkTextTagClass { GtkType gtk_text_tag_get_type (void); GtkTextTag *gtk_text_tag_new (const gchar *name); +gint gtk_text_tag_get_priority (GtkTextTag *tag); void gtk_text_tag_set_priority (GtkTextTag *tag, gint priority); gint gtk_text_tag_event (GtkTextTag *tag, @@ -103,6 +104,100 @@ gint gtk_text_tag_event (GtkTextTag *tag, GdkEvent *event, const GtkTextIter *iter); +/* + * Style object created by folding a set of tags together + */ + +typedef struct _GtkTextAppearance GtkTextAppearance; + +struct _GtkTextAppearance +{ + GdkColor bg_color; + GdkColor fg_color; + GdkBitmap *bg_stipple; + GdkBitmap *fg_stipple; + + guint underline : 4; /* PangoUnderline */ + guint overstrike : 1; + + /* Whether to use background-related values; this is irrelevant for + * the values struct when in a tag, but is used for the composite + * values struct; it's true if any of the tags being composited + * had background stuff set. */ + guint draw_bg : 1; + + /* This is only used when we are actually laying out and rendering + * a paragraph; not when a GtkTextAppearance is part of a + * GtkTextStyleValues. + */ + guint inside_selection : 1; +}; + +struct _GtkTextStyleValues +{ + guint refcount; + + GtkTextAppearance appearance; + + gint border_width; + GtkShadowType relief; + GtkJustification justify; + GtkTextDirection direction; + + PangoFontDescription *font_desc; + + /* lMargin1 */ + gint left_margin; + + /* lMargin2 */ + gint left_wrapped_line_margin; + + /* super/subscript offset, can be negative */ + gint offset; + + gint right_margin; + + gint pixels_above_lines; + + gint pixels_below_lines; + + gint pixels_inside_wrap; + + GtkTextTabArray *tab_array; + + GtkWrapMode wrap_mode; /* How to handle wrap-around for this tag. + * Must be GTK_WRAPMODE_CHAR, + * GTK_WRAPMODE_NONE, GTK_WRAPMODE_WORD + */ + + gchar *language; + + /* hide the text */ + guint invisible : 1; + + /* Background is fit to full line height rather than + * baseline +/- ascent/descent (font height) */ + guint bg_full_height : 1; + + /* can edit this text */ + guint editable : 1; + + /* colors are allocated etc. */ + guint realized : 1; + + guint pad1 : 1; + guint pad2 : 1; + guint pad3 : 1; + guint pad4 : 1; +}; + +GtkTextStyleValues *gtk_text_style_values_new (void); +void gtk_text_style_values_copy (GtkTextStyleValues *src, + GtkTextStyleValues *dest); +void gtk_text_style_values_unref (GtkTextStyleValues *values); +void gtk_text_style_values_ref (GtkTextStyleValues *values); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktexttagprivate.h b/gtk/gtktexttagprivate.h index c19ddf275..d8ec06fe8 100644 --- a/gtk/gtktexttagprivate.h +++ b/gtk/gtktexttagprivate.h @@ -13,99 +13,6 @@ void gtk_text_style_values_fill_from_tags (GtkTextStyleValues *values, void gtk_text_tag_array_sort (GtkTextTag **tag_array_p, guint len); -/* - * Style object created by folding a set of tags together - */ - -typedef struct _GtkTextAppearance GtkTextAppearance; - -struct _GtkTextAppearance -{ - GdkColor bg_color; - GdkColor fg_color; - GdkBitmap *bg_stipple; - GdkBitmap *fg_stipple; - - guint underline : 4; /* PangoUnderline */ - guint overstrike : 1; - - /* Whether to use background-related values; this is irrelevant for - * the values struct when in a tag, but is used for the composite - * values struct; it's true if any of the tags being composited - * had background stuff set. */ - guint draw_bg : 1; - - /* This is only used when we are actually laying out and rendering - * a paragraph; not when a GtkTextAppearance is part of a - * GtkTextStyleValues. - */ - guint inside_selection : 1; -}; - -struct _GtkTextStyleValues -{ - guint refcount; - - GtkTextAppearance appearance; - - gint border_width; - GtkShadowType relief; - GtkJustification justify; - GtkTextDirection direction; - - PangoFontDescription *font_desc; - - /* lMargin1 */ - gint left_margin; - - /* lMargin2 */ - gint left_wrapped_line_margin; - - /* super/subscript offset, can be negative */ - gint offset; - - gint right_margin; - - gint pixels_above_lines; - - gint pixels_below_lines; - - gint pixels_inside_wrap; - - GtkTextTabArray *tab_array; - - GtkWrapMode wrap_mode; /* How to handle wrap-around for this tag. - * Must be GTK_WRAPMODE_CHAR, - * GTK_WRAPMODE_NONE, GTK_WRAPMODE_WORD - */ - - gchar *language; - - /* hide the text */ - guint elide : 1; - - /* Background is fit to full line height rather than - * baseline +/- ascent/descent (font height) */ - guint bg_full_height : 1; - - /* can edit this text */ - guint editable : 1; - - /* colors are allocated etc. */ - guint realized : 1; - - guint pad1 : 1; - guint pad2 : 1; - guint pad3 : 1; - guint pad4 : 1; -}; - -GtkTextStyleValues *gtk_text_style_values_new (void); -void gtk_text_style_values_copy (GtkTextStyleValues *src, - GtkTextStyleValues *dest); -void gtk_text_style_values_unref (GtkTextStyleValues *values); -void gtk_text_style_values_ref (GtkTextStyleValues *values); - /* ensure colors are allocated, etc. for drawing */ void gtk_text_style_values_realize (GtkTextStyleValues *values, GdkColormap *cmap, diff --git a/gtk/gtktexttagtable.c b/gtk/gtktexttagtable.c index b204c61b8..f79b34bfa 100644 --- a/gtk/gtktexttagtable.c +++ b/gtk/gtktexttagtable.c @@ -125,6 +125,12 @@ gtk_text_tag_table_destroy (GtkObject *object) (* GTK_OBJECT_CLASS(parent_class)->destroy) (object); } +static void +foreach_unref (GtkTextTag *tag, gpointer data) +{ + g_object_unref (G_OBJECT (tag)); +} + static void gtk_text_tag_table_finalize (GObject *object) { @@ -132,8 +138,11 @@ gtk_text_tag_table_finalize (GObject *object) table = GTK_TEXT_TAG_TABLE(object); - g_hash_table_destroy(table->hash); + gtk_text_tag_table_foreach (table, foreach_unref, NULL); + g_hash_table_destroy(table->hash); + g_slist_free (table->anonymous); + (* G_OBJECT_CLASS(parent_class)->finalize) (object); } @@ -174,14 +183,23 @@ gtk_text_tag_table_add(GtkTextTagTable *table, GtkTextTag *tag) { guint size; - g_return_if_fail(GTK_IS_TEXT_TAG_TABLE(table)); - g_return_if_fail(GTK_IS_OBJECT(tag)); - g_return_if_fail(g_hash_table_lookup(table->hash, tag->name) == NULL); + g_return_if_fail(GTK_IS_TEXT_TAG_TABLE (table)); + g_return_if_fail(GTK_IS_TEXT_TAG (tag)); + g_return_if_fail(tag->name == NULL || + g_hash_table_lookup(table->hash, tag->name) == NULL); g_return_if_fail(tag->table == NULL); - + gtk_object_ref(GTK_OBJECT(tag)); gtk_object_sink(GTK_OBJECT(tag)); - g_hash_table_insert(table->hash, tag->name, tag); + + if (tag->name) + g_hash_table_insert(table->hash, tag->name, tag); + else + { + table->anonymous = g_slist_prepend (table->anonymous, tag); + table->anon_count += 1; + } + tag->table = table; /* We get the highest tag priority, as the most-recently-added @@ -204,19 +222,11 @@ gtk_text_tag_table_lookup(GtkTextTagTable *table, const gchar *name) } void -gtk_text_tag_table_remove(GtkTextTagTable *table, const gchar *name) +gtk_text_tag_table_remove(GtkTextTagTable *table, GtkTextTag *tag) { - GtkTextTag *tag; - - g_return_if_fail(GTK_IS_TEXT_TAG_TABLE(table)); - g_return_if_fail(name != NULL); - - tag = g_hash_table_lookup(table->hash, name); - - if (tag == NULL) - return; - - g_return_if_fail(tag->table == table); + g_return_if_fail (GTK_IS_TEXT_TAG_TABLE(table)); + g_return_if_fail (GTK_IS_TEXT_TAG (tag)); + g_return_if_fail (tag->table == table); /* Set ourselves to the highest priority; this means when we're removed, there won't be any gaps in the @@ -224,23 +234,48 @@ gtk_text_tag_table_remove(GtkTextTagTable *table, const gchar *name) gtk_text_tag_set_priority(tag, gtk_text_tag_table_size(table) - 1); tag->table = NULL; - - g_hash_table_remove(table->hash, name); + if (tag->name) + g_hash_table_remove(table->hash, tag->name); + else + { + table->anonymous = g_slist_remove (table->anonymous, tag); + table->anon_count -= 1; + } + gtk_signal_emit(GTK_OBJECT(table), signals[TAG_REMOVED], tag); gtk_object_unref(GTK_OBJECT(tag)); } +struct ForeachData +{ + GtkTextTagTableForeach func; + gpointer data; +}; + +static void +hash_foreach (gpointer key, gpointer value, gpointer data) +{ + struct ForeachData *fd = data; + + (* fd->func) (value, fd->data); +} + void -gtk_text_tag_table_foreach(GtkTextTagTable *table, - GHFunc func, - gpointer data) +gtk_text_tag_table_foreach(GtkTextTagTable *table, + GtkTextTagTableForeach func, + gpointer data) { + struct ForeachData d; + g_return_if_fail(GTK_IS_TEXT_TAG_TABLE(table)); g_return_if_fail(func != NULL); - g_hash_table_foreach(table->hash, func, data); + d.func = func; + d.data = data; + + g_hash_table_foreach(table->hash, hash_foreach, &d); } guint @@ -248,5 +283,5 @@ gtk_text_tag_table_size(GtkTextTagTable *table) { g_return_val_if_fail(GTK_IS_TEXT_TAG_TABLE(table), 0); - return g_hash_table_size(table->hash); + return g_hash_table_size(table->hash) + table->anon_count; } diff --git a/gtk/gtktexttagtable.h b/gtk/gtktexttagtable.h index fee66bd72..c85ec2f1a 100644 --- a/gtk/gtktexttagtable.h +++ b/gtk/gtktexttagtable.h @@ -7,6 +7,10 @@ extern "C" { #endif /* __cplusplus */ +#include + +typedef void (* GtkTextTagTableForeach) (GtkTextTag *tag, gpointer data); + #define GTK_TYPE_TEXT_TAG_TABLE (gtk_text_tag_table_get_type()) #define GTK_TEXT_TAG_TABLE(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_TEXT_TAG_TABLE, GtkTextTagTable)) #define GTK_TEXT_TAG_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_TEXT_TAG_TABLE, GtkTextTagTableClass)) @@ -20,6 +24,8 @@ struct _GtkTextTagTable { GtkObject parent_instance; GHashTable *hash; + GSList *anonymous; + gint anon_count; }; struct _GtkTextTagTableClass { @@ -33,17 +39,17 @@ struct _GtkTextTagTableClass { GtkType gtk_text_tag_table_get_type (void); GtkTextTagTable *gtk_text_tag_table_new (void); -void gtk_text_tag_table_add (GtkTextTagTable *table, - GtkTextTag *tag); -GtkTextTag *gtk_text_tag_table_lookup (GtkTextTagTable *table, - const gchar *name); -void gtk_text_tag_table_remove (GtkTextTagTable *table, - const gchar *name); -void gtk_text_tag_table_foreach (GtkTextTagTable *table, - GHFunc func, - gpointer data); - -guint gtk_text_tag_table_size (GtkTextTagTable *table); +void gtk_text_tag_table_add (GtkTextTagTable *table, + GtkTextTag *tag); +void gtk_text_tag_table_remove (GtkTextTagTable *table, + GtkTextTag *tag); +GtkTextTag *gtk_text_tag_table_lookup (GtkTextTagTable *table, + const gchar *name); +void gtk_text_tag_table_foreach (GtkTextTagTable *table, + GtkTextTagTableForeach func, + gpointer data); +guint gtk_text_tag_table_size (GtkTextTagTable *table); + #ifdef __cplusplus } diff --git a/gtk/gtktexttypes.c b/gtk/gtktexttypes.c index c9ba97df6..0a05e0dac 100644 --- a/gtk/gtktexttypes.c +++ b/gtk/gtktexttypes.c @@ -140,3 +140,92 @@ gtk_text_latin1_to_utf (const gchar *latin1, gint len) +#include +#include +#include + +gchar* +g_convert (const gchar *str, + gint len, + const gchar *to_codeset, + const gchar *from_codeset, + gint *bytes_converted) +{ + gchar *dest; + gchar *outp; + const gchar *p; + size_t inbytes_remaining; + size_t outbytes_remaining; + size_t err; + iconv_t cd; + size_t outbuf_size; + + g_return_val_if_fail (str != NULL, NULL); + g_return_val_if_fail (to_codeset != NULL, NULL); + g_return_val_if_fail (from_codeset != NULL, NULL); + + cd = iconv_open (to_codeset, from_codeset); + + if (cd == (iconv_t) -1) + { + /* Something went wrong. */ + if (errno == EINVAL) + g_warning ("Conversion from character set `%s' to `%s' is not supported", + from_codeset, to_codeset); + else + g_warning ("Failed to convert character set `%s' to `%s': %s", + from_codeset, to_codeset, strerror (errno)); + + if (bytes_converted) + *bytes_converted = 0; + + return NULL; + } + + if (len < 0) + len = strlen (str); + + p = str; + inbytes_remaining = len; + outbuf_size = len + 1; /* + 1 for nul in case len == 1 */ + outbytes_remaining = outbuf_size - 1; /* -1 for nul */ + outp = dest = g_malloc (outbuf_size); + + again: + + err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining); + + if (err == (size_t) -1) + { + if (errno == E2BIG) + { + size_t used = outp - dest; + outbuf_size *= 2; + dest = g_realloc (dest, outbuf_size); + + outp = dest + used; + outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */ + + goto again; + } + else + g_warning ("iconv() failed: %s", strerror (errno)); + } + + *outp = '\0'; + + if (iconv_close (cd) != 0) + g_warning ("Failed to close iconv() conversion descriptor: %s", + strerror (errno)); + + if (bytes_converted) + *bytes_converted = p - str; + + if (p == str) + { + g_free (dest); + return NULL; + } + else + return dest; +} diff --git a/gtk/gtktexttypes.h b/gtk/gtktexttypes.h index 19d72a120..ad8244854 100644 --- a/gtk/gtktexttypes.h +++ b/gtk/gtktexttypes.h @@ -1,16 +1,16 @@ #ifndef GTK_TEXT_TYPES_H #define GTK_TEXT_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + #include #include #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -typedef struct _GtkTextLine GtkTextLine; typedef struct _GtkTextCounter GtkTextCounter; typedef struct _GtkTextLineSegment GtkTextLineSegment; typedef struct _GtkTextLineSegmentClass GtkTextLineSegmentClass; @@ -19,7 +19,6 @@ typedef struct _GtkTextViewSearch GtkTextViewSearch; typedef struct _GtkTextTab GtkTextTab; typedef struct _GtkTextViewStyle GtkTextViewStyle; typedef struct _GtkTextMarkBody GtkTextMarkBody; -typedef struct _GtkTextLayout GtkTextLayout; /* * Search @@ -126,6 +125,12 @@ gchar* gtk_text_latin1_to_utf (const gchar *latin1, gint len); +gchar* g_convert (const gchar *str, + gint len, + const gchar *to_codeset, + const gchar *from_codeset, + gint *bytes_converted); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 7304f7302..db87d9c16 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -59,6 +59,8 @@ #include "gtktextview.h" #include "gtkimmulticontext.h" #include "gdk/gdkkeysyms.h" +#include "gtktexttypes.h" +#include enum { MOVE_INSERT, @@ -219,6 +221,9 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view, gint x, gint y); +static GtkAdjustment* get_hadjustment (GtkTextView *text_view); +static GtkAdjustment* get_vadjustment (GtkTextView *text_view); + enum { TARGET_STRING, TARGET_TEXT, @@ -427,22 +432,22 @@ gtk_text_view_class_init (GtkTextViewClass *klass) /* Eventually we want to move by display lines, not paragraphs */ add_move_insert_binding (binding_set, GDK_Up, 0, - GTK_TEXT_MOVEMENT_LINE, -1); + GTK_TEXT_MOVEMENT_WRAPPED_LINE, -1); add_move_insert_binding (binding_set, GDK_Down, 0, - GTK_TEXT_MOVEMENT_LINE, 1); + GTK_TEXT_MOVEMENT_WRAPPED_LINE, 1); add_move_insert_binding (binding_set, GDK_p, GDK_CONTROL_MASK, - GTK_TEXT_MOVEMENT_LINE, -1); + GTK_TEXT_MOVEMENT_WRAPPED_LINE, -1); add_move_insert_binding (binding_set, GDK_n, GDK_CONTROL_MASK, - GTK_TEXT_MOVEMENT_LINE, 1); + GTK_TEXT_MOVEMENT_WRAPPED_LINE, 1); add_move_insert_binding (binding_set, GDK_a, GDK_CONTROL_MASK, - GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, -1); + GTK_TEXT_MOVEMENT_LINE_ENDS, -1); add_move_insert_binding (binding_set, GDK_e, GDK_CONTROL_MASK, - GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, 1); + GTK_TEXT_MOVEMENT_LINE_ENDS, 1); add_move_insert_binding (binding_set, GDK_f, GDK_MOD1_MASK, GTK_TEXT_MOVEMENT_WORD, 1); @@ -493,12 +498,12 @@ gtk_text_view_class_init (GtkTextViewClass *klass) gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK, "delete_text", 2, - GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_PARAGRAPH, + GTK_TYPE_ENUM, GTK_TEXT_DELETE_HALF_LINE, GTK_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK, "delete_text", 2, - GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHOLE_PARAGRAPH, + GTK_TYPE_ENUM, GTK_TEXT_DELETE_WHOLE_LINE, GTK_TYPE_INT, 1); gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK, @@ -614,6 +619,9 @@ gtk_text_view_init (GtkTextView *text_view) gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit", GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view); + + text_view->editable = TRUE; + text_view->cursor_visible = TRUE; } GtkWidget* @@ -664,7 +672,7 @@ gtk_text_view_set_buffer (GtkTextView *text_view, if (text_view->layout) gtk_text_layout_set_buffer (text_view->layout, buffer); - gtk_text_buffer_get_iter_at_char (text_view->buffer, &start, 0); + 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", @@ -707,6 +715,16 @@ gtk_text_view_get_iter_at_pixel (GtkTextView *text_view, y + text_view->yoffset); } +void +gtk_text_view_get_iter_location (GtkTextView *text_view, + const GtkTextIter *iter, + GdkRectangle *location) +{ + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + g_return_if_fail (gtk_text_iter_get_buffer (iter) == text_view->buffer); + + gtk_text_layout_get_iter_location (text_view->layout, iter, location); +} static void set_adjustment_clamped (GtkAdjustment *adj, gfloat val) @@ -817,7 +835,7 @@ gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view, if (scroll_inc != 0) { - set_adjustment_clamped (text_view->vadjustment, + set_adjustment_clamped (get_vadjustment (text_view), current_y_scroll + scroll_inc); retval = TRUE; } @@ -838,7 +856,7 @@ gtk_text_view_scroll_to_mark_adjusted (GtkTextView *text_view, if (scroll_inc != 0) { - set_adjustment_clamped (text_view->hadjustment, + set_adjustment_clamped (get_hadjustment (text_view), current_x_scroll + scroll_inc); retval = TRUE; } @@ -936,6 +954,62 @@ gtk_text_view_get_wrap_mode (GtkTextView *text_view) return text_view->wrap_mode; } +void +gtk_text_view_set_editable (GtkTextView *text_view, + gboolean setting) +{ + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + if (text_view->editable != setting) + { + text_view->editable = setting; + + if (text_view->layout) + { + text_view->layout->default_style->editable = text_view->editable; + gtk_text_layout_default_style_changed (text_view->layout); + } + } +} + +gboolean +gtk_text_view_get_editable (GtkTextView *text_view) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + + return text_view->editable; +} + +void +gtk_text_view_set_cursor_visible (GtkTextView *text_view, + gboolean setting) +{ + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + if (text_view->cursor_visible != setting) + { + text_view->cursor_visible = setting; + + if (GTK_WIDGET_HAS_FOCUS (text_view)) + { + GtkTextMark *insert; + + insert = gtk_text_buffer_get_mark (text_view->buffer, + "insert"); + gtk_text_mark_set_visible (insert, text_view->cursor_visible); + } + } +} + +gboolean +gtk_text_view_get_cursor_visible (GtkTextView *text_view) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + + return text_view->cursor_visible; +} + + gboolean gtk_text_view_place_cursor_onscreen (GtkTextView *text_view) { @@ -976,8 +1050,11 @@ gtk_text_view_finalize (GObject *object) text_view = GTK_TEXT_VIEW (object); - gtk_object_unref (GTK_OBJECT (text_view->hadjustment)); - gtk_object_unref (GTK_OBJECT (text_view->vadjustment)); + if (text_view->hadjustment) + gtk_object_unref (GTK_OBJECT (text_view->hadjustment)); + if (text_view->vadjustment) + gtk_object_unref (GTK_OBJECT (text_view->vadjustment)); + gtk_object_unref (GTK_OBJECT (text_view->im_context)); (* G_OBJECT_CLASS (parent_class)->finalize) (object); @@ -1060,8 +1137,9 @@ gtk_text_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { /* Hrm */ - requisition->width = 1; - requisition->height = 1; + + requisition->width = 200; + requisition->height = 200; } static void @@ -1101,6 +1179,10 @@ gtk_text_view_size_allocate (GtkWidget *widget, gtk_text_view_get_first_para_iter (text_view, &first_para); y = gtk_text_layout_get_line_y (text_view->layout, &first_para) + text_view->first_para_pixels; + /* Ensure h/v adj exist */ + get_hadjustment (text_view); + get_vadjustment (text_view); + vadj = text_view->vadjustment; if (y > vadj->upper - vadj->page_size) y = MAX (0, vadj->upper - vadj->page_size); @@ -1110,7 +1192,7 @@ gtk_text_view_size_allocate (GtkWidget *widget, vadj->value = text_view->yoffset = y; yoffset_changed = TRUE; } - + text_view->hadjustment->page_size = allocation->width; text_view->hadjustment->page_increment = allocation->width / 2; text_view->hadjustment->lower = 0; @@ -1233,15 +1315,14 @@ changed_handler (GtkTextLayout *layout, if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels) { text_view->yoffset += new_height - old_height; - text_view->vadjustment->value = text_view->yoffset; + get_vadjustment (text_view)->value = text_view->yoffset; yoffset_changed = TRUE; } gtk_text_view_scroll_calc_now (text_view); if (yoffset_changed) - gtk_adjustment_value_changed (text_view->vadjustment); - + gtk_adjustment_value_changed (get_vadjustment (text_view)); } } @@ -1412,6 +1493,39 @@ get_event_coordinates (GdkEvent *event, gint *x, gint *y) return FALSE; } +static gint +emit_event_on_tags (GtkWidget *widget, + GdkEvent *event, + GtkTextIter *iter) +{ + GSList *tags; + GSList *tmp; + gint retval = FALSE; + GtkTextView *text_view; + + text_view = GTK_TEXT_VIEW (widget); + + tags = gtk_text_buffer_get_tags (text_view->buffer, iter); + + tmp = tags; + while (tmp != NULL) + { + GtkTextTag *tag = tmp->data; + + if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, iter)) + { + retval = TRUE; + break; + } + + tmp = g_slist_next (tmp); + } + + g_slist_free (tags); + + return retval; +} + static gint gtk_text_view_event (GtkWidget *widget, GdkEvent *event) { @@ -1423,14 +1537,10 @@ gtk_text_view_event (GtkWidget *widget, GdkEvent *event) if (text_view->layout == NULL || text_view->buffer == NULL) return FALSE; - - /* FIXME eventually we really want to synthesize enter/leave - events here as the canvas does for canvas items */ if (get_event_coordinates (event, &x, &y)) { GtkTextIter iter; - gint retval = FALSE; x += text_view->xoffset; y += text_view->yoffset; @@ -1442,33 +1552,23 @@ gtk_text_view_event (GtkWidget *widget, GdkEvent *event) &iter, x, y); - { - GSList *tags; - GSList *tmp; - - tags = gtk_text_buffer_get_tags (text_view->buffer, &iter); - - tmp = tags; - while (tmp != NULL) - { - GtkTextTag *tag = tmp->data; + return emit_event_on_tags (widget, event, &iter); + } + else if (event->type == GDK_KEY_PRESS || + event->type == GDK_KEY_RELEASE) + { + GtkTextMark *insert; + GtkTextIter iter; - if (gtk_text_tag_event (tag, GTK_OBJECT (widget), event, &iter)) - { - retval = TRUE; - break; - } + insert = gtk_text_buffer_get_mark (text_view->buffer, + "insert"); - tmp = g_slist_next (tmp); - } + gtk_text_buffer_get_iter_at_mark (text_view->buffer, &iter, insert); - g_slist_free (tags); - } - - return retval; + return emit_event_on_tags (widget, event, &iter); } - - return FALSE; + else + return FALSE; } static gint @@ -1490,7 +1590,8 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event) return TRUE; else if (event->keyval == GDK_Return) { - gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1, + text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -1560,7 +1661,9 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) gtk_text_buffer_paste_primary_selection (text_view->buffer, &iter, - event->time); + event->time, + TRUE, + text_view->editable); return TRUE; } else if (event->button == 3) @@ -1596,7 +1699,7 @@ gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event) insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer, "insert"); - gtk_text_mark_set_visible (insert, TRUE); + gtk_text_mark_set_visible (insert, GTK_TEXT_VIEW (widget)->cursor_visible); gtk_text_view_start_cursor_blink (GTK_TEXT_VIEW (widget)); @@ -1762,7 +1865,7 @@ gtk_text_view_move_insert (GtkTextView *text_view, "insert")); newplace = insert; - if (step == GTK_TEXT_MOVEMENT_LINE) + if (step == GTK_TEXT_MOVEMENT_WRAPPED_LINE) gtk_text_view_get_virtual_cursor_pos (text_view, &cursor_x_pos, NULL); switch (step) @@ -1783,28 +1886,29 @@ gtk_text_view_move_insert (GtkTextView *text_view, gtk_text_iter_forward_word_ends (&newplace, count); break; - case GTK_TEXT_MOVEMENT_LINE: + case GTK_TEXT_MOVEMENT_WRAPPED_LINE: gtk_text_view_move_iter_by_lines (text_view, &newplace, count); gtk_text_layout_move_iter_to_x (text_view->layout, &newplace, cursor_x_pos); break; - case GTK_TEXT_MOVEMENT_PARAGRAPH: + case GTK_TEXT_MOVEMENT_LINE: /* This should almost certainly instead be doing the parallel thing to WORD */ - gtk_text_iter_down_lines (&newplace, count); + /* gtk_text_iter_down_lines (&newplace, count); */ + /* FIXME */ break; - case GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS: + case GTK_TEXT_MOVEMENT_LINE_ENDS: if (count > 0) gtk_text_iter_forward_to_newline (&newplace); else if (count < 0) - gtk_text_iter_set_line_char (&newplace, 0); + gtk_text_iter_set_line_offset (&newplace, 0); break; case GTK_TEXT_MOVEMENT_BUFFER_ENDS: if (count > 0) gtk_text_buffer_get_last_iter (text_view->buffer, &newplace); else if (count < 0) - gtk_text_buffer_get_iter_at_char (text_view->buffer, &newplace, 0); + gtk_text_buffer_get_iter_at_offset (text_view->buffer, &newplace, 0); break; default: @@ -1825,7 +1929,7 @@ gtk_text_view_move_insert (GtkTextView *text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), 0); - if (step == GTK_TEXT_MOVEMENT_LINE) + if (step == GTK_TEXT_MOVEMENT_WRAPPED_LINE) { gtk_text_view_set_virtual_cursor_pos (text_view, cursor_x_pos, -1); } @@ -1865,7 +1969,7 @@ gtk_text_view_scroll_text (GtkTextView *text_view, { default: case GTK_TEXT_SCROLL_TO_TOP: - gtk_text_buffer_get_iter_at_char (text_view->buffer, &anchor, 0); + gtk_text_buffer_get_iter_at_offset (text_view->buffer, &anchor, 0); y0 = 0; y1 = adj->page_size; break; @@ -1954,7 +2058,7 @@ find_whitepace_region (const GtkTextIter *center, *end = *center; if (gtk_text_iter_backward_find_char (start, not_whitespace, NULL)) - gtk_text_iter_forward_char (start); /* we want the first whitespace... */ + gtk_text_iter_next_char (start); /* we want the first whitespace... */ if (whitespace (gtk_text_iter_get_char (end), NULL)) gtk_text_iter_forward_find_char (end, not_whitespace, NULL); @@ -1974,7 +2078,8 @@ gtk_text_view_delete_text (GtkTextView *text_view, if (type == GTK_TEXT_DELETE_CHAR) { /* Char delete deletes the selection, if one exists */ - if (gtk_text_buffer_delete_selection (text_view->buffer)) + if (gtk_text_buffer_delete_selection (text_view->buffer, TRUE, + text_view->editable)) return; } @@ -2002,13 +2107,13 @@ gtk_text_view_delete_text (GtkTextView *text_view, case GTK_TEXT_DELETE_WHOLE_WORD: break; - case GTK_TEXT_DELETE_HALF_LINE: + case GTK_TEXT_DELETE_HALF_WRAPPED_LINE: break; - case GTK_TEXT_DELETE_WHOLE_LINE: + case GTK_TEXT_DELETE_WHOLE_WRAPPED_LINE: break; - case GTK_TEXT_DELETE_HALF_PARAGRAPH: + case GTK_TEXT_DELETE_HALF_LINE: while (count > 0) { if (!gtk_text_iter_forward_to_newline (&end)) @@ -2021,10 +2126,10 @@ gtk_text_view_delete_text (GtkTextView *text_view, and support that */ break; - case GTK_TEXT_DELETE_WHOLE_PARAGRAPH: + case GTK_TEXT_DELETE_WHOLE_LINE: if (count > 0) { - gtk_text_iter_set_line_char (&start, 0); + gtk_text_iter_set_line_offset (&start, 0); gtk_text_iter_forward_to_newline (&end); /* Do the lines beyond the first. */ @@ -2054,10 +2159,14 @@ gtk_text_view_delete_text (GtkTextView *text_view, if (!gtk_text_iter_equal (&start, &end)) { - gtk_text_buffer_delete (text_view->buffer, &start, &end); - - if (leave_one) - gtk_text_buffer_insert_at_cursor (text_view->buffer, " ", 1); + if (gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end, + text_view->editable)) + { + if (leave_one) + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, + " ", 1, + text_view->editable); + } gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2068,7 +2177,7 @@ gtk_text_view_delete_text (GtkTextView *text_view, static void gtk_text_view_cut_text (GtkTextView *text_view) { - gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME); + gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2088,7 +2197,7 @@ gtk_text_view_copy_text (GtkTextView *text_view) static void gtk_text_view_paste_text (GtkTextView *text_view) { - gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME); + gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2338,11 +2447,13 @@ gtk_text_view_scroll_calc_now (GtkTextView *text_view) text_view->width = width; text_view->height = height; - gtk_text_view_set_adjustment_upper (text_view->hadjustment, + gtk_text_view_set_adjustment_upper (get_hadjustment (text_view), MAX (widget->allocation.width, width)); - gtk_text_view_set_adjustment_upper (text_view->vadjustment, + gtk_text_view_set_adjustment_upper (get_vadjustment (text_view), MAX (widget->allocation.height, height)); + /* hadj/vadj exist since we called get_hadjustment/get_vadjustment above */ + /* Set up the step sizes; we'll say that a page is our allocation minus one step, and a step is 1/10 of our allocation. */ @@ -2567,9 +2678,10 @@ gtk_text_view_drag_data_get (GtkWidget *widget, static void gtk_text_view_drag_data_delete (GtkWidget *widget, - GdkDragContext *context) + GdkDragContext *context) { - gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer); + gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer, + TRUE, GTK_TEXT_VIEW (widget)->editable); } static void @@ -2610,9 +2722,18 @@ gtk_text_view_drag_motion (GtkWidget *widget, } else { - gtk_text_mark_set_visible (text_view->dnd_mark, TRUE); - - gdk_drag_status (context, context->suggested_action, time); + if (gtk_text_iter_editable (&newplace, text_view->editable)) + { + gtk_text_mark_set_visible (text_view->dnd_mark, text_view->cursor_visible); + + gdk_drag_status (context, context->suggested_action, time); + } + else + { + /* Can't drop here. */ + gdk_drag_status (context, 0, time); + gtk_text_mark_set_visible (text_view->dnd_mark, FALSE); + } } gtk_text_buffer_move_mark (text_view->buffer, @@ -2712,16 +2833,18 @@ gtk_text_view_drag_data_received (GtkWidget *widget, utf = gtk_text_latin1_to_utf ((const gchar*)selection_data->data, selection_data->length); - gtk_text_buffer_insert (text_view->buffer, &drop_point, - utf, -1); + gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point, + utf, -1, + text_view->editable); g_free (utf); } break; case UTF8: - gtk_text_buffer_insert (text_view->buffer, &drop_point, - (const gchar *)selection_data->data, - selection_data->length); + gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point, + (const gchar *)selection_data->data, + selection_data->length, + text_view->editable); break; case CTEXT: @@ -2737,15 +2860,26 @@ gtk_text_view_drag_data_received (GtkWidget *widget, &list); for (i=0; ibuffer, &drop_point, utf, -1); - - g_free (utf); + if (g_get_charset (&charset)) + { + utf = g_convert (list[i], -1, + "UTF8", charset, NULL); + free_utf = TRUE; + } + else + utf = list[i]; + + gtk_text_buffer_insert_interactive (text_view->buffer, + &drop_point, utf, -1, + text_view->editable); + + if (free_utf) + g_free(utf); } if (count > 0) @@ -2758,6 +2892,33 @@ gtk_text_view_drag_data_received (GtkWidget *widget, } } +static GtkAdjustment* +get_hadjustment (GtkTextView *text_view) +{ + if (text_view->hadjustment == NULL) + gtk_text_view_set_scroll_adjustments (text_view, + (GtkAdjustment*) + gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0), + text_view->vadjustment); + + return text_view->hadjustment; +} + +static GtkAdjustment* +get_vadjustment (GtkTextView *text_view) +{ + if (text_view->vadjustment == NULL) + gtk_text_view_set_scroll_adjustments (text_view, + text_view->hadjustment, + (GtkAdjustment*) + gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0)); + + return text_view->vadjustment; +} + + static void gtk_text_view_set_scroll_adjustments (GtkTextView *text_view, GtkAdjustment *hadj, @@ -2858,17 +3019,20 @@ gtk_text_view_commit_handler (GtkIMContext *context, const gchar *str, GtkTextView *text_view) { - gtk_text_buffer_delete_selection (text_view->buffer); + gtk_text_buffer_delete_selection (text_view->buffer, TRUE, + text_view->editable); if (!strcmp (str, "\n")) { - gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1, + text_view->editable); } else { if (text_view->overwrite_mode) gtk_text_view_delete_text (text_view, GTK_TEXT_DELETE_CHAR, 1); - gtk_text_buffer_insert_at_cursor (text_view->buffer, str, strlen (str)); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, str, -1, + text_view->editable); } gtk_text_view_scroll_to_mark (text_view, diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 8af1a9e7f..d1dca9ebf 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -13,9 +13,9 @@ typedef enum { GTK_TEXT_MOVEMENT_CHAR, /* move by forw/back chars */ GTK_TEXT_MOVEMENT_POSITIONS, /* move by left/right chars */ GTK_TEXT_MOVEMENT_WORD, /* move by forward/back words */ - GTK_TEXT_MOVEMENT_LINE, /* move up/down lines (wrapped lines) */ - GTK_TEXT_MOVEMENT_PARAGRAPH, /* move up/down paragraphs (newline-ended lines) */ - GTK_TEXT_MOVEMENT_PARAGRAPH_ENDS, /* move to either end of a paragraph */ + GTK_TEXT_MOVEMENT_WRAPPED_LINE, /* move up/down lines (wrapped lines) */ + GTK_TEXT_MOVEMENT_LINE, /* move up/down paragraphs (newline-ended lines) */ + GTK_TEXT_MOVEMENT_LINE_ENDS, /* move to either end of a paragraph */ GTK_TEXT_MOVEMENT_BUFFER_ENDS /* move to ends of the buffer */ } GtkTextViewMovementStep; @@ -32,10 +32,10 @@ typedef enum { left/right of cursor if we're in the middle of a word */ GTK_TEXT_DELETE_WHOLE_WORD, - GTK_TEXT_DELETE_HALF_LINE, - GTK_TEXT_DELETE_WHOLE_LINE, - GTK_TEXT_DELETE_HALF_PARAGRAPH, /* like C-k in Emacs (or its reverse) */ - GTK_TEXT_DELETE_WHOLE_PARAGRAPH, /* C-k in pico, kill whole line */ + GTK_TEXT_DELETE_HALF_WRAPPED_LINE, + GTK_TEXT_DELETE_WHOLE_WRAPPED_LINE, + GTK_TEXT_DELETE_HALF_LINE, /* like C-k in Emacs (or its reverse) */ + GTK_TEXT_DELETE_WHOLE_LINE, /* C-k in pico, kill whole line */ GTK_TEXT_DELETE_WHITESPACE, /* M-\ in Emacs */ GTK_TEXT_DELETE_WHITESPACE_LEAVE_ONE /* M-space in Emacs */ } GtkTextViewDeleteType; @@ -64,6 +64,10 @@ struct _GtkTextView { GtkWrapMode wrap_mode; /* Default wrap mode */ + gboolean editable; /* default editability */ + + gboolean cursor_visible; + GdkWindow *bin_window; GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; @@ -144,6 +148,18 @@ void gtk_text_view_set_wrap_mode (GtkTextView *text_view, GtkWrapMode wrap_mode); GtkWrapMode gtk_text_view_get_wrap_mode (GtkTextView *text_view); +void gtk_text_view_set_editable (GtkTextView *text_view, + gboolean setting); +gboolean gtk_text_view_get_editable (GtkTextView *text_view); + +void gtk_text_view_set_cursor_visible (GtkTextView *text_view, + gboolean setting); +gboolean gtk_text_view_get_cursor_visible (GtkTextView *text_view); + +void gtk_text_view_get_iter_location (GtkTextView *text_view, + const GtkTextIter *iter, + GdkRectangle *location); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/testtext.c b/gtk/testtext.c index fad48f039..bbff4d00a 100644 --- a/gtk/testtext.c +++ b/gtk/testtext.c @@ -20,6 +20,8 @@ struct _Buffer GtkTextBuffer *buffer; char *filename; gint untitled_serial; + GtkTextTag *not_editable_tag; + GtkTextTag *found_text_tag; }; struct _View @@ -41,6 +43,9 @@ static gboolean save_buffer (Buffer *buffer); static gboolean save_as_buffer (Buffer *buffer); static char * buffer_pretty_name (Buffer *buffer); static void buffer_filename_set (Buffer *buffer); +static void buffer_search_forward (Buffer *buffer, + const char *str, + View *view); static View *view_from_widget (GtkWidget *widget); @@ -290,14 +295,14 @@ msgbox_run (GtkWindow *parent, * Example buffer filling code */ static gint -blink_timeout(gpointer data) +blink_timeout (gpointer data) { GtkTextTag *tag; static gboolean flip = FALSE; - tag = GTK_TEXT_TAG(data); + tag = GTK_TEXT_TAG (data); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "foreground", flip ? "blue" : "purple", NULL); @@ -307,42 +312,46 @@ blink_timeout(gpointer data) } static gint -tag_event_handler(GtkTextTag *tag, GtkWidget *widget, GdkEvent *event, +tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event, const GtkTextIter *iter, gpointer user_data) { gint char_index; - char_index = gtk_text_iter_get_char_index(iter); + char_index = gtk_text_iter_get_offset (iter); switch (event->type) { case GDK_MOTION_NOTIFY: - printf("Motion event at char %d tag `%s'\n", + printf ("Motion event at char %d tag `%s'\n", char_index, tag->name); break; case GDK_BUTTON_PRESS: - printf("Button press at char %d tag `%s'\n", + printf ("Button press at char %d tag `%s'\n", char_index, tag->name); break; case GDK_2BUTTON_PRESS: - printf("Double click at char %d tag `%s'\n", + printf ("Double click at char %d tag `%s'\n", char_index, tag->name); break; case GDK_3BUTTON_PRESS: - printf("Triple click at char %d tag `%s'\n", + printf ("Triple click at char %d tag `%s'\n", char_index, tag->name); break; case GDK_BUTTON_RELEASE: - printf("Button release at char %d tag `%s'\n", + printf ("Button release at char %d tag `%s'\n", char_index, tag->name); break; case GDK_KEY_PRESS: case GDK_KEY_RELEASE: + printf ("Key event at char %d tag `%s'\n", + char_index, tag->name); + break; + case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: case GDK_PROPERTY_NOTIFY: @@ -365,12 +374,12 @@ tag_event_handler(GtkTextTag *tag, GtkWidget *widget, GdkEvent *event, } static void -setup_tag(GtkTextTag *tag) +setup_tag (GtkTextTag *tag) { - gtk_signal_connect(GTK_OBJECT(tag), + gtk_signal_connect (GTK_OBJECT (tag), "event", - GTK_SIGNAL_FUNC(tag_event_handler), + GTK_SIGNAL_FUNC (tag_event_handler), NULL); } @@ -413,77 +422,77 @@ fill_example_buffer (GtkTextBuffer *buffer) int i; char *str; - tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); + tag = gtk_text_buffer_create_tag (buffer, "fg_blue"); - /* gtk_timeout_add(1000, blink_timeout, tag); */ + /* gtk_timeout_add (1000, blink_timeout, tag); */ - setup_tag(tag); + setup_tag (tag); color.red = color.green = 0; color.blue = 0xffff; color2.red = 0xfff; color2.blue = 0x0; color2.green = 0; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "foreground_gdk", &color, "background_gdk", &color2, "font", "Sans 24", NULL); - tag = gtk_text_buffer_create_tag(buffer, "fg_red"); + tag = gtk_text_buffer_create_tag (buffer, "fg_red"); - setup_tag(tag); + setup_tag (tag); color.blue = color.green = 0; color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "offset", -4, "foreground_gdk", &color, NULL); - tag = gtk_text_buffer_create_tag(buffer, "bg_green"); + tag = gtk_text_buffer_create_tag (buffer, "bg_green"); - setup_tag(tag); + setup_tag (tag); color.blue = color.red = 0; color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "background_gdk", &color, "font", "Sans 10", NULL); - tag = gtk_text_buffer_create_tag(buffer, "overstrike"); + tag = gtk_text_buffer_create_tag (buffer, "overstrike"); - setup_tag(tag); + setup_tag (tag); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "overstrike", TRUE, NULL); - tag = gtk_text_buffer_create_tag(buffer, "underline"); + tag = gtk_text_buffer_create_tag (buffer, "underline"); - setup_tag(tag); + setup_tag (tag); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "underline", PANGO_UNDERLINE_SINGLE, NULL); - setup_tag(tag); + setup_tag (tag); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "underline", PANGO_UNDERLINE_SINGLE, NULL); - tag = gtk_text_buffer_create_tag(buffer, "centered"); + tag = gtk_text_buffer_create_tag (buffer, "centered"); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "justify", GTK_JUSTIFY_CENTER, NULL); - tag = gtk_text_buffer_create_tag(buffer, "rtl_quote"); + tag = gtk_text_buffer_create_tag (buffer, "rtl_quote"); - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "wrap_mode", GTK_WRAPMODE_WORD, "direction", GTK_TEXT_DIR_RTL, "left_wrapped_line_margin", 20, @@ -492,31 +501,31 @@ fill_example_buffer (GtkTextBuffer *buffer) NULL); pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_default_colormap(), + gtk_widget_get_default_colormap (), &mask, NULL, book_closed_xpm); - g_assert(pixmap != NULL); + g_assert (pixmap != NULL); i = 0; while (i < 100) { GtkTextMark * temp_mark; - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - str = g_strdup_printf("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", + str = g_strdup_printf ("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n", i); - gtk_text_buffer_insert(buffer, &iter, str, -1); + gtk_text_buffer_insert (buffer, &iter, str, -1); - g_free(str); + g_free (str); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 5); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5); - gtk_text_buffer_insert(buffer, &iter, + gtk_text_buffer_insert (buffer, &iter, "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n" /* This is UTF8 stuff, Emacs doesn't really know how to display it */ @@ -526,59 +535,59 @@ fill_example_buffer (GtkTextBuffer *buffer) gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE); #if 1 - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 6); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 13); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 10); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 16); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16); - gtk_text_buffer_apply_tag(buffer, "underline", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 1, 14); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 1, 24); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24); - gtk_text_buffer_apply_tag(buffer, "overstrike", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "overstrike", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 9); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 0, 16); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 10); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 4, 8); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter2, 4, 15); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2); #endif gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark); gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1); gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark); - gtk_text_buffer_apply_tag (buffer, "centered", &iter2, &iter); + gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter); gtk_text_buffer_move_mark (buffer, temp_mark, &iter); gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1); gtk_text_buffer_insert (buffer, &iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n", -1); gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark); - gtk_text_buffer_apply_tag (buffer, "rtl_quote", &iter2, &iter); + gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter); ++i; } - gdk_pixmap_unref(pixmap); + gdk_pixmap_unref (pixmap); if (mask) - gdk_bitmap_unref(mask); + gdk_bitmap_unref (mask); - printf("%d lines %d chars\n", - gtk_text_buffer_get_line_count(buffer), - gtk_text_buffer_get_char_count(buffer)); + printf ("%d lines %d chars\n", + gtk_text_buffer_get_line_count (buffer), + gtk_text_buffer_get_char_count (buffer)); gtk_text_buffer_set_modified (buffer, FALSE); } @@ -591,7 +600,7 @@ fill_file_buffer (GtkTextBuffer *buffer, const char *filename) gint remaining = 0; GtkTextIter iter, end; - f = fopen(filename, "r"); + f = fopen (filename, "r"); if (f == NULL) { @@ -602,7 +611,7 @@ fill_file_buffer (GtkTextBuffer *buffer, const char *filename) return FALSE; } - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0); while (!feof (f)) { gint count; @@ -650,7 +659,7 @@ fill_file_buffer (GtkTextBuffer *buffer, const char *filename) } static gint -delete_event_cb(GtkWidget *window, GdkEventAny *event, gpointer data) +delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data) { View *view = view_from_widget (window); @@ -801,7 +810,7 @@ do_exit (gpointer callback_data, tmp_list = tmp_list->next; } - gtk_main_quit(); + gtk_main_quit (); pop_active_window (); } @@ -839,6 +848,118 @@ do_direction_changed (gpointer callback_data, gtk_widget_queue_resize (view->text_view); } +static void +do_editable_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_cursor_visible_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_apply_editable (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + GtkTextIter start; + GtkTextIter end; + + if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer, + &start, &end)) + { + if (callback_action) + { + gtk_text_buffer_remove_tag (view->buffer->buffer, + view->buffer->not_editable_tag, + &start, &end); + } + else + { + gtk_text_buffer_apply_tag (view->buffer->buffer, + view->buffer->not_editable_tag, + &start, &end); + } + } +} + +static void +dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data) +{ + GtkTextBuffer *buffer; + View *view = data; + GtkTextIter start, end; + gchar *search_string; + + buffer = gtk_object_get_data (GTK_OBJECT (dialog), "buffer"); + + gtk_text_buffer_get_bounds (buffer, &start, &end); + + /* Remove trailing newline */ + gtk_text_iter_prev_char (&end); + + search_string = gtk_text_iter_get_text (&start, &end); + + printf ("Searching for `%s'\n", search_string); + + buffer_search_forward (view->buffer, search_string, view); + + g_free (search_string); + + gtk_widget_destroy (dialog); +} + +static void +do_search (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + GtkWidget *dialog; + GtkWidget *search_text; + GtkTextBuffer *buffer; + + dialog = gtk_dialog_new_with_buttons ("Search", + GTK_WINDOW (view->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_BUTTON_CLOSE, + GTK_RESPONSE_NONE, NULL); + + buffer = gtk_text_buffer_new (NULL); + + /* FIXME memory leak once buffer is a GObject */ + search_text = gtk_text_view_new_with_buffer (buffer); + + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox), + search_text, + TRUE, TRUE, 0); + + gtk_object_set_data (GTK_OBJECT (dialog), "buffer", buffer); + + gtk_signal_connect (GTK_OBJECT (dialog), + "response", + GTK_SIGNAL_FUNC (dialog_response_callback), + view); + + gtk_widget_show (search_text); + + gtk_widget_grab_focus (search_text); + + gtk_widget_show_all (dialog); +} + static void view_init_menus (View *view) { @@ -889,13 +1010,26 @@ static GtkItemFactoryEntry menu_items[] = { "/File/_Close", "W" , do_close, 0, NULL }, { "/File/E_xit", "Q" , do_exit, 0, NULL }, + { "/_Edit", NULL, 0, 0, "" }, + { "/Edit/Find...", NULL, do_search, 0, NULL }, + { "/_Settings", NULL, 0, 0, "" }, { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "" }, { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Editable", NULL, do_editable_changed, TRUE, "" }, + { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + + { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "" }, + { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "" }, { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, - + { "/_Attributes", NULL, 0, 0, "" }, + { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL }, + { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL }, { "/_Test", NULL, 0, 0, "" }, { "/Test/_Example", NULL, do_example, 0, NULL }, }; @@ -938,7 +1072,7 @@ save_buffer (Buffer *buffer) } else { - gtk_text_buffer_get_iter_at_char (buffer->buffer, &start, 0); + gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0); gtk_text_buffer_get_last_iter (buffer->buffer, &end); chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE); @@ -988,7 +1122,7 @@ save_as_ok_func (const char *filename, gpointer data) { struct stat statbuf; - if (stat(filename, &statbuf) == 0) + if (stat (filename, &statbuf) == 0) { gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename); gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1); @@ -1061,6 +1195,15 @@ create_buffer (void) buffer->filename = NULL; buffer->untitled_serial = -1; + buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL); + gtk_object_set (GTK_OBJECT (buffer->not_editable_tag), + "editable", FALSE, + "foreground", "purple", NULL); + + buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL); + gtk_object_set (GTK_OBJECT (buffer->found_text_tag), + "foreground", "red", NULL); + buffers = g_slist_prepend (buffers, buffer); return buffer; @@ -1107,6 +1250,60 @@ buffer_filename_set (Buffer *buffer) } } +static void +buffer_search_forward (Buffer *buffer, const char *str, + View *view) +{ + GtkTextIter iter; + GtkTextIter start, end; + gint char_len; + int i = 0; + GtkWidget *dialog; + + /* remove tag from whole buffer */ + gtk_text_buffer_get_bounds (buffer->buffer, &start, &end); + gtk_text_buffer_remove_tag (buffer->buffer, buffer->found_text_tag, + &start, &end ); + + gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter, + gtk_text_buffer_get_mark (buffer->buffer, + "insert")); + + + char_len = g_utf8_strlen (str, -1); + + if (char_len > 0) + { + while (gtk_text_iter_forward_search (&iter, str, TRUE, FALSE)) + { + GtkTextIter end = iter; + + gtk_text_iter_forward_chars (&end, char_len); + + gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag, + &iter, &end); + + iter = end; + + ++i; + } + } + + dialog = gtk_message_dialog_new (GTK_WINDOW (view->window), + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + GTK_DIALOG_DESTROY_WITH_PARENT, + "%d strings found and marked in red", + i); + + gtk_signal_connect_object (GTK_OBJECT (dialog), + "response", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (dialog)); + + gtk_widget_show (dialog); +} + static void buffer_ref (Buffer *buffer) { @@ -1137,7 +1334,7 @@ close_view (View *view) g_free (view); if (!views) - gtk_main_quit(); + gtk_main_quit (); } static void @@ -1178,7 +1375,7 @@ create_view (Buffer *buffer) gtk_object_set_data (GTK_OBJECT (view->window), "view", view); gtk_signal_connect (GTK_OBJECT (view->window), "delete_event", - GTK_SIGNAL_FUNC(delete_event_cb), NULL); + GTK_SIGNAL_FUNC (delete_event_cb), NULL); view->accel_group = gtk_accel_group_new (); view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "
", view->accel_group); @@ -1195,8 +1392,8 @@ create_view (Buffer *buffer) gtk_item_factory_get_widget (view->item_factory, "
"), FALSE, FALSE, 0); - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); @@ -1204,11 +1401,11 @@ create_view (Buffer *buffer) gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), GTK_WRAPMODE_WORD); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(sw), view->text_view); + gtk_container_add (GTK_CONTAINER (sw), view->text_view); gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500); - gtk_widget_grab_focus(view->text_view); + gtk_widget_grab_focus (view->text_view); view_set_title (view); view_init_menus (view); @@ -1218,14 +1415,15 @@ create_view (Buffer *buffer) } int -main(int argc, char** argv) +main (int argc, char** argv) { Buffer *buffer; View *view; int i; - gtk_init(&argc, &argv); - + gtk_init (&argc, &argv); + gdk_rgb_init (); /* FIXME remove this */ + buffer = create_buffer (); view = create_view (buffer); buffer_unref (buffer); @@ -1254,7 +1452,7 @@ main(int argc, char** argv) } pop_active_window (); - gtk_main(); + gtk_main (); return 0; } diff --git a/gtk/testtextbuffer.c b/gtk/testtextbuffer.c index 884ed0f88..8047dc62d 100644 --- a/gtk/testtextbuffer.c +++ b/gtk/testtextbuffer.c @@ -5,72 +5,72 @@ #include #include "gtktextbtree.h" -static void fill_buffer(GtkTextBuffer *buffer); +static void fill_buffer (GtkTextBuffer *buffer); -static void run_tests(GtkTextBuffer *buffer); +static void run_tests (GtkTextBuffer *buffer); int -main(int argc, char** argv) +main (int argc, char** argv) { GtkTextBuffer *buffer; int n; gunichar ch; GtkTextIter start, end; - gtk_init(&argc, &argv); + gtk_init (&argc, &argv); /* Check UTF8 unknown char thing */ - g_assert(g_utf8_strlen (gtk_text_unknown_char_utf8, 3) == 1); + g_assert (g_utf8_strlen (gtk_text_unknown_char_utf8, 3) == 1); ch = g_utf8_get_char (gtk_text_unknown_char_utf8); - g_assert(ch == gtk_text_unknown_char); + g_assert (ch == gtk_text_unknown_char); /* First, we turn on btree debugging. */ gtk_debug_flags |= GTK_DEBUG_TEXT; /* Create a buffer */ - buffer = gtk_text_buffer_new(NULL); + buffer = gtk_text_buffer_new (NULL); /* Check that buffer starts with one empty line and zero chars */ - n = gtk_text_buffer_get_line_count(buffer); + n = gtk_text_buffer_get_line_count (buffer); if (n != 1) - g_error("%d lines, expected 1", n); + g_error ("%d lines, expected 1", n); - n = gtk_text_buffer_get_char_count(buffer); + n = gtk_text_buffer_get_char_count (buffer); if (n != 1) - g_error("%d chars, expected 1", n); + g_error ("%d chars, expected 1", n); /* Run gruesome alien test suite on buffer */ - run_tests(buffer); + run_tests (buffer); /* Put stuff in the buffer */ - fill_buffer(buffer); + fill_buffer (buffer); /* Subject stuff-bloated buffer to further torment */ - run_tests(buffer); + run_tests (buffer); /* Delete all stuff from the buffer */ - gtk_text_buffer_get_bounds(buffer, &start, &end); - gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_buffer_get_bounds (buffer, &start, &end); + gtk_text_buffer_delete (buffer, &start, &end); /* Check buffer for emptiness (note that a single empty line always remains in the buffer) */ - n = gtk_text_buffer_get_line_count(buffer); + n = gtk_text_buffer_get_line_count (buffer); if (n != 1) - g_error("%d lines, expected 1", n); + g_error ("%d lines, expected 1", n); - n = gtk_text_buffer_get_char_count(buffer); + n = gtk_text_buffer_get_char_count (buffer); if (n != 1) - g_error("%d chars, expected 1", n); + g_error ("%d chars, expected 1", n); - run_tests(buffer); + run_tests (buffer); return 0; } static void -run_tests(GtkTextBuffer *buffer) +run_tests (GtkTextBuffer *buffer) { GtkTextIter iter; GtkTextIter start; @@ -80,149 +80,151 @@ run_tests(GtkTextBuffer *buffer) gint num_chars; GtkTextMark *bar_mark; - gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_get_bounds (buffer, &start, &end); /* Check that walking the tree via chars and via indexes produces * the same number of indexable locations. */ - num_chars = gtk_text_buffer_get_char_count(buffer); + num_chars = gtk_text_buffer_get_char_count (buffer); iter = start; - bar_mark = gtk_text_buffer_create_mark(buffer, "bar", &iter, FALSE); + bar_mark = gtk_text_buffer_create_mark (buffer, "bar", &iter, FALSE); i = 0; while (i < num_chars) { GtkTextIter current; GtkTextMark *foo_mark; - gtk_text_buffer_get_iter_at_char(buffer, ¤t, i); + gtk_text_buffer_get_iter_at_offset (buffer, ¤t, i); - if (!gtk_text_iter_equal(&iter, ¤t)) + if (!gtk_text_iter_equal (&iter, ¤t)) { - g_error("get_char_index didn't return current iter"); + g_error ("get_char_index didn't return current iter"); } - j = gtk_text_iter_get_char_index(&iter); + j = gtk_text_iter_get_offset (&iter); if (i != j) { - g_error("iter converted to %d not %d", j, i); + g_error ("iter converted to %d not %d", j, i); } /* get/set mark */ - gtk_text_buffer_get_iter_at_mark(buffer, &mark, bar_mark); + gtk_text_buffer_get_iter_at_mark (buffer, &mark, bar_mark); - if (!gtk_text_iter_equal(&iter, &mark)) + if (!gtk_text_iter_equal (&iter, &mark)) { - gtk_text_iter_spew(&iter, "iter"); - gtk_text_iter_spew(&mark, "mark"); - g_error("Mark not moved to the right place."); + gtk_text_iter_spew (&iter, "iter"); + gtk_text_iter_spew (&mark, "mark"); + g_error ("Mark not moved to the right place."); } - foo_mark = gtk_text_buffer_create_mark(buffer, "foo", &iter, FALSE); - gtk_text_buffer_get_iter_at_mark(buffer, &mark, foo_mark); - gtk_text_buffer_delete_mark(buffer, foo_mark); + foo_mark = gtk_text_buffer_create_mark (buffer, "foo", &iter, FALSE); + gtk_text_buffer_get_iter_at_mark (buffer, &mark, foo_mark); + gtk_text_buffer_delete_mark (buffer, foo_mark); - if (!gtk_text_iter_equal(&iter, &mark)) + if (!gtk_text_iter_equal (&iter, &mark)) { - gtk_text_iter_spew(&iter, "iter"); - gtk_text_iter_spew(&mark, "mark"); - g_error("Mark not created in the right place."); + gtk_text_iter_spew (&iter, "iter"); + gtk_text_iter_spew (&mark, "mark"); + g_error ("Mark not created in the right place."); } + + if (gtk_text_iter_is_last (&iter)) + g_error ("iterators ran out before chars (offset %d of %d)", + i, num_chars); - if (!gtk_text_iter_forward_char(&iter)) - g_error("iterators ran out before chars"); + gtk_text_iter_next_char (&iter); - gtk_text_buffer_move_mark(buffer, bar_mark, &iter); + gtk_text_buffer_move_mark (buffer, bar_mark, &iter); ++i; } - if (!gtk_text_iter_equal(&iter, &end)) - g_error("Iterating over all chars didn't end with the end iter"); + if (!gtk_text_iter_equal (&iter, &end)) + g_error ("Iterating over all chars didn't end with the end iter"); /* Do the tree-walk backward */ - num_chars = gtk_text_buffer_get_char_count(buffer); - gtk_text_buffer_get_iter_at_char(buffer, &iter, -1); + num_chars = gtk_text_buffer_get_char_count (buffer); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, -1); - gtk_text_buffer_move_mark(buffer, bar_mark, &iter); + gtk_text_buffer_move_mark (buffer, bar_mark, &iter); i = num_chars; - if (!gtk_text_iter_equal(&iter, &end)) - g_error("iter at char -1 is not equal to the end iterator"); + if (!gtk_text_iter_equal (&iter, &end)) + g_error ("iter at char -1 is not equal to the end iterator"); while (i >= 0) { GtkTextIter current; GtkTextMark *foo_mark; - gtk_text_buffer_get_iter_at_char(buffer, ¤t, i); + gtk_text_buffer_get_iter_at_offset (buffer, ¤t, i); - if (!gtk_text_iter_equal(&iter, ¤t)) + if (!gtk_text_iter_equal (&iter, ¤t)) { - g_error("get_char_index didn't return current iter while going backward"); + g_error ("get_char_index didn't return current iter while going backward"); } - j = gtk_text_iter_get_char_index(&iter); + j = gtk_text_iter_get_offset (&iter); if (i != j) { - g_error("going backward, iter converted to %d not %d", j, i); + g_error ("going backward, iter converted to %d not %d", j, i); } /* get/set mark */ - gtk_text_buffer_get_iter_at_mark(buffer, &mark, bar_mark); + gtk_text_buffer_get_iter_at_mark (buffer, &mark, bar_mark); - if (!gtk_text_iter_equal(&iter, &mark)) + if (!gtk_text_iter_equal (&iter, &mark)) { - gtk_text_iter_spew(&iter, "iter"); - gtk_text_iter_spew(&mark, "mark"); - g_error("Mark not moved to the right place."); + gtk_text_iter_spew (&iter, "iter"); + gtk_text_iter_spew (&mark, "mark"); + g_error ("Mark not moved to the right place."); } - foo_mark = gtk_text_buffer_create_mark(buffer, "foo", &iter, FALSE); - gtk_text_buffer_get_iter_at_mark(buffer, &mark, foo_mark); - gtk_text_buffer_delete_mark(buffer, foo_mark); + foo_mark = gtk_text_buffer_create_mark (buffer, "foo", &iter, FALSE); + gtk_text_buffer_get_iter_at_mark (buffer, &mark, foo_mark); + gtk_text_buffer_delete_mark (buffer, foo_mark); - if (!gtk_text_iter_equal(&iter, &mark)) + if (!gtk_text_iter_equal (&iter, &mark)) { - gtk_text_iter_spew(&iter, "iter"); - gtk_text_iter_spew(&mark, "mark"); - g_error("Mark not created in the right place."); + gtk_text_iter_spew (&iter, "iter"); + gtk_text_iter_spew (&mark, "mark"); + g_error ("Mark not created in the right place."); } if (i > 0) { - if (!gtk_text_iter_backward_char(&iter)) - g_error("iterators ran out before char indexes"); + if (!gtk_text_iter_prev_char (&iter)) + g_error ("iterators ran out before char indexes"); - gtk_text_buffer_move_mark(buffer, bar_mark, &iter); + gtk_text_buffer_move_mark (buffer, bar_mark, &iter); } else { - if (gtk_text_iter_backward_char(&iter)) - g_error("went backward from 0?"); + if (gtk_text_iter_prev_char (&iter)) + g_error ("went backward from 0?"); } --i; } - if (!gtk_text_iter_equal(&iter, &start)) - g_error("Iterating backward over all chars didn't end with the start iter"); + if (!gtk_text_iter_equal (&iter, &start)) + g_error ("Iterating backward over all chars didn't end with the start iter"); /* * Check that get_line_count returns the same number of lines * as walking the tree by line */ i = 1; /* include current (first) line */ - gtk_text_buffer_get_iter_at_line(buffer, &iter, 0); - while (gtk_text_iter_forward_line(&iter)) + gtk_text_buffer_get_iter_at_line (buffer, &iter, 0); + while (gtk_text_iter_forward_line (&iter)) ++i; - - /* Add 1 to the line count, because 'i' counts the end-iterator line */ - if (i != gtk_text_buffer_get_line_count(buffer) + 1) - g_error("Counted %d lines, buffer has %d", i, - gtk_text_buffer_get_line_count(buffer) + 1); + + if (i != gtk_text_buffer_get_line_count (buffer)) + g_error ("Counted %d lines, buffer has %d", i, + gtk_text_buffer_get_line_count (buffer)); } @@ -252,7 +254,7 @@ static char *book_closed_xpm[] = { " "}; static void -fill_buffer(GtkTextBuffer *buffer) +fill_buffer (GtkTextBuffer *buffer) { GtkTextTag *tag; GdkColor color, color2; @@ -262,65 +264,65 @@ fill_buffer(GtkTextBuffer *buffer) GdkBitmap *mask; int i; - tag = gtk_text_buffer_create_tag(buffer, "fg_blue"); + tag = gtk_text_buffer_create_tag (buffer, "fg_blue"); color.red = color.green = 0; color.blue = 0xffff; color2.red = 0xfff; color2.blue = 0x0; color2.green = 0; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "foreground_gdk", &color, "background_gdk", &color2, "font", "-*-courier-bold-r-*-*-30-*-*-*-*-*-*-*", NULL); - tag = gtk_text_buffer_create_tag(buffer, "fg_red"); + tag = gtk_text_buffer_create_tag (buffer, "fg_red"); color.blue = color.green = 0; color.red = 0xffff; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "offset", -4, "foreground_gdk", &color, NULL); - tag = gtk_text_buffer_create_tag(buffer, "bg_green"); + tag = gtk_text_buffer_create_tag (buffer, "bg_green"); color.blue = color.red = 0; color.green = 0xffff; - gtk_object_set(GTK_OBJECT(tag), + gtk_object_set (GTK_OBJECT (tag), "background_gdk", &color, "font", "-*-courier-bold-r-*-*-10-*-*-*-*-*-*-*", NULL); pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, - gtk_widget_get_default_colormap(), + gtk_widget_get_default_colormap (), &mask, NULL, book_closed_xpm); - g_assert(pixmap != NULL); + g_assert (pixmap != NULL); i = 0; while (i < 10) { gchar *str; - gtk_text_buffer_get_iter_at_char(buffer, &iter, 0); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_get_iter_at_char(buffer, &iter, 1); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 1); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - str = g_strdup_printf("%d Hello World!\nwoo woo woo woo woo woo woo woo\n", + str = g_strdup_printf ("%d Hello World!\nwoo woo woo woo woo woo woo woo\n", i); - gtk_text_buffer_insert(buffer, &iter, str, -1); + gtk_text_buffer_insert (buffer, &iter, str, -1); - g_free(str); + g_free (str); - gtk_text_buffer_insert(buffer, &iter, + gtk_text_buffer_insert (buffer, &iter, "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line\n\n" /* This is UTF8 stuff, Emacs doesn't really know how to display it */ @@ -330,64 +332,64 @@ fill_buffer(GtkTextBuffer *buffer) gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_get_iter_at_char(buffer, &iter, 4); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 4); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_get_iter_at_char(buffer, &iter, 7); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 7); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_get_iter_at_char(buffer, &iter, 8); + gtk_text_buffer_get_iter_at_offset (buffer, &iter, 8); gtk_text_buffer_insert_pixmap (buffer, &iter, pixmap, mask); - gtk_text_buffer_get_iter_at_line_char(buffer, &iter, 0, 8); + gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 8); iter2 = iter; - gtk_text_iter_forward_chars(&iter2, 10); + gtk_text_iter_forward_chars (&iter2, 10); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2); - gtk_text_iter_forward_chars(&iter, 7); - gtk_text_iter_forward_chars(&iter2, 10); + gtk_text_iter_forward_chars (&iter, 7); + gtk_text_iter_forward_chars (&iter2, 10); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2); - gtk_text_iter_forward_chars(&iter, 12); - gtk_text_iter_forward_chars(&iter2, 10); + gtk_text_iter_forward_chars (&iter, 12); + gtk_text_iter_forward_chars (&iter2, 10); - gtk_text_buffer_apply_tag(buffer, "bg_green", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2); - gtk_text_iter_forward_chars(&iter, 10); - gtk_text_iter_forward_chars(&iter2, 15); + gtk_text_iter_forward_chars (&iter, 10); + gtk_text_iter_forward_chars (&iter2, 15); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2); - gtk_text_iter_forward_chars(&iter, 20); - gtk_text_iter_forward_chars(&iter2, 20); + gtk_text_iter_forward_chars (&iter, 20); + gtk_text_iter_forward_chars (&iter2, 20); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2); - gtk_text_iter_backward_chars(&iter, 25); - gtk_text_iter_forward_chars(&iter2, 5); + gtk_text_iter_backward_chars (&iter, 25); + gtk_text_iter_forward_chars (&iter2, 5); - gtk_text_buffer_apply_tag(buffer, "fg_red", &iter, &iter2); - gtk_text_buffer_apply_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2); - gtk_text_iter_forward_chars(&iter, 15); - gtk_text_iter_backward_chars(&iter2, 10); + gtk_text_iter_forward_chars (&iter, 15); + gtk_text_iter_backward_chars (&iter2, 10); - gtk_text_buffer_remove_tag(buffer, "fg_red", &iter, &iter2); - gtk_text_buffer_remove_tag(buffer, "fg_blue", &iter, &iter2); + gtk_text_buffer_remove_tag_by_name (buffer, "fg_red", &iter, &iter2); + gtk_text_buffer_remove_tag_by_name (buffer, "fg_blue", &iter, &iter2); ++i; } - gdk_pixmap_unref(pixmap); + gdk_pixmap_unref (pixmap); if (mask) - gdk_bitmap_unref(mask); + gdk_bitmap_unref (mask); } -- cgit v1.2.1