]> Pileus Git - ~andy/gtk/commitdiff
Add gtkprintoperationpreview.[ch] Set default preview command. Hardcoded
authorAlexander Larsson <alexl@redhat.com>
Fri, 2 Jun 2006 15:16:13 +0000 (15:16 +0000)
committerAlexander Larsson <alexl@src.gnome.org>
Fri, 2 Jun 2006 15:16:13 +0000 (15:16 +0000)
2006-06-02  Alexander Larsson  <alexl@redhat.com>

* gtk/Makefile.am:
Add gtkprintoperationpreview.[ch]
Set default preview command. Hardcoded for now.

* gtk/gtkmarshalers.list:
Add BOOLEAN:OBJECT,OBJECT,OBJECT

* gtk/gtkprintbackend.c:
Add preview command property.

* gtk/gtkprintcontext.[ch]:
Make less dependent on PrintOperation for output settings
Externally set cairo_t and dpi. Resettable.
Create fontmap without metrics hinting (so that print preview
text layout doesn't depend on zoom level).

* gtk/gtkprintoperation-private.h:
* gtk/gtkprintoperation-unix.c:
* gtk/gtkprintoperation.[ch]:
Initial work on print preview API and default implementation
using an external preview app.

* gtk/gtkprintoperation-win32.c:
Some needed updates. Not done, needs more work.

* gtk/gtkprintoperationpreview.[ch]:
New interface used in print preview api.

* gtk/gtkprintunixdialog.c:
Add print preview dialog.

* tests/print-editor.c:
Test using an custom print preview widget.

16 files changed:
ChangeLog
ChangeLog.pre-2-10
gtk/Makefile.am
gtk/gtkmarshalers.list
gtk/gtkprintbackend.c
gtk/gtkprintcontext.c
gtk/gtkprintcontext.h
gtk/gtkprintoperation-private.h
gtk/gtkprintoperation-unix.c
gtk/gtkprintoperation-win32.c
gtk/gtkprintoperation.c
gtk/gtkprintoperation.h
gtk/gtkprintoperationpreview.c [new file with mode: 0644]
gtk/gtkprintoperationpreview.h [new file with mode: 0644]
gtk/gtkprintunixdialog.c
tests/print-editor.c

index d0505a9fad1fb55f96ebe886c2d43d9b6bd35936..e9e5a46539383620343ecac9270c5a4ff8d58453 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2006-06-02  Alexander Larsson  <alexl@redhat.com>
+
+       * gtk/Makefile.am:
+       Add gtkprintoperationpreview.[ch]
+       Set default preview command. Hardcoded for now.
+       
+       * gtk/gtkmarshalers.list:
+       Add BOOLEAN:OBJECT,OBJECT,OBJECT
+       
+       * gtk/gtkprintbackend.c:
+       Add preview command property.
+       
+       * gtk/gtkprintcontext.[ch]:
+       Make less dependent on PrintOperation for output settings
+       Externally set cairo_t and dpi. Resettable.
+       Create fontmap without metrics hinting (so that print preview
+       text layout doesn't depend on zoom level).
+       
+       * gtk/gtkprintoperation-private.h:
+       * gtk/gtkprintoperation-unix.c: 
+       * gtk/gtkprintoperation.[ch]:
+       Initial work on print preview API and default implementation
+       using an external preview app.
+       
+       * gtk/gtkprintoperation-win32.c:
+       Some needed updates. Not done, needs more work.
+       
+       * gtk/gtkprintoperationpreview.[ch]:
+       New interface used in print preview api.
+       
+       * gtk/gtkprintunixdialog.c:
+       Add print preview dialog.
+       
+       * tests/print-editor.c:
+       Test using an custom print preview widget.
+
 2006-06-02  Emmanuele Bassi  <ebassi@gnome.org>
 
        * gtk/gtkrecentmanager.c
index d0505a9fad1fb55f96ebe886c2d43d9b6bd35936..e9e5a46539383620343ecac9270c5a4ff8d58453 100644 (file)
@@ -1,3 +1,39 @@
+2006-06-02  Alexander Larsson  <alexl@redhat.com>
+
+       * gtk/Makefile.am:
+       Add gtkprintoperationpreview.[ch]
+       Set default preview command. Hardcoded for now.
+       
+       * gtk/gtkmarshalers.list:
+       Add BOOLEAN:OBJECT,OBJECT,OBJECT
+       
+       * gtk/gtkprintbackend.c:
+       Add preview command property.
+       
+       * gtk/gtkprintcontext.[ch]:
+       Make less dependent on PrintOperation for output settings
+       Externally set cairo_t and dpi. Resettable.
+       Create fontmap without metrics hinting (so that print preview
+       text layout doesn't depend on zoom level).
+       
+       * gtk/gtkprintoperation-private.h:
+       * gtk/gtkprintoperation-unix.c: 
+       * gtk/gtkprintoperation.[ch]:
+       Initial work on print preview API and default implementation
+       using an external preview app.
+       
+       * gtk/gtkprintoperation-win32.c:
+       Some needed updates. Not done, needs more work.
+       
+       * gtk/gtkprintoperationpreview.[ch]:
+       New interface used in print preview api.
+       
+       * gtk/gtkprintunixdialog.c:
+       Add print preview dialog.
+       
+       * tests/print-editor.c:
+       Test using an custom print preview widget.
+
 2006-06-02  Emmanuele Bassi  <ebassi@gnome.org>
 
        * gtk/gtkrecentmanager.c
index d04a1cf666a832a0887560d7f1858599ec8a44eb..136527b9193ef2089ad3e8ab3f0719111576902d 100644 (file)
@@ -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 88511709e56dc87bd4694cba269477eb7cb38e9b..e089d1335115ca7255fff463a0ce94f6f82a3064 100644 (file)
@@ -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 a2af6c4865326437fd2bf0fb93fb788df7d50239..1a139deb52d998b1a001ed7e4a9aa9d1a8d1e89d 100644 (file)
@@ -191,7 +191,7 @@ _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
   return NULL;
 }
 
-GtkPrintBackend *
+static GtkPrintBackend *
 _gtk_print_backend_create (const char *backend_name)
 {
   GSList *l;
@@ -200,7 +200,6 @@ _gtk_print_backend_create (const char *backend_name)
   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 5e68ae21732f0329df0cff5a69993b9ff0e5ed8b..219a830ea6807426b15c437de2f743f58171292f 100644 (file)
@@ -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 *object)
   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 (GtkPrintContextClass *class)
 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 (GtkPrintOperation *op)
       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_orientation (GtkPrintContext *context)
   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 (GtkPrintContext *context)
   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 (GtkPrintContext *context)
     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 (GtkPrintContext *context)
   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 (GtkPrintContext *context)
 {
   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 (GtkPrintContext *context)
 {
   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 0ce480087fdabcb54ef13aeb7681e41fe4758573..936cae4f4033a1dd004b1a1b3ac46af5313b5e32 100644 (file)
@@ -51,6 +51,11 @@ PangoFontMap *gtk_print_context_get_pango_fontmap    (GtkPrintContext *context);
 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 c44f1b492399f0e7dba28f4f55c7be365aa15279..7edfc0cdce0c7077225d01c4f033fc7c97257821 100644 (file)
@@ -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;
@@ -78,17 +80,29 @@ struct _GtkPrintOperationPrivate
                      gboolean           cancelled);
 };
 
-GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *operation,
-                                                                         GtkWindow         *parent,
-                                                                         gboolean          *do_print,
-                                                                         GError           **error);
 
 typedef void (* GtkPrintOperationPrintFunc) (GtkPrintOperation *op,
-                                            GtkWindow         *parent);
-
-void _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
-                                                            GtkWindow                  *parent,
-                                                            GtkPrintOperationPrintFunc  print_cb);
+                                            GtkWindow         *parent,
+                                            gboolean           is_preview);
+
+GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog             (GtkPrintOperation           *operation,
+                                                                                     GtkWindow                   *parent,
+                                                                                     gboolean                    *do_print,
+                                                                                     GError                     **error);
+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           *op,
+                                                                                     GtkPageSetup                *page_setup,
+                                                                                     gdouble                     *dpi_x,
+                                                                                     gdouble                     *dpi_y,
+                                                                                     const gchar                 *target);
+void                    _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation           *op,
+                                                                                     GtkPageSetup                *page_setup,
+                                                                                     cairo_surface_t             *surface);
 
 void _gtk_print_operation_set_status (GtkPrintOperation *op,
                                      GtkPrintStatus     status,
index cf57ec62901c98d08a92e292e01b48aa9c10bdd0..d6b486a486e80c0136605caf34a123ad8ee6b3d7 100644 (file)
@@ -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"
 #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_unix)
   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,70 @@ 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;
+  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);
+      priv->print_context = _gtk_print_context_new (op);
+      _gtk_print_context_set_page_setup (priv->print_context, page_setup);
 
