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