]> www.fi.muni.cz Git - evince.git/blob - shell/ev-jobs.c
Translation updated.
[evince.git] / shell / ev-jobs.c
1 #include "ev-jobs.h"
2 #include "ev-job-queue.h"
3 #include "ev-document-thumbnails.h"
4 #include "ev-document-links.h"
5 #include "ev-document-images.h"
6 #include "ev-document-forms.h"
7 #include "ev-document-factory.h"
8 #include "ev-document-misc.h"
9 #include "ev-file-helpers.h"
10 #include "ev-document-fonts.h"
11 #include "ev-selection.h"
12 #include "ev-async-renderer.h"
13 #include "ev-file-exporter.h"
14 #include "ev-window.h"
15
16 #include <glib/gstdio.h>
17 #include <unistd.h>
18 #include <libgnomevfs/gnome-vfs-uri.h>
19 #include <libgnomevfs/gnome-vfs-utils.h>
20 #include <libgnomevfs/gnome-vfs-ops.h>
21
22 static void ev_job_init                 (EvJob               *job);
23 static void ev_job_class_init           (EvJobClass          *class);
24 static void ev_job_links_init           (EvJobLinks          *job);
25 static void ev_job_links_class_init     (EvJobLinksClass     *class);
26 static void ev_job_render_init          (EvJobRender         *job);
27 static void ev_job_render_class_init    (EvJobRenderClass    *class);
28 static void ev_job_thumbnail_init       (EvJobThumbnail      *job);
29 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
30 static void ev_job_load_init            (EvJobLoad           *job);
31 static void ev_job_load_class_init      (EvJobLoadClass      *class);
32 static void ev_job_print_init           (EvJobPrint          *job);
33 static void ev_job_print_class_init     (EvJobPrintClass     *class);
34
35 enum
36 {
37         FINISHED,
38         LAST_SIGNAL
39 };
40
41 static guint job_signals[LAST_SIGNAL] = { 0 };
42
43 G_DEFINE_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
44 G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
45 G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
46 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
47 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
48 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
49 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
50
51 static void ev_job_init (EvJob *job) { /* Do Nothing */ }
52
53 static void
54 ev_job_dispose (GObject *object)
55 {
56         EvJob *job;
57
58         job = EV_JOB (object);
59
60         if (job->document) {
61                 g_object_unref (job->document);
62                 job->document = NULL;
63         }
64
65         (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
66 }
67
68 static void
69 ev_job_class_init (EvJobClass *class)
70 {
71         GObjectClass *oclass;
72
73         oclass = G_OBJECT_CLASS (class);
74
75         oclass->dispose = ev_job_dispose;
76
77         job_signals [FINISHED] =
78                 g_signal_new ("finished",
79                               EV_TYPE_JOB,
80                               G_SIGNAL_RUN_LAST,
81                               G_STRUCT_OFFSET (EvJobClass, finished),
82                               NULL, NULL,
83                               g_cclosure_marshal_VOID__VOID,
84                               G_TYPE_NONE, 0);
85 }
86
87
88 static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ }
89
90 static void
91 ev_job_links_dispose (GObject *object)
92 {
93         EvJobLinks *job;
94
95         job = EV_JOB_LINKS (object);
96
97         if (job->model) {
98                 g_object_unref (job->model);
99                 job->model = NULL;
100         }
101
102         (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
103 }
104
105 static void
106 ev_job_links_class_init (EvJobLinksClass *class)
107 {
108         GObjectClass *oclass;
109
110         oclass = G_OBJECT_CLASS (class);
111
112         oclass->dispose = ev_job_links_dispose;
113 }
114
115
116 static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ }
117
118 static void
119 ev_job_render_dispose (GObject *object)
120 {
121         EvJobRender *job;
122
123         job = EV_JOB_RENDER (object);
124
125         if (job->surface) {
126                 cairo_surface_destroy (job->surface);
127                 job->surface = NULL;
128         }
129
130         if (job->rc) {
131                 g_object_unref (job->rc);
132                 job->rc = NULL;
133         }
134
135         if (job->selection) {
136                 cairo_surface_destroy (job->selection);
137                 job->selection = NULL;
138         }
139
140         if (job->selection_region) {
141                 gdk_region_destroy (job->selection_region);
142                 job->selection_region = NULL;
143         }
144
145         (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
146 }
147
148 static void
149 ev_job_render_class_init (EvJobRenderClass *class)
150 {
151         GObjectClass *oclass;
152
153         oclass = G_OBJECT_CLASS (class);
154
155         oclass->dispose = ev_job_render_dispose;
156 }
157
158 static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ }
159
160 static void
161 ev_job_thumbnail_dispose (GObject *object)
162 {
163         EvJobThumbnail *job;
164
165         job = EV_JOB_THUMBNAIL (object);
166
167         if (job->thumbnail) {
168                 g_object_unref (job->thumbnail);
169                 job->thumbnail = NULL;
170         }
171
172         if (job->rc) {
173                 g_object_unref (job->rc);
174                 job->rc = NULL;
175         }
176
177         (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
178 }
179
180 static void
181 ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
182 {
183         GObjectClass *oclass;
184
185         oclass = G_OBJECT_CLASS (class);
186
187         oclass->dispose = ev_job_thumbnail_dispose;
188 }
189
190 static void ev_job_print_init (EvJobPrint *job) { /* Do Nothing */ }
191
192 static void
193 ev_job_print_dispose (GObject *object)
194 {
195         EvJobPrint *job;
196
197         job = EV_JOB_PRINT (object);
198
199         if (job->temp_file) {
200                 g_unlink (job->temp_file);
201                 g_free (job->temp_file);
202                 job->temp_file = NULL;
203         }
204
205         if (job->error) {
206                 g_error_free (job->error);
207                 job->error = NULL;
208         }
209
210         if (job->ranges) {
211                 g_free (job->ranges);
212                 job->ranges = NULL;
213                 job->n_ranges = 0;
214         }
215
216         (* G_OBJECT_CLASS (ev_job_print_parent_class)->dispose) (object);
217 }
218
219 static void
220 ev_job_print_class_init (EvJobPrintClass *class)
221 {
222         GObjectClass *oclass;
223
224         oclass = G_OBJECT_CLASS (class);
225
226         oclass->dispose = ev_job_print_dispose;
227 }
228
229 /* Public functions */
230 void
231 ev_job_finished (EvJob *job)
232 {
233         g_return_if_fail (EV_IS_JOB (job));
234
235         g_signal_emit (job, job_signals[FINISHED], 0);
236 }
237
238 EvJob *
239 ev_job_links_new (EvDocument *document)
240 {
241         EvJob *job;
242
243         job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
244         job->document = g_object_ref (document);
245
246         return job;
247 }
248
249 void
250 ev_job_links_run (EvJobLinks *job)
251 {
252         g_return_if_fail (EV_IS_JOB_LINKS (job));
253
254         ev_document_doc_mutex_lock ();
255         job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document));
256         EV_JOB (job)->finished = TRUE;
257         ev_document_doc_mutex_unlock ();
258 }
259
260
261 EvJob *
262 ev_job_render_new (EvDocument      *document,
263                    EvRenderContext *rc,
264                    gint             width,
265                    gint             height,
266                    EvRectangle     *selection_points,
267                    GdkColor        *text,
268                    GdkColor        *base,
269                    gboolean         include_forms,
270                    gboolean         include_links,
271                    gboolean         include_images,
272                    gboolean         include_text,
273                    gboolean         include_selection)
274 {
275         EvJobRender *job;
276
277         g_return_val_if_fail (EV_IS_RENDER_CONTEXT (rc), NULL);
278         if (include_selection)
279                 g_return_val_if_fail (selection_points != NULL, NULL);
280
281         job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
282
283         EV_JOB (job)->document = g_object_ref (document);
284         job->rc = g_object_ref (rc);
285         job->target_width = width;
286         job->target_height = height;
287         job->text = *text;
288         job->base = *base;
289         job->include_forms = include_forms;
290         job->include_links = include_links;
291         job->include_images = include_images;
292         job->include_text = include_text;
293         job->include_selection = include_selection;
294
295         if (include_selection)
296                 job->selection_points = *selection_points;
297
298         if (EV_IS_ASYNC_RENDERER (document)) {  
299                 EV_JOB (job)->async = TRUE;
300         }
301
302         return EV_JOB (job);
303 }
304
305 static void
306 render_finished_cb (EvDocument      *document,
307                     GdkPixbuf       *pixbuf,
308                     EvJobRender     *job)
309 {
310         g_signal_handlers_disconnect_by_func (EV_JOB (job)->document,
311                                               render_finished_cb, job);
312
313         /* FIXME: ps backend should be ported to cairo */
314         job->surface = ev_document_misc_surface_from_pixbuf (pixbuf);
315         EV_JOB (job)->finished = TRUE;
316         ev_job_finished (EV_JOB (job));
317 }
318
319 void
320 ev_job_render_run (EvJobRender *job)
321 {
322         g_return_if_fail (EV_IS_JOB_RENDER (job));
323
324         ev_document_doc_mutex_lock ();
325
326         if (EV_JOB (job)->async) {
327                 EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
328                 ev_async_renderer_render_pixbuf (renderer, job->rc->page, job->rc->scale,
329                                                  job->rc->rotation);
330                 g_signal_connect (EV_JOB (job)->document, "render_finished",
331                                   G_CALLBACK (render_finished_cb), job);
332         } else {
333                 ev_document_fc_mutex_lock ();
334                 
335                 job->surface = ev_document_render (EV_JOB (job)->document, job->rc);
336
337                 if (job->include_links && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document))
338                         job->link_mapping =
339                                 ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document),
340                                                              job->rc->page);
341                 if (job->include_images && EV_IS_DOCUMENT_IMAGES (EV_JOB (job)->document))
342                         job->image_mapping =
343                                 ev_document_images_get_images (EV_DOCUMENT_IMAGES (EV_JOB (job)->document),
344                                                                job->rc->page);
345                 if (job->include_forms && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document))
346                         job->form_field_mapping =
347                                 ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (EV_JOB(job)->document),
348                                                                    job->rc->page);
349                 if (job->include_text && EV_IS_SELECTION (EV_JOB (job)->document))
350                         job->text_mapping =
351                                 ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document),
352                                                                 job->rc);
353                 if (job->include_selection && EV_IS_SELECTION (EV_JOB (job)->document)) {
354                         ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document),
355                                                        job->rc,
356                                                        &(job->selection),
357                                                        &(job->selection_points),
358                                                        NULL,
359                                                        &(job->text), &(job->base));
360                         job->selection_region =
361                                 ev_selection_get_selection_region (EV_SELECTION (EV_JOB (job)->document),
362                                                                    job->rc,
363                                                                    &(job->selection_points));
364                 }
365                 
366                 ev_document_fc_mutex_unlock ();
367                 EV_JOB (job)->finished = TRUE;
368         }
369
370         ev_document_doc_mutex_unlock ();
371 }
372
373 EvJob *
374 ev_job_thumbnail_new (EvDocument      *document,
375                       EvRenderContext *rc)
376 {
377         EvJobThumbnail *job;
378
379         job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
380
381         EV_JOB (job)->document = g_object_ref (document);
382         job->rc = g_object_ref (rc);
383
384         return EV_JOB (job);
385 }
386
387 void
388 ev_job_thumbnail_run (EvJobThumbnail *job)
389 {
390         g_return_if_fail (EV_IS_JOB_THUMBNAIL (job));
391
392         ev_document_doc_mutex_lock ();
393
394         job->thumbnail =
395                 ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document),
396                                                       job->rc, TRUE);
397         EV_JOB (job)->finished = TRUE;
398
399         ev_document_doc_mutex_unlock ();
400 }
401
402 static void ev_job_fonts_init (EvJobFonts *job) { /* Do Nothing */ }
403
404 static void ev_job_fonts_class_init (EvJobFontsClass *class) { /* Do Nothing */ }
405
406 EvJob *
407 ev_job_fonts_new (EvDocument *document)
408 {
409         EvJobFonts *job;
410
411         job = g_object_new (EV_TYPE_JOB_FONTS, NULL);
412
413         EV_JOB (job)->document = g_object_ref (document);
414
415         return EV_JOB (job);
416 }
417
418 void
419 ev_job_fonts_run (EvJobFonts *job)
420 {
421         EvDocumentFonts *fonts;
422
423         g_return_if_fail (EV_IS_JOB_FONTS (job));
424
425         ev_document_doc_mutex_lock ();
426         
427         fonts = EV_DOCUMENT_FONTS (EV_JOB (job)->document);
428         ev_document_fc_mutex_lock ();
429         job->scan_completed = !ev_document_fonts_scan (fonts, 20);
430         ev_document_fc_mutex_unlock ();
431         
432         EV_JOB (job)->finished = TRUE;
433
434         ev_document_doc_mutex_unlock ();
435 }
436
437 static void ev_job_load_init (EvJobLoad *job) { /* Do Nothing */ }
438
439 static void
440 ev_job_load_dispose (GObject *object)
441 {
442         EvJobLoad *job = EV_JOB_LOAD (object);
443
444         if (job->uri) {
445                 g_free (job->uri);
446                 job->uri = NULL;
447         }
448
449         if (job->error) {
450                 g_error_free (job->error);
451                 job->error = NULL;
452         }
453
454         if (job->dest) {
455                 g_object_unref (job->dest);
456                 job->dest = NULL;
457         }
458
459         (* G_OBJECT_CLASS (ev_job_load_parent_class)->dispose) (object);
460 }
461
462 static void
463 ev_job_load_class_init (EvJobLoadClass *class)
464 {
465         GObjectClass *oclass;
466
467         oclass = G_OBJECT_CLASS (class);
468
469         oclass->dispose = ev_job_load_dispose;
470 }
471
472
473 EvJob *
474 ev_job_load_new (const gchar *uri, EvLinkDest *dest, EvWindowRunMode mode)
475 {
476         EvJobLoad *job;
477
478         job = g_object_new (EV_TYPE_JOB_LOAD, NULL);
479
480         job->uri = g_strdup (uri);
481         if (dest)
482                 job->dest = g_object_ref (dest);
483
484         job->mode = mode;
485
486         return EV_JOB (job);
487 }
488
489 void
490 ev_job_load_set_uri (EvJobLoad *job, const gchar *uri)
491 {
492         if (job->uri)
493                 g_free (job->uri);
494         job->uri = g_strdup (uri);
495 }
496
497 void
498 ev_job_load_run (EvJobLoad *job)
499 {
500         g_return_if_fail (EV_IS_JOB_LOAD (job));
501         
502         if (job->error) {
503                 g_error_free (job->error);
504                 job->error = NULL;
505         }
506
507         ev_document_fc_mutex_lock ();
508         
509         /* This job may already have a document even if the job didn't complete
510            because, e.g., a password is required - if so, just reload rather than
511            creating a new instance */
512         if (EV_JOB (job)->document) {
513                 ev_document_load (EV_JOB (job)->document,
514                                   job->uri,
515                                   &job->error);
516         } else {
517                 EV_JOB(job)->document =
518                         ev_document_factory_get_document (job->uri,
519                                                           &job->error);
520         }
521
522         ev_document_fc_mutex_unlock ();
523         EV_JOB (job)->finished = TRUE;
524 }
525
526 EvJob *
527 ev_job_print_new (EvDocument    *document,
528                   const gchar   *format,
529                   gdouble        width,
530                   gdouble        height,
531                   EvPrintRange  *ranges,
532                   gint           n_ranges,
533                   EvPrintPageSet page_set,
534                   gint           copies,
535                   gdouble        collate,
536                   gdouble        reverse)
537 {
538         EvJobPrint *job;
539
540         job = g_object_new (EV_TYPE_JOB_PRINT, NULL);
541
542         EV_JOB (job)->document = g_object_ref (document);
543
544         job->format = format;
545         
546         job->temp_file = NULL;
547         job->error = NULL;
548
549         job->width = width;
550         job->height = height;
551
552         job->ranges = ranges;
553         job->n_ranges = n_ranges;
554
555         job->page_set = page_set;
556         
557         job->copies = copies;
558         job->collate = collate;
559         job->reverse = reverse;
560         
561         return EV_JOB (job);
562 }
563
564 static gint
565 ev_print_job_get_first_page (EvJobPrint *job)
566 {
567         gint i;
568         gint first_page = G_MAXINT;
569         
570         if (job->n_ranges == 0)
571                 return 0;
572
573         for (i = 0; i < job->n_ranges; i++) {
574                 if (job->ranges[i].start < first_page)
575                         first_page = job->ranges[i].start;
576         }
577
578         return MAX (0, first_page);
579 }
580
581 static gint
582 ev_print_job_get_last_page (EvJobPrint *job)
583 {
584         gint i;
585         gint last_page = G_MININT;
586         gint max_page;
587
588         max_page = ev_document_get_n_pages (EV_JOB (job)->document) - 1;
589
590         if (job->n_ranges == 0)
591                 return max_page;
592
593         for (i = 0; i < job->n_ranges; i++) {
594                 if (job->ranges[i].end > last_page)
595                         last_page = job->ranges[i].end;
596         }
597
598         return MIN (max_page, last_page);
599 }
600
601 static gboolean
602 ev_print_job_print_page_in_range (EvJobPrint *job,
603                                   gint        page)
604 {
605         gint i;
606
607         for (i = 0; i < job->n_ranges; i++) {
608                 if (page >= job->ranges[i].start &&
609                     page <= job->ranges[i].end)
610                         return TRUE;
611         }
612
613         return FALSE;
614 }
615
616 static gboolean
617 ev_print_job_print_page_in_set (EvJobPrint *job,
618                                 gint        page)
619 {
620         switch (job->page_set) {
621                 case EV_PRINT_PAGE_SET_EVEN:
622                         return page % 2 == 0;
623                 case EV_PRINT_PAGE_SET_ODD:
624                         return page % 2 != 0;
625                 case EV_PRINT_PAGE_SET_ALL:
626                         return TRUE;
627         }
628
629         return FALSE;
630 }
631
632 static void
633 ev_job_print_do_page (EvJobPrint *job, gint page)
634 {
635         EvDocument      *document = EV_JOB (job)->document;
636         EvRenderContext *rc;
637
638         rc = ev_render_context_new (0, page, 1.0);
639         ev_file_exporter_do_page (EV_FILE_EXPORTER (document), rc);
640         g_object_unref (rc);
641 }
642
643 void
644 ev_job_print_run (EvJobPrint *job)
645 {
646         EvDocument *document = EV_JOB (job)->document;
647         gint        fd;
648         gint        last_page;
649         gint        first_page;
650         gint        i;
651         gchar      *filename;
652         
653         g_return_if_fail (EV_IS_JOB_PRINT (job));
654
655         if (job->temp_file)
656                 g_free (job->temp_file);
657         job->temp_file = NULL;
658         
659         if (job->error)
660                 g_error_free (job->error);
661         job->error = NULL;
662
663         filename = g_strdup_printf ("evince_print.%s.XXXXXX", job->format);
664         fd = g_file_open_tmp (filename, &job->temp_file, &job->error);
665         g_free (filename);
666         if (fd <= -1) {
667                 EV_JOB (job)->finished = TRUE;
668                 return;
669         }
670
671         first_page = ev_print_job_get_first_page (job);
672         last_page = ev_print_job_get_last_page (job);
673
674         ev_document_doc_mutex_lock ();
675         ev_file_exporter_begin (EV_FILE_EXPORTER (document),
676                                 g_ascii_strcasecmp (job->format, "pdf") == 0 ?
677                                 EV_FILE_FORMAT_PDF : EV_FILE_FORMAT_PS,
678                                 job->temp_file,
679                                 MIN (first_page, last_page),
680                                 MAX (first_page, last_page),
681                                 job->width, job->height, FALSE);
682         ev_document_doc_mutex_unlock ();
683
684         for (i = 0; i < job->copies; i++) {
685                 gint page, step;
686                 
687                 step = job->reverse ? -1 : 1;
688                 page = job->reverse ? last_page : first_page;
689                 
690                 while ((job->reverse && (page >= first_page)) ||
691                        (!job->reverse && (page <= last_page))) {
692                         gint n_pages = 1;
693                         gint j;
694
695                         if (job->n_ranges > 0 &&
696                             !ev_print_job_print_page_in_range (job, page)) {
697                                 page += step;
698                                 continue;
699                         }
700
701                         if (!ev_print_job_print_page_in_set (job, page + 1)) {
702                                 page += step;
703                                 continue;
704                         }
705
706                         if (job->collate)
707                                 n_pages = job->copies;
708
709                         for (j = 0; j < n_pages; j++) {
710                                 ev_document_doc_mutex_lock ();
711                                 ev_job_print_do_page (job, page);
712                                 ev_document_doc_mutex_unlock ();
713                         }
714
715                         page += step;
716                 }
717
718                 if (job->collate)
719                         break;
720         }
721
722         ev_document_doc_mutex_lock ();
723         ev_file_exporter_end (EV_FILE_EXPORTER (document));
724         ev_document_doc_mutex_unlock ();
725
726         close (fd);
727         
728         EV_JOB (job)->finished = TRUE;
729 }