3 #include "ev-job-queue.h"
4 #include "ev-document-thumbnails.h"
5 #include "ev-document-links.h"
6 #include "ev-document-images.h"
7 #include "ev-document-forms.h"
8 #include "ev-file-exporter.h"
9 #include "ev-document-factory.h"
10 #include "ev-document-misc.h"
11 #include "ev-file-helpers.h"
12 #include "ev-document-fonts.h"
13 #include "ev-async-renderer.h"
17 #include <glib/gstdio.h>
18 #include <glib/gi18n.h>
21 static void ev_job_init (EvJob *job);
22 static void ev_job_class_init (EvJobClass *class);
23 static void ev_job_links_init (EvJobLinks *job);
24 static void ev_job_links_class_init (EvJobLinksClass *class);
25 static void ev_job_render_init (EvJobRender *job);
26 static void ev_job_render_class_init (EvJobRenderClass *class);
27 static void ev_job_thumbnail_init (EvJobThumbnail *job);
28 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
29 static void ev_job_load_init (EvJobLoad *job);
30 static void ev_job_load_class_init (EvJobLoadClass *class);
31 static void ev_job_save_init (EvJobSave *job);
32 static void ev_job_save_class_init (EvJobSaveClass *class);
33 static void ev_job_print_init (EvJobPrint *job);
34 static void ev_job_print_class_init (EvJobPrintClass *class);
46 static guint job_signals[LAST_SIGNAL] = { 0 };
47 static guint job_render_signals[RENDER_LAST_SIGNAL] = { 0 };
49 G_DEFINE_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
50 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
51 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
52 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
53 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
54 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
55 G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
56 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
58 static void ev_job_init (EvJob *job) { /* Do Nothing */ }
61 ev_job_dispose (GObject *object)
65 job = EV_JOB (object);
68 g_object_unref (job->document);
72 (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
76 ev_job_class_init (EvJobClass *class)
80 oclass = G_OBJECT_CLASS (class);
82 oclass->dispose = ev_job_dispose;
84 job_signals [FINISHED] =
85 g_signal_new ("finished",
88 G_STRUCT_OFFSET (EvJobClass, finished),
90 g_cclosure_marshal_VOID__VOID,
95 static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ }
98 ev_job_links_dispose (GObject *object)
102 ev_debug_message (DEBUG_JOBS, NULL);
104 job = EV_JOB_LINKS (object);
107 g_object_unref (job->model);
111 (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
115 ev_job_links_class_init (EvJobLinksClass *class)
117 GObjectClass *oclass;
119 oclass = G_OBJECT_CLASS (class);
121 oclass->dispose = ev_job_links_dispose;
125 static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ }
128 ev_job_render_dispose (GObject *object)
132 job = EV_JOB_RENDER (object);
135 ev_debug_message (DEBUG_JOBS, "page: %d", job->ev_page->index);
136 g_object_unref (job->ev_page);
141 cairo_surface_destroy (job->surface);
145 if (job->selection) {
146 cairo_surface_destroy (job->selection);
147 job->selection = NULL;
150 if (job->selection_region) {
151 gdk_region_destroy (job->selection_region);
152 job->selection_region = NULL;
155 (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
159 ev_job_render_class_init (EvJobRenderClass *class)
161 GObjectClass *oclass;
163 oclass = G_OBJECT_CLASS (class);
165 job_render_signals [PAGE_READY] =
166 g_signal_new ("page-ready",
169 G_STRUCT_OFFSET (EvJobRenderClass, page_ready),
171 g_cclosure_marshal_VOID__VOID,
174 oclass->dispose = ev_job_render_dispose;
177 static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ }
180 ev_job_thumbnail_dispose (GObject *object)
184 job = EV_JOB_THUMBNAIL (object);
186 ev_debug_message (DEBUG_JOBS, "%d", job->page);
188 if (job->thumbnail) {
189 g_object_unref (job->thumbnail);
190 job->thumbnail = NULL;
193 (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
197 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
199 GObjectClass *oclass;
201 oclass = G_OBJECT_CLASS (class);
203 oclass->dispose = ev_job_thumbnail_dispose;
206 static void ev_job_print_init (EvJobPrint *job) { /* Do Nothing */ }
209 ev_job_print_dispose (GObject *object)
213 job = EV_JOB_PRINT (object);
215 ev_debug_message (DEBUG_JOBS, NULL);
217 if (job->temp_file) {
218 g_unlink (job->temp_file);
219 g_free (job->temp_file);
220 job->temp_file = NULL;
224 g_error_free (job->error);
229 g_free (job->ranges);
234 (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
238 ev_job_print_class_init (EvJobPrintClass *class)
240 GObjectClass *oclass;
242 oclass = G_OBJECT_CLASS (class);
244 oclass->dispose = ev_job_print_dispose;
247 /* Public functions */
249 ev_job_finished (EvJob *job)
251 ev_debug_message (DEBUG_JOBS, NULL);
253 g_return_if_fail (EV_IS_JOB (job));
255 g_signal_emit (job, job_signals[FINISHED], 0);
259 ev_job_links_new (EvDocument *document)
263 ev_debug_message (DEBUG_JOBS, NULL);
265 job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
266 job->document = g_object_ref (document);
272 ev_job_links_run (EvJobLinks *job)
274 ev_debug_message (DEBUG_JOBS, NULL);
276 g_return_if_fail (EV_IS_JOB_LINKS (job));
278 ev_document_doc_mutex_lock ();
279 job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document));
280 EV_JOB (job)->finished = TRUE;
281 ev_document_doc_mutex_unlock ();
285 ev_job_render_new (EvDocument *document,
295 ev_debug_message (DEBUG_JOBS, "page: %d", page);
297 job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
299 EV_JOB (job)->document = g_object_ref (document);
301 job->rotation = rotation;
303 job->target_width = width;
304 job->target_height = height;
307 if (EV_IS_ASYNC_RENDERER (document)) {
308 EV_JOB (job)->async = TRUE;
315 ev_job_render_set_selection_info (EvJobRender *job,
316 EvRectangle *selection_points,
317 EvSelectionStyle selection_style,
321 job->flags |= EV_RENDER_INCLUDE_SELECTION;
323 job->selection_points = *selection_points;
324 job->selection_style = selection_style;
330 render_finished_cb (EvDocument *document,
334 g_signal_handlers_disconnect_by_func (EV_JOB (job)->document,
335 render_finished_cb, job);
337 job->surface = ev_document_misc_surface_from_pixbuf (pixbuf);
338 job->page_ready = TRUE;
339 g_signal_emit (job, job_render_signals[PAGE_READY], 0);
340 EV_JOB (job)->finished = TRUE;
341 ev_job_finished (EV_JOB (job));
345 notify_page_ready (EvJobRender *job)
347 ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index);
349 g_signal_emit (job, job_render_signals[PAGE_READY], 0);
355 ev_job_render_page_ready (EvJobRender *job)
357 ev_debug_message (DEBUG_JOBS, "%d", job->ev_page->index);
359 job->page_ready = TRUE;
360 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
361 (GSourceFunc)notify_page_ready,
363 (GDestroyNotify)g_object_unref);
367 ev_job_render_run (EvJobRender *job)
369 g_return_if_fail (EV_IS_JOB_RENDER (job));
371 ev_debug_message (DEBUG_JOBS, "page: %d", job->page);
373 ev_document_doc_mutex_lock ();
375 if (EV_JOB (job)->async) {
376 EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
377 ev_async_renderer_render_pixbuf (renderer, job->page, job->scale,
379 g_signal_connect (EV_JOB (job)->document, "render_finished",
380 G_CALLBACK (render_finished_cb), job);
384 ev_document_fc_mutex_lock ();
386 job->ev_page = ev_document_get_page (EV_JOB (job)->document, job->page);
388 rc = ev_render_context_new (job->ev_page, job->rotation, job->scale);
390 job->surface = ev_document_render (EV_JOB (job)->document, rc);
391 if ((job->flags & EV_RENDER_INCLUDE_SELECTION) && EV_IS_SELECTION (EV_JOB (job)->document)) {
392 ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document),
395 &(job->selection_points),
397 job->selection_style,
398 &(job->text), &(job->base));
399 job->selection_region =
400 ev_selection_get_selection_region (EV_SELECTION (EV_JOB (job)->document),
402 job->selection_style,
403 &(job->selection_points));
406 ev_job_render_page_ready (job);
408 ev_document_fc_mutex_unlock ();
410 if ((job->flags & EV_RENDER_INCLUDE_TEXT) && EV_IS_SELECTION (EV_JOB (job)->document))
412 ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document), rc);
413 if ((job->flags & EV_RENDER_INCLUDE_LINKS) && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document))
415 ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), job->page);
416 if ((job->flags & EV_RENDER_INCLUDE_FORMS) && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document))
417 job->form_field_mapping =
418 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB (job)->document),
420 if ((job->flags & EV_RENDER_INCLUDE_IMAGES) && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document))
422 ev_document_images_get_image_mapping (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
426 EV_JOB (job)->finished = TRUE;
429 ev_document_doc_mutex_unlock ();
433 ev_job_thumbnail_new (EvDocument *document,
440 ev_debug_message (DEBUG_JOBS, "%d", page);
442 job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
444 EV_JOB (job)->document = g_object_ref (document);
446 job->rotation = rotation;
453 ev_job_thumbnail_run (EvJobThumbnail *job)
458 ev_debug_message (DEBUG_JOBS, "%d", job->page);
460 g_return_if_fail (EV_IS_JOB_THUMBNAIL (job));
462 ev_document_doc_mutex_lock ();
464 page = ev_document_get_page (EV_JOB (job)->document, job->page);
465 rc = ev_render_context_new (page, job->rotation, job->scale);
466 g_object_unref (page);
469 ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document),
472 ev_document_doc_mutex_unlock ();
474 EV_JOB (job)->finished = TRUE;
477 static void ev_job_fonts_init (EvJobFonts *job) { /* Do Nothing */ }
479 static void ev_job_fonts_class_init (EvJobFontsClass *class) { /* Do Nothing */ }
482 ev_job_fonts_new (EvDocument *document)
486 ev_debug_message (DEBUG_JOBS, NULL);
488 job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
490 EV_JOB (job)->document = g_object_ref (document);
496 ev_job_fonts_run (EvJobFonts *job)
498 EvDocumentFonts *fonts;
500 ev_debug_message (DEBUG_JOBS, NULL);
502 g_return_if_fail (EV_IS_JOB_FONTS (job));
504 ev_document_doc_mutex_lock ();
506 fonts = EV_DOCUMENT_FONTS (EV_JOB (job)->document);
507 ev_document_fc_mutex_lock ();
508 job->scan_completed = !ev_document_fonts_scan (fonts, 20);
509 ev_document_fc_mutex_unlock ();
511 EV_JOB (job)->finished = TRUE;
513 ev_document_doc_mutex_unlock ();
516 static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ }
519 ev_job_load_dispose (GObject *object)
521 EvJobLoad *job = EV_JOB_LOAD (object);
523 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
531 g_error_free (job->error);
536 g_object_unref (job->dest);
540 if (job->search_string) {
541 g_free (job->search_string);
542 job->search_string = NULL;
545 (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
549 ev_job_load_class_init (EvJobLoadClass *class)
551 GObjectClass *oclass;
553 oclass = G_OBJECT_CLASS (class);
555 oclass->dispose = ev_job_load_dispose;
560 ev_job_load_new (const gchar *uri,
562 EvWindowRunMode mode,
563 const gchar *search_string)
567 ev_debug_message (DEBUG_JOBS, "%s", uri);
569 job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
571 job->uri = g_strdup (uri);
573 job->dest = g_object_ref (dest);
577 job->search_string = g_strdup (search_string);
583 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
585 ev_debug_message (DEBUG_JOBS, "%s", uri);
589 job->uri = g_strdup (uri);
593 ev_job_load_run (EvJobLoad *job)
595 g_return_if_fail (EV_IS_JOB_LOAD (job));
597 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
600 g_error_free (job->error);
604 ev_document_fc_mutex_lock ();
606 /* This job may already have a document even if the job didn't complete
607 because, e.g., a password is required - if so, just reload rather than
608 creating a new instance */
609 if (EV_JOB (job)->document) {
610 ev_document_load (EV_JOB (job)->document,
614 EV_JOB(job)->document =
615 ev_document_factory_get_document (job->uri,
619 ev_document_fc_mutex_unlock ();
620 EV_JOB (job)->finished = TRUE;
623 static void ev_job_save_init (EvJobSave *job) { /* Do Nothing */ }
626 ev_job_save_dispose (GObject *object)
628 EvJobSave *job = EV_JOB_SAVE (object);
630 ev_debug_message (DEBUG_JOBS, "%s", job->uri);
637 if (job->document_uri) {
638 g_free (job->document_uri);
639 job->document_uri = NULL;
643 g_error_free (job->error);
647 (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
651 ev_job_save_class_init (EvJobSaveClass *class)
653 GObjectClass *oclass;
655 oclass = G_OBJECT_CLASS (class);
657 oclass->dispose = ev_job_save_dispose;
661 ev_job_save_new (EvDocument *document,
663 const gchar *document_uri)
667 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", uri, document_uri);
669 job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
671 EV_JOB (job)->document = g_object_ref (document);
672 job->uri = g_strdup (uri);
673 job->document_uri = g_strdup (document_uri);
680 ev_job_save_run (EvJobSave *job)
687 ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job->uri, job->document_uri);
689 filename = ev_tmp_filename ("saveacopy");
690 tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
693 fd = g_mkstemp (tmp_filename);
696 gint save_errno = errno;
698 display_name = g_filename_display_name (tmp_filename);
699 g_set_error (&(job->error),
701 g_file_error_from_errno (save_errno),
702 _("Failed to create file “%s”: %s"),
703 display_name, g_strerror (save_errno));
704 g_free (display_name);
705 g_free (tmp_filename);
710 ev_document_doc_mutex_lock ();
712 /* Save document to temp filename */
713 local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
714 ev_document_save (EV_JOB (job)->document, local_uri, &(job->error));
717 ev_document_doc_mutex_unlock ();
724 /* If original document was compressed,
725 * compress it again before saving
727 if (g_object_get_data (G_OBJECT (EV_JOB (job)->document),
728 "uri-uncompressed")) {
729 EvCompressionType ctype = EV_COMPRESSION_NONE;
733 ext = g_strrstr (job->document_uri, ".gz");
734 if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
735 ctype = EV_COMPRESSION_GZIP;
737 ext = g_strrstr (job->document_uri, ".bz2");
738 if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
739 ctype = EV_COMPRESSION_BZIP2;
741 uri_comp = ev_file_compress (local_uri, ctype, &(job->error));
743 ev_tmp_filename_unlink (tmp_filename);
745 if (!uri_comp || job->error) {
748 local_uri = uri_comp;
752 g_free (tmp_filename);
762 ev_xfer_uri_simple (local_uri, job->uri, &(job->error));
763 ev_tmp_uri_unlink (local_uri);
767 ev_job_print_new (EvDocument *document,
771 EvPrintRange *ranges,
773 EvPrintPageSet page_set,
774 gint pages_per_sheet,
781 ev_debug_message (DEBUG_JOBS, "format: %s, width: %f, height:%f,"
782 "n_ranges: %d, pages_per_sheet: %d, copies: %d,"
783 "collate: %s, reverse: %s",
784 format, width, height, n_ranges, pages_per_sheet, copies,
785 collate ? "True" : "False", reverse ? "True" : "False");
787 job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
789 EV_JOB (job)->document = g_object_ref (document);
791 job->format = format;
793 job->temp_file = NULL;
797 job->height = height;
799 job->ranges = ranges;
800 job->n_ranges = n_ranges;
802 job->page_set = page_set;
804 job->pages_per_sheet = CLAMP (pages_per_sheet, 1, 16);
806 job->copies = copies;
807 job->collate = collate;
808 job->reverse = reverse;
814 ev_print_job_get_first_page (EvJobPrint *job)
817 gint first_page = G_MAXINT;
819 if (job->n_ranges == 0)
822 for (i = 0; i < job->n_ranges; i++) {
823 if (job->ranges[i].start < first_page)
824 first_page = job->ranges[i].start;
827 return MAX (0, first_page);
831 ev_print_job_get_last_page (EvJobPrint *job)
834 gint last_page = G_MININT;
837 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
839 if (job->n_ranges == 0)
842 for (i = 0; i < job->n_ranges; i++) {
843 if (job->ranges[i].end > last_page)
844 last_page = job->ranges[i].end;
847 return MIN (max_page, last_page);
851 ev_print_job_print_page_in_set (EvJobPrint *job,
854 switch (job->page_set) {
855 case EV_PRINT_PAGE_SET_EVEN:
856 return page % 2 == 0;
857 case EV_PRINT_PAGE_SET_ODD:
858 return page % 2 != 0;
859 case EV_PRINT_PAGE_SET_ALL:
867 ev_job_print_get_page_list (EvJobPrint *job,
870 gint i, j, page, max_page;
874 max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
876 for (i = 0; i < job->n_ranges; i++) {
880 if (job->ranges[i].start == -1)
881 job->ranges[i].start = 0;
882 if (job->ranges[i].end == -1)
883 job->ranges[i].end = max_page;
885 if (job->ranges[i].start > max_page)
888 start = job->ranges[i].start + 1;
889 end = job->ranges[i].end <= max_page ? job->ranges[i].end + 1 : max_page + 1;
890 rsize = end - start + 1;
892 switch (job->page_set) {
893 case EV_PRINT_PAGE_SET_EVEN:
894 pages += start % 2 == 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
896 case EV_PRINT_PAGE_SET_ODD:
897 pages += start % 2 != 0 ? (rsize / 2) + (rsize % 2) : (rsize / 2);
910 page_list = g_new (gint, pages);
913 for (i = 0; i < job->n_ranges; i++) {
914 for (j = job->ranges[i].start; j <= job->ranges[i].end; j++) {
918 if (ev_print_job_print_page_in_set (job, j + 1))
919 page_list[page++] = j;
927 ev_job_print_run (EvJobPrint *job)
929 EvDocument *document = EV_JOB (job)->document;
930 EvFileExporterContext fc;
940 g_return_if_fail (EV_IS_JOB_PRINT (job));
942 ev_debug_message (DEBUG_JOBS, NULL);
945 g_free (job->temp_file);
946 job->temp_file = NULL;
949 g_error_free (job->error);
952 filename = g_strdup_printf ("evince_print.%s.XXXXXX", job->format);
953 fd = g_file_open_tmp (filename, &job->temp_file, &job->error);
956 EV_JOB (job)->finished = TRUE;
960 page_list = ev_job_print_get_page_list (job, &n_pages);
963 EV_JOB (job)->finished = TRUE;
967 first_page = ev_print_job_get_first_page (job);
968 last_page = ev_print_job_get_last_page (job);
970 fc.format = g_ascii_strcasecmp (job->format, "pdf") == 0 ?
971 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS;
972 fc.filename = job->temp_file;
973 fc.first_page = MIN (first_page, last_page);
974 fc.last_page = MAX (first_page, last_page);
975 fc.paper_width = job->width;
976 fc.paper_height = job->height;
978 fc.pages_per_sheet = MAX (1, job->pages_per_sheet);
980 rc = ev_render_context_new (NULL, 0, 1.0);
982 ev_document_doc_mutex_lock ();
983 ev_file_exporter_begin (EV_FILE_EXPORTER (document), &fc);
985 for (i = 0; i < job->copies; i++) {
989 step = job->reverse ? -1 * job->pages_per_sheet : job->pages_per_sheet;
990 page = job->reverse ? ((n_pages - 1) / job->pages_per_sheet) * job->pages_per_sheet : 0;
991 n_copies = job->collate ? 1 : job->copies;
993 while ((job->reverse && (page >= 0)) || (!job->reverse && (page < n_pages))) {
996 for (k = 0; k < n_copies; k++) {
997 ev_file_exporter_begin_page (EV_FILE_EXPORTER (document));
999 for (j = 0; j < job->pages_per_sheet; j++) {
1004 if (p < 0 || p >= n_pages)
1007 ev_page = ev_document_get_page (document, page_list[p]);
1008 ev_render_context_set_page (rc, ev_page);
1009 g_object_unref (ev_page);
1011 ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
1014 ev_file_exporter_end_page (EV_FILE_EXPORTER (document));
1024 ev_file_exporter_end (EV_FILE_EXPORTER (document));
1025 ev_document_doc_mutex_unlock ();
1029 g_object_unref (rc);
1031 EV_JOB (job)->finished = TRUE;