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