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-async-renderer.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_object_unref (job->dest);
724 if (job->search_string) {
725 g_free (job->search_string);
726 job->search_string = NULL;
729 (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
733 ev_job_load_run (EvJob *job)
735 EvJobLoad *job_load = EV_JOB_LOAD (job);
736 GError *error = NULL;
738 ev_debug_message (DEBUG_JOBS, "%s", job_load->uri);
739 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
741 ev_document_fc_mutex_lock ();
743 /* TODO: reuse the job!!! */
744 /* This job may already have a document even if the job didn't complete
745 because, e.g., a password is required - if so, just reload rather than
746 creating a new instance */
748 ev_document_load (job->document,
752 job->document = ev_document_factory_get_document (job_load->uri,
756 ev_document_fc_mutex_unlock ();
759 ev_job_failed_from_error (job, error);
760 g_error_free (error);
762 ev_job_succeeded (job);
769 ev_job_load_class_init (EvJobLoadClass *class)
771 GObjectClass *oclass = G_OBJECT_CLASS (class);
772 EvJobClass *job_class = EV_JOB_CLASS (class);
774 oclass->dispose = ev_job_load_dispose;
775 job_class->run = ev_job_load_run;
779 ev_job_load_new (const gchar *uri,
781 EvWindowRunMode mode,
782 const gchar *search_string)
786 ev_debug_message (DEBUG_JOBS, "%s", uri);
788 job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
790 job->uri = g_strdup (uri);
791 job->dest = dest ? g_object_ref (dest) : NULL;
793 job->search_string = search_string ? g_strdup (search_string) : NULL;
799 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
801 ev_debug_message (DEBUG_JOBS, "%s", uri);
805 job->uri = g_strdup (uri);
810 ev_job_save_init (EvJobSave *job)
812 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
816 ev_job_save_dispose (GObject *object)
818 EvJobSave *job = EV_JOB_SAVE (object);
820 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
827 if (job->document_uri) {
828 g_free (job->document_uri);
829 job->document_uri = NULL;
832 (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
836 ev_job_save_run (EvJob *job)
838 EvJobSave *job_save = EV_JOB_SAVE (job);
843 GError *error = NULL;
845 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri);
846 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
848 filename = ev_tmp_filename ("saveacopy");
849 tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
852 fd = g_mkstemp (tmp_filename);
855 gint save_errno = errno;
857 display_name = g_filename_display_name (tmp_filename);
860 g_file_error_from_errno (save_errno),
861 _("Failed to create file “%s”: %s"),
862 display_name, g_strerror (save_errno));
863 g_free (display_name);
864 g_free (tmp_filename);
869 ev_document_doc_mutex_lock ();
871 /* Save document to temp filename */
872 local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
873 ev_document_save (job->document, local_uri, &error);
876 ev_document_doc_mutex_unlock ();
880 ev_job_failed_from_error (job, error);
881 g_error_free (error);
886 /* If original document was compressed,
887 * compress it again before saving
889 if (g_object_get_data (G_OBJECT (job->document), "uri-uncompressed")) {
890 EvCompressionType ctype = EV_COMPRESSION_NONE;
894 ext = g_strrstr (job_save->document_uri, ".gz");
895 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
896 ctype = EV_COMPRESSION_GZIP;
898 ext = g_strrstr (job_save->document_uri, ".bz2");
899 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
900 ctype = EV_COMPRESSION_BZIP2;
902 uri_comp = ev_file_compress (local_uri, ctype, &error);
904 ev_tmp_filename_unlink (tmp_filename);
906 if (!uri_comp || error) {
909 local_uri = uri_comp;
913 g_free (tmp_filename);
917 ev_job_failed_from_error (job, error);
918 g_error_free (error);
926 ev_xfer_uri_simple (local_uri, job_save->uri, &error);
927 ev_tmp_uri_unlink (local_uri);
930 ev_job_failed_from_error (job, error);
931 g_error_free (error);
933 ev_job_succeeded (job);
940 ev_job_save_class_init (EvJobSaveClass *class)
942 GObjectClass *oclass = G_OBJECT_CLASS (class);
943 EvJobClass *job_class = EV_JOB_CLASS (class);
945 oclass->dispose = ev_job_save_dispose;
946 job_class->run = ev_job_save_run;
950 ev_job_save_new (EvDocument *document,
952 const gchar *document_uri)
956 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
958 job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
960 EV_JOB (job)->document = g_object_ref (document);
961 job->uri = g_strdup (uri);
962 job->document_uri = g_strdup (document_uri);
969 ev_job_print_init (EvJobPrint *job)
971 EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD;
975 ev_job_print_dispose (GObject *object)
979 job = EV_JOB_PRINT (object);
981 ev_debug_message (DEBUG_JOBS, NULL);
983 if (job->temp_file) {
984 g_unlink (job->temp_file);
985 g_free (job->temp_file);
986 job->temp_file = NULL;
990 g_free (job->ranges);
995 (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
999 ev_print_job_get_first_page (EvJobPrint *job)
1002 gint first_page = G_MAXINT;
1004 if (job->n_ranges == 0)
1007 for (i = 0; i < job->n_ranges; i++) {
1008 if (job->ranges[i].start < first_page)
1009 first_page = job->ranges[i].start;
1012 return MAX (0, first_page);
1016 ev_print_job_get_last_page (EvJobPrint *job)
1019 gint last_page = G_MININT;
1022 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1024 if (job->n_ranges == 0)
1027 for (i = 0; i < job->n_ranges; i++) {
1028 if (job->ranges[i].end > last_page)
1029 last_page = job->ranges[i].end;
1032 return MIN (max_page, last_page);
1036 ev_print_job_print_page_in_set (EvJobPrint *job,
1039 switch (job->page_set) {
1040 case EV_PRINT_PAGE_SET_EVEN:
1041 return page % 2 == 0;
1042 case EV_PRINT_PAGE_SET_ODD:
1043 return page % 2 != 0;
1044 case EV_PRINT_PAGE_SET_ALL:
1052 ev_job_print_get_page_list (EvJobPrint *job,
1055 gint i, j, page, max_page;
1059 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
1061 for (i = 0; i < job->n_ranges; i++) {
1065 if (job->ranges[i].start == -1)
1066 job->ranges[i].start = 0;
1067 if (job->ranges[i].end == -1)
1068 job->ranges[i].end = max_page;
1070 if (job->ranges[i].start > max_page)
1073 start = job->ranges[i].start + 1;
1074 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
1075 rsize = end - start + 1;
1077 switch (job->page_set) {
1078 case EV_PRINT_PAGE_SET_EVEN:
1079 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1081 case EV_PRINT_PAGE_SET_ODD:
1082 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
1095 page_list = g_new (gint, pages);
1098 for (i = 0; i < job->n_ranges; i++) {
1099 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
1103 if (ev_print_job_print_page_in_set (job, j + 1))
1104 page_list[page++] = j;
1112 ev_job_print_run (EvJob *job)
1114 EvDocument *document = EV_JOB (job)->document;
1115 EvJobPrint *job_print = EV_JOB_PRINT (job);
1116 EvFileExporterContext fc;
1117 EvRenderContext *rc;
1125 GError *error = NULL;
1127 ev_debug_message (DEBUG_JOBS, NULL);
1128 ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job);
1130 if (job_print->temp_file)
1131 g_free (job_print->temp_file);
1132 job_print->temp_file = NULL;
1134 filename = g_strdup_printf ("evince_print.%s.XXXXXX", job_print->format);
1135 fd = g_file_open_tmp (filename, &job_print->temp_file, &error);
1138 ev_job_failed_from_error (job, error);
1139 g_error_free (error);
1144 page_list = ev_job_print_get_page_list (job_print, &n_pages);
1148 ev_job_succeeded (job);
1153 first_page = ev_print_job_get_first_page (job_print);
1154 last_page = ev_print_job_get_last_page (job_print);
1156 fc.format = g_ascii_strcasecmp (job_print->format, "pdf") == 0 ?
1157 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
1158 fc.filename = job_print->temp_file;
1159 fc.first_page = MIN (first_page, last_page);
1160 fc.last_page = MAX (first_page, last_page);
1161 fc.paper_width = job_print->width;
1162 fc.paper_height = job_print->height;
1164 fc.pages_per_sheet = MAX (1, job_print->pages_per_sheet);
1166 rc = ev_render_context_new (NULL, 0, 1.0);
1168 ev_document_doc_mutex_lock ();
1169 ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
1171 for (i = 0; i < job_print->copies; i++) {
1175 step = job_print->reverse ? -1 * job_print->pages_per_sheet : job_print->pages_per_sheet;
1176 page = job_print->reverse ? ((n_pages - 1) / job_print->pages_per_sheet) * job_print->pages_per_sheet : 0;
1177 n_copies = job_print->collate ? 1 : job_print->copies;
1179 while ((job_print->reverse && (page >= 0)) || (!job_print->reverse && (page < n_pages))) {
1182 for (k = 0; k < n_copies; k++) {
1183 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
1185 for (j = 0; j < job_print->pages_per_sheet; j++) {
1190 if (p < 0 || p >= n_pages)
1193 ev_page = ev_document_get_page (document, page_list[p]);
1194 ev_render_context_set_page (rc, ev_page);
1195 g_object_unref (ev_page);
1197 ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
1200 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
1206 if (!job_print->collate)
1210 ev_file_exporter_end (EV_FILE_EXPORTER (document));
1211 ev_document_doc_mutex_unlock ();
1215 g_object_unref (rc);
1217 ev_job_succeeded (job);
1223 ev_job_print_class_init (EvJobPrintClass *class)
1225 GObjectClass *oclass = G_OBJECT_CLASS (class);
1226 EvJobClass *job_class = EV_JOB_CLASS (class);
1228 oclass->dispose = ev_job_print_dispose;
1229 job_class->run = ev_job_print_run;
1233 ev_job_print_new (EvDocument *document,
1234 const gchar *format,
1237 EvPrintRange *ranges,
1239 EvPrintPageSet page_set,
1240 gint pages_per_sheet,
1247 ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
1248 "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
1249 "collate: %s, reverse: %s",
1250 format, width, height, n_ranges, pages_per_sheet, copies,
1251 collate ? "True" : "False", reverse ? "True" : "False");
1253 job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
1255 EV_JOB (job)->document = g_object_ref (document);
1257 job->format = format;
1259 job->temp_file = NULL;
1262 job->height = height;
1264 job->ranges = ranges;
1265 job->n_ranges = n_ranges;
1267 job->page_set = page_set;
1269 job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
1271 job->copies = copies;
1272 job->collate = collate;
1273 job->reverse = reverse;
1275 return EV_JOB (job);