]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-print-operation.c
Do not disable printing when cairo printing is available.
[evince.git] / shell / ev-print-operation.c
index 8498dceb7b1677cd0b6fc9e4235d15c876ebdc31..e583dfbfe81d3985b985d6780f5c528ccaa53900 100644 (file)
 
 #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>
@@ -37,6 +32,7 @@
 #include "ev-job-scheduler.h"
 #include "ev-application.h"
 #include "ev-file-helpers.h"
+#include "ev-document-print.h"
 
 enum {
        PROP_0,
@@ -87,7 +83,6 @@ struct _EvPrintOperationClass {
                                                      GtkPrintOperationResult result);
        void              (* begin_print)            (EvPrintOperation       *op);
        void              (* status_changed)         (EvPrintOperation       *op);
-                                                     
 };
 
 G_DEFINE_ABSTRACT_TYPE (EvPrintOperation, ev_print_operation, G_TYPE_OBJECT)
@@ -337,7 +332,7 @@ ev_print_operation_update_status (EvPrintOperation *op,
 typedef struct _EvPrintOperationExport      EvPrintOperationExport;
 typedef struct _EvPrintOperationExportClass EvPrintOperationExportClass;
 
-GType           ev_print_operation_export_get_type (void) G_GNUC_CONST;
+static GType    ev_print_operation_export_get_type (void) G_GNUC_CONST;
 
 static void     ev_print_operation_export_begin    (EvPrintOperationExport *export);
 static gboolean export_print_page                  (EvPrintOperationExport *export);
@@ -372,7 +367,7 @@ struct _EvPrintOperationExport {
        gint n_pages_to_print;
        gint uncollated_copies;
        gint collated_copies;
-       gint uncollated, collated, total;
+       gint uncollated, collated, total, blank;
 
        gint range, n_ranges;
        GtkPageRange *ranges;
@@ -576,12 +571,13 @@ find_range (EvPrintOperationExport *export)
        }
 }
 
-static void
+static gboolean
 clamp_ranges (EvPrintOperationExport *export)
 {
        gint num_of_correct_ranges = 0;
        gint n_pages_to_print = 0;
        gint i;
+       gboolean null_flag = FALSE;
 
        for (i = 0; i < export->n_ranges; i++) {
                gint n_pages;
@@ -612,16 +608,27 @@ clamp_ranges (EvPrintOperationExport *export)
                } else if (n_pages % 2 == 0) {
                        n_pages_to_print += n_pages / 2;
                } else if (export->page_set == GTK_PAGE_SET_EVEN) {
-                       n_pages_to_print += export->ranges[i].start % 2 == 0 ?
+                       if (n_pages==1 && export->ranges[i].start % 2 == 0)
+                               null_flag = TRUE;
+                       else 
+                               n_pages_to_print += export->ranges[i].start % 2 == 0 ?
                                n_pages / 2 : (n_pages / 2) + 1;
                } else if (export->page_set == GTK_PAGE_SET_ODD) {
-                       n_pages_to_print += export->ranges[i].start % 2 == 0 ?
+                       if (n_pages==1 && export->ranges[i].start % 2 != 0) 
+                               null_flag = TRUE;
+                       else 
+                               n_pages_to_print += export->ranges[i].start % 2 == 0 ?
                                (n_pages / 2) + 1 : n_pages / 2;
                }
        }
 
-       export->n_ranges = num_of_correct_ranges;
-       export->n_pages_to_print = n_pages_to_print;
+       if (null_flag && !n_pages_to_print) {
+               return FALSE;
+       } else {
+               export->n_ranges = num_of_correct_ranges;
+               export->n_pages_to_print = n_pages_to_print;
+               return TRUE;
+       }
 }
 
 static void
@@ -669,8 +676,8 @@ export_print_inc_page (EvPrintOperationExport *export)
                        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));
+       } while ((export->page_set == GTK_PAGE_SET_EVEN && (export->page / export->pages_per_sheet) % 2 == 0) ||
+                (export->page_set == GTK_PAGE_SET_ODD && (export->page  / export->pages_per_sheet) % 2 == 1));
 
        return TRUE;
 }
@@ -703,9 +710,9 @@ ev_print_operation_export_run_next (EvPrintOperationExport *export)
 }
 
 static void
