]> www.fi.muni.cz Git - evince.git/commitdiff
First step of the printing system rework. EvJobPrint has been replaced by
authorCarlos Garcia Campos <carlosgc@gnome.org>
Sat, 27 Dec 2008 18:37:13 +0000 (18:37 +0000)
committerCarlos Garcia Campos <carlosgc@src.gnome.org>
Sat, 27 Dec 2008 18:37:13 +0000 (18:37 +0000)
2008-12-24  Carlos Garcia Campos  <carlosgc@gnome.org>

* shell/Makefile.am:
* shell/ev-print-operation.[ch]:
* shell/ev-jobs.[ch]: (ev_job_export_init),
(ev_job_export_dispose), (ev_job_export_run),
(ev_job_export_class_init), (ev_job_export_new),
(ev_job_export_set_page):
* shell/ev-window.c: (ev_window_print_operation_done),
(ev_window_print_range), (ev_window_dispose):

First step of the printing system rework. EvJobPrint has been
replaced by EvJobExport so that every page is scheduled to be
exported in a thread instead of scheduling the whole printing
process. This way the gui is responsive during printing.

svn path=/trunk/; revision=3306

ChangeLog
shell/Makefile.am
shell/ev-jobs.c
shell/ev-jobs.h
shell/ev-print-operation.c [new file with mode: 0644]
shell/ev-print-operation.h [new file with mode: 0644]
shell/ev-window.c

index e2b6718c7be6c474e71e904927583df66729cfed..30685690695c391ce24e02b534df753472493699 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-12-24  Carlos Garcia Campos  <carlosgc@gnome.org>
+
+       * shell/Makefile.am:
+       * shell/ev-print-operation.[ch]:
+       * shell/ev-jobs.[ch]: (ev_job_export_init),
+       (ev_job_export_dispose), (ev_job_export_run),
+       (ev_job_export_class_init), (ev_job_export_new),
+       (ev_job_export_set_page):
+       * shell/ev-window.c: (ev_window_print_operation_done),
+       (ev_window_print_range), (ev_window_dispose):
+
+       First step of the printing system rework. EvJobPrint has been
+       replaced by EvJobExport so that every page is scheduled to be
+       exported in a thread instead of scheduling the whole printing
+       process. This way the gui is responsive during printing.
+       
 2008-12-24  Carlos Garcia Campos  <carlosgc@gnome.org>
 
        * shell/ev-window.c: (setup_size_from_metadata),
index 1a1549427cab24e8e5957b7f8c677f91ceab2e0d..7f7ad4d7660ef9039491a36682b9f6da6c2a41c5 100644 (file)
@@ -61,6 +61,8 @@ evince_SOURCES=                               \
        ev-password-view.c              \
        ev-pixbuf-cache.c               \
        ev-pixbuf-cache.h               \
+       ev-print-operation.h            \
+       ev-print-operation.c            \
        ev-properties-dialog.c          \
        ev-properties-dialog.h          \
        ev-properties-fonts.c           \
index 1a5dd475c2349ad77fe98fa147d1c98547c3dbb3..a952243e8ede4405e1e3cce3d595825be54b8a2f 100644 (file)
@@ -54,12 +54,12 @@ static void ev_job_load_init          (EvJobLoad             *job);
 static void ev_job_load_class_init       (EvJobLoadClass        *class);
 static void ev_job_save_init              (EvJobSave             *job);
 static void ev_job_save_class_init        (EvJobSaveClass        *class);
-static void ev_job_print_init             (EvJobPrint            *job);
-static void ev_job_print_class_init       (EvJobPrintClass       *class);
 static void ev_job_find_init              (EvJobFind             *job);
 static void ev_job_find_class_init        (EvJobFindClass        *class);
 static void ev_job_layers_init            (EvJobLayers           *job);
 static void ev_job_layers_class_init      (EvJobLayersClass      *class);
+static void ev_job_export_init            (EvJobExport           *job);
+static void ev_job_export_class_init      (EvJobExportClass      *class);
 
 enum {
        CANCELLED,
@@ -95,9 +95,9 @@ G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
-G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobLayers, ev_job_layers, EV_TYPE_JOB)
+G_DEFINE_TYPE (EvJobExport, ev_job_export, EV_TYPE_JOB)
 
 /* EvJob */
 static void
@@ -1069,317 +1069,6 @@ ev_job_save_new (EvDocument  *document,
        return EV_JOB (job);
 }
 
