Print preview api



Ok, after a lot of work (mostly by John and Alex),
we finally have a proposal for a print preview 
api that will allow us to use an external viewer
by default, but also support internal preview.

It consists of the following pieces: 

1) GtkPrintOperation gets a new signal

gboolean (*preview) (GtkPrintOperation        *operation,
	             GtkPrintOperationPreview *preview, 
	             GtkPrintContext          *context,
		     GtkWindow                *parent);

This signal is emitted when the user clicks the preview
button. It the application does not handle it, the
default handler will arrange for the external viewer
to be spawned.

An application that handles the preview internally
should return TRUE from the signal handler. The 
GtkPrintOperationPreview that is passed to the signal
handler lets the application control the preview.


2) The GtkPrintOperationPreview interface has 
a number of signals:

void (*ready)         (GtkPrintOperationPreview *preview, 
	               GtkPrintContext          *context);

The ready signal is emitted when pagination is done. The
GtkPrintOperation::preview handler should connect to this
signal to know when it is safe to start displaying pages.

 void (*got_page_size) (GtkPrintOperationPreview *preview, 
		        GtkPrintContext          *context,
		        GtkPageSetup             *page_setup);

The got-page-size signal is emitted for every rendered
page, when the page setup for the page is know. This signal
can be used to adjust the cairo context used for rendering
the page (e.g. for resizing the preview window).

And methods:

void gtk_print_operation_preview_render_page 
                         (GtkPrintOperationPreview *preview,
                          gint                      page_nr)

Renders the requested page to the cairo context currently
set on the print context for the preview. 

void gtk_print_operation_preview_end_preview    
                         (GtkPrintOperationPreview *preview)

Must be called to clean up when the preview is finished.


3) A new way of handling the cairo context associated 
with a GtkPrintContext. A print context is no longer 
directly associated with a cairo surface. Instead, a 
cairo context is set with

void gtk_print_context_set_cairo_context 
                        (GtkPrintContext *context,
                         cairo_t         *cr,
                         double           dpi_x,
                         double           dpi_y);

And this can be repeated, typically in a got-page-size
handler.

The attached patch against current cvs has a 
very basic preview implementation in print-editor.c 
that demonstrates this api.

Comments appreciated,

Matthias


Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.308
diff -u -p -r1.308 Makefile.am
--- gtk/Makefile.am	22 May 2006 17:19:09 -0000	1.308
+++ gtk/Makefile.am	1 Jun 2006 20:34:39 -0000
@@ -4,6 +4,7 @@ SUBDIRS=theme-bits
 
 if OS_UNIX
 SUBDIRS += xdgmime
+GTK_PRINT_PREVIEW_COMMAND="evince %f"
 endif
 
 DIST_SUBDIRS=theme-bits xdgmime
@@ -25,6 +26,7 @@ INCLUDES =						\
 	-DGTK_HOST=\"$(host)\"				\
 	-DGTK_COMPILATION				\
 	-DGTK_PRINT_BACKENDS=\"$(GTK_PRINT_BACKENDS)\"	\
+	-DGTK_PRINT_PREVIEW_COMMAND=\"$(GTK_PRINT_PREVIEW_COMMAND)\"	\
 	-I$(top_builddir)/gtk				\
 	-I$(top_srcdir) -I../gdk			\
 	-I$(top_srcdir)/gdk				\
@@ -231,6 +233,7 @@ gtk_public_h_sources =          \
 	gtkpreview.h		\
 	gtkprintcontext.h	\
 	gtkprintoperation.h	\
+	gtkprintoperationpreview.h	\
 	gtkprintsettings.h	\
 	gtkprivate.h		\
 	gtkprogress.h		\
@@ -487,6 +490,7 @@ gtk_c_sources =                 \
 	gtkpreview.c		\
 	gtkprintcontext.c	\
 	gtkprintoperation.c	\
+	gtkprintoperationpreview.c	\
 	gtkprintsettings.c	\
 	gtkprintutils.c		\
 	gtkprogress.c		\
Index: gtk/gtkmarshalers.list
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmarshalers.list,v
retrieving revision 1.67
diff -u -p -r1.67 gtkmarshalers.list
--- gtk/gtkmarshalers.list	22 May 2006 17:19:09 -0000	1.67
+++ gtk/gtkmarshalers.list	1 Jun 2006 20:34:39 -0000
@@ -32,6 +32,7 @@ BOOLEAN:OBJECT,INT,INT,UINT
 BOOLEAN:OBJECT,STRING,STRING,BOXED
 BOOLEAN:OBJECT,BOXED
 BOOLEAN:OBJECT,BOXED,BOXED
+BOOLEAN:OBJECT,OBJECT,OBJECT
 BOOLEAN:OBJECT,STRING,STRING
 BOOLEAN:INT
 BOOLEAN:INT,INT
Index: gtk/gtkprintbackend.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.c,v
retrieving revision 1.7
diff -u -p -r1.7 gtkprintbackend.c
--- gtk/gtkprintbackend.c	1 Jun 2006 05:02:56 -0000	1.7
+++ gtk/gtkprintbackend.c	1 Jun 2006 20:34:39 -0000
@@ -200,7 +200,6 @@ _gtk_print_backend_create (const char *b
   GtkPrintBackendModule *pb_module;
   GtkPrintBackend *pb;
 
-  /* TODO: make module loading code work */
   for (l = loaded_backends; l != NULL; l = l->next)
     {
       pb_module = l->data;
@@ -255,6 +254,11 @@ gtk_print_backend_initialize (void)
 							  GTK_PRINT_BACKENDS,
 							  GTK_PARAM_READWRITE));
 
+      gtk_settings_install_property (g_param_spec_string ("gtk-print-preview-command",
+							  P_("Default command to run when displaying a print preview"),
+							  P_("Command to run when displaying a print preview"),
+							  GTK_PRINT_PREVIEW_COMMAND,
+							  GTK_PARAM_READWRITE)); 
       initialized = TRUE;
     }
 }
Index: gtk/gtkprintbackend.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.h,v
retrieving revision 1.8
diff -u -p -r1.8 gtkprintbackend.h
--- gtk/gtkprintbackend.h	24 May 2006 10:50:56 -0000	1.8
+++ gtk/gtkprintbackend.h	1 Jun 2006 20:34:39 -0000
@@ -140,6 +140,9 @@ void        gtk_print_backend_print_stre
 GList *     gtk_print_backend_load_modules         (void);
 void        gtk_print_backend_destroy              (GtkPrintBackend         *print_backend);
 
+/* Methods private to gtk */
+GtkPrintBackend * _gtk_print_backend_create        (const char *backend_name);
+
 /* Backend-only functions for GtkPrintBackend */
 
 void        gtk_print_backend_add_printer          (GtkPrintBackend         *print_backend,
Index: gtk/gtkprintcontext.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintcontext.c,v
retrieving revision 1.4
diff -u -p -r1.4 gtkprintcontext.c
--- gtk/gtkprintcontext.c	31 May 2006 13:38:10 -0000	1.4
+++ gtk/gtkprintcontext.c	1 Jun 2006 20:34:39 -0000
@@ -40,6 +40,9 @@ struct _GtkPrintContext
   GtkPageSetup *page_setup;
   PangoFontMap *fontmap;
 
+  gdouble surface_dpi_x;
+  gdouble surface_dpi_y;
+  
   gdouble pixels_per_unit_x;
   gdouble pixels_per_unit_y;
 };
@@ -60,8 +63,8 @@ gtk_print_context_finalize (GObject *obj
   if (context->page_setup)
     g_object_unref (context->page_setup);
 
-  cairo_destroy (context->cr);
-
+  if (context->cr)
+    cairo_destroy (context->cr);
   
   G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
 }
