#include <glib.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkalignment.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmain.h>
#include <gtk/gtktable.h>
#include <gtk/gtkwindow.h>
#include <stdio.h>

#define ROWS    5
#define COLUMNS 5
#define ITERATIONS 100

static double time_first_expose = 0.0;
static double time_last_expose  = 0.0;
static GTimer* timer = NULL;
static int expose_count = 0;

static GtkWidget *
create_table_item (guint index)
{
    GtkWidget * item = NULL;
    gchar * label = g_strdup_printf ("%d", index);

    item = gtk_vbox_new (FALSE, 0);

    GtkWidget * top = gtk_hbox_new (FALSE, 0);
    GtkWidget * bottom = gtk_hbox_new (FALSE, 0);

    gtk_container_add (GTK_CONTAINER (item), top);
    gtk_container_add (GTK_CONTAINER (item), bottom);

    gtk_container_add (GTK_CONTAINER (top),
                       gtk_button_new_with_label (label));
    gtk_container_add (GTK_CONTAINER (top),
                       gtk_alignment_new (0.5, 0.5, 0.0, 0.0));
    gtk_container_add (GTK_CONTAINER (bottom),
                       gtk_label_new (""));
    gtk_container_add (GTK_CONTAINER (bottom),
                       gtk_check_button_new ());

    g_free (label);
    return item;
}

static gboolean
window_expose_cb (GtkWindow * win, GdkEventExpose * e)
{
    ++expose_count;

    if (expose_count == 1)
    {
      time_first_expose = g_timer_elapsed(timer, NULL);
    }
    else if (expose_count >= ITERATIONS)
    {
      time_last_expose = g_timer_elapsed(timer, NULL);
      gtk_main_quit ();
    }

    return FALSE;
}

static gboolean
idle_callback(gpointer data)
{
  GtkWidget* widget;

  widget = data;

  gdk_window_invalidate_rect(widget->window, NULL, TRUE);
  gdk_window_process_updates(widget->window, TRUE);

  return TRUE;
}

int
main (int argc, char * argv[])
{
    guint i, j;
    GtkWidget* window;
    GtkWidget* table;
    GtkWidget* item;
    double time_initialization;
    double time_construction;

    timer = g_timer_new();
    g_timer_start(timer);

    gtk_init(&argc, &argv);

    time_initialization = g_timer_elapsed(timer, NULL);
    g_timer_start(timer);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    table = gtk_table_new (ROWS, COLUMNS, FALSE);

    for (i = 0; i < ROWS; i++)
    {
        for (j = 0; j < COLUMNS; j++)
        {
            item = create_table_item (i * COLUMNS + j);
            gtk_table_attach_defaults (GTK_TABLE (table),
                                       item,
                                       j,
                                       j + 1,
                                       i,
                                       i + 1);

        }
    }

    gtk_container_add (GTK_CONTAINER (window), table);
    gtk_widget_show_all(table);

    g_signal_connect (G_OBJECT (window), "expose-event",
                      G_CALLBACK (window_expose_cb), NULL);

    g_idle_add(&idle_callback, window);
    time_construction = g_timer_elapsed(timer, NULL);
    g_timer_start(timer);

    gtk_widget_show(window);
    gtk_main ();

    printf("%.4f: initialization\n%.4f: construction\n"
           "%.4f: first expose\n%.4f: last expose\n",
           time_initialization, time_construction,
           time_first_expose, time_last_expose);

    g_timer_destroy(timer);

    return 0;
}