-/* EvJobPrint */
-static void
-ev_job_print_init (EvJobPrint *job)
-{
-       EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
-}
-
-static void
-ev_job_print_dispose (GObject *object)
-{
-       EvJobPrint *job;
-
-       job = EV_JOB_PRINT (object);
-
-       ev_debug_message (DEBUG_JOBS, NULL);
-       
-       if (job->temp_file) {
-               g_unlink (job->temp_file);
-               g_free (job->temp_file);
-               job->temp_file = NULL;
-       }
-
-       if (job->ranges) {
-               g_free (job->ranges);
-               job->ranges = NULL;
-               job->n_ranges = 0;
-       }
-
-       (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
-}
-
-static gint
-ev_print_job_get_first_page (EvJobPrint *job)
-{
-       gint i;
-       gint first_page = G_MAXINT;
-       
-       if (job->n_ranges == 0)
-               return 0;
-
-       for (i = 0; i < job->n_ranges; i++) {
-               if (job->ranges[i].start < first_page)
-                       first_page = job->ranges[i].start;
-       }
-
-       return MAX (0, first_page);
-}
-
-static gint
-ev_print_job_get_last_page (EvJobPrint *job)
-{
-       gint i;
-       gint last_page = G_MININT;
-       gint max_page;
-
-       max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
-
-       if (job->n_ranges == 0)
-               return max_page;
-
-       for (i = 0; i < job->n_ranges; i++) {
-               if (job->ranges[i].end > last_page)
-                       last_page = job->ranges[i].end;
-       }
-
-       return MIN (max_page, last_page);
-}
-
-static gboolean
-ev_print_job_print_page_in_set (EvJobPrint *job,
-                               gint        page)
-{
-       switch (job->page_set) {
-               case EV_PRINT_PAGE_SET_EVEN:
-                       return page % 2 == 0;
-               case EV_PRINT_PAGE_SET_ODD:
-                       return page % 2 != 0;
-               case EV_PRINT_PAGE_SET_ALL:
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-
-static gint *
-ev_job_print_get_page_list (EvJobPrint *job,
-                           gint       *n_pages)
-{
-       gint  i, j, page, max_page;
-       gint  pages = 0;
-       gint *page_list;
-
-       max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
-
-       for (i = 0; i < job->n_ranges; i++) {
-               gint rsize;
-               gint start, end;
-
-               if (job->ranges[i].start == -1)
-                       job->ranges[i].start = 0;
-               if (job->ranges[i].end == -1)
-                       job->ranges[i].end = max_page;
-
-               if (job->ranges[i].start > max_page)
-                       continue;
-               
-               start = job->ranges[i].start + 1;
-               end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
-               rsize = end - start + 1;
-
-               switch (job->page_set) {
-                       case EV_PRINT_PAGE_SET_EVEN:
-                               pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
-                               break;
-                       case EV_PRINT_PAGE_SET_ODD:
-                               pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
-                               break;
-                       default:
-                               pages += rsize;
-                               break;
-               }
-       }
-
-       *n_pages = pages;
-
-       if (pages == 0)
-               return NULL;
-
-       page_list = g_new (gint, pages);
-
-       page = 0;
-       for (i = 0; i < job->n_ranges; i++) {
-               for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
-                       if (j > max_page)
-                               break;
-               
-                       if (ev_print_job_print_page_in_set (job, j + 1))
-                               page_list[page++] = j;
-               }
-       }
-
-       return page_list;
-}
-
-static gboolean
-ev_job_print_run (EvJob *job)
-{
-       EvDocument            *document = EV_JOB (job)->document;
-       EvJobPrint            *job_print = EV_JOB_PRINT (job);
-       EvFileExporterContext  fc;
-       EvRenderContext       *rc;
-       gint                   fd;
-       gint                  *page_list;
-       gint                   n_pages;
-       gint                   last_page;
-       gint                   first_page;
-       gint                   i, j;
-       gchar                 *filename;
-       GError                *error = NULL;
-       
-       ev_debug_message (DEBUG_JOBS, NULL);
-       ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
-       
-       if (job_print->temp_file)
-               g_free (job_print->temp_file);
-       job_print->temp_file = NULL;
-       
-       filename = g_strdup_printf ("evince_print.%s.XXXXXX", job_print->format);
-       fd = g_file_open_tmp (filename, &job_print->temp_file, &error);
-       g_free (filename);
-       if (fd <= -1) {
-               ev_job_failed_from_error (job, error);
-               g_error_free (error);
-               
-               return FALSE;
-       }
-
-       page_list = ev_job_print_get_page_list (job_print, &n_pages);
-       if (n_pages == 0) {
-               close (fd);
-               /* TODO: error */
-               ev_job_succeeded (job);
-               
-               return FALSE;
-       }
-
-       first_page = ev_print_job_get_first_page (job_print);
-       last_page = ev_print_job_get_last_page (job_print);
-
-       fc.format = g_ascii_strcasecmp (job_print->format, "pdf") == 0 ?
-               EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
-       fc.filename = job_print->temp_file;
-       fc.first_page = MIN (first_page, last_page);
-       fc.last_page = MAX (first_page, last_page);
-       fc.paper_width = job_print->width;
-       fc.paper_height = job_print->height;
-       fc.duplex = FALSE;
-       fc.pages_per_sheet = MAX (1, job_print->pages_per_sheet);
-
-       rc = ev_render_context_new (NULL, 0, 1.0);
-
-       ev_document_doc_mutex_lock ();
-       ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
-
-       for (i = 0; i < job_print->copies; i++) {
-               gint page, step;
-               gint n_copies;
-               
-               step = job_print->reverse ? -1 * job_print->pages_per_sheet : job_print->pages_per_sheet;
-               page = job_print->reverse ? ((n_pages - 1) / job_print->pages_per_sheet) * job_print->pages_per_sheet : 0;
-               n_copies = job_print->collate ? 1 : job_print->copies;
-
-               while ((job_print->reverse && (page >= 0)) || (!job_print->reverse && (page < n_pages))) {
-                       gint k;
-
-                       for (k = 0; k < n_copies; k++) {
-                               ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
-                               
-                               for (j = 0; j < job_print->pages_per_sheet; j++) {
-                                       EvPage *ev_page;
-                                       
-                                       gint p = page + j;
-
-                                       if (p < 0 || p >= n_pages)
-                                               break;
-
-                                       ev_page = ev_document_get_page (document, page_list[p]);
-                                       ev_render_context_set_page (rc, ev_page);
-                                       g_object_unref (ev_page);
-                                       
-                                       ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
-                               }
-
-                               ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
-                       }
-
-                       page += step;
-               }
-
-               if (!job_print->collate)
-                       break;
-       }
-
-       ev_file_exporter_end (EV_FILE_EXPORTER (document));
-       ev_document_doc_mutex_unlock ();
-       
-       g_free (page_list);
-       close (fd);
-       g_object_unref (rc);
-       
-       ev_job_succeeded (job);
-       
-       return FALSE;
-}
-
-static void
-ev_job_print_class_init (EvJobPrintClass *class)
-{
-       GObjectClass *oclass = G_OBJECT_CLASS (class);
-       EvJobClass   *job_class = EV_JOB_CLASS (class);
-
-       oclass->dispose = ev_job_print_dispose;
-       job_class->run = ev_job_print_run;
-}
-
-EvJob *
-ev_job_print_new (EvDocument    *document,
-                 const gchar   *format,
-                 gdouble        width,
-                 gdouble        height,
-                 EvPrintRange  *ranges,
-                 gint           n_ranges,
-                 EvPrintPageSet page_set,
-                 gint           pages_per_sheet,
-                 gint           copies,
-                 gdouble        collate,
-                 gdouble        reverse)
-{
-       EvJobPrint *job;
-
-       ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
-                         "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
-                         "collate: %s, reverse: %s",
-                         format, width, height, n_ranges, pages_per_sheet, copies,
-                         collate ? "True" : "False", reverse  ? "True" : "False");
-
-       job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
-
-       EV_JOB (job)->document = g_object_ref (document);
-
-       job->format = format;
-       
-       job->temp_file = NULL;
-
-       job->width = width;
-       job->height = height;
-
-       job->ranges = ranges;
-       job->n_ranges = n_ranges;
-
-       job->page_set = page_set;
-
-       job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
-       
-       job->copies = copies;
-       job->collate = collate;
-       job->reverse = reverse;
-       
-       return EV_JOB (job);
-}
-
 /* EvJobFind */
 static void
 ev_job_find_init (EvJobFind *job)
@@ -1603,3 +1292,92 @@ ev_job_layers_new (EvDocument *document)
        
        return job;
 }
+
+/* EvJobExport */
+static void
+ev_job_export_init (EvJobExport *job)
+{
+       EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
+       job->page = -1;
+}
+
+static void
+ev_job_export_dispose (GObject *object)
+{
+       EvJobExport *job;
+
+       ev_debug_message (DEBUG_JOBS, NULL);
+       
+       job = EV_JOB_EXPORT (object);
+
+       if (job->rc) {
+               g_object_unref (job->rc);
+               job->rc = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_job_export_parent_class)->dispose) (object);
+}
+
+static gboolean
+ev_job_export_run (EvJob *job)
+{
+       EvJobExport *job_export = EV_JOB_EXPORT (job);
+       EvPage      *ev_page;
+
+       g_assert (job_export->page != -1);
+
+       ev_debug_message (DEBUG_JOBS, NULL);
+       ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
+       
+       ev_document_doc_mutex_lock ();
+       
+       ev_page = ev_document_get_page (job->document, job_export->page);
+       if (job_export->rc) {
+               job->failed = FALSE;
+               job->finished = FALSE;
+               g_clear_error (&job->error);
+               
+               ev_render_context_set_page (job_export->rc, ev_page);
+       } else {
+               job_export->rc = ev_render_context_new (ev_page, 0, 1.0);
+       }
+       g_object_unref (ev_page);
+       
+       ev_file_exporter_do_page (EV_FILE_EXPORTER (job->document), job_export->rc);
+       
+       ev_document_doc_mutex_unlock ();
+       
+       ev_job_succeeded (job);
+       
+       return FALSE;
+}
+
+static void
+ev_job_export_class_init (EvJobExportClass *class)
+{
+       GObjectClass *oclass = G_OBJECT_CLASS (class);
+       EvJobClass   *job_class = EV_JOB_CLASS (class);
+
+       oclass->dispose = ev_job_export_dispose;
+       job_class->run = ev_job_export_run;
+}
+
+EvJob *
+ev_job_export_new (EvDocument *document)
+{
+       EvJob *job;
+
+       ev_debug_message (DEBUG_JOBS, NULL);
+
+       job = g_object_new (EV_TYPE_JOB_EXPORT, NULL);
+       job->document = g_object_ref (document);
+       
+       return job;
+}
+
+void
+ev_job_export_set_page (EvJobExport *job,
+                       gint         page)
+{
+       job->page = page;
+}
index 6d6581a3072474089e588aea86d5b3aec784b466..27b40a1c102a31f83f4d629c44a632afab31bfe9 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "ev-document.h"
 #include "ev-selection.h"
+#include "ev-render-context.h"
 #include "ev-window.h"
 
 G_BEGIN_DECLS
@@ -54,15 +55,15 @@ typedef struct _EvJobLoadClass EvJobLoadClass;
 typedef struct _EvJobSave EvJobSave;
 typedef struct _EvJobSaveClass EvJobSaveClass;
 
-typedef struct _EvJobPrint EvJobPrint;
-typedef struct _EvJobPrintClass EvJobPrintClass;
-
 typedef struct _EvJobFind EvJobFind;
 typedef struct _EvJobFindClass EvJobFindClass;
 
 typedef struct _EvJobLayers EvJobLayers;
 typedef struct _EvJobLayersClass EvJobLayersClass;
 
+typedef struct _EvJobExport EvJobExport;
+typedef struct _EvJobExportClass EvJobExportClass;
+
 #define EV_TYPE_JOB                         (ev_job_get_type())
 #define EV_JOB(object)                      (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob))
 #define EV_JOB_CLASS(klass)                 (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass))
@@ -104,11 +105,6 @@ typedef struct _EvJobLayersClass EvJobLayersClass;
 #define EV_JOB_SAVE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_SAVE, EvJobSaveClass))
 #define EV_IS_JOB_SAVE(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_SAVE))
 
-#define EV_TYPE_JOB_PRINT                    (ev_job_print_get_type())
-#define EV_JOB_PRINT(object)                 (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_PRINT, EvJobPrint))
-#define EV_JOB_PRINT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_PRINT, EvJobPrintClass))
-#define EV_IS_JOB_PRINT(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_PRINT))
-
 #define EV_TYPE_JOB_FIND                     (ev_job_find_get_type())
 #define EV_JOB_FIND(object)                  (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FIND, EvJobFind))
 #define EV_JOB_FIND_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FIND, EvJobFindClass))
