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