]> www.fi.muni.cz Git - evince.git/blob - libview/ev-jobs.c
140c51ad9a9e67b936fbe31cb9941cf516f44bab
[evince.git] / libview / ev-jobs.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
4  *  Copyright (C) 2005 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #include <config.h>
22
23 #include "ev-jobs.h"
24 #include "ev-document-thumbnails.h"
25 #include "ev-document-links.h"
26 #include "ev-document-images.h"
27 #include "ev-document-forms.h"
28 #include "ev-file-exporter.h"
29 #include "ev-document-factory.h"
30 #include "ev-document-misc.h"
31 #include "ev-file-helpers.h"
32 #include "ev-document-fonts.h"
33 #include "ev-document-security.h"
34 #include "ev-document-find.h"
35 #include "ev-document-layers.h"
36 #include "ev-document-print.h"
37 #include "ev-document-annotations.h"
38 #include "ev-document-attachments.h"
39 #include "ev-debug.h"
40
41 #include <errno.h>
42 #include <glib/gstdio.h>
43 #include <glib/gi18n-lib.h>
44 #include <unistd.h>
45
46 static void ev_job_init                   (EvJob                 *job);
47 static void ev_job_class_init             (EvJobClass            *class);
48 static void ev_job_links_init             (EvJobLinks            *job);
49 static void ev_job_links_class_init       (EvJobLinksClass       *class);
50 static void ev_job_attachments_init       (EvJobAttachments      *job);
51 static void ev_job_attachments_class_init (EvJobAttachmentsClass *class);
52 static void ev_job_render_init            (EvJobRender           *job);
53 static void ev_job_render_class_init      (EvJobRenderClass      *class);
54 static void ev_job_page_data_init         (EvJobPageData         *job);
55 static void ev_job_page_data_class_init   (EvJobPageDataClass    *class);
56 static void ev_job_thumbnail_init         (EvJobThumbnail        *job);
57 static void ev_job_thumbnail_class_init   (EvJobThumbnailClass   *class);
58 static void ev_job_load_init              (EvJobLoad             *job);
59 static void ev_job_load_class_init        (EvJobLoadClass        *class);
60 static void ev_job_save_init              (EvJobSave             *job);
61 static void ev_job_save_class_init        (EvJobSaveClass        *class);
62 static void ev_job_find_init              (EvJobFind             *job);
63 static void ev_job_find_class_init        (EvJobFindClass        *class);
64 static void ev_job_layers_init            (EvJobLayers           *job);
65 static void ev_job_layers_class_init      (EvJobLayersClass      *class);
66 static void ev_job_export_init            (EvJobExport           *job);
67 static void ev_job_export_class_init      (EvJobExportClass      *class);
68 static void ev_job_print_init             (EvJobPrint            *job);
69 static void ev_job_print_class_init       (EvJobPrintClass       *class);
70
71 enum {
72         CANCELLED,
73         FINISHED,
74         LAST_SIGNAL
75 };
76
77 enum {
78         FONTS_UPDATED,
79         FONTS_LAST_SIGNAL
80 };
81
82 enum {
83         FIND_UPDATED,
84         FIND_LAST_SIGNAL
85 };
86
87 static guint job_signals[LAST_SIGNAL] = { 0 };
88 static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 };
89 static guint job_find_signals[FIND_LAST_SIGNAL] = { 0 };
90
91 G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
92 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
93 G_DEFINE_TYPE (EvJobAttachments, ev_job_attachments, EV_TYPE_JOB)
94 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
95 G_DEFINE_TYPE (EvJobPageData, ev_job_page_data, EV_TYPE_JOB)
96 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
97 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
98 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
99 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
100 G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB)
101 G_DEFINE_TYPE (EvJobLayers, ev_job_layers, EV_TYPE_JOB)
102 G_DEFINE_TYPE (EvJobExport, ev_job_export, EV_TYPE_JOB)
103 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
104
105 /* EvJob */
106 static void
107 ev_job_init (EvJob *job)
108 {
109         job->cancellable = g_cancellable_new ();
110 }
111
112 static void
113 ev_job_dispose (GObject *object)
114 {
115         EvJob *job;
116
117         job = EV_JOB (object);
118
119         if (job->document) {
120                 g_object_unref (job->document);
121                 job->document = NULL;
122         }
123
124         if (job->cancellable) {
125                 g_object_unref (job->cancellable);
126                 job->cancellable = NULL;
127         }
128
129         if (job->error) {
130                 g_error_free (job->error);
131                 job->error = NULL;
132         }
133
134         (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
135 }
136
137 static void
138 ev_job_class_init (EvJobClass *class)
139 {
140         GObjectClass *oclass;
141
142         oclass = G_OBJECT_CLASS (class);
143
144         oclass->dispose = ev_job_dispose;
145
146         job_signals[CANCELLED] =
147                 g_signal_new ("cancelled",
148                               EV_TYPE_JOB,
149                               G_SIGNAL_RUN_LAST,
150                               G_STRUCT_OFFSET (EvJobClass, cancelled),
151                               NULL, NULL,
152                               g_cclosure_marshal_VOID__VOID,
153                               G_TYPE_NONE, 0);
154         job_signals [FINISHED] =
155                 g_signal_new ("finished",
156                               EV_TYPE_JOB,
157                               G_SIGNAL_RUN_FIRST,
158                               G_STRUCT_OFFSET (EvJobClass, finished),
159                               NULL, NULL,
160                               g_cclosure_marshal_VOID__VOID,
161                               G_TYPE_NONE, 0);
162 }
163
164 static gboolean
165 emit_finished (EvJob *job)
166 {
167         ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
168
169         job->idle_finished_id = 0;
170         
171         if (job->cancelled) {
172                 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit finished", EV_GET_TYPE_NAME (job), job);
173         } else {
174                 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
175                 g_signal_emit (job, job_signals[FINISHED], 0);
176         }
177         
178         return FALSE;
179 }
180
181 static void
182 ev_job_emit_finished (EvJob *job)
183 {
184         ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
185
186         if (g_cancellable_is_cancelled (job->cancellable)) {
187                 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, returning", EV_GET_TYPE_NAME (job), job);
188                 return;
189         }
190         
191         job->finished = TRUE;
192         
193         if (job->run_mode == EV_JOB_RUN_THREAD) {
194                 job->idle_finished_id =
195                         g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
196                                          (GSourceFunc)emit_finished,
197                                          g_object_ref (job),
198                                          (GDestroyNotify)g_object_unref);
199         } else {
200                 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
201                 g_signal_emit (job, job_signals[FINISHED], 0);
202         }
203 }
204
205 gboolean
206 ev_job_run (EvJob *job)
207 {
208         EvJobClass *class = EV_JOB_GET_CLASS (job);
209         
210         return class->run (job);
211 }
212
213 void
214 ev_job_cancel (EvJob *job)
215 {
216         if (job->cancelled || (job->finished && job->idle_finished_id == 0))
217                 return;
218
219         ev_debug_message (DEBUG_JOBS, "job %s (%p) cancelled", EV_GET_TYPE_NAME (job), job);
220         ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
221         
222         /* This should never be called from a thread */
223         job->cancelled = TRUE;
224         g_cancellable_cancel (job->cancellable);
225         g_signal_emit (job, job_signals[CANCELLED], 0);
226 }
227
228 void
229 ev_job_failed (EvJob       *job,
230                GQuark       domain,
231                gint         code,
232                const gchar *format,
233                ...)
234 {
235         va_list args;
236         gchar  *message;
237         
238         if (job->failed || job->finished)
239                 return;
240
241         ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
242         
243         job->failed = TRUE;
244         
245         va_start (args, format);
246         message = g_strdup_vprintf (format, args);
247         va_end (args);
248         
249         job->error = g_error_new_literal (domain, code, message);
250         g_free (message);
251         
252         ev_job_emit_finished (job);                                                                                                               
253 }
254
255 void
256 ev_job_failed_from_error (EvJob  *job,
257                           GError *error)
258 {
259         if (job->failed || job->finished)
260                 return;
261         
262         ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
263
264         job->failed = TRUE;
265         job->error = g_error_copy (error);
266
267         ev_job_emit_finished (job);
268 }
269
270 void
271 ev_job_succeeded (EvJob *job)
272 {
273         if (job->finished)
274                 return;
275
276         ev_debug_message (DEBUG_JOBS, "job %s (%p) succeeded", EV_GET_TYPE_NAME (job), job);
277         
278         job->failed = FALSE;
279         ev_job_emit_finished (job);
280 }
281
282 gboolean
283 ev_job_is_finished (EvJob *job)
284 {
285         return job->finished;
286 }
287
288 gboolean
289 ev_job_is_failed (EvJob *job)
290 {
291         return job->failed;
292 }
293
294 EvJobRunMode
295 ev_job_get_run_mode (EvJob *job)
296 {
297         return job->run_mode;
298 }
299
300 void
301 ev_job_set_run_mode (EvJob       *job,
302                      EvJobRunMode run_mode)
303 {
304         job->run_mode = run_mode;
305 }
306
307 /* EvJobLinks */
308 static void
309 ev_job_links_init (EvJobLinks *job)
310 {
311         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
312 }
313
314 static void
315 ev_job_links_dispose (GObject *object)
316 {
317         EvJobLinks *job;
318
319         ev_debug_message (DEBUG_JOBS, NULL);
320         
321         job = EV_JOB_LINKS (object);
322
323         if (job->model) {
324                 g_object_unref (job->model);
325                 job->model = NULL;
326         }
327
328         (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
329 }
330
331 static gboolean
332 ev_job_links_run (EvJob *job)
333 {
334         EvJobLinks *job_links = EV_JOB_LINKS (job);
335
336         ev_debug_message (DEBUG_JOBS, NULL);
337         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
338         
339         ev_document_doc_mutex_lock ();
340         job_links->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (job->document));
341         ev_document_doc_mutex_unlock ();
342         
343         ev_job_succeeded (job);
344         
345         return FALSE;
346 }
347
348 static void
349 ev_job_links_class_init (EvJobLinksClass *class)
350 {
351         GObjectClass *oclass = G_OBJECT_CLASS (class);
352         EvJobClass   *job_class = EV_JOB_CLASS (class);
353
354         oclass->dispose = ev_job_links_dispose;
355         job_class->run = ev_job_links_run;
356 }
357
358 EvJob *
359 ev_job_links_new (EvDocument *document)
360 {
361         EvJob *job;
362
363         ev_debug_message (DEBUG_JOBS, NULL);
364
365         job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
366         job->document = g_object_ref (document);
367         
368         return job;
369 }
370
371 /* EvJobAttachments */
372 static void
373 ev_job_attachments_init (EvJobAttachments *job)
374 {
375         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
376 }
377
378 static void
379 ev_job_attachments_dispose (GObject *object)
380 {
381         EvJobAttachments *job;
382
383         ev_debug_message (DEBUG_JOBS, NULL);
384         
385         job = EV_JOB_ATTACHMENTS (object);
386
387         if (job->attachments) {
388                 g_list_foreach (job->attachments, (GFunc)g_object_unref, NULL);
389                 g_list_free (job->attachments);
390                 job->attachments = NULL;
391         }
392
393         (* G_OBJECT_CLASS (ev_job_attachments_parent_class)->dispose) (object);
394 }
395
396 static gboolean
397 ev_job_attachments_run (EvJob *job)
398 {
399         EvJobAttachments *job_attachments = EV_JOB_ATTACHMENTS (job);
400
401         ev_debug_message (DEBUG_JOBS, NULL);
402         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
403
404         ev_document_doc_mutex_lock ();
405         job_attachments->attachments =
406                 ev_document_attachments_get_attachments (EV_DOCUMENT_ATTACHMENTS (job->document));
407         ev_document_doc_mutex_unlock ();
408
409         ev_job_succeeded (job);
410
411         return FALSE;
412 }
413
414 static void
415 ev_job_attachments_class_init (EvJobAttachmentsClass *class)
416 {
417         GObjectClass *oclass = G_OBJECT_CLASS (class);
418         EvJobClass   *job_class = EV_JOB_CLASS (class);
419
420         oclass->dispose = ev_job_attachments_dispose;
421         job_class->run = ev_job_attachments_run;
422 }
423
424 EvJob *
425 ev_job_attachments_new (EvDocument *document)
426 {
427         EvJob *job;
428
429         ev_debug_message (DEBUG_JOBS, NULL);
430
431         job = g_object_new (EV_TYPE_JOB_ATTACHMENTS, NULL);
432         job->document = g_object_ref (document);
433         
434         return job;
435 }
436
437 /* EvJobRender */
438 static void
439 ev_job_render_init (EvJobRender *job)
440 {
441         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
442 }
443
444 static void
445 ev_job_render_dispose (GObject *object)
446 {
447         EvJobRender *job;
448
449         job = EV_JOB_RENDER (object);
450
451         ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->page, job);
452
453         if (job->surface) {
454                 cairo_surface_destroy (job->surface);
455                 job->surface = NULL;
456         }
457
458         if (job->selection) {
459                 cairo_surface_destroy (job->selection);
460                 job->selection = NULL;
461         }
462
463         if (job->selection_region) {
464                 gdk_region_destroy (job->selection_region);
465                 job->selection_region = NULL;
466         }
467
468         (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
469 }
470
471 static gboolean
472 ev_job_render_run (EvJob *job)
473 {
474         EvJobRender     *job_render = EV_JOB_RENDER (job);
475         EvPage          *ev_page;
476         EvRenderContext *rc;
477
478         ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job);
479         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
480         
481         ev_document_doc_mutex_lock ();
482
483         ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page);
484                 
485         ev_document_fc_mutex_lock ();
486
487         ev_page = ev_document_get_page (job->document, job_render->page);
488         rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale);
489         g_object_unref (ev_page);
490
491         job_render->surface = ev_document_render (job->document, rc);
492         /* If job was cancelled during the page rendering,
493          * we return now, so that the thread is finished ASAP
494          */
495         if (g_cancellable_is_cancelled (job->cancellable)) {
496                 ev_document_fc_mutex_unlock ();
497                 ev_document_doc_mutex_unlock ();
498                 g_object_unref (rc);
499
500                 return FALSE;
501         }
502
503         if (job_render->include_selection && EV_IS_SELECTION (job->document)) {
504                 ev_selection_render_selection (EV_SELECTION (job->document),
505                                                rc,
506                                                &(job_render->selection),
507                                                &(job_render->selection_points),
508                                                NULL,
509                                                job_render->selection_style,
510                                                &(job_render->text), &(job_render->base));
511                 job_render->selection_region =
512                         ev_selection_get_selection_region (EV_SELECTION (job->document),
513                                                            rc,
514                                                            job_render->selection_style,
515                                                            &(job_render->selection_points));
516         }
517
518         g_object_unref (rc);
519
520         ev_document_fc_mutex_unlock ();
521         ev_document_doc_mutex_unlock ();
522         
523         ev_job_succeeded (job);
524         
525         return FALSE;
526 }
527
528 static void
529 ev_job_render_class_init (EvJobRenderClass *class)
530 {
531         GObjectClass *oclass = G_OBJECT_CLASS (class);
532         EvJobClass   *job_class = EV_JOB_CLASS (class);
533
534         oclass->dispose = ev_job_render_dispose;
535         job_class->run = ev_job_render_run;
536 }
537
538 EvJob *
539 ev_job_render_new (EvDocument   *document,
540                    gint          page,
541                    gint          rotation,
542                    gdouble       scale,
543                    gint          width,
544                    gint          height)
545 {
546         EvJobRender *job;
547
548         ev_debug_message (DEBUG_JOBS, "page: %d", page);
549         
550         job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
551
552         EV_JOB (job)->document = g_object_ref (document);
553         job->page = page;
554         job->rotation = rotation;
555         job->scale = scale;
556         job->target_width = width;
557         job->target_height = height;
558
559         return EV_JOB (job);
560 }
561
562 void
563 ev_job_render_set_selection_info (EvJobRender     *job,
564                                   EvRectangle     *selection_points,
565                                   EvSelectionStyle selection_style,
566                                   GdkColor        *text,
567                                   GdkColor        *base)
568 {
569         job->include_selection = TRUE;
570
571         job->selection_points = *selection_points;
572         job->selection_style = selection_style;
573         job->text = *text;
574         job->base = *base;
575 }
576
577 /* EvJobPageData */
578 static void
579 ev_job_page_data_init (EvJobPageData *job)
580 {
581         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
582 }
583
584 static gboolean
585 ev_job_page_data_run (EvJob *job)
586 {
587         EvJobPageData *job_pd = EV_JOB_PAGE_DATA (job);
588         EvPage        *ev_page;
589
590         ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_pd->page, job);
591         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
592
593         ev_document_doc_mutex_lock ();
594         ev_page = ev_document_get_page (job->document, job_pd->page);
595
596         if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_TEXT) && EV_IS_SELECTION (job->document))
597                 job_pd->text_mapping =
598                         ev_selection_get_selection_map (EV_SELECTION (job->document), ev_page);
599         if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document))
600                 job_pd->link_mapping =
601                         ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), ev_page);
602         if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document))
603                 job_pd->form_field_mapping =
604                         ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document),
605                                                            ev_page);
606         if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document))
607                 job_pd->image_mapping =
608                         ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document),
609                                                               ev_page);
610         if ((job_pd->flags & EV_PAGE_DATA_INCLUDE_ANNOTS) && EV_IS_DOCUMENT_ANNOTATIONS (job->document))
611                 job_pd->annot_mapping =
612                         ev_document_annotations_get_annotations (EV_DOCUMENT_ANNOTATIONS (job->document),
613                                                                  ev_page);
614         g_object_unref (ev_page);
615         ev_document_doc_mutex_unlock ();
616
617         ev_job_succeeded (job);
618
619         return FALSE;
620 }
621
622 static void
623 ev_job_page_data_class_init (EvJobPageDataClass *class)
624 {
625         EvJobClass *job_class = EV_JOB_CLASS (class);
626
627         job_class->run = ev_job_page_data_run;
628 }
629
630 EvJob *
631 ev_job_page_data_new (EvDocument        *document,
632                       gint               page,
633                       EvJobPageDataFlags flags)
634 {
635         EvJobPageData *job;
636
637         ev_debug_message (DEBUG_JOBS, "%d", page);
638
639         job = g_object_new (EV_TYPE_JOB_PAGE_DATA, NULL);
640
641         EV_JOB (job)->document = g_object_ref (document);
642         job->page = page;
643         job->flags = flags;
644
645         return EV_JOB (job);
646 }
647
648 /* EvJobThumbnail */
649 static void
650 ev_job_thumbnail_init (EvJobThumbnail *job)
651 {
652         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
653 }
654
655 static void
656 ev_job_thumbnail_dispose (GObject *object)
657 {
658         EvJobThumbnail *job;
659
660         job = EV_JOB_THUMBNAIL (object);
661
662         ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job);
663         
664         if (job->thumbnail) {
665                 g_object_unref (job->thumbnail);
666                 job->thumbnail = NULL;
667         }
668
669         (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
670 }
671
672 static gboolean
673 ev_job_thumbnail_run (EvJob *job)
674 {
675         EvJobThumbnail  *job_thumb = EV_JOB_THUMBNAIL (job);
676         EvRenderContext *rc;
677         EvPage          *page;
678
679         ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job);
680         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
681         
682         ev_document_doc_mutex_lock ();
683
684         page = ev_document_get_page (job->document, job_thumb->page);
685         rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
686         g_object_unref (page);
687
688         job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document),
689                                                                      rc, TRUE);
690         g_object_unref (rc);
691         ev_document_doc_mutex_unlock ();
692
693         ev_job_succeeded (job);
694         
695         return FALSE;
696 }
697
698 static void
699 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
700 {
701         GObjectClass *oclass = G_OBJECT_CLASS (class);
702         EvJobClass   *job_class = EV_JOB_CLASS (class);
703
704         oclass->dispose = ev_job_thumbnail_dispose;
705         job_class->run = ev_job_thumbnail_run;
706 }
707
708 EvJob *
709 ev_job_thumbnail_new (EvDocument *document,
710                       gint        page,
711                       gint        rotation,
712                       gdouble     scale)
713 {
714         EvJobThumbnail *job;
715
716         ev_debug_message (DEBUG_JOBS, "%d", page);
717         
718         job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
719
720         EV_JOB (job)->document = g_object_ref (document);
721         job->page = page;
722         job->rotation = rotation;
723         job->scale = scale;
724
725         return EV_JOB (job);
726 }
727
728 /* EvJobFonts */
729 static void
730 ev_job_fonts_init (EvJobFonts *job)
731 {
732         EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
733 }
734
735 static gboolean
736 ev_job_fonts_run (EvJob *job)
737 {
738         EvJobFonts      *job_fonts = EV_JOB_FONTS (job);
739         EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
740
741         ev_debug_message (DEBUG_JOBS, NULL);
742         
743         /* Do not block the main loop */
744         if (!ev_document_doc_mutex_trylock ())
745                 return TRUE;
746         
747         if (!ev_document_fc_mutex_trylock ())
748                 return TRUE;
749
750 #ifdef EV_ENABLE_DEBUG
751         /* We use the #ifdef in this case because of the if */
752         if (ev_document_fonts_get_progress (fonts) == 0)
753                 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
754 #endif
755
756         job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
757         g_signal_emit (job_fonts, job_fonts_signals[FONTS_UPDATED], 0,
758                        ev_document_fonts_get_progress (fonts));
759
760         ev_document_fc_mutex_unlock ();
761         ev_document_doc_mutex_unlock ();
762
763         if (job_fonts->scan_completed)
764                 ev_job_succeeded (job);
765         
766         return !job_fonts->scan_completed;
767 }
768
769 static void
770 ev_job_fonts_class_init (EvJobFontsClass *class)
771 {
772         EvJobClass *job_class = EV_JOB_CLASS (class);
773         
774         job_class->run = ev_job_fonts_run;
775         
776         job_fonts_signals[FONTS_UPDATED] =
777                 g_signal_new ("updated",
778                               EV_TYPE_JOB_FONTS,
779                               G_SIGNAL_RUN_LAST,
780                               G_STRUCT_OFFSET (EvJobFontsClass, updated),
781                               NULL, NULL,
782                               g_cclosure_marshal_VOID__DOUBLE,
783                               G_TYPE_NONE,
784                               1, G_TYPE_DOUBLE);
785 }
786
787 EvJob *
788 ev_job_fonts_new (EvDocument *document)
789 {
790         EvJobFonts *job;
791
792         ev_debug_message (DEBUG_JOBS, NULL);
793         
794         job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
795
796         EV_JOB (job)->document = g_object_ref (document);
797
798         return EV_JOB (job);
799 }
800
801 /* EvJobLoad */
802 static void
803 ev_job_load_init (EvJobLoad *job)
804 {
805         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
806 }
807
808 static void
809 ev_job_load_dispose (GObject *object)
810 {
811         EvJobLoad *job = EV_JOB_LOAD (object);
812
813         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
814         
815         if (job->uri) {
816                 g_free (job->uri);
817                 job->uri = NULL;
818         }
819
820         if (job->password) {
821                 g_free (job->password);
822                 job->password = NULL;
823         }
824
825         (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
826 }
827
828 static gboolean
829 ev_job_load_run (EvJob *job)
830 {
831         EvJobLoad *job_load = EV_JOB_LOAD (job);
832         GError    *error = NULL;
833         
834         ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
835         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
836         
837         ev_document_fc_mutex_lock ();
838
839         /* This job may already have a document even if the job didn't complete
840            because, e.g., a password is required - if so, just reload rather than
841            creating a new instance */
842         if (job->document) {
843                 const gchar *uncompressed_uri;
844
845                 if (job_load->password) {
846                         ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
847                                                            job_load->password);
848                 }
849                 
850                 job->failed = FALSE;
851                 job->finished = FALSE;
852                 g_clear_error (&job->error);
853
854                 uncompressed_uri = g_object_get_data (G_OBJECT (job->document),
855                                                       "uri-uncompressed");
856                 ev_document_load (job->document,
857                                   uncompressed_uri ? uncompressed_uri : job_load->uri,
858                                   &error);
859         } else {
860                 job->document = ev_document_factory_get_document (job_load->uri,
861                                                                   &error);
862         }
863
864         ev_document_fc_mutex_unlock ();
865
866         if (error) {
867                 ev_job_failed_from_error (job, error);
868                 g_error_free (error);
869         } else {
870                 ev_job_succeeded (job);
871         }
872
873         return FALSE;
874 }
875
876 static void
877 ev_job_load_class_init (EvJobLoadClass *class)
878 {
879         GObjectClass *oclass = G_OBJECT_CLASS (class);
880         EvJobClass   *job_class = EV_JOB_CLASS (class);
881
882         oclass->dispose = ev_job_load_dispose;
883         job_class->run = ev_job_load_run;
884 }
885
886 EvJob *
887 ev_job_load_new (const gchar *uri)
888 {
889         EvJobLoad *job;
890
891         ev_debug_message (DEBUG_JOBS, "%s", uri);
892         
893         job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
894         job->uri = g_strdup (uri);
895
896         return EV_JOB (job);
897 }
898
899 void
900 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
901 {
902         ev_debug_message (DEBUG_JOBS, "%s", uri);
903         
904         if (job->uri)
905                 g_free (job->uri);
906         job->uri = g_strdup (uri);
907 }
908
909 void
910 ev_job_load_set_password (EvJobLoad *job, const gchar *password)
911 {
912         ev_debug_message (DEBUG_JOBS, NULL);
913
914         if (job->password)
915                 g_free (job->password);
916         job->password = password ? g_strdup (password) : NULL;
917 }
918
919 /* EvJobSave */
920 static void
921 ev_job_save_init (EvJobSave *job)
922 {
923         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
924 }
925
926 static void
927 ev_job_save_dispose (GObject *object)
928 {
929         EvJobSave *job = EV_JOB_SAVE (object);
930
931         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
932         
933         if (job->uri) {
934                 g_free (job->uri);
935                 job->uri = NULL;
936         }
937
938         if (job->document_uri) {
939                 g_free (job->document_uri);
940                 job->document_uri = NULL;
941         }
942
943         (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
944 }
945
946 static gboolean
947 ev_job_save_run (EvJob *job)
948 {
949         EvJobSave *job_save = EV_JOB_SAVE (job);
950         gint       fd;
951         gchar     *tmp_filename = NULL;
952         gchar     *local_uri;
953         GError    *error = NULL;
954         
955         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
956         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
957
958         fd = ev_mkstemp ("saveacopy.XXXXXX", &tmp_filename, &error);
959         if (fd == -1) {
960                 ev_job_failed_from_error (job, error);
961                 g_error_free (error);
962
963                 return FALSE;
964         }
965
966         ev_document_doc_mutex_lock ();
967
968         /* Save document to temp filename */
969         local_uri = g_filename_to_uri (tmp_filename, NULL, &error);
970         if (local_uri != NULL) {
971                 ev_document_save (job->document, local_uri, &error);
972         }
973
974         close (fd);
975
976         ev_document_doc_mutex_unlock ();
977
978         if (error) {
979                 g_free (local_uri);
980                 ev_job_failed_from_error (job, error);
981                 g_error_free (error);
982                 
983                 return FALSE;
984         }
985
986         /* If original document was compressed,
987          * compress it again before saving
988          */
989         if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
990                 EvCompressionType ctype = EV_COMPRESSION_NONE;
991                 const gchar      *ext;
992                 gchar            *uri_comp;
993                 
994                 ext = g_strrstr (job_save->document_uri, ".gz");
995                 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
996                         ctype = EV_COMPRESSION_GZIP;
997                 
998                 ext = g_strrstr (job_save->document_uri, ".bz2");
999                 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
1000                         ctype = EV_COMPRESSION_BZIP2;
1001
1002                 uri_comp = ev_file_compress (local_uri, ctype, &error);
1003                 g_free (local_uri);
1004                 g_unlink (tmp_filename);
1005
1006                 if (!uri_comp || error) {
1007                         local_uri = NULL;
1008                 } else {
1009                         local_uri = uri_comp;
1010                 }
1011         }
1012
1013         g_free (tmp_filename);
1014
1015         if (error) {
1016                 g_free (local_uri);
1017                 ev_job_failed_from_error (job, error);
1018                 g_error_free (error);
1019                 
1020                 return FALSE;
1021         }
1022
1023         if (!local_uri)
1024                 return FALSE;
1025
1026         ev_xfer_uri_simple (local_uri, job_save->uri, &error);
1027         ev_tmp_uri_unlink (local_uri);
1028
1029         if (error) {
1030                 ev_job_failed_from_error (job, error);
1031                 g_error_free (error);
1032         } else {
1033                 ev_job_succeeded (job);
1034         }
1035         
1036         return FALSE;
1037 }
1038
1039 static void
1040 ev_job_save_class_init (EvJobSaveClass *class)
1041 {
1042         GObjectClass *oclass = G_OBJECT_CLASS (class);
1043         EvJobClass   *job_class = EV_JOB_CLASS (class);
1044
1045         oclass->dispose = ev_job_save_dispose;
1046         job_class->run = ev_job_save_run;
1047 }
1048
1049 EvJob *
1050 ev_job_save_new (EvDocument  *document,
1051                  const gchar *uri,
1052                  const gchar *document_uri)
1053 {
1054         EvJobSave *job;
1055
1056         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
1057
1058         job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
1059
1060         EV_JOB (job)->document = g_object_ref (document);
1061         job->uri = g_strdup (uri);
1062         job->document_uri = g_strdup (document_uri);
1063
1064         return EV_JOB (job);
1065 }
1066
1067 /* EvJobFind */
1068 static void
1069 ev_job_find_init (EvJobFind *job)
1070 {
1071         EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
1072 }
1073
1074 static void
1075 ev_job_find_dispose (GObject *object)
1076 {
1077         EvJobFind *job = EV_JOB_FIND (object);
1078
1079         ev_debug_message (DEBUG_JOBS, NULL);
1080
1081         if (job->text) {
1082                 g_free (job->text);
1083                 job->text = NULL;
1084         }
1085
1086         if (job->pages) {
1087                 gint i;
1088
1089                 for (i = 0; i < job->n_pages; i++) {
1090                         g_list_foreach (job->pages[i], (GFunc)ev_rectangle_free, NULL);
1091                         g_list_free (job->pages[i]);
1092                 }
1093
1094                 g_free (job->pages);
1095                 job->pages = NULL;
1096         }
1097         
1098         (* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object);
1099 }
1100
1101 static gboolean
1102 ev_job_find_run (EvJob *job)
1103 {
1104         EvJobFind      *job_find = EV_JOB_FIND (job);
1105         EvDocumentFind *find = EV_DOCUMENT_FIND (job->document);
1106         EvPage         *ev_page;
1107         GList          *matches;
1108
1109         ev_debug_message (DEBUG_JOBS, NULL);
1110         
1111         /* Do not block the main loop */
1112         if (!ev_document_doc_mutex_trylock ())
1113                 return TRUE;
1114         
1115 #ifdef EV_ENABLE_DEBUG
1116         /* We use the #ifdef in this case because of the if */
1117         if (job_find->current_page == job_find->start_page)
1118                 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1119 #endif
1120
1121         ev_page = ev_document_get_page (job->document, job_find->current_page);
1122         matches = ev_document_find_find_text (find, ev_page, job_find->text,
1123                                               job_find->case_sensitive);
1124         g_object_unref (ev_page);
1125         
1126         ev_document_doc_mutex_unlock ();
1127
1128         if (!job_find->has_results)
1129                 job_find->has_results = (matches != NULL);
1130
1131         job_find->pages[job_find->current_page] = matches;
1132         g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page);
1133                        
1134         job_find->current_page = (job_find->current_page + 1) % job_find->n_pages;
1135         if (job_find->current_page == job_find->start_page) {
1136                 ev_job_succeeded (job);
1137
1138                 return FALSE;
1139         }
1140
1141         return TRUE;
1142 }
1143
1144 static void
1145 ev_job_find_class_init (EvJobFindClass *class)
1146 {
1147         EvJobClass   *job_class = EV_JOB_CLASS (class);
1148         GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1149         
1150         job_class->run = ev_job_find_run;
1151         gobject_class->dispose = ev_job_find_dispose;
1152         
1153         job_find_signals[FIND_UPDATED] =
1154                 g_signal_new ("updated",
1155                               EV_TYPE_JOB_FIND,
1156                               G_SIGNAL_RUN_LAST,
1157                               G_STRUCT_OFFSET (EvJobFindClass, updated),
1158                               NULL, NULL,
1159                               g_cclosure_marshal_VOID__INT,
1160                               G_TYPE_NONE,
1161                               1, G_TYPE_INT);
1162 }
1163
1164 EvJob *
1165 ev_job_find_new (EvDocument  *document,
1166                  gint         start_page,
1167                  gint         n_pages,
1168                  const gchar *text,
1169                  gboolean     case_sensitive)
1170 {
1171         EvJobFind *job;
1172         
1173         ev_debug_message (DEBUG_JOBS, NULL);
1174         
1175         job = g_object_new (EV_TYPE_JOB_FIND, NULL);
1176
1177         EV_JOB (job)->document = g_object_ref (document);
1178         job->start_page = start_page;
1179         job->current_page = start_page;
1180         job->n_pages = n_pages;
1181         job->pages = g_new0 (GList *, n_pages);
1182         job->text = g_strdup (text);
1183         job->case_sensitive = case_sensitive;
1184         job->has_results = FALSE;
1185
1186         return EV_JOB (job);
1187 }
1188
1189 gint
1190 ev_job_find_get_n_results (EvJobFind *job,
1191                            gint       page)
1192 {
1193         return g_list_length (job->pages[page]);
1194 }
1195
1196 gdouble
1197 ev_job_find_get_progress (EvJobFind *job)
1198 {
1199         gint pages_done;
1200
1201         if (ev_job_is_finished (EV_JOB (job)))
1202                 return 1.0;
1203         
1204         if (job->current_page > job->start_page) {
1205                 pages_done = job->current_page - job->start_page + 1;
1206         } else if (job->current_page == job->start_page) {
1207                 pages_done = job->n_pages;
1208         } else {
1209                 pages_done = job->n_pages - job->start_page + job->current_page;
1210         }
1211
1212         return pages_done / (gdouble) job->n_pages;
1213 }
1214
1215 gboolean
1216 ev_job_find_has_results (EvJobFind *job)
1217 {
1218         return job->has_results;
1219 }
1220
1221 GList **
1222 ev_job_find_get_results (EvJobFind *job)
1223 {
1224         return job->pages;
1225 }
1226
1227 /* EvJobLayers */
1228 static void
1229 ev_job_layers_init (EvJobLayers *job)
1230 {
1231         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1232 }
1233
1234 static void
1235 ev_job_layers_dispose (GObject *object)
1236 {
1237         EvJobLayers *job;
1238
1239         ev_debug_message (DEBUG_JOBS, NULL);
1240         
1241         job = EV_JOB_LAYERS (object);
1242
1243         if (job->model) {
1244                 g_object_unref (job->model);
1245                 job->model = NULL;
1246         }
1247
1248         (* G_OBJECT_CLASS (ev_job_layers_parent_class)->dispose) (object);
1249 }
1250
1251 static gboolean
1252 ev_job_layers_run (EvJob *job)
1253 {
1254         EvJobLayers *job_layers = EV_JOB_LAYERS (job);
1255
1256         ev_debug_message (DEBUG_JOBS, NULL);
1257         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1258         
1259         ev_document_doc_mutex_lock ();
1260         job_layers->model = ev_document_layers_get_layers (EV_DOCUMENT_LAYERS (job->document));
1261         ev_document_doc_mutex_unlock ();
1262         
1263         ev_job_succeeded (job);
1264         
1265         return FALSE;
1266 }
1267
1268 static void
1269 ev_job_layers_class_init (EvJobLayersClass *class)
1270 {
1271         GObjectClass *oclass = G_OBJECT_CLASS (class);
1272         EvJobClass   *job_class = EV_JOB_CLASS (class);
1273
1274         oclass->dispose = ev_job_layers_dispose;
1275         job_class->run = ev_job_layers_run;
1276 }
1277
1278 EvJob *
1279 ev_job_layers_new (EvDocument *document)
1280 {
1281         EvJob *job;
1282
1283         ev_debug_message (DEBUG_JOBS, NULL);
1284
1285         job = g_object_new (EV_TYPE_JOB_LAYERS, NULL);
1286         job->document = g_object_ref (document);
1287         
1288         return job;
1289 }
1290
1291 /* EvJobExport */
1292 static void
1293 ev_job_export_init (EvJobExport *job)
1294 {
1295         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1296         job->page = -1;
1297 }
1298
1299 static void
1300 ev_job_export_dispose (GObject *object)
1301 {
1302         EvJobExport *job;
1303
1304         ev_debug_message (DEBUG_JOBS, NULL);
1305         
1306         job = EV_JOB_EXPORT (object);
1307
1308         if (job->rc) {
1309                 g_object_unref (job->rc);
1310                 job->rc = NULL;
1311         }
1312
1313         (* G_OBJECT_CLASS (ev_job_export_parent_class)->dispose) (object);
1314 }
1315
1316 static gboolean
1317 ev_job_export_run (EvJob *job)
1318 {
1319         EvJobExport *job_export = EV_JOB_EXPORT (job);
1320         EvPage      *ev_page;
1321
1322         g_assert (job_export->page != -1);
1323
1324         ev_debug_message (DEBUG_JOBS, NULL);
1325         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1326         
1327         ev_document_doc_mutex_lock ();
1328         
1329         ev_page = ev_document_get_page (job->document, job_export->page);
1330         if (job_export->rc) {
1331                 job->failed = FALSE;
1332                 job->finished = FALSE;
1333                 g_clear_error (&job->error);
1334                 
1335                 ev_render_context_set_page (job_export->rc, ev_page);
1336         } else {
1337                 job_export->rc = ev_render_context_new (ev_page, 0, 1.0);
1338         }
1339         g_object_unref (ev_page);
1340         
1341         ev_file_exporter_do_page (EV_FILE_EXPORTER (job->document), job_export->rc);
1342         
1343         ev_document_doc_mutex_unlock ();
1344         
1345         ev_job_succeeded (job);
1346         
1347         return FALSE;
1348 }
1349
1350 static void
1351 ev_job_export_class_init (EvJobExportClass *class)
1352 {
1353         GObjectClass *oclass = G_OBJECT_CLASS (class);
1354         EvJobClass   *job_class = EV_JOB_CLASS (class);
1355
1356         oclass->dispose = ev_job_export_dispose;
1357         job_class->run = ev_job_export_run;
1358 }
1359
1360 EvJob *
1361 ev_job_export_new (EvDocument *document)
1362 {
1363         EvJob *job;
1364
1365         ev_debug_message (DEBUG_JOBS, NULL);
1366
1367         job = g_object_new (EV_TYPE_JOB_EXPORT, NULL);
1368         job->document = g_object_ref (document);
1369         
1370         return job;
1371 }
1372
1373 void
1374 ev_job_export_set_page (EvJobExport *job,
1375                         gint         page)
1376 {
1377         job->page = page;
1378 }
1379
1380 /* EvJobPrint */
1381 static void
1382 ev_job_print_init (EvJobPrint *job)
1383 {
1384         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1385         job->page = -1;
1386 }
1387
1388 static void
1389 ev_job_print_dispose (GObject *object)
1390 {
1391         EvJobPrint *job;
1392
1393         ev_debug_message (DEBUG_JOBS, NULL);
1394
1395         job = EV_JOB_PRINT (object);
1396
1397         if (job->cr) {
1398                 cairo_destroy (job->cr);
1399                 job->cr = NULL;
1400         }
1401
1402         (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
1403 }
1404
1405 static gboolean
1406 ev_job_print_run (EvJob *job)
1407 {
1408         EvJobPrint     *job_print = EV_JOB_PRINT (job);
1409         EvPage         *ev_page;
1410         cairo_status_t  cr_status;
1411
1412         g_assert (job_print->page != -1);
1413         g_assert (job_print->cr != NULL);
1414
1415         ev_debug_message (DEBUG_JOBS, NULL);
1416         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1417
1418         job->failed = FALSE;
1419         job->finished = FALSE;
1420         g_clear_error (&job->error);
1421
1422         ev_document_doc_mutex_lock ();
1423
1424         ev_page = ev_document_get_page (job->document, job_print->page);
1425         ev_document_print_print_page (EV_DOCUMENT_PRINT (job->document),
1426                                       ev_page, job_print->cr);
1427         g_object_unref (ev_page);
1428
1429         ev_document_doc_mutex_unlock ();
1430
1431         cr_status = cairo_status (job_print->cr);
1432         if (cr_status == CAIRO_STATUS_SUCCESS) {
1433                 ev_job_succeeded (job);
1434         } else {
1435                 ev_job_failed (job,
1436                                GTK_PRINT_ERROR,
1437                                GTK_PRINT_ERROR_GENERAL,
1438                                _("Failed to print page %d: %s"),
1439                                job_print->page,
1440                                cairo_status_to_string (cr_status));
1441         }
1442
1443         return FALSE;
1444 }
1445
1446 static void
1447 ev_job_print_class_init (EvJobPrintClass *class)
1448 {
1449         GObjectClass *oclass = G_OBJECT_CLASS (class);
1450         EvJobClass   *job_class = EV_JOB_CLASS (class);
1451
1452         oclass->dispose = ev_job_print_dispose;
1453         job_class->run = ev_job_print_run;
1454 }
1455
1456 EvJob *
1457 ev_job_print_new (EvDocument *document)
1458 {
1459         EvJob *job;
1460
1461         ev_debug_message (DEBUG_JOBS, NULL);
1462
1463         job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1464         job->document = g_object_ref (document);
1465
1466         return job;
1467 }
1468
1469 void
1470 ev_job_print_set_page (EvJobPrint *job,
1471                        gint        page)
1472 {
1473         job->page = page;
1474 }
1475
1476 void
1477 ev_job_print_set_cairo (EvJobPrint *job,
1478                         cairo_t    *cr)
1479 {
1480         if (job->cr == cr)
1481                 return;
1482
1483         if (job->cr)
1484                 cairo_destroy (job->cr);
1485         job->cr = cr ? cairo_reference (cr) : NULL;
1486 }