@@ -119,6 +115,11 @@ typedef struct _EvJobLayersClass EvJobLayersClass;
 #define EV_JOB_LAYERS_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_LAYERS, EvJobLayersClass))
 #define EV_IS_JOB_LAYERS(object)             (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LAYERS))
 
+#define EV_TYPE_JOB_EXPORT                    (ev_job_export_get_type())
+#define EV_JOB_EXPORT(object)                 (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_EXPORT, EvJobExport))
+#define EV_JOB_EXPORT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_EXPORT, EvJobExportClass))
+#define EV_IS_JOB_EXPORT(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_EXPORT))
+
 typedef enum {
        EV_JOB_RUN_THREAD,
        EV_JOB_RUN_MAIN_LOOP
@@ -284,28 +285,6 @@ struct _EvJobSaveClass
        EvJobClass parent_class;
 };
 
-struct _EvJobPrint
-{
-       EvJob parent;
-
-       const gchar *format;
-       gchar  *temp_file;
-       EvPrintRange *ranges;
-       gint n_ranges;
-       EvPrintPageSet page_set;
-       gint copies;
-       gint pages_per_sheet;
-       gboolean collate;
-       gboolean reverse;
-       gdouble width;
-       gdouble height;
-};
-
-struct _EvJobPrintClass
-{
-       EvJobClass parent_class;
-};
-
 struct _EvJobFind
 {
        EvJob parent;
@@ -340,6 +319,19 @@ struct _EvJobLayersClass
        EvJobClass parent_class;
 };
 
+struct _EvJobExport
+{
+       EvJob parent;
+
+       gint page;
+       EvRenderContext *rc;
+};
+
+struct _EvJobExportClass
+{
+       EvJobClass parent_class;
+};
+
 /* Base job class */
 GType           ev_job_get_type           (void) G_GNUC_CONST;
 gboolean        ev_job_run                (EvJob          *job);
@@ -407,20 +399,6 @@ GType           ev_job_save_get_type      (void) G_GNUC_CONST;
 EvJob          *ev_job_save_new           (EvDocument      *document,
                                           const gchar     *uri,
                                           const gchar     *document_uri);
