Re: Real Time Drawing



Hi,

On Tue, 15 Mar 2005 09:57:24 +0000, Athanasios Anastasiou
<thanos atmail com> wrote:
Also could it be better that i add an expose_event handler to the widget
i want to draw and just post invalidate messages towards the widget from
the thread?

I  do something similar in my app. I have a structure like this:

- realtime thread runs and produces a packet of data every 20ms

- it posts a pointer to the packet into a GAsyncQueue

- the GAsyncQueue is connected to my GUI app (magic code 
  below) ... a callback is triggered for each data item that arrives
  on the queue

- the callback uses the packet of data to update the app's model,
  calculates what parts of the screen will be affected, invalidates
  those widgets / parts of widgets, and frees the packet

- the "expose" handler is called at some later point and draws the
  current state of the model to the screen

This maybe sounds complicated, but it's not that much code. You're
guaranteed not to drop any packets, and the screen repaints can never
fall behind the updates. If the system becomes heavily loaded, you'll
just see a lower FPS for screen painting. Plus all your GUI code is
single-threaded, much simpler!

I used to use pipes for this, but I had problems getting the thing
working on the win32 version of GTK. The AsyncQueue code comes from a
very helpful post by Paul Pogonyshev last year. I've pasted it below
to save you searching the archives (hope no one minds).

Finally, you asked about books on GTK. The most up to date one I know
is the GNOME2 developer's guide. It has a long and rather good section
on GTK/GObject/GLib etc:

http://www.amazon.com/exec/obidos/tg/detail/-/1593270305/102-1804772-0460922

http://www.nostarch.com/frameset.php?startat=gnome

---------- Forwarded message ----------
From: Paul Pogonyshev
Date: Wed, 14 Jul 2004 16:27:22 +0300
Subject: Re: Proper way to provide gtk+ app with asynchronous data?
To: gtk-app-devel-list gnome org

Russell Shaw wrote:
I'm trying to figure out how to wake up the main gtk gui thread when
new data is available in a GAsyncQueue (command_queue), so that i can
display the data in a gtk widget:

Here is an excerpt from Quarry (http://home.gna.org/quarry/) that
does exactly what you described.

The larger part of code below is the main thread's code that deals
with incoming "messages".  To send some data from another thread,
just do something like this:

 event_data = g_malloc(sizeof(ThreadEventData));
 event_data->callback = some_callback;
 event_data->data     = some_result_of_long_computation;

 g_async_queue_push(thread_events_queue, event_data);
 g_main_context_wakeup(NULL);

Then `some_callback' will be invoked in main thread's context with
`some_result_of_long_computation' pointer as argument.  Depending
on the implicit "message" you send, the callback should or should
not g_free() its argument (if you send messages only when a thread
terminates, then it certainly should free).

Paul

typedef void (* ThreadEventCallback) (void *result);

typedef struct _ThreadEventData ThreadEventData;

struct _ThreadEventData {
 ThreadEventCallback   callback;
 void                 *result;
};

static GSourceFuncs thread_events_functions = {
 thread_events_prepare,
 thread_events_check,
 thread_events_dispatch,
 NULL,
};

static GSource  *thread_events;
GAsyncQueue     *thread_events_queue;

static gboolean
thread_event_callback(gpointer data)
{
 ThreadEventData *thread_completion_data = (ThreadEventData *) data;

 thread_completion_data->callback(thread_completion_data->result);

 return TRUE;
}

static gboolean
thread_events_prepare(GSource *source, gint *timeout)
{
 UNUSED(source);

 *timeout = -1;
 return g_async_queue_length(thread_events_queue) > 0;
}

static gboolean
thread_events_check(GSource *source)
{
 UNUSED(source);

 return g_async_queue_length(thread_events_queue) > 0;
}

static gboolean
thread_events_dispatch(GSource *source, GSourceFunc callback,
                      gpointer user_data)
{
 gpointer data = g_async_queue_pop(thread_events_queue);
 gboolean result = callback(data);

 UNUSED(source);
 UNUSED(user_data);

 g_free(data);

 return result;
}

 /* Somewhere before gtk_main() call. */

 thread_events_queue = g_async_queue_new();

 thread_events = g_source_new(&thread_events_functions, sizeof(GSource));
 g_source_set_callback(thread_events, thread_event_callback, NULL, NULL);
 g_source_attach(thread_events, NULL);

 ...

 gtk_main();

 ...

 /* And somewhere after it destroy the queue. */

 g_source_destroy(thread_events);
 g_async_queue_unref(thread_events_queue);

--------



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