-      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);
+         
+         op_unix->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
+         if (op_unix->surface == NULL) {
+           rdata->do_print = FALSE;
+           goto out;
+         }
+         
+         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:  
+ 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 +445,7 @@ finish_print (PrintResponseData *rdata,
     rdata->destroy (rdata);
 }
 
-static void
+static void 
 handle_print_response (GtkWidget *dialog,
                       gint       response,
                       gpointer   data)
@@ -335,24 +461,31 @@ handle_print_response (GtkWidget *dialog,
       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
 
       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
-      if (printer == NULL)
-       goto out;
-      
+      if (printer != NULL)
+       rdata->do_print = TRUE;
+    } 
+  else if (response == GTK_RESPONSE_APPLY)
+    {
+      /* print preview */
+      rdata->result = GTK_PRINT_OPERATION_RESULT_PREVIEW;
       rdata->do_print = TRUE;
+    }
 
+  if (rdata->do_print)
+    {
       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));
-
+      
       g_signal_emit_by_name (rdata->op, "custom-widget-apply", rdata->op->priv->custom_widget);
-    } 
-
- out:  
+    }
+  
   finish_print (rdata, printer, page_setup, settings);
 
   if (settings)
     g_object_unref (settings);
-  
+    
   gtk_widget_destroy (GTK_WIDGET (pd));
 }
 
 