-
-/* EvJobPrint */
-GType           ev_job_print_get_type     (void) G_GNUC_CONST;
-EvJob          *ev_job_print_new          (EvDocument      *document,
-                                          const gchar     *format,
-                                          gdouble          width,
-                                          gdouble          height,
-                                          EvPrintRange    *ranges,
-                                          gint             n_ranges,
-                                          EvPrintPageSet   page_set,
-                                          gint             pages_per_sheet,
-                                          gint             copies,
-                                          gdouble          collate,
-                                          gdouble          reverse);
 /* EvJobFind */
 GType           ev_job_find_get_type      (void) G_GNUC_CONST;
 EvJob          *ev_job_find_new           (EvDocument      *document,
@@ -438,6 +416,12 @@ GList         **ev_job_find_get_results   (EvJobFind       *job);
 GType           ev_job_layers_get_type    (void) G_GNUC_CONST;
 EvJob          *ev_job_layers_new         (EvDocument     *document);
 
+/* EvJobExport */
+GType           ev_job_export_get_type    (void) G_GNUC_CONST;
+EvJob          *ev_job_export_new         (EvDocument     *document);
+void            ev_job_export_set_page    (EvJobExport    *job,
+                                          gint            page);
+
 G_END_DECLS
 
 #endif /* __EV_JOBS_H__ */
diff --git a/shell/ev-print-operation.c b/shell/ev-print-operation.c
new file mode 100644 (file)
index 0000000..c71ff42
--- /dev/null
@@ -0,0 +1,1043 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "ev-print-operation.h"
+
+#if GTK_CHECK_VERSION (2, 14, 0)
+#include <gtk/gtkunixprint.h>
+#else
+#include <gtk/gtkprintunixdialog.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <unistd.h>
+
+#include "ev-page-cache.h"
+#include "ev-file-exporter.h"
+#include "ev-jobs.h"
+#include "ev-job-scheduler.h"
+#include "ev-application.h"
+#include "ev-file-helpers.h"
+
+enum {
+       PROP_0,
+       PROP_DOCUMENT
+};
+
+enum {
+       DONE,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _EvPrintOperation {
+       GObject parent;
+
+       EvDocument *document;
+};
+
+struct _EvPrintOperationClass {
+       GObjectClass parent_class;
+
+       void              (* set_current_page)       (EvPrintOperation       *op,
+                                                     gint                    current_page);
+       void              (* set_print_settings)     (EvPrintOperation       *op,
+                                                     GtkPrintSettings       *print_settings);
+       GtkPrintSettings *(* get_print_settings)     (EvPrintOperation       *op);
+       void              (* set_default_page_setup) (EvPrintOperation       *op,
+                                                     GtkPageSetup           *page_setup);
+       GtkPageSetup     *(* get_default_page_setup) (EvPrintOperation       *op);
+       void              (* set_job_name)           (EvPrintOperation       *op,
+                                                     const gchar            *job_name);
+       void              (* run)                    (EvPrintOperation       *op,
+                                                     GtkWindow              *parent);
+       void              (* cancel)                 (EvPrintOperation       *op);
+       void              (* get_error)              (EvPrintOperation       *op,
+                                                     GError                **error);
+
+       /* signals */
+       void              (* done)                   (EvPrintOperation       *op,
+                                                     GtkPrintOperationResult result);
+};
+
+G_DEFINE_ABSTRACT_TYPE (EvPrintOperation, ev_print_operation, G_TYPE_OBJECT)
+
+static void
+ev_print_operation_finalize (GObject *object)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (object);
+
+       if (op->document) {
+               g_object_unref (op->document);
+               op->document = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_print_operation_parent_class)->finalize) (object);
+}
+
+static void
+ev_print_operation_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (object);
+
+       switch (prop_id) {
+       case PROP_DOCUMENT:
+               op->document = g_value_dup_object (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_print_operation_init (EvPrintOperation *op)
+{
+}
+
+static void
+ev_print_operation_class_init (EvPrintOperationClass *klass)
+{
+       GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+       g_object_class->set_property = ev_print_operation_set_property;
+       g_object_class->finalize = ev_print_operation_finalize;
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_DOCUMENT,
+                                        g_param_spec_object ("document",
+                                                             "Document",
+                                                             "The document to print",
+                                                             EV_TYPE_DOCUMENT,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY));
+       signals[DONE] =
+               g_signal_new ("done",
+                             G_TYPE_FROM_CLASS (g_object_class),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (EvPrintOperationClass, done),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__ENUM,
+                             G_TYPE_NONE, 1,
+                             GTK_TYPE_PRINT_OPERATION_RESULT);
+       
+}
+
+/* Public methods */
+void
+ev_print_operation_set_current_page (EvPrintOperation *op,
+                                    gint              current_page)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+       g_return_if_fail (current_page >= 0);
+
+       class->set_current_page (op, current_page);
+}
+
+void
+ev_print_operation_set_print_settings (EvPrintOperation *op,
+                                      GtkPrintSettings *print_settings)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+       g_return_if_fail (GTK_IS_PRINT_SETTINGS (print_settings));
+
+       class->set_print_settings (op, print_settings);
+}
+
+GtkPrintSettings *
+ev_print_operation_get_print_settings (EvPrintOperation *op)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_val_if_fail (EV_IS_PRINT_OPERATION (op), NULL);
+
+       return class->get_print_settings (op);
+}
+
+void
+ev_print_operation_set_default_page_setup (EvPrintOperation *op,
+                                          GtkPageSetup     *page_setup)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+       g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
+
+       class->set_default_page_setup (op, page_setup);
+}
+
+GtkPageSetup *
+ev_print_operation_get_default_page_setup (EvPrintOperation *op)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_val_if_fail (EV_IS_PRINT_OPERATION (op), NULL);
+
+       return class->get_default_page_setup (op);
+}
+
+void
+ev_print_operation_set_job_name (EvPrintOperation *op,
+                                const gchar      *job_name)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+       g_return_if_fail (job_name != NULL);
+
+       class->set_job_name (op, job_name);
+}
+
+void
+ev_print_operation_run (EvPrintOperation *op,
+                       GtkWindow        *parent)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+
+       class->run (op, parent);
+}
+
+void
+ev_print_operation_cancel (EvPrintOperation *op)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+
+       class->cancel (op);
+}
+
+void
+ev_print_operation_get_error (EvPrintOperation *op,
+                             GError          **error)
+{
+       EvPrintOperationClass *class = EV_PRINT_OPERATION_GET_CLASS (op);
+
+       g_return_if_fail (EV_IS_PRINT_OPERATION (op));
+
+       class->get_error (op, error);
+}
+
+/* Export interface */
+#define EV_TYPE_PRINT_OPERATION_EXPORT         (ev_print_operation_export_get_type())
+#define EV_PRINT_OPERATION_EXPORT(object)      (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_PRINT_OPERATION_EXPORT, EvPrintOperationExport))
+#define EV_PRINT_OPERATION_EXPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_PRINT_OPERATION_EXPORT, EvPrintOperationExportClass))
+#define EV_IS_PRINT_OPERATION_EXPORT(object)   (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_PRINT_OPERATION_EXPORT))
+
+typedef struct _EvPrintOperationExport      EvPrintOperationExport;
+typedef struct _EvPrintOperationExportClass EvPrintOperationExportClass;
+
+GType           ev_print_operation_export_get_type (void) G_GNUC_CONST;
+
+static gboolean export_print_page                  (EvPrintOperationExport *export);
+
+struct _EvPrintOperationExport {
+       EvPrintOperation parent;
+
+       GtkWindow *parent_window;
+       EvJob *job_export;
+       GError *error;
+
+       gboolean print_preview;
+       gint n_pages;
+       gint current_page;
+       GtkPrinter *printer;
+       GtkPageSetup *page_setup;
+       GtkPrintSettings *print_settings;
+       GtkPageSet page_set;
+       gint copies;
+       guint collate     : 1;
+       guint reverse     : 1;
+       gint pages_per_sheet;
+       gint fd;
+       gchar *temp_file;
+       gchar *job_name;
+       
+       guint idle_id;
+       
+       /* Context */
+       gint uncollated_copies;
+       gint collated_copies;
+       gint uncollated, collated, total;
+
+       gint range, n_ranges;
+       GtkPageRange *ranges;
+       GtkPageRange one_range;
+
+       gint page, start, end, inc;
+};
+
+struct _EvPrintOperationExportClass {
+       EvPrintOperationClass parent_class;
+};
+
+G_DEFINE_TYPE (EvPrintOperationExport, ev_print_operation_export, EV_TYPE_PRINT_OPERATION)
+
+static void
+ev_print_operation_export_set_current_page (EvPrintOperation *op,
+                                           gint              current_page)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       g_return_if_fail (current_page < export->n_pages);
+       
+       export->current_page = current_page;
+}
+
+static void
+ev_print_operation_export_set_print_settings (EvPrintOperation *op,
+                                             GtkPrintSettings *print_settings)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       if (print_settings == export->print_settings)
+               return;
+
+       g_object_ref (print_settings);
+       if (export->print_settings)
+               g_object_unref (export->print_settings);
+       export->print_settings = print_settings;
+}
+
+static GtkPrintSettings *
+ev_print_operation_export_get_print_settings (EvPrintOperation *op)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       return export->print_settings;
+}
+
+static void
+ev_print_operation_export_set_default_page_setup (EvPrintOperation *op,
+                                                 GtkPageSetup     *page_setup)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       if (page_setup == export->page_setup)
+               return;
+
+       g_object_ref (page_setup);
+       if (export->page_setup)
+               g_object_unref (export->page_setup);
+       export->page_setup = page_setup;
+}
+
+static GtkPageSetup *
+ev_print_operation_export_get_default_page_setup (EvPrintOperation *op)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       return export->page_setup;
+}
+
+static void
+ev_print_operation_export_set_job_name (EvPrintOperation *op,
+                                       const gchar      *job_name)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       g_free (export->job_name);
+       export->job_name = g_strdup (job_name);
+}
+
+static void
+ev_print_operation_export_set_printer (EvPrintOperationExport *export,
+                                      GtkPrinter             *printer)
+{
+       if (printer == export->printer)
+               return;
+
+       g_object_ref (printer);
+       if (export->printer)
+               g_object_unref (export->printer);
+       export->printer = printer;
+}
+
+static void
+find_range (EvPrintOperationExport *export)
+{
+       GtkPageRange *range;
+
+       range = &export->ranges[export->range];
+
+       if (export->inc < 0) {
+               export->start = range->end;
+               export->end = range->start - 1;
+       } else {
+               export->start = range->start;
+               export->end = range->end + 1;
+       }
+}
+
+static void
+clamp_ranges (EvPrintOperationExport *export)
+{
+       gint num_of_correct_ranges = 0;
+       gint i;
+
+       for (i = 0; i < export->n_ranges; i++) {
+               if ((export->ranges[i].start >= 0) &&
+                   (export->ranges[i].start < export->n_pages) &&
+                   (export->ranges[i].end >= 0) &&
+                   (export->ranges[i].end < export->n_pages)) {
+                       export->ranges[num_of_correct_ranges] = export->ranges[i];
+                       num_of_correct_ranges++;
+               } else if ((export->ranges[i].start >= 0) &&
+                          (export->ranges[i].start < export->n_pages) &&
+                          (export->ranges[i].end >= export->n_pages)) {
+                       export->ranges[i].end = export->n_pages - 1;
+                       export->ranges[num_of_correct_ranges] = export->ranges[i];
+                       num_of_correct_ranges++;
+               } else if ((export->ranges[i].end >= 0) &&
+                          (export->ranges[i].end < export->n_pages) &&
+                          (export->ranges[i].start < 0)) {
+                       export->ranges[i].start = 0;
+                       export->ranges[num_of_correct_ranges] = export->ranges[i];
+                       num_of_correct_ranges++;
+               }
+       }
+
+       export->n_ranges = num_of_correct_ranges;
+}
+
+static gint
+get_first_page (EvPrintOperationExport *export)
+{
+       gint i;
+       gint first_page = G_MAXINT;
+
+       if (export->n_ranges == 0)
+               return 0;
+
+       for (i = 0; i < export->n_ranges; i++) {
+               if (export->ranges[i].start < first_page)
+                       first_page = export->ranges[i].start;
+       }
+
+       return MAX (0, first_page);
+}
+
+static gint
+get_last_page (EvPrintOperationExport *export)
+{
+       gint i;
+       gint last_page = G_MININT;
+       gint max_page = export->n_pages - 1;
+
+       if (export->n_ranges == 0)
+               return max_page;
+
+       for (i = 0; i < export->n_ranges; i++) {
+               if (export->ranges[i].end > last_page)
+                       last_page = export->ranges[i].end;
+       }
+
+       return MIN (max_page, last_page);
+}
+
+static gboolean
+export_print_inc_page (EvPrintOperationExport *export)
+{
+       do {
+               export->page += export->inc;
+               if (export->page == export->end) {
+                       export->range += export->inc;
+                       if (export->range == -1 || export->range == export->n_ranges) {
+                               export->uncollated++;
+                               if (export->uncollated == export->uncollated_copies)
+                                       return FALSE;
+
+                               export->range = export->inc < 0 ? export->n_ranges - 1 : 0;
+                       }
+                       find_range (export);
+                       export->page = export->start;
+               }
+       } while ((export->page_set == GTK_PAGE_SET_EVEN && export->page % 2 == 0) ||
+                (export->page_set == GTK_PAGE_SET_ODD && export->page % 2 == 1));
+
+       return TRUE;
+}
+
+static void
+ev_print_operation_export_clear_temp_file (EvPrintOperationExport *export)
+{
+       if (!export->temp_file)
+               return;
+
+       g_unlink (export->temp_file);
+       g_free (export->temp_file);
+       export->temp_file = NULL;
+}
+
+static void
+print_job_finished (GtkPrintJob            *print_job,
+                   EvPrintOperationExport *export,
+                   GError                 *error)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (export);
+       
+       if (error) {
+               g_set_error_literal (&export->error,
+                                    GTK_PRINT_ERROR,
+                                    GTK_PRINT_ERROR_GENERAL,
+                                    error->message);
+               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_ERROR);
+       } else {
+               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_APPLY);
+       }
+
+       ev_print_operation_export_clear_temp_file (export);
+       g_object_unref (print_job);
+}
+
+static void
+export_print_done (EvPrintOperationExport *export)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (export);
+       GtkPrintSettings *settings;
+       EvFileExporterCapabilities capabilities;
+
+       /* Some printers take into account some print settings,
+        * and others don't. However we have exported the document
+        * to a ps or pdf file according to such print settings. So,
+        * we want to send the exported file to printer with those
+        * settings set to default values.
+        */
+       settings = gtk_print_settings_copy (export->print_settings);
+       capabilities = ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (op->document));
+
+       gtk_print_settings_set_page_ranges (settings, NULL, 0);
+       gtk_print_settings_set_print_pages (settings, GTK_PRINT_PAGES_ALL);
+       if (capabilities & EV_FILE_EXPORTER_CAN_COPIES)
+               gtk_print_settings_set_n_copies (settings, 1);
+       if (capabilities & EV_FILE_EXPORTER_CAN_PAGE_SET)
+               gtk_print_settings_set_page_set (settings, GTK_PAGE_SET_ALL);
+       if (capabilities & EV_FILE_EXPORTER_CAN_SCALE)
+               gtk_print_settings_set_scale (settings, 1.0);
+       if (capabilities & EV_FILE_EXPORTER_CAN_COLLATE)
+               gtk_print_settings_set_collate (settings, FALSE);
+       if (capabilities & EV_FILE_EXPORTER_CAN_REVERSE)
+               gtk_print_settings_set_reverse (settings, FALSE);
+       if (capabilities & EV_FILE_EXPORTER_CAN_NUMBER_UP) {
+               gtk_print_settings_set_number_up (settings, 1);
+               gtk_print_settings_set_int (settings, "cups-"GTK_PRINT_SETTINGS_NUMBER_UP, 1);
+       }
+
+       if (export->print_preview) {
+               gchar *uri;
+               gchar *print_settings_file = NULL;
+
+               print_settings_file = ev_tmp_filename ("print-settings");
+               gtk_print_settings_to_file (settings, print_settings_file, NULL);
+
+               uri = g_filename_to_uri (export->temp_file, NULL, NULL);
+               ev_application_open_uri_at_dest (EV_APP,
+                                                uri,
+                                                gtk_window_get_screen (export->parent_window),
+                                                NULL,
+                                                EV_WINDOW_MODE_PREVIEW,
+                                                NULL,
+                                                TRUE,
+                                                print_settings_file,
+                                                GDK_CURRENT_TIME);
+               g_free (print_settings_file);
+               g_free (uri);
+
+               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_APPLY);
+               /* temp_file will be deleted by the previewer */
+       } else {
+               GtkPrintJob *job;
+               GError      *error = NULL;
+               
+               job = gtk_print_job_new (export->job_name,
+                                        export->printer,
+                                        settings,
+                                        export->page_setup);
+               gtk_print_job_set_source_file (job, export->temp_file, &error);
+               if (error) {
+                       g_set_error_literal (&export->error,
+                                            GTK_PRINT_ERROR,
+                                            GTK_PRINT_ERROR_GENERAL,
+                                            error->message);
+                       g_error_free (error);
+                       ev_print_operation_export_clear_temp_file (export);
+                       g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_ERROR);
+               } else {
+                       gtk_print_job_send (job,
+                                           (GtkPrintJobCompleteFunc)print_job_finished,
+                                           g_object_ref (export),
+                                           (GDestroyNotify)g_object_unref);
+               }
+       }
+       g_object_unref (settings);
+}
+
+static void
+export_print_page_idle_finished (EvPrintOperationExport *export)
+{
+       export->idle_id = 0;
+}
+
+static void
+export_job_finished (EvJobExport            *job,
+                    EvPrintOperationExport *export)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (export);
+
+       if (export->pages_per_sheet == 1 || export->total % export->pages_per_sheet == 0) {
+               ev_document_doc_mutex_lock ();
+               ev_file_exporter_end_page (EV_FILE_EXPORTER (op->document));
+               ev_document_doc_mutex_unlock ();
+       }
+
+       /* Reschedule */
+       export->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                          (GSourceFunc)export_print_page,
+                                          export,
+                                          (GDestroyNotify)export_print_page_idle_finished);
+}
+
+static void
+export_job_cancelled (EvJobExport            *job,
+                     EvPrintOperationExport *export)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (export);
+
+       if (export->idle_id > 0)
+               g_source_remove (export->idle_id);
+       export->idle_id = 0;
+
+       g_signal_handlers_disconnect_by_func (export->job_export,
+                                             export_job_finished,
+                                             export);
+       g_signal_handlers_disconnect_by_func (export->job_export,
+                                             export_job_cancelled,
+                                             export);
+       g_object_unref (export->job_export);
+       export->job_export = NULL;
+
+       if (export->fd != -1) {
+               close (export->fd);
+               export->fd = -1;
+       }
+
+       ev_print_operation_export_clear_temp_file (export);
+
+       g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_CANCEL);
+}
+
+static gboolean
+export_print_page (EvPrintOperationExport *export)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (export);
+       
+       export->total++;
+       export->collated++;
+
+       if (export->collated == export->collated_copies) {
+               export->collated = 0;
+               if (!export_print_inc_page (export)) {
+                       ev_document_doc_mutex_lock ();
+                       if (export->pages_per_sheet > 1 &&
+                           export->total - 1 % export->pages_per_sheet == 0)
+                               ev_file_exporter_end_page (EV_FILE_EXPORTER (op->document));
+                       ev_file_exporter_end (EV_FILE_EXPORTER (op->document));
+                       ev_document_doc_mutex_unlock ();
+
+                       close (export->fd);
+                       export->fd = -1;
+
+                       export_print_done (export);
+                       
+                       return FALSE;
+               }
+       }
+
+       if (export->pages_per_sheet == 1 || export->total % export->pages_per_sheet == 1) {
+               ev_document_doc_mutex_lock ();
+               ev_file_exporter_begin_page (EV_FILE_EXPORTER (op->document));
+               ev_document_doc_mutex_unlock ();
+       }
+       
+       if (!export->job_export) {
+               export->job_export = ev_job_export_new (op->document);
+               g_signal_connect (G_OBJECT (export->job_export), "finished",
+                                 G_CALLBACK (export_job_finished),
+                                 (gpointer)export);
+               g_signal_connect (G_OBJECT (export->job_export), "cancelled",
+                                 G_CALLBACK (export_job_cancelled),
+                                 (gpointer)export);
+       }
+
+       ev_job_export_set_page (EV_JOB_EXPORT (export->job_export), export->page);
+       ev_job_scheduler_push_job (export->job_export, EV_JOB_PRIORITY_NONE);
+       
+       return FALSE;
+}
+
+static gboolean
+ev_print_operation_export_print_dialog_response_cb (GtkDialog              *dialog,
+                                                   gint                    response,
+                                                   EvPrintOperationExport *export)
+{
+       GtkPrintPages         print_pages;
+       GtkPrintSettings     *print_settings;
+       GtkPageSetup         *page_setup;
+       GtkPrinter           *printer;
+       gdouble               scale;
+       gdouble               width;
+       gdouble               height;
+       gint                  first_page;
+       gint                  last_page;
+       const gchar          *file_format;
+       gchar                *filename;
+       EvFileExporterContext fc;
+       GError               *error = NULL;
+       EvPrintOperation     *op = EV_PRINT_OPERATION (export);
+       
+       if (response != GTK_RESPONSE_OK &&
+           response != GTK_RESPONSE_APPLY) {
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+
+               return FALSE;
+       }
+
+       export->print_preview = (response == GTK_RESPONSE_APPLY);
+       
+       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dialog));
+       ev_print_operation_export_set_printer (export, printer);
+
+       print_settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dialog));
+       ev_print_operation_export_set_print_settings (op, print_settings);
+
+       page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dialog));
+       ev_print_operation_export_set_default_page_setup (op, page_setup);
+
+       if (!gtk_printer_accepts_ps (export->printer)) {
+               g_set_error (&export->error,
+                            GTK_PRINT_ERROR,
+                            GTK_PRINT_ERROR_GENERAL,
+                            "%s", _("Printing is not supported on this printer."));
+               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_ERROR);
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+               
+               return FALSE;
+       }
+
+       file_format = gtk_print_settings_get (print_settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
+       
+       filename = g_strdup_printf ("evince_print.%s.XXXXXX", file_format);
+       export->fd = g_file_open_tmp (filename, &export->temp_file, &error);
+       g_free (filename);
+       if (export->fd <= -1) {
+               g_set_error_literal (&export->error,
+                                    GTK_PRINT_ERROR,
+                                    GTK_PRINT_ERROR_GENERAL,
+                                    error->message);
+               g_error_free (error);
+               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_ERROR);
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+
+               return FALSE;
+       }
+
+       export->current_page = gtk_print_unix_dialog_get_current_page (GTK_PRINT_UNIX_DIALOG (dialog));
+       print_pages = gtk_print_settings_get_print_pages (print_settings);
+       
+       switch (print_pages) {
+       case GTK_PRINT_PAGES_CURRENT:
+               export->ranges = &export->one_range;
+               
+               export->ranges[0].start = export->current_page;
+               export->ranges[0].end = export->current_page;
+               export->n_ranges = 1;
+                               
+               break;
+       case GTK_PRINT_PAGES_RANGES: {
+               gint i;
+               
+               export->ranges = gtk_print_settings_get_page_ranges (print_settings, &export->n_ranges);
+               for (i = 0; i < export->n_ranges; i++)
+                       if (export->ranges[i].end == -1 || export->ranges[i].end >= export->n_pages)
+                               export->ranges[i].end = export->n_pages - 1;
+       }
+               break;
+       case GTK_PRINT_PAGES_ALL:
+               export->ranges = &export->one_range;
+
+               export->ranges[0].start = 0;
+               export->ranges[0].end = export->n_pages - 1;
+               export->n_ranges = 1;
+               
+               break;
+       }
+       clamp_ranges (export);
+
+       export->page_set = gtk_print_settings_get_page_set (print_settings);
+
+       width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
+       height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
+       scale = gtk_print_settings_get_scale (print_settings) * 0.01;
+       if (scale != 1.0) {
+               width *= scale;
+               height *= scale;
+       }
+
+       export->pages_per_sheet = gtk_print_settings_get_number_up (print_settings);
+       
+       export->copies = gtk_print_settings_get_n_copies (print_settings);
+       export->collate = gtk_print_settings_get_collate (print_settings);
+       export->reverse = gtk_print_settings_get_reverse (print_settings);
+
+       if (export->collate) {
+               export->uncollated_copies = export->copies;
+               export->collated_copies = 1;
+       } else {
+               export->uncollated_copies = 1;
+               export->collated_copies = export->copies;
+       }
+
+       if (export->reverse) {
+               export->range = export->n_ranges - 1;
+               export->inc = -1;
+       } else {
+               export->range = 0;
+               export->inc = 1;
+       }
+       find_range (export);
+
+       export->page = export->start - export->inc;
+       export->collated = export->collated_copies - 1;
+
+       first_page = get_first_page (export);
+       last_page = get_last_page (export);
+
+       fc.format = g_ascii_strcasecmp (file_format, "pdf") == 0 ?
+               EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
+       fc.filename = export->temp_file;
+       fc.first_page = MIN (first_page, last_page);
+       fc.last_page = MAX (first_page, last_page);
+       fc.paper_width = width;
+       fc.paper_height = height;
+       fc.duplex = FALSE;
+       fc.pages_per_sheet = MAX (1, export->pages_per_sheet);
+
+       ev_document_doc_mutex_lock ();
+       ev_file_exporter_begin (EV_FILE_EXPORTER (op->document), &fc);
+       ev_document_doc_mutex_unlock ();
+
+       export->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                          (GSourceFunc)export_print_page,
+                                          export,
+                                          (GDestroyNotify)export_print_page_idle_finished);
+       
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+
+       return TRUE;
+}
+
+static void
+ev_print_operation_export_run (EvPrintOperation *op,
+                              GtkWindow        *parent)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+       GtkWidget              *dialog;
+       GtkPrintCapabilities    capabilities;
+
+       export->parent_window = parent;
+       export->error = NULL;
+       
+       dialog = gtk_print_unix_dialog_new (_("Print"), parent);
+       gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+       
+       capabilities = GTK_PRINT_CAPABILITY_PREVIEW |
+               ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (op->document));
+       gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog),
+                                                      capabilities);
+
+       gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (dialog),
+                                               export->current_page);
+       
+       gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dialog),
+                                           export->print_settings);
+       
+       if (export->page_setup)
+               gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dialog),
+                                                     export->page_setup);
+       
+       g_signal_connect (G_OBJECT (dialog), "response",
+                         G_CALLBACK (ev_print_operation_export_print_dialog_response_cb),
+                         export);
+
+       gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+ev_print_operation_export_cancel (EvPrintOperation *op)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       if (export->job_export) {
+               ev_job_cancel (export->job_export);
+       }
+}
+
+static void
+ev_print_operation_export_get_error (EvPrintOperation *op,
+                                    GError          **error)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (op);
+
+       g_propagate_error (error, export->error);
+       export->error = NULL;
+}
+
+static void
+ev_print_operation_export_finalize (GObject *object)
+{
+       EvPrintOperationExport *export = EV_PRINT_OPERATION_EXPORT (object);
+
+       if (export->idle_id > 0) {
+               g_source_remove (export->idle_id);
+               export->idle_id = 0;
+       }
+
+       if (export->fd != -1) {
+               close (export->fd);
+               export->fd = -1;
+       }
+       
+       if (export->ranges) {
+               if (export->ranges != &export->one_range)
+                       g_free (export->ranges);
+               export->ranges = NULL;
+               export->n_ranges = 0;
+       }
+
+       if (export->temp_file) {
+               g_free (export->temp_file);
+               export->temp_file = NULL;
+       }
+
+       if (export->job_name) {
+               g_free (export->job_name);
+               export->job_name = NULL;
+       }
+
+       if (export->job_export) {
+               if (!ev_job_is_finished (export->job_export))
+                       ev_job_cancel (export->job_export);
+               g_signal_handlers_disconnect_by_func (export->job_export,
+                                                     export_job_finished,
+                                                     export);
+               g_signal_handlers_disconnect_by_func (export->job_export,
+                                                     export_job_cancelled,
+                                                     export);
+               g_object_unref (export->job_export);
+               export->job_export = NULL;
+       }
+
+       if (export->error) {
+               g_error_free (export->error);
+               export->error = NULL;
+       }
+
+       if (export->print_settings) {
+               g_object_unref (export->print_settings);
+               export->print_settings = NULL;
+       }
+
+       if (export->page_setup) {
+               g_object_unref (export->page_setup);
+               export->page_setup = NULL;
+       }
+
+       if (export->printer) {
+               g_object_unref (export->printer);
+               export->printer = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_print_operation_export_parent_class)->finalize) (object);
+}
+
+static void
+ev_print_operation_export_init (EvPrintOperationExport *export)
+{
+}
+
+static GObject *
+ev_print_operation_export_constructor (GType                  type,
+                                      guint                  n_construct_properties,
+                                      GObjectConstructParam *construct_params)
+{
+       GObject                *object;
+       EvPrintOperationExport *export;
+       EvPrintOperation       *op;
+       
+       object = G_OBJECT_CLASS (ev_print_operation_export_parent_class)->constructor (type,
+                                                                                      n_construct_properties,
+                                                                                      construct_params);
+       export = EV_PRINT_OPERATION_EXPORT (object);
+       op = EV_PRINT_OPERATION (object);
+       export->n_pages = ev_page_cache_get_n_pages (ev_page_cache_get (op->document));
+
+       return object;
+}
+
+static void
+ev_print_operation_export_class_init (EvPrintOperationExportClass *klass)
+{
+       GObjectClass          *g_object_class = G_OBJECT_CLASS (klass);
+       EvPrintOperationClass *ev_print_op_class = EV_PRINT_OPERATION_CLASS (klass);
+
+       ev_print_op_class->set_current_page = ev_print_operation_export_set_current_page;
+       ev_print_op_class->set_print_settings = ev_print_operation_export_set_print_settings;
+       ev_print_op_class->get_print_settings = ev_print_operation_export_get_print_settings;
+       ev_print_op_class->set_default_page_setup = ev_print_operation_export_set_default_page_setup;
+       ev_print_op_class->get_default_page_setup = ev_print_operation_export_get_default_page_setup;
+       ev_print_op_class->set_job_name = ev_print_operation_export_set_job_name;
+       ev_print_op_class->run = ev_print_operation_export_run;
+       ev_print_op_class->cancel = ev_print_operation_export_cancel;
+       ev_print_op_class->get_error = ev_print_operation_export_get_error;
+
+       g_object_class->constructor = ev_print_operation_export_constructor;
+       g_object_class->finalize = ev_print_operation_export_finalize;
+}
+
+/* Factory method */
+EvPrintOperation *
+ev_print_operation_new (EvDocument *document)
+{
+       /* TODO: EvPrintOperationPrint */
+
+       return EV_PRINT_OPERATION (g_object_new (EV_TYPE_PRINT_OPERATION_EXPORT,
+                                                "document", document, NULL));
+}
diff --git a/shell/ev-print-operation.h b/shell/ev-print-operation.h
new file mode 100644 (file)
index 0000000..8e7d6f8
--- /dev/null
@@ -0,0 +1,59 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EV_PRINT_OPERATION_H__
+#define __EV_PRINT_OPERATION_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+typedef struct _EvPrintOperation      EvPrintOperation;
+typedef struct _EvPrintOperationClass EvPrintOperationClass;
+
+#define EV_TYPE_PRINT_OPERATION              (ev_print_operation_get_type())
+#define EV_PRINT_OPERATION(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_PRINT_OPERATION, EvPrintOperation))
+#define EV_PRINT_OPERATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_PRINT_OPERATION, EvPrintOperationClass))
+#define EV_IS_PRINT_OPERATION(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_PRINT_OPERATION))
+#define EV_PRINT_OPERATION_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_PRINT_OPERATION, EvPrintOperationClass))
+
+GType             ev_print_operation_get_type               (void) G_GNUC_CONST;
+
+EvPrintOperation *ev_print_operation_new                    (EvDocument       *document);
+void              ev_print_operation_set_current_page       (EvPrintOperation *op,
+                                                            gint              current_page);
+void              ev_print_operation_set_print_settings     (EvPrintOperation *op,
+                                                            GtkPrintSettings *print_settings);
+GtkPrintSettings *ev_print_operation_get_print_settings     (EvPrintOperation *op);
+void              ev_print_operation_set_default_page_setup (EvPrintOperation *op,
+                                                            GtkPageSetup     *page_setup);
+GtkPageSetup     *ev_print_operation_get_default_page_setup (EvPrintOperation *op);
+void              ev_print_operation_set_job_name           (EvPrintOperation *op,
+                                                            const gchar      *job_name);
+void              ev_print_operation_run                    (EvPrintOperation *op,
+                                                            GtkWindow        *parent);
+void              ev_print_operation_cancel                 (EvPrintOperation *op);
+void              ev_print_operation_get_error              (EvPrintOperation *op,
+                                                            GError          **error);
+G_END_DECLS
+       
+#endif /* __EV_PRINT_OPERATION_H__ */
index e3c225c8f31bd59916bdcfe29992510b6c5ae1d0..324cddade02589bbd4f1ba930dee41b75389b550 100644 (file)
@@ -87,6 +87,7 @@
 #include "ev-view.h"
 #include "ev-window.h"
 #include "ev-window-title.h"
