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