@@ -83,15 +86,31 @@ gtk_print_context_class_init (GtkPrintCo
 GtkPrintContext *
 _gtk_print_context_new (GtkPrintOperation *op)
 {
-  GtkPrintOperationPrivate *priv = op->priv;
   GtkPrintContext *context;
 
   context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
 
   context->op = op;
-  context->cr = cairo_create (priv->surface);
+  context->cr = NULL;
+  context->fontmap = pango_cairo_font_map_new ();
+  
+  return context;
+}
+
+void
+gtk_print_context_set_cairo_context (GtkPrintContext *context,
+				     cairo_t         *cr,
+				     double           dpi_x,
+				     double           dpi_y)
+{
+  if (context->cr)
+    cairo_destroy (context->cr);
+
+  context->cr = cairo_reference (cr);
+  context->surface_dpi_x = dpi_x;
+  context->surface_dpi_y = dpi_y;
 
-  switch (priv->unit)
+  switch (context->op->priv->unit)
     {
     default:
     case GTK_UNIT_PIXEL:
@@ -100,34 +119,31 @@ _gtk_print_context_new (GtkPrintOperatio
       context->pixels_per_unit_y = 1.0;
       break;
     case GTK_UNIT_POINTS:
-      context->pixels_per_unit_x = priv->dpi_x / POINTS_PER_INCH;
-      context->pixels_per_unit_y = priv->dpi_y / POINTS_PER_INCH;
+      context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
+      context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
       break;
     case GTK_UNIT_INCH:
-      context->pixels_per_unit_x = priv->dpi_x;
-      context->pixels_per_unit_y = priv->dpi_y;
+      context->pixels_per_unit_x = dpi_x;
+      context->pixels_per_unit_y = dpi_y;
       break;
     case GTK_UNIT_MM:
-      context->pixels_per_unit_x = priv->dpi_x / MM_PER_INCH;
-      context->pixels_per_unit_y = priv->dpi_y / MM_PER_INCH;
+      context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
+      context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
       break;
     }
   cairo_scale (context->cr,
 	       context->pixels_per_unit_x,
 	       context->pixels_per_unit_y);
     
-  context->fontmap = pango_cairo_font_map_new ();
   /* We use the unit-scaled resolution, as we still want fonts given in points to work */
   pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (context->fontmap),
-				       priv->dpi_y / context->pixels_per_unit_y);
-  
-  return context;
+				       dpi_y / context->pixels_per_unit_y);
 }
 
+
 void
 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
 {
-  GtkPrintOperationPrivate *priv = context->op->priv;
   cairo_t *cr = context->cr;
   cairo_matrix_t matrix;
   GtkPaperSize *paper_size;
@@ -136,9 +152,9 @@ _gtk_print_context_rotate_according_to_o
   paper_size = gtk_page_setup_get_paper_size (context->page_setup);
 
   width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
-  width = width * priv->dpi_x / context->pixels_per_unit_x;
+  width = width * context->surface_dpi_x / context->pixels_per_unit_x;
   height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
-  height = height * priv->dpi_y / context->pixels_per_unit_y;
+  height = height * context->surface_dpi_y / context->pixels_per_unit_y;
   
   switch (gtk_page_setup_get_orientation (context->page_setup))
     {
@@ -188,8 +204,8 @@ _gtk_print_context_translate_into_margin
   top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
 
   cairo_translate (context->cr,
-		   left * priv->dpi_x / context->pixels_per_unit_x,
-		   top * priv->dpi_y / context->pixels_per_unit_y);
+		   left * context->surface_dpi_x / context->pixels_per_unit_x,
+		   top * context->surface_dpi_y / context->pixels_per_unit_y);
 }
 
 void
@@ -272,7 +288,7 @@ gtk_print_context_get_width (GtkPrintCon
     width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
 
   /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
-  return width * priv->dpi_x / context->pixels_per_unit_x;
+  return width * context->surface_dpi_x / context->pixels_per_unit_x;
 }
 
 /**
@@ -300,8 +316,8 @@ gtk_print_context_get_height (GtkPrintCo
   else
     height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
 
-  /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
-  return height * priv->dpi_y / context->pixels_per_unit_y;
+  /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
+  return height * context->surface_dpi_y / context->pixels_per_unit_y;
 }
 
 /**
@@ -320,7 +336,7 @@ gtk_print_context_get_dpi_x (GtkPrintCon
 {
   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
 
-  return context->op->priv->dpi_x;
+  return context->surface_dpi_x;
 }
 
 /**
@@ -339,7 +355,7 @@ gtk_print_context_get_dpi_y (GtkPrintCon
 {
   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
 
-  return context->op->priv->dpi_y;
+  return context->surface_dpi_y;
 }
 
 /**
@@ -376,10 +392,16 @@ PangoContext *
 gtk_print_context_create_pango_context (GtkPrintContext *context)
 {
   PangoContext *pango_context;
+  cairo_font_options_t *options;
 
   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
   
   pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (context->fontmap));
+
+  options = cairo_font_options_create ();
+  cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
+  pango_cairo_context_set_font_options (pango_context, options);
+  cairo_font_options_destroy (options);
   
   return pango_context;
 }
Index: gtk/gtkprintcontext.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintcontext.h,v
retrieving revision 1.3
diff -u -p -r1.3 gtkprintcontext.h
--- gtk/gtkprintcontext.h	31 May 2006 13:38:10 -0000	1.3
+++ gtk/gtkprintcontext.h	1 Jun 2006 20:34:39 -0000
@@ -51,6 +51,11 @@ PangoFontMap *gtk_print_context_get_pang
 PangoContext *gtk_print_context_create_pango_context (GtkPrintContext *context);
 PangoLayout  *gtk_print_context_create_pango_layout  (GtkPrintContext *context);
 
+/* Needed for preview implementations */
+void         gtk_print_context_set_cairo_context     (GtkPrintContext *context,
+						      cairo_t         *cr,
+						      double           dpi_x,
+						      double           dpi_y);
 
 G_END_DECLS
 
Index: gtk/gtkprintjob.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintjob.c,v
retrieving revision 1.8
diff -u -p -r1.8 gtkprintjob.c
--- gtk/gtkprintjob.c	16 May 2006 16:13:48 -0000	1.8
+++ gtk/gtkprintjob.c	1 Jun 2006 20:34:39 -0000
@@ -212,14 +212,14 @@ gtk_print_job_constructor (GType        
   job = GTK_PRINT_JOB (object);
 
   priv = job->priv;
-  g_assert (priv->printer_set &&
-	    priv->settings_set &&
+  g_assert (priv->settings_set &&
 	    priv->page_setup_set);
-  
-  _gtk_printer_prepare_for_print (priv->printer,
-				  job,
-				  priv->settings,
-				  priv->page_setup);
+ 
+  if (priv->printer)
+    _gtk_printer_prepare_for_print (priv->printer,
+				    job,
+				    priv->settings,
+				    priv->page_setup);
 
   return object;
 }
@@ -545,8 +545,12 @@ gtk_print_job_set_property (GObject     
     
     case GTK_PRINT_JOB_PROP_PRINTER:
       priv->printer = GTK_PRINTER (g_value_dup_object (value));
-      priv->printer_set = TRUE;
-      priv->backend = g_object_ref (gtk_printer_get_backend (priv->printer));
+      
+      if (priv->printer != NULL)
+        {
+          priv->printer_set = TRUE;
+          priv->backend = g_object_ref (gtk_printer_get_backend (priv->printer));
+        }
       break;
 
     case GTK_PRINT_JOB_PROP_PAGE_SETUP:
Index: gtk/gtkprintoperation-private.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-private.h,v
retrieving revision 1.11
diff -u -p -r1.11 gtkprintoperation-private.h
--- gtk/gtkprintoperation-private.h	1 Jun 2006 12:38:07 -0000	1.11
+++ gtk/gtkprintoperation-private.h	1 Jun 2006 20:34:39 -0000
@@ -46,9 +46,11 @@ struct _GtkPrintOperationPrivate
   guint print_pages_idle_id;
   guint show_progress_timeout_id;
 
+  GtkPrintContext *print_context;
+  
   /* Data for the print job: */
-  cairo_surface_t *surface;
-  gdouble dpi_x, dpi_y;
+  /* cairo_surface_t *surface; */
+  /*  gdouble dpi_x, dpi_y; */
 
   GtkPrintPages print_pages;
   GtkPageRange *page_ranges;
@@ -84,11 +86,23 @@ GtkPrintOperationResult _gtk_print_opera
 									  GError           **error);
 
 typedef void (* GtkPrintOperationPrintFunc) (GtkPrintOperation *op,
-					     GtkWindow         *parent);
+					     GtkWindow         *parent,
+					     gboolean           is_preview);
 
 void _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
 							     GtkWindow                  *parent,
 							     GtkPrintOperationPrintFunc  print_cb);
