GTK textview text tag extended to end of file

[I updated this post to make it *slightly* easier to read.]

Hi, my app uses textview and text tags and native serialization to save to a file.

Here is the starting situation:

  • multiple text lines in a textview window
  • the first line has blue text and bold weight tags applied
  • the second line has blue text and orange background tags applied
  • subsequent lines have no tags applied

I place the cursor at the end of the first line and press the Delete key to join the lines, then save the file and re-open. The first (joined) line looks right, but all subsequent lines, to end of file, now have orange-background tag applied.

(If you change the order of tag creation and thus the tag priorities, the problem may not happen. But I don’t see why the serialization should ever extend a tag to EOF when the tag was never applied to that text.

If you want to see the problem, please compile the C code below and then run it – it will open a window with a textview instance containing some canned tagged text followed by untagged text. At the bottom of the window is a Save/Exit button.

Don’t make any edits in the window yet. Click Save/Exit to save the current contents to a file (myfile.gtk in the current directory). Have a look at myfile.gtk with cat or less. You should see:

GTKTEXTBUFFERCONTENTS-0001[size field] <text_view_markup>
 <tags>
  <tag name="orange-hiliter" priority="2">
   <attr name="background-gdk" type="GdkColor" value="ffff:a5a5:0" />
  </tag>
  <tag name="bold" priority="1">
   <attr name="weight" type="gint" value="700" />
  </tag>
  <tag name="blue-ink" priority="0">
   <attr name="foreground-gdk" type="GdkColor" value="0:0:ffff" />
  </tag>
 </tags>
<text><apply_tag name="bold"><apply_tag name="blue-ink">Bold blue text</apply_tag></apply_tag>
<apply_tag name="orange-hiliter"><apply_tag name="blue-ink">Blue text in orange</apply_tag></apply_tag>

Misc. text hi there.
More. text etc etc..
Even more. text etc etc..</text>
</text_view_markup>

which is fine. Now start the app again – it will see that myfile.gtk exists and read that into the buffer (instead of the canned text). Now put the cursor at the end of the first line and press the Delete key on the keyboard, to join the 1st and 2nd lines. Then click Save/Exit again and have a look at the file:

GTKTEXTBUFFERCONTENTS-0001[size field] <text_view_markup>
 <tags>
  <tag name="blue-ink" priority="0">
   <attr name="foreground-gdk" type="GdkColor" value="0:0:ffff" />
  </tag>
  <tag name="orange-hiliter" priority="2">
   <attr name="background-gdk" type="GdkColor" value="ffff:a5a5:0" />
  </tag>
  <tag name="bold" priority="1">
   <attr name="weight" type="gint" value="700" />
  </tag>
 </tags>
<text><apply_tag name="bold"><apply_tag name="blue-ink">Bold blue text</apply_tag></apply_tag><apply_tag name="blue-ink"><apply_tag name="orange-hiliter">Blue text in orange</apply_tag></apply_tag><apply_tag name="orange-hiliter">

Misc. text hi there.
More. text etc etc..
Even more. text etc etc..</apply_tag></text>
</text_view_markup>

You can see the orange-hiliter tag has been extended to EOF. Run the app again and you see that the 2nd and subsequent lines, which were never tagged, now are have orange-background tag applied.

Does anyone know why this happens? I can’t figure out how to re-assign tag priorities to prevent this problem in every case.

Here is the makefile and C code.

makefile:

CFLAGS = `pkg-config --cflags gtk+-3.0`
OBJECTS = tag-test.o 
default: tag-test
%.o: %.c
     gcc $(CFLAGS) -c $<
tag-test: $(OBJECTS)
     gcc $(CFLAGS) $(OBJECTS) `pkg-config --libs gtk+-3.0` -o $@

And tag-test.c:

#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>

void save_file(void);
GtkTextBuffer *buffer;
GtkWidget *window;
GtkWidget *text_view1;

   int 
main (int argc, char *argv[]) {
    GtkTextIter iter, start, end;
    gsize len;
    struct stat fstat;
    GdkAtom de_format;
    GtkWidget *grid, *save_button;
    guint8 fdata[15000];
    GError *err;
    FILE *fp;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Textview");
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 600);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    text_view1 = gtk_text_view_new();
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view1), GTK_WRAP_CHAR);
    gtk_widget_set_vexpand(text_view1, TRUE);
    gtk_widget_set_hexpand(text_view1, TRUE);

    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view1));


    gtk_text_buffer_create_tag(buffer, "blue-ink", "foreground", "blue", NULL);
    gtk_text_buffer_create_tag(buffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);
    gtk_text_buffer_create_tag(buffer, "orange-hiliter", "background", "orange", NULL);


    grid = gtk_grid_new();
    gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
    gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
    gtk_grid_attach(GTK_GRID(grid), text_view1, 0, 0, 1, 1);

    save_button = gtk_toggle_button_new_with_label("Save/Exit");
    gtk_grid_attach(GTK_GRID(grid), save_button, 0, 1, 1, 1);
    g_signal_connect(save_button, "clicked", G_CALLBACK(save_file), text_view1);
    
    gtk_container_add(GTK_CONTAINER(window), grid);

    gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);

    if (stat("myfile.gtk", &fstat) == 0)  {  // file exists, read it
        len = fstat.st_size;
        fp = fopen("myfile.gtk", "r");
        fread(fdata, 1, len, fp);
        fclose(fp);
        de_format = gtk_text_buffer_register_deserialize_tagset(buffer, "default");
        gtk_text_buffer_deserialize_set_can_create_tags(buffer, de_format, FALSE);
        gtk_text_buffer_deserialize(buffer, buffer, de_format, &iter, fdata, len, &err);
    }
    else  {     //  create new contents
        gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 
                    "Bold blue text", -1, "blue-ink", "bold", NULL);
        gtk_text_buffer_insert(buffer, &iter, "\n", 1);
        gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 
                    "Blue text in orange", -1, "blue-ink", "orange-hiliter", NULL);
        gtk_text_buffer_insert(buffer, &iter, "\n", 1);
        gtk_text_buffer_insert(buffer, &iter, "\nMisc. text hi there.", -1);
        gtk_text_buffer_insert(buffer, &iter, "\nMore. text etc etc..", -1);
        gtk_text_buffer_insert(buffer, &iter, "\nEven more. text etc etc..", -1);
    }


    gtk_widget_show_all(window);

    g_signal_connect_after(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_main();

    return 0;
}

    void
save_file(void) {       
    GtkTextIter iter, start, end;
    gsize len;
    struct stat fstat;
    GdkAtom se_format;
    FILE *fp;
    guint8 *serialized;

    se_format = gtk_text_buffer_register_serialize_tagset(buffer, "default" );
    gtk_text_buffer_get_bounds(buffer, &start, &end);
    serialized = gtk_text_buffer_serialize(buffer, buffer, se_format, 
                    &start, &end, &len);
    fp = fopen("myfile.gtk", "w");
    fwrite(serialized, 1, len, fp);
    fclose(fp);
    gtk_main_quit();
}

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.