Re: Proper way to provide gtk+ app with asynchronous data?



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]