+
+void _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
+							   GtkWindow *parent,
+							   const char *filename);
+
+cairo_surface_t *_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *operation, 
+						 		               gdouble width, 
+								               gdouble heigh,
+									       gdouble *dpi_x,
+									       gdouble *dpi_y,
+								               const gchar *target);
 
 void _gtk_print_operation_set_status (GtkPrintOperation *op,
 				      GtkPrintStatus     status,
Index: gtk/gtkprintoperation-unix.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-unix.c,v
retrieving revision 1.19
diff -u -p -r1.19 gtkprintoperation-unix.c
--- gtk/gtkprintoperation-unix.c	1 Jun 2006 12:38:07 -0000	1.19
+++ gtk/gtkprintoperation-unix.c	1 Jun 2006 20:34:39 -0000
@@ -25,6 +25,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <errno.h>
+#include <stdlib.h>       
+#include <fcntl.h>
 
 #include "gtkprintoperation-private.h"
 #include "gtkmarshal.h"
@@ -41,13 +44,17 @@
 #include "gtkalias.h"
 #include "gtkintl.h"
 
-
 typedef struct {
-  GtkPrintJob *job;         /* the job we are sending to the printer */
-  gulong job_status_changed_tag;
   GtkWindow *parent;        /* just in case we need to throw error dialogs */
   GMainLoop *loop;
   gboolean data_sent;
+
+  /* Real printing (not preview: */
+  GtkPrintJob *job;         /* the job we are sending to the printer */
+  cairo_surface_t *surface;
+  gulong job_status_changed_tag;
+
+  
 } GtkPrintOperationUnix;
 
 typedef struct _PrinterFinder PrinterFinder;
@@ -62,21 +69,24 @@ unix_start_page (GtkPrintOperation *op,
 		 GtkPrintContext   *print_context,
 		 GtkPageSetup      *page_setup)
 {
+  GtkPrintOperationUnix *op_unix;  
   GtkPaperSize *paper_size;
   cairo_surface_type_t type;
   double w, h;
 
+  op_unix = op->priv->platform_data;
+  
   paper_size = gtk_page_setup_get_paper_size (page_setup);
 
   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
   
-  type = cairo_surface_get_type (op->priv->surface);
+  type = cairo_surface_get_type (op_unix->surface);
 
   if (type == CAIRO_SURFACE_TYPE_PS)
-    cairo_ps_surface_set_size (op->priv->surface, w, h);
+    cairo_ps_surface_set_size (op_unix->surface, w, h);
   else if (type == CAIRO_SURFACE_TYPE_PDF)
-    cairo_pdf_surface_set_size (op->priv->surface, w, h);
+    cairo_pdf_surface_set_size (op_unix->surface, w, h);
 }
 
 static void
@@ -102,6 +112,112 @@ op_unix_free (GtkPrintOperationUnix *op_
   g_free (op_unix);
 }
 
+static char *
+shell_command_substitute_file (const gchar *cmd,
+			       const gchar *filename)
+{
+  const char *inptr, *start;
+  char *result;
+  GString *final;
+
+  g_return_val_if_fail (cmd != NULL, NULL);
+  g_return_val_if_fail (filename != NULL, NULL);
+
+  result = NULL;
+  final = g_string_new (NULL);
+
+  start = inptr = cmd;
+
+  while ((inptr = strchr (inptr, '%')) != NULL) 
+    {
+      g_string_append_len (final, start, inptr - start);
+      inptr++;
+      switch (*inptr) 
+        {
+          case 'f':
+            g_string_append (final, filename ? filename : "");
+            break;
+
+          case '%':
+            g_string_append_c (final, '%');
+            break;
+
+          default:
+            g_string_append_c (final, '%');
+            if (*inptr)
+              g_string_append_c (final, *inptr);
+            break;
+        }
+      if (*inptr)
+        inptr++;
+      start = inptr;
+    }
+  g_string_append (final, start);
+
+  result = final->str;
+
+  g_string_free (final, FALSE);
+
+  return result;
+}
+
+void
+_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
+						      GtkWindow *parent,
+						      const char *filename)
+{
+  int argc;
+  gchar **argv;
+  gchar *cmd;
+  gchar *preview_cmd;
+  GtkSettings *settings;
+  gchar *quoted_filename;
+  GdkScreen *screen;
+  GError *error = NULL;
+ 
+  settings = gtk_settings_get_default ();
+  g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);
+
+  quoted_filename = g_shell_quote (filename);
+  cmd = shell_command_substitute_file (preview_cmd, quoted_filename);
+  g_shell_parse_argv (cmd, &argc, &argv, &error);
+
+  if (error !=NULL)
+    goto out;
+
+  if (parent)
+    screen = gtk_window_get_screen (parent);
+  else
+    screen = gdk_screen_get_default ();
+  
+  gdk_spawn_on_screen (screen, NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
+
+ out:
+  if (error != NULL)
+    {
+      GtkWidget *edialog;
+      edialog = gtk_message_dialog_new (parent, 
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR,
+                                        GTK_BUTTONS_CLOSE,
+                                        _("Error launching preview") /* FIXME better text */);
+      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
+                                                "%s", error->message);
+      gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
+      g_signal_connect (edialog, "response",
+                        G_CALLBACK (gtk_widget_destroy), NULL);
+
+      gtk_window_present (GTK_WINDOW (edialog));
+
+      g_error_free (error); 
+   } 
+
+  g_free (cmd);
+  g_free (quoted_filename);
+  g_free (preview_cmd);
+  g_strfreev (argv);
+}
+
 static void
 unix_finish_send  (GtkPrintJob *job,
                    void        *user_data, 
@@ -129,6 +245,7 @@ unix_finish_send  (GtkPrintJob *job,
     }
 
   op_unix->data_sent = TRUE;
+
   if (op_unix->loop)
     g_main_loop_quit (op_unix->loop);
 }
