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