+#include "ev-print-operation.h"
 
 #ifdef ENABLE_DBUS
 #include "ev-media-player-keys.h"
@@ -184,12 +185,10 @@ struct _EvWindowPrivate {
        EvJob            *reload_job;
        EvJob            *thumbnail_job;
        EvJob            *save_job;
-       EvJob            *print_job;
        EvJob            *find_job;
 
        /* Printing */
        gboolean          print_preview;
-       GtkPrintJob      *gtk_print_job;
        GtkPrinter       *printer;
        GtkPrintSettings *print_settings;
        GtkPageSetup     *print_page_setup;
@@ -239,8 +238,6 @@ static void     ev_window_reload_job_cb                 (EvJob            *job,
                                                         EvWindow         *window);
 static void     ev_window_set_icon_from_thumbnail       (EvJobThumbnail   *job,
                                                         EvWindow         *ev_window);
-static void     ev_window_print_job_cb                  (EvJob            *job,
-                                                        EvWindow         *window);
 static void     ev_window_save_job_cb                   (EvJob            *save,
                                                         EvWindow         *window);
 static void     ev_window_sizing_mode_changed_cb        (EvView           *view,
@@ -2291,26 +2288,6 @@ ev_window_cmd_file_print_setup (GtkAction *action, EvWindow *ev_window)
                ev_window);
 }
 
