Hey, just thought I'd post this so other people can find it if they run into the same/similar issues. Anything to help me understand this a bit better is much appreciated.
I was using the "mark-set" signal for GtkTextBuffer (of a GtkSourceBuffer) to display the current line and column of the GtkSourceView widget. The code I was trying to use was:
Code:
void
on_mark_set (GtkTextBuffer *textbuffer, GtkTextIter *arg1, GtkTextMark *arg2, gpointer user_data)
{
Document *d = (Document*)user_data;
update_statusbar (d);
}
void
update_statusbar (Document *current_document)
{
gint column;
gint line;
GtkTextMark *mark = NULL;
GtkTextIter iter;
/* get iter at the insertion point */
mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (current_document->buffer));
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (current_document->buffer),
&iter, mark);
/* get current line */
line = gtk_text_iter_get_line (&iter) + 1;
/* get current column */
column = gtk_text_iter_get_line_offset (&iter) + 1;
/* ... update statusbar here */
}
This
seemed to work at first. However, if you type too fast (such as mashing a bunch of keys at once or hitting two keys in rapid succession) I'd get a nice crash:
Code:
Gtk-WARNING **: Invalid text buffer iterator: either the iterator is uninitialized, or the characters/pixbufs/widgets in the buffer have been modified since the iterator was created.
You must use marks, character numbers, or line numbers to preserve a position across buffer modifications.
You can apply tags and insert marks without invalidating your iterators,
but any mutation that affects 'indexable' buffer contents (contents that can be referred to by character offset)
will invalidate all outstanding iterators
Gtk-CRITICAL **: gtk_text_buffer_get_iter_at_mark: assertion `GTK_IS_TEXT_MARK (mark)' failed
So, I figured that the update_statusbar function was being multi-threaded? Calls using "iter" and/or "mark" were crashing because another instance of the function had changed them... or the mark had changed in the widget? Still trying to understand this better. But in any case, I figured I needed a way to update the status bar ONLY if the user had stopped typing long enough to update the statusbar without them typing and thus updating the statusbar again.
This is the part I'm "ify" on as I'm still not a seasoned pro with all this GTK+ stuff (Not until I get
Foundations of GTK+ Development anyway). Don't know if my assumptions as to why I encountered this problem are correct.
I got it working using g_idle_add as shown below:
Code:
void
on_mark_set (GtkTextBuffer *textbuffer, GtkTextIter *arg1, GtkTextMark *arg2, gpointer user_data)
{
Document *d = (Document*)user_data;
static guint idle_id;
if (idle_id != 0)
{
g_source_remove (idle_id);
idle_id = 0;
}
idle_id = g_idle_add((GSourceFunc)update_statusbar, d);
}
gboolean
update_statusbar (Document *current_document)
{
gint column;
gint line;
GtkTextMark *mark = NULL;
GtkTextIter iter;
gdk_threads_enter ();
/* get iter at the insertion point */
mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (current_document->buffer));
gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (current_document->buffer),
&iter, mark);
/* get current line */
line = gtk_text_iter_get_line (&iter) + 1;
/* get current column */
column = gtk_text_iter_get_line_offset (&iter) + 1;
gdk_threads_leave ();
/* ... update statusbar here */
return FALSE; /* remove idle */
}