forked from AuroraMiddleware/gtk
Get rid of the newline-that-could-not-be-deleted; buffers may now be
2001-09-24 Havoc Pennington <hp@redhat.com> * gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c, gtktextlayout.c: Get rid of the newline-that-could-not-be-deleted; buffers may now be zero-length. Much easier to fix than expected, once I figured out the right way to do it. However, there are various subtle bugs introduced by this that will have to get sorted out. Please use bugzilla.
This commit is contained in:
parent
7837ddcde4
commit
1e3b62fd13
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -1,3 +1,13 @@
|
||||
2001-09-24 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/gtktextiter.c, gtk/gtktextbuffer.c, gtk/gtktextbtree.c,
|
||||
gtktextlayout.c:
|
||||
Get rid of the newline-that-could-not-be-deleted; buffers may
|
||||
now be zero-length. Much easier to fix than expected, once
|
||||
I figured out the right way to do it. However, there are
|
||||
various subtle bugs introduced by this that will have to get
|
||||
sorted out. Please use bugzilla.
|
||||
|
||||
Mon Sep 24 15:09:08 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* gtk/gtkwindow.c (gtk_window_move_resize): Don't wait for a
|
||||
|
@ -102,6 +102,14 @@ between the old and new positions).
|
||||
</footnote>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Text buffers always contain at least one line, but may be empty (that is,
|
||||
buffers can contain zero characters). The last line in the text buffer never
|
||||
ends in a line separator (such as newline); the other lines in the buffer always
|
||||
end in a line separator. Line separators count as characters when computing
|
||||
character counts and character offsets.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
||||
|
@ -96,9 +96,9 @@ Creates a new #GtkMenu.
|
||||
Adds a new #GtkMenuItem to the end of the menu's item list.
|
||||
</para>
|
||||
|
||||
<!-- # Unused Parameters # -->
|
||||
@menu: a #GtkMenu.
|
||||
@child: The #GtkMenuItem to add.
|
||||
<!-- # Unused Parameters # -->
|
||||
@m:
|
||||
@c:
|
||||
|
||||
@ -108,9 +108,9 @@ Adds a new #GtkMenuItem to the end of the menu's item list.
|
||||
Adds a new #GtkMenuItem to the beginning of the menu's item list.
|
||||
</para>
|
||||
|
||||
<!-- # Unused Parameters # -->
|
||||
@menu: a #GtkMenu.
|
||||
@child: The #GtkMenuItem to add.
|
||||
<!-- # Unused Parameters # -->
|
||||
@menu_child:
|
||||
@m:
|
||||
@c:
|
||||
@ -122,10 +122,10 @@ Adds a new #GtkMenuItem to the menu's item list at the position
|
||||
indicated by @position.
|
||||
</para>
|
||||
|
||||
<!-- # Unused Parameters # -->
|
||||
@menu: a #GtkMenu.
|
||||
@child: The #GtkMenuItem to add.
|
||||
@pos:
|
||||
<!-- # Unused Parameters # -->
|
||||
@position: The position in the item list where @child is added.
|
||||
Positions are numbered from 0 to n-1.
|
||||
|
||||
|
@ -185,22 +185,32 @@ struct _GtkTextBTree {
|
||||
guint tag_changed_handler;
|
||||
guint tag_removed_handler;
|
||||
/* Incremented when a segment with a byte size > 0
|
||||
is added to or removed from the tree (i.e. the
|
||||
length of a line may have changed, and lines may
|
||||
have been added or removed). This invalidates
|
||||
all outstanding iterators.
|
||||
*/
|
||||
* is added to or removed from the tree (i.e. the
|
||||
* length of a line may have changed, and lines may
|
||||
* have been added or removed). This invalidates
|
||||
* all outstanding iterators.
|
||||
*/
|
||||
guint chars_changed_stamp;
|
||||
/* Incremented when any segments are added or deleted;
|
||||
this makes outstanding iterators recalculate their
|
||||
pointed-to segment and segment offset.
|
||||
*/
|
||||
* this makes outstanding iterators recalculate their
|
||||
* pointed-to segment and segment offset.
|
||||
*/
|
||||
guint segments_changed_stamp;
|
||||
|
||||
/* Cache the last line in the buffer */
|
||||
GtkTextLine *last_line;
|
||||
guint last_line_stamp;
|
||||
|
||||
/* Cache the next-to-last line in the buffer,
|
||||
* containing the end iterator
|
||||
*/
|
||||
GtkTextLine *end_iter_line;
|
||||
|
||||
GtkTextLineSegment *end_iter_segment;
|
||||
int end_iter_segment_byte_index;
|
||||
int end_iter_segment_char_offset;
|
||||
guint end_iter_line_stamp;
|
||||
|
||||
guint end_iter_segment_stamp;
|
||||
|
||||
GHashTable *child_anchor_table;
|
||||
};
|
||||
|
||||
@ -409,9 +419,15 @@ _gtk_text_btree_new (GtkTextTagTable *table,
|
||||
tree->chars_changed_stamp = g_random_int ();
|
||||
tree->segments_changed_stamp = g_random_int ();
|
||||
|
||||
tree->end_iter_line_stamp = tree->chars_changed_stamp - 1;
|
||||
tree->end_iter_line = NULL;
|
||||
tree->last_line_stamp = tree->chars_changed_stamp - 1;
|
||||
tree->last_line = NULL;
|
||||
|
||||
tree->end_iter_line_stamp = tree->chars_changed_stamp - 1;
|
||||
tree->end_iter_segment_stamp = tree->segments_changed_stamp - 1;
|
||||
tree->end_iter_line = NULL;
|
||||
tree->end_iter_segment_byte_index = 0;
|
||||
tree->end_iter_segment_char_offset = 0;
|
||||
|
||||
g_object_ref (G_OBJECT (tree->table));
|
||||
|
||||
tree->tag_changed_handler = g_signal_connect (G_OBJECT (tree->table),
|
||||
@ -570,6 +586,7 @@ _gtk_text_btree_delete (GtkTextIter *start,
|
||||
_gtk_text_btree_check (tree);
|
||||
|
||||
{
|
||||
/* FIXME this code should no longer be required */
|
||||
/*
|
||||
* The code below is ugly, but it's needed to make sure there
|
||||
* is always a dummy empty line at the end of the text. If the
|
||||
@ -1903,11 +1920,20 @@ _gtk_text_btree_get_line (GtkTextBTree *tree,
|
||||
return line;
|
||||
}
|
||||
|
||||
GtkTextLine*
|
||||
_gtk_text_btree_get_end_iter_line (GtkTextBTree *tree)
|
||||
{
|
||||
return
|
||||
_gtk_text_btree_get_line (tree,
|
||||
_gtk_text_btree_line_count (tree) - 1,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GtkTextLine*
|
||||
_gtk_text_btree_get_line_at_char (GtkTextBTree *tree,
|
||||
gint char_index,
|
||||
gint *line_start_index,
|
||||
gint *real_char_index)
|
||||
gint char_index,
|
||||
gint *line_start_index,
|
||||
gint *real_char_index)
|
||||
{
|
||||
GtkTextBTreeNode *node;
|
||||
GtkTextLine *line;
|
||||
@ -1918,10 +1944,13 @@ _gtk_text_btree_get_line_at_char (GtkTextBTree *tree,
|
||||
|
||||
node = tree->root_node;
|
||||
|
||||
/* Clamp to valid indexes (-1 is magic for "highest index") */
|
||||
if (char_index < 0 || char_index >= node->num_chars)
|
||||
/* Clamp to valid indexes (-1 is magic for "highest index"),
|
||||
* node->num_chars includes the two newlines that aren't really
|
||||
* in the buffer.
|
||||
*/
|
||||
if (char_index < 0 || char_index >= (node->num_chars - 1))
|
||||
{
|
||||
char_index = node->num_chars - 1;
|
||||
char_index = node->num_chars - 2;
|
||||
}
|
||||
|
||||
*real_char_index = char_index;
|
||||
@ -2242,8 +2271,10 @@ _gtk_text_btree_line_count (GtkTextBTree *tree)
|
||||
gint
|
||||
_gtk_text_btree_char_count (GtkTextBTree *tree)
|
||||
{
|
||||
/* Exclude newline in bogus last line */
|
||||
return tree->root_node->num_chars - 1;
|
||||
/* Exclude newline in bogus last line and the
|
||||
* one in the last line that is after the end iterator
|
||||
*/
|
||||
return tree->root_node->num_chars - 2;
|
||||
}
|
||||
|
||||
#define LOTSA_TAGS 1000
|
||||
@ -3137,6 +3168,88 @@ _gtk_text_line_is_last (GtkTextLine *line,
|
||||
return line == get_last_line (tree);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_end_iter_line (GtkTextBTree *tree)
|
||||
{
|
||||
if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
|
||||
{
|
||||
int n_lines;
|
||||
int real_line;
|
||||
|
||||
/* n_lines is without the magic line at the end */
|
||||
n_lines = _gtk_text_btree_line_count (tree);
|
||||
|
||||
g_assert (n_lines >= 1);
|
||||
|
||||
tree->end_iter_line = _gtk_text_btree_get_line (tree, n_lines - 1, &real_line);
|
||||
|
||||
tree->end_iter_line_stamp = tree->chars_changed_stamp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_end_iter_segment (GtkTextBTree *tree)
|
||||
{
|
||||
if (tree->end_iter_segment_stamp != tree->segments_changed_stamp)
|
||||
{
|
||||
GtkTextLineSegment *seg;
|
||||
GtkTextLineSegment *last_with_chars;
|
||||
|
||||
ensure_end_iter_line (tree);
|
||||
|
||||
last_with_chars = NULL;
|
||||
|
||||
seg = tree->end_iter_line->segments;
|
||||
while (seg != NULL)
|
||||
{
|
||||
if (seg->char_count > 0)
|
||||
last_with_chars = seg;
|
||||
seg = seg->next;
|
||||
}
|
||||
|
||||
tree->end_iter_segment = last_with_chars;
|
||||
|
||||
/* We know the last char in the last line is '\n' */
|
||||
tree->end_iter_segment_byte_index = last_with_chars->byte_count - 1;
|
||||
tree->end_iter_segment_char_offset = last_with_chars->char_count - 1;
|
||||
|
||||
tree->end_iter_segment_stamp = tree->segments_changed_stamp;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_text_line_contains_end_iter (GtkTextLine *line,
|
||||
GtkTextBTree *tree)
|
||||
{
|
||||
ensure_end_iter_line (tree);
|
||||
|
||||
return line == tree->end_iter_line;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_text_btree_is_end (GtkTextBTree *tree,
|
||||
GtkTextLine *line,
|
||||
GtkTextLineSegment *seg,
|
||||
int byte_index,
|
||||
int char_offset)
|
||||
{
|
||||
g_return_val_if_fail (byte_index >= 0 || char_offset >= 0, FALSE);
|
||||
|
||||
/* Do this first to avoid walking segments in most cases */
|
||||
if (!_gtk_text_line_contains_end_iter (line, tree))
|
||||
return FALSE;
|
||||
|
||||
ensure_end_iter_segment (tree);
|
||||
|
||||
if (seg != tree->end_iter_segment)
|
||||
return FALSE;
|
||||
|
||||
if (byte_index >= 0)
|
||||
return byte_index == tree->end_iter_segment_byte_index;
|
||||
else
|
||||
return char_offset == tree->end_iter_segment_char_offset;
|
||||
}
|
||||
|
||||
GtkTextLine*
|
||||
_gtk_text_line_next (GtkTextLine *line)
|
||||
{
|
||||
@ -3172,6 +3285,23 @@ _gtk_text_line_next (GtkTextLine *line)
|
||||
}
|
||||
}
|
||||
|
||||
GtkTextLine*
|
||||
_gtk_text_line_next_excluding_last (GtkTextLine *line)
|
||||
{
|
||||
GtkTextLine *next;
|
||||
|
||||
next = _gtk_text_line_next (line);
|
||||
|
||||
/* If we were on the end iter line, we can't go to
|
||||
* the last line
|
||||
*/
|
||||
if (next && next->next == NULL && /* these checks are optimization only */
|
||||
_gtk_text_line_next (next) == NULL)
|
||||
return NULL;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
GtkTextLine*
|
||||
_gtk_text_line_previous (GtkTextLine *line)
|
||||
{
|
||||
@ -3950,9 +4080,9 @@ node_compare (GtkTextBTreeNode *lhs,
|
||||
|
||||
/* remember that tag == NULL means "any tag" */
|
||||
GtkTextLine*
|
||||
_gtk_text_line_next_could_contain_tag (GtkTextLine *line,
|
||||
GtkTextBTree *tree,
|
||||
GtkTextTag *tag)
|
||||
_gtk_text_line_next_could_contain_tag (GtkTextLine *line,
|
||||
GtkTextBTree *tree,
|
||||
GtkTextTag *tag)
|
||||
{
|
||||
GtkTextBTreeNode *node;
|
||||
GtkTextTagInfo *info;
|
||||
@ -3968,17 +4098,17 @@ _gtk_text_line_next_could_contain_tag (GtkTextLine *line,
|
||||
/* Right now we can only offer linear-search if the user wants
|
||||
* to know about any tag toggle at all.
|
||||
*/
|
||||
return _gtk_text_line_next (line);
|
||||
return _gtk_text_line_next_excluding_last (line);
|
||||
}
|
||||
|
||||
/* Our tag summaries only have node precision, not line
|
||||
precision. This means that if any line under a node could contain a
|
||||
tag, then any of the others could also contain a tag.
|
||||
|
||||
In the future we could have some mechanism to keep track of how
|
||||
many toggles we've found under a node so far, since we have a
|
||||
count of toggles under the node. But for now I'm going with KISS.
|
||||
*/
|
||||
* precision. This means that if any line under a node could contain a
|
||||
* tag, then any of the others could also contain a tag.
|
||||
*
|
||||
* In the future we could have some mechanism to keep track of how
|
||||
* many toggles we've found under a node so far, since we have a
|
||||
* count of toggles under the node. But for now I'm going with KISS.
|
||||
*/
|
||||
|
||||
/* return same-node line, if any. */
|
||||
if (line->next)
|
||||
@ -4330,7 +4460,7 @@ summary_list_destroy (Summary *summary)
|
||||
static GtkTextLine*
|
||||
get_last_line (GtkTextBTree *tree)
|
||||
{
|
||||
if (tree->end_iter_line_stamp != tree->chars_changed_stamp)
|
||||
if (tree->last_line_stamp != tree->chars_changed_stamp)
|
||||
{
|
||||
gint n_lines;
|
||||
GtkTextLine *line;
|
||||
@ -4342,11 +4472,11 @@ get_last_line (GtkTextBTree *tree)
|
||||
|
||||
line = _gtk_text_btree_get_line (tree, n_lines, &real_line);
|
||||
|
||||
tree->end_iter_line_stamp = tree->chars_changed_stamp;
|
||||
tree->end_iter_line = line;
|
||||
tree->last_line_stamp = tree->chars_changed_stamp;
|
||||
tree->last_line = line;
|
||||
}
|
||||
|
||||
return tree->end_iter_line;
|
||||
return tree->last_line;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -23,6 +23,11 @@ guint _gtk_text_btree_get_chars_changed_stamp (GtkTextBTree *tree);
|
||||
guint _gtk_text_btree_get_segments_changed_stamp (GtkTextBTree *tree);
|
||||
void _gtk_text_btree_segments_changed (GtkTextBTree *tree);
|
||||
|
||||
gboolean _gtk_text_btree_is_end (GtkTextBTree *tree,
|
||||
GtkTextLine *line,
|
||||
GtkTextLineSegment *seg,
|
||||
int byte_index,
|
||||
int char_offset);
|
||||
|
||||
/* Indexable segment mutation */
|
||||
|
||||
@ -82,6 +87,7 @@ void _gtk_text_btree_tag (const GtkTextIter *start,
|
||||
GtkTextLine * _gtk_text_btree_get_line (GtkTextBTree *tree,
|
||||
gint line_number,
|
||||
gint *real_line_number);
|
||||
GtkTextLine * _gtk_text_btree_get_end_iter_line (GtkTextBTree *tree);
|
||||
GtkTextLine * _gtk_text_btree_get_line_at_char (GtkTextBTree *tree,
|
||||
gint char_index,
|
||||
gint *line_start_index,
|
||||
@ -205,9 +211,12 @@ gboolean _gtk_text_line_byte_has_tag (GtkTextLine
|
||||
GtkTextBTree *tree,
|
||||
gint byte_in_line,
|
||||
GtkTextTag *tag);
|
||||
gboolean _gtk_text_line_is_last (GtkTextLine *line,
|
||||
GtkTextBTree *tree);
|
||||
gboolean _gtk_text_line_is_last (GtkTextLine *line,
|
||||
GtkTextBTree *tree);
|
||||
gboolean _gtk_text_line_contains_end_iter (GtkTextLine *line,
|
||||
GtkTextBTree *tree);
|
||||
GtkTextLine * _gtk_text_line_next (GtkTextLine *line);
|
||||
GtkTextLine * _gtk_text_line_next_excluding_last (GtkTextLine *line);
|
||||
GtkTextLine * _gtk_text_line_previous (GtkTextLine *line);
|
||||
void _gtk_text_line_add_data (GtkTextLine *line,
|
||||
GtkTextLineData *data);
|
||||
|
@ -407,11 +407,8 @@ gtk_text_buffer_get_tag_table (GtkTextBuffer *buffer)
|
||||
* @text: UTF-8 text to insert
|
||||
* @len: length of @text in bytes
|
||||
*
|
||||
* Deletes current contents of @buffer, and inserts @text instead. If
|
||||
* @text doesn't end with a newline, a newline is added;
|
||||
* #GtkTextBuffer contents must always end with a newline. If @text
|
||||
* ends with a newline, the new buffer contents will be exactly
|
||||
* @text. If @len is -1, @text must be nul-terminated.
|
||||
* Deletes current contents of @buffer, and inserts @text instead. If
|
||||
* @len is -1, @text must be nul-terminated. @text must be valid UTF-8.
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_set_text (GtkTextBuffer *buffer,
|
||||
@ -426,12 +423,6 @@ gtk_text_buffer_set_text (GtkTextBuffer *buffer,
|
||||
if (len < 0)
|
||||
len = strlen (text);
|
||||
|
||||
/* Chop newline, since the buffer will already have one
|
||||
* in it.
|
||||
*/
|
||||
if (len > 0 && text[len-1] == '\n')
|
||||
len -= 1;
|
||||
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
|
||||
gtk_text_buffer_delete (buffer, &start, &end);
|
||||
@ -1135,14 +1126,6 @@ gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
|
||||
|
||||
gtk_text_iter_order (start, end);
|
||||
|
||||
/* Somewhat annoyingly, if you try to delete the final newline
|
||||
* the BTree will put it back; which means you can't deduce the
|
||||
* final contents of the buffer purely by monitoring insert/delete
|
||||
* signals on the buffer. But if you delete the final newline, any
|
||||
* tags on the newline will go away, oddly. See comment in
|
||||
* gtktextbtree.c. This is all sort of annoying, but really hard
|
||||
* to fix.
|
||||
*/
|
||||
g_signal_emit (G_OBJECT (buffer),
|
||||
signals[DELETE_RANGE],
|
||||
0,
|
||||
@ -1163,11 +1146,6 @@ gtk_text_buffer_emit_delete (GtkTextBuffer *buffer,
|
||||
* calling this function; however, the @start and @end will be
|
||||
* re-initialized to point to the location where text was deleted.
|
||||
*
|
||||
* Note that the final newline in the buffer may not be deleted; a
|
||||
* #GtkTextBuffer always contains at least one newline. You can
|
||||
* safely include the final newline in the range [@start,@end) but it
|
||||
* won't be affected by the deletion.
|
||||
*
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_delete (GtkTextBuffer *buffer,
|
||||
@ -1529,14 +1507,15 @@ gtk_text_buffer_mark_set (GtkTextBuffer *buffer,
|
||||
GtkTextMark *mark)
|
||||
{
|
||||
/* IMO this should NOT work like insert_text and delete_range,
|
||||
where the real action happens in the default handler.
|
||||
|
||||
The reason is that the default handler would be _required_,
|
||||
i.e. the whole widget would start breaking and segfaulting
|
||||
if the default handler didn't get run. So you can't really
|
||||
override the default handler or stop the emission; that is,
|
||||
this signal is purely for notification, and not to allow users
|
||||
to modify the default behavior. */
|
||||
* where the real action happens in the default handler.
|
||||
*
|
||||
* The reason is that the default handler would be _required_,
|
||||
* i.e. the whole widget would start breaking and segfaulting if the
|
||||
* default handler didn't get run. So you can't really override the
|
||||
* default handler or stop the emission; that is, this signal is
|
||||
* purely for notification, and not to allow users to modify the
|
||||
* default behavior.
|
||||
*/
|
||||
|
||||
g_object_ref (G_OBJECT (mark));
|
||||
|
||||
@ -2701,8 +2680,6 @@ clipboard_get_contents_cb (GtkClipboard *clipboard,
|
||||
GtkTextIter start, end;
|
||||
|
||||
gtk_text_buffer_get_bounds (contents, &start, &end);
|
||||
/* strip off the trailing newline, it isn't part of the text that was cut */
|
||||
gtk_text_iter_backward_char (&end);
|
||||
|
||||
str = gtk_text_iter_get_visible_text (&start, &end);
|
||||
gtk_selection_data_set_text (selection_data, str);
|
||||
@ -3466,8 +3443,16 @@ _gtk_text_buffer_get_line_log_attrs (GtkTextBuffer *buffer,
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (anywhere_in_line != NULL, NULL);
|
||||
g_return_val_if_fail (!gtk_text_iter_is_end (anywhere_in_line), NULL);
|
||||
|
||||
/* special-case for empty last line in buffer */
|
||||
if (gtk_text_iter_is_end (anywhere_in_line) &&
|
||||
gtk_text_iter_get_line_offset (anywhere_in_line) == 0)
|
||||
{
|
||||
if (char_len)
|
||||
*char_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME we also need to recompute log attrs if the language tag at
|
||||
* the start of a paragraph changes
|
||||
*/
|
||||
|
@ -1532,7 +1532,19 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
|
||||
|
||||
check_invariants (iter);
|
||||
|
||||
return _gtk_text_line_is_last (real->line, real->tree);
|
||||
if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
|
||||
return FALSE;
|
||||
|
||||
/* Now we need the segments validated */
|
||||
real = gtk_text_iter_make_real (iter);
|
||||
|
||||
if (real == NULL)
|
||||
return FALSE;
|
||||
|
||||
return _gtk_text_btree_is_end (real->tree, real->line,
|
||||
real->segment,
|
||||
real->segment_byte_offset,
|
||||
real->segment_char_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1701,18 +1713,23 @@ gtk_text_iter_get_attributes (const GtkTextIter *iter,
|
||||
/* The return value of this indicates WHETHER WE MOVED.
|
||||
* The return value of public functions indicates
|
||||
* (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
|
||||
*
|
||||
* This function will not change the iterator if
|
||||
* it's already on the last (end iter) line, i.e. it
|
||||
* won't move to the end of the last line.
|
||||
*/
|
||||
static gboolean
|
||||
forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
|
||||
{
|
||||
GtkTextLine *new_line;
|
||||
|
||||
new_line = _gtk_text_line_next (real->line);
|
||||
|
||||
g_assert (new_line != real->line);
|
||||
|
||||
if (new_line != NULL)
|
||||
if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
|
||||
{
|
||||
GtkTextLine *new_line;
|
||||
|
||||
new_line = _gtk_text_line_next (real->line);
|
||||
g_assert (new_line);
|
||||
g_assert (new_line != real->line);
|
||||
g_assert (!_gtk_text_line_is_last (new_line, real->tree));
|
||||
|
||||
real->line = new_line;
|
||||
|
||||
real->line_byte_offset = 0;
|
||||
@ -1731,24 +1748,11 @@ forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no way to move forward; we were already
|
||||
at the "end" index. (the end index is the last
|
||||
line pointer, segment_byte_offset of 0) */
|
||||
|
||||
g_assert (real->line_char_offset == 0 ||
|
||||
real->line_byte_offset == 0);
|
||||
|
||||
/* The only indexable segment allowed on the bogus
|
||||
line at the end is a single char segment containing
|
||||
a newline. */
|
||||
if (real->segments_changed_stamp ==
|
||||
_gtk_text_btree_get_segments_changed_stamp (real->tree))
|
||||
{
|
||||
g_assert (real->segment->type == >k_text_char_type);
|
||||
g_assert (real->segment->char_count == 1);
|
||||
}
|
||||
/* We leave real->line as-is */
|
||||
|
||||
/* There is no way to move forward a line; we were already at
|
||||
* the line containing the end iterator.
|
||||
* However we may not be at the end iterator itself.
|
||||
*/
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -1950,6 +1954,8 @@ _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
|
||||
{
|
||||
/* End of buffer */
|
||||
|
||||
g_assert (gtk_text_iter_is_end (iter));
|
||||
|
||||
check_invariants (iter);
|
||||
|
||||
return FALSE;
|
||||
@ -2442,6 +2448,11 @@ gtk_text_iter_forward_line (GtkTextIter *iter)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* On the last line, move to end of it */
|
||||
|
||||
if (!gtk_text_iter_is_end (iter))
|
||||
gtk_text_iter_forward_to_end (iter);
|
||||
|
||||
check_invariants (iter);
|
||||
return FALSE;
|
||||
}
|
||||
@ -2789,7 +2800,9 @@ test_log_attrs (const GtkTextIter *iter,
|
||||
|
||||
offset = gtk_text_iter_get_line_offset (iter);
|
||||
|
||||
g_assert (char_len > 0);
|
||||
/* char_len may be 0 and attrs will be NULL if so, if
|
||||
* iter is the end iter and the last line is empty
|
||||
*/
|
||||
|
||||
if (offset < char_len)
|
||||
result = (* func) (attrs, offset, 0, char_len);
|
||||
@ -2814,8 +2827,10 @@ find_line_log_attrs (const GtkTextIter *iter,
|
||||
iter, &char_len);
|
||||
|
||||
offset = gtk_text_iter_get_line_offset (iter);
|
||||
|
||||
g_assert (char_len > 0);
|
||||
|
||||
/* char_len may be 0 and attrs will be NULL if so, if
|
||||
* iter is the end iter and the last line is empty
|
||||
*/
|
||||
|
||||
if (offset < char_len)
|
||||
result = (* func) (attrs, offset, 0, char_len, found_offset,
|
||||
@ -3734,7 +3749,7 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
|
||||
|
||||
current_line = real->line;
|
||||
next_line = _gtk_text_line_next_could_contain_tag (current_line,
|
||||
real->tree, tag);
|
||||
real->tree, tag);
|
||||
|
||||
while (_gtk_text_iter_forward_indexable_segment (iter))
|
||||
{
|
||||
@ -3756,8 +3771,8 @@ gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
|
||||
|
||||
current_line = real->line;
|
||||
next_line = _gtk_text_line_next_could_contain_tag (current_line,
|
||||
real->tree,
|
||||
tag);
|
||||
real->tree,
|
||||
tag);
|
||||
}
|
||||
|
||||
if (gtk_text_iter_toggles_tag (iter, tag))
|
||||
@ -5175,5 +5190,8 @@ _gtk_text_iter_check (const GtkTextIter *iter)
|
||||
g_error ("wrong char index was cached");
|
||||
}
|
||||
}
|
||||
|
||||
if (_gtk_text_line_is_last (real->line, real->tree))
|
||||
g_error ("Iterator was on last line (past the end iterator)");
|
||||
}
|
||||
|
||||
|
@ -578,13 +578,11 @@ gtk_text_layout_get_lines (GtkTextLayout *layout,
|
||||
/* -1 since bottom_y is one past */
|
||||
last_btree_line =
|
||||
_gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
|
||||
layout, bottom_y - 1, NULL);
|
||||
layout, bottom_y - 1, NULL);
|
||||
|
||||
if (!last_btree_line)
|
||||
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);
|
||||
_gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
|
||||
|
||||
g_assert (last_btree_line != NULL);
|
||||
|
||||
@ -596,7 +594,7 @@ gtk_text_layout_get_lines (GtkTextLayout *layout,
|
||||
if (line == last_btree_line)
|
||||
break;
|
||||
|
||||
line = _gtk_text_line_next (line);
|
||||
line = _gtk_text_line_next_excluding_last (line);
|
||||
}
|
||||
|
||||
retval = g_slist_reverse (retval);
|
||||
@ -722,7 +720,7 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout,
|
||||
if (line == last_line)
|
||||
break;
|
||||
|
||||
line = _gtk_text_line_next (line);
|
||||
line = _gtk_text_line_next_excluding_last (line);
|
||||
}
|
||||
|
||||
gtk_text_layout_invalidated (layout);
|
||||
@ -862,7 +860,7 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout,
|
||||
}
|
||||
|
||||
seen += line_data->height;
|
||||
line = _gtk_text_line_next (line);
|
||||
line = _gtk_text_line_next_excluding_last (line);
|
||||
}
|
||||
|
||||
/* If we found and validated any invalid lines, update size and
|
||||
@ -2005,6 +2003,9 @@ line_display_index_to_iter (GtkTextLayout *layout,
|
||||
gint index,
|
||||
gint trailing)
|
||||
{
|
||||
g_return_if_fail (!_gtk_text_line_is_last (display->line,
|
||||
_gtk_text_buffer_get_btree (layout->buffer)));
|
||||
|
||||
if (index >= display->insert_index + layout->preedit_len)
|
||||
index -= layout->preedit_len;
|
||||
else if (index > display->insert_index)
|
||||
@ -2066,8 +2067,8 @@ get_line_at_y (GtkTextLayout *layout,
|
||||
layout, y, line_top);
|
||||
if (*line == 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);
|
||||
*line = _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
|
||||
|
||||
if (line_top)
|
||||
*line_top =
|
||||
_gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
|
||||
@ -2306,9 +2307,8 @@ find_display_line_below (GtkTextLayout *layout,
|
||||
if (!line)
|
||||
{
|
||||
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);
|
||||
_gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
|
||||
|
||||
line_top =
|
||||
_gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
|
||||
line, layout);
|
||||
@ -2346,7 +2346,7 @@ find_display_line_below (GtkTextLayout *layout,
|
||||
line_top += display->bottom_margin;
|
||||
gtk_text_layout_free_line_display (layout, display);
|
||||
|
||||
next = _gtk_text_line_next (line);
|
||||
next = _gtk_text_line_next_excluding_last (line);
|
||||
if (!next)
|
||||
found_line = line;
|
||||
|
||||
@ -2374,8 +2374,8 @@ find_display_line_above (GtkTextLayout *layout,
|
||||
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 (_gtk_text_buffer_get_btree (layout->buffer),
|
||||
_gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
|
||||
line = _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
|
||||
|
||||
line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout);
|
||||
}
|
||||
|
||||
@ -2658,7 +2658,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
|
||||
|
||||
gtk_text_layout_free_line_display (layout, display);
|
||||
|
||||
line = _gtk_text_line_next (line);
|
||||
line = _gtk_text_line_next_excluding_last (line);
|
||||
}
|
||||
|
||||
return
|
||||
@ -2939,7 +2939,7 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
|
||||
}
|
||||
else if (new_index > byte_count)
|
||||
{
|
||||
line = _gtk_text_line_next (line);
|
||||
line = _gtk_text_line_next_excluding_last (line);
|
||||
if (!line)
|
||||
goto done;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "../gtk/gtktexttypes.h" /* Private header, for UNKNOWN_CHAR */
|
||||
@ -28,7 +29,8 @@ main (int argc, char** argv)
|
||||
int n;
|
||||
gunichar ch;
|
||||
GtkTextIter start, end;
|
||||
|
||||
gchar *text;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
/* Check UTF8 unknown char thing */
|
||||
@ -49,12 +51,34 @@ main (int argc, char** argv)
|
||||
g_error ("%d lines, expected 1", n);
|
||||
|
||||
n = gtk_text_buffer_get_char_count (buffer);
|
||||
if (n != 1)
|
||||
g_error ("%d chars, expected 1", n);
|
||||
if (n != 0)
|
||||
g_error ("%d chars, expected 0", n);
|
||||
|
||||
/* Run gruesome alien test suite on buffer */
|
||||
run_tests (buffer);
|
||||
|
||||
/* Check set/get text */
|
||||
gtk_text_buffer_set_text (buffer, "Hello", -1);
|
||||
if (gtk_text_buffer_get_char_count (buffer) != g_utf8_strlen ("Hello", -1))
|
||||
g_error ("Wrong number of chars (%d not %d)",
|
||||
gtk_text_buffer_get_char_count (buffer),
|
||||
(int) g_utf8_strlen ("Hello", -1));
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
|
||||
if (strcmp (text, "Hello") != 0)
|
||||
g_error ("Got '%s' as buffer contents", text);
|
||||
g_free (text);
|
||||
|
||||
gtk_text_buffer_set_text (buffer, "", -1);
|
||||
|
||||
n = gtk_text_buffer_get_line_count (buffer);
|
||||
if (n != 1)
|
||||
g_error ("%d lines, expected 1", n);
|
||||
|
||||
n = gtk_text_buffer_get_char_count (buffer);
|
||||
if (n != 0)
|
||||
g_error ("%d chars, expected 0", n);
|
||||
|
||||
/* Put stuff in the buffer */
|
||||
|
||||
fill_buffer (buffer);
|
||||
@ -73,8 +97,8 @@ main (int argc, char** argv)
|
||||
g_error ("%d lines, expected 1", n);
|
||||
|
||||
n = gtk_text_buffer_get_char_count (buffer);
|
||||
if (n != 1)
|
||||
g_error ("%d chars, expected 1", n);
|
||||
if (n != 0)
|
||||
g_error ("%d chars, expected 0", n);
|
||||
|
||||
run_tests (buffer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user