-print_job_finished (GtkPrintJob            *print_job,
-                   EvPrintOperationExport *export,
-                   GError                 *error)
+gtk_print_job_finished (GtkPrintJob            *print_job,
+                       EvPrintOperationExport *export,
+                       GError                 *error)
 {
        EvPrintOperation *op = EV_PRINT_OPERATION (export);
 
@@ -731,6 +738,7 @@ export_print_done (EvPrintOperationExport *export)
        EvPrintOperation *op = EV_PRINT_OPERATION (export);
        GtkPrintSettings *settings;
        EvFileExporterCapabilities capabilities;
+       GError *error = NULL;
 
        g_assert (export->temp_file != NULL);
        
@@ -761,56 +769,98 @@ export_print_done (EvPrintOperationExport *export)
        }
 
        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);
+               GKeyFile *key_file;
+               gchar    *data = NULL;
+               gsize     data_len;
+               gchar    *print_settings_file = NULL;
 
-               g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_APPLY);
-               /* temp_file will be deleted by the previewer */
+               key_file = g_key_file_new ();
 
-               ev_print_operation_export_run_next (export);
+               gtk_print_settings_to_key_file (settings, key_file, NULL);
+               gtk_page_setup_to_key_file (export->page_setup, key_file, NULL);
+               g_key_file_set_string (key_file, "Print Job", "title", export->job_name);
+
+               data = g_key_file_to_data (key_file, &data_len, &error);
+               if (data) {
+                       gint fd;
+                       
+                       fd = g_file_open_tmp ("print-settingsXXXXXX", &print_settings_file, &error);
+                       if (!error)
+                               g_file_set_contents (print_settings_file, data, data_len, &error);
+                       close (fd);
+                       
+                       g_free (data);
+               }
+
+               g_key_file_free (key_file);
+
+               if (!error) {
+                       gint    argc;
+                       gchar **argv;
+                       gchar  *cmd;
+                       gchar  *quoted_filename;
+                       gchar  *quoted_settings_filename;
+
+                       quoted_filename = g_shell_quote (export->temp_file);
+                       quoted_settings_filename = g_shell_quote (print_settings_file);
+                       cmd = g_strdup_printf ("evince-previewer --unlink-tempfile --print-settings %s %s",
+                                              quoted_settings_filename, quoted_filename);
+
+                       g_shell_parse_argv (cmd, &argc, &argv, &error);
+
+                       g_free (quoted_filename);
+                       g_free (quoted_settings_filename);
+                       g_free (cmd);
+
+                       if (!error) {
+                               gdk_spawn_on_screen (gtk_window_get_screen (export->parent_window),
+                                                    NULL, argv, NULL,
+                                                    G_SPAWN_SEARCH_PATH,
+                                                    NULL, NULL, NULL,
+                                                    &error);
+                       }
+
+                       g_strfreev (argv);
+               }
+
+               if (error) {
+                       if (print_settings_file)
+                               g_unlink (print_settings_file);
+                       g_free (print_settings_file);
+               } else {
+                       g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_APPLY);
+                       /* temp_file will be deleted by the previewer */
+
+                       ev_print_operation_export_run_next (export);
+               }
        } 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);
-
-                       ev_print_operation_export_run_next (export);
-               } else {
+               if (!error){
                        gtk_print_job_send (job,
-                                           (GtkPrintJobCompleteFunc)print_job_finished,
+                                           (GtkPrintJobCompleteFunc)gtk_print_job_finished,
                                            g_object_ref (export),
                                            (GDestroyNotify)g_object_unref);
                }
        }
        g_object_unref (settings);
+
+       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);
+
+               ev_print_operation_export_run_next (export);
+       }
 }
 
 static void
