/*
 * cairo-tests.c
 *
 * Compare two different Cairo paths vs. X11 drawing.
 *
 * Written by Davyd Madeley <davyd@fugro-fsi.com.au> to illustrate an example.
 * All permissions given, use this code as desired.
 *
 * Compile with
 *   gcc -g `pkg-config --cflags --libs gtk+-2.0` -o cairo-tests cairo-tests.c 
 */

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

typedef void (*DrawFunc) (GdkWindow *window);

#define SIZE 300
#define DIAM 5
#define INC 6

/* draw each arc individually with Cairo */
static void
expose_da1 (GdkWindow *window)
{
	cairo_t *cr = gdk_cairo_create (GDK_DRAWABLE (window));
	double x, y;

	cairo_set_line_width (cr, 1.0);

	for (x = 0; x < SIZE; x += INC)
	{
		for (y = 0; y < SIZE; y += INC)
		{
			cairo_arc (cr, x+DIAM/2., y+DIAM/2., (DIAM-1)/2., -M_PI, M_PI);
			cairo_stroke (cr);
		}
	}
	
	cairo_destroy (cr);
}

/* for comparison, draw each arc with X11 */
static void
expose_da2 (GdkWindow *window)
{
	int x, y;

	GdkGC *gc = gdk_gc_new (GDK_DRAWABLE (window));

	for (x = 0; x < SIZE; x += INC)
	{
		for (y = 0; y < SIZE; y += INC)
		{
			gdk_draw_arc (GDK_DRAWABLE (window), gc, FALSE, x, y,
					DIAM-1, DIAM-1, 0, 64 * 360);
		}
	}

	g_object_unref (gc);
}

/* now use Cairo again, but with a mask */
static void
expose_da3 (GdkWindow *window)
{
	cairo_t *cr = gdk_cairo_create (GDK_DRAWABLE (window));
	double x, y;

	/* create the masking surface */
	cairo_surface_t *circ = cairo_surface_create_similar (
			cairo_get_target (cr), CAIRO_CONTENT_ALPHA,
			DIAM, DIAM);
	cairo_t *cr2 = cairo_create (circ);
	cairo_set_line_width (cr2, 1.0);
	cairo_arc (cr2, DIAM/2., DIAM/2., (DIAM-1)/2., -M_PI, M_PI);
	cairo_stroke (cr2);
	cairo_destroy (cr2);

	for (x = 0; x < SIZE; x += INC)
	{
		for (y = 0; y < SIZE; y += INC)
		{
			cairo_mask_surface (cr, circ, x, y);
		}
	}
	
	cairo_destroy (cr);
	cairo_surface_destroy (circ);
}

static gboolean
expose (GtkWidget *da, GdkEventExpose *event, gpointer data)
{
	g_print ("expose %p... ", da);

	DrawFunc func = (DrawFunc) data;

	GTimer *timer = g_timer_new ();
	func (da->window);
	g_timer_stop (timer);
	g_print ("took %g seconds\n", g_timer_elapsed (timer, NULL));

	g_timer_destroy (timer);

	return TRUE;
}

int
main (int argc, char **argv)
{
	gtk_init (&argc, &argv);

	GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_default_size (GTK_WINDOW (window), SIZE * 2, SIZE * 2);
	g_signal_connect_swapped (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
	
	GtkWidget *table = gtk_table_new (2, 2, TRUE);
	gtk_container_add (GTK_CONTAINER (window), table);

	GtkWidget *da1 = gtk_drawing_area_new ();
	gtk_table_attach_defaults (GTK_TABLE (table), da1, 0, 1, 0, 1);
	g_print ("cairo (no mask) = %p\n", da1);
	g_signal_connect (da1, "expose-event", G_CALLBACK (expose), expose_da1);
	
	GtkWidget *da2 = gtk_drawing_area_new ();
	gtk_table_attach_defaults (GTK_TABLE (table), da2, 1, 2, 0, 1);
	g_print ("x11             = %p\n", da2);
	g_signal_connect (da2, "expose-event", G_CALLBACK (expose), expose_da2);

	GtkWidget *da3 = gtk_drawing_area_new ();
	gtk_table_attach_defaults (GTK_TABLE (table), da3, 0, 1, 1, 2);
	g_print ("cairo (mask)    = %p\n", da3);
	g_signal_connect (da3, "expose-event", G_CALLBACK (expose), expose_da3);

	gtk_widget_show_all (window);

	gtk_main ();
}
