#include<glib.h>
#include<gtk/gtk.h>


typedef struct
{
  GThreadFunc func;
  gpointer data;
  GMutex *mutex;
  GCond *cond;
  gboolean done;
  gpointer retval;
} GdkThreadCallback;

static gboolean
dispatch (gpointer data)
{
  GdkThreadCallback *cb = data;

  gdk_threads_enter ();
  if (!g_source_is_destroyed (g_main_get_current_source ()))
    cb->retval = cb->func (cb->data);
  gdk_threads_leave ();

  g_mutex_lock (cb->mutex);
  cb->done = TRUE;
  g_cond_signal (cb->cond);
  g_mutex_unlock (cb->mutex);

  return FALSE;
}

gpointer 
gdk_threads_call_func (GThreadFunc func, gpointer data)
{
  gpointer ret;

  if (g_thread_self () != gdk_main_thread ())
    {
      GdkThreadCallback cb;

      cb.func = func;
      cb.data = data;
      cb.mutex = g_mutex_new ();
      cb.cond = g_cond_new ();
      cb.done = FALSE;
      cb.retval = NULL;

      g_idle_add (dispatch, &cb);

      gdk_threads_leave ();
      g_mutex_lock (cb.mutex);
      while (!cb.done)
	g_cond_wait (cb.cond, cb.mutex);
      ret = cb.retval;
      g_mutex_unlock (cb.mutex);
      gdk_threads_enter ();

      g_mutex_free (cb.mutex);
      g_cond_free (cb.cond);
    }
  else
    ret = func (data);

  return ret;
}