@@ -436,6 +569,39 @@ _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation
     }
 }
 
+cairo_surface_t *
+_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
+                                                             GtkPageSetup *page_setup,
+                                                             gdouble *dpi_x,
+                                                             gdouble *dpi_y,
+                                                             const gchar *target)
+{
+  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);
+    
+  *dpi_x = *dpi_y = 72;
+  return cairo_pdf_surface_create (target, w, h);
+}
+
+void
+_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
+                                                             GtkPageSetup *page_setup,
+                                                             cairo_surface_t *surface)
+{
+  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);
+  cairo_pdf_surface_set_size (surface, w, h);
+}
+
+
 GtkPrintOperationResult
 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
                                                  GtkWindow         *parent,
@@ -459,6 +625,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
   if (op->priv->show_dialog)
     {
       pd = get_print_dialog (op, parent);
+
       response = gtk_dialog_run (GTK_DIALOG (pd));
       handle_print_response (pd, response, &rdata);
     }
@@ -477,6 +644,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
       GDK_THREADS_ENTER ();  
 
       g_main_loop_unref (rdata.loop);
+      rdata.loop = NULL;
     }
 
   *do_print = rdata.do_print;
index 97e1aaa605785f09023393b1d3df2965adeb66bc..c546ea4c835c9ed9ae061f416336779fed0b43f7 100644 (file)
@@ -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 efc211fc5c31423876fa08a49095c30954a807a3..d4f8fa25a340bd61ea8ff6cef4073b52d8691e41 100644 (file)
  */
 
 #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:
@@ -145,6 +158,94 @@ gtk_print_operation_init (GtkPrintOperation *operation)
   priv->job_name = g_strdup_printf ("%s job #%d", appname, ++job_nr);
 }
 
+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 gboolean
+preview_iface_is_selected (GtkPrintOperationPreview *preview,
+                          gint                      page_nr)
+{
+  GtkPrintOperation *op;
+  GtkPrintOperationPrivate *priv;
+  int i;
+  
+  op = GTK_PRINT_OPERATION (preview);
+  priv = op->priv;
+  
+  switch (priv->print_pages)
+    {
+    case GTK_PRINT_PAGES_ALL:
+      return (page_nr >= 0) && (page_nr < priv->nr_of_pages);
+    case GTK_PRINT_PAGES_CURRENT:
+      return page_nr == priv->current_page;
+    case GTK_PRINT_PAGES_RANGES:
+      for (i = 0; i < priv->num_page_ranges; i++)
+       {
+         if (page_nr >= priv->page_ranges[i].start &&
+             page_nr <= priv->page_ranges[i].end)
+           return TRUE;
+       }
+      return FALSE;
+    }
+  return FALSE;
+}
+
+static void
+preview_iface_init (GtkPrintOperationPreviewIface *iface)
+{
+  iface->render_page = preview_iface_render_page;
+  iface->end_preview = preview_iface_end_preview;
+  iface->is_selected = preview_iface_is_selected;
+}
+
+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)
+{
+  g_free (op->priv->page_ranges);
+  op->priv->page_ranges = NULL;
+
+  _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
+}
+
+
 static void
 gtk_print_operation_set_property (GObject      *object,
                                  guint         prop_id,
@@ -256,6 +357,151 @@ gtk_print_operation_get_property (GObject    *object,
     }
 }
 
+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;
+
+  GDK_THREADS_ENTER ();
+  
+  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);
+  
+  GDK_THREADS_LEAVE ();
+}
+
+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);
+
+  _gtk_print_operation_platform_backend_resize_preview_surface (op, page_setup, pop->surface);
+}
+
+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 dpi_x, dpi_y;
+  gchar *tmp_dir;
+  gchar *dir_template;
+  gchar *preview_filename;
+  PreviewOp *pop;
+  GtkPageSetup *page_setup;
+  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;
+
+  page_setup = gtk_print_context_get_page_setup (context);
+
+  pop->surface =
+    _gtk_print_operation_platform_backend_create_preview_surface (op,
+                                                                 page_setup,
+                                                                 &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 +533,8 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class)
   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 +777,36 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class)
                  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.
