]> www.fi.muni.cz Git - evince.git/blob - shell/ev-jobs.c
Fixes bug #542924. Makes enums static to fix Solaris build.
[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, NULL);
252         
253         g_return_if_fail (EV_IS_JOB (job));
254
255         g_signal_emit (job, job_signals[FINISHED], 0);
256 }
257
258 EvJob *
259 ev_job_links_new (EvDocument *document)
260 {
261         EvJob *job;
262
263         ev_debug_message (DEBUG_JOBS, NULL);
264         
265         job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
266         job->document = g_object_ref (document);
267
268         return job;
269 }
270
271 void
272 ev_job_links_run (EvJobLinks *job)
273 {
274         ev_debug_message (DEBUG_JOBS, NULL);
275         
276         g_return_if_fail (EV_IS_JOB_LINKS (job));
277
278         ev_document_doc_mutex_lock ();
279         job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document));
280         EV_JOB (job)->finished = TRUE;
281         ev_document_doc_mutex_unlock ();
282 }
283
284 EvJob *
285 ev_job_render_new (EvDocument   *document,
286                    gint          page,
287                    gint          rotation,
288                    gdouble       scale, 
289                    gint          width,
290                    gint          height,
291                    EvRenderFlags flags)
292 {
293         EvJobRender *job;
294
295         ev_debug_message (DEBUG_JOBS, "page: %d", page);
296         
297         job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
298
299         EV_JOB (job)->document = g_object_ref (document);
300         job->page = page;
301         job->rotation = rotation;
302         job->scale = scale;
303         job->target_width = width;
304         job->target_height = height;
305         job->flags = flags;
306
307         if (EV_IS_ASYNC_RENDERER (document)) {  
308                 EV_JOB (job)->async = TRUE;
309         }
310
311         return EV_JOB (job);
312 }
313
314 void
315 ev_job_render_set_selection_info (EvJobRender     *job,
316                                   EvRectangle     *selection_points,
317                                   EvSelectionStyle selection_style,
318                                   GdkColor        *text,
319                                   GdkColor        *base)
320 {
321         job->flags |= EV_RENDER_INCLUDE_SELECTION;
322         
323         job->selection_points = *selection_points;
324         job->selection_style = selection_style;
325         job->text = *text;
326         job->base = *base;
327 }
328
329 static void
330 render_finished_cb (EvDocument      *document,
331                     GdkPixbuf       *pixbuf,
332                     EvJobRender     *job)
333 {
334         g_signal_handlers_disconnect_by_func (EV_JOB (job)->document,
335                                               render_finished_cb, job);
336
337         job->surface = ev_document_misc_surface_from_pixbuf (pixbuf);
338         job->page_ready = TRUE;
339         g_signal_emit (job, job_render_signals[PAGE_READY], 0);
340         EV_JOB (job)->finished = TRUE;
341         ev_job_finished (EV_JOB (job));
342 }
343
344 static gboolean
345 notify_page_ready (EvJobRender *job)
346 {
347         ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index);
348         
349         g_signal_emit (job, job_render_signals[PAGE_READY], 0);
350
351         return FALSE;
352 }
353
354 static void
355 ev_job_render_page_ready (EvJobRender *job)
356 {
357         ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index);
358         
359         job->page_ready = TRUE;
360         g_idle_add_full (G_PRIORITY_HIGH_IDLE,
361                          (GSourceFunc)notify_page_ready,
362                          g_object_ref (job),
363                          (GDestroyNotify)g_object_unref);
364 }
365
366 void
367 ev_job_render_run (EvJobRender *job)
368 {
369         g_return_if_fail (EV_IS_JOB_RENDER (job));
370
371         ev_debug_message (DEBUG_JOBS, "page: %d", job->page);
372         
373         ev_document_doc_mutex_lock ();
374
375         if (EV_JOB (job)->async) {
376                 EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
377                 ev_async_renderer_render_pixbuf (renderer, job->page, job->scale,
378                                                  job->rotation);
379                 g_signal_connect (EV_JOB (job)->document, "render_finished",
380                                   G_CALLBACK (render_finished_cb), job);
381         } else {
382                 EvRenderContext *rc;
383                 
384                 ev_document_fc_mutex_lock ();
385
386                 job->ev_page = ev_document_get_page (EV_JOB (job)->document, job->page);
387
388                 rc = ev_render_context_new (job->ev_page, job->rotation, job->scale);
389                 
390                 job->surface = ev_document_render (EV_JOB (job)->document, rc);
391                 if ((job->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (EV_JOB (job)->document)) {
392                         ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document),
393                                                        rc,
394                                                        &(job->selection),
395                                                        &(job->selection_points),
396                                                        NULL,
397                                                        job->selection_style,
398                                                        &(job->text), &(job->base));
399                         job->selection_region =
400                                 ev_selection_get_selection_region (EV_SELECTION (EV_JOB (job)->document),
401                                                                    rc,
402                                                                    job->selection_style,
403                                                                    &(job->selection_points));
404                 }
405
406                 ev_job_render_page_ready (job);
407                 
408                 ev_document_fc_mutex_unlock ();
409                 
410                 if ((job->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (EV_JOB (job)->document))
411                         job->text_mapping =
412                                 ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document), rc);
413                 if ((job->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document))
414                         job->link_mapping =
415                                 ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), job->page);
416                 if ((job->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document))
417                         job->form_field_mapping =
418                                 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB (job)->document),
419                                                                    job->ev_page);
420                 if ((job->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document))
421                         job->image_mapping =
422                                 ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
423                                                                       job->page);
424                 g_object_unref (rc);
425                 
426                 EV_JOB (job)->finished = TRUE;
427         }
428
429         ev_document_doc_mutex_unlock ();
430 }
431
432 EvJob *
433 ev_job_thumbnail_new (EvDocument *document,
434                       gint        page,
435                       gint        rotation,
436                       gdouble     scale)
437 {
438         EvJobThumbnail *job;
439
440         ev_debug_message (DEBUG_JOBS, "%d", page);
441         
442         job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
443
444         EV_JOB (job)->document = g_object_ref (document);
445         job->page = page;
446         job->rotation = rotation;
447         job->scale = scale;
448
449         return EV_JOB (job);
450 }
451
452 void
453 ev_job_thumbnail_run (EvJobThumbnail *job)
454 {
455         EvRenderContext *rc;
456         EvPage          *page;
457
458         ev_debug_message (DEBUG_JOBS, "%d", job->page);
459         
460         g_return_if_fail (EV_IS_JOB_THUMBNAIL (job));
461
462         ev_document_doc_mutex_lock ();
463
464         page = ev_document_get_page (EV_JOB (job)->document, job->page);
465         rc = ev_render_context_new (page, job->rotation, job->scale);
466         g_object_unref (page);
467
468         job->thumbnail =
469                 ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document),
470                                                       rc, TRUE);
471         g_object_unref (rc);
472         ev_document_doc_mutex_unlock ();
473         
474         EV_JOB (job)->finished = TRUE;
475 }
476
477 static void ev_job_fonts_init (EvJobFonts *job) { /* Do Nothing */ }
478
479 static void ev_job_fonts_class_init (EvJobFontsClass *class) { /* Do Nothing */ }
480
481 EvJob *
482 ev_job_fonts_new (EvDocument *document)
483 {
484         EvJobFonts *job;
485
486         ev_debug_message (DEBUG_JOBS, NULL);
487         
488         job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
489
490         EV_JOB (job)->document = g_object_ref (document);
491
492         return EV_JOB (job);
493 }
494
495 void
496 ev_job_fonts_run (EvJobFonts *job)
497 {
498         EvDocumentFonts *fonts;
499
500         ev_debug_message (DEBUG_JOBS, NULL);
501         
502         g_return_if_fail (EV_IS_JOB_FONTS (job));
503
504         ev_document_doc_mutex_lock ();
505         
506         fonts = EV_DOCUMENT_FONTS (EV_JOB (job)->document);
507         ev_document_fc_mutex_lock ();
508         job->scan_completed = !ev_document_fonts_scan (fonts, 20);
509         ev_document_fc_mutex_unlock ();
510         
511         EV_JOB (job)->finished = TRUE;
512
513         ev_document_doc_mutex_unlock ();
514 }
515
516 static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ }
517
518 static void
519 ev_job_load_dispose (GObject *object)
520 {
521         EvJobLoad *job = EV_JOB_LOAD (object);
522
523         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
524         
525         if (job->uri) {
526                 g_free (job->uri);
527                 job->uri = NULL;
528         }
529
530         if (job->error) {
531                 g_error_free (job->error);
532                 job->error = NULL;
533         }
534
535         if (job->dest) {
536                 g_object_unref (job->dest);
537                 job->dest = NULL;
538         }
539
540         if (job->search_string) {
541                 g_free (job->search_string);
542                 job->search_string = NULL;
543         }
544
545         (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
546 }
547
548 static void
549 ev_job_load_class_init (EvJobLoadClass *class)
550 {
551         GObjectClass *oclass;
552
553         oclass = G_OBJECT_CLASS (class);
554
555         oclass->dispose = ev_job_load_dispose;
556 }
557
558
559 EvJob *
560 ev_job_load_new (const gchar    *uri,
561                  EvLinkDest     *dest,
562                  EvWindowRunMode mode,
563                  const gchar    *search_string)
564 {
565         EvJobLoad *job;
566
567         ev_debug_message (DEBUG_JOBS, "%s", uri);
568         
569         job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
570
571         job->uri = g_strdup (uri);
572         if (dest)
573                 job->dest = g_object_ref (dest);
574
575         job->mode = mode;
576         if (search_string)
577                 job->search_string = g_strdup (search_string);
578
579         return EV_JOB (job);
580 }
581
582 void
583 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
584 {
585         ev_debug_message (DEBUG_JOBS, "%s", uri);
586         
587         if (job->uri)
588                 g_free (job->uri);
589         job->uri = g_strdup (uri);
590 }
591
592 void
593 ev_job_load_run (EvJobLoad *job)
594 {
595         g_return_if_fail (EV_IS_JOB_LOAD (job));
596
597         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
598         
599         if (job->error) {
600                 g_error_free (job->error);
601                 job->error = NULL;
602         }
603
604         ev_document_fc_mutex_lock ();
605         
606         /* This job may already have a document even if the job didn't complete
607            because, e.g., a password is required - if so, just reload rather than
608            creating a new instance */
609         if (EV_JOB (job)->document) {
610                 ev_document_load (EV_JOB (job)->document,
611                                   job->uri,
612                                   &job->error);
613         } else {
614                 EV_JOB(job)->document =
615                         ev_document_factory_get_document (job->uri,
616                                                           &job->error);
617         }
618
619         ev_document_fc_mutex_unlock ();
620         EV_JOB (job)->finished = TRUE;
621 }
622
623 static void ev_job_save_init (EvJobSave *job) { /* Do Nothing */ }
624
625 static void
626 ev_job_save_dispose (GObject *object)
627 {
628         EvJobSave *job = EV_JOB_SAVE (object);
629
630         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
631         
632         if (job->uri) {
633                 g_free (job->uri);
634                 job->uri = NULL;
635         }
636
637         if (job->document_uri) {
638                 g_free (job->document_uri);
639                 job->document_uri = NULL;
640         }
641
642         if (job->error) {
643                 g_error_free (job->error);
644                 job->error = NULL;
645         }
646
647         (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
648 }
649
650 static void
651 ev_job_save_class_init (EvJobSaveClass *class)
652 {
653         GObjectClass *oclass;
654
655         oclass = G_OBJECT_CLASS (class);
656
657         oclass->dispose = ev_job_save_dispose;
658 }
659
660 EvJob *
661 ev_job_save_new (EvDocument  *document,
662                  const gchar *uri,
663                  const gchar *document_uri)
664 {
665         EvJobSave *job;
666
667         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
668
669         job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
670
671         EV_JOB (job)->document = g_object_ref (document);
672         job->uri = g_strdup (uri);
673         job->document_uri = g_strdup (document_uri);
674         job->error = NULL;
675
676         return EV_JOB (job);
677 }
678
679 void
680 ev_job_save_run (EvJobSave *job)
681 {
682         gint   fd;
683         gchar *filename;
684         gchar *tmp_filename;
685         gchar *local_uri;
686
687         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job->uri, job->document_uri);
688         
689         filename = ev_tmp_filename ("saveacopy");
690         tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
691         g_free (filename);
692
693         fd = g_mkstemp (tmp_filename);
694         if (fd == -1) {
695                 gchar *display_name;
696                 gint   save_errno = errno;
697
698                 display_name = g_filename_display_name (tmp_filename);
699                 g_set_error (&(job->error),
700                              G_FILE_ERROR,
701                              g_file_error_from_errno (save_errno),
702                              _("Failed to create file “%s”: %s"),
703                              display_name, g_strerror (save_errno));
704                 g_free (display_name);
705                 g_free (tmp_filename);
706
707                 return;
708         }
709
710         ev_document_doc_mutex_lock ();
711
712         /* Save document to temp filename */
713         local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
714         ev_document_save (EV_JOB (job)->document, local_uri, &(job->error));
715         close (fd);
716
717         ev_document_doc_mutex_unlock ();
718
719         if (job->error) {
720                 g_free (local_uri);
721                 return;
722         }
723
724         /* If original document was compressed,
725          * compress it again before saving
726          */
727         if (g_object_get_data (G_OBJECT (EV_JOB (job)->document),
728                                "uri-uncompressed")) {
729                 EvCompressionType ctype = EV_COMPRESSION_NONE;
730                 const gchar      *ext;
731                 gchar            *uri_comp;
732                 
733                 ext = g_strrstr (job->document_uri, ".gz");
734                 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
735                         ctype = EV_COMPRESSION_GZIP;
736                 
737                 ext = g_strrstr (job->document_uri, ".bz2");
738                 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
739                         ctype = EV_COMPRESSION_BZIP2;
740
741                 uri_comp = ev_file_compress (local_uri, ctype, &(job->error));
742                 g_free (local_uri);
743                 ev_tmp_filename_unlink (tmp_filename);
744
745                 if (!uri_comp || job->error) {
746                         local_uri = NULL;
747                 } else {
748                         local_uri = uri_comp;
749                 }
750         }
751
752         g_free (tmp_filename);
753         
754         if (job->error) {
755                 g_free (local_uri);
756                 return;
757         }
758
759         if (!local_uri)
760                 return;
761
762         ev_xfer_uri_simple (local_uri, job->uri, &(job->error));
763         ev_tmp_uri_unlink (local_uri);
764 }
765
766 EvJob *
767 ev_job_print_new (EvDocument    *document,
768                   const gchar   *format,
769                   gdouble        width,
770                   gdouble        height,
771                   EvPrintRange  *ranges,
772                   gint           n_ranges,
773                   EvPrintPageSet page_set,
774                   gint           pages_per_sheet,
775                   gint           copies,
776                   gdouble        collate,
777                   gdouble        reverse)
778 {
779         EvJobPrint *job;
780
781         ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
782                           "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
783                           "collate: %s, reverse: %s",
784                           format, width, height, n_ranges, pages_per_sheet, copies,
785                           collate ? "True" : "False", reverse  ? "True" : "False");
786
787         job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
788
789         EV_JOB (job)->document = g_object_ref (document);
790
791         job->format = format;
792         
793         job->temp_file = NULL;
794         job->error = NULL;
795
796         job->width = width;
797         job->height = height;
798
799         job->ranges = ranges;
800         job->n_ranges = n_ranges;
801
802         job->page_set = page_set;
803
804         job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
805         
806         job->copies = copies;
807         job->collate = collate;
808         job->reverse = reverse;
809         
810         return EV_JOB (job);
811 }
812
813 static gint
814 ev_print_job_get_first_page (EvJobPrint *job)
815 {
816         gint i;
817         gint first_page = G_MAXINT;
818         
819         if (job->n_ranges == 0)
820                 return 0;
821
822         for (i = 0; i < job->n_ranges; i++) {
823                 if (job->ranges[i].start < first_page)
824                         first_page = job->ranges[i].start;
825         }
826
827         return MAX (0, first_page);
828 }
829
830 static gint
831 ev_print_job_get_last_page (EvJobPrint *job)
832 {
833         gint i;
834         gint last_page = G_MININT;
835         gint max_page;
836
837         max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
838
839         if (job->n_ranges == 0)
840                 return max_page;
841
842         for (i = 0; i < job->n_ranges; i++) {
843                 if (job->ranges[i].end > last_page)
844                         last_page = job->ranges[i].end;
845         }
846
847         return MIN (max_page, last_page);
848 }
849
850 static gboolean
851 ev_print_job_print_page_in_set (EvJobPrint *job,
852                                 gint        page)
853 {
854         switch (job->page_set) {
855                 case EV_PRINT_PAGE_SET_EVEN:
856                         return page % 2 == 0;
857                 case EV_PRINT_PAGE_SET_ODD:
858                         return page % 2 != 0;
859                 case EV_PRINT_PAGE_SET_ALL:
860                         return TRUE;
861         }
862
863         return FALSE;
864 }
865
866 static gint *
867 ev_job_print_get_page_list (EvJobPrint *job,
868                             gint       *n_pages)
869 {
870         gint  i, j, page, max_page;
871         gint  pages = 0;
872         gint *page_list;
873
874         max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
875
876         for (i = 0; i < job->n_ranges; i++) {
877                 gint rsize;
878                 gint start, end;
879
880                 if (job->ranges[i].start == -1)
881                         job->ranges[i].start = 0;
882                 if (job->ranges[i].end == -1)
883                         job->ranges[i].end = max_page;
884
885                 if (job->ranges[i].start > max_page)
886                         continue;
887                 
888                 start = job->ranges[i].start + 1;
889                 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
890                 rsize = end - start + 1;
891
892                 switch (job->page_set) {
893                         case EV_PRINT_PAGE_SET_EVEN:
894                                 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
895                                 break;
896                         case EV_PRINT_PAGE_SET_ODD:
897                                 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
898                                 break;
899                         default:
900                                 pages += rsize;
901                                 break;
902                 }
903         }
904
905         *n_pages = pages;
906
907         if (pages == 0)
908                 return NULL;
909
910         page_list = g_new (gint, pages);
911
912         page = 0;
913         for (i = 0; i < job->n_ranges; i++) {
914                 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
915                         if (j > max_page)
916                                 break;
917                 
918                         if (ev_print_job_print_page_in_set (job, j + 1))
919                                 page_list[page++] = j;
920                 }
921         }
922
923         return page_list;
924 }
925
926 void
927 ev_job_print_run (EvJobPrint *job)
928 {
929         EvDocument            *document = EV_JOB (job)->document;
930         EvFileExporterContext  fc;
931         EvRenderContext       *rc;
932         gint                   fd;
933         gint                  *page_list;
934         gint                   n_pages;
935         gint                   last_page;
936         gint                   first_page;
937         gint                   i, j;
938         gchar                 *filename;
939         
940         g_return_if_fail (EV_IS_JOB_PRINT (job));
941
942         ev_debug_message (DEBUG_JOBS, NULL);
943         
944         if (job->temp_file)
945                 g_free (job->temp_file);
946         job->temp_file = NULL;
947         
948         if (job->error)
949                 g_error_free (job->error);
950         job->error = NULL;
951
952         filename = g_strdup_printf ("evince_print.%s.XXXXXX", job->format);
953         fd = g_file_open_tmp (filename, &job->temp_file, &job->error);
954         g_free (filename);
955         if (fd <= -1) {
956                 EV_JOB (job)->finished = TRUE;
957                 return;
958         }
959
960         page_list = ev_job_print_get_page_list (job, &n_pages);
961         if (n_pages == 0) {
962                 close (fd);
963                 EV_JOB (job)->finished = TRUE;
964                 return;
965         }
966
967         first_page = ev_print_job_get_first_page (job);
968         last_page = ev_print_job_get_last_page (job);
969
970         fc.format = g_ascii_strcasecmp (job->format, "pdf") == 0 ?
971                 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
972         fc.filename = job->temp_file;
973         fc.first_page = MIN (first_page, last_page);
974         fc.last_page = MAX (first_page, last_page);
975         fc.paper_width = job->width;
976         fc.paper_height = job->height;
977         fc.duplex = FALSE;
978         fc.pages_per_sheet = MAX (1, job->pages_per_sheet);
979
980         rc = ev_render_context_new (NULL, 0, 1.0);
981
982         ev_document_doc_mutex_lock ();
983         ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
984
985         for (i = 0; i < job->copies; i++) {
986                 gint page, step;
987                 gint n_copies;
988                 
989                 step = job->reverse ? -1 * job->pages_per_sheet : job->pages_per_sheet;
990                 page = job->reverse ? ((n_pages - 1) / job->pages_per_sheet) * job->pages_per_sheet : 0;
991                 n_copies = job->collate ? 1 : job->copies;
992
993                 while ((job->reverse && (page >= 0)) || (!job->reverse && (page < n_pages))) {
994                         gint k;
995
996                         for (k = 0; k < n_copies; k++) {
997                                 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
998                                 
999                                 for (j = 0; j < job->pages_per_sheet; j++) {
1000                                         EvPage *ev_page;
1001                                         
1002                                         gint p = page + j;
1003
1004                                         if (p < 0 || p >= n_pages)
1005                                                 break;
1006
1007                                         ev_page = ev_document_get_page (document, page_list[p]);
1008                                         ev_render_context_set_page (rc, ev_page);
1009                                         g_object_unref (ev_page);
1010                                         
1011                                         ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
1012                                 }
1013
1014                                 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
1015                         }
1016
1017                         page += step;
1018                 }
1019
1020                 if (!job->collate)
1021                         break;
1022         }
1023
1024         ev_file_exporter_end (EV_FILE_EXPORTER (document));
1025         ev_document_doc_mutex_unlock ();
1026         
1027         g_free (page_list);
1028         close (fd);
1029         g_object_unref (rc);
1030         
1031         EV_JOB (job)->finished = TRUE;
1032 }