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