#include <gtk/gtk.h>

#include "torturer.h"
#include "paint.h"
#include "dummyenumtypes.h"

#define SIZE_SMALL 1
#define SIZE_MEDIUM 200
#define SIZE_LARGE 10000
#define POS_X 0
#define POS_Y 0

/* Globals */
GtkWidget  *drawing_area;
GtkWidget  *test_window;
GtkWidget **checkboxes;
GtkStyle   *style;
GdkWindow  *window;

extern GtkWidget *crash_test_label;

typedef void (* ForeachCombinationFn) (int *values, gpointer data);

static void
foreach_combination_of_enums (GType *enum_types, int num_enum_types, ForeachCombinationFn func, gpointer data)
{
  GEnumClass **enum_classes;
  int *indices;
  int *values;
  
  int i;
  
  enum_classes = g_new (GEnumClass *, num_enum_types);
  indices = g_new (int, num_enum_types);
  values = g_new (int, num_enum_types);
  
#define SET_VALUE(k) (values[(k)] = enum_classes[(k)]->values[indices[(k)]].value)
  
  /* Initialize the enum classes and the "zero" values */
  for (i = 0; i < num_enum_types; i++) {
    enum_classes[i] = g_type_class_ref (enum_types[i]);
    if (!enum_classes[i])
      g_error ("Invalid enum type %d", (int) enum_types[i]);
    
    indices[i] = 0;
    SET_VALUE (i);
  }
  
  /* Go through all the combinations of enum values.  We ripple-carry on
   * the "indices" array; each index can attain as many values as the
   * number of possible values for the corresponding enum class.
   */
  
  while (1) {
    (* func) (values, data);
    
    /* Compute the next set of indices */
    for (i = 0; i < num_enum_types; i++) {
      indices[i]++;
      
      if (indices[i] < enum_classes[i]->n_values) {
	SET_VALUE (i);
	goto next_set_of_values;
      }
      
      /* Zero this index and ripple-carry to the next one */
      indices[i] = 0;
      SET_VALUE (i);
    }
    
    break; /* We are done with all the combinations, since we ripple-carried to the end */
    
  next_set_of_values:
    ;
  }
  
#undef SET_VALUE
  
  for (i = 0; i < num_enum_types; i++)
    g_type_class_unref (enum_classes[i]);
  
  g_free (enum_classes);
  g_free (indices);
  g_free (values);
}

static gchar *
set_detail (GtkDetailDummyType detail) {
  gchar *detail_string;

  switch (detail) {
  case GTK_DETAIL_DUMMY_TRY:
    detail_string = g_strdup_printf ("Crashy crashy.");
    printf ("detail = \"%s\"   ", detail_string);
    break;
  case GTK_DETAIL_DUMMY_NULL:
    detail_string = NULL;
    printf ("detail = NULL   ");
    break;
  default:
    g_error ("Invalid value for the detail enum\n");
  }
  return detail_string;
}

static gboolean
set_bool (GtkBoolDummyType val) {
  gboolean val_gboolean;

  switch (val) {
  case GTK_BOOL_DUMMY_TRUE:
    val_gboolean  = TRUE;
    break;
  case GTK_BOOL_DUMMY_FALSE:
    val_gboolean = FALSE;
    break;
  default:
    g_error ("Invalid value for the bool enum\n");
  }
  printf ("(fill | use_text) = %i   ", val_gboolean);
  return val_gboolean;
}

static gint
set_size (GtkSizeDummyType size) {
  gint width;

  switch (size) {
  case GTK_SIZE_DUMMY_SMALL:
    width  = SIZE_SMALL; /* height will just have the same value */
    break;
  case GTK_SIZE_DUMMY_MEDIUM:
    width  = SIZE_MEDIUM;
    break;
  case GTK_SIZE_DUMMY_LARGE:
    width  = SIZE_LARGE;
    break;
  default:
    g_error ("Invalid value for the size enum\n");    
  }
  printf ("width = height = %i   ", width);
  return width;
}

