3
votes

I want to display the current situation on a simulated battlefield using Cairo on GTK+ window. My application has to use provided framework which operates in its own main loop. So, I can not call gtk_main in the main thread and have to launch GTK+ main runloop in separate thread:

...
g_thread_init(NULL);
g_thread_create(gui_main_loop, data, FALSE, NULL);
...

...
gpointer gui_main_loop(gpointer data)
{
...
    gdk_threads_init();
    gdk_threads_enter();
...
    // Here I make my cute UI
...
    gtk_main();
    gdk_threads_leave();
...
}
...

I've attached a handler to the "draw" event of my drawing area:

...
gboolean rendering(GtkWidget *widget, cairo_t *c, gpointer data)
{
    // Here I render my UI using cairo.
    return TRUE;
}
...
// I call this function before gtk_main
g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(rendering), data);
...

So, my GTK+ window lives in another thread and is redrawn each time I resize the window. But I need to update it several times a second in order to monitor the current situation on the battlefield. On every iteration I call the invalidate function from my main thread:

...
gdk_window_invalidate_rect(gtk_widget_get_window(drawing_area), NULL, true);
...

But in several seconds the UI freezes. It reacts on window resizes but ignores gdk_window_invalidate_rect calls. What am I doing wrong?

1

1 Answers

0
votes

Have you tried adding gdk_threads_enter/gdk_threads_leave around your gdk_window_invalidate_rect call ?

You'd also better use gtk_widget_queue_draw instead of gdk_window_invalidate_rect. But keep in mind that you need to make sure you "rendering" callback draws fast enough. You should measure that. Using clipping in cairo or using gtk_widget_queue_draw_area instead of gtk_widget_queue_draw will help with performance if you don't need to redraw the full image each time.