@@ -825,7 +875,7 @@ export_job_finished (EvJobExport            *job,
 {
        EvPrintOperation *op = EV_PRINT_OPERATION (export);
 
-       if (export->pages_per_sheet == 1 || export->total % export->pages_per_sheet == 0) {
+       if (export->pages_per_sheet == 1 || (export->total + export->blank) % 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 ();
@@ -898,28 +948,41 @@ export_print_page (EvPrintOperationExport *export)
        export->total++;
        export->collated++;
 
+       /* when printing multiple collated copies & multiple pages per sheet we want to
+          prevent the next copy bleeding into the last sheet of the previous one
+          we therefore check whether we've reached the last page in a document
+          if that is the case and the given sheet is not filled with pages,
+          we introduce a few blank pages to finish off the sheet
+          to make sure nothing goes wrong, the final condition ensures that
+          we're not at the end of a sheet, otherwise we'd introduce a blank sheet! */
+
+       if (export->collate == 1 && export->total > 1 && export->pages_per_sheet > 1 &&
+           (export->page + 1) % export->n_pages == 0 && (export->total - 1 + export->blank) % export->pages_per_sheet != 0) {
+               ev_document_doc_mutex_lock ();
+               ev_file_exporter_end_page (EV_FILE_EXPORTER (op->document));
+               /* keep track of how many blank pages have been added */
+               export->blank += export->pages_per_sheet - (export->total - 1 + export->blank) % export->pages_per_sheet;
+               ev_document_doc_mutex_unlock ();
+       }
+
+
        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;
-
                        update_progress (export);
-                       
                        export_print_done (export);
 
                        return FALSE;
                }
        }
 
-       if (export->pages_per_sheet == 1 || export->total % export->pages_per_sheet == 1) {
+       if (export->pages_per_sheet == 1 || (export->total + export->blank) % 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 ();
@@ -988,8 +1051,6 @@ ev_print_operation_export_print_dialog_response_cb (GtkDialog              *dial
                return;
        }
 
-       ev_print_operation_update_status (op, -1, -1, 0.0);
-       
        export->print_preview = (response == GTK_RESPONSE_APPLY);
        
        printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dialog));
@@ -1062,8 +1123,25 @@ ev_print_operation_export_print_dialog_response_cb (GtkDialog              *dial
                
                break;
        }
-       clamp_ranges (export);
+       if (export->n_ranges < 1 || !clamp_ranges (export)) {
+               GtkWidget *message_dialog;
+
+               message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+                                                GTK_DIALOG_MODAL,
+                                                GTK_MESSAGE_WARNING,
+                                                GTK_BUTTONS_CLOSE,
+                                                "%s", _("Invalid page selection"));
+               gtk_window_set_title (GTK_WINDOW (message_dialog), _("Warning"));
+               gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog),
+                                                         "%s", _("Your print range selection does not include any page"));
+               g_signal_connect (message_dialog, "response",
+                                 G_CALLBACK (gtk_widget_destroy),
+                                 NULL);
+               gtk_widget_show (message_dialog);
 
+               return;
+       } else  ev_print_operation_update_status (op, -1, -1, 0.0);
        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;
@@ -1294,12 +1372,300 @@ ev_print_operation_export_class_init (EvPrintOperationExportClass *klass)
        g_object_class->finalize = ev_print_operation_export_finalize;
 }
 