static gint
set_gap_x (GtkGapXDummyType gap_x) {
  gint gap_x_int;

  switch (gap_x) {
  case GTK_GAP_X_DUMMY_SMALL:
    gap_x_int  = SIZE_SMALL;
    break;
  case GTK_GAP_X_DUMMY_MEDIUM:
    gap_x_int = SIZE_MEDIUM;
    break;
  case GTK_GAP_X_DUMMY_LARGE:
    gap_x_int = SIZE_LARGE;
    break;
  default:
    g_error ("Invalid value for the gap x enum\n");    
  }
  printf ("gap_x = %i   ", gap_x_int);
  return gap_x_int;
}

static gint
set_gap_width (GtkGapWidthDummyType gap_width) {
  gint gap_width_int;

  switch (gap_width) {
  case GTK_GAP_WIDTH_DUMMY_SMALL:
    gap_width_int = SIZE_SMALL;
    break;
  case GTK_GAP_WIDTH_DUMMY_MEDIUM:
    gap_width_int = SIZE_MEDIUM;
    break;
  case GTK_GAP_WIDTH_DUMMY_LARGE:
    gap_width_int = SIZE_LARGE;
    break;
  default:
    g_error ("Invalid value for the gap width enum\n");    
  }
  printf ("gap_width = %i   ", gap_width_int);
  return gap_width_int;
}

static GdkRectangle *
set_area (GtkAreaDummyType area) {
  GdkRectangle *rectangle;

  rectangle = g_new (GdkRectangle, 1);
  rectangle->x = POS_X;
  rectangle->y = POS_Y;

  switch (area) {
  case GTK_AREA_DUMMY_SMALL:
    rectangle->width = SIZE_SMALL;
    break;
  case GTK_AREA_DUMMY_MEDIUM:
    rectangle->width = SIZE_MEDIUM;
    break;
  case GTK_AREA_DUMMY_LARGE:
    rectangle->width = SIZE_LARGE;
    break;
  case GTK_AREA_DUMMY_NULL:
    g_free (rectangle);
    rectangle = NULL;
    break;
  default:
    g_error ("Invalid value for the area enum\n");
  }
  if (rectangle)
    printf ("area = (%i, %i, %i, %i)   ", POS_X, POS_X, rectangle->width, rectangle->width);
  else
    printf ("area = NULL   ");
  return rectangle;
}

static GdkPoint *
set_polygon (GdkPoint *points, gint *number_of_points) {

  /* Let's make a simple triangle */
  gint n_points = 3, i = 0;

  *number_of_points = (gint) n_points;

  points = g_new (GdkPoint, n_points);
  points[i].x = 20; points[i++].y = 10;
  points[i].x = 10; points[i++].y = 20;
  points[i].x = 30; points[i++].y = 20;

  printf ("points = (");
  for (i = 0; i < n_points - 1; i++) {
    printf ("%i, %i ; ", points[i].x, points[i].y);
  }
  printf ("%i, %i)   npoints = %i   ", points[n_points - 1].x, points[n_points - 1].y, n_points);

  return points;
}

static PangoLayout *
set_layout (PangoLayout *layout, GtkWidget *widget) {
  PangoContext *context;
  char         *text;

  context = gtk_widget_get_pango_context (widget);
  layout = pango_layout_new (context);
  text = g_strdup_printf ("Crashy crashy.");

  pango_layout_set_text (layout, text, -1);

  printf ("layout text = \"%s\"", text);

  g_free (text);
  return layout;
}


/* All gtk_paint_* functions use at least these 6 parameters: style, window, detail,
 * state_type, area, widget.
 */

