]> www.fi.muni.cz Git - evince.git/blob - libview/ev-jobs.c
view: do not call get_thumbnail_frame when pixbuf is NULL.
[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         if (pixbuf)
818                 job_thumb->thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
819         g_object_unref (pixbuf);
820
821         ev_job_succeeded (job);
822         
823         return FALSE;
824 }
825
826 static void
827 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
828 {
829         GObjectClass *oclass = G_OBJECT_CLASS (class);
830         EvJobClass   *job_class = EV_JOB_CLASS (class);
831
832         oclass->dispose = ev_job_thumbnail_dispose;
833         job_class->run = ev_job_thumbnail_run;
834 }
835
836 EvJob *
837 ev_job_thumbnail_new (EvDocument *document,
838                       gint        page,
839                       gint        rotation,
840                       gdouble     scale)
841 {
842         EvJobThumbnail *job;
843
844         ev_debug_message (DEBUG_JOBS, "%d", page);
845         
846         job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
847
848         EV_JOB (job)->document = g_object_ref (document);
849         job->page = page;
850         job->rotation = rotation;
851         job->scale = scale;
852
853         return EV_JOB (job);
854 }
855
856 /* EvJobFonts */
857 static void
858 ev_job_fonts_init (EvJobFonts *job)
859 {
860         EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
861 }
862
863 static gboolean
864 ev_job_fonts_run (EvJob *job)
865 {
866         EvJobFonts      *job_fonts = EV_JOB_FONTS (job);
867         EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
868
869         ev_debug_message (DEBUG_JOBS, NULL);
870         
871         /* Do not block the main loop */
872         if (!ev_document_doc_mutex_trylock ())
873                 return TRUE;
874         
875         if (!ev_document_fc_mutex_trylock ())
876                 return TRUE;
877
878 #ifdef EV_ENABLE_DEBUG
879         /* We use the #ifdef in this case because of the if */
880         if (ev_document_fonts_get_progress (fonts) == 0)
881                 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
882 #endif
883
884         job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
885         g_signal_emit (job_fonts, job_fonts_signals[FONTS_UPDATED], 0,
886                        ev_document_fonts_get_progress (fonts));
887
888         ev_document_fc_mutex_unlock ();
889         ev_document_doc_mutex_unlock ();
890
891         if (job_fonts->scan_completed)
892                 ev_job_succeeded (job);
893         
894         return !job_fonts->scan_completed;
895 }
896
897 static void
898 ev_job_fonts_class_init (EvJobFontsClass *class)
899 {
900         EvJobClass *job_class = EV_JOB_CLASS (class);
901         
902         job_class->run = ev_job_fonts_run;
903         
904         job_fonts_signals[FONTS_UPDATED] =
905                 g_signal_new ("updated",
906                               EV_TYPE_JOB_FONTS,
907                               G_SIGNAL_RUN_LAST,
908                               G_STRUCT_OFFSET (EvJobFontsClass, updated),
909                               NULL, NULL,
910                               g_cclosure_marshal_VOID__DOUBLE,
911                               G_TYPE_NONE,
912                               1, G_TYPE_DOUBLE);
913 }
914
915 EvJob *
916 ev_job_fonts_new (EvDocument *document)
917 {
918         EvJobFonts *job;
919
920         ev_debug_message (DEBUG_JOBS, NULL);
921         
922         job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
923
924         EV_JOB (job)->document = g_object_ref (document);
925
926         return EV_JOB (job);
927 }
928
929 /* EvJobLoad */
930 static void
931 ev_job_load_init (EvJobLoad *job)
932 {
933         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
934 }
935
936 static void
937 ev_job_load_dispose (GObject *object)
938 {
939         EvJobLoad *job = EV_JOB_LOAD (object);
940
941         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
942         
943         if (job->uri) {
944                 g_free (job->uri);
945                 job->uri = NULL;
946         }
947
948         if (job->password) {
949                 g_free (job->password);
950                 job->password = NULL;
951         }
952
953         (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
954 }
955
956 static gboolean
957 ev_job_load_run (EvJob *job)
958 {
959         EvJobLoad *job_load = EV_JOB_LOAD (job);
960         GError    *error = NULL;
961         
962         ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
963         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
964         
965         ev_document_fc_mutex_lock ();
966
967         /* This job may already have a document even if the job didn't complete
968            because, e.g., a password is required - if so, just reload rather than
969            creating a new instance */
970         if (job->document) {
971                 const gchar *uncompressed_uri;
972
973                 if (job_load->password) {
974                         ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
975                                                            job_load->password);
976                 }
977                 
978                 job->failed = FALSE;
979                 job->finished = FALSE;
980                 g_clear_error (&job->error);
981
982                 uncompressed_uri = g_object_get_data (G_OBJECT (job->document),
983                                                       "uri-uncompressed");
984                 ev_document_load (job->document,
985                                   uncompressed_uri ? uncompressed_uri : job_load->uri,
986                                   &error);
987         } else {
988                 job->document = ev_document_factory_get_document (job_load->uri,
989                                                                   &error);
990         }
991
992         ev_document_fc_mutex_unlock ();
993
994         if (error) {
995                 ev_job_failed_from_error (job, error);
996                 g_error_free (error);
997         } else {
998                 ev_job_succeeded (job);
999         }
1000
1001         return FALSE;
1002 }
1003
1004 static void
1005 ev_job_load_class_init (EvJobLoadClass *class)
1006 {
1007         GObjectClass *oclass = G_OBJECT_CLASS (class);
1008         EvJobClass   *job_class = EV_JOB_CLASS (class);
1009
1010         oclass->dispose = ev_job_load_dispose;
1011         job_class->run = ev_job_load_run;
1012 }
1013
1014 EvJob *
1015 ev_job_load_new (const gchar *uri)
1016 {
1017         EvJobLoad *job;
1018
1019         ev_debug_message (DEBUG_JOBS, "%s", uri);
1020         
1021         job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
1022         job->uri = g_strdup (uri);
1023
1024         return EV_JOB (job);
1025 }
1026
1027 void
1028 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
1029 {
1030         ev_debug_message (DEBUG_JOBS, "%s", uri);
1031         
1032         if (job->uri)
1033                 g_free (job->uri);
1034         job->uri = g_strdup (uri);
1035 }
1036
1037 void
1038 ev_job_load_set_password (EvJobLoad *job, const gchar *password)
1039 {
1040         ev_debug_message (DEBUG_JOBS, NULL);
1041
1042         if (job->password)
1043                 g_free (job->password);
1044         job->password = password ? g_strdup (password) : NULL;
1045 }
1046
1047 /* EvJobSave */
1048 static void
1049 ev_job_save_init (EvJobSave *job)
1050 {
1051         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1052 }
1053
1054 static void
1055 ev_job_save_dispose (GObject *object)
1056 {
1057         EvJobSave *job = EV_JOB_SAVE (object);
1058
1059         ev_debug_message (DEBUG_JOBS, "%s", job->uri);
1060         
1061         if (job->uri) {
1062                 g_free (job->uri);
1063                 job->uri = NULL;
1064         }
1065
1066         if (job->document_uri) {
1067                 g_free (job->document_uri);
1068                 job->document_uri = NULL;
1069         }
1070
1071         (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
1072 }
1073
1074 static gboolean
1075 ev_job_save_run (EvJob *job)
1076 {
1077         EvJobSave *job_save = EV_JOB_SAVE (job);
1078         gint       fd;
1079         gchar     *tmp_filename = NULL;
1080         gchar     *local_uri;
1081         GError    *error = NULL;
1082         
1083         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
1084         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1085
1086         fd = ev_mkstemp ("saveacopy.XXXXXX", &tmp_filename, &error);
1087         if (fd == -1) {
1088                 ev_job_failed_from_error (job, error);
1089                 g_error_free (error);
1090
1091                 return FALSE;
1092         }
1093
1094         ev_document_doc_mutex_lock ();
1095
1096         /* Save document to temp filename */
1097         local_uri = g_filename_to_uri (tmp_filename, NULL, &error);
1098         if (local_uri != NULL) {
1099                 ev_document_save (job->document, local_uri, &error);
1100         }
1101
1102         close (fd);
1103
1104         ev_document_doc_mutex_unlock ();
1105
1106         if (error) {
1107                 g_free (local_uri);
1108                 ev_job_failed_from_error (job, error);
1109                 g_error_free (error);
1110                 
1111                 return FALSE;
1112         }
1113
1114         /* If original document was compressed,
1115          * compress it again before saving
1116          */
1117         if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
1118                 EvCompressionType ctype = EV_COMPRESSION_NONE;
1119                 const gchar      *ext;
1120                 gchar            *uri_comp;
1121                 
1122                 ext = g_strrstr (job_save->document_uri, ".gz");
1123                 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
1124                         ctype = EV_COMPRESSION_GZIP;
1125                 
1126                 ext = g_strrstr (job_save->document_uri, ".bz2");
1127                 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
1128                         ctype = EV_COMPRESSION_BZIP2;
1129
1130                 uri_comp = ev_file_compress (local_uri, ctype, &error);
1131                 g_free (local_uri);
1132                 g_unlink (tmp_filename);
1133
1134                 if (!uri_comp || error) {
1135                         local_uri = NULL;
1136                 } else {
1137                         local_uri = uri_comp;
1138                 }
1139         }
1140
1141         g_free (tmp_filename);
1142
1143         if (error) {
1144                 g_free (local_uri);
1145                 ev_job_failed_from_error (job, error);
1146                 g_error_free (error);
1147                 
1148                 return FALSE;
1149         }
1150
1151         if (!local_uri)
1152                 return FALSE;
1153
1154         ev_xfer_uri_simple (local_uri, job_save->uri, &error);
1155         ev_tmp_uri_unlink (local_uri);
1156
1157         if (error) {
1158                 ev_job_failed_from_error (job, error);
1159                 g_error_free (error);
1160         } else {
1161                 ev_job_succeeded (job);
1162         }
1163         
1164         return FALSE;
1165 }
1166
1167 static void
1168 ev_job_save_class_init (EvJobSaveClass *class)
1169 {
1170         GObjectClass *oclass = G_OBJECT_CLASS (class);
1171         EvJobClass   *job_class = EV_JOB_CLASS (class);
1172
1173         oclass->dispose = ev_job_save_dispose;
1174         job_class->run = ev_job_save_run;
1175 }
1176
1177 EvJob *
1178 ev_job_save_new (EvDocument  *document,
1179                  const gchar *uri,
1180                  const gchar *document_uri)
1181 {
1182         EvJobSave *job;
1183
1184         ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
1185
1186         job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
1187
1188         EV_JOB (job)->document = g_object_ref (document);
1189         job->uri = g_strdup (uri);
1190         job->document_uri = g_strdup (document_uri);
1191
1192         return EV_JOB (job);
1193 }
1194
1195 /* EvJobFind */
1196 static void
1197 ev_job_find_init (EvJobFind *job)
1198 {
1199         EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
1200 }
1201
1202 static void
1203 ev_job_find_dispose (GObject *object)
1204 {
1205         EvJobFind *job = EV_JOB_FIND (object);
1206
1207         ev_debug_message (DEBUG_JOBS, NULL);
1208
1209         if (job->text) {
1210                 g_free (job->text);
1211                 job->text = NULL;
1212         }
1213
1214         if (job->pages) {
1215                 gint i;
1216
1217                 for (i = 0; i < job->n_pages; i++) {
1218                         g_list_foreach (job->pages[i], (GFunc)ev_rectangle_free, NULL);
1219                         g_list_free (job->pages[i]);
1220                 }
1221
1222                 g_free (job->pages);
1223                 job->pages = NULL;
1224         }
1225         
1226         (* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object);
1227 }
1228
1229 static gboolean
1230 ev_job_find_run (EvJob *job)
1231 {
1232         EvJobFind      *job_find = EV_JOB_FIND (job);
1233         EvDocumentFind *find = EV_DOCUMENT_FIND (job->document);
1234         EvPage         *ev_page;
1235         GList          *matches;
1236
1237         ev_debug_message (DEBUG_JOBS, NULL);
1238         
1239         /* Do not block the main loop */
1240         if (!ev_document_doc_mutex_trylock ())
1241                 return TRUE;
1242         
1243 #ifdef EV_ENABLE_DEBUG
1244         /* We use the #ifdef in this case because of the if */
1245         if (job_find->current_page == job_find->start_page)
1246                 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1247 #endif
1248
1249         ev_page = ev_document_get_page (job->document, job_find->current_page);
1250         matches = ev_document_find_find_text (find, ev_page, job_find->text,
1251                                               job_find->case_sensitive);
1252         g_object_unref (ev_page);
1253         
1254         ev_document_doc_mutex_unlock ();
1255
1256         if (!job_find->has_results)
1257                 job_find->has_results = (matches != NULL);
1258
1259         job_find->pages[job_find->current_page] = matches;
1260         g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page);
1261                        
1262         job_find->current_page = (job_find->current_page + 1) % job_find->n_pages;
1263         if (job_find->current_page == job_find->start_page) {
1264                 ev_job_succeeded (job);
1265
1266                 return FALSE;
1267         }
1268
1269         return TRUE;
1270 }
1271
1272 static void
1273 ev_job_find_class_init (EvJobFindClass *class)
1274 {
1275         EvJobClass   *job_class = EV_JOB_CLASS (class);
1276         GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1277         
1278         job_class->run = ev_job_find_run;
1279         gobject_class->dispose = ev_job_find_dispose;
1280         
1281         job_find_signals[FIND_UPDATED] =
1282                 g_signal_new ("updated",
1283                               EV_TYPE_JOB_FIND,
1284                               G_SIGNAL_RUN_LAST,
1285                               G_STRUCT_OFFSET (EvJobFindClass, updated),
1286                               NULL, NULL,
1287                               g_cclosure_marshal_VOID__INT,
1288                               G_TYPE_NONE,
1289                               1, G_TYPE_INT);
1290 }
1291
1292 EvJob *
1293 ev_job_find_new (EvDocument  *document,
1294                  gint         start_page,
1295                  gint         n_pages,
1296                  const gchar *text,
1297                  gboolean     case_sensitive)
1298 {
1299         EvJobFind *job;
1300         
1301         ev_debug_message (DEBUG_JOBS, NULL);
1302         
1303         job = g_object_new (EV_TYPE_JOB_FIND, NULL);
1304
1305         EV_JOB (job)->document = g_object_ref (document);
1306         job->start_page = start_page;
1307         job->current_page = start_page;
1308         job->n_pages = n_pages;
1309         job->pages = g_new0 (GList *, n_pages);
1310         job->text = g_strdup (text);
1311         job->case_sensitive = case_sensitive;
1312         job->has_results = FALSE;
1313
1314         return EV_JOB (job);
1315 }
1316
1317 gint
1318 ev_job_find_get_n_results (EvJobFind *job,
1319                            gint       page)
1320 {
1321         return g_list_length (job->pages[page]);
1322 }
1323
1324 gdouble
1325 ev_job_find_get_progress (EvJobFind *job)
1326 {
1327         gint pages_done;
1328
1329         if (ev_job_is_finished (EV_JOB (job)))
1330                 return 1.0;
1331         
1332         if (job->current_page > job->start_page) {
1333                 pages_done = job->current_page - job->start_page + 1;
1334         } else if (job->current_page == job->start_page) {
1335                 pages_done = job->n_pages;
1336         } else {
1337                 pages_done = job->n_pages - job->start_page + job->current_page;
1338         }
1339
1340         return pages_done / (gdouble) job->n_pages;
1341 }
1342
1343 gboolean
1344 ev_job_find_has_results (EvJobFind *job)
1345 {
1346         return job->has_results;
1347 }
1348
1349 GList **
1350 ev_job_find_get_results (EvJobFind *job)
1351 {
1352         return job->pages;
1353 }
1354
1355 /* EvJobLayers */
1356 static void
1357 ev_job_layers_init (EvJobLayers *job)
1358 {
1359         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1360 }
1361
1362 static void
1363 ev_job_layers_dispose (GObject *object)
1364 {
1365         EvJobLayers *job;
1366
1367         ev_debug_message (DEBUG_JOBS, NULL);
1368         
1369         job = EV_JOB_LAYERS (object);
1370
1371         if (job->model) {
1372                 g_object_unref (job->model);
1373                 job->model = NULL;
1374         }
1375
1376         (* G_OBJECT_CLASS (ev_job_layers_parent_class)->dispose) (object);
1377 }
1378
1379 static gboolean
1380 ev_job_layers_run (EvJob *job)
1381 {
1382         EvJobLayers *job_layers = EV_JOB_LAYERS (job);
1383
1384         ev_debug_message (DEBUG_JOBS, NULL);
1385         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1386         
1387         ev_document_doc_mutex_lock ();
1388         job_layers->model = ev_document_layers_get_layers (EV_DOCUMENT_LAYERS (job->document));
1389         ev_document_doc_mutex_unlock ();
1390         
1391         ev_job_succeeded (job);
1392         
1393         return FALSE;
1394 }
1395
1396 static void
1397 ev_job_layers_class_init (EvJobLayersClass *class)
1398 {
1399         GObjectClass *oclass = G_OBJECT_CLASS (class);
1400         EvJobClass   *job_class = EV_JOB_CLASS (class);
1401
1402         oclass->dispose = ev_job_layers_dispose;
1403         job_class->run = ev_job_layers_run;
1404 }
1405
1406 EvJob *
1407 ev_job_layers_new (EvDocument *document)
1408 {
1409         EvJob *job;
1410
1411         ev_debug_message (DEBUG_JOBS, NULL);
1412
1413         job = g_object_new (EV_TYPE_JOB_LAYERS, NULL);
1414         job->document = g_object_ref (document);
1415         
1416         return job;
1417 }
1418
1419 /* EvJobExport */
1420 static void
1421 ev_job_export_init (EvJobExport *job)
1422 {
1423         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1424         job->page = -1;
1425 }
1426
1427 static void
1428 ev_job_export_dispose (GObject *object)
1429 {
1430         EvJobExport *job;
1431
1432         ev_debug_message (DEBUG_JOBS, NULL);
1433         
1434         job = EV_JOB_EXPORT (object);
1435
1436         if (job->rc) {
1437                 g_object_unref (job->rc);
1438                 job->rc = NULL;
1439         }
1440
1441         (* G_OBJECT_CLASS (ev_job_export_parent_class)->dispose) (object);
1442 }
1443
1444 static gboolean
1445 ev_job_export_run (EvJob *job)
1446 {
1447         EvJobExport *job_export = EV_JOB_EXPORT (job);
1448         EvPage      *ev_page;
1449
1450         g_assert (job_export->page != -1);
1451
1452         ev_debug_message (DEBUG_JOBS, NULL);
1453         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1454         
1455         ev_document_doc_mutex_lock ();
1456         
1457         ev_page = ev_document_get_page (job->document, job_export->page);
1458         if (job_export->rc) {
1459                 job->failed = FALSE;
1460                 job->finished = FALSE;
1461                 g_clear_error (&job->error);
1462                 
1463                 ev_render_context_set_page (job_export->rc, ev_page);
1464         } else {
1465                 job_export->rc = ev_render_context_new (ev_page, 0, 1.0);
1466         }
1467         g_object_unref (ev_page);
1468         
1469         ev_file_exporter_do_page (EV_FILE_EXPORTER (job->document), job_export->rc);
1470         
1471         ev_document_doc_mutex_unlock ();
1472         
1473         ev_job_succeeded (job);
1474         
1475         return FALSE;
1476 }
1477
1478 static void
1479 ev_job_export_class_init (EvJobExportClass *class)
1480 {
1481         GObjectClass *oclass = G_OBJECT_CLASS (class);
1482         EvJobClass   *job_class = EV_JOB_CLASS (class);
1483
1484         oclass->dispose = ev_job_export_dispose;
1485         job_class->run = ev_job_export_run;
1486 }
1487
1488 EvJob *
1489 ev_job_export_new (EvDocument *document)
1490 {
1491         EvJob *job;
1492
1493         ev_debug_message (DEBUG_JOBS, NULL);
1494
1495         job = g_object_new (EV_TYPE_JOB_EXPORT, NULL);
1496         job->document = g_object_ref (document);
1497         
1498         return job;
1499 }
1500
1501 void
1502 ev_job_export_set_page (EvJobExport *job,
1503                         gint         page)
1504 {
1505         job->page = page;
1506 }
1507
1508 /* EvJobPrint */
1509 static void
1510 ev_job_print_init (EvJobPrint *job)
1511 {
1512         EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1513         job->page = -1;
1514 }
1515
1516 static void
1517 ev_job_print_dispose (GObject *object)
1518 {
1519         EvJobPrint *job;
1520
1521         ev_debug_message (DEBUG_JOBS, NULL);
1522
1523         job = EV_JOB_PRINT (object);
1524
1525         if (job->cr) {
1526                 cairo_destroy (job->cr);
1527                 job->cr = NULL;
1528         }
1529
1530         (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
1531 }
1532
1533 static gboolean
1534 ev_job_print_run (EvJob *job)
1535 {
1536         EvJobPrint     *job_print = EV_JOB_PRINT (job);
1537         EvPage         *ev_page;
1538         cairo_status_t  cr_status;
1539
1540         g_assert (job_print->page != -1);
1541         g_assert (job_print->cr != NULL);
1542
1543         ev_debug_message (DEBUG_JOBS, NULL);
1544         ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1545
1546         job->failed = FALSE;
1547         job->finished = FALSE;
1548         g_clear_error (&job->error);
1549
1550         ev_document_doc_mutex_lock ();
1551
1552         ev_page = ev_document_get_page (job->document, job_print->page);
1553         ev_document_print_print_page (EV_DOCUMENT_PRINT (job->document),
1554                                       ev_page, job_print->cr);
1555         g_object_unref (ev_page);
1556
1557         ev_document_doc_mutex_unlock ();
1558
1559         cr_status = cairo_status (job_print->cr);
1560         if (cr_status == CAIRO_STATUS_SUCCESS) {
1561                 ev_job_succeeded (job);
1562         } else {
1563                 ev_job_failed (job,
1564                                GTK_PRINT_ERROR,
1565                                GTK_PRINT_ERROR_GENERAL,
1566                                _("Failed to print page %d: %s"),
1567                                job_print->page,
1568                                cairo_status_to_string (cr_status));
1569         }
1570
1571         return FALSE;
1572 }
1573
1574 static void
1575 ev_job_print_class_init (EvJobPrintClass *class)
1576 {
1577         GObjectClass *oclass = G_OBJECT_CLASS (class);
1578         EvJobClass   *job_class = EV_JOB_CLASS (class);
1579
1580         oclass->dispose = ev_job_print_dispose;
1581         job_class->run = ev_job_print_run;
1582 }
1583
1584 EvJob *
1585 ev_job_print_new (EvDocument *document)
1586 {
1587         EvJob *job;
1588
1589         ev_debug_message (DEBUG_JOBS, NULL);
1590
1591         job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1592         job->document = g_object_ref (document);
1593
1594         return job;
1595 }
1596
1597 void
1598 ev_job_print_set_page (EvJobPrint *job,
1599                        gint        page)
1600 {
1601         job->page = page;
1602 }
1603
1604 void
1605 ev_job_print_set_cairo (EvJobPrint *job,
1606                         cairo_t    *cr)
1607 {
1608         if (job->cr == cr)
1609                 return;
1610
1611         if (job->cr)
1612                 cairo_destroy (job->cr);
1613         job->cr = cr ? cairo_reference (cr) : NULL;
1614 }