#include <gtk/gtk.h>
#include "gtkthreads.h"
#include <pthread.h>

#include <fcntl.h>

/* This mutex must be held when reading or modifying gtk_lock_state */
pthread_mutex_t gtk_lock_mutex = PTHREAD_MUTEX_INITIALIZER;

/* Used to make sure that the mainloop thread gives up the lock at
 * least once */
pthread_cond_t gtk_lock_cond = PTHREAD_COND_INITIALIZER;

/* Used to signal mainloop to release lock */
gint gtk_lock_pipe[2];

static void gtk_threads_callback (gpointer          data, 
				 gint              source,
				 GdkInputCondition condition);

void
gtk_threads_init (void)
{
  pipe (gtk_lock_pipe);
  fcntl (gtk_lock_pipe[0], F_SETFL, O_NONBLOCK);
  fcntl (gtk_lock_pipe[1], F_SETFL, O_NONBLOCK);

  gdk_input_add (gtk_lock_pipe[0], GDK_INPUT_READ, gtk_threads_callback, NULL);
}

void
gtk_threads_enter (void)
{
  char c;
  write(gtk_lock_pipe[1], "A", 1);
  pthread_mutex_lock (&gtk_lock_mutex);
  read (gtk_lock_pipe[0], &c, 1);
  pthread_cond_signal (&gtk_lock_cond);
}

void
gtk_threads_leave (void)
{
  pthread_mutex_unlock (&gtk_lock_mutex);
}

void
gtk_threads_enter_main (void)
{
  pthread_mutex_lock (&gtk_lock_mutex);
}

void
gtk_threads_leave_main (void)
{
  pthread_mutex_unlock (&gtk_lock_mutex);
}

void
gtk_threads_main (void)
{
  gtk_threads_enter_main();
  gtk_main();
  gtk_threads_leave_main ();
}

static void 
gtk_threads_callback (gpointer          data, 
		     gint              source,
		     GdkInputCondition condition)
{
  pthread_cond_wait (&gtk_lock_cond, &gtk_lock_mutex);
}

