/*
 * This is a very simple sample program for GTK+ for Win32 to cause deadlock.
 * (If gtk_text_insert() is called from "worker thread", program is deadlocked.)
 *
 * gcc -g `gtk-config --cflags --libs gtk gthread` textins.c
 */

#include <stdio.h>
#include <gtk/gtk.h>
#include <pthread.h>

#define	COUNT_MAX	1000

#if	((GLIB_MAJOR_VERSION == 1) && (GLIB_MINOR_VERSION < 3))
#define g_usleep(time)	usleep(time)
#endif  /* GLIB_VERSION <= 1.2  */

pthread_t	t1 = (pthread_t)NULL;
int		count;
int		thread_stop_flag = 0;

void		create_window(void);
void		cb_start(GtkWidget*, gpointer);
void		cb_stop(GtkWidget*, gpointer);
void		*insert_thread(void*);

void	create_window()
{
  GtkWidget	*window;
  GtkWidget	*swindow;
  GtkWidget	*vbox;
  GtkWidget	*hbox;
  GtkWidget	*button;
  GtkWidget	*text;

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect(GTK_OBJECT(window), "delete_event",
		     GTK_SIGNAL_FUNC (gtk_false),
		     (gpointer)window);
  gtk_signal_connect(GTK_OBJECT(window), "destroy",
		     GTK_SIGNAL_FUNC(gtk_main_quit),
		     NULL);
  gtk_window_set_title(GTK_WINDOW(window), "pthread test.");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_widget_show(vbox);

  swindow = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow),
				 GTK_POLICY_AUTOMATIC,
				 GTK_POLICY_AUTOMATIC);
  gtk_widget_show(swindow);

  text = gtk_text_new(NULL, NULL);

  gtk_container_add(GTK_CONTAINER(swindow), text);
  gtk_box_pack_start(GTK_BOX(vbox), swindow, TRUE, TRUE, 0);
  gtk_widget_show(text);

  hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show(hbox);

  button = gtk_button_new_with_label("START");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     GTK_SIGNAL_FUNC(cb_start),
		     text);
  gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
  gtk_widget_show(button);

  button = gtk_button_new_with_label("STOP");
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
		     GTK_SIGNAL_FUNC(cb_stop),
		     text);
  gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
  gtk_widget_show(button);

  gtk_widget_show(window);
}

void	cb_start(GtkWidget *widget, gpointer data)
{
  if (!t1) {
    /*
     * create worker thread.
     */
    count = 0;
    pthread_create(&t1, NULL, insert_thread, data);
  }
}

void	*insert_thread(void *data)
{
  GtkText	*text = GTK_TEXT(data);
  char		str[5];

  while (count < COUNT_MAX && thread_stop_flag == 0) {
    sprintf(str, "%04d", count);
    GDK_THREADS_ENTER();
    gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, str, strlen(str));
    GDK_THREADS_LEAVE();

    g_usleep(10);
    count++;
  }
  return((void*)NULL);
}

void	cb_stop(GtkWidget *widget, gpointer data)
{
  if (t1) {
    /*
     * terminate worker thread.
     */
    thread_stop_flag = 1;
    GDK_THREADS_LEAVE();
    pthread_join(t1, NULL);
    GDK_THREADS_ENTER();
    t1 = (pthread_t)NULL;
    thread_stop_flag = 0;
  }
}

int main(int argc, char *argv[])
{
  g_thread_init(NULL);
  gtk_init(&argc, &argv);
  create_window();

  GDK_THREADS_ENTER();
  gtk_main();
  GDK_THREADS_LEAVE();
  return 0;
}
