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