#include "ev-selection.h"
 #include "ev-async-renderer.h"
 #include "ev-ps-exporter.h"
+#include "ev-window.h"
 
 #include <glib/gstdio.h>
 #include <unistd.h>
                job->error = 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);
 }
 
 }
 
 EvJob *
-ev_job_print_new (EvDocument *document,
-                 gdouble     width,
-                 gdouble     height)
+ev_job_print_new (EvDocument   *document,
+                 EvPrintRange *ranges,
+                 gint          n_ranges,
+                 gdouble       width,
+                 gdouble       height)
 {
        EvJobPrint *job;
 
 
        job->temp_file = NULL;
        job->error = NULL;
+
+       job->ranges = ranges;
+       job->n_ranges = n_ranges;
        
        job->width = width;
        job->height = height;
        return EV_JOB (job);
 }
 
+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 (EvJobPrint *job,
+                        gint        page)
+{
+       gint i;
+
+       for (i = 0; i < job->n_ranges; i++) {
+               if (page >= job->ranges[i].start &&
+                   page <= job->ranges[i].end)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 void
 ev_job_print_run (EvJobPrint *job)
 {
        EvDocument *document = EV_JOB (job)->document;
        gint        fd;
        gint        last_page;
+       gint        first_page;
        gint        i;
        
        g_return_if_fail (EV_IS_JOB_PRINT (job));
                return;
        }
 
-       last_page = ev_document_get_n_pages (document) - 1;
-       
+       first_page = ev_print_job_get_first_page (job);
+       last_page = ev_print_job_get_last_page (job);
+
        ev_document_doc_mutex_lock ();
        ev_ps_exporter_begin (EV_PS_EXPORTER (document),
                              job->temp_file,
-                             MIN (0, last_page),
-                             MAX (0, last_page),
+                             MIN (first_page, last_page),
+                             MAX (first_page, last_page),
                              job->width, job->height, FALSE);
        ev_document_doc_mutex_unlock ();
 
-       for (i = 0; i <= last_page; i++) {
+       for (i = first_page; i <= last_page; i++) {
                EvRenderContext *rc;
 
-               rc = ev_render_context_new (0, i, 1.0);
+               if (job->n_ranges > 0 &&
+                   !ev_print_job_print_page (job, i))
+                       continue;
                
+               rc = ev_render_context_new (0, i, 1.0);
+
                ev_document_doc_mutex_lock ();
                ev_ps_exporter_do_page (EV_PS_EXPORTER (document), rc);
                ev_document_doc_mutex_unlock ();
 
                                    gint       response,
                                    EvWindow  *window)
 {
-       EvBackend document_type;
-       gboolean  export_to_ps = TRUE;
+       EvBackend     document_type;
+       gboolean      export_to_ps = TRUE;
+       GtkPrintPages print_pages;
        
        if (response != GTK_RESPONSE_OK) {
                gtk_widget_destroy (GTK_WIDGET (dialog));
                gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dialog)));
 
        document_type = ev_document_factory_get_backend (window->priv->document);
-       switch (document_type) {
-               case EV_BACKEND_PDF:
-                       export_to_ps = !gtk_printer_accepts_pdf (window->priv->printer);
-                       break;
-               case EV_BACKEND_PS:
-                       export_to_ps = FALSE;
-                       break;
-               default:
-                       export_to_ps = TRUE;
-                       break;
+       print_pages = gtk_print_settings_get_print_pages (window->priv->print_settings);
+       
+       if (print_pages == GTK_PRINT_PAGES_ALL) {
+               switch (document_type) {
+                       case EV_BACKEND_PDF:
+                               /* Export to ps when printing to file */
+                               if (gtk_print_settings_has_key (window->priv->print_settings,
+                                                               GTK_PRINT_SETTINGS_OUTPUT_URI)) {
+                                       export_to_ps = TRUE;
+                               } else {
+                                       export_to_ps = !gtk_printer_accepts_pdf (window->priv->printer);
+                               }
+
+                               break;
+                       case EV_BACKEND_PS:
+                               export_to_ps = FALSE;
+                               break;
+                       default:
+                               export_to_ps = TRUE;
+                               break;
+               }
        }
 
        if ((export_to_ps || document_type == EV_BACKEND_PS) &&
        }
 
        if (export_to_ps) {
-               EvPageCache *page_cache;
-               gint         width;
-               gint         height;
+               EvPrintRange *ranges = NULL;
+               EvPageCache  *page_cache;
+               gint          n_ranges = 0;
+               gint          current_page;
+               gint          width;
+               gint          height;
 
                ev_window_clear_print_job (window);
 
+               current_page =
+                       gtk_print_unix_dialog_get_current_page (GTK_PRINT_UNIX_DIALOG (dialog));
+
+               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;
+
+                               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));
+                       }
+                               break;
+                       default:
+                               break;
+               }
+                               
                page_cache = ev_page_cache_get (window->priv->document);
                ev_page_cache_get_size (page_cache,
-                                       ev_page_cache_get_current_page (page_cache),
-                                       0, 1.0, &width, &height);
+                                       current_page,
+                                       0, 1.0,
+                                       &width, &height);
        
                window->priv->print_job =
                        ev_job_print_new (window->priv->document,
+                                         ranges, n_ranges,
                                          (gdouble)width,
                                          (gdouble)height);
+               
                g_signal_connect (window->priv->print_job, "finished",
                                  G_CALLBACK (ev_window_print_job_cb),
                                  window);
        current_page = ev_page_cache_get_current_page (page_cache);
        document_last_page = ev_page_cache_get_n_pages (page_cache);
 
-       
        if (!ev_window->priv->print_settings)
                ev_window->priv->print_settings = gtk_print_settings_new ();
 
-       if (first_page != 1 && last_page != document_last_page) {
+       if (first_page != 1 || last_page != document_last_page) {
                GtkPageRange range;
 
-               range.start = first_page;
-               range.end = last_page;
+               /* Ranges in GtkPrint are 0 - N */
+               range.start = first_page - 1;
+               range.end = last_page - 1;
                
                gtk_print_settings_set_print_pages (ev_window->priv->print_settings,
                                                    GTK_PRINT_PAGES_RANGES);
 
        dialog = gtk_print_unix_dialog_new (_("Print"), GTK_WINDOW (ev_window));
        ev_window->priv->print_dialog = dialog;
+       gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog),
+                                                      GTK_PRINT_CAPABILITY_PAGE_SET |
+                                                      GTK_PRINT_CAPABILITY_COPIES |
+                                                      GTK_PRINT_CAPABILITY_COLLATE |
+                                                      GTK_PRINT_CAPABILITY_REVERSE |
+                                                      GTK_PRINT_CAPABILITY_SCALE |
+                                                      GTK_PRINT_CAPABILITY_GENERATE_PS);
        gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (dialog),
                                                current_page);