+   *
+   * If you don't override this a default implementation using an external
+   * viewer will be used.
+   *
+   * 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 +1713,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 +1721,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 +1740,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 +1754,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 +1765,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,
-                                           width, height);
-  cairo_pdf_surface_set_dpi (priv->surface, 300, 300);
-  
-  priv->dpi_x = 72;
-  priv->dpi_y = 72;
+  surface = cairo_pdf_surface_create (priv->pdf_target,
+                                     width, height);
+  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 +1811,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 +1887,9 @@ print_pages_idle_done (gpointer user_data)
   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,13 +1925,56 @@ 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);
+  
+  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);
+
+  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;
 
   GDK_THREADS_ENTER ();
@@ -1656,15 +1984,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 +2012,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 +2079,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 +2101,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 +2141,17 @@ show_progress_timeout (PrintPagesData *data)
 
 static void
 print_pages (GtkPrintOperation *op,
-            GtkWindow         *parent)
+            GtkWindow         *parent,
+            gboolean           is_preview)
 {
   GtkPrintOperationPrivate *priv = op->priv;
   PrintPagesData *data;
+
   _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 +2172,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) {
+       /* Programmer error */
+       g_error ("You must set a cairo context on the print context");
+      }
+      
+      priv->start_page = preview_start_page;
+      priv->end_page = preview_end_page;
+      priv->end_run = preview_end_run;
+
+      priv->print_pages = gtk_print_settings_get_print_pages (priv->print_settings);
+      priv->page_ranges = gtk_print_settings_get_page_ranges (priv->print_settings,
+                                                             &priv->num_page_ranges);
+      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 +2218,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 +2306,7 @@ gtk_print_operation_run (GtkPrintOperation  *op,
                                                               &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 +2348,7 @@ gtk_print_operation_run_async (GtkPrintOperation *op,
     {
       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 8f430850fafb95ff9b571fa77c8a513df7926321..4b8443c0645bcf9d3440b6558561d76ffa96f35a 100644 (file)
@@ -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 ()
diff --git a/gtk/gtkprintoperationpreview.c b/gtk/gtkprintoperationpreview.c
new file mode 100644 (file)
index 0000000..c640bd9
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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);
+}
+
+gboolean
+gtk_print_operation_preview_is_selected (GtkPrintOperationPreview *preview,
+                                        gint                      page_nr)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION_PREVIEW (preview));
+
+  return GTK_PRINT_OPERATION_PREVIEW_GET_IFACE (preview)->is_selected (preview, page_nr);
+}
+
diff --git a/gtk/gtkprintoperationpreview.h b/gtk/gtkprintoperationpreview.h
new file mode 100644 (file)
index 0000000..b4a776d
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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);
+  gboolean          (*is_selected)    (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_end_preview (GtkPrintOperationPreview *preview);
+gboolean gtk_print_operation_preview_is_selected (GtkPrintOperationPreview *preview,
+                                                 gint                      page_nr);
+
+#endif /* __GTK_PRINT_OPERATION_PREVIEW_H__ */
index e92822d7a0d717f16b0ecb6b8906f71141749a4f..c6ebc21134c39809c5187e9025a2720a1b89a0e5 100644 (file)
@@ -275,7 +275,8 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
                    (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 c49ede459bb7cd1a038f0143290c3f33c689ec46..b18cbe83163c0f39ac8012eeb05ddd1bb69cb5cc 100644 (file)
@@ -1,3 +1,4 @@
+#include <math.h>
 #include <pango/pangocairo.h>
 #include <gtk/gtk.h>
 #include <gtk/gtkprintoperation.h>
@@ -303,7 +304,6 @@ begin_print (GtkPrintOperation *operation,
   gtk_print_operation_set_n_pages (operation, g_list_length (page_breaks) + 1);
   
   print_data->page_breaks = page_breaks;
-  
 }
 
 static void
@@ -317,6 +317,7 @@ draw_page (GtkPrintOperation *operation,
   int start, end, i;
   PangoLayoutIter *iter;
   double start_pos;
+
   if (page_nr == 0)
     start = 0;
   else
@@ -430,17 +431,195 @@ custom_widget_apply (GtkPrintOperation *operation,
   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);
+
+  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;
+  
+  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);
+  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);
+
+  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 +631,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 +649,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 +671,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