#include <gtk/gtk.h>

#define PREVIEW_SCALE 72

typedef struct
{
	GtkPrintOperationPreview *preview;
	GtkWidget *area;	// preview drawing area
} PreviewOp;

GtkWidget *window1;

void create_window();
static void on_test(GtkButton *button, gpointer user_data);
static void begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data);
static void draw_page (GtkPrintOperation *operation, GtkPrintContext   *context,  gint page_nr, gpointer user_data);
gboolean preview_cb (GtkPrintOperation *op,
					 GtkPrintOperationPreview *preview,
					 GtkPrintContext          *context,
					 GtkWindow                *parent,
					 gpointer                  data);
static void preview_destroy (GtkWindow *window, PreviewOp *pop);
static void preview_got_page_size (GtkPrintOperationPreview *preview,
								   GtkPrintContext          *context,
								   GtkPageSetup             *page_setup1,
								   gpointer                  data);
gboolean paginate_document(GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data);
static void
preview_ready (GtkPrintOperationPreview *preview,
	       GtkPrintContext          *context,
	       gpointer                  data);
static gboolean preview_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data);

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

	create_window();

	gtk_main ();

	return 0;
}

#ifdef _WIN32
#include <windows.h>
int APIENTRY WinMain( HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR lpCmdLine, int nCmdShow)
{
	return main( __argc, __argv );
}
#endif

void create_window()
{
	GtkWidget *button5;

	window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title (GTK_WINDOW (window1), "test");
	gtk_widget_show (window1);
	g_signal_connect (window1, "destroy", G_CALLBACK (gtk_main_quit), NULL);

	button5 = gtk_button_new_with_mnemonic("Click");
	gtk_widget_show (button5);
	gtk_container_add (GTK_CONTAINER (window1), button5);

	g_signal_connect(button5, "clicked", G_CALLBACK (on_test), NULL);
}

void begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
{
	//print only one test page
	gtk_print_operation_set_n_pages (operation, 1);

	GtkPageSetup *page_setup = gtk_print_context_get_page_setup (context);
	gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_PORTRAIT);

	printf("begin_print\n");
}

void on_test(GtkButton *button, gpointer user_data)
{
	GtkPrintOperation *operation;
	GError *error = NULL;

	operation = gtk_print_operation_new ();
	gtk_print_operation_set_show_progress(operation, TRUE);
	gtk_print_operation_set_unit(operation, GTK_UNIT_POINTS);

	g_signal_connect (G_OBJECT (operation), "begin-print", G_CALLBACK (begin_print), NULL);
	g_signal_connect (G_OBJECT (operation), "draw-page", G_CALLBACK (draw_page), NULL);
	g_signal_connect (G_OBJECT (operation), "preview", G_CALLBACK (preview_cb), NULL);
	g_signal_connect (G_OBJECT (operation), "paginate", G_CALLBACK (paginate_document), NULL);
	
	gtk_print_operation_run (operation, (GtkPrintOperationAction)GTK_PRINT_OPERATION_ACTION_PREVIEW, GTK_WINDOW (window1), &error);
	g_object_unref (operation);

	if (error)
	{
		GtkWidget *dialog;

		dialog = gtk_message_dialog_new (GTK_WINDOW (window1),
			GTK_DIALOG_DESTROY_WITH_PARENT,
			GTK_MESSAGE_ERROR,
			GTK_BUTTONS_CLOSE,
			"%s", error->message);
		g_error_free (error);
		g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);

		gtk_widget_show (dialog);      
	}
}

void draw_page (GtkPrintOperation *operation,
				GtkPrintContext   *context,
				gint               page_nr,
				gpointer           user_data)
{
	cairo_t *cr;

	printf("draw_page\n");

	cr = gtk_print_context_get_cairo_context (context);

	// Draw a red rectangle, as wide as the paper (inside the margins)
	cairo_set_source_rgb (cr, 1.0, 0, 0);
	cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), gtk_print_context_get_height (context));
	cairo_fill (cr);
}