/* The most common parameter set: the 6 usual ones + shadow_type, x, y, width, height */
static void
test_state_shadow_area_detail_size_functions (int *values, gpointer data)
{
  GtkStateType state;
  GtkShadowType shadow;
  GtkDetailDummyType detail;
  GtkAreaDummyType area;
  GtkSizeDummyType size;
  guint32 tests = GPOINTER_TO_UINT(data);

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  
  state  = values[i++];
  shadow = values[i++];
  detail = values[i++];
  area   = values[i++];
  size   = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   ", state, shadow);

  /* For all the "dummy" enum types, set the real values and print them out */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);
  printf ("\n");

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_BOXES)) {
    printf ("Testing box... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_box (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_CHECKS)) {
    printf ("Testing check... ");
    fflush (NULL);
    gtk_paint_check (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_DIAMONDS)) {
    printf ("Testing diamond... ");
    fflush (NULL);
    gtk_paint_diamond (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_FLAT_BOXES)) {
    printf ("Testing flat box... ");
    fflush (NULL);
    gtk_paint_flat_box (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_OPTIONS)) {
    printf ("Testing option... ");
    fflush (NULL);
    gtk_paint_option (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_SHADOWS)) {
    printf ("Testing shadow... ");
    fflush (NULL);
    gtk_paint_shadow (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_TABS)) {
    printf ("Testing tab... ");
    fflush (NULL);
    gtk_paint_tab (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }  

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + x, y, width, height */
static void
test_state_area_detail_size_functions (int *values, gpointer data)
{
  GtkStateType state;
  GtkDetailDummyType detail;
  GtkAreaDummyType area;
  GtkSizeDummyType size;
  guint32 tests = GPOINTER_TO_UINT(data);

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  
  state  = values[i++];
  detail = values[i++];
  area   = values[i++];
  size   = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   ", state);

  /* For all the "dummy" enum types, set the real values and print them out */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);
  printf ("\n");

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_HLINES)) {
    printf ("(hline : x1 = %i   x2 = %i   y = %i) ", POS_X, POS_X + width, POS_Y);
    printf ("Testing hline... ");
    fflush (NULL);
    gtk_paint_hline (style, window, state, rectangle, drawing_area, detail_string, POS_X, POS_X + width, POS_Y);
    printf ("OK\n");
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_VLINES)) {
    printf ("(vline : y1 = %i   y2 = %i   x = %i) ", POS_Y, POS_Y + height, POS_X);
    printf ("Testing vline... ");
    fflush (NULL);
    gtk_paint_vline (style, window, state, rectangle, drawing_area, detail_string, POS_Y, POS_Y + height, POS_X);
    printf ("OK\n");
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_FOCUSES)) {
    printf ("Testing focus... ");
    fflush (NULL);
    gtk_paint_focus (style, window, state, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }  

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + shadow_type, arrow_type, fill, x, y, width, height */
static void
test_state_shadow_area_detail_arrow_fill_size_functions (int *values, gpointer data)
{
  GtkStateType  state;
  GtkShadowType shadow;
  GtkArrowType  arrow;
  GtkDetailDummyType detail;
  GtkAreaDummyType   area;
  GtkBoolDummyType   fill;
  GtkSizeDummyType   size;
  guint32 tests = GPOINTER_TO_UINT(data);

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  gboolean      fill_gboolean;
  
  state  = values[i++];
  shadow = values[i++];
  arrow  = values[i++];
  detail = values[i++];
  area   = values[i++];
  fill   = values[i++];
  size   = values[i++];

  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   arrow_type = %i   ", state, shadow, arrow);
  
  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  fill_gboolean = set_bool (fill);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_ARROWS)) {
    printf ("Testing arrow... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_arrow (style, window, state, shadow, rectangle, drawing_area, detail_string, arrow, fill, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + shadow_type, x, y, width, height, gap_side, gap_x, gap_width */
static void
test_state_shadow_area_detail_size_gaps_functions (int *values, gpointer data)
{
  GtkStateType    state;
  GtkShadowType   shadow;
  GtkPositionType gap_side;
  GtkDetailDummyType     detail;
  GtkAreaDummyType       area;
  GtkSizeDummyType       size;
  GtkGapXDummyType       gap_x;
  GtkGapWidthDummyType   gap_width;

  gint          width, height, gap_x_int, gap_width_int, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state     = values[i++];
  shadow    = values[i++];
  gap_side  = values[i++];
  area      = values[i++];
  detail    = values[i++];
  size      = values[i++];
  gap_x     = values[i++];
  gap_width = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   gap_side = %i   ", state, shadow, gap_side);

  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);
  gap_x_int = set_gap_x (gap_x);
  gap_width_int = set_gap_width (gap_width);
  printf ("\n");

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_BOX_GAPS)) {
    printf ("Testing box gap... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_box_gap (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height, gap_side, gap_x_int, gap_width_int);
    printf ("OK\n");
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_SHADOW_GAPS)) {
    printf ("Testing shadow gap... ");
    fflush (NULL);
    gtk_paint_shadow_gap (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height, gap_side, gap_x_int, gap_width_int);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + shadow_type, x, y, width, height, gap_side */
static void
test_state_shadow_area_detail_size_gapside_functions (int *values, gpointer data)
{
  GtkStateType    state;
  GtkShadowType   shadow;
  GtkPositionType gap_side;
  GtkDetailDummyType     detail;
  GtkAreaDummyType       area;
  GtkSizeDummyType       size;

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state     = values[i++];
  shadow    = values[i++];
  gap_side  = values[i++];
  area      = values[i++];
  detail    = values[i++];
  size      = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   gap_side = %i   ", state, shadow, gap_side);

  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_EXTENSIONS)) {
    printf ("Testing extension... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_extension (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height, gap_side);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + shadow_type, x, y, width, height, orientation */
static void
test_state_shadow_area_detail_size_orientation_functions (int *values, gpointer data)
{
  GtkStateType    state;
  GtkShadowType   shadow;
  GtkOrientation  orientation;
  GtkDetailDummyType     detail;
  GtkAreaDummyType       area;
  GtkSizeDummyType       size;

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state        = values[i++];
  shadow       = values[i++];
  orientation  = values[i++];
  area         = values[i++];
  detail       = values[i++];
  size         = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   orientation = %i   ", state, shadow, orientation);

  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);
  printf ("\n");

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_HANDLES)) {
    printf ("Testing handle... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_handle (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height, orientation);
    printf ("OK\n");
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_SLIDERS)) {
    printf ("Testing slider... ");
    fflush (NULL);
    gtk_paint_slider (style, window, state, shadow, rectangle, drawing_area, detail_string, POS_X, POS_Y, width, height, orientation);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + shadow_type fill, x, y, points, npoints */
static void
test_state_shadow_area_detail_fill_points_npoints_functions (int *values, gpointer data)
{
  GtkStateType  state;
  GtkShadowType shadow;
  GtkDetailDummyType detail;
  GtkAreaDummyType   area;
  GtkBoolDummyType   fill;

  /* Special polygon variables */
  GdkPoint *points;
  gint      npoints;

  gint          i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  gboolean      fill_gboolean;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state  = values[i++];
  shadow = values[i++];
  detail = values[i++];
  area   = values[i++];
  fill   = values[i++];

  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   shadow_type = %i   ", state, shadow);
  
  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  fill_gboolean = set_bool (fill);
  rectangle = set_area (area);

  /* Set the polygon */
  points = set_polygon (points, &npoints);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_POLYGONS)) {
    printf ("Testing polygon... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_polygon (style, window, state, shadow, rectangle, drawing_area, detail_string, points, npoints, fill);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
  if (points)
    g_free (points);
}

/* Parameter set: the 6 usual ones + x, y, expanderstyle */
static void
test_state_area_detail_expander_functions (int *values, gpointer data)
{
  GtkStateType     state;
  GtkExpanderStyle expander;
  GtkDetailDummyType     detail;
  GtkAreaDummyType       area;

  gint          i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state        = values[i++];
  expander     = values[i++];
  area         = values[i++];
  detail       = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   expander_style = %i   ", state, expander);

  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  rectangle = set_area (area);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_EXPANDERS)) {
    printf ("Testing expander... ");
    fflush (NULL);
    gtk_paint_expander (style, window, state, rectangle, drawing_area, detail_string, POS_X, POS_Y, expander);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Parameter set: the 6 usual ones + use_text, x, y, layout */
static void
test_state_usetext_area_detail_layout_functions (int *values, gpointer data)
{
  GtkStateType  state;
  GtkDetailDummyType detail;
  GtkAreaDummyType   area;
  GtkBoolDummyType   use_text;

  /* Special layout variables */
  PangoLayout  *layout;

  gint          i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  gboolean      use_text_gboolean;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state    = values[i++];
  detail   = values[i++];
  area     = values[i++];
  use_text = values[i++];

  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   ", state);
  
  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  use_text_gboolean = set_bool (use_text);
  rectangle = set_area (area);

  /* Set the layout */
  layout = set_layout (layout, drawing_area);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_LAYOUTS)) {
    printf ("Testing layout... ");
    fflush (NULL); /* Flush all open streams (i.e. stdout) so that everything gets printed before the crash, if any */
    gtk_paint_layout (style, window, state, use_text_gboolean, rectangle, drawing_area, detail_string, POS_X, POS_Y, layout);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
  if (layout)
    g_object_unref (layout);
}

