#include <math.h>
#include <gtk/gtk.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gstdio.h>
#include <pthread.h>

typedef struct
{
  GtkPrintOperation *operation;
  GtkPrintContext   *context;
  gint               page_nr;
} PrintDataThread;

static void
begin_print (GtkPrintOperation *operation, 
	     GtkPrintContext   *context,
	     gpointer           user_data)
{
  gtk_print_operation_set_n_pages (operation, 10);
}

void *
draw_page_in_thread (void *user_data)
{
  PangoFontDescription *desc;
  PrintDataThread      *in_data = (PrintDataThread *) user_data;
  GtkPrintOperation    *operation = in_data->operation;
  GtkPrintContext      *context = in_data->context;
  PangoLayout          *layout;
  gdouble               width;
  gdouble               height;
  cairo_t              *cr;
  gchar                *page_str;
  gint                  text_width;
  gint                  text_height;
  gint                  page_nr = in_data->page_nr;

  GDK_THREADS_ENTER ();

  cr = gtk_print_context_get_cairo_context (context);

  width = gtk_print_context_get_width (context);
  height = gtk_print_context_get_height (context);

  cairo_rectangle (cr, 0, 0, width, height);
  cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
  cairo_fill_preserve (cr);
  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_set_line_width (cr, 1);
  cairo_stroke (cr);

  layout = gtk_print_context_create_pango_layout (context);

  desc = pango_font_description_from_string ("sans 64");
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc);

  cairo_move_to (cr, width / 8, height / 8);

  page_str = g_strdup_printf ("%d/%d", page_nr + 1, 100);
  pango_layout_set_text (layout, page_str, -1);
  g_free (page_str);

  pango_layout_set_width (layout, -1);
  pango_layout_get_pixel_size (layout, &text_width, &text_height);
  pango_cairo_show_layout (cr, layout);
  
  g_object_unref (layout);

  gtk_print_operation_page_drawing_finished (operation);

  GDK_THREADS_LEAVE ();

  return (NULL);
}

static void
draw_page (GtkPrintOperation *operation,
	   GtkPrintContext   *context,
	   gint               page_nr,
	   gpointer           user_data)
{
  pthread_t *thread = NULL;
  pthread_attr_t pthread_custom_attr;
  PrintDataThread *thread_data = NULL;

  thread_data = g_new (PrintDataThread, 1);

  thread_data->operation = operation;
  thread_data->context = context;
  thread_data->page_nr = page_nr;
  thread = g_new (pthread_t, 1);
  pthread_attr_init (&pthread_custom_attr);

  pthread_create (thread, &pthread_custom_attr, draw_page_in_thread, (void *) thread_data);
}

static void
end_print (GtkPrintOperation *operation, 
	   GtkPrintContext   *context,
	   gpointer           user_data)
{
}

void
do_printing (GtkWidget *parent, GtkWindow *window)
{
  GtkPrintOperation *operation;
  GError *error = NULL;

  operation = gtk_print_operation_new ();
  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), "end-print", 
		    G_CALLBACK (end_print), NULL);

  gtk_print_operation_set_use_full_page (operation, FALSE);
  gtk_print_operation_set_unit (operation, GTK_UNIT_POINTS);
  gtk_print_operation_set_allow_threads (operation, TRUE);

  gtk_print_operation_run (operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, window, &error);

  g_object_unref (operation);

  if (error)
    {
      GtkWidget *dialog;
      
      dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
				       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);      
    }
}

int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *button;

  gtk_init (&argc, &argv);

  window = gtk_dialog_new ();

  g_signal_connect_after (window, "destroy",
		          G_CALLBACK (gtk_main_quit), NULL);

  gtk_window_set_default_size (GTK_WINDOW (window), 100, 50);

  button = gtk_button_new_with_label ("Print something.");

  g_signal_connect (button, "clicked", G_CALLBACK (do_printing), GTK_WINDOW (window));

  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), GTK_WIDGET (button), FALSE, FALSE, 2);

  gtk_widget_show_all (GTK_WIDGET (window));
  
  gtk_main ();

  return 0;
}