@@ -140,6 +257,8 @@ unix_end_run (GtkPrintOperation *op,
 {
   GtkPrintOperationUnix *op_unix = op->priv->platform_data;
 
+  cairo_surface_finish (op_unix->surface);
+  
   if (cancelled)
     return;
 
@@ -147,10 +266,11 @@ unix_end_run (GtkPrintOperation *op,
     op_unix->loop = g_main_loop_new (NULL, FALSE);
   
   /* TODO: Check for error */
-  gtk_print_job_send (op_unix->job,
-                      unix_finish_send, 
-                      op_unix, NULL,
-		      NULL);
+  if (op_unix->job != NULL)
+    gtk_print_job_send (op_unix->job,
+                        unix_finish_send, 
+                        op_unix, NULL,
+		        NULL);
 
   if (wait)
     {
@@ -253,64 +373,66 @@ finish_print (PrintResponseData *rdata,
 {
   GtkPrintOperation *op = rdata->op;
   GtkPrintOperationPrivate *priv = op->priv;
+  gboolean is_preview;
 
-  priv->start_page = unix_start_page;
-  priv->end_page = unix_end_page;
-  priv->end_run = unix_end_run;
+  g_print ("finish_print\n");
+  
+  is_preview = rdata->result == GTK_PRINT_OPERATION_RESULT_PREVIEW;
   
   if (rdata->do_print)
     {
-      GtkPrintOperationUnix *op_unix;
-
       gtk_print_operation_set_print_settings (op, settings);
-      
-      op_unix = g_new0 (GtkPrintOperationUnix, 1);
-      op_unix->job = gtk_print_job_new (priv->job_name,
-					printer,
-					settings,
-					page_setup);
+      op->priv->print_context = _gtk_print_context_new (op);
 
-      gtk_print_job_set_track_print_status (op_unix->job, priv->track_print_status);
-      
-      rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
-      if (op->priv->surface == NULL)
+      if (!is_preview)
         {
-	  rdata->do_print = FALSE;
-	  op_unix_free (op_unix);
-	  rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
-	  goto out;
-	}
-
-      _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
-      op_unix->job_status_changed_tag =
-	g_signal_connect (op_unix->job, "status-changed",
-			  G_CALLBACK (job_status_changed_cb), op);
-      
-      op_unix->parent = rdata->parent;
-
-      priv->dpi_x = 72;
-      priv->dpi_y = 72;
- 
-      priv->platform_data = op_unix;
-      priv->free_platform_data = (GDestroyNotify) op_unix_free;
-
-      priv->print_pages = op_unix->job->print_pages;
-      priv->page_ranges = op_unix->job->page_ranges;
-      priv->num_page_ranges = op_unix->job->num_page_ranges;
-  
-      priv->manual_num_copies = op_unix->job->num_copies;
-      priv->manual_collation = op_unix->job->collate;
-      priv->manual_reverse = op_unix->job->reverse;
-      priv->manual_page_set = op_unix->job->page_set;
-      priv->manual_scale = op_unix->job->scale;
-      priv->manual_orientation = op_unix->job->rotate_to_orientation;
+	  GtkPrintOperationUnix *op_unix;
+	  cairo_t *cr;
+	  
+	  op_unix = g_new0 (GtkPrintOperationUnix, 1);     
+	  priv->platform_data = op_unix;
+	  priv->free_platform_data = (GDestroyNotify) op_unix_free;
+	  op_unix->parent = rdata->parent;
+	  
+	  priv->start_page = unix_start_page;
+	  priv->end_page = unix_end_page;
+	  priv->end_run = unix_end_run;
+	  
+	  op_unix->job = gtk_print_job_new (priv->job_name,
+					    printer,
+					    settings,
+					    page_setup);
+          gtk_print_job_set_track_print_status (op_unix->job, priv->track_print_status);
+	  /* TODO: handle error */
+	  op_unix->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
+	  cr = cairo_create (op_unix->surface);
+	  gtk_print_context_set_cairo_context (op->priv->print_context,
+					       cr, 72, 72);
+	  cairo_destroy (cr);
+
+          _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
+	  
+          op_unix->job_status_changed_tag =
+	    g_signal_connect (op_unix->job, "status-changed",
+			      G_CALLBACK (job_status_changed_cb), op);
+	  
+          priv->print_pages = op_unix->job->print_pages;
+          priv->page_ranges = op_unix->job->page_ranges;
+          priv->num_page_ranges = op_unix->job->num_page_ranges;
+	  
+          priv->manual_num_copies = op_unix->job->num_copies;
+          priv->manual_collation = op_unix->job->collate;
+          priv->manual_reverse = op_unix->job->reverse;
+          priv->manual_page_set = op_unix->job->page_set;
+          priv->manual_scale = op_unix->job->scale;
+          priv->manual_orientation = op_unix->job->rotate_to_orientation;
+        }
     } 
-
- out:  
+  
   if (rdata->print_cb)
     {
       if (rdata->do_print)
-        rdata->print_cb (op, rdata->parent); 
+        rdata->print_cb (op, rdata->parent, is_preview); 
       else
        _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); 
     }
@@ -319,7 +441,7 @@ finish_print (PrintResponseData *rdata,
     rdata->destroy (rdata);
 }
 
-static void
+static void 
 handle_print_response (GtkWidget *dialog,
 		       gint       response,
 		       gpointer   data)
@@ -330,6 +452,8 @@ handle_print_response (GtkWidget *dialog
   GtkPageSetup *page_setup = NULL;
   GtkPrinter *printer = NULL;
 
+  g_print ("handle_print_response\n");
+  
   if (response == GTK_RESPONSE_OK)
     {
       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
@@ -345,14 +469,24 @@ handle_print_response (GtkWidget *dialog
 
       g_signal_emit_by_name (rdata->op, "custom-widget-apply", rdata->op->priv->custom_widget);
     } 
+  else if (response == GTK_RESPONSE_APPLY)
+    {
+      /* print preview */
+      rdata->result = GTK_PRINT_OPERATION_RESULT_PREVIEW;
+      rdata->do_print = TRUE;
 
+      settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
+      page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
+    }
+  
  out:  
   finish_print (rdata, printer, page_setup, settings);
 
   if (settings)
     g_object_unref (settings);
-  
+
   gtk_widget_destroy (GTK_WIDGET (pd));
+ 
 }
 
 
@@ -436,6 +570,19 @@ _gtk_print_operation_platform_backend_ru
     }
 }
 
+cairo_surface_t *
+_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
+							      gdouble width,
+							      gdouble height,
+							      gdouble *dpi_x,
+							      gdouble *dpi_y,
+							      const gchar *target)
+{
+  g_print ("pdf surface size: %f x %f\n", width, height);
+  *dpi_x = *dpi_y = 72;
+  return cairo_pdf_surface_create (target, width, height);
+}
+
 GtkPrintOperationResult
 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
 						  GtkWindow         *parent,
@@ -459,6 +606,7 @@ _gtk_print_operation_platform_backend_ru
   if (op->priv->show_dialog)
     {
       pd = get_print_dialog (op, parent);
+
       response = gtk_dialog_run (GTK_DIALOG (pd));
       handle_print_response (pd, response, &rdata);
     }
Index: gtk/gtkprintoperation-win32.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-win32.c,v
retrieving revision 1.9
diff -u -p -r1.9 gtkprintoperation-win32.c
--- gtk/gtkprintoperation-win32.c	23 May 2006 16:30:45 -0000	1.9
+++ gtk/gtkprintoperation-win32.c	1 Jun 2006 20:34:39 -0000
@@ -492,6 +492,7 @@ win32_end_run (GtkPrintOperation *op,
   GlobalFree(op_win32->devmode);
   GlobalFree(op_win32->devnames);
 
+  cairo_surface_finish (op->priv->surface);
   cairo_surface_destroy (op->priv->surface);
   op->priv->surface = NULL;
 
Index: gtk/gtkprintoperation.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation.c,v
retrieving revision 1.24
diff -u -p -r1.24 gtkprintoperation.c
--- gtk/gtkprintoperation.c	1 Jun 2006 12:38:07 -0000	1.24
+++ gtk/gtkprintoperation.c	1 Jun 2006 20:34:39 -0000
@@ -19,6 +19,10 @@
  */
 
 #include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>       
+
 #include <string.h>
 #include "gtkprintoperation-private.h"
 #include "gtkmarshalers.h"
@@ -41,6 +45,7 @@ enum {
   STATUS_CHANGED,
   CREATE_CUSTOM_WIDGET,
   CUSTOM_WIDGET_APPLY,
+  PREVIEW,
   LAST_SIGNAL
 };
 
@@ -65,7 +70,15 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 static int job_nr = 0;
 
-G_DEFINE_TYPE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT)
+static void          preview_iface_init (GtkPrintOperationPreviewIface *iface);
+static GtkPageSetup *create_page_setup  (GtkPrintOperation             *op);
+static void          common_render_page (GtkPrintOperation             *op,
+					 gint                           page_nr);
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_PRINT_OPERATION_PREVIEW,
+						preview_iface_init))
 
 /**
  * gtk_print_error_quark:
@@ -146,6 +159,60 @@ gtk_print_operation_init (GtkPrintOperat
 }
 
 static void
+preview_iface_render_page (GtkPrintOperationPreview *preview,
+			   gint page_nr)
+{
+  GtkPrintOperation *op;
+
+  op = GTK_PRINT_OPERATION (preview);
+  common_render_page (op, page_nr);
+}
+
+static void
+preview_iface_end_preview (GtkPrintOperationPreview *preview)
+{
+  GtkPrintOperation *op;
+  
+  op = GTK_PRINT_OPERATION (preview);
+
+  g_signal_emit (op, signals[END_PRINT], 0, op->priv->print_context);
+
+  if (op->priv->rloop)
+    g_main_loop_quit (op->priv->rloop);
+
+  op->priv->end_run (op, op->priv->is_sync, TRUE);
+}
+
+static void
+preview_iface_init (GtkPrintOperationPreviewIface *iface)
+{
+  iface->render_page = preview_iface_render_page;
+  iface->end_preview = preview_iface_end_preview;
+}
+
+static void
+preview_start_page (GtkPrintOperation *op,
+		    GtkPrintContext   *print_context,
+		    GtkPageSetup      *page_setup)
+{
+  g_signal_emit_by_name (op, "got-page-size",print_context, page_setup);
+}
+
+static void
+preview_end_page (GtkPrintOperation *op,
+		  GtkPrintContext   *print_context)
+{
+}
+
+static void
+preview_end_run (GtkPrintOperation *op,
+		 gboolean           wait,
+		 gboolean           cancelled)
+{
+}
+
+
+static void
 gtk_print_operation_set_property (GObject      *object,
 				  guint         prop_id,
 				  const GValue *value,
@@ -256,6 +323,158 @@ gtk_print_operation_get_property (GObjec
     }
 }
 
+typedef struct
+{
+  GtkPrintOperationPreview *preview;
+  GtkPrintContext *print_context;
+  GtkWindow *parent;
+  cairo_surface_t *surface;
+  gchar *filename;
+  guint page_nr;
+  gboolean wait;
+} PreviewOp;
+
+static void
+preview_print_idle_done (gpointer data)
+{
+  GtkPrintOperation *op;
+  PreviewOp *pop = (PreviewOp *) data;
+
+  op = GTK_PRINT_OPERATION (pop->preview);
+
+  _gtk_print_operation_platform_backend_launch_preview (op,
+							pop->parent,
+							pop->filename);
+
+  g_free (pop->filename);
+  cairo_surface_finish (pop->surface);
+  cairo_surface_destroy (pop->surface);
+
+  gtk_print_operation_preview_end_preview (pop->preview);
+  g_free (pop);
+}
+
+static gboolean
+preview_print_idle (gpointer data)
+{
+  PreviewOp *pop;
+  GtkPrintOperation *op;
+  gboolean retval = TRUE;
+  cairo_t *cr;
+
+  GDK_THREADS_ENTER ();
+
+  pop = (PreviewOp *) data;
+  op = GTK_PRINT_OPERATION (pop->preview);
+
+  gtk_print_operation_preview_render_page (pop->preview, pop->page_nr);
+  
+  cr = gtk_print_context_get_cairo_context (pop->print_context);
+  cairo_show_page (cr);
+  
+  /* TODO: print out sheets not pages and follow ranges */
+  pop->page_nr++;
+  if (op->priv->nr_of_pages <= pop->page_nr)
+    retval = FALSE;
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static void
+preview_got_page_size (GtkPrintOperationPreview *preview, 
+		       GtkPrintContext          *context,
+		       GtkPageSetup             *page_setup,
+		       PreviewOp *pop)
+{
+  GtkPrintOperation *op = GTK_PRINT_OPERATION (preview);
+  GtkPaperSize *paper_size;
+  double w, h;
+
+  paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+  w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
+  h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
+
+  /* TODO: don't hardcode pdf */
+  cairo_pdf_surface_set_size (pop->surface, w, h);
+}
+
+static void
+preview_ready (GtkPrintOperationPreview *preview,
+               GtkPrintContext *context,
+	       PreviewOp *pop)
+{
+
+  pop->page_nr = 0;
+  pop->print_context = context;
+
+  g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+	           preview_print_idle,
+		   pop,
+		   preview_print_idle_done); 
+
+}
+
+/**
+ * gtk_print_operation_preview_handler:
+ *
+ * Default handler for preview operations
+ **/
+static gboolean
+gtk_print_operation_preview_handler (GtkPrintOperation *op,
+                                     GtkPrintOperationPreview *preview, 
+				     GtkPrintContext          *context,
+				     GtkWindow                *parent)
+{
+  gdouble width, height, dpi_x, dpi_y;
+  gchar *tmp_dir;
+  gchar *dir_template;
+  gchar *preview_filename;
+  PreviewOp *pop;
+  GtkPrintSettings *settings;
+  cairo_t *cr;
+
+  dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL);
+
+  /* use temp dirs because apps like evince need to have extentions
+     to determine the mine type */
+  tmp_dir = mkdtemp(dir_template);
+
+  preview_filename = g_build_filename (tmp_dir, 
+                                      "Print Preview.pdf",
+                                      NULL);
+  
+  g_free (dir_template);
+
+  pop = g_new0 (PreviewOp, 1);
+  pop->filename = preview_filename;
+  pop->preview = preview;
+  pop->parent = parent;
+
+  settings = op->priv->print_settings;
+
+  width = gtk_print_settings_get_paper_width (settings, GTK_UNIT_POINTS);
+  height = gtk_print_settings_get_paper_height (settings, GTK_UNIT_POINTS);
+
+  pop->surface =
+    _gtk_print_operation_platform_backend_create_preview_surface (op,
+								  width, height,
+								  &dpi_x, &dpi_y,
+								  pop->filename);
+
+  cr = cairo_create (pop->surface);
+  gtk_print_context_set_cairo_context (op->priv->print_context, cr,
+				       dpi_x, dpi_y);
+  cairo_destroy (cr);
+
+  g_signal_connect (preview, "ready", (GCallback) preview_ready, pop);
+  g_signal_connect (preview, "got-page-size", (GCallback) preview_got_page_size, pop);
+  
+  return TRUE;
+}
+
 static GtkWidget *
 gtk_print_operation_create_custom_widget (GtkPrintOperation *operation)
 {
@@ -287,7 +506,8 @@ gtk_print_operation_class_init (GtkPrint
   gobject_class->set_property = gtk_print_operation_set_property;
   gobject_class->get_property = gtk_print_operation_get_property;
   gobject_class->finalize = gtk_print_operation_finalize;
-
+ 
+  class->preview = gtk_print_operation_preview_handler; 
   class->create_custom_widget = gtk_print_operation_create_custom_widget;
   
   g_type_class_add_private (gobject_class, sizeof (GtkPrintOperationPrivate));
@@ -530,6 +750,33 @@ gtk_print_operation_class_init (GtkPrint
 		  g_cclosure_marshal_VOID__OBJECT,
 		  G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
 
+   /**
+   * GtkPrintOperation::preview:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   * @preview: the #GtkPrintPreviewOperation for the current operation
+   * @context: the #GtkPrintContext that will be used
+   * @parent: the #GtkWindow to use as window parent, or NULL
+   *
+   * Gets emitted when a preview is requested from the native dialog.
+   * If you handle this you must set the cairo_context on the printing context.
+   *
+   * Returns: #TRUE if the listener wants to take over control of the preview
+   * 
+   * Since: 2.10
+   */
+  signals[PREVIEW] =
+    g_signal_new (I_("preview"),
+		  G_TYPE_FROM_CLASS (gobject_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GtkPrintOperationClass, preview),
+		  _gtk_boolean_handled_accumulator, NULL,
+		  _gtk_marshal_BOOLEAN__OBJECT_OBJECT_OBJECT,
+		  G_TYPE_BOOLEAN, 3,
+		  GTK_TYPE_PRINT_OPERATION_PREVIEW,
+		  GTK_TYPE_PRINT_CONTEXT,
+		  GTK_TYPE_WINDOW);
+
+  
   /**
    * GtkPrintOperation:default-page-setup:
    *
@@ -1436,6 +1683,7 @@ pdf_start_page (GtkPrintOperation *op,
 		GtkPageSetup      *page_setup)
 {
   GtkPaperSize *paper_size;
+  cairo_surface_t *surface = op->priv->platform_data;
   double w, h;
 
   paper_size = gtk_page_setup_get_paper_size (page_setup);
@@ -1443,7 +1691,7 @@ pdf_start_page (GtkPrintOperation *op,
   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
   
-  cairo_pdf_surface_set_size (op->priv->surface, w, h);
+  cairo_pdf_surface_set_size (surface, w, h);
 }
 
 static void
@@ -1462,9 +1710,10 @@ pdf_end_run (GtkPrintOperation *op,
 	     gboolean           cancelled)
 {
   GtkPrintOperationPrivate *priv = op->priv;
+  cairo_surface_t *surface = priv->platform_data;
 
-  cairo_surface_destroy (priv->surface);
-  priv->surface = NULL;
+  cairo_surface_finish (surface);
+  cairo_surface_destroy (surface);
 }
 
 static GtkPrintOperationResult
@@ -1475,6 +1724,8 @@ run_pdf (GtkPrintOperation  *op,
 {
   GtkPrintOperationPrivate *priv = op->priv;
   GtkPageSetup *page_setup;
+  cairo_surface_t *surface;
+  cairo_t *cr;
   double width, height;
   /* This will be overwritten later by the non-default size, but
      we need to pass some size: */
@@ -1484,13 +1735,19 @@ run_pdf (GtkPrintOperation  *op,
   height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
   g_object_unref (page_setup);
   
-  priv->surface = cairo_pdf_surface_create (priv->pdf_target,
+  surface = cairo_pdf_surface_create (priv->pdf_target,
 					    width, height);
-  cairo_pdf_surface_set_dpi (priv->surface, 300, 300);
-  
-  priv->dpi_x = 72;
-  priv->dpi_y = 72;
+  cairo_pdf_surface_set_dpi (surface, 300, 300);
+
+  priv->platform_data = surface;
+  priv->free_platform_data = (GDestroyNotify) cairo_surface_destroy;
 
+  cr = cairo_create (surface);
+  gtk_print_context_set_cairo_context (op->priv->print_context,
+				       cr, 72, 72);
+  cairo_destroy (cr);
+
+  
   priv->print_pages = GTK_PRINT_PAGES_ALL;
   priv->page_ranges = NULL;
   priv->num_page_ranges = 0;
@@ -1524,10 +1781,11 @@ typedef struct
 
   gint page, start, end, inc;
 
-  GtkPageSetup *initial_page_setup;
-  GtkPrintContext *print_context;  
+  gboolean initialized;
 
   GtkWidget *progress;
+ 
+  gboolean is_preview; 
 } PrintPagesData;
 
 static void
@@ -1599,12 +1857,9 @@ print_pages_idle_done (gpointer user_dat
   if (data->progress)
     gtk_widget_destroy (data->progress);
 
-  g_object_unref (data->print_context);
-  g_object_unref (data->initial_page_setup);
-
   g_object_unref (data->op);
 
-  if (priv->rloop)
+  if (priv->rloop && !data->is_preview)
     g_main_loop_quit (priv->rloop);
 
   g_free (data);
@@ -1640,15 +1895,62 @@ update_progress (PrintPagesData *data)
     }
  }
 
+static void
+common_render_page (GtkPrintOperation *op,
+		    gint page_nr)
+{
+  GtkPrintOperationPrivate *priv = op->priv;
+  GtkPageSetup *page_setup;
+  GtkPrintContext *print_context;
+  cairo_t *cr;
+
+  print_context = priv->print_context;
+  
+  page_setup = create_page_setup (op);
+  
+  g_signal_emit (op, signals[REQUEST_PAGE_SETUP], 0, 
+		 print_context, page_nr, page_setup);
+  
+  _gtk_print_context_set_page_setup (print_context, page_setup);
+  
+  /* TODO: override for preview */
+  priv->start_page (op, print_context, page_setup);
+  
+  cr = gtk_print_context_get_cairo_context (print_context);
+  
+  cairo_save (cr);
+  if (priv->manual_scale != 1.0)
+    cairo_scale (cr,
+		 priv->manual_scale,
+		 priv->manual_scale);
+  
+  if (priv->manual_orientation)
+    _gtk_print_context_rotate_according_to_orientation (print_context);
+  
+  if (!priv->use_full_page)
+    _gtk_print_context_translate_into_margin (print_context);
+  
+  g_signal_emit (op, signals[DRAW_PAGE], 0, 
+		 print_context, page_nr);
+
+  /* TODO: override for preview */
+  priv->end_page (op, print_context);
+  
+  cairo_restore (cr);
+
+  g_object_unref (page_setup);
+}
+
 static gboolean
 print_pages_idle (gpointer user_data)
 {
   PrintPagesData *data; 
   GtkPrintOperationPrivate *priv; 
   GtkPageSetup *page_setup;
-  cairo_t *cr;
   gboolean done = FALSE;
 
+  g_print ("print_pages_idle\n");
+  
   GDK_THREADS_ENTER ();
 
   data = (PrintPagesData*)user_data;
@@ -1656,15 +1958,15 @@ print_pages_idle (gpointer user_data)
 
   if (priv->status == GTK_PRINT_STATUS_PREPARING)
     {
-      if (!data->print_context)
+      if (!data->initialized)
 	{
-	  data->print_context = _gtk_print_context_new (data->op);
-	  data->initial_page_setup = create_page_setup (data->op);
-
-	  _gtk_print_context_set_page_setup (data->print_context, 
-					     data->initial_page_setup);
+	  data->initialized = TRUE;
+	  page_setup = create_page_setup (data->op);
+	  _gtk_print_context_set_page_setup (priv->print_context, 
+					     page_setup);
+	  g_object_unref (page_setup);
       
-	  g_signal_emit (data->op, signals[BEGIN_PRINT], 0, data->print_context);
+	  g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
       
 	  if (priv->manual_collation)
 	    {
@@ -1684,7 +1986,7 @@ print_pages_idle (gpointer user_data)
 	{
 	  gboolean paginated = FALSE;
 
-	  g_signal_emit (data->op, signals[PAGINATE], 0, data->print_context, &paginated);
+	  g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated);
 	  if (!paginated)
 	    goto out;
 	}
@@ -1751,36 +2053,18 @@ print_pages_idle (gpointer user_data)
 	  goto out;
 	}
     }
+ 
+  if (data->is_preview)
+    {
+      done = TRUE;
 
-  page_setup = gtk_page_setup_copy (data->initial_page_setup);
-  g_signal_emit (data->op, signals[REQUEST_PAGE_SETUP], 0, 
-		 data->print_context, data->page, page_setup);
-  
-  _gtk_print_context_set_page_setup (data->print_context, page_setup);
-  priv->start_page (data->op, data->print_context, page_setup);
-  
-  cr = gtk_print_context_get_cairo_context (data->print_context);
-  
-  cairo_save (cr);
-  if (priv->manual_scale != 1.0)
-    cairo_scale (cr,
-		 priv->manual_scale,
-		 priv->manual_scale);
-  
-  if (priv->manual_orientation)
-    _gtk_print_context_rotate_according_to_orientation (data->print_context);
-  
-  if (!priv->use_full_page)
-    _gtk_print_context_translate_into_margin (data->print_context);
-  
-  g_signal_emit (data->op, signals[DRAW_PAGE], 0, 
-		 data->print_context, data->page);
-  
-  priv->end_page (data->op, data->print_context);
-  
-  cairo_restore (cr);
-  
-  g_object_unref (page_setup);
+      g_object_ref (data->op);
+      
+      g_signal_emit_by_name (data->op, "ready", priv->print_context);
+      goto out;
+    }
+
+  common_render_page (data->op, data->page);
 
  out:
 
@@ -1791,11 +2075,9 @@ print_pages_idle (gpointer user_data)
       done = TRUE;
     }
 
-  if (done)
+  if (done && !data->is_preview)
     {
-      g_signal_emit (data->op, signals[END_PRINT], 0, data->print_context);
-      
-      cairo_surface_finish (priv->surface);
+      g_signal_emit (data->op, signals[END_PRINT], 0, priv->print_context);
       priv->end_run (data->op, priv->is_sync, priv->cancelled);
     }
 
@@ -1833,15 +2115,19 @@ show_progress_timeout (PrintPagesData *d
 
 static void
 print_pages (GtkPrintOperation *op,
-	     GtkWindow         *parent)
+	     GtkWindow         *parent,
+	     gboolean		is_preview)
 {
   GtkPrintOperationPrivate *priv = op->priv;
   PrintPagesData *data;
- 
+
+  g_print ("print_pages\n");
+  
   _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_PREPARING, NULL);  
 
   data = g_new0 (PrintPagesData, 1);
   data->op = g_object_ref (op);
+  data->is_preview = is_preview;
 
   if (priv->show_progress)
     {
@@ -1862,6 +2148,37 @@ print_pages (GtkPrintOperation *op,
       data->progress = progress;
     }
 
+  if (is_preview)
+    {
+      gboolean handled;
+      
+      g_signal_emit_by_name (op, "preview",
+			     GTK_PRINT_OPERATION_PREVIEW (op),
+			     op->priv->print_context,
+			     parent,
+			     &handled);
+      
+      if (!handled ||
+	  gtk_print_context_get_cairo_context (priv->print_context) == NULL) {
+	/* TODO: handle error */
+      }
+      
+      priv->start_page = preview_start_page;
+      priv->end_page = preview_end_page;
+      priv->end_run = preview_end_run;
+
+      /* TODO: Do we really need to set these? */
+      priv->print_pages = GTK_PRINT_PAGES_ALL;
+      priv->page_ranges = NULL;
+      priv->num_page_ranges = 0;
+      priv->manual_num_copies = 1;
+      priv->manual_collation = FALSE;
+      priv->manual_reverse = FALSE;
+      priv->manual_page_set = GTK_PAGE_SET_ALL;
+      priv->manual_scale = 1.0;
+      priv->manual_orientation = TRUE;
+    }
+  
   priv->print_pages_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
 					       print_pages_idle, 
 					       data, 
@@ -1877,9 +2194,10 @@ print_pages (GtkPrintOperation *op,
       GDK_THREADS_LEAVE ();
       g_main_loop_run (priv->rloop);
       GDK_THREADS_ENTER ();
+      
+      g_main_loop_unref (priv->rloop);
+      priv->rloop = NULL;
     }
-  g_main_loop_unref (priv->rloop);
-  priv->rloop = NULL;
 }
 
 /**
@@ -1964,7 +2282,7 @@ gtk_print_operation_run (GtkPrintOperati
 							       &do_print,
 							       error);
   if (do_print)
-    print_pages (op, parent);
+    print_pages (op, parent, result == GTK_PRINT_OPERATION_RESULT_PREVIEW);
   else 
     _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
 
@@ -2006,7 +2324,7 @@ gtk_print_operation_run_async (GtkPrintO
     {
       run_pdf (op, parent, &do_print, NULL);
       if (do_print)
-	print_pages (op, parent);
+	print_pages (op, parent, FALSE);
       else 
 	_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
     }
Index: gtk/gtkprintoperation.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation.h,v
retrieving revision 1.10
diff -u -p -r1.10 gtkprintoperation.h
--- gtk/gtkprintoperation.h	24 May 2006 16:15:14 -0000	1.10
+++ gtk/gtkprintoperation.h	1 Jun 2006 20:34:39 -0000
@@ -29,6 +29,7 @@
 #include "gtkpagesetup.h"
 #include "gtkprintsettings.h"
 #include "gtkprintcontext.h"
+#include "gtkprintoperationpreview.h"
 
 G_BEGIN_DECLS
 
@@ -84,7 +85,13 @@ struct _GtkPrintOperationClass
   GtkWidget *(*create_custom_widget) (GtkPrintOperation *operation);
   void       (*custom_widget_apply)  (GtkPrintOperation *operation,
 				      GtkWidget *widget);
+
   
+  gboolean (*preview)	     (GtkPrintOperation        *operation,
+			      GtkPrintOperationPreview *preview, 
+			      GtkPrintContext          *context,
+			      GtkWindow                *parent);  
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
@@ -98,7 +105,8 @@ struct _GtkPrintOperationClass
 typedef enum {
   GTK_PRINT_OPERATION_RESULT_ERROR,
   GTK_PRINT_OPERATION_RESULT_APPLY,
-  GTK_PRINT_OPERATION_RESULT_CANCEL
+  GTK_PRINT_OPERATION_RESULT_CANCEL,
+  GTK_PRINT_OPERATION_RESULT_PREVIEW
 } GtkPrintOperationResult;
 
 #define GTK_PRINT_ERROR gtk_print_error_quark ()
Index: gtk/gtkprintoperationpreview.c
===================================================================
RCS file: gtk/gtkprintoperationpreview.c
diff -N gtk/gtkprintoperationpreview.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gtk/gtkprintoperationpreview.c	1 Jun 2006 20:34:39 -0000
@@ -0,0 +1,107 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperationpreview.c: Abstract print preview interface
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gtkprintoperationpreview.h"
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+
+static void gtk_print_operation_preview_base_init (gpointer g_iface);
+
+GType
+gtk_print_operation_preview_get_type (void)
+{
+  static GType print_operation_preview_type = 0;
+
+  if (!print_operation_preview_type)
+    {
+      static const GTypeInfo print_operation_preview_info =
+      {
+        sizeof (GtkPrintOperationPreviewIface), /* class_size */
+	gtk_print_operation_preview_base_init,   /* base_init */
+	NULL,		/* base_finalize */
+	NULL,
+	NULL,		/* class_finalize */
+	NULL,		/* class_data */
+	0,
+	0,              /* n_preallocs */
+	NULL
+      };
+
+      print_operation_preview_type =
+	g_type_register_static (G_TYPE_INTERFACE, I_("GtkPrintOperationPreview"),
+				&print_operation_preview_info, 0);
+
+      g_type_interface_add_prerequisite (print_operation_preview_type, G_TYPE_OBJECT);
+    }
+
+  return print_operation_preview_type;
+}
+
+static void
+gtk_print_operation_preview_base_init (gpointer g_iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      g_signal_new (I_("ready"),
+		    GTK_TYPE_PRINT_OPERATION_PREVIEW,
+		    G_SIGNAL_RUN_LAST,
+		    G_STRUCT_OFFSET (GtkPrintOperationPreviewIface, ready),
+		    NULL, NULL,
+		    g_cclosure_marshal_VOID__OBJECT,
+		    G_TYPE_NONE, 1,
+		    G_TYPE_OBJECT);
+
+      g_signal_new (I_("got-page-size"),
+		    GTK_TYPE_PRINT_OPERATION_PREVIEW,
+		    G_SIGNAL_RUN_LAST,
+		    G_STRUCT_OFFSET (GtkPrintOperationPreviewIface, ready),
+		    NULL, NULL,
+		    _gtk_marshal_VOID__OBJECT_OBJECT,
+		    G_TYPE_NONE, 2,
+		    GTK_TYPE_PRINT_CONTEXT,
+		    GTK_TYPE_PAGE_SETUP);
+
+      initialized = TRUE;
+    }
+}
+
+
+void    
+gtk_print_operation_preview_render_page (GtkPrintOperationPreview *preview,
+					 gint			   page_nr)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION_PREVIEW (preview));
+
+  GTK_PRINT_OPERATION_PREVIEW_GET_IFACE (preview)->render_page (preview,
+								page_nr);
+}
+
+void
+gtk_print_operation_preview_end_preview (GtkPrintOperationPreview *preview)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION_PREVIEW (preview));
+
+  GTK_PRINT_OPERATION_PREVIEW_GET_IFACE (preview)->end_preview (preview);
+}
+
Index: gtk/gtkprintoperationpreview.h
===================================================================
RCS file: gtk/gtkprintoperationpreview.h
diff -N gtk/gtkprintoperationpreview.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gtk/gtkprintoperationpreview.h	1 Jun 2006 20:34:39 -0000
@@ -0,0 +1,75 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperationpreview.h: Abstract print preview interface
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_OPERATION_PREVIEW_H__
+#define __GTK_PRINT_OPERATION_PREVIEW_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include "gtkprintcontext.h" 
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_OPERATION_PREVIEW                  (gtk_print_operation_preview_get_type ())
+#define GTK_PRINT_OPERATION_PREVIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW, GtkPrintOperationPreview))
+#define GTK_IS_PRINT_OPERATION_PREVIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW))
+#define GTK_PRINT_OPERATION_PREVIEW_GET_IFACE(obj)        (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW, GtkPrintOperationPreviewIface))
+
+typedef struct _GtkPrintOperationPreview      GtkPrintOperationPreview;      /*dummy typedef */
+typedef struct _GtkPrintOperationPreviewIface GtkPrintOperationPreviewIface;
+
+
+struct _GtkPrintOperationPreviewIface
+{
+  GTypeInterface g_iface;
+
+  /* signals */
+  void              (*ready)          (GtkPrintOperationPreview *preview, 
+				       GtkPrintContext          *context);
+  void              (*got_page_size)  (GtkPrintOperationPreview *preview, 
+				       GtkPrintContext          *context,
+				       GtkPageSetup             *page_setup);
+ 
+  /* methods */
+  void              (*render_page)    (GtkPrintOperationPreview *preview,
+				       gint                      page_nr);
+  void              (*end_preview)    (GtkPrintOperationPreview *preview);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType   gtk_print_operation_preview_get_type       (void) G_GNUC_CONST;
+
+void    gtk_print_operation_preview_render_page    (GtkPrintOperationPreview *preview,
+						    gint                      page_nr);
+void    gtk_print_operation_preview_render_sheet   (GtkPrintOperationPreview *preview,
+						    gint                      page_nr);
+void    gtk_print_operation_preview_end_preview    (GtkPrintOperationPreview *preview); 
+
+
+#endif /* __GTK_PRINT_OPERATION_PREVIEW_H__ */
Index: gtk/gtkprintunixdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintunixdialog.c,v
retrieving revision 1.22
diff -u -p -r1.22 gtkprintunixdialog.c
--- gtk/gtkprintunixdialog.c	1 Jun 2006 04:58:18 -0000	1.22
+++ gtk/gtkprintunixdialog.c	1 Jun 2006 20:34:39 -0000
@@ -275,7 +275,8 @@ gtk_print_unix_dialog_init (GtkPrintUnix
 		    (GCallback) gtk_print_unix_dialog_destroy, 
 		    NULL);
 
-  gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+			  GTK_STOCK_PRINT_PREVIEW, GTK_RESPONSE_APPLY, 
 			  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 			  GTK_STOCK_PRINT, GTK_RESPONSE_OK,
                           NULL);
