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