]> www.fi.muni.cz Git - evince.git/blob - ps/ps-document.c
Add a get_orientation api. Improve set_orientation.
[evince.git] / ps / ps-document.c
1 /* Ghostscript widget for GTK/GNOME
2  * 
3  * Copyright (C) 1998 - 2005 the Free Software Foundation
4  * 
5  * Authors: Jonathan Blandford, Jaka Mocnik
6  * 
7  * Based on code by: Federico Mena (Quartic), Szekeres Istvan (Pista)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24  
25 #include "config.h"
26 #include <string.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <gtk/gtk.h>
30 #include <gtk/gtkobject.h>
31 #include <gdk/gdkprivate.h>
32 #include <gdk/gdkx.h>
33 #include <gdk/gdk.h>
34 #include <glib/gi18n.h>
35 #include <X11/Intrinsic.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <stdio.h>
44 #include <math.h>
45
46 #include "ps-document.h"
47 #include "ev-debug.h"
48 #include "gsdefaults.h"
49 #include "ev-ps-exporter.h"
50 #include "ev-async-renderer.h"
51
52 #define MAX_BUFSIZE 1024
53
54 #define PS_DOCUMENT_IS_COMPRESSED(gs) (PS_DOCUMENT(gs)->gs_filename_unc != NULL)
55 #define PS_DOCUMENT_GET_PS_FILE(gs)   (PS_DOCUMENT_IS_COMPRESSED(gs) ? \
56                                        PS_DOCUMENT(gs)->gs_filename_unc : \
57                                        PS_DOCUMENT(gs)->gs_filename)
58
59 /* structure to describe section of file to send to ghostscript */
60 struct record_list
61 {
62         FILE *fp;
63         long begin;
64         guint len;
65         gboolean seek_needed;
66         gboolean close;
67         struct record_list *next;
68 };
69
70 static gboolean broken_pipe = FALSE;
71
72 /* Forward declarations */
73 static void     ps_document_init                        (PSDocument           *gs);
74 static void     ps_document_class_init                  (PSDocumentClass      *klass);
75 static void     send_ps                                 (PSDocument           *gs,
76                                                          long                  begin,
77                                                          unsigned int          len,
78                                                          gboolean              close);
79 static void     output                                  (gpointer              data,
80                                                          gint                  source,
81                                                          GdkInputCondition     condition);
82 static void     input                                   (gpointer              data,
83                                                          gint                  source,
84                                                          GdkInputCondition     condition);
85 static void     stop_interpreter                        (PSDocument           *gs);
86 static gint     start_interpreter                       (PSDocument           *gs);
87 static void     ps_document_document_iface_init         (EvDocumentIface      *iface);
88 static void     ps_document_ps_exporter_iface_init      (EvPSExporterIface    *iface);
89 static void     ps_async_renderer_iface_init            (EvAsyncRendererIface *iface);
90
91 G_DEFINE_TYPE_WITH_CODE (PSDocument, ps_document, G_TYPE_OBJECT,
92                          {
93                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
94                                                         ps_document_document_iface_init);
95                                  G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
96                                                         ps_document_ps_exporter_iface_init);
97                                  G_IMPLEMENT_INTERFACE (EV_TYPE_ASYNC_RENDERER,
98                                                         ps_async_renderer_iface_init);
99                          });
100
101 static GObjectClass *parent_class = NULL;
102 static PSDocumentClass *gs_class = NULL;
103
104 static void
105 ps_document_init (PSDocument *gs)
106 {
107         gs->bpixmap = NULL;
108
109         gs->interpreter_pid = -1;
110
111         gs->busy = FALSE;
112         gs->gs_filename = 0;
113         gs->gs_filename_unc = 0;
114
115         broken_pipe = FALSE;
116
117         gs->structured_doc = FALSE;
118         gs->reading_from_pipe = FALSE;
119         gs->send_filename_to_gs = FALSE;
120
121         gs->doc = NULL;
122
123         gs->interpreter_input = -1;
124         gs->interpreter_output = -1;
125         gs->interpreter_err = -1;
126         gs->interpreter_input_id = 0;
127         gs->interpreter_output_id = 0;
128         gs->interpreter_error_id = 0;
129
130         gs->ps_input = NULL;
131         gs->input_buffer = NULL;
132         gs->input_buffer_ptr = NULL;
133         gs->bytes_left = 0;
134         gs->buffer_bytes_left = 0;
135
136         gs->gs_status = _("No document loaded.");
137
138         gs->ps_export_pagelist = NULL;
139         gs->ps_export_filename = NULL;
140
141         gs->orientation = GTK_GS_ORIENTATION_NONE;
142 }
143
144 static void
145 ps_document_dispose (GObject *object)
146 {
147         PSDocument *gs = PS_DOCUMENT (object);
148
149         g_return_if_fail (gs != NULL);
150
151         if (gs->gs_psfile) {
152                 fclose (gs->gs_psfile);
153                 gs->gs_psfile = NULL;
154         }
155
156         if (gs->gs_filename) {
157                 g_free (gs->gs_filename);
158                 gs->gs_filename = NULL;
159         }
160
161         if (gs->doc) {
162                 psfree (gs->doc);
163                 gs->doc = NULL;
164         }
165
166         if (gs->gs_filename_unc) {
167                 unlink(gs->gs_filename_unc);
168                 g_free(gs->gs_filename_unc);
169                 gs->gs_filename_unc = NULL;
170         }
171
172         if (gs->bpixmap) {
173                 gdk_drawable_unref (gs->bpixmap);
174         }
175
176         if(gs->input_buffer) {
177                 g_free(gs->input_buffer);
178                 gs->input_buffer = NULL;
179         }
180
181         stop_interpreter (gs);
182
183         G_OBJECT_CLASS (parent_class)->dispose (object);
184 }
185
186 static void
187 ps_document_class_init(PSDocumentClass *klass)
188 {
189         GObjectClass *object_class;
190
191         object_class = (GObjectClass *) klass;
192         parent_class = g_type_class_peek_parent (klass);
193         gs_class = klass;
194
195         object_class->dispose = ps_document_dispose;    
196
197         klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE);
198         klass->next_atom = gdk_atom_intern ("NEXT", FALSE);
199         klass->page_atom = gdk_atom_intern ("PAGE", FALSE);
200         klass->string_atom = gdk_atom_intern ("STRING", FALSE);
201 }
202
203 static void
204 push_pixbuf (PSDocument *gs)
205 {
206         GdkColormap *cmap;
207         GdkPixbuf *pixbuf;
208         int width, height;
209
210         cmap = gdk_window_get_colormap (gs->pstarget);
211         gdk_drawable_get_size (gs->bpixmap, &width, &height);
212         pixbuf =  gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap,
213                                                 0, 0, 0, 0,
214                                                 width, height);
215         g_signal_emit_by_name (gs, "render_finished", pixbuf);
216         g_object_unref (pixbuf);
217 }
218
219 static void
220 interpreter_failed (PSDocument *gs, char *msg)
221 {
222         LOG ("Interpreter failed %s", msg);
223
224         push_pixbuf (gs);
225
226         stop_interpreter (gs);
227 }
228
229 static gboolean
230 ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
231 {
232         PSDocument *gs = (PSDocument *) data;
233
234         if(event->type != GDK_CLIENT_EVENT)
235                 return FALSE;
236
237         gs->message_window = event->client.data.l[0];
238
239         if (event->client.message_type == gs_class->page_atom) {
240                 LOG ("GS rendered the document");
241                 gs->busy = FALSE;
242
243                 push_pixbuf (gs);
244         }
245
246         return TRUE;
247 }
248
249 static void
250 send_ps (PSDocument *gs, long begin, unsigned int len, gboolean close)
251 {
252         struct record_list *ps_new;
253
254         if (gs->interpreter_input < 0) {
255                 g_critical("No pipe to gs: error in send_ps().");
256                 return;
257         }
258
259         ps_new = g_new0 (struct record_list, 1);
260         ps_new->fp = gs->gs_psfile;
261         ps_new->begin = begin;
262         ps_new->len = len;
263         ps_new->seek_needed = TRUE;
264         ps_new->close = close;
265         ps_new->next = NULL;
266
267         if (gs->input_buffer == NULL) {
268                 gs->input_buffer = g_malloc(MAX_BUFSIZE);
269         }
270
271         if (gs->ps_input == NULL) {
272                 gs->input_buffer_ptr = gs->input_buffer;
273                 gs->bytes_left = len;
274                 gs->buffer_bytes_left = 0;
275                 gs->ps_input = ps_new;
276                 gs->interpreter_input_id = gdk_input_add
277                         (gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
278         } else {
279                 struct record_list *p = gs->ps_input;
280                 while (p->next != NULL) {
281                         p = p->next;
282                 }
283                 p->next = ps_new;
284         }
285 }
286
287 static float
288 get_xdpi (PSDocument *gs)
289 {
290         return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
291 }
292
293 static float
294 get_ydpi (PSDocument *gs)
295 {
296         return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
297 }
298
299 static void
300 setup_pixmap (PSDocument *gs, int page, double scale)
301 {
302         GdkGC *fill;
303         GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
304         GdkColormap *colormap;
305         double width, height;
306         int pixmap_width, pixmap_height;
307
308         ev_document_get_page_size (EV_DOCUMENT (gs), page, &width, &height);
309         pixmap_width = width * scale + 0.5;
310         pixmap_height = height * scale + 0.5;
311
312         if(gs->bpixmap) {
313                 int w, h;
314
315                 gdk_drawable_get_size (gs->bpixmap, &w, &h);
316
317                 if (pixmap_width != w || h != pixmap_height) {
318                         gdk_drawable_unref (gs->bpixmap);
319                         gs->bpixmap = NULL;
320                         stop_interpreter (gs);
321                 }
322         }
323
324         if (!gs->bpixmap) {
325                 LOG ("Create pixmap");
326
327                 fill = gdk_gc_new (gs->pstarget);
328                 colormap = gdk_drawable_get_colormap (gs->pstarget);
329                 gdk_color_alloc (colormap, &white);
330                 gdk_gc_set_foreground (fill, &white);
331                 gs->bpixmap = gdk_pixmap_new (gs->pstarget, pixmap_width,
332                                               pixmap_height, -1);
333                 gdk_draw_rectangle (gs->bpixmap, fill, TRUE,
334                                     0, 0, pixmap_width, pixmap_height);
335         }
336 }
337
338 #define DEFAULT_PAGE_SIZE 1
339
340 static void
341 get_page_box (PSDocument *gs, int page, int *urx, int *ury, int *llx, int *lly)
342 {
343         gint new_llx = 0;
344         gint new_lly = 0;
345         gint new_urx = 0;
346         gint new_ury = 0;
347         GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes ();
348         int new_pagesize = -1;
349
350         g_return_if_fail (PS_IS_DOCUMENT (gs));
351
352         if (new_pagesize == -1) {
353                 new_pagesize = DEFAULT_PAGE_SIZE;
354                 if (gs->doc) {
355                 /* If we have a document:
356                  * We use -- the page size (if specified)
357                  * or the doc. size (if specified)
358                  * or the page bbox (if specified)
359                  * or the bounding box
360                  */
361                         if ((page >= 0) && (gs->doc->numpages > page) &&
362                             (gs->doc->pages) && (gs->doc->pages[page].size)) {
363                                 new_pagesize = gs->doc->pages[page].size - gs->doc->size;
364                         } else if (gs->doc->default_page_size != NULL) {
365                                 new_pagesize = gs->doc->default_page_size - gs->doc->size;
366                         } else if ((page >= 0) &&
367                                    (gs->doc->numpages > page) &&
368                                    (gs->doc->pages) &&
369                                    (gs->doc->pages[page].boundingbox[URX] >
370                                     gs->doc->pages[page].boundingbox[LLX]) &&
371                                    (gs->doc->pages[page].boundingbox[URY] >
372                                     gs->doc->pages[page].boundingbox[LLY])) {
373                                 new_pagesize = -1;
374                         } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
375                                    (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
376                                 new_pagesize = -1;
377                         }
378                 }
379         }
380
381         /* Compute bounding box */
382         if (gs->doc && (gs->doc->epsf || new_pagesize == -1)) {    /* epsf or bbox */
383                 if ((page >= 0) &&
384                     (gs->doc->pages) &&
385                     (gs->doc->pages[page].boundingbox[URX] >
386                      gs->doc->pages[page].boundingbox[LLX]) &&
387                     (gs->doc->pages[page].boundingbox[URY] >
388                      gs->doc->pages[page].boundingbox[LLY])) {
389                         /* use page bbox */
390                         new_llx = gs->doc->pages[page].boundingbox[LLX];
391                         new_lly = gs->doc->pages[page].boundingbox[LLY];
392                         new_urx = gs->doc->pages[page].boundingbox[URX];
393                         new_ury = gs->doc->pages[page].boundingbox[URY];
394                 } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
395                            (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
396                         /* use doc bbox */
397                         new_llx = gs->doc->boundingbox[LLX];
398                         new_lly = gs->doc->boundingbox[LLY];
399                         new_urx = gs->doc->boundingbox[URX];
400                         new_ury = gs->doc->boundingbox[URY];
401                 }
402         } else {
403                 if (new_pagesize < 0)
404                         new_pagesize = DEFAULT_PAGE_SIZE;
405                 new_llx = new_lly = 0;
406                 if (gs->doc && gs->doc->size &&
407                     (new_pagesize < gs->doc->numsizes)) {
408                         new_urx = gs->doc->size[new_pagesize].width;
409                         new_ury = gs->doc->size[new_pagesize].height;
410                 } else {
411                         new_urx = papersizes[new_pagesize].width;
412                         new_ury = papersizes[new_pagesize].height;
413                 }
414         }
415
416         if (new_urx <= new_llx)
417                 new_urx = papersizes[12].width;
418         if (new_ury <= new_lly)
419                 new_ury = papersizes[12].height;
420
421         *urx = new_urx;
422         *ury = new_ury;
423         *llx = new_llx;
424         *lly = new_lly;
425 }
426
427 static int
428 get_page_orientation (PSDocument *gs, int page)
429 {
430         int orientation;
431
432         orientation = GTK_GS_ORIENTATION_NONE;
433
434         if (gs->structured_doc) {
435                 orientation = gs->doc->pages[page].orientation;
436         }
437         if (orientation == GTK_GS_ORIENTATION_NONE) {
438                 orientation = gs->doc->default_page_orientation;
439         }
440         if (orientation == GTK_GS_ORIENTATION_NONE) {
441                 orientation = gs->doc->orientation;
442         }
443         if (orientation == GTK_GS_ORIENTATION_NONE) {
444                 orientation = GTK_GS_ORIENTATION_PORTRAIT;
445         }
446         if (gs->orientation != GTK_GS_ORIENTATION_NONE) {
447                 orientation = gs->orientation;
448         }
449
450         return orientation;
451 }
452
453 static void
454 setup_page (PSDocument *gs, int page, double scale)
455 {
456         char buf[1024];
457         int urx, ury, llx, lly, orientation;
458 #ifdef HAVE_LOCALE_H
459         char *savelocale;
460 #endif
461
462         LOG ("Setup the page");
463
464 #ifdef HAVE_LOCALE_H
465         /* gs needs floating point parameters with '.' as decimal point
466          * while some (european) locales use ',' instead, so we set the 
467          * locale for this snprintf to "C".
468          */
469         savelocale = setlocale (LC_NUMERIC, "C");
470 #endif
471         get_page_box (gs, page, &urx, &ury, &llx, &lly);
472         orientation = get_page_orientation (gs, page);
473
474         g_snprintf (buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
475                     0L, orientation * 90, llx, lly, urx, ury,
476                     get_xdpi (gs) * scale,
477                     get_ydpi (gs) * scale,
478                     0, 0, 0, 0);
479         LOG ("GS property %s", buf);
480
481 #ifdef HAVE_LOCALE_H
482         setlocale(LC_NUMERIC, savelocale);
483 #endif
484         gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom,
485                              8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen(buf));
486         gdk_flush ();
487 }
488
489 static void
490 close_pipe (int p[2])
491 {
492         if (p[0] != -1) {
493                 close (p[0]);
494         }
495         if (p[1] != -1) {
496                 close (p[1]);
497         }
498 }
499
500 static gboolean
501 is_interpreter_ready (PSDocument *gs)
502 {
503         return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
504 }
505
506 static void
507 output (gpointer data, gint source, GdkInputCondition condition)
508 {
509         char buf[MAX_BUFSIZE + 1];
510         guint bytes = 0;
511         PSDocument *gs = PS_DOCUMENT(data);
512
513         if (source == gs->interpreter_output) {
514                 bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
515                 if (bytes == 0) {            /* EOF occurred */
516                         close (gs->interpreter_output);
517                         gs->interpreter_output = -1;
518                         gdk_input_remove (gs->interpreter_output_id);
519                         return;
520                 } else if (bytes == -1) {
521                         /* trouble... */
522                         interpreter_failed (gs, NULL);
523                         return;
524                 }
525                 if (gs->interpreter_err == -1) {
526                         interpreter_failed (gs, NULL);
527                 }
528         } else if (source == gs->interpreter_err) {
529                 bytes = read (gs->interpreter_err, buf, MAX_BUFSIZE);
530                 if (bytes == 0) {            /* EOF occurred */
531                         close (gs->interpreter_err);
532                         gs->interpreter_err = -1;
533                         gdk_input_remove (gs->interpreter_error_id);
534                         return;
535                 } else if (bytes == -1) {
536                         /* trouble... */
537                         interpreter_failed (gs, NULL);
538                         return;
539                 }
540                 if (gs->interpreter_output == -1) {
541                         interpreter_failed(gs, NULL);
542                 }
543         }
544
545         if (bytes > 0) {
546                 buf[bytes] = '\0';
547                 printf ("%s", buf);
548         }
549 }
550
551 static void
552 catchPipe (int i)
553 {
554         broken_pipe = True;
555 }
556
557 static void
558 input(gpointer data, gint source, GdkInputCondition condition)
559 {
560         PSDocument *gs = PS_DOCUMENT(data);
561         int bytes_written;
562         void (*oldsig) (int);
563         oldsig = signal(SIGPIPE, catchPipe);
564
565         LOG ("Input");
566
567         do {
568                 if (gs->buffer_bytes_left == 0) {
569                         /* Get a new section if required */
570                         if (gs->ps_input && gs->bytes_left == 0) {
571                                 struct record_list *ps_old = gs->ps_input;
572                                 gs->ps_input = ps_old->next;
573                                 if (ps_old->close && NULL != ps_old->fp)
574                                         fclose (ps_old->fp);
575                                 g_free (ps_old);
576                         }
577
578                         /* Have to seek at the beginning of each section */
579                         if (gs->ps_input && gs->ps_input->seek_needed) {
580                                 fseek (gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
581                                 gs->ps_input->seek_needed = FALSE;
582                                 gs->bytes_left = gs->ps_input->len;
583                         }
584
585                         if (gs->bytes_left > MAX_BUFSIZE) {
586                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof(char),
587                                                                MAX_BUFSIZE, gs->ps_input->fp);
588                         } else if (gs->bytes_left > 0) {
589                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof(char),
590                                                                gs->bytes_left, gs->ps_input->fp);
591                         } else {
592                                 gs->buffer_bytes_left = 0;
593                         }
594                         if (gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
595                                 interpreter_failed (gs, NULL); /* Error occurred */
596                         }
597                         gs->input_buffer_ptr = gs->input_buffer;
598                         gs->bytes_left -= gs->buffer_bytes_left;
599                 }
600
601                 if (gs->buffer_bytes_left > 0) {
602                         bytes_written = write (gs->interpreter_input,
603                                                gs->input_buffer_ptr, gs->buffer_bytes_left);
604
605                         if (broken_pipe) {
606                                 interpreter_failed (gs, g_strdup(_("Broken pipe.")));
607                                 broken_pipe = FALSE;
608                                 interpreter_failed (gs, NULL);
609                         } else if (bytes_written == -1) {
610                                 if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
611                                         interpreter_failed (gs, NULL);   /* Something bad happened */
612                                 }
613                                 } else {
614                                 gs->buffer_bytes_left -= bytes_written;
615                                 gs->input_buffer_ptr += bytes_written;
616                         }
617                 }
618         } while (gs->ps_input && gs->buffer_bytes_left == 0);
619
620         signal (SIGPIPE, oldsig);
621
622         if (gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
623                 if (gs->interpreter_input_id != 0) {
624                         gdk_input_remove (gs->interpreter_input_id);
625                         gs->interpreter_input_id = 0;
626                 }
627         }
628 }
629
630 static int
631 start_interpreter (PSDocument *gs)
632 {
633         int std_in[2] = { -1, -1 };   /* pipe to interp stdin */
634         int std_out[2];               /* pipe from interp stdout */
635         int std_err[2];               /* pipe from interp stderr */
636
637 #define NUM_ARGS    100
638 #define NUM_GS_ARGS (NUM_ARGS - 20)
639 #define NUM_ALPHA_ARGS 10
640
641         char *argv[NUM_ARGS], *dir, *gv_env;
642         char **gs_args, **alpha_args = NULL;
643         int argc = 0, i;
644
645         LOG ("Start the interpreter");
646
647         if(!gs->gs_filename)
648                 return 0;
649
650         stop_interpreter(gs);
651
652         /* set up the args... */
653         gs_args = g_strsplit (gtk_gs_defaults_get_interpreter_cmd (), " ", NUM_GS_ARGS);
654         for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) {
655                 argv[argc] = gs_args[i];
656         }
657
658         alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
659         for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) {
660                 argv[argc] = alpha_args[i];
661         }
662
663         argv[argc++] = "-dNOPAUSE";
664         argv[argc++] = "-dQUIET";
665         argv[argc++] = "-dSAFER";
666
667         /* set up the pipes */
668         if (gs->send_filename_to_gs) {
669                 argv[argc++] = PS_DOCUMENT_GET_PS_FILE (gs);
670                 argv[argc++] = "-c";
671                 argv[argc++] = "quit";
672         } else {
673                 argv[argc++] = "-";
674         }
675
676         argv[argc++] = NULL;
677
678         if (!gs->reading_from_pipe && !gs->send_filename_to_gs) {
679                 if (pipe (std_in) == -1) {
680                         g_critical ("Unable to open pipe to Ghostscript.");
681                         return -1;
682                 }
683         }
684
685         if (pipe (std_out) == -1) {
686                 close_pipe (std_in);
687                 return -1;
688         }
689
690         if (pipe(std_err) == -1) {
691                 close_pipe (std_in);
692                 close_pipe (std_out);
693                 return -1;
694         }
695
696         gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld",
697                                   gdk_x11_drawable_get_xid (gs->pstarget),
698                                   gdk_x11_drawable_get_xid (gs->bpixmap));
699         LOG ("Launching ghostview with env %s", gv_env);
700
701         gs->interpreter_pid = fork ();
702         switch (gs->interpreter_pid) {
703                 case -1:                     /* error */
704                         close_pipe (std_in);
705                         close_pipe (std_out);
706                         close_pipe (std_err);
707                         return -2;
708                         break;
709                 case 0:                      /* child */
710                         close (std_out[0]);
711                         dup2 (std_out[1], 1);
712                         close (std_out[1]);
713
714                         close (std_err[0]);
715                         dup2 (std_err[1], 2);
716                         close (std_err[1]);
717
718                         if (!gs->reading_from_pipe) {
719                                 if (gs->send_filename_to_gs) {
720                                         int stdinfd;
721                                         /* just in case gs tries to read from stdin */
722                                         stdinfd = open("/dev/null", O_RDONLY);
723                                         if (stdinfd != 0) {
724                                                 dup2(stdinfd, 0);
725                                                 close(stdinfd);
726                                         }
727                                 } else {
728                                         close (std_in[1]);
729                                         dup2 (std_in[0], 0);
730                                         close (std_in[0]);
731                                 }
732                         }
733
734                         putenv(gv_env);
735
736                         /* change to directory where the input file is. This helps
737                          * with postscript-files which include other files using
738                          * a relative path */
739                         dir = g_path_get_dirname (gs->gs_filename);
740                         chdir (dir);
741                         g_free (dir);
742
743                         execvp (argv[0], argv);
744
745                         /* Notify error */
746                         g_critical ("Unable to execute [%s]\n", argv[0]);
747                         g_strfreev (gs_args);
748                         g_free (gv_env);
749                         g_strfreev (alpha_args);
750                         _exit (1);
751                         break;
752                 default:                     /* parent */
753                         if (!gs->send_filename_to_gs && !gs->reading_from_pipe) {
754                                 int result;
755                                 close (std_in[0]);
756                                 /* use non-blocking IO for pipe to ghostscript */
757                                 result = fcntl (std_in[1], F_GETFL, 0);
758                                 fcntl (std_in[1], F_SETFL, result | O_NONBLOCK);
759                                 gs->interpreter_input = std_in[1];
760                         } else {
761                                 gs->interpreter_input = -1;
762                         }
763                         close (std_out[1]);
764
765                         gs->interpreter_output = std_out[0];
766                         close (std_err[1]);
767                         gs->interpreter_err = std_err[0];
768                         gs->interpreter_output_id =
769                                 gdk_input_add (std_out[0], GDK_INPUT_READ, output, gs);
770                         gs->interpreter_error_id =
771                                 gdk_input_add (std_err[0], GDK_INPUT_READ, output, gs);
772                         break;
773         }
774
775         return TRUE;
776 }
777
778 static void
779 stop_interpreter(PSDocument * gs)
780 {
781         if (gs->interpreter_pid > 0) {
782                 int status = 0;
783                 LOG ("Stop the interpreter");
784                 kill (gs->interpreter_pid, SIGTERM);
785                 while ((wait(&status) == -1) && (errno == EINTR));
786                 gs->interpreter_pid = -1;
787                 if (status == 1) {
788                         gs->gs_status = _("Interpreter failed.");
789                 }
790         }
791
792         if (gs->interpreter_input >= 0) {
793                 close (gs->interpreter_input);
794                 gs->interpreter_input = -1;
795                 if (gs->interpreter_input_id != 0) {
796                         gdk_input_remove(gs->interpreter_input_id);
797                         gs->interpreter_input_id = 0;
798                 }
799                 while (gs->ps_input) {
800                         struct record_list *ps_old = gs->ps_input;
801                         gs->ps_input = gs->ps_input->next;
802                         if (ps_old->close && NULL != ps_old->fp)
803                                 fclose (ps_old->fp);
804                         g_free (ps_old);
805                 }
806         }
807
808         if (gs->interpreter_output >= 0) {
809                 close (gs->interpreter_output);
810                 gs->interpreter_output = -1;
811                 if (gs->interpreter_output_id) {
812                         gdk_input_remove (gs->interpreter_output_id);
813                         gs->interpreter_output_id = 0;
814                 }
815         }
816
817         if (gs->interpreter_err >= 0) {
818                 close (gs->interpreter_err);
819                 gs->interpreter_err = -1;
820                 if (gs->interpreter_error_id) {
821                         gdk_input_remove (gs->interpreter_error_id);
822                         gs->interpreter_error_id = 0;
823                 }
824         }
825
826         gs->busy = FALSE;
827 }
828
829 /* If file exists and is a regular file then return its length, else -1 */
830 static gint
831 file_length (const gchar * filename)
832 {
833         struct stat stat_rec;
834
835         if (filename && (stat (filename, &stat_rec) == 0) && S_ISREG (stat_rec.st_mode))
836                 return stat_rec.st_size;
837         else
838                 return -1;
839 }
840
841 /* Test if file exists, is a regular file and its length is > 0 */
842 static gboolean
843 file_readable(const char *filename)
844 {
845         return (file_length (filename) > 0);
846 }
847
848 /*
849  * Decompress gs->gs_filename if necessary
850  * Set gs->filename_unc to the name of the uncompressed file or NULL.
851  * Error reporting via signal 'interpreter_message'
852  * Return name of input file to use or NULL on error..
853  */
854 static gchar *
855 check_filecompressed (PSDocument * gs)
856 {
857         FILE *file;
858         gchar buf[1024];
859         gchar *filename, *filename_unc, *filename_err, *cmdline;
860         const gchar *cmd;
861         int fd;
862
863         cmd = NULL;
864
865         if ((file = fopen(gs->gs_filename, "r")) &&
866             (fread (buf, sizeof(gchar), 3, file) == 3)) {
867                 if ((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
868                         /* file is gzipped or compressed */
869                         cmd = gtk_gs_defaults_get_ungzip_cmd ();
870                 } else if (strncmp (buf, "BZh", 3) == 0) {
871                         /* file is compressed with bzip2 */
872                         cmd = gtk_gs_defaults_get_unbzip2_cmd ();
873                 }
874         }
875
876         if (NULL != file)
877                 fclose(file);
878
879         if (!cmd)
880                 return gs->gs_filename;
881
882         /* do the decompression */
883         filename = g_shell_quote (gs->gs_filename);
884         filename_unc = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL);
885         if ((fd = mkstemp (filename_unc)) < 0) {
886                 g_free (filename_unc);
887                 g_free (filename);
888                 return NULL;
889         }
890         close (fd);
891
892         filename_err = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL);
893         if ((fd = mkstemp(filename_err)) < 0) {
894                 g_free (filename_err);
895                 g_free (filename_unc);
896                 g_free (filename);
897                 return NULL;
898         }
899         close (fd);
900
901         cmdline = g_strdup_printf ("%s %s >%s 2>%s", cmd,
902                                    filename, filename_unc, filename_err);
903         if (system (cmdline) == 0 &&
904             file_readable (filename_unc) &&
905             file_length (filename_err) == 0) {
906                 /* sucessfully uncompressed file */
907                 gs->gs_filename_unc = filename_unc;
908         } else {
909                 /* report error */
910                 g_snprintf (buf, 1024, _("Error while decompressing file %s:\n"),
911                             gs->gs_filename);
912                 interpreter_failed (gs, buf);
913                 unlink (filename_unc);
914                 g_free (filename_unc);
915                 filename_unc = NULL;
916         }
917
918         unlink (filename_err);
919         g_free (filename_err);
920         g_free (cmdline);
921         g_free (filename);
922
923         return filename_unc;
924 }
925
926 static gint
927 ps_document_enable_interpreter(PSDocument *gs)
928 {
929         g_return_val_if_fail (PS_IS_DOCUMENT (gs), FALSE);
930
931         if (!gs->gs_filename)
932                 return 0;
933
934         return start_interpreter (gs);
935 }
936
937 static gboolean
938 document_load (PSDocument *gs, const gchar *fname)
939 {
940         g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE);
941
942         LOG ("Load the document");
943
944         if (fname == NULL) {
945                 gs->gs_status = "";
946                 return FALSE;
947         }
948
949         /* prepare this document */
950         gs->structured_doc = FALSE;
951         gs->send_filename_to_gs = TRUE;
952         gs->gs_filename = g_strdup (fname);
953
954         if ((gs->reading_from_pipe = (strcmp (fname, "-") == 0))) {
955                 gs->send_filename_to_gs = FALSE;
956         } else {
957                 /*
958                  * We need to make sure that the file is loadable/exists!
959                  * otherwise we want to exit without loading new stuff...
960                  */
961                 gchar *filename = NULL;
962
963                 if (!file_readable(fname)) {
964                         gchar buf[1024];
965
966                         g_snprintf (buf, 1024, _("Cannot open file %s.\n"), fname);
967                         interpreter_failed (gs, buf);
968                         gs->gs_status = _("File is not readable.");
969                 } else {
970                         filename = check_filecompressed(gs);
971                 }
972
973                 if (!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
974                         interpreter_failed (gs, NULL);
975                         return FALSE;
976                 }
977
978                 /* we grab the vital statistics!!! */
979                 gs->doc = psscan(gs->gs_psfile, TRUE, filename);
980
981                 if ((!gs->doc->epsf && gs->doc->numpages > 0) ||
982                     (gs->doc->epsf && gs->doc->numpages > 1)) {
983                         gs->structured_doc = TRUE;
984                         gs->send_filename_to_gs = FALSE;
985                 }
986         }
987
988         gs->gs_status = _("Document loaded.");
989
990         return TRUE;
991 }
992
993 static gboolean
994 ps_document_next_page (PSDocument *gs)
995 {
996         XEvent event;
997
998         LOG ("Make ghostscript render next page");
999
1000         g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE);
1001         g_return_val_if_fail (gs->interpreter_pid != 0, FALSE);
1002         g_return_val_if_fail (gs->busy != TRUE, FALSE);
1003
1004         gs->busy = TRUE;
1005
1006         event.xclient.type = ClientMessage;
1007         event.xclient.display = gdk_display;
1008         event.xclient.window = gs->message_window;
1009         event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1010         event.xclient.format = 32;
1011
1012         gdk_error_trap_push ();
1013         XSendEvent (gdk_display, gs->message_window, FALSE, 0, &event);
1014         gdk_flush ();
1015         gdk_error_trap_pop ();
1016
1017         return TRUE;
1018 }
1019
1020 static gboolean
1021 render_page (PSDocument *gs, int page)
1022 {
1023         g_return_val_if_fail(gs != NULL, FALSE);
1024         g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE);
1025
1026         if(!gs->gs_filename) {
1027                 return FALSE;
1028         }
1029
1030         if (gs->structured_doc && gs->doc) {
1031                 LOG ("It's a structured document, let's send one page to gs");
1032
1033                 if (is_interpreter_ready (gs)) {
1034                         ps_document_next_page (gs);
1035                 } else {
1036                         ps_document_enable_interpreter (gs);
1037                         send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1038                         send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1039                 }
1040
1041                 send_ps (gs, gs->doc->pages[page].begin,
1042                          gs->doc->pages[page].len, FALSE);
1043         } else {
1044                 /* Unstructured document
1045                  *
1046                  * In the case of non structured documents,
1047                  * GS read the PS from the  actual file (via command
1048                  * line. Hence, ggv only send a signal next page.
1049                  * If ghostview is not running it is usually because
1050                  * the last page of the file was displayed. In that
1051                  * case, ggv restarts GS again and the first page is displayed.
1052                  */
1053
1054                 LOG ("It's an unstructured document, gs will just read the file");
1055
1056                 if (!is_interpreter_ready (gs)) {
1057                         ps_document_enable_interpreter(gs);
1058                 }
1059                 ps_document_next_page(gs);
1060         }
1061
1062         return TRUE;
1063 }
1064
1065 static gboolean
1066 ps_document_load (EvDocument  *document,
1067                   const char  *uri,
1068                   GError     **error)
1069 {
1070         gboolean result;
1071         char *filename;
1072
1073         filename = g_filename_from_uri (uri, NULL, error);
1074         if (!filename)
1075                 return FALSE;
1076
1077         result = document_load (PS_DOCUMENT (document), filename);
1078         if (!result) {
1079                 g_set_error (error, G_FILE_ERROR,
1080                              G_FILE_ERROR_FAILED,
1081                              "Failed to load document '%s'\n",
1082                              uri);
1083         }
1084
1085         g_free (filename);
1086
1087         return result;
1088 }
1089
1090 static gboolean
1091 save_page_list (PSDocument *document, int *page_list, const char *filename)
1092 {
1093         gboolean result = TRUE;
1094         GtkGSDocSink *sink = gtk_gs_doc_sink_new ();
1095         FILE *f;
1096         gchar *buf;
1097
1098         pscopydoc (sink, document->gs_filename, document->doc, page_list);
1099         
1100         buf = gtk_gs_doc_sink_get_buffer (sink);
1101         
1102         f = fopen (filename, "w");
1103         if (f) {
1104                 fputs (buf, f);
1105                 fclose (f);
1106         } else {
1107                 result = FALSE;
1108         }
1109
1110         g_free (buf);
1111         gtk_gs_doc_sink_free (sink);
1112         g_free (sink);
1113
1114         return result;
1115 }
1116
1117 static gboolean
1118 ps_document_save (EvDocument  *document,
1119                   const char  *uri,
1120                   GError     **error)
1121 {
1122         PSDocument *ps = PS_DOCUMENT (document);
1123         int *page_list;
1124         gboolean result;
1125         int i;
1126         char *filename;
1127
1128         filename = g_filename_from_uri (uri, NULL, error);
1129         if (!filename)
1130                 return FALSE;
1131
1132         page_list = g_new0 (int, ps->doc->numpages);
1133         for (i = 0; i < ps->doc->numpages; i++) {
1134                 page_list[i] = 1;
1135         }
1136
1137         result = save_page_list (ps, page_list, filename);
1138
1139         g_free (page_list);
1140         g_free (filename);
1141
1142         return result;
1143 }
1144
1145 static int
1146 ps_document_get_n_pages (EvDocument  *document)
1147 {
1148         PSDocument *ps = PS_DOCUMENT (document);
1149
1150         g_return_val_if_fail (ps != NULL, -1);
1151
1152         if (!ps->gs_filename || !ps->doc) {
1153                 return -1;
1154         }
1155
1156         return ps->structured_doc ? ps->doc->numpages : 1;
1157 }
1158
1159 static void
1160 ps_document_get_page_size (EvDocument   *document,
1161                            int           page,
1162                            double       *width,
1163                            double       *height)
1164 {
1165         PSDocument *gs = PS_DOCUMENT (document);
1166         int w, h;
1167         int urx, ury, llx, lly, orientation;
1168
1169         get_page_box (PS_DOCUMENT (document), page, &urx, &ury, &llx, &lly);
1170         orientation = get_page_orientation (PS_DOCUMENT (document), page);
1171
1172         switch (orientation) {
1173                 case GTK_GS_ORIENTATION_PORTRAIT:
1174                 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1175                         w = (urx - llx) / 72.0 * get_xdpi (gs) + 0.5;
1176                         h = (ury - lly) / 72.0 * get_ydpi (gs) + 0.5;
1177                         break;
1178                 case GTK_GS_ORIENTATION_LANDSCAPE:
1179                 case GTK_GS_ORIENTATION_SEASCAPE:
1180                         w = (ury - lly) / 72.0 * get_xdpi (gs) + 0.5;
1181                         h = (urx - llx) / 72.0 * get_ydpi (gs) + 0.5;
1182                         break;
1183                 default:
1184                         w = h = 0;
1185                         g_assert_not_reached ();
1186                         break;
1187         }
1188
1189         if (width) {
1190                 *width = w;
1191         }
1192
1193         if (height) {
1194                 *height = h;
1195         }
1196 }
1197
1198 static gboolean
1199 ps_document_can_get_text (EvDocument *document)
1200 {
1201         return FALSE;
1202 }
1203
1204 static void
1205 ps_async_renderer_render_pixbuf (EvAsyncRenderer *renderer, int page, double scale)
1206 {
1207         PSDocument *gs = PS_DOCUMENT (renderer);
1208
1209         if (gs->pstarget == NULL) {
1210                 GtkWidget *widget;
1211
1212                 widget = gtk_window_new (GTK_WINDOW_POPUP);
1213                 gtk_widget_realize (widget);
1214                 gs->pstarget = widget->window;
1215
1216                 g_assert (gs->pstarget != NULL);
1217
1218                 g_signal_connect (widget, "event",
1219                                   G_CALLBACK (ps_document_widget_event),
1220                                   gs);
1221         }
1222
1223         setup_pixmap (gs, page, scale);
1224         setup_page (gs, page, scale);
1225
1226         render_page (gs, page);
1227 }
1228
1229 static EvDocumentInfo *
1230 ps_document_get_info (EvDocument *document)
1231 {
1232         EvDocumentInfo *info;
1233         PSDocument *ps = PS_DOCUMENT (document);
1234
1235         info = g_new0 (EvDocumentInfo, 1);
1236         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
1237                             EV_DOCUMENT_INFO_N_PAGES;
1238         info->title = g_strdup (ps->doc->title);
1239         info->n_pages = ev_document_get_n_pages (document);
1240
1241         return info;
1242 }
1243
1244 static EvOrientation
1245 ps_document_get_orientation (EvDocument *document)
1246 {
1247         EvOrientation orientation;
1248         PSDocument *ps = PS_DOCUMENT (document);
1249
1250         g_return_val_if_fail (ps != NULL, EV_ORIENTATION_PORTRAIT);
1251
1252         switch (ps->orientation) {
1253                 case GTK_GS_ORIENTATION_PORTRAIT:
1254                         orientation = EV_ORIENTATION_PORTRAIT;
1255                         break;
1256                 case GTK_GS_ORIENTATION_LANDSCAPE:
1257                         orientation = EV_ORIENTATION_LANDSCAPE;
1258                         break;
1259                 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1260                         orientation = EV_ORIENTATION_UPSIDEDOWN;
1261                         break;
1262                 case GTK_GS_ORIENTATION_SEASCAPE:
1263                         orientation = EV_ORIENTATION_SEASCAPE;
1264                         break;
1265                 default:
1266                         orientation = EV_ORIENTATION_PORTRAIT;
1267                         break;
1268         }
1269
1270         return orientation;
1271 }
1272
1273 static void
1274 ps_document_set_orientation (EvDocument *document, EvOrientation orientation)
1275 {
1276         PSDocument *ps = PS_DOCUMENT (document);
1277
1278         g_return_if_fail (ps != NULL);
1279
1280         switch (orientation) {
1281                 case EV_ORIENTATION_PORTRAIT:
1282                         ps->orientation = GTK_GS_ORIENTATION_PORTRAIT;
1283                         break;
1284                 case EV_ORIENTATION_LANDSCAPE:
1285                         ps->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1286                         break;
1287                 case EV_ORIENTATION_UPSIDEDOWN:
1288                         ps->orientation = GTK_GS_ORIENTATION_UPSIDEDOWN;
1289                         break;
1290                 case EV_ORIENTATION_SEASCAPE:
1291                         ps->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1292                         break;
1293         }
1294 }
1295
1296 static void
1297 ps_document_document_iface_init (EvDocumentIface *iface)
1298 {
1299         iface->load = ps_document_load;
1300         iface->save = ps_document_save;
1301         iface->can_get_text = ps_document_can_get_text;
1302         iface->get_n_pages = ps_document_get_n_pages;
1303         iface->get_page_size = ps_document_get_page_size;
1304         iface->get_info = ps_document_get_info;
1305         iface->set_orientation = ps_document_set_orientation;
1306         iface->get_orientation = ps_document_get_orientation;
1307 }
1308
1309 static void
1310 ps_async_renderer_iface_init (EvAsyncRendererIface *iface)
1311 {
1312         iface->render_pixbuf = ps_async_renderer_render_pixbuf;
1313 }
1314
1315 static void
1316 ps_document_ps_export_begin (EvPSExporter *exporter, const char *filename,
1317                              int first_page, int last_page)
1318 {
1319         PSDocument *document = PS_DOCUMENT (exporter);
1320
1321         g_free (document->ps_export_pagelist);
1322         
1323         document->ps_export_pagelist = g_new0 (int, document->doc->numpages);
1324         document->ps_export_filename = g_strdup (filename);
1325 }
1326
1327 static void
1328 ps_document_ps_export_do_page (EvPSExporter *exporter, int page)
1329 {
1330         PSDocument *document = PS_DOCUMENT (exporter);
1331         
1332         document->ps_export_pagelist[page] = 1;
1333 }
1334
1335 static void
1336 ps_document_ps_export_end (EvPSExporter *exporter)
1337 {
1338         PSDocument *document = PS_DOCUMENT (exporter);
1339
1340         save_page_list (document, document->ps_export_pagelist,
1341                         document->ps_export_filename);
1342
1343         g_free (document->ps_export_pagelist);
1344         g_free (document->ps_export_filename);  
1345         document->ps_export_pagelist = NULL;
1346         document->ps_export_filename = NULL;
1347 }
1348
1349 static void
1350 ps_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1351 {
1352         iface->begin = ps_document_ps_export_begin;
1353         iface->do_page = ps_document_ps_export_do_page;
1354         iface->end = ps_document_ps_export_end;
1355 }