Index: tests/print-editor.c
===================================================================
RCS file: /cvs/gnome/gtk+/tests/print-editor.c,v
retrieving revision 1.7
diff -u -p -r1.7 print-editor.c
--- tests/print-editor.c	31 May 2006 14:06:02 -0000	1.7
+++ tests/print-editor.c	1 Jun 2006 20:34:39 -0000
@@ -262,6 +262,7 @@ begin_print (GtkPrintOperation *operatio
   int num_lines;
   int line;
 
+  g_print ("begin-print\n");
   width = gtk_print_context_get_width (context);
   height = gtk_print_context_get_height (context);
 
@@ -304,6 +305,7 @@ begin_print (GtkPrintOperation *operatio
   
   print_data->page_breaks = page_breaks;
   
+  g_print ("found %d pages\n", g_list_length (page_breaks));
 }
 
 static void
@@ -317,6 +319,9 @@ draw_page (GtkPrintOperation *operation,
   int start, end, i;
   PangoLayoutIter *iter;
   double start_pos;
+
+  g_print ("draw-page %d\n", page_nr);
+
   if (page_nr == 0)
     start = 0;
   else
@@ -430,17 +435,205 @@ custom_widget_apply (GtkPrintOperation *
   data->font = g_strdup (selected_font);
 }
 
+typedef struct 
+{
+  GtkPrintOperation *op;
+  GtkPrintOperationPreview *preview;
+  GtkWidget         *spin;
+  GtkWidget         *area;
+  gint               page;
+  PrintData *data;
+  gdouble dpi_x, dpi_y;
+} PreviewOp;
+
+static gboolean
+preview_expose (GtkWidget      *widget,
+		GdkEventExpose *event,
+		gpointer        data)
+{
+  PreviewOp *pop = data;
+
+  gdk_window_clear (pop->area->window);
+  gtk_print_operation_preview_render_page (pop->preview,
+					   pop->page - 1);
+
+  return TRUE;
+}
+
+static void
+preview_ready (GtkPrintOperationPreview *preview,
+	       GtkPrintContext          *context,
+	       gpointer                  data)
+{
+  PreviewOp *pop = data;
+  gint n_pages;
+
+  g_object_get (pop->op, "n-pages", &n_pages, NULL);
+  g_print ("ready to preview %d pages\n", n_pages);
+
+  gtk_spin_button_set_range (GTK_SPIN_BUTTON (pop->spin), 
+			     1.0, n_pages);
+
+  g_signal_connect (pop->area, "expose_event",
+		    G_CALLBACK (preview_expose),
+		    pop);
+
+  gtk_widget_queue_draw (pop->area);
+}
+
+static void
+preview_got_page_size (GtkPrintOperationPreview *preview, 
+		       GtkPrintContext          *context,
+		       GtkPageSetup             *page_setup,
+		       gpointer                  data)
+{
+  PreviewOp *pop = data;
+  GtkPaperSize *paper_size;
+  double w, h;
+  cairo_t *cr;
+  gdouble dpi_x, dpi_y;
+
+  paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+  w = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
+  h = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
+
+  cr = gdk_cairo_create (pop->area->window);
+
+  dpi_x = pop->area->allocation.width/w;
+  dpi_y = pop->area->allocation.height/h;
+  
+  g_print ("new dpi: %f, %f\n", dpi_x, dpi_y);
+  if (fabs (dpi_x - pop->dpi_x) > 0.001 ||
+      fabs (dpi_y - pop->dpi_y) > 0.001)
+    {
+      gtk_print_context_set_cairo_context (context, cr, dpi_x, dpi_y);
+      pop->dpi_x = dpi_x;
+      pop->dpi_y = dpi_y;
+    }
+
+  pango_cairo_update_layout (cr, pop->data->layout);
+  cairo_destroy (cr);
+}
+
+static void
+update_page (GtkSpinButton *widget,
+	     gpointer       data)
+{
+  PreviewOp *pop = data;
+
+  pop->page = gtk_spin_button_get_value_as_int (widget);
+  g_print ("go to page %d\n", pop->page);
+  gtk_widget_queue_draw (pop->area);
+}
+
+static void
+preview_destroy (GtkWindow *window, 
+		 PreviewOp *pop)
+{
+  gtk_print_operation_preview_end_preview (pop->preview);
+  g_object_unref (pop->op);
+
+  g_free (pop);
+}
+
+static gboolean 
+do_preview (GtkPrintOperation        *op,
+	    GtkPrintOperationPreview *preview,
+	    GtkPrintContext          *context,
+	    GtkWindow                *parent,
+	    gpointer                  data)
+{
+  GtkPrintSettings *settings;
+  GtkWidget *window, *close, *page, *hbox, *vbox, *da;
+  gdouble width, height;
+  cairo_t *cr;
+  PreviewOp *pop;
+  PrintData *print_data = data;
+
+  pop = g_new0 (PreviewOp, 1);
+
+  pop->data = print_data;
+  settings = gtk_print_operation_get_print_settings (op);
+
+#if 0
+  /* FIXME need to figure out the size */
+  width = gtk_print_settings_get_paper_width (settings, GTK_UNIT_PIXEL);
+  height = gtk_print_settings_get_paper_height (settings, GTK_UNIT_PIXEL);
+
+  g_print ("%f x %f\n", width, height);
+#endif
+  width = 200;
+  height = 300;
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_transient_for (GTK_WINDOW (window), 
+				GTK_WINDOW (main_window));
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox,
+		      FALSE, FALSE, 0);
+  page = gtk_spin_button_new_with_range (1, 100, 1);
+  gtk_box_pack_start (GTK_BOX (hbox), page, FALSE, FALSE, 0);
+  
+  close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+  gtk_box_pack_start (GTK_BOX (hbox), close, FALSE, FALSE, 0);
+
+  da = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (GTK_WIDGET (da), width, height);
+  gtk_box_pack_start (GTK_BOX (vbox), da, TRUE, TRUE, 0);
+
+  gtk_widget_set_double_buffered (da, FALSE);
+
+  gtk_widget_realize (da);
+  
+  cr = gdk_cairo_create (da->window);
+
+  /* TODO: What dpi to use here? This will be used for pagination.. */
+  gtk_print_context_set_cairo_context (context, cr, 72, 72);
+  cairo_destroy (cr);
+  
+  pop->op = op;
+  pop->preview = preview;
+  pop->spin = page;
+  pop->area = da;
+  pop->page = 1;
+
+  g_signal_connect (page, "value-changed", 
+		    G_CALLBACK (update_page), pop);
+  g_signal_connect_swapped (close, "clicked", 
+			    G_CALLBACK (gtk_widget_destroy), window);
+
+  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_widget_show_all (window);
+  
+  return TRUE;
+}
+
+/* FIXME had to move this to the heap, since previewing
+ * returns too early from the sync api 
+ */
+PrintData *print_data;
+
 static void
 do_print (GtkAction *action)
 {
   GtkWidget *error_dialog;
   GtkPrintOperation *print;
-  PrintData print_data;
   GtkPrintOperationResult res;
   GError *error;
 
-  print_data.text = get_text ();
-  print_data.font = g_strdup ("Sans 12");
+  print_data = g_new0 (PrintData, 1);
+
+  print_data->text = get_text ();
+  print_data->font = g_strdup ("Sans 12");
 
   print = gtk_print_operation_new ();
 
@@ -452,12 +645,15 @@ do_print (GtkAction *action)
   if (page_setup != NULL)
     gtk_print_operation_set_default_page_setup (print, page_setup);
   
-  g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), &print_data);
-  g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), &print_data);
-  g_signal_connect (print, "create_custom_widget", G_CALLBACK (create_custom_widget), &print_data);
-  g_signal_connect (print, "custom_widget_apply", G_CALLBACK (custom_widget_apply), &print_data);
-  
+  g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), print_data);
+  g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), print_data);
+  g_signal_connect (print, "create_custom_widget", G_CALLBACK (create_custom_widget), print_data);
+  g_signal_connect (print, "custom_widget_apply", G_CALLBACK (custom_widget_apply), print_data);
+  g_signal_connect (print, "preview", G_CALLBACK (do_preview), print_data);
+
   error = NULL;
+
+#if 1
   res = gtk_print_operation_run (print, GTK_WINDOW (main_window), &error);
 
   if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
@@ -467,7 +663,7 @@ do_print (GtkAction *action)
 					     GTK_MESSAGE_ERROR,
 					     GTK_BUTTONS_CLOSE,
 					     "Error printing file:\n%s",
-					     error->message);
+					     error ? error->message : "no details");
       g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
       gtk_widget_show (error_dialog);
       g_error_free (error);
@@ -489,10 +685,15 @@ do_print (GtkAction *action)
       g_signal_connect (print, "status_changed",
 			G_CALLBACK (status_changed_cb), NULL);
     }
+#else
+  gtk_print_operation_run_async (print, GTK_WINDOW (main_window));
+#endif
 
   g_object_unref (print);
+#if 0
   g_free (print_data.text);
   g_free (print_data.font);
+#endif
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]