+#if GTK_CHECK_VERSION (2, 17, 1)
+/* Print to cairo interface */
+#define EV_TYPE_PRINT_OPERATION_PRINT         (ev_print_operation_print_get_type())
+#define EV_PRINT_OPERATION_PRINT(object)      (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_PRINT_OPERATION_PRINT, EvPrintOperationPrint))
+#define EV_PRINT_OPERATION_PRINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_PRINT_OPERATION_PRINT, EvPrintOperationPrintClass))
+#define EV_IS_PRINT_OPERATION_PRINT(object)   (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_PRINT_OPERATION_PRINT))
+
+typedef struct _EvPrintOperationPrint      EvPrintOperationPrint;
+typedef struct _EvPrintOperationPrintClass EvPrintOperationPrintClass;
+
+static GType ev_print_operation_print_get_type (void) G_GNUC_CONST;
+
+struct _EvPrintOperationPrint {
+       EvPrintOperation parent;
+
+       GtkPrintOperation *op;
+       EvJob             *job_print;
+       gchar             *job_name;
+};
+
+struct _EvPrintOperationPrintClass {
+       EvPrintOperationClass parent_class;
+};
+
+G_DEFINE_TYPE (EvPrintOperationPrint, ev_print_operation_print, EV_TYPE_PRINT_OPERATION)
+
+static void
+ev_print_operation_print_set_current_page (EvPrintOperation *op,
+                                          gint              current_page)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_set_current_page (print->op, current_page);
+}
+
+static void
+ev_print_operation_print_set_print_settings (EvPrintOperation *op,
+                                            GtkPrintSettings *print_settings)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_set_print_settings (print->op, print_settings);
+}
+
+static GtkPrintSettings *
+ev_print_operation_print_get_print_settings (EvPrintOperation *op)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       return gtk_print_operation_get_print_settings (print->op);
+}
+
+static void
+ev_print_operation_print_set_default_page_setup (EvPrintOperation *op,
+                                                GtkPageSetup     *page_setup)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_set_default_page_setup (print->op, page_setup);
+}
+
+static GtkPageSetup *
+ev_print_operation_print_get_default_page_setup (EvPrintOperation *op)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       return gtk_print_operation_get_default_page_setup (print->op);
+}
+
+static void
+ev_print_operation_print_set_job_name (EvPrintOperation *op,
+                                      const gchar      *job_name)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       g_free (print->job_name);
+       print->job_name = g_strdup (job_name);
+
+       gtk_print_operation_set_job_name (print->op, print->job_name);
+}
+
+static const gchar *
+ev_print_operation_print_get_job_name (EvPrintOperation *op)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       if (!print->job_name) {
+               gchar *name;
+
+               g_object_get (print->op, "job_name", &name, NULL);
+               print->job_name = name;
+       }
+
+       return print->job_name;
+}
+
+static void
+ev_print_operation_print_run (EvPrintOperation *op,
+                             GtkWindow        *parent)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_run (print->op,
+                                GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                parent, NULL);
+}
+
+static void
+ev_print_operation_print_cancel (EvPrintOperation *op)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_cancel (print->op);
+}
+
+static void
+ev_print_operation_print_get_error (EvPrintOperation *op,
+                                   GError          **error)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (op);
+
+       gtk_print_operation_get_error (print->op, error);
+}
+
+static void
+ev_print_operation_print_begin_print (EvPrintOperationPrint *print,
+                                     GtkPrintContext       *context)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (print);
+       gint              n_pages;
+
+       n_pages = ev_page_cache_get_n_pages (ev_page_cache_get (op->document));
+       gtk_print_operation_set_n_pages (print->op, n_pages);
+
+       /* FIXME: gtk_print should provide the progress */
+       ev_print_operation_update_status (op, -1, n_pages, 0);
+
+       g_signal_emit (op, signals[BEGIN_PRINT], 0);
+}
+
+static void
+ev_print_operation_print_done (EvPrintOperationPrint  *print,
+                              GtkPrintOperationResult result)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (print);
+
+       /* FIXME: gtk_print should provide the progress */
+       ev_print_operation_update_status (op, 0, 1, 1.0);
+
+       g_signal_emit (op, signals[DONE], 0, result);
+}
+
+static void
+print_job_finished (EvJobPrint            *job,
+                   EvPrintOperationPrint *print)
+{
+       gtk_print_operation_draw_page_finish (print->op);
+       ev_job_print_set_cairo (job, NULL);
+}
+
+static void
+print_job_cancelled (EvJobPrint            *job,
+                    EvPrintOperationPrint *print)
+{
+       gtk_print_operation_cancel (print->op);
+}
+
+static void
+ev_print_operation_print_draw_page (EvPrintOperationPrint *print,
+                                   GtkPrintContext       *context,
+                                   gint                   page)
+{
+       EvPrintOperation *op = EV_PRINT_OPERATION (print);
+       cairo_t          *cr;
+       gdouble           cr_width, cr_height;
+       gint              width, height;
+
+       gtk_print_operation_set_defer_drawing (print->op);
+
+       if (!print->job_print) {
+               print->job_print = ev_job_print_new (op->document);
+               g_signal_connect (G_OBJECT (print->job_print), "finished",
+                                 G_CALLBACK (print_job_finished),
+                                 (gpointer)print);
+               g_signal_connect (G_OBJECT (print->job_print), "cancelled",
+                                 G_CALLBACK (print_job_cancelled),
+                                 (gpointer)print);
+       }
+
+       ev_job_print_set_page (EV_JOB_PRINT (print->job_print), page);
+
+       cr = gtk_print_context_get_cairo_context (context);
+       cr_width = gtk_print_context_get_width (context);
+       cr_height = gtk_print_context_get_height (context);
+       ev_page_cache_get_size (ev_page_cache_get (op->document),
+                               page, 0, 1.0,
+                               &width, &height);
+       cairo_scale (cr, cr_width / (gdouble)width, cr_height / (gdouble)height);
+
+       ev_job_print_set_cairo (EV_JOB_PRINT (print->job_print), cr);
+       ev_job_scheduler_push_job (print->job_print, EV_JOB_PRIORITY_NONE);
+}
+
+static void
+ev_print_operation_print_finalize (GObject *object)
+{
+       EvPrintOperationPrint *print = EV_PRINT_OPERATION_PRINT (object);
+
+       if (print->op) {
+               g_object_unref (print->op);
+               print->op = NULL;
+       }
+
+       if (print->job_name) {
+               g_free (print->job_name);
+               print->job_name = NULL;
+       }
+
+       if (print->job_print) {
+               if (!ev_job_is_finished (print->job_print))
+                       ev_job_cancel (print->job_print);
+               g_signal_handlers_disconnect_by_func (print->job_print,
+                                                     print_job_finished,
+                                                     print);
+               g_signal_handlers_disconnect_by_func (print->job_print,
+                                                     print_job_cancelled,
+                                                     print);
+               g_object_unref (print->job_print);
+               print->job_print = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_print_operation_print_parent_class)->finalize) (object);
+}
+
+static void
+ev_print_operation_print_init (EvPrintOperationPrint *print)
+{
+       print->op = gtk_print_operation_new ();
+       g_signal_connect_swapped (print->op, "begin_print",
+                                 G_CALLBACK (ev_print_operation_print_begin_print),
+                                 print);
+       g_signal_connect_swapped (print->op, "done",
+                                 G_CALLBACK (ev_print_operation_print_done),
+                                 print);
+       g_signal_connect_swapped (print->op, "draw_page",
+                                 G_CALLBACK (ev_print_operation_print_draw_page),
+                                 print);
+       gtk_print_operation_set_allow_async (print->op, TRUE);
+}
+
+static void
+ev_print_operation_print_class_init (EvPrintOperationPrintClass *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_print_set_current_page;
+       ev_print_op_class->set_print_settings = ev_print_operation_print_set_print_settings;
+       ev_print_op_class->get_print_settings = ev_print_operation_print_get_print_settings;
+       ev_print_op_class->set_default_page_setup = ev_print_operation_print_set_default_page_setup;
+       ev_print_op_class->get_default_page_setup = ev_print_operation_print_get_default_page_setup;
+       ev_print_op_class->set_job_name = ev_print_operation_print_set_job_name;
+       ev_print_op_class->get_job_name = ev_print_operation_print_get_job_name;
+       ev_print_op_class->run = ev_print_operation_print_run;
+       ev_print_op_class->cancel = ev_print_operation_print_cancel;
+       ev_print_op_class->get_error = ev_print_operation_print_get_error;
+
+       g_object_class->finalize = ev_print_operation_print_finalize;
+}
+#endif /* GTK_CHECK_VERSION (2, 17, 1) */
+
+gboolean ev_print_operation_exists_for_document (EvDocument *document)
+{
+#if GTK_CHECK_VERSION (2, 17, 1)
+       return (EV_IS_FILE_EXPORTER(document) || EV_IS_DOCUMENT_PRINT(document));
+#else
+       return EV_IS_FILE_EXPORTER(document);
+#endif
+}
+
 /* Factory method */
 EvPrintOperation *
 ev_print_operation_new (EvDocument *document)
 {
-       /* TODO: EvPrintOperationPrint */
+       EvPrintOperation *op;
 
-       return EV_PRINT_OPERATION (g_object_new (EV_TYPE_PRINT_OPERATION_EXPORT,
-                                                "document", document, NULL));
+#if GTK_CHECK_VERSION (2, 17, 1)
+       if (EV_IS_DOCUMENT_PRINT (document))
+               op = EV_PRINT_OPERATION (g_object_new (EV_TYPE_PRINT_OPERATION_PRINT,
+                                                      "document", document, NULL));
+       else
+#endif
+               op = EV_PRINT_OPERATION (g_object_new (EV_TYPE_PRINT_OPERATION_EXPORT,
+                                                      "document", document, NULL));
+
+       return op;
 }