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"
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
41 static void ev_job_init (EvJob *job);
42 static void ev_job_class_init (EvJobClass *class);
43 static void ev_job_links_init (EvJobLinks *job);
44 static void ev_job_links_class_init (EvJobLinksClass *class);
45 static void ev_job_render_init (EvJobRender *job);
46 static void ev_job_render_class_init (EvJobRenderClass *class);
47 static void ev_job_thumbnail_init (EvJobThumbnail *job);
48 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
49 static void ev_job_load_init (EvJobLoad *job);
50 static void ev_job_load_class_init (EvJobLoadClass *class);
51 static void ev_job_save_init (EvJobSave *job);
52 static void ev_job_save_class_init (EvJobSaveClass *class);
53 static void ev_job_print_init (EvJobPrint *job);
54 static void ev_job_print_class_init (EvJobPrintClass *class);
72 static guint job_signals[LAST_SIGNAL] = { 0 };
73 static guint job_render_signals[RENDER_LAST_SIGNAL] = { 0 };
74 static guint job_fonts_signals[FONTS_LAST_SIGNAL] = { 0 };
76 G_DEFINE_ABSTRACT_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
77 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
78 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
79 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
80 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
81 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
82 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
83 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
87 ev_job_init (EvJob *job)
89 job->cancellable = g_cancellable_new ();
93 ev_job_dispose (GObject *object)
97 job = EV_JOB (object);
100 g_object_unref (job->document);
101 job->document = NULL;
104 if (job->cancellable) {
105 g_object_unref (job->cancellable);
106 job->cancellable = NULL;
110 g_error_free (job->error);
114 (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
118 ev_job_class_init (EvJobClass *class)
120 GObjectClass *oclass;
122 oclass = G_OBJECT_CLASS (class);
124 oclass->dispose = ev_job_dispose;
126 job_signals[CANCELLED] =
127 g_signal_new ("cancelled",
130 G_STRUCT_OFFSET (EvJobClass, cancelled),
132 g_cclosure_marshal_VOID__VOID,
134 job_signals [FINISHED] =
135 g_signal_new ("finished",
138 G_STRUCT_OFFSET (EvJobClass, finished),
140 g_cclosure_marshal_VOID__VOID,
145 emit_finished (EvJob *job)
147 ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
149 job->idle_finished_id = 0;
151 if (job->cancelled) {
152 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit finished", EV_GET_TYPE_NAME (job), job);
154 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
155 g_signal_emit (job, job_signals[FINISHED], 0);
162 ev_job_emit_finished (EvJob *job)
164 ev_debug_message (DEBUG_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
166 if (g_cancellable_is_cancelled (job->cancellable)) {
167 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, returning", EV_GET_TYPE_NAME (job), job);
171 job->finished = TRUE;
173 if (job->run_mode == EV_JOB_RUN_THREAD) {
174 job->idle_finished_id =
175 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
176 (GSourceFunc)emit_finished,
178 (GDestroyNotify)g_object_unref);
180 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
181 g_signal_emit (job, job_signals[FINISHED], 0);
186 ev_job_run (EvJob *job)
188 EvJobClass *class = EV_JOB_GET_CLASS (job);
190 return class->run (job);
194 ev_job_cancel (EvJob *job)
196 if (job->cancelled || (job->finished && job->idle_finished_id == 0))
199 ev_debug_message (DEBUG_JOBS, "job %s (%p) cancelled", EV_GET_TYPE_NAME (job), job);
200 ev_profiler_stop (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
202 /* This should never be called from a thread */
203 job->cancelled = TRUE;
204 g_cancellable_cancel (job->cancellable);
205 g_signal_emit (job, job_signals[CANCELLED], 0);
209 ev_job_failed (EvJob *job,
218 if (job->failed || job->finished)
221 ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
225 va_start (args, format);
226 message = g_strdup_vprintf (format, args);
229 job->error = g_error_new (domain, code, message);
232 ev_job_emit_finished (job);
236 ev_job_failed_from_error (EvJob *job,
239 if (job->failed || job->finished)
242 ev_debug_message (DEBUG_JOBS, "job %s (%p) failed", EV_GET_TYPE_NAME (job), job);
245 job->error = g_error_copy (error);
247 ev_job_emit_finished (job);
251 ev_job_succeeded (EvJob *job)
256 ev_debug_message (DEBUG_JOBS, "job %s (%p) succeeded", EV_GET_TYPE_NAME (job), job);
259 ev_job_emit_finished (job);
263 ev_job_is_finished (EvJob *job)
265 return job->finished;
269 ev_job_is_failed (EvJob *job)
275 ev_job_get_run_mode (EvJob *job)
277 return job->run_mode;
281 ev_job_set_run_mode (EvJob *job,
282 EvJobRunMode run_mode)
284 job->run_mode = run_mode;
289 ev_job_links_init (EvJobLinks *job)
291 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
295 ev_job_links_dispose (GObject *object)
299 ev_debug_message (DEBUG_JOBS, NULL);
301 job = EV_JOB_LINKS (object);
304 g_object_unref (job->model);
308 (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
312 ev_job_links_run (EvJob *job)
314 EvJobLinks *job_links = EV_JOB_LINKS (job);
316 ev_debug_message (DEBUG_JOBS, NULL);
317 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
319 ev_document_doc_mutex_lock ();
320 job_links->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (job->document));
321 ev_document_doc_mutex_unlock ();
323 ev_job_succeeded (job);
329 ev_job_links_class_init (EvJobLinksClass *class)
331 GObjectClass *oclass = G_OBJECT_CLASS (class);
332 EvJobClass *job_class = EV_JOB_CLASS (class);
334 oclass->dispose = ev_job_links_dispose;
335 job_class->run = ev_job_links_run;
339 ev_job_links_new (EvDocument *document)
343 ev_debug_message (DEBUG_JOBS, NULL);
345 job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
346 job->document = g_object_ref (document);
353 ev_job_render_init (EvJobRender *job)
355 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
359 ev_job_render_dispose (GObject *object)
363 job = EV_JOB_RENDER (object);
366 ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->ev_page->index, job);
367 g_object_unref (job->ev_page);
372 cairo_surface_destroy (job->surface);
376 if (job->selection) {
377 cairo_surface_destroy (job->selection);
378 job->selection = NULL;
381 if (job->selection_region) {
382 gdk_region_destroy (job->selection_region);
383 job->selection_region = NULL;
386 (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
390 notify_page_ready (EvJobRender *job)
392 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job);
393 ev_profiler_stop (EV_PROFILE_JOBS, "Rendering page %d", job->ev_page->index);
395 if (EV_JOB (job)->cancelled) {
396 ev_debug_message (DEBUG_JOBS, "%s (%p) job was cancelled, do not emit page_ready", EV_GET_TYPE_NAME (job), job);
398 g_signal_emit (job, job_render_signals[PAGE_READY], 0);
405 ev_job_render_page_ready (EvJobRender *job)
407 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->ev_page->index, job);
409 job->page_ready = TRUE;
410 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
411 (GSourceFunc)notify_page_ready,
413 (GDestroyNotify)g_object_unref);
417 ev_job_render_run (EvJob *job)
419 EvJobRender *job_render = EV_JOB_RENDER (job);
422 ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job);
423 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
425 ev_document_doc_mutex_lock ();
427 ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page);
429 ev_document_fc_mutex_lock ();
431 job_render->ev_page = ev_document_get_page (job->document, job_render->page);
432 rc = ev_render_context_new (job_render->ev_page, job_render->rotation, job_render->scale);
434 job_render->surface = ev_document_render (job->document, rc);
435 /* If job was cancelled during the page rendering,
436 * we return now, so that the thread is finished ASAP
438 if (g_cancellable_is_cancelled (job->cancellable)) {
439 ev_document_fc_mutex_unlock ();
440 ev_document_doc_mutex_unlock ();
446 if ((job_render->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (job->document)) {
447 ev_selection_render_selection (EV_SELECTION (job->document),
449 &(job_render->selection),
450 &(job_render->selection_points),
452 job_render->selection_style,
453 &(job_render->text), &(job_render->base));
454 job_render->selection_region =
455 ev_selection_get_selection_region (EV_SELECTION (job->document),
457 job_render->selection_style,
458 &(job_render->selection_points));
461 ev_job_render_page_ready (job_render);
463 ev_document_fc_mutex_unlock ();
465 if ((job_render->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (job->document))
466 job_render->text_mapping =
467 ev_selection_get_selection_map (EV_SELECTION (job->document), rc);
468 if ((job_render->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (job->document))
469 job_render->link_mapping =
470 ev_document_links_get_links (EV_DOCUMENT_LINKS (job->document), job_render->page);
471 if ((job_render->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (job->document))
472 job_render->form_field_mapping =
473 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (job->document),
474 job_render->ev_page);
475 if ((job_render->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (job->document))
476 job_render->image_mapping =
477 ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (job->document),
480 ev_document_doc_mutex_unlock ();
482 ev_job_succeeded (job);
488 ev_job_render_class_init (EvJobRenderClass *class)
490 GObjectClass *oclass = G_OBJECT_CLASS (class);
491 EvJobClass *job_class = EV_JOB_CLASS (class);
493 job_render_signals [PAGE_READY] =
494 g_signal_new ("page-ready",
497 G_STRUCT_OFFSET (EvJobRenderClass, page_ready),
499 g_cclosure_marshal_VOID__VOID,
502 oclass->dispose = ev_job_render_dispose;
503 job_class->run = ev_job_render_run;
507 ev_job_render_new (EvDocument *document,
517 ev_debug_message (DEBUG_JOBS, "page: %d", page);
519 job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
521 EV_JOB (job)->document = g_object_ref (document);
523 job->rotation = rotation;
525 job->target_width = width;
526 job->target_height = height;
533 ev_job_render_set_selection_info (EvJobRender *job,
534 EvRectangle *selection_points,
535 EvSelectionStyle selection_style,
539 job->flags |= EV_RENDER_INCLUDE_SELECTION;
541 job->selection_points = *selection_points;
542 job->selection_style = selection_style;
549 ev_job_thumbnail_init (EvJobThumbnail *job)
551 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
555 ev_job_thumbnail_dispose (GObject *object)
559 job = EV_JOB_THUMBNAIL (object);
561 ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job);
563 if (job->thumbnail) {
564 g_object_unref (job->thumbnail);
565 job->thumbnail = NULL;
568 (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
572 ev_job_thumbnail_run (EvJob *job)
574 EvJobThumbnail *job_thumb = EV_JOB_THUMBNAIL (job);
578 ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job);
579 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
581 ev_document_doc_mutex_lock ();
583 page = ev_document_get_page (job->document, job_thumb->page);
584 rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale);
585 g_object_unref (page);
587 job_thumb->thumbnail = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (job->document),
590 ev_document_doc_mutex_unlock ();
592 ev_job_succeeded (job);
598 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
600 GObjectClass *oclass = G_OBJECT_CLASS (class);
601 EvJobClass *job_class = EV_JOB_CLASS (class);
603 oclass->dispose = ev_job_thumbnail_dispose;
604 job_class->run = ev_job_thumbnail_run;
608 ev_job_thumbnail_new (EvDocument *document,
615 ev_debug_message (DEBUG_JOBS, "%d", page);
617 job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
619 EV_JOB (job)->document = g_object_ref (document);
621 job->rotation = rotation;
629 ev_job_fonts_init (EvJobFonts *job)
631 EV_JOB (job)->run_mode = EV_JOB_RUN_MAIN_LOOP;
635 ev_job_fonts_run (EvJob *job)
637 EvJobFonts *job_fonts = EV_JOB_FONTS (job);
638 EvDocumentFonts *fonts = EV_DOCUMENT_FONTS (job->document);
640 ev_debug_message (DEBUG_JOBS, NULL);
642 /* Do not block the main loop */
643 if (!ev_document_doc_mutex_trylock ())
646 if (!ev_document_fc_mutex_trylock ())
649 #ifdef EV_ENABLE_DEBUG
650 /* We use the #ifdef in this case because of the if */
651 if (ev_document_fonts_get_progress (fonts) == 0)
652 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
655 job_fonts->scan_completed = !ev_document_fonts_scan (fonts, 20);
656 g_signal_emit (job_fonts, job_fonts_signals[UPDATED], 0,
657 ev_document_fonts_get_progress (fonts));
659 ev_document_fc_mutex_unlock ();
660 ev_document_doc_mutex_unlock ();
662 if (job_fonts->scan_completed)
663 ev_job_succeeded (job);
665 return !job_fonts->scan_completed;
669 ev_job_fonts_class_init (EvJobFontsClass *class)
671 EvJobClass *job_class = EV_JOB_CLASS (class);
673 job_class->run = ev_job_fonts_run;
675 job_fonts_signals[UPDATED] =
676 g_signal_new ("updated",
679 G_STRUCT_OFFSET (EvJobFontsClass, updated),
681 g_cclosure_marshal_VOID__DOUBLE,
687 ev_job_fonts_new (EvDocument *document)
691 ev_debug_message (DEBUG_JOBS, NULL);
693 job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
695 EV_JOB (job)->document = g_object_ref (document);
702 ev_job_load_init (EvJobLoad *job)
704 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
708 ev_job_load_dispose (GObject *object)
710 EvJobLoad *job = EV_JOB_LOAD (object);
712 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
720 g_free (job->password);
721 job->password = NULL;
725 g_object_unref (job->dest);
729 if (job->search_string) {
730 g_free (job->search_string);
731 job->search_string = NULL;
734 (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
738 ev_job_load_run (EvJob *job)
740 EvJobLoad *job_load = EV_JOB_LOAD (job);
741 GError *error = NULL;
743 ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
744 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
746 ev_document_fc_mutex_lock ();
748 /* This job may already have a document even if the job didn't complete
749 because, e.g., a password is required - if so, just reload rather than
750 creating a new instance */
752 if (job_load->password) {
753 ev_document_security_set_password (EV_DOCUMENT_SECURITY (job->document),
758 job->finished = FALSE;
759 g_clear_error (&job->error);
761 ev_document_load (job->document,
765 job->document = ev_document_factory_get_document (job_load->uri,
769 ev_document_fc_mutex_unlock ();
772 ev_job_failed_from_error (job, error);
773 g_error_free (error);
775 ev_job_succeeded (job);
782 ev_job_load_class_init (EvJobLoadClass *class)
784 GObjectClass *oclass = G_OBJECT_CLASS (class);
785 EvJobClass *job_class = EV_JOB_CLASS (class);
787 oclass->dispose = ev_job_load_dispose;
788 job_class->run = ev_job_load_run;
792 ev_job_load_new (const gchar *uri,
794 EvWindowRunMode mode,
795 const gchar *search_string)
799 ev_debug_message (DEBUG_JOBS, "%s", uri);
801 job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
803 job->uri = g_strdup (uri);
804 job->dest = dest ? g_object_ref (dest) : NULL;
806 job->search_string = search_string ? g_strdup (search_string) : NULL;
812 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
814 ev_debug_message (DEBUG_JOBS, "%s", uri);
818 job->uri = g_strdup (uri);
822 ev_job_load_set_password (EvJobLoad *job, const gchar *password)
824 ev_debug_message (DEBUG_JOBS, NULL);
827 g_free (job->password);
828 job->password = password ? g_strdup (password) : NULL;
833 ev_job_save_init (EvJobSave *job)
835 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
839 ev_job_save_dispose (GObject *object)
841 EvJobSave *job = EV_JOB_SAVE (object);
843 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
850 if (job->document_uri) {
851 g_free (job->document_uri);
852 job->document_uri = NULL;
855 (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
859 ev_job_save_run (EvJob *job)
861 EvJobSave *job_save = EV_JOB_SAVE (job);
866 GError *error = NULL;
868 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
869 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
871 filename = ev_tmp_filename ("saveacopy");
872 tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
875 fd = g_mkstemp (tmp_filename);
878 gint save_errno = errno;
880 display_name = g_filename_display_name (tmp_filename);
883 g_file_error_from_errno (save_errno),
884 _("Failed to create file “%s”: %s"),
885 display_name, g_strerror (save_errno));
886 g_free (display_name);
887 g_free (tmp_filename);
892 ev_document_doc_mutex_lock ();
894 /* Save document to temp filename */
895 local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
896 ev_document_save (job->document, local_uri, &error);
899 ev_document_doc_mutex_unlock ();
903 ev_job_failed_from_error (job, error);
904 g_error_free (error);
909 /* If original document was compressed,
910 * compress it again before saving
912 if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
913 EvCompressionType ctype = EV_COMPRESSION_NONE;
917 ext = g_strrstr (job_save->document_uri, ".gz");
918 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
919 ctype = EV_COMPRESSION_GZIP;
921 ext = g_strrstr (job_save->document_uri, ".bz2");
922 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
923 ctype = EV_COMPRESSION_BZIP2;
925 uri_comp = ev_file_compress (local_uri, ctype, &error);
927 ev_tmp_filename_unlink (tmp_filename);
929 if (!uri_comp || error) {
932 local_uri = uri_comp;
936 g_free (tmp_filename);
940 ev_job_failed_from_error (job, error);
941 g_error_free (error);
949 ev_xfer_uri_simple (local_uri, job_save->uri, &error);
950 ev_tmp_uri_unlink (local_uri);
953 ev_job_failed_from_error (job, error);
954 g_error_free (error);
956 ev_job_succeeded (job);
963 ev_job_save_class_init (EvJobSaveClass *class)
965 GObjectClass *oclass = G_OBJECT_CLASS (class);
966 EvJobClass *job_class = EV_JOB_CLASS (class);
968 oclass->dispose = ev_job_save_dispose;
969 job_class->run = ev_job_save_run;
973 ev_job_save_new (EvDocument *document,
975 const gchar *document_uri)
979 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
981 job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
983 EV_JOB (job)->document = g_object_ref (document);
984 job->uri = g_strdup (uri);
985 job->document_uri = g_strdup (document_uri);
992 ev_job_print_init (EvJobPrint *job)
994 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
998 ev_job_print_dispose (GObject *object)
1002 job = EV_JOB_PRINT (object);
1004 ev_debug_message (DEBUG_JOBS, NULL);
1006 if (job->temp_file) {
1007 g_unlink (job->temp_file);
1008 g_free (job->temp_file);
1009 job->temp_file = NULL;
1013 g_free (job->ranges);
1018 (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
1022 ev_print_job_get_first_page (EvJobPrint *job)
1025 gint first_page = G_MAXINT;
1027 if (job->n_ranges == 0)
1030 for (i = 0; i < job->n_ranges; i++) {
1031 if (job->ranges[i].start < first_page)
1032 first_page = job->ranges[i].start;
1035 return MAX (0, first_page);
1039 ev_print_job_get_last_page (EvJobPrint *job)
1042 gint last_page = G_MININT;
1045 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1047 if (job->n_ranges == 0)
1050 for (i = 0; i < job->n_ranges; i++) {
1051 if (job->ranges[i].end > last_page)
1052 last_page = job->ranges[i].end;
1055 return MIN (max_page, last_page);
1059 ev_print_job_print_page_in_set (EvJobPrint *job,
1062 switch (job->page_set) {
1063 case EV_PRINT_PAGE_SET_EVEN:
1064 return page % 2 == 0;
1065 case EV_PRINT_PAGE_SET_ODD:
1066 return page % 2 != 0;
1067 case EV_PRINT_PAGE_SET_ALL:
1075 ev_job_print_get_page_list (EvJobPrint *job,
1078 gint i, j, page, max_page;
1082 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1084 for (i = 0; i < job->n_ranges; i++) {
1088 if (job->ranges[i].start == -1)
1089 job->ranges[i].start = 0;
1090 if (job->ranges[i].end == -1)
1091 job->ranges[i].end = max_page;
1093 if (job->ranges[i].start > max_page)
1096 start = job->ranges[i].start + 1;
1097 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
1098 rsize = end - start + 1;
1100 switch (job->page_set) {
1101 case EV_PRINT_PAGE_SET_EVEN:
1102 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1104 case EV_PRINT_PAGE_SET_ODD:
1105 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1118 page_list = g_new (gint, pages);
1121 for (i = 0; i < job->n_ranges; i++) {
1122 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
1126 if (ev_print_job_print_page_in_set (job, j + 1))
1127 page_list[page++] = j;
1135 ev_job_print_run (EvJob *job)
1137 EvDocument *document = EV_JOB (job)->document;
1138 EvJobPrint *job_print = EV_JOB_PRINT (job);
1139 EvFileExporterContext fc;
1140 EvRenderContext *rc;
1148 GError *error = NULL;
1150 ev_debug_message (DEBUG_JOBS, NULL);
1151 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1153 if (job_print->temp_file)
1154 g_free (job_print->temp_file);
1155 job_print->temp_file = NULL;
1157 filename = g_strdup_printf ("evince_print.%s.XXXXXX", job_print->format);
1158 fd = g_file_open_tmp (filename, &job_print->temp_file, &error);
1161 ev_job_failed_from_error (job, error);
1162 g_error_free (error);
1167 page_list = ev_job_print_get_page_list (job_print, &n_pages);
1171 ev_job_succeeded (job);
1176 first_page = ev_print_job_get_first_page (job_print);
1177 last_page = ev_print_job_get_last_page (job_print);
1179 fc.format = g_ascii_strcasecmp (job_print->format, "pdf") == 0 ?
1180 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
1181 fc.filename = job_print->temp_file;
1182 fc.first_page = MIN (first_page, last_page);
1183 fc.last_page = MAX (first_page, last_page);
1184 fc.paper_width = job_print->width;
1185 fc.paper_height = job_print->height;
1187 fc.pages_per_sheet = MAX (1, job_print->pages_per_sheet);
1189 rc = ev_render_context_new (NULL, 0, 1.0);
1191 ev_document_doc_mutex_lock ();
1192 ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
1194 for (i = 0; i < job_print->copies; i++) {
1198 step = job_print->reverse ? -1 * job_print->pages_per_sheet : job_print->pages_per_sheet;
1199 page = job_print->reverse ? ((n_pages - 1) / job_print->pages_per_sheet) * job_print->pages_per_sheet : 0;
1200 n_copies = job_print->collate ? 1 : job_print->copies;
1202 while ((job_print->reverse && (page >= 0)) || (!job_print->reverse && (page < n_pages))) {
1205 for (k = 0; k < n_copies; k++) {
1206 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
1208 for (j = 0; j < job_print->pages_per_sheet; j++) {
1213 if (p < 0 || p >= n_pages)
1216 ev_page = ev_document_get_page (document, page_list[p]);
1217 ev_render_context_set_page (rc, ev_page);
1218 g_object_unref (ev_page);
1220 ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
1223 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
1229 if (!job_print->collate)
1233 ev_file_exporter_end (EV_FILE_EXPORTER (document));
1234 ev_document_doc_mutex_unlock ();
1238 g_object_unref (rc);
1240 ev_job_succeeded (job);
1246 ev_job_print_class_init (EvJobPrintClass *class)
1248 GObjectClass *oclass = G_OBJECT_CLASS (class);
1249 EvJobClass *job_class = EV_JOB_CLASS (class);
1251 oclass->dispose = ev_job_print_dispose;
1252 job_class->run = ev_job_print_run;
1256 ev_job_print_new (EvDocument *document,
1257 const gchar *format,
1260 EvPrintRange *ranges,
1262 EvPrintPageSet page_set,
1263 gint pages_per_sheet,
1270 ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
1271 "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
1272 "collate: %s, reverse: %s",
1273 format, width, height, n_ranges, pages_per_sheet, copies,
1274 collate ? "True" : "False", reverse ? "True" : "False");
1276 job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1278 EV_JOB (job)->document = g_object_ref (document);
1280 job->format = format;
1282 job->temp_file = NULL;
1285 job->height = height;
1287 job->ranges = ranges;
1288 job->n_ranges = n_ranges;
1290 job->page_set = page_set;
1292 job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
1294 job->copies = copies;
1295 job->collate = collate;
1296 job->reverse = reverse;
1298 return EV_JOB (job);