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