1 /* this file is part of evince, a gnome document viewer
3 * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
4 * Copyright (C) 2005 Red Hat, Inc
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.
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.
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.
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"
38 #include <glib/gstdio.h>
39 #include <glib/gi18n.h>
42 static void ev_job_init (EvJob *job);
43 static void ev_job_class_init (EvJobClass *class);
44 static void ev_job_links_init (EvJobLinks *job);
45 static void ev_job_links_class_init (EvJobLinksClass *class);
46 static void ev_job_attachments_init (EvJobAttachments *job);
47 static void ev_job_attachments_class_init (EvJobAttachmentsClass *class);
48 static void ev_job_render_init (EvJobRender *job);
49 static void ev_job_render_class_init (EvJobRenderClass *class);
50 static void ev_job_thumbnail_init (EvJobThumbnail *job);
51 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
52 static void ev_job_load_init (EvJobLoad *job);
53 static void ev_job_load_class_init (EvJobLoadClass *class);
54 static void ev_job_save_init (EvJobSave *job);
55 static void ev_job_save_class_init (EvJobSaveClass *class);
56 static void ev_job_print_init (EvJobPrint *job);
57 static void ev_job_print_class_init (EvJobPrintClass *class);
58 static void ev_job_find_init (EvJobFind *job);
59 static void ev_job_find_class_init (EvJobFindClass *class);
82 static guint job_signals[LAST_SIGNAL] = { 0 };
83 static guint job_render_signals[RENDER_LAST_SIGNAL] = { 0 };
84 static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 };
85 static guint job_find_signals[FIND_LAST_SIGNAL] = { 0 };
87 G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
88 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
89 G_DEFINE_TYPE (EvJobAttachments, ev_job_attachments, EV_TYPE_JOB)
90 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
91 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
92 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
93 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
94 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
95 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
96 G_DEFINE_TYPE (EvJobFind, ev_job_find, EV_TYPE_JOB)
100 ev_job_init (EvJob *job)
102 job->cancellable = g_cancellable_new ();
106 ev_job_dispose (GObject *object)
110 job = EV_JOB (object);
113 g_object_unref (job->document);
114 job->document = NULL;
117 if (job->cancellable) {
118 g_object_unref (job->cancellable);
119 job->cancellable = NULL;
123 g_error_free (job->error);
127 (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
131 ev_job_class_init (EvJobClass *class)
133 GObjectClass *oclass;
135 oclass = G_OBJECT_CLASS (class);
137 oclass->dispose = ev_job_dispose;
139 job_signals[CANCELLED] =
140 g_signal_new ("cancelled",
143 G_STRUCT_OFFSET (EvJobClass, cancelled),
145 g_cclosure_marshal_VOID__VOID,
147 job_signals [FINISHED] =
148 g_signal_new ("finished",
151 G_STRUCT_OFFSET (EvJobClass, finished),
153 g_cclosure_marshal_VOID__VOID,
158 emit_finished (EvJob *job)
160 ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
162 job->idle_finished_id = 0;
164 if (job->cancelled) {
165 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit finished", EV_GET_TYPE_NAME (job), job);
167 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
168 g_signal_emit (job, job_signals[FINISHED], 0);
175 ev_job_emit_finished (EvJob *job)
177 ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
179 if (g_cancellable_is_cancelled (job->cancellable)) {
180 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, returning", EV_GET_TYPE_NAME (job), job);
184 job->finished = TRUE;
186 if (job->run_mode == EV_JOB_RUN_THREAD) {
187 job->idle_finished_id =
188 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
189 (GSourceFunc)emit_finished,
191 (GDestroyNotify)g_object_unref);
193 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
194 g_signal_emit (job, job_signals[FINISHED], 0);
199 ev_job_run (EvJob *job)
201 EvJobClass *class = EV_JOB_GET_CLASS (job);
203 return class->run (job);
207 ev_job_cancel (EvJob *job)
209 if (job->cancelled || (job->finished && job->idle_finished_id == 0))
212 ev_debug_message (DEBUG_JOBS, "job %s (%p) cancelled", EV_GET_TYPE_NAME (job), job);
213 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
215 /* This should never be called from a thread */
216 job->cancelled = TRUE;
217 g_cancellable_cancel (job->cancellable);
218 g_signal_emit (job, job_signals[CANCELLED], 0);
222 ev_job_failed (EvJob *job,
231 if (job->failed || job->finished)
234 ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
238 va_start (args, format);
239 message = g_strdup_vprintf (format, args);
242 job->error = g_error_new (domain, code, message);
245 ev_job_emit_finished (job);
249 ev_job_failed_from_error (EvJob *job,
252 if (job->failed || job->finished)
255 ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
258 job->error = g_error_copy (error);
260 ev_job_emit_finished (job);
264 ev_job_succeeded (EvJob *job)
269 ev_debug_message (DEBUG_JOBS, "job %s (%p) succeeded", EV_GET_TYPE_NAME (job), job);
272 ev_job_emit_finished (job);
276 ev_job_is_finished (EvJob *job)
278 return job->finished;
282 ev_job_is_failed (EvJob *job)
288 ev_job_get_run_mode (EvJob *job)
290 return job->run_mode;
294 ev_job_set_run_mode (EvJob *job,
295 EvJobRunMode run_mode)
297 job->run_mode = run_mode;
302 ev_job_links_init (EvJobLinks *job)
304 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
308 ev_job_links_dispose (GObject *object)
312 ev_debug_message (DEBUG_JOBS, NULL);
314 job = EV_JOB_LINKS (object);
317 g_object_unref (job->model);
321 (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
325 ev_job_links_run (EvJob *job)
327 EvJobLinks *job_links = EV_JOB_LINKS (job);
329 ev_debug_message (DEBUG_JOBS, NULL);
330 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
332 ev_document_doc_mutex_lock ();
333 job_links->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (job->document));
334 ev_document_doc_mutex_unlock ();
336 ev_job_succeeded (job);
342 ev_job_links_class_init (EvJobLinksClass *class)
344 GObjectClass *oclass = G_OBJECT_CLASS (class);
345 EvJobClass *job_class = EV_JOB_CLASS (class);
347 oclass->dispose = ev_job_links_dispose;
348 job_class->run = ev_job_links_run;
352 ev_job_links_new (EvDocument *document)
356 ev_debug_message (DEBUG_JOBS, NULL);
358 job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
359 job->document = g_object_ref (document);
364 /* EvJobAttachments */
366 ev_job_attachments_init (EvJobAttachments *job)
368 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
372 ev_job_attachments_dispose (GObject *object)
374 EvJobAttachments *job;
376 ev_debug_message (DEBUG_JOBS, NULL);
378 job = EV_JOB_ATTACHMENTS (object);
380 if (job->attachments) {
381 g_list_foreach (job->attachments, (GFunc)g_object_unref, NULL);
382 g_list_free (job->attachments);
383 job->attachments = NULL;
386 (* G_OBJECT_CLASS (ev_job_attachments_parent_class)->dispose) (object);
390 ev_job_attachments_run (EvJob *job)
392 EvJobAttachments *job_attachments = EV_JOB_ATTACHMENTS (job);
394 ev_debug_message (DEBUG_JOBS, NULL);
395 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
397 ev_document_doc_mutex_lock ();
398 job_attachments->attachments = ev_document_get_attachments (job->document);
399 ev_document_doc_mutex_unlock ();
401 ev_job_succeeded (job);
407 ev_job_attachments_class_init (EvJobAttachmentsClass *class)
409 GObjectClass *oclass = G_OBJECT_CLASS (class);
410 EvJobClass *job_class = EV_JOB_CLASS (class);
412 oclass->dispose = ev_job_attachments_dispose;
413 job_class->run = ev_job_attachments_run;
417 ev_job_attachments_new (EvDocument *document)
421 ev_debug_message (DEBUG_JOBS, NULL);
423 job = g_object_new (EV_TYPE_JOB_ATTACHMENTS, NULL);
424 job->document = g_object_ref (document);
431 ev_job_render_init (EvJobRender *job)
433 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
437 ev_job_render_dispose (GObject *object)
441 job = EV_JOB_RENDER (object);
444 ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->ev_page->index, job);
445 g_object_unref (job->ev_page);
450 cairo_surface_destroy (job->surface);
454 if (job->selection) {
455 cairo_surface_destroy (job->selection);
456 job->selection = NULL;
459 if (job->selection_region) {
460 gdk_region_destroy (job->selection_region);
461 job->selection_region = NULL;
464 (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
468 notify_page_ready (EvJobRender *job)
470 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job);
471 ev_profiler_stop (EV_PROFILE_JOBS, "Rendering page %d", job->ev_page->index);
473 if (EV_JOB (job)->cancelled) {
474 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit page_ready", EV_GET_TYPE_NAME (job), job);
476 g_signal_emit (job, job_render_signals[PAGE_READY], 0);
483 ev_job_render_page_ready (EvJobRender *job)
485 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job);
487 job->page_ready = TRUE;
488 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
489 (GSourceFunc)notify_page_ready,
491 (GDestroyNotify)g_object_unref);
495 ev_job_render_run (EvJob *job)
497 EvJobRender *job_render = EV_JOB_RENDER (job);
500 ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job);
501 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
503 ev_document_doc_mutex_lock ();
505 ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page);
507 ev_document_fc_mutex_lock ();
509 job_render->ev_page = ev_document_get_page (job->document, job_render->page);
510 rc = ev_render_context_new (job_render->ev_page, job_render->rotation, job_render->scale);
512 job_render->surface = ev_document_render (job->document, rc);
513 /* If job was cancelled during the page rendering,
514 * we return now, so that the thread is finished ASAP
516 if (g_cancellable_is_cancelled (job->cancellable)) {
517 ev_document_fc_mutex_unlock ();
518 ev_document_doc_mutex_unlock ();
524 if ((job_render->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (job->document)) {
525 ev_selection_render_selection (EV_SELECTION (job->document),
527 &(job_render->selection),
528 &(job_render->selection_points),
530 job_render->selection_style,
531 &(job_render->text), &(job_render->base));
532 job_render->selection_region =
533 ev_selection_get_selection_region (EV_SELECTION (job->document),
535 job_render->selection_style,
536 &(job_render->selection_points));
539 ev_job_render_page_ready (job_render);
541 ev_document_fc_mutex_unlock ();
543 if ((job_render->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (job->document))
544 job_render->text_mapping =
545 ev_selection_get_selection_map (EV_SELECTION (job->document), rc);
546 if ((job_render->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document))
547 job_render->link_mapping =
548 ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), job_render->page);
549 if ((job_render->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document))
550 job_render->form_field_mapping =
551 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document),
552 job_render->ev_page);
553 if ((job_render->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document))
554 job_render->image_mapping =
555 ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document),
558 ev_document_doc_mutex_unlock ();
560 ev_job_succeeded (job);
566 ev_job_render_class_init (EvJobRenderClass *class)
568 GObjectClass *oclass = G_OBJECT_CLASS (class);
569 EvJobClass *job_class = EV_JOB_CLASS (class);
571 job_render_signals [PAGE_READY] =
572 g_signal_new ("page-ready",
575 G_STRUCT_OFFSET (EvJobRenderClass, page_ready),
577 g_cclosure_marshal_VOID__VOID,
580 oclass->dispose = ev_job_render_dispose;
581 job_class->run = ev_job_render_run;
585 ev_job_render_new (EvDocument *document,
595 ev_debug_message (DEBUG_JOBS, "page: %d", page);
597 job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
599 EV_JOB (job)->document = g_object_ref (document);
601 job->rotation = rotation;
603 job->target_width = width;
604 job->target_height = height;
611 ev_job_render_set_selection_info (EvJobRender *job,
612 EvRectangle *selection_points,
613 EvSelectionStyle selection_style,
617 job->flags |= EV_RENDER_INCLUDE_SELECTION;
619 job->selection_points = *selection_points;
620 job->selection_style = selection_style;
627 ev_job_thumbnail_init (EvJobThumbnail *job)
629 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
633 ev_job_thumbnail_dispose (GObject *object)
637 job = EV_JOB_THUMBNAIL (object);
639 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job);
641 if (job->thumbnail) {
642 g_object_unref (job->thumbnail);
643 job->thumbnail = NULL;
646 (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
650 ev_job_thumbnail_run (EvJob *job)
652 EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job);
656 ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job);
657 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
659 ev_document_doc_mutex_lock ();
661 page = ev_document_get_page (job->document, job_thumb->page);
662 rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
663 g_object_unref (page);
665 job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document),
668 ev_document_doc_mutex_unlock ();
670 ev_job_succeeded (job);
676 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
678 GObjectClass *oclass = G_OBJECT_CLASS (class);
679 EvJobClass *job_class = EV_JOB_CLASS (class);
681 oclass->dispose = ev_job_thumbnail_dispose;
682 job_class->run = ev_job_thumbnail_run;
686 ev_job_thumbnail_new (EvDocument *document,
693 ev_debug_message (DEBUG_JOBS, "%d", page);
695 job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
697 EV_JOB (job)->document = g_object_ref (document);
699 job->rotation = rotation;
707 ev_job_fonts_init (EvJobFonts *job)
709 EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
713 ev_job_fonts_run (EvJob *job)
715 EvJobFonts *job_fonts = EV_JOB_FONTS (job);
716 EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
718 ev_debug_message (DEBUG_JOBS, NULL);
720 /* Do not block the main loop */
721 if (!ev_document_doc_mutex_trylock ())
724 if (!ev_document_fc_mutex_trylock ())
727 #ifdef EV_ENABLE_DEBUG
728 /* We use the #ifdef in this case because of the if */
729 if (ev_document_fonts_get_progress (fonts) == 0)
730 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
733 job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
734 g_signal_emit (job_fonts, job_fonts_signals[FONTS_UPDATED], 0,
735 ev_document_fonts_get_progress (fonts));
737 ev_document_fc_mutex_unlock ();
738 ev_document_doc_mutex_unlock ();
740 if (job_fonts->scan_completed)
741 ev_job_succeeded (job);
743 return !job_fonts->scan_completed;
747 ev_job_fonts_class_init (EvJobFontsClass *class)
749 EvJobClass *job_class = EV_JOB_CLASS (class);
751 job_class->run = ev_job_fonts_run;
753 job_fonts_signals[FONTS_UPDATED] =
754 g_signal_new ("updated",
757 G_STRUCT_OFFSET (EvJobFontsClass, updated),
759 g_cclosure_marshal_VOID__DOUBLE,
765 ev_job_fonts_new (EvDocument *document)
769 ev_debug_message (DEBUG_JOBS, NULL);
771 job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
773 EV_JOB (job)->document = g_object_ref (document);
780 ev_job_load_init (EvJobLoad *job)
782 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
786 ev_job_load_dispose (GObject *object)
788 EvJobLoad *job = EV_JOB_LOAD (object);
790 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
798 g_free (job->password);
799 job->password = NULL;
803 g_object_unref (job->dest);
807 if (job->search_string) {
808 g_free (job->search_string);
809 job->search_string = NULL;
812 (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
816 ev_job_load_run (EvJob *job)
818 EvJobLoad *job_load = EV_JOB_LOAD (job);
819 GError *error = NULL;
821 ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
822 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
824 ev_document_fc_mutex_lock ();
826 /* This job may already have a document even if the job didn't complete
827 because, e.g., a password is required - if so, just reload rather than
828 creating a new instance */
830 if (job_load->password) {
831 ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
836 job->finished = FALSE;
837 g_clear_error (&job->error);
839 ev_document_load (job->document,
843 job->document = ev_document_factory_get_document (job_load->uri,
847 ev_document_fc_mutex_unlock ();
850 ev_job_failed_from_error (job, error);
851 g_error_free (error);
853 ev_job_succeeded (job);
860 ev_job_load_class_init (EvJobLoadClass *class)
862 GObjectClass *oclass = G_OBJECT_CLASS (class);
863 EvJobClass *job_class = EV_JOB_CLASS (class);
865 oclass->dispose = ev_job_load_dispose;
866 job_class->run = ev_job_load_run;
870 ev_job_load_new (const gchar *uri,
872 EvWindowRunMode mode,
873 const gchar *search_string)
877 ev_debug_message (DEBUG_JOBS, "%s", uri);
879 job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
881 job->uri = g_strdup (uri);
882 job->dest = dest ? g_object_ref (dest) : NULL;
884 job->search_string = search_string ? g_strdup (search_string) : NULL;
890 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
892 ev_debug_message (DEBUG_JOBS, "%s", uri);
896 job->uri = g_strdup (uri);
900 ev_job_load_set_password (EvJobLoad *job, const gchar *password)
902 ev_debug_message (DEBUG_JOBS, NULL);
905 g_free (job->password);
906 job->password = password ? g_strdup (password) : NULL;
911 ev_job_save_init (EvJobSave *job)
913 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
917 ev_job_save_dispose (GObject *object)
919 EvJobSave *job = EV_JOB_SAVE (object);
921 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
928 if (job->document_uri) {
929 g_free (job->document_uri);
930 job->document_uri = NULL;
933 (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
937 ev_job_save_run (EvJob *job)
939 EvJobSave *job_save = EV_JOB_SAVE (job);
944 GError *error = NULL;
946 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
947 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
949 filename = ev_tmp_filename ("saveacopy");
950 tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
953 fd = g_mkstemp (tmp_filename);
956 gint save_errno = errno;
958 display_name = g_filename_display_name (tmp_filename);
961 g_file_error_from_errno (save_errno),
962 _("Failed to create file “%s”: %s"),
963 display_name, g_strerror (save_errno));
964 g_free (display_name);
965 g_free (tmp_filename);
970 ev_document_doc_mutex_lock ();
972 /* Save document to temp filename */
973 local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
974 ev_document_save (job->document, local_uri, &error);
977 ev_document_doc_mutex_unlock ();
981 ev_job_failed_from_error (job, error);
982 g_error_free (error);
987 /* If original document was compressed,
988 * compress it again before saving
990 if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
991 EvCompressionType ctype = EV_COMPRESSION_NONE;
995 ext = g_strrstr (job_save->document_uri, ".gz");
996 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
997 ctype = EV_COMPRESSION_GZIP;
999 ext = g_strrstr (job_save->document_uri, ".bz2");
1000 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
1001 ctype = EV_COMPRESSION_BZIP2;
1003 uri_comp = ev_file_compress (local_uri, ctype, &error);
1005 ev_tmp_filename_unlink (tmp_filename);
1007 if (!uri_comp || error) {
1010 local_uri = uri_comp;
1014 g_free (tmp_filename);
1018 ev_job_failed_from_error (job, error);
1019 g_error_free (error);
1027 ev_xfer_uri_simple (local_uri, job_save->uri, &error);
1028 ev_tmp_uri_unlink (local_uri);
1031 ev_job_failed_from_error (job, error);
1032 g_error_free (error);
1034 ev_job_succeeded (job);
1041 ev_job_save_class_init (EvJobSaveClass *class)
1043 GObjectClass *oclass = G_OBJECT_CLASS (class);
1044 EvJobClass *job_class = EV_JOB_CLASS (class);
1046 oclass->dispose = ev_job_save_dispose;
1047 job_class->run = ev_job_save_run;
1051 ev_job_save_new (EvDocument *document,
1053 const gchar *document_uri)
1057 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
1059 job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
1061 EV_JOB (job)->document = g_object_ref (document);
1062 job->uri = g_strdup (uri);
1063 job->document_uri = g_strdup (document_uri);
1065 return EV_JOB (job);
1070 ev_job_print_init (EvJobPrint *job)
1072 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
1076 ev_job_print_dispose (GObject *object)
1080 job = EV_JOB_PRINT (object);
1082 ev_debug_message (DEBUG_JOBS, NULL);
1084 if (job->temp_file) {
1085 g_unlink (job->temp_file);
1086 g_free (job->temp_file);
1087 job->temp_file = NULL;
1091 g_free (job->ranges);
1096 (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
1100 ev_print_job_get_first_page (EvJobPrint *job)
1103 gint first_page = G_MAXINT;
1105 if (job->n_ranges == 0)
1108 for (i = 0; i < job->n_ranges; i++) {
1109 if (job->ranges[i].start < first_page)
1110 first_page = job->ranges[i].start;
1113 return MAX (0, first_page);
1117 ev_print_job_get_last_page (EvJobPrint *job)
1120 gint last_page = G_MININT;
1123 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1125 if (job->n_ranges == 0)
1128 for (i = 0; i < job->n_ranges; i++) {
1129 if (job->ranges[i].end > last_page)
1130 last_page = job->ranges[i].end;
1133 return MIN (max_page, last_page);
1137 ev_print_job_print_page_in_set (EvJobPrint *job,
1140 switch (job->page_set) {
1141 case EV_PRINT_PAGE_SET_EVEN:
1142 return page % 2 == 0;
1143 case EV_PRINT_PAGE_SET_ODD:
1144 return page % 2 != 0;
1145 case EV_PRINT_PAGE_SET_ALL:
1153 ev_job_print_get_page_list (EvJobPrint *job,
1156 gint i, j, page, max_page;
1160 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1162 for (i = 0; i < job->n_ranges; i++) {
1166 if (job->ranges[i].start == -1)
1167 job->ranges[i].start = 0;
1168 if (job->ranges[i].end == -1)
1169 job->ranges[i].end = max_page;
1171 if (job->ranges[i].start > max_page)
1174 start = job->ranges[i].start + 1;
1175 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
1176 rsize = end - start + 1;
1178 switch (job->page_set) {
1179 case EV_PRINT_PAGE_SET_EVEN:
1180 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1182 case EV_PRINT_PAGE_SET_ODD:
1183 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1196 page_list = g_new (gint, pages);
1199 for (i = 0; i < job->n_ranges; i++) {
1200 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
1204 if (ev_print_job_print_page_in_set (job, j + 1))
1205 page_list[page++] = j;
1213 ev_job_print_run (EvJob *job)
1215 EvDocument *document = EV_JOB (job)->document;
1216 EvJobPrint *job_print = EV_JOB_PRINT (job);
1217 EvFileExporterContext fc;
1218 EvRenderContext *rc;
1226 GError *error = NULL;
1228 ev_debug_message (DEBUG_JOBS, NULL);
1229 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1231 if (job_print->temp_file)
1232 g_free (job_print->temp_file);
1233 job_print->temp_file = NULL;
1235 filename = g_strdup_printf ("evince_print.%s.XXXXXX", job_print->format);
1236 fd = g_file_open_tmp (filename, &job_print->temp_file, &error);
1239 ev_job_failed_from_error (job, error);
1240 g_error_free (error);
1245 page_list = ev_job_print_get_page_list (job_print, &n_pages);
1249 ev_job_succeeded (job);
1254 first_page = ev_print_job_get_first_page (job_print);
1255 last_page = ev_print_job_get_last_page (job_print);
1257 fc.format = g_ascii_strcasecmp (job_print->format, "pdf") == 0 ?
1258 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
1259 fc.filename = job_print->temp_file;
1260 fc.first_page = MIN (first_page, last_page);
1261 fc.last_page = MAX (first_page, last_page);
1262 fc.paper_width = job_print->width;
1263 fc.paper_height = job_print->height;
1265 fc.pages_per_sheet = MAX (1, job_print->pages_per_sheet);
1267 rc = ev_render_context_new (NULL, 0, 1.0);
1269 ev_document_doc_mutex_lock ();
1270 ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
1272 for (i = 0; i < job_print->copies; i++) {
1276 step = job_print->reverse ? -1 * job_print->pages_per_sheet : job_print->pages_per_sheet;
1277 page = job_print->reverse ? ((n_pages - 1) / job_print->pages_per_sheet) * job_print->pages_per_sheet : 0;
1278 n_copies = job_print->collate ? 1 : job_print->copies;
1280 while ((job_print->reverse && (page >= 0)) || (!job_print->reverse && (page < n_pages))) {
1283 for (k = 0; k < n_copies; k++) {
1284 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
1286 for (j = 0; j < job_print->pages_per_sheet; j++) {
1291 if (p < 0 || p >= n_pages)
1294 ev_page = ev_document_get_page (document, page_list[p]);
1295 ev_render_context_set_page (rc, ev_page);
1296 g_object_unref (ev_page);
1298 ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
1301 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
1307 if (!job_print->collate)
1311 ev_file_exporter_end (EV_FILE_EXPORTER (document));
1312 ev_document_doc_mutex_unlock ();
1316 g_object_unref (rc);
1318 ev_job_succeeded (job);
1324 ev_job_print_class_init (EvJobPrintClass *class)
1326 GObjectClass *oclass = G_OBJECT_CLASS (class);
1327 EvJobClass *job_class = EV_JOB_CLASS (class);
1329 oclass->dispose = ev_job_print_dispose;
1330 job_class->run = ev_job_print_run;
1334 ev_job_print_new (EvDocument *document,
1335 const gchar *format,
1338 EvPrintRange *ranges,
1340 EvPrintPageSet page_set,
1341 gint pages_per_sheet,
1348 ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
1349 "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
1350 "collate: %s, reverse: %s",
1351 format, width, height, n_ranges, pages_per_sheet, copies,
1352 collate ? "True" : "False", reverse ? "True" : "False");
1354 job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1356 EV_JOB (job)->document = g_object_ref (document);
1358 job->format = format;
1360 job->temp_file = NULL;
1363 job->height = height;
1365 job->ranges = ranges;
1366 job->n_ranges = n_ranges;
1368 job->page_set = page_set;
1370 job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
1372 job->copies = copies;
1373 job->collate = collate;
1374 job->reverse = reverse;
1376 return EV_JOB (job);
1381 ev_job_find_init (EvJobFind *job)
1383 EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
1387 ev_job_find_dispose (GObject *object)
1389 EvJobFind *job = EV_JOB_FIND (object);
1391 ev_debug_message (DEBUG_JOBS, NULL);
1401 for (i = 0; i < job->n_pages; i++) {
1402 g_list_foreach (job->pages[i], (GFunc)g_free, NULL);
1403 g_list_free (job->pages[i]);
1406 g_free (job->pages);
1410 (* G_OBJECT_CLASS (ev_job_find_parent_class)->dispose) (object);
1414 ev_job_find_run (EvJob *job)
1416 EvJobFind *job_find = EV_JOB_FIND (job);
1417 EvDocumentFind *find = EV_DOCUMENT_FIND (job->document);
1421 ev_debug_message (DEBUG_JOBS, NULL);
1423 /* Do not block the main loop */
1424 if (!ev_document_doc_mutex_trylock ())
1427 #ifdef EV_ENABLE_DEBUG
1428 /* We use the #ifdef in this case because of the if */
1429 if (job_find->current_page == job_find->start_page)
1430 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1433 ev_page = ev_document_get_page (job->document, job_find->current_page);
1434 matches = ev_document_find_find_text (find, ev_page, job_find->text,
1435 job_find->case_sensitive);
1436 g_object_unref (ev_page);
1438 ev_document_doc_mutex_unlock ();
1440 if (!job_find->has_results)
1441 job_find->has_results = (matches != NULL);
1443 job_find->pages[job_find->current_page] = matches;
1444 g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page);
1446 job_find->current_page = (job_find->current_page + 1) % job_find->n_pages;
1447 if (job_find->current_page == job_find->start_page) {
1448 ev_job_succeeded (job);
1457 ev_job_find_class_init (EvJobFindClass *class)
1459 EvJobClass *job_class = EV_JOB_CLASS (class);
1460 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1462 job_class->run = ev_job_find_run;
1463 gobject_class->dispose = ev_job_find_dispose;
1465 job_find_signals[FIND_UPDATED] =
1466 g_signal_new ("updated",
1469 G_STRUCT_OFFSET (EvJobFindClass, updated),
1471 g_cclosure_marshal_VOID__INT,
1477 ev_job_find_new (EvDocument *document,
1481 gboolean case_sensitive)
1485 ev_debug_message (DEBUG_JOBS, NULL);
1487 job = g_object_new (EV_TYPE_JOB_FIND, NULL);
1489 EV_JOB (job)->document = g_object_ref (document);
1490 job->start_page = start_page;
1491 job->current_page = start_page;
1492 job->n_pages = n_pages;
1493 job->pages = g_new0 (GList *, n_pages);
1494 job->text = g_strdup (text);
1495 job->case_sensitive = case_sensitive;
1496 job->has_results = FALSE;
1498 return EV_JOB (job);
1502 ev_job_find_get_n_results (EvJobFind *job,
1505 return g_list_length (job->pages[page]);
1509 ev_job_find_get_progress (EvJobFind *job)
1513 if (ev_job_is_finished (EV_JOB (job)))
1516 if (job->current_page > job->start_page) {
1517 pages_done = job->current_page - job->start_page + 1;
1518 } else if (job->current_page == job->start_page) {
1519 pages_done = job->n_pages;
1521 pages_done = job->n_pages - job->start_page + job->current_page;
1524 return pages_done / (gdouble) job->n_pages;
1528 ev_job_find_has_results (EvJobFind *job)
1530 return job->has_results;
1534 ev_job_find_get_results (EvJobFind *job)