This is a bare bones save_as()
function:
gint save_as(GtkWidget *parent, struct buffers B)
{
GtkWidget *file_chooser = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(parent), GTK_FILE_CHOOSER_ACTION_SAVE, "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_OK, NULL);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), "Untitled");
gint response = gtk_dialog_run(GTK_DIALOG(file_chooser));
switch(response)
{
case GTK_RESPONSE_OK:
GFile *file = g_file_new_for_path(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser)));
GtkTextIter *start;
gtk_text_buffer_get_start(B.buffer0, &start);
GtkTextIter *end;
gtk_text_buffer_get_end(B.buffer0, &end);
// program abnormally terminates on the following line
gchar *contents = gtk_text_buffer_get_text(B.buffer0, &start, &end, FALSE);
g_file_replace_contents(file, contents, strlen(contents), NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, NULL);
g_free(contents);
gtk_widget_destroy(file_chooser);
return GTK_RESPONSE_OK;
break;
case GTK_RESPONSE_CANCEL:
gtk_widget_destroy(file_chooser);
return GTK_RESPONSE_CANCEL;
}
// user pressed X
gtk_widget_destroy(file_chooser);
return GTK_RESPONSE_CANCEL;
}
This is pretty much all we need to diagnose and fix the problem.
Here is the full message I get when I try to click on File -> Save As... and then on Save:
(test:4478): Gtk-WARNING **: 11:56:20.184: 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
(test:4478): Gtk-CRITICAL **: 11:56:20.184: gtk_text_buffer_get_text: assertion 'gtk_text_iter_get_buffer (start) == buffer' failed
Segmentation fault (core dumped)
For some reason, it seems that the iterators start
and end
do not belong to B.buffer0
. Apart from GTK+3 documentation, I also followed answers to this question as a guide.
Why is this happening and how it can be fixed?
I also tried changing the following lines:
gtk_text_buffer_get_start_iter(B.buffer0, &start);
to gtk_text_buffer_get_start_iter(B.buffer0, start);
gtk_text_buffer_get_start_iter(B.buffer0, &end);
to gtk_text_buffer_get_start_iter(B.buffer0, end);
gchar *contents = gtk_text_buffer_get_text(B.buffer0, &start, &end, FALSE);
to gchar *contents = gtk_text_buffer_get_text(B.buffer0, start, end, FALSE);
The only error I get is:
Segmentation fault (core dumped)
This is also supposed to be the correct way to send arguments according to the documentation.
Also, I tried replacing contents = gtk_text_buffer_get_text(B.buffer0, start, end, FALSE);
with contents = gtk_text_iter_get_text(start, end);
but I get the same error.
I also noticed that I get two warnings during compiling after applying those changes:
src/save.c:96:5: warning: ‘start’ may be used uninitialized in this function [-Wmaybe-uninitialized]
gtk_text_buffer_get_start_iter(B.buffer0, start);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/save.c:98:5: warning: ‘end’ may be used uninitialized in this function [-Wmaybe-uninitialized]
gtk_text_buffer_get_end_iter(B.buffer0, end);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This obviously means that gtk_text_buffer_get_start/end_iter()
fails to associate start
and end
with B.buffer0
, but why? It says that start
and end
are passed uninitialized, but isn't that normal since I'm initializing them now? Or I should do something before that?
Definition of struct buffer is in a file called
buffer.h
. Here it is (not the whole file, just the struct definition):
struct buffers
{
GtkTextBuffer *buffer0;
GtkTextBuffer *buffer1;
GtkTextBuffer *buffer2;
};
The instance I use is:
struct buffers Buffer;
This is a global variable, so buffer.h
is included in every file that uses Buffer
. And for the same purpose (globality), of course it is declared extern struct buffers Buffer;
in the header file associated with the source file in which it is defined.
This buffer is passed to a function save_as()
like this:
gint response = save_as(main_window, Buffer);
In case you're wondering why I just don't use global variable instead of passing it as a parameter, it is because I can just pass any variable of type struct buffers
to a save_file()
and let it do the job, instead of having another function for each struct buffers
variable.
I tried initializing iterators upon their definition:
GtkTextIter *start = NULL;
GtkTextIter *end = NULL;
Everything compiles without any warnings. Unfortunately, this doesn't solve the problem. Upon clicking File -> Save As and then Save, the program exits and I get messages:
(test:4081): Gtk-CRITICAL **: 19:48:29.843: gtk_text_buffer_get_start_iter: assertion 'iter != NULL' failed
(test:4081): Gtk-CRITICAL **: 19:48:29.844: gtk_text_buffer_get_end_iter: assertion 'iter != NULL' failed
(test:4081): Gtk-CRITICAL **: 19:48:29.844: gtk_text_buffer_get_text: assertion 'start != NULL' failed
Why is it even important that my start
and end
iterators are NULL
at least in the first two cases? Aren't those two functions supposed to set start
and end
iterators to the start and the end of a file, respectively? Therefore, why does it matter to what iterators are set prior to that?