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