gboolean preview_cb (GtkPrintOperation *op,
					 GtkPrintOperationPreview *preview,
					 GtkPrintContext          *context,
					 GtkWindow                *parent,
					 gpointer                  data)
{
	GtkWidget *window, *vbox, *da, *sw;
	cairo_t *cr;

	PreviewOp *pop = new PreviewOp;

	//settings1 = gtk_print_operation_get_print_settings (op);

	window = gtk_window_new (GTK_WINDOW_TOPLEVEL); //gtk_dialog_new();
	gtk_window_set_title (GTK_WINDOW (window), "Document Preview");
	gtk_window_set_modal (GTK_WINDOW (window), TRUE);
	gtk_window_set_destroy_with_parent (GTK_WINDOW (window), TRUE);
#ifndef _WINDOWS  //TOFIX API is buggy on Win32 (kills modal dialog state)
	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
#endif
	gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
	gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DIALOG);
	gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (window1));
	gtk_window_set_decorated(GTK_WINDOW (window), TRUE);
	gtk_widget_realize(window);
#if GTK_CHECK_VERSION(2,18,0)
	gdk_window_set_decorations(gtk_widget_get_window(window), (GdkWMDecoration)(GDK_DECOR_ALL));
#else
	gdk_window_set_decorations(window->window, (GdkWMDecoration)(GDK_DECOR_ALL));
#endif

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (window), vbox);
	//vbox = GTK_DIALOG (window)->vbox;

	sw = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
		GTK_POLICY_AUTOMATIC,
		GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);

	da = gtk_drawing_area_new();
	gtk_widget_set_double_buffered(da, FALSE);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), da);
	gtk_widget_realize(da);

#if GTK_CHECK_VERSION(2,18,0)
	cr = gdk_cairo_create (gtk_widget_get_window(da));
#else
	cr = gdk_cairo_create (da->window);
#endif
	gtk_print_context_set_cairo_context (context, cr, PREVIEW_SCALE, PREVIEW_SCALE);
	cairo_destroy (cr);

	gtk_widget_show (window);

	pop->preview = preview;
	pop->area = da;

	g_signal_connect (preview, "ready",			G_CALLBACK (preview_ready), pop);
	g_signal_connect (preview, "got-page-size",	G_CALLBACK (preview_got_page_size), pop);
	g_signal_connect (window, "destroy", G_CALLBACK (preview_destroy), pop);

	gtk_window_set_default_size(GTK_WINDOW(window), 400, 500);
	gtk_window_resize(GTK_WINDOW(window), 400, 500);

	gtk_widget_show_all (window);
	gtk_grab_add(window);	//block all other widgets in the app

	return TRUE;
}

static void
preview_ready (GtkPrintOperationPreview *preview,
	       GtkPrintContext          *context,
	       gpointer                  data)
{
	PreviewOp *pop = (PreviewOp *)data;

	printf("preview_ready\n");
	
	g_signal_connect (pop->area, "expose_event", G_CALLBACK (preview_expose), pop);
	gtk_widget_queue_draw (pop->area);
}

void preview_destroy (GtkWindow *window, PreviewOp *pop)
{
	printf("preview_destroy\n");

	gtk_print_operation_preview_end_preview (pop->preview);
	delete pop;

	gtk_window_present(GTK_WINDOW(window1)); //activate main window
}

void preview_got_page_size (GtkPrintOperationPreview *preview,
							GtkPrintContext          *context,
							GtkPageSetup             *page_setup1,
							gpointer                  data)
{
	PreviewOp *pop = (PreviewOp *)data;
	GtkPaperSize *paper_size;
	int w, h;

	printf("preview_got_page_size\n");

	paper_size = gtk_page_setup_get_paper_size (page_setup1);
	w = (int)gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
	h = (int)gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);

	gint page_width;	// requested area width
	gint page_height;

	page_width  = w * PREVIEW_SCALE;
	page_height = h * PREVIEW_SCALE;

	gtk_widget_set_size_request(GTK_WIDGET(pop->area),  page_width, page_height);
}

gboolean paginate_document(GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
{
	printf("paginate_document\n");
	gtk_print_operation_set_n_pages (operation, 1);
	return TRUE;	//done paginating
}

gboolean preview_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	//TRACE("Printing: print preview expose\n");
	PreviewOp *pop = (PreviewOp *)data;

#if GTK_CHECK_VERSION(2,18,0)
	GdkWindow *window = gtk_widget_get_window(pop->area);
#else
	GdkWindow *window = pop->area->window;
#endif
	gdk_window_clear (window);

	gtk_print_operation_preview_render_page (pop->preview, 1);
	return FALSE;
}

