Rendering in a worker thread
- From: "Marc DELDEM" <marc deldem gmail com>
- To: gtk-list gnome org
- Subject: Rendering in a worker thread
- Date: Mon, 14 Apr 2008 22:59:39 +0200
Hi,
I'm new to GTK. I want to do some complex rendering in a worker thread. I've done a basic sample but I've got a problem on the refresh of the window.
The rendering thread draws and fills a polygon in a pixmap, then copies the pixmap content into a drawing area. After a complete loop, the rendering thread sleeps during 1 second and do a new loop. At each loop, the color used to fill the polygon is changed.
At the first time, the polygon is drawn in red. In the next loop, the color used is blue and in the next loop, red color is used again, and so one.
The problem I've in my sample is that in the first rendering loop, the polygon is not always drawn in red.
I suppose I've not correctly understand the way to require a refresh when the rendering is done in a worker thread and not from the main thread.
Here is my code sample :
#include <string.h>
#include <unistd.h>
#include <gtk/gtk.h>
// Handlers
static gboolean s_boDestroy();
static gboolean s_boConfigureEvent(GtkWidget* pWidget, GdkEventConfigure* pEvent);
static gboolean s_boExposeEvent(GtkWidget* pArea, GdkEventExpose* pEvent);
// Thread
static void* s_pRendererThread(void* pArgs);
typedef struct
{
GtkWidget* pWidget;
GdkPixmap* pPixmap;
int nWidth;
int nHeight;
} ThreadArgs;
// Static Variables
static GdkPixmap* s_pPixmap = NULL;
static gboolean s_boInitialConfig = false;
static ThreadArgs s_ThreadArgs;
int main(int argc, char** argv)
{
// Init
memset(&s_ThreadArgs, 0, sizeof(ThreadArgs));
s_ThreadArgs.nWidth = 240;
s_ThreadArgs.nHeight = 320;
// Init threads
g_thread_init(NULL);
gdk_threads_init();
// Init GTK
gtk_init(&argc, &argv);
// Main Window
GtkWidget* pMainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(pMainWindow), "destroy", G_CALLBACK(s_boDestroy), NULL);
gtk_window_set_title(GTK_WINDOW(pMainWindow), "renderer_thread");
gtk_widget_set_size_request(pMainWindow, 240, 320);
// Drawing Area
GtkWidget* pDrawingArea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(pMainWindow), pDrawingArea);
g_signal_connect(G_OBJECT(pDrawingArea), "configure_event", G_CALLBACK(s_boConfigureEvent), NULL);
g_signal_connect(G_OBJECT(pDrawingArea), "expose_event", G_CALLBACK(s_boExposeEvent), NULL);
// Display the widgets
gtk_widget_show_all(pMainWindow);
// Enter main loop
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
return 0;
}
static gboolean s_boDestroy()
{
gtk_main_quit();
return TRUE;
}
static gboolean s_boConfigureEvent(GtkWidget* pWidget, GdkEventConfigure* pEvent)
{
if(s_boInitialConfig == false)
{
s_boInitialConfig = true;
int nWidth = 240;
int nHeight = 320;
// Create the Pixmap
s_pPixmap = gdk_pixmap_new(pWidget->window, nWidth, nHeight, -1);
// Update Thread Args
s_ThreadArgs.nWidth = nWidth;
s_ThreadArgs.nHeight = nHeight;
s_ThreadArgs.pWidget = pWidget;
s_ThreadArgs.pPixmap = s_pPixmap;
// Clear pixmap with white brush
gboolean boFilled = TRUE;
gdk_draw_rectangle(
s_pPixmap,
pWidget->style->white_gc,
boFilled,
0, 0,
pWidget->allocation.width, pWidget->allocation.height
);
// Create the thread
GError* pError = NULL;
g_thread_create(s_pRendererThread, &s_ThreadArgs, FALSE, &pError);
}
return TRUE;
}
static gboolean s_boExposeEvent(GtkWidget* pWidget, GdkEventExpose* pEvent)
{
return TRUE;
}
static void* s_pRendererThread(void* pArgs)
{
ThreadArgs* pThreadArgs = static_cast<ThreadArgs*>(pArgs);
int nXMin = 5;
int nXMax = pThreadArgs->nWidth-nXMin;
int nYMin = 5;
int nYMax = pThreadArgs->nHeight-nYMin;
GdkPoint Points[4];
Points[0].x = nXMin; Points[0].y = nYMin;
Points[1].x = nXMax; Points[1].y = nYMin;
Points[2].x = nXMax; Points[2].y = nYMax;
Points[3].x = nXMin; Points[3].y = nYMax;
GdkColor RedColor, BlueColor;
memset(&RedColor, 0, sizeof(GdkColor));
RedColor.red = 0xFFFF;
memset(&BlueColor, 0, sizeof(GdkColor));
BlueColor.blue = 0xFFFF;
int nStep = 0;
gboolean boFilled = TRUE;
GdkColor* pCurrentColor = &RedColor;
GtkWidget* pWidget = pThreadArgs->pWidget;
GdkPixmap* pPixmap = pThreadArgs->pPixmap;
GdkGC* pGC = gdk_gc_new(pPixmap);
for(;;)
{
gdk_threads_enter();
// Select current color (Red or Blue)
pCurrentColor = ((nStep++%2)==0 ? &RedColor : &BlueColor);
gdk_gc_set_rgb_fg_color(pGC, pCurrentColor);
// Draw polygon onto pixmap
gdk_draw_polygon(pPixmap, pGC, boFilled, Points, 4);
// Copy pixmap onto widget
gdk_draw_drawable(
pWidget->window,
pWidget->style->fg_gc[GTK_WIDGET_STATE(pWidget)],
pPixmap,
0, 0,
0, 0,
-1, -1
);
gdk_flush();
gdk_threads_leave();
sleep(1);
}
return NULL;
}
Thanks for any help.
Regards,
Marc Deldem
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]