/* Parameter set: the 6 usual ones + shadow_type, x, y, width, height, orientation */
static void
test_state_area_detail_edge_size_functions (int *values, gpointer data)
{
  GtkStateType    state;
  GdkWindowEdge   edge;
  GtkDetailDummyType     detail;
  GtkAreaDummyType       area;
  GtkSizeDummyType       size;

  gint          width, height, i = 0;
  gchar        *detail_string;
  GdkRectangle *rectangle;
  guint32 tests = GPOINTER_TO_UINT(data);
  
  state  = values[i++];
  edge   = values[i++];
  area   = values[i++];
  detail = values[i++];
  size   = values[i++];
  
  /* For all the real enum types, print out the current value */
  printf ("state_type = %i   edge = %i   ", state, edge);

  /* For all the "dummy" enum types, set the real values */
  detail_string = set_detail (detail);
  width = set_size (size);
  height = width;
  rectangle = set_area (area);

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_RESIZE_GRIPS)) {
    printf ("Testing resize grip... ");
    fflush (NULL);
    gtk_paint_resize_grip (style, window, state, rectangle, drawing_area, detail_string, edge, POS_X, POS_Y, width, height);
    printf ("OK\n");
  }

  if (detail_string)
    g_free (detail_string);
  if (rectangle)
    g_free (rectangle);
}