-static void
-ev_window_clear_print_job (EvWindow *window)
-{
-       if (window->priv->print_job) {
-               if (!ev_job_is_finished (window->priv->print_job))
-                       ev_job_cancel (window->priv->print_job);
-
-               g_signal_handlers_disconnect_by_func (window->priv->print_job,
-                                                     ev_window_print_job_cb,
-                                                     window);
-               g_object_unref (window->priv->print_job);
-               window->priv->print_job = NULL;
-       }
-
-       if (window->priv->gtk_print_job) {
-               g_object_unref (window->priv->gtk_print_job);
-               window->priv->gtk_print_job = NULL;
-       }
-}
-
 static void
 ev_window_load_print_settings_from_metadata (EvWindow *window)
 {
@@ -2348,267 +2325,58 @@ ev_window_save_print_settings (EvWindow *window)
 }
 
 static void
-ev_window_print_finished (GtkPrintJob *print_job,
-                         EvWindow    *window,
-                         GError      *error)
-{
-       ev_window_clear_print_job (window);
-       
-       if (error) {
-               ev_window_error_message (window, error,
-                                        "%s", _("Failed to print document"));
-       } else {
-               /* If printed successfully, save print settings */
-               ev_application_set_print_settings (EV_APP,
-                                                  window->priv->print_settings);
-               ev_window_save_print_settings (window);
-       }
-}
-
-static void
-ev_window_print_send (EvWindow    *window,
-                     const gchar *filename)
-{
-       GtkPrintSettings *settings;
-       EvFileExporterCapabilities capabilities;
-       
-       /* Some printers take into account some print settings,
-        * and others don't. However we have exported the document
-        * to a ps or pdf file according to such print settings. So,
-        * we want to send the exported file to printer with those
-        * settings set to default values. 
-        */
-       settings = gtk_print_settings_copy (window->priv->print_settings);
-       capabilities = ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (window->priv->document));
-
-       gtk_print_settings_set_page_ranges (settings, NULL, 0);
-       gtk_print_settings_set_print_pages (settings, GTK_PRINT_PAGES_ALL);
-       if (capabilities & EV_FILE_EXPORTER_CAN_COPIES)
-               gtk_print_settings_set_n_copies (settings, 1);
-       if (capabilities & EV_FILE_EXPORTER_CAN_PAGE_SET)
-               gtk_print_settings_set_page_set (settings, GTK_PAGE_SET_ALL);
-       if (capabilities & EV_FILE_EXPORTER_CAN_SCALE)
-               gtk_print_settings_set_scale (settings, 1.0);
-       if (capabilities & EV_FILE_EXPORTER_CAN_COLLATE)
-               gtk_print_settings_set_collate (settings, FALSE);
-       if (capabilities & EV_FILE_EXPORTER_CAN_REVERSE)
-               gtk_print_settings_set_reverse (settings, FALSE);
-       if (capabilities & EV_FILE_EXPORTER_CAN_NUMBER_UP) {
-               gtk_print_settings_set_number_up (settings, 1);
-               gtk_print_settings_set_int (settings, "cups-"GTK_PRINT_SETTINGS_NUMBER_UP, 1);
-       }
-       
-       if (window->priv->print_preview) {
-               gchar *uri;
-               gchar *print_settings_file = NULL;
-
-               ev_application_set_print_settings (EV_APP,
-                                                  window->priv->print_settings);
-               
-               print_settings_file = ev_tmp_filename ("print-settings");
-               gtk_print_settings_to_file (settings, print_settings_file, NULL);
-
-               uri = g_filename_to_uri (filename, NULL, NULL);
-               ev_application_open_uri_at_dest (EV_APP,
-                                                uri, 
-                                                gtk_window_get_screen (GTK_WINDOW (window)),
-                                                NULL,
-                                                EV_WINDOW_MODE_PREVIEW,
-                                                NULL, 
-                                                TRUE,
-                                                print_settings_file,
-                                                GDK_CURRENT_TIME);
-               g_free (print_settings_file);
-               g_free (uri);
-       } else {
-               GtkPrintJob *job;
-               GError      *error = NULL;
-       
-               job = gtk_print_job_new (gtk_window_get_title (GTK_WINDOW (window)),
-                                        window->priv->printer,
-                                        settings,
-                                        window->priv->print_page_setup);
-
-               if (window->priv->gtk_print_job)
-                       g_object_unref (window->priv->gtk_print_job);
-               window->priv->gtk_print_job = job;
-
-               if (gtk_print_job_set_source_file (job, filename, &error)) {
-                       gtk_print_job_send (job,
-                                           (GtkPrintJobCompleteFunc)ev_window_print_finished,
-                                           window, NULL);
-               } else {
-                       ev_window_clear_print_job (window);
-                       g_warning ("%s", error->message);
-                       g_error_free (error);
-               }
-       }
-
-       g_object_unref (settings);
-}
-
-static void
-ev_window_print_job_cb (EvJob    *job,
-                       EvWindow *window)
+ev_window_print_operation_done (EvPrintOperation       *op,
+                               GtkPrintOperationResult result,
+                               EvWindow               *ev_window)
 {
-       if (ev_job_is_failed (job)) {
-               g_warning ("%s", job->error->message);
-               ev_window_clear_print_job (window);
-               return;
-       }
-
-       g_assert (EV_JOB_PRINT (job)->temp_file != NULL);
-
-       ev_window_print_send (window, EV_JOB_PRINT (job)->temp_file);
-}
-
-static gboolean
-ev_window_print_dialog_response_cb (GtkDialog *dialog,
-                                   gint       response,
-                                   EvWindow  *window)
-{
-       EvPrintRange  *ranges = NULL;
-       EvPrintPageSet page_set;
-       gint           n_ranges = 0;
-       gint           copies;
-       gint           pages_per_sheet;
-       gboolean       collate;
-       gboolean       reverse;
-       gdouble        scale;
-       gint           current_page;
-       gdouble        width;
-       gdouble        height;
-       GtkPrintPages  print_pages;
-       const gchar   *file_format;
-       
-       if (response != GTK_RESPONSE_OK &&
-           response != GTK_RESPONSE_APPLY) {
-               gtk_widget_destroy (GTK_WIDGET (dialog));
-               window->priv->print_dialog = NULL;
-
-               return FALSE;
-       }
-
-       window->priv->print_preview = (response == GTK_RESPONSE_APPLY);
-
-       if (window->priv->printer)
-               g_object_unref (window->priv->printer);
-       if (window->priv->print_settings)
-               g_object_unref (window->priv->print_settings);
-       if (window->priv->print_page_setup)
-               g_object_unref (window->priv->print_page_setup);
-       
-       window->priv->printer = g_object_ref (
-               gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dialog)));
-       window->priv->print_settings = g_object_ref (
-               gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dialog)));
-       window->priv->print_page_setup = g_object_ref (
-               gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dialog)));
-
-       file_format = gtk_print_settings_get (window->priv->print_settings,
-                                             GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
-       
-       if (!gtk_printer_accepts_ps (window->priv->printer)) {
-               ev_window_error_message (window, NULL, "%s",
-                                        _("Printing is not supported on this printer."));
-               return FALSE;
-       }
+       switch (result) {
+       case GTK_PRINT_OPERATION_RESULT_APPLY: {
+               GtkPrintSettings *print_settings;
 
-       ev_window_clear_print_job (window);
-       
-       current_page = gtk_print_unix_dialog_get_current_page (GTK_PRINT_UNIX_DIALOG (dialog));
-       print_pages = gtk_print_settings_get_print_pages (window->priv->print_settings);
-       
-       switch (print_pages) {
-       case GTK_PRINT_PAGES_CURRENT:
-               ranges = g_new0 (EvPrintRange, 1);
-               
-               ranges->start = current_page;
-               ranges->end = current_page;
-               n_ranges = 1;
-                               
-               break;
-       case GTK_PRINT_PAGES_RANGES: {
-               GtkPageRange *page_range;
+               if (ev_window->priv->print_settings)
+                       g_object_unref (ev_window->priv->print_settings);
+               print_settings = ev_print_operation_get_print_settings (op);
                
-               page_range = gtk_print_settings_get_page_ranges (window->priv->print_settings,
-                                                                &n_ranges);
-               if (n_ranges > 0)
-                       ranges = g_memdup (page_range, n_ranges * sizeof (GtkPageRange));
+               ev_application_set_print_settings (EV_APP, print_settings);
+               ev_window->priv->print_settings = g_object_ref (print_settings);
+               ev_window_save_print_settings (ev_window);
        }
                break;
-       case GTK_PRINT_PAGES_ALL: {
-               gint n_pages;
-
-               n_pages = ev_page_cache_get_n_pages (ev_page_cache_get (window->priv->document));
-               
-               ranges = g_new0 (EvPrintRange, 1);
+       case GTK_PRINT_OPERATION_RESULT_ERROR: {
+               GError *error = NULL;
 
-               ranges->start = 0;
-               ranges->end = n_pages - 1;
-               n_ranges = 1;
+               ev_print_operation_get_error (op, &error);
+               ev_window_error_message (ev_window, error,
+                                        "%s", _("Failed to print document"));
+               g_error_free (error);
        }
                break;
+       case GTK_PRINT_OPERATION_RESULT_CANCEL:
+       default:
+               break;
        }
 
-       page_set = (EvPrintPageSet)gtk_print_settings_get_page_set (window->priv->print_settings);
-
-       scale = gtk_print_settings_get_scale (window->priv->print_settings) * 0.01;
-       
-       width = gtk_page_setup_get_paper_width (window->priv->print_page_setup,
-                                               GTK_UNIT_POINTS);
-       height = gtk_page_setup_get_paper_height (window->priv->print_page_setup,
-                                                 GTK_UNIT_POINTS);
-       
-       if (scale != 1.0) {
-               width *= scale;
-               height *= scale;
-       }
-
-       pages_per_sheet = gtk_print_settings_get_number_up (window->priv->print_settings);
-       
-       copies = gtk_print_settings_get_n_copies (window->priv->print_settings);
-       collate = gtk_print_settings_get_collate (window->priv->print_settings);
-       reverse = gtk_print_settings_get_reverse (window->priv->print_settings);
-       
-       window->priv->print_job = ev_job_print_new (window->priv->document,
-                                                   file_format ? file_format : "ps",
-                                                   width, height,
-                                                   ranges, n_ranges,
-                                                   page_set,
-                                                   pages_per_sheet,
-                                                   copies, collate,
-                                                   reverse);
-       
-       g_signal_connect (window->priv->print_job, "finished",
-                         G_CALLBACK (ev_window_print_job_cb),
-                         window);
-       /* The priority doesn't matter for this job */
-       ev_job_scheduler_push_job (window->priv->print_job, EV_JOB_PRIORITY_NONE);
-       
-       gtk_widget_destroy (GTK_WIDGET (dialog));
-       window->priv->print_dialog = NULL;
-
-       return TRUE;
+       g_object_unref (op);
 }
 
 void
-ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
+ev_window_print_range (EvWindow *ev_window,
+                      gint      first_page,
+                      gint      last_page)
 {
-       GtkWidget           *dialog;
+       EvPrintOperation    *op;
        EvPageCache         *page_cache;
        gint                 current_page;
        gint                 document_last_page;
-       GtkPrintCapabilities capabilities;
 
        g_return_if_fail (EV_IS_WINDOW (ev_window));
        g_return_if_fail (ev_window->priv->document != NULL);
 
-       if (ev_window->priv->print_dialog) {
-               gtk_window_present (GTK_WINDOW (ev_window->priv->print_dialog));
-               return;
-       }
-       
+       op = ev_print_operation_new (ev_window->priv->document);
+       g_signal_connect (G_OBJECT (op), "done",
+                         G_CALLBACK (ev_window_print_operation_done),
+                         (gpointer)ev_window);
+
        page_cache = ev_page_cache_get (ev_window->priv->document);
        current_page = ev_page_cache_get_current_page (page_cache);
        document_last_page = ev_page_cache_get_n_pages (page_cache);
@@ -2632,29 +2400,13 @@ ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
                                                    &range, 1);
        }
 
-       dialog = gtk_print_unix_dialog_new (_("Print"), GTK_WINDOW (ev_window));
-       ev_window->priv->print_dialog = dialog;
-       
-       capabilities = GTK_PRINT_CAPABILITY_PREVIEW |
-               ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (ev_window->priv->document));
-       gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog),
-                                                      capabilities);
-
-       gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (dialog),
-                                               current_page);
-       
-       gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dialog),
-                                           ev_window->priv->print_settings);
-       
+       ev_print_operation_set_job_name (op, gtk_window_get_title (GTK_WINDOW (ev_window)));
+       ev_print_operation_set_current_page (op, current_page);
+       ev_print_operation_set_print_settings (op, ev_window->priv->print_settings);
        if (ev_window->priv->print_page_setup)
-               gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dialog),
-                                                     ev_window->priv->print_page_setup);
-       
-       g_signal_connect (G_OBJECT (dialog), "response",
-                         G_CALLBACK (ev_window_print_dialog_response_cb),
-                         ev_window);
+               ev_print_operation_set_default_page_setup (op, ev_window->priv->print_page_setup);
 
-       gtk_widget_show (dialog);
+       ev_print_operation_run (op, GTK_WINDOW (ev_window));
 }
 
 static void
@@ -4395,13 +4147,7 @@ ev_window_dispose (GObject *object)
        }
 
        ev_window_close_dialogs (window);
-       ev_window_clear_print_job (window);
 
-       if (window->priv->gtk_print_job) {
-               g_object_unref (window->priv->gtk_print_job);
-               window->priv->gtk_print_job = NULL;
-       }
-       
        if (window->priv->printer) {
                g_object_unref (window->priv->printer);
                window->priv->printer = NULL;