]> www.fi.muni.cz Git - evince.git/blob - shell/ev-jobs.c
Updated Slovenian translation
[evince.git] / shell / ev-jobs.c
1 #include <config.h>
2 #include "ev-jobs.h"
3 #include "ev-job-queue.h"
4 #include "ev-document-thumbnails.h"
5 #include "ev-document-links.h"
6 #include "ev-document-images.h"
7 #include "ev-document-forms.h"
8 #include "ev-file-exporter.h"
9 #include "ev-document-factory.h"
10 #include "ev-document-misc.h"
11 #include "ev-file-helpers.h"
12 #include "ev-document-fonts.h"
13 #include "ev-async-renderer.h"
14
15 #include <errno.h>
16 #include <glib/gstdio.h>
17 #include <glib/gi18n.h>
18 #include <unistd.h>
19
20 static void ev_job_init                 (EvJob               *job);
21 static void ev_job_class_init           (EvJobClass          *class);
22 static void ev_job_links_init           (EvJobLinks          *job);
23 static void ev_job_links_class_init     (EvJobLinksClass     *class);
24 static void ev_job_render_init          (EvJobRender         *job);
25 static void ev_job_render_class_init    (EvJobRenderClass    *class);
26 static void ev_job_thumbnail_init       (EvJobThumbnail      *job);
27 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
28 static void ev_job_load_init            (EvJobLoad           *job);
29 static void ev_job_load_class_init      (EvJobLoadClass      *class);
30 static void ev_job_save_init            (EvJobSave           *job);
31 static void ev_job_save_class_init      (EvJobSaveClass      *class);
32 static void ev_job_print_init           (EvJobPrint          *job);
33 static void ev_job_print_class_init     (EvJobPrintClass     *class);
34
35 enum {
36         FINISHED,
37         LAST_SIGNAL
38 };
39
40 enum {
41         PAGE_READY,
42         RENDER_LAST_SIGNAL
43 };
44
45 static guint job_signals[LAST_SIGNAL] = { 0 };
46 static guint job_render_signals[RENDER_LAST_SIGNAL] = { 0 };
47
48 G_DEFINE_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
49 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
50 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
51 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
52 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
53 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
54 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
55 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
56
57 static void ev_job_init (EvJob *job) { /* Do Nothing */ }
58
59 static void
60 ev_job_dispose (GObject *object)
61 {
62         EvJob *job;
63
64         job = EV_JOB (object);
65
66         if (job->document) {
67                 g_object_unref (job->document);
68                 job->document = NULL;
69         }
70
71         (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
72 }
73
74 static void
75 ev_job_class_init (EvJobClass *class)
76 {
77         GObjectClass *oclass;
78
79         oclass = G_OBJECT_CLASS (class);
80
81         oclass->dispose = ev_job_dispose;
82
83         job_signals [FINISHED] =
84                 g_signal_new ("finished",
85                               EV_TYPE_JOB,
86                               G_SIGNAL_RUN_LAST,
87                               G_STRUCT_OFFSET (EvJobClass, finished),
88                               NULL, NULL,
89                               g_cclosure_marshal_VOID__VOID,
90                               G_TYPE_NONE, 0);
91 }
92
93
94 static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ }
95
96 static void
97 ev_job_links_dispose (GObject *object)
98 {
99         EvJobLinks *job;
100
101         job = EV_JOB_LINKS (object);
102
103         if (job->model) {
104                 g_object_unref (job->model);
105                 job->model = NULL;
106         }
107
108         (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
109 }
110
111 static void
112 ev_job_links_class_init (EvJobLinksClass *class)
113 {
114         GObjectClass *oclass;
115
116         oclass = G_OBJECT_CLASS (class);
117
118         oclass->dispose = ev_job_links_dispose;
119 }
120
121
122 static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ }
123
124 static void
125 ev_job_render_dispose (GObject *object)
126 {
127         EvJobRender *job;
128
129         job = EV_JOB_RENDER (object);
130
131         if (job->ev_page) {
132                 g_object_unref (job->ev_page);
133                 job->ev_page = NULL;
134         }
135         
136         if (job->surface) {
137                 cairo_surface_destroy (job->surface);
138                 job->surface = NULL;
139         }
140
141         if (job->selection) {
142                 cairo_surface_destroy (job->selection);
143                 job->selection = NULL;
144         }
145
146         if (job->selection_region) {
147                 gdk_region_destroy (job->selection_region);
148                 job->selection_region = NULL;
149         }
150
151         (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
152 }
153
154 static void
155 ev_job_render_class_init (EvJobRenderClass *class)
156 {
157         GObjectClass *oclass;
158
159         oclass = G_OBJECT_CLASS (class);
160
161         job_render_signals [PAGE_READY] =
162                 g_signal_new ("page-ready",
163                               EV_TYPE_JOB_RENDER,
164                               G_SIGNAL_RUN_LAST,
165                               G_STRUCT_OFFSET (EvJobRenderClass, page_ready),
166                               NULL, NULL,
167                               g_cclosure_marshal_VOID__VOID,
168                               G_TYPE_NONE, 0);
169
170         oclass->dispose = ev_job_render_dispose;
171 }
172
173 static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ }
174
175 static void
176 ev_job_thumbnail_dispose (GObject *object)
177 {
178         EvJobThumbnail *job;
179
180         job = EV_JOB_THUMBNAIL (object);
181
182         if (job->thumbnail) {
183                 g_object_unref (job->thumbnail);
184                 job->thumbnail = NULL;
185         }
186
187         (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
188 }
189
190 static void
191 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
192 {
193         GObjectClass *oclass;
194
195         oclass = G_OBJECT_CLASS (class);
196
197         oclass->dispose = ev_job_thumbnail_dispose;
198 }
199
200 static void ev_job_print_init (EvJobPrint *job) { /* Do Nothing */ }
201
202 static void
203 ev_job_print_dispose (GObject *object)
204 {
205         EvJobPrint *job;
206
207         job = EV_JOB_PRINT (object);
208
209         if (job->temp_file) {
210                 g_unlink (job->temp_file);
211                 g_free (job->temp_file);
212                 job->temp_file = NULL;
213         }
214
215         if (job->error) {
216                 g_error_free (job->error);
217                 job->error = NULL;
218         }
219
220         if (job->ranges) {
221                 g_free (job->ranges);
222                 job->ranges = NULL;
223                 job->n_ranges = 0;
224         }
225
226         (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
227 }
228
229 static void
230 ev_job_print_class_init (EvJobPrintClass *class)
231 {
232         GObjectClass *oclass;
233
234         oclass = G_OBJECT_CLASS (class);
235
236         oclass->dispose = ev_job_print_dispose;
237 }
238
239 /* Public functions */
240 void
241 ev_job_finished (EvJob *job)
242 {
243         g_return_if_fail (EV_IS_JOB (job));
244
245         g_signal_emit (job, job_signals[FINISHED], 0);
246 }
247
248 EvJob *
249 ev_job_links_new (EvDocument *document)
250 {
251         EvJob *job;
252
253         job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
254         job->document = g_object_ref (document);
255
256         return job;
257 }
258
259 void
260 ev_job_links_run (EvJobLinks *job)
261 {
262         g_return_if_fail (EV_IS_JOB_LINKS (job));
263
264         ev_document_doc_mutex_lock ();
265         job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document));
266         EV_JOB (job)->finished = TRUE;
267         ev_document_doc_mutex_unlock ();
268 }
269
270 EvJob *
271 ev_job_render_new (EvDocument   *document,
272                    gint          page,
273                    gint          rotation,
274                    gdouble       scale, 
275                    gint          width,
276                    gint          height,
277                    EvRenderFlags flags)
278 {
279         EvJobRender *job;
280
281         job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
282
283         EV_JOB (job)->document = g_object_ref (document);
284         job->page = page;
285         job->rotation = rotation;
286         job->scale = scale;
287         job->target_width = width;
288         job->target_height = height;
289         job->flags = flags;
290
291         if (EV_IS_ASYNC_RENDERER (document)) {  
292                 EV_JOB (job)->async = TRUE;
293         }
294
295         return EV_JOB (job);
296 }
297
298 void
299 ev_job_render_set_selection_info (EvJobRender     *job,
300                                   EvRectangle     *selection_points,
301                                   EvSelectionStyle selection_style,
302                                   GdkColor        *text,
303                                   GdkColor        *base)
304 {
305         job->flags |= EV_RENDER_INCLUDE_SELECTION;
306         
307         job->selection_points = *selection_points;
308         job->selection_style = selection_style;
309         job->text = *text;
310         job->base = *base;
311 }
312
313 static void
314 render_finished_cb (EvDocument      *document,
315                     GdkPixbuf       *pixbuf,
316                     EvJobRender     *job)
317 {
318         g_signal_handlers_disconnect_by_func (EV_JOB (job)->document,
319                                               render_finished_cb, job);
320
321         job->surface = ev_document_misc_surface_from_pixbuf (pixbuf);
322         job->page_ready = TRUE;
323         g_signal_emit (job, job_render_signals[PAGE_READY], 0);
324         EV_JOB (job)->finished = TRUE;
325         ev_job_finished (EV_JOB (job));
326 }
327
328 static gboolean
329 notify_page_ready (EvJobRender *job)
330 {
331         g_signal_emit (job, job_render_signals[PAGE_READY], 0);
332
333         return FALSE;
334 }
335
336 static void
337 ev_job_render_page_ready (EvJobRender *job)
338 {
339         job->page_ready = TRUE;
340         g_idle_add_full (G_PRIORITY_HIGH_IDLE,
341                          (GSourceFunc)notify_page_ready,
342                          g_object_ref (job),
343                          (GDestroyNotify)g_object_unref);
344 }
345
346 void
347 ev_job_render_run (EvJobRender *job)
348 {
349         g_return_if_fail (EV_IS_JOB_RENDER (job));
350
351         ev_document_doc_mutex_lock ();
352
353         if (EV_JOB (job)->async) {
354                 EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
355                 ev_async_renderer_render_pixbuf (renderer, job->page, job->scale,
356                                                  job->rotation);
357                 g_signal_connect (EV_JOB (job)->document, "render_finished",
358                                   G_CALLBACK (render_finished_cb), job);
359         } else {
360                 EvRenderContext *rc;
361                 
362                 ev_document_fc_mutex_lock ();
363
364                 job->ev_page = ev_document_get_page (EV_JOB (job)->document, job->page);
365
366                 rc = ev_render_context_new (job->ev_page, job->rotation, job->scale);
367                 
368                 job->surface = ev_document_render (EV_JOB (job)->document, rc);
369                 if ((job->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (EV_JOB (job)->document)) {
370                         ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document),
371                                                        rc,
372                                                        &(job->selection),
373                                                        &(job->selection_points),
374                                                        NULL,
375                                                        job->selection_style,
376                                                        &(job->text), &(job->base));
377                         job->selection_region =
378                                 ev_selection_get_selection_region (EV_SELECTION (EV_JOB (job)->document),
379                                                                    rc,
380                                                                    job->selection_style,
381                                                                    &(job->selection_points));
382                 }
383
384                 ev_job_render_page_ready (job);
385                 
386                 ev_document_fc_mutex_unlock ();
387                 
388                 if ((job->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (EV_JOB (job)->document))
389                         job->text_mapping =
390                                 ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document), rc);
391                 if ((job->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document))
392                         job->link_mapping =
393                                 ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), job->page);
394                 if ((job->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document))
395                         job->form_field_mapping =
396                                 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB (job)->document),
397                                                                    job->ev_page);
398                 if ((job->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document))
399                         job->image_mapping =
400                                 ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
401                                                                       job->page);
402                 g_object_unref (rc);
403                 
404                 EV_JOB (job)->finished = TRUE;
405         }
406
407         ev_document_doc_mutex_unlock ();
408 }
409
410 EvJob *
411 ev_job_thumbnail_new (EvDocument *document,
412                       gint        page,
413                       gint        rotation,
414                       gdouble     scale)
415 {
416         EvJobThumbnail *job;
417
418         job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
419
420         EV_JOB (job)->document = g_object_ref (document);
421         job->page = page;
422         job->rotation = rotation;
423         job->scale = scale;
424
425         return EV_JOB (job);
426 }
427
428 void
429 ev_job_thumbnail_run (EvJobThumbnail *job)
430 {
431         EvRenderContext *rc;
432         EvPage          *page;
433         
434         g_return_if_fail (EV_IS_JOB_THUMBNAIL (job));
435
436         ev_document_doc_mutex_lock ();
437
438         page = ev_document_get_page (EV_JOB (job)->document, job->page);
439         rc = ev_render_context_new (page, job->rotation, job->scale);
440         g_object_unref (page);
441
442         job->thumbnail =
443                 ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document),
444                                                       rc, TRUE);
445         g_object_unref (rc);
446         ev_document_doc_mutex_unlock ();
447         
448         EV_JOB (job)->finished = TRUE;
449 }
450
451 static void ev_job_fonts_init (EvJobFonts *job) { /* Do Nothing */ }
452
453 static void ev_job_fonts_class_init (EvJobFontsClass *class) { /* Do Nothing */ }
454
455 EvJob *
456 ev_job_fonts_new (EvDocument *document)
457 {
458         EvJobFonts *job;
459
460         job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
461
462         EV_JOB (job)->document = g_object_ref (document);
463
464         return EV_JOB (job);
465 }
466
467 void
468 ev_job_fonts_run (EvJobFonts *job)
469 {
470         EvDocumentFonts *fonts;
471
472         g_return_if_fail (EV_IS_JOB_FONTS (job));
473
474         ev_document_doc_mutex_lock ();
475         
476         fonts = EV_DOCUMENT_FONTS (EV_JOB (job)->document);
477         ev_document_fc_mutex_lock ();
478         job->scan_completed = !ev_document_fonts_scan (fonts, 20);
479         ev_document_fc_mutex_unlock ();
480         
481         EV_JOB (job)->finished = TRUE;
482
483         ev_document_doc_mutex_unlock ();
484 }
485
486 static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ }
487
488 static void
489 ev_job_load_dispose (GObject *object)
490 {
491         EvJobLoad *job = EV_JOB_LOAD (object);
492
493         if (job->uri) {
494                 g_free (job->uri);
495                 job->uri = NULL;
496         }
497
498         if (job->error) {
499                 g_error_free (job->error);
500                 job->error = NULL;
501         }
502
503         if (job->dest) {
504                 g_object_unref (job->dest);
505                 job->dest = NULL;
506         }
507
508         if (job->search_string) {
509                 g_free (job->search_string);
510                 job->search_string = NULL;
511         }
512
513         (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
514 }
515
516 static void
517 ev_job_load_class_init (EvJobLoadClass *class)
518 {
519         GObjectClass *oclass;
520
521         oclass = G_OBJECT_CLASS (class);
522
523         oclass->dispose = ev_job_load_dispose;
524 }
525
526
527 EvJob *
528 ev_job_load_new (const gchar    *uri,
529                  EvLinkDest     *dest,
530                  EvWindowRunMode mode,
531                  const gchar    *search_string)
532 {
533         EvJobLoad *job;
534
535         job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
536
537         job->uri = g_strdup (uri);
538         if (dest)
539                 job->dest = g_object_ref (dest);
540
541         job->mode = mode;
542         if (search_string)
543                 job->search_string = g_strdup (search_string);
544
545         return EV_JOB (job);
546 }
547
548 void
549 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
550 {
551         if (job->uri)
552                 g_free (job->uri);
553         job->uri = g_strdup (uri);
554 }
555
556 void
557 ev_job_load_run (EvJobLoad *job)
558 {
559         g_return_if_fail (EV_IS_JOB_LOAD (job));
560         
561         if (job->error) {
562                 g_error_free (job->error);
563                 job->error = NULL;
564         }
565
566         ev_document_fc_mutex_lock ();
567         
568         /* This job may already have a document even if the job didn't complete
569            because, e.g., a password is required - if so, just reload rather than
570            creating a new instance */
571         if (EV_JOB (job)->document) {
572                 ev_document_load (EV_JOB (job)->document,
573                                   job->uri,
574                                   &job->error);
575         } else {
576                 EV_JOB(job)->document =
577                         ev_document_factory_get_document (job->uri,
578                                                           &job->error);
579         }
580
581         ev_document_fc_mutex_unlock ();
582         EV_JOB (job)->finished = TRUE;
583 }
584
585 static void ev_job_save_init (EvJobSave *job) { /* Do Nothing */ }
586
587 static void
588 ev_job_save_dispose (GObject *object)
589 {
590         EvJobSave *job = EV_JOB_SAVE (object);
591
592         if (job->uri) {
593                 g_free (job->uri);
594                 job->uri = NULL;
595         }
596
597         if (job->document_uri) {
598                 g_free (job->document_uri);
599                 job->document_uri = NULL;
600         }
601
602         if (job->error) {
603                 g_error_free (job->error);
604                 job->error = NULL;
605         }
606
607         (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
608 }
609
610 static void
611 ev_job_save_class_init (EvJobSaveClass *class)
612 {
613         GObjectClass *oclass;
614
615         oclass = G_OBJECT_CLASS (class);
616
617         oclass->dispose = ev_job_save_dispose;
618 }
619
620 EvJob *
621 ev_job_save_new (EvDocument  *document,
622                  const gchar *uri,
623                  const gchar *document_uri)
624 {
625         EvJobSave *job;
626
627         job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
628
629         EV_JOB (job)->document = g_object_ref (document);
630         job->uri = g_strdup (uri);
631         job->document_uri = g_strdup (document_uri);
632         job->error = NULL;
633
634         return EV_JOB (job);
635 }
636
637 void
638 ev_job_save_run (EvJobSave *job)
639 {
640         gint   fd;
641         gchar *filename;
642         gchar *tmp_filename;
643         gchar *local_uri;
644         
645         filename = ev_tmp_filename ("saveacopy");
646         tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
647         g_free (filename);
648
649         fd = g_mkstemp (tmp_filename);
650         if (fd == -1) {
651                 gchar *display_name;
652                 gint   save_errno = errno;
653
654                 display_name = g_filename_display_name (tmp_filename);
655                 g_set_error (&(job->error),
656                              G_FILE_ERROR,
657                              g_file_error_from_errno (save_errno),
658                              _("Failed to create file “%s”: %s"),
659                              display_name, g_strerror (save_errno));
660                 g_free (display_name);
661                 g_free (tmp_filename);
662
663                 return;
664         }
665
666         ev_document_doc_mutex_lock ();
667
668         /* Save document to temp filename */
669         local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
670         ev_document_save (EV_JOB (job)->document, local_uri, &(job->error));
671         close (fd);
672
673         ev_document_doc_mutex_unlock ();
674
675         if (job->error) {
676                 g_free (local_uri);
677                 return;
678         }
679
680         /* If original document was compressed,
681          * compress it again before saving
682          */
683         if (g_object_get_data (G_OBJECT (EV_JOB (job)->document),
684                                "uri-uncompressed")) {
685                 EvCompressionType ctype = EV_COMPRESSION_NONE;
686                 const gchar      *ext;
687                 gchar            *uri_comp;
688                 
689                 ext = g_strrstr (job->document_uri, ".gz");
690                 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
691                         ctype = EV_COMPRESSION_GZIP;
692                 
693                 ext = g_strrstr (job->document_uri, ".bz2");
694                 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
695                         ctype = EV_COMPRESSION_BZIP2;
696
697                 uri_comp = ev_file_compress (local_uri, ctype, &(job->error));
698                 g_free (local_uri);
699                 ev_tmp_filename_unlink (tmp_filename);
700
701                 if (!uri_comp || job->error) {
702                         local_uri = NULL;
703                 } else {
704                         local_uri = uri_comp;
705                 }
706         }
707
708         g_free (tmp_filename);
709         
710         if (job->error) {
711                 g_free (local_uri);
712                 return;
713         }
714
715         if (!local_uri)
716                 return;
717
718         ev_xfer_uri_simple (local_uri, job->uri, &(job->error));
719         ev_tmp_uri_unlink (local_uri);
720 }
721
722 EvJob *
723 ev_job_print_new (EvDocument    *document,
724                   const gchar   *format,
725                   gdouble        width,
726                   gdouble        height,
727                   EvPrintRange  *ranges,
728                   gint           n_ranges,
729                   EvPrintPageSet page_set,
730                   gint           pages_per_sheet,
731                   gint           copies,
732                   gdouble        collate,
733                   gdouble        reverse)
734 {
735         EvJobPrint *job;
736
737         job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
738
739         EV_JOB (job)->document = g_object_ref (document);
740
741         job->format = format;
742         
743         job->temp_file = NULL;
744         job->error = NULL;
745
746         job->width = width;
747         job->height = height;
748
749         job->ranges = ranges;
750         job->n_ranges = n_ranges;
751
752         job->page_set = page_set;
753
754         job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
755         
756         job->copies = copies;
757         job->collate = collate;
758         job->reverse = reverse;
759         
760         return EV_JOB (job);
761 }
762
763 static gint
764 ev_print_job_get_first_page (EvJobPrint *job)
765 {
766         gint i;
767         gint first_page = G_MAXINT;
768         
769         if (job->n_ranges == 0)
770                 return 0;
771
772         for (i = 0; i < job->n_ranges; i++) {
773                 if (job->ranges[i].start < first_page)
774                         first_page = job->ranges[i].start;
775         }
776
777         return MAX (0, first_page);
778 }
779
780 static gint
781 ev_print_job_get_last_page (EvJobPrint *job)
782 {
783         gint i;
784         gint last_page = G_MININT;
785         gint max_page;
786
787         max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
788
789         if (job->n_ranges == 0)
790                 return max_page;
791
792         for (i = 0; i < job->n_ranges; i++) {
793                 if (job->ranges[i].end > last_page)
794                         last_page = job->ranges[i].end;
795         }
796
797         return MIN (max_page, last_page);
798 }
799
800 static gboolean
801 ev_print_job_print_page_in_set (EvJobPrint *job,
802                                 gint        page)
803 {
804         switch (job->page_set) {
805                 case EV_PRINT_PAGE_SET_EVEN:
806                         return page % 2 == 0;
807                 case EV_PRINT_PAGE_SET_ODD:
808                         return page % 2 != 0;
809                 case EV_PRINT_PAGE_SET_ALL:
810                         return TRUE;
811         }
812
813         return FALSE;
814 }
815
816 static gint *
817 ev_job_print_get_page_list (EvJobPrint *job,
818                             gint       *n_pages)
819 {
820         gint  i, j, page, max_page;
821         gint  pages = 0;
822         gint *page_list;
823
824         max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
825
826         for (i = 0; i < job->n_ranges; i++) {
827                 gint rsize;
828                 gint start, end;
829
830                 if (job->ranges[i].start == -1)
831                         job->ranges[i].start = 0;
832                 if (job->ranges[i].end == -1)
833                         job->ranges[i].end = max_page;
834
835                 if (job->ranges[i].start > max_page)
836                         continue;
837                 
838                 start = job->ranges[i].start + 1;
839                 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
840                 rsize = end - start + 1;
841
842                 switch (job->page_set) {
843                         case EV_PRINT_PAGE_SET_EVEN:
844                                 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
845                                 break;
846                         case EV_PRINT_PAGE_SET_ODD:
847                                 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
848                                 break;
849                         default:
850                                 pages += rsize;
851                                 break;
852                 }
853         }
854
855         *n_pages = pages;
856
857         if (pages == 0)
858                 return NULL;
859
860         page_list = g_new (gint, pages);
861
862         page = 0;
863         for (i = 0; i < job->n_ranges; i++) {
864                 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
865                         if (j > max_page)
866                                 break;
867                 
868                         if (ev_print_job_print_page_in_set (job, j + 1))
869                                 page_list[page++] = j;
870                 }
871         }
872
873         return page_list;
874 }
875
876 void
877 ev_job_print_run (EvJobPrint *job)
878 {
879         EvDocument            *document = EV_JOB (job)->document;
880         EvFileExporterContext  fc;
881         EvRenderContext       *rc;
882         gint                   fd;
883         gint                  *page_list;
884         gint                   n_pages;
885         gint                   last_page;
886         gint                   first_page;
887         gint                   i, j;
888         gchar                 *filename;
889         
890         g_return_if_fail (EV_IS_JOB_PRINT (job));
891
892         if (job->temp_file)
893                 g_free (job->temp_file);
894         job->temp_file = NULL;
895         
896         if (job->error)
897                 g_error_free (job->error);
898         job->error = NULL;
899
900         filename = g_strdup_printf ("evince_print.%s.XXXXXX", job->format);
901         fd = g_file_open_tmp (filename, &job->temp_file, &job->error);
902         g_free (filename);
903         if (fd <= -1) {
904                 EV_JOB (job)->finished = TRUE;
905                 return;
906         }
907
908         page_list = ev_job_print_get_page_list (job, &n_pages);
909         if (n_pages == 0) {
910                 close (fd);
911                 EV_JOB (job)->finished = TRUE;
912                 return;
913         }
914
915         first_page = ev_print_job_get_first_page (job);
916         last_page = ev_print_job_get_last_page (job);
917
918         fc.format = g_ascii_strcasecmp (job->format, "pdf") == 0 ?
919                 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
920         fc.filename = job->temp_file;
921         fc.first_page = MIN (first_page, last_page);
922         fc.last_page = MAX (first_page, last_page);
923         fc.paper_width = job->width;
924         fc.paper_height = job->height;
925         fc.duplex = FALSE;
926         fc.pages_per_sheet = MAX (1, job->pages_per_sheet);
927
928         rc = ev_render_context_new (NULL, 0, 1.0);
929
930         ev_document_doc_mutex_lock ();
931         ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
932
933         for (i = 0; i < job->copies; i++) {
934                 gint page, step;
935                 gint n_copies;
936                 
937                 step = job->reverse ? -1 * job->pages_per_sheet : job->pages_per_sheet;
938                 page = job->reverse ? ((n_pages - 1) / job->pages_per_sheet) * job->pages_per_sheet : 0;
939                 n_copies = job->collate ? 1 : job->copies;
940
941                 while ((job->reverse && (page >= 0)) || (!job->reverse && (page < n_pages))) {
942                         gint k;
943
944                         for (k = 0; k < n_copies; k++) {
945                                 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
946                                 
947                                 for (j = 0; j < job->pages_per_sheet; j++) {
948                                         EvPage *ev_page;
949                                         
950                                         gint p = page + j;
951
952                                         if (p < 0 || p >= n_pages)
953                                                 break;
954
955                                         ev_page = ev_document_get_page (document, page_list[p]);
956                                         ev_render_context_set_page (rc, ev_page);
957                                         g_object_unref (ev_page);
958                                         
959                                         ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
960                                 }
961
962                                 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
963                         }
964
965                         page += step;
966                 }
967
968                 if (!job->collate)
969                         break;
970         }
971
972         ev_file_exporter_end (EV_FILE_EXPORTER (document));
973         ev_document_doc_mutex_unlock ();
974         
975         g_free (page_list);
976         close (fd);
977         g_object_unref (rc);
978         
979         EV_JOB (job)->finished = TRUE;
980 }