/* Now the functions that define enums and do the "foreach" loop */
static void
test_all_state_shadow_area_detail_size (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_SIZE
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_size_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_area_detail_size (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_SIZE
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_area_detail_size_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_shadow_area_detail_arrow_fill_size (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_TYPE_ARROW_TYPE,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_BOOL,  /* fill */
    GTK_DUMMY_TYPE_SIZE
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_arrow_fill_size_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_shadow_area_detail_size_gaps_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_TYPE_POSITION_TYPE,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_SIZE,
    GTK_DUMMY_TYPE_GAP_X,
    GTK_DUMMY_TYPE_GAP_WIDTH
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_size_gaps_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_shadow_area_detail_size_gapside_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_TYPE_POSITION_TYPE,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_SIZE,
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_size_gapside_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_shadow_area_detail_size_orientation_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_TYPE_ORIENTATION,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_SIZE,
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_size_orientation_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_shadow_area_detail_fill_points_npoints_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_SHADOW_TYPE,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_BOOL  /* fill */
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_shadow_area_detail_fill_points_npoints_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_area_detail_expander_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_TYPE_EXPANDER_STYLE,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_DETAIL
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_area_detail_expander_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_usetext_area_detail_layout_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_BOOL  /* use_text */
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_usetext_area_detail_layout_functions, GUINT_TO_POINTER(tests));
}

static void
test_all_state_area_detail_edge_size_functions (guint32 tests)
{
  GType enum_types[] = {
    GTK_TYPE_STATE_TYPE,
    GDK_TYPE_WINDOW_EDGE,
    GTK_DUMMY_TYPE_AREA,
    GTK_DUMMY_TYPE_DETAIL,
    GTK_DUMMY_TYPE_SIZE,
  };
  int num_enum_types = G_N_ELEMENTS (enum_types);
  
  foreach_combination_of_enums (enum_types, num_enum_types, test_state_area_detail_edge_size_functions, GUINT_TO_POINTER(tests));
}

int area_width;
int area_height;

static gboolean
map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
{
  guint32 tests = GPOINTER_TO_UINT(data);
  style = gtk_widget_get_style (widget);

  window = widget->window;
  gtk_label_set_text (GTK_LABEL (crash_test_label), "Testing...");

  while (gtk_events_pending ())
    gtk_main_iteration ();

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_BOXES) || TEST_IS_ACTIVE (tests, GTK_PAINT_CHECKS)
      || TEST_IS_ACTIVE (tests, GTK_PAINT_DIAMONDS) || TEST_IS_ACTIVE (tests, GTK_PAINT_FLAT_BOXES)
      || TEST_IS_ACTIVE (tests, GTK_PAINT_OPTIONS) || TEST_IS_ACTIVE (tests, GTK_PAINT_SHADOWS)
      || TEST_IS_ACTIVE (tests, GTK_PAINT_TABS)) {
    test_all_state_shadow_area_detail_size (tests);
  }
  
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_FOCUSES) || TEST_IS_ACTIVE (tests, GTK_PAINT_HLINES)
      || TEST_IS_ACTIVE (tests, GTK_PAINT_VLINES)) {
    test_all_state_area_detail_size (tests);
  }
  
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_ARROWS)) {
    test_all_state_shadow_area_detail_arrow_fill_size (tests);
  }
  
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_BOX_GAPS) || TEST_IS_ACTIVE (tests, GTK_PAINT_SHADOW_GAPS)) {
    test_all_state_shadow_area_detail_size_gaps_functions (tests);
  }
  
  if (TEST_IS_ACTIVE (tests, GTK_PAINT_EXTENSIONS)) {
    test_all_state_shadow_area_detail_size_gapside_functions (tests);
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_HANDLES) || TEST_IS_ACTIVE (tests, GTK_PAINT_SLIDERS)) {
    test_all_state_shadow_area_detail_size_orientation_functions (tests);
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_POLYGONS)) {
    test_all_state_shadow_area_detail_fill_points_npoints_functions (tests);
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_EXPANDERS)) {
    test_all_state_area_detail_expander_functions (tests);
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_LAYOUTS)) {
    test_all_state_usetext_area_detail_layout_functions (tests);
  }

  if (TEST_IS_ACTIVE (tests, GTK_PAINT_RESIZE_GRIPS)) {
    test_all_state_area_detail_edge_size_functions (tests);
  }

  gtk_label_set_text (GTK_LABEL (crash_test_label), "Finished. No crashes occurred.");
  printf ("Finished. No crashes occurred.\n");
  gtk_widget_destroy (test_window);

  return FALSE;
}

void
gtk_paint_functions_test (guint32 tests)
{
  /* GTK initializations */
  test_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position (GTK_WINDOW (test_window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size (GTK_WINDOW (test_window), gdk_screen_width () / 2, gdk_screen_height () / 2);
  //gtk_window_set_resizable (GTK_WINDOW (test_window), FALSE);

  drawing_area = gtk_drawing_area_new ();
  g_signal_connect (drawing_area, "map-event",
		    G_CALLBACK (map_event_cb), GUINT_TO_POINTER(tests));
  gtk_container_add (GTK_CONTAINER (test_window), drawing_area);

  gtk_widget_show_all (test_window);
}
