GTK and threads



Hi,

I'm currently having a problem in a application where I try to update a 
GtkListStore from a thread. When calling gtk_list_store_set I often get error 
messages that repeat

Gtk-CRITICAL **: gtk_tree_model_sort_get_value: 
     assertion `VALID_ITER (iter, tree_model_sort)' failed 
GLib-GObject-CRITICAL **: g_object_set_property: 
     assertion `G_IS_VALUE (value)' failed 
GLib-GObject-CRITICAL **: g_value_unset: 
     assertion `G_IS_VALUE (value)' failed 
   
and end with

Gtk-CRITICAL **: file /build/buildd/gtk+2.0-2.12.9/gtk/gtktreeview.c: 
    line 6154 (do_validate_rows): 
    assertion `gtk_tree_model_iter_next (tree_view->priv->model, &iter)'     
    failed. 
There is a disparity between the internal view of the GtkTreeView, 
and the GtkTreeModel.  This generally means that the model has changed 
without letting the view know.  Any display from now on is likely to 
be incorrect.

In worst case it all ends with a segmentation fault. 
Below you'll find a sample application that allows to update a list store via 
a thread or directly. Given enough columns and rows in the model the updating 
through a thread always results in a segmentation fault but the direct update 
seems to work without problems. At least on my system.
Is this behavior normal to GTK+? I know in Java/Swing and .NET/Windows Forms 
manipulation of GUI widgets has to be done in a special thread. Is there a 
similar concept in GTK+? Or maybe something is wrong with my code?

I'm using GTK+ 2.12.9 on Ubuntu 8.04.

Thanks in advance
Bernhard

#include <gtk/gtk.h>

enum {
    COLUMN_1_INT = 0,
    COLUMN_2_STRING,
    COLUMN_3_STRING,
    COLUMN_4_STRING,
    COLUMN_5_STRING,
    COLUMN_6_STRING,
    COLUMN_7_STRING,
    COLUMN_8_STRING,
    COLUMN_9_STRING,
    COLUMN_10_STRING,
    NO_OF_COLUMNS
};

static int counter = 0;
static GtkListStore *store;

static gpointer update_store ( gpointer user_data )
{
    int i;
    GtkTreeIter iter;
    
    gtk_list_store_clear ( store );
    
    ++counter;
    
    for ( i = 0; i < 3000 ; ++i )
    {
        gtk_list_store_append ( store, &iter );
        
        gtk_list_store_set ( store, &iter, 
                            COLUMN_1_INT, counter,
                            COLUMN_2_STRING, "column 2",
                            COLUMN_3_STRING, "column 3",
                            COLUMN_4_STRING, "column 4",
                            COLUMN_5_STRING, "column 5",
                            COLUMN_6_STRING, "column 6",
                            COLUMN_7_STRING, "column 7",
                            COLUMN_8_STRING, "column 8",
                            COLUMN_9_STRING, "column 9",
                            COLUMN_10_STRING, "column 10",
                            -1 );
    }
    
    return NULL;
}

static void tree_view_setup_column ( GtkTreeView *tree_view, int columnIndex )
{
    GtkTreeViewColumn *column = gtk_tree_view_column_new ();

    GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();

    gtk_tree_view_column_pack_start ( column, renderer, FALSE );

    gtk_tree_view_column_add_attribute ( column, renderer, "text", 
columnIndex);

    gtk_tree_view_append_column ( tree_view, column );
    
}

gboolean on_direct_clicked ( GtkToolButton *button, gpointer user_data )
{
    update_store ( NULL );
    
    return FALSE;
}

gboolean on_thread_clicked ( GtkToolButton *button, gpointer user_data )
{
    g_thread_create ( update_store, NULL, FALSE, NULL );
    
    return FALSE;
}

int main (int argc, char *argv[])
{
    int i;
    GtkWidget *window;
    GtkScrolledWindow *scrolled_w;
    GtkTreeView *tree_view;
    GtkBox *hbox;
    GtkToolbar *toolbar;
    GtkToolItem *button;
    
    gtk_init (&argc, &argv);
    
    g_thread_init ( NULL );

    hbox = GTK_BOX( gtk_vbox_new ( FALSE, 5 ) );
    
    toolbar = GTK_TOOLBAR( gtk_toolbar_new() );
    
    button = gtk_tool_button_new ( NULL, "direct" );
    
    g_signal_connect( button, "clicked", G_CALLBACK(on_direct_clicked),NULL );
    
    gtk_toolbar_insert ( toolbar, button, -1 );
    
    button = gtk_tool_button_new ( NULL, "thread" );
    
    g_signal_connect( button, "clicked", G_CALLBACK(on_thread_clicked),NULL );
    
    gtk_toolbar_insert ( toolbar, button, -1 );
    
    gtk_box_pack_start ( hbox, GTK_WIDGET( toolbar ), FALSE, TRUE, 0 );
    
    tree_view = GTK_TREE_VIEW( gtk_tree_view_new () );

    for ( i = 0 ; i < NO_OF_COLUMNS ; ++i )
        tree_view_setup_column ( tree_view, i );
    
    store = gtk_list_store_new ( NO_OF_COLUMNS, 
                                G_TYPE_INT,    // COLUMN_1_INT
                                G_TYPE_STRING, // COLUMN_2_STRING
                                G_TYPE_STRING, // COLUMN_3_STRING
                                G_TYPE_STRING, // COLUMN_4_STRING
                                G_TYPE_STRING, // COLUMN_5_STRING
                                G_TYPE_STRING, // COLUMN_6_STRING
                                G_TYPE_STRING, // COLUMN_7_STRING
                                G_TYPE_STRING, // COLUMN_8_STRING
                                G_TYPE_STRING, // COLUMN_9_STRING
                                G_TYPE_STRING  // COLUMN_10_STRING
                                );

    update_store ( NULL );
    
    gtk_tree_view_set_model ( tree_view, GTK_TREE_MODEL( store ) );

    scrolled_w = GTK_SCROLLED_WINDOW( gtk_scrolled_window_new( NULL, NULL ) );
    
    gtk_scrolled_window_add_with_viewport( scrolled_w, GTK_WIDGET(tree_view));
    
    gtk_box_pack_start ( hbox, GTK_WIDGET( scrolled_w ), TRUE, TRUE, 0 );
    
    window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    
    g_signal_connect ( window, "destroy", gtk_main_quit, NULL );
    
    gtk_container_add ( GTK_CONTAINER( window ), GTK_WIDGET( hbox ) );
    
    gtk_window_set_default_size ( GTK_WINDOW( window ), 640, 480 );
    
    gtk_widget_show_all ( window );

    gtk_main ();
    
    return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]