]> www.fi.muni.cz Git - evince.git/blob - ps/ps-document.c
c1a94813fcf9e217daaa6e500f2aeb673d804caa
[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 /*
26 Ghostview interface to ghostscript
27
28 When the GHOSTVIEW environment variable is set, ghostscript draws on
29 an existing drawable rather than creating its own window.  Ghostscript
30 can be directed to draw on either a window or a pixmap.
31
32 Drawing on a Window
33
34 The GHOSTVIEW environment variable contains the window id of the target
35 window.  The window id is an integer.  Ghostscript will use the attributes
36 of the window to obtain the width, height, colormap, screen, and visual of
37 the window. The remainder of the information is gotten from the GHOSTVIEW
38 property on that window.
39
40
41 Drawing on a Pixmap
42
43 The GHOSTVIEW environment variable contains a window id and a pixmap id.
44 They are integers separated by white space.  Ghostscript will use the
45 attributes of the window to obtain the colormap, screen, and visual to use.
46 The width and height will be obtained from the pixmap. The remainder of the
47 information, is gotten from the GHOSTVIEW property on the window.  In this
48 case, the property is deleted when read.
49
50 The GHOSTVIEW environment variable
51
52 parameters:     window-id [pixmap-id]
53
54 scanf format:   "%d %d"
55
56 explanation of parameters:
57
58         window-id: tells ghostscript where to
59                     - read the GHOSTVIEW property
60                     - send events
61                     If pixmap-id is not present,
62                     ghostscript will draw on this window.
63
64         pixmap-id: If present, tells ghostscript that a pixmap will be used
65                     as the final destination for drawing.  The window will
66                     not be touched for drawing purposes.
67
68 The GHOSTVIEW property
69
70 type:   STRING
71
72 parameters:
73
74     bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right]
75
76 scanf format: "%d %d %d %d %d %d %f %f %d %d %d %d"
77
78 explanation of parameters:
79
80         bpixmap: pixmap id of the backing pixmap for the window.  If no
81                 pixmap is to be used, this parameter should be zero.  This
82                 parameter must be zero when drawing on a pixmap.
83
84         orient: orientation of the page.  The number represents clockwise
85                 rotation of the paper in degrees.  Permitted values are
86                 0, 90, 180, 270.
87
88         llx, lly, urx, ury: Bounding box of the drawable.  The bounding box
89                 is specified in PostScript points in default user coordinates.
90
91         xdpi, ydpi: Resolution of window.  (This can be derived from the
92                 other parameters, but not without roundoff error.  These
93                 values are included to avoid this error.)
94
95         left, bottom, top, right: (optional)
96                 Margins around the window.  The margins extend the imageable
97                 area beyond the boundaries of the window.  This is primarily
98                 used for popup zoom windows.  I have encountered several
99                 instances of PostScript programs that position themselves
100                 with respect to the imageable area.  The margins are specified
101                 in PostScript points.  If omitted, the margins are assumed to
102                 be 0.
103
104 Events from ghostscript
105
106 If the final destination is a pixmap, the client will get a property notify
107 event when ghostscript reads the GHOSTVIEW property causing it to be deleted.
108
109 Ghostscript sends events to the window where it read the GHOSTVIEW property.
110 These events are of type ClientMessage.  The message_type is set to
111 either PAGE or DONE.  The first long data value gives the window to be used
112 to send replies to ghostscript.  The second long data value gives the primary
113 drawable.  If rendering to a pixmap, it is the primary drawable.  If rendering
114 to a window, the backing pixmap is the primary drawable.  If no backing pixmap
115 is employed, then the window is the primary drawable.  This field is necessary
116 to distinguish multiple ghostscripts rendering to separate pixmaps where the
117 GHOSTVIEW property was placed on the same window.
118
119 The PAGE message indicates that a "page" has completed.  Ghostscript will
120 wait until it receives a ClientMessage whose message_type is NEXT before
121 continuing.
122
123 The DONE message indicates that ghostscript has finished processing.
124
125 */
126
127 #include "config.h"
128 #include <string.h>
129 #include <stdlib.h>
130 #include <signal.h>
131 #include <gtk/gtk.h>
132 #include <gtk/gtkobject.h>
133 #include <gdk/gdkprivate.h>
134 #include <gdk/gdkx.h>
135 #include <gdk/gdk.h>
136 #include <glib/gi18n.h>
137 #ifdef  HAVE_XINERAMA
138 #   include <gdk/gdkx.h>
139 #   include <X11/extensions/Xinerama.h>
140 #endif /* HAVE_XINERAMA */
141 #include <X11/Intrinsic.h>
142 #include <unistd.h>
143 #include <fcntl.h>
144 #include <stdlib.h>
145 #include <errno.h>
146 #include <sys/stat.h>
147 #include <sys/types.h>
148 #include <sys/wait.h>
149 #include <stdio.h>
150 #include <math.h>
151
152 #include "ps-document.h"
153 #include "ev-debug.h"
154 #include "gsdefaults.h"
155
156 #ifdef HAVE_LOCALE_H
157 #   include <locale.h>
158 #endif
159
160 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
161 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
162 #   define O_NONBLOCK O_NDELAY
163 #endif
164
165 #define PS_DOCUMENT_WATCH_INTERVAL 1000
166 #define PS_DOCUMENT_WATCH_TIMEOUT  2
167
168 #define MAX_BUFSIZE 1024
169
170 #define PS_DOCUMENT_IS_COMPRESSED(gs)       (PS_DOCUMENT(gs)->gs_filename_unc != NULL)
171 #define PS_DOCUMENT_GET_PS_FILE(gs)         (PS_DOCUMENT_IS_COMPRESSED(gs) ? \
172                                         PS_DOCUMENT(gs)->gs_filename_unc : \
173                                         PS_DOCUMENT(gs)->gs_filename)
174
175 enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL };
176
177 enum {
178         PROP_0,
179         PROP_TITLE
180 };
181
182 /* structure to describe section of file to send to ghostscript */
183 struct record_list {
184   FILE *fp;
185   long begin;
186   guint len;
187   gboolean seek_needed;
188   gboolean close;
189   struct record_list *next;
190 };
191
192 static gboolean broken_pipe = FALSE;
193
194 static void
195 catchPipe(int i)
196 {
197   broken_pipe = True;
198 }
199
200 /* Forward declarations */
201 static void ps_document_init(PSDocument * gs);
202 static void ps_document_class_init(PSDocumentClass * klass);
203 static void ps_document_emit_error_msg(PSDocument * gs, const gchar * msg);
204 static void ps_document_finalize(GObject * object);
205 static void send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close);
206 static void set_up_page(PSDocument * gs);
207 static void close_pipe(int p[2]);
208 static void interpreter_failed(PSDocument * gs);
209 static float compute_xdpi(void);
210 static float compute_ydpi(void);
211 static gboolean compute_size(PSDocument * gs);
212 static void output(gpointer data, gint source, GdkInputCondition condition);
213 static void input(gpointer data, gint source, GdkInputCondition condition);
214 static void stop_interpreter(PSDocument * gs);
215 static gint start_interpreter(PSDocument * gs);
216 gboolean computeSize(void);
217 static gboolean ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid);
218 static void ps_document_document_iface_init (EvDocumentIface *iface);
219 static gboolean ps_document_goto_page(PSDocument * gs, gint page);
220
221 static GObjectClass *parent_class = NULL;
222
223 static PSDocumentClass *gs_class = NULL;
224
225 static void
226 ps_document_init(PSDocument * gs)
227 {
228   gs->bpixmap = NULL;
229
230   gs->current_page = 0;
231   gs->disable_start = FALSE;
232   gs->interpreter_pid = -1;
233
234   gs->width = -1;
235   gs->height = -1;
236   gs->busy = FALSE;
237   gs->changed = FALSE;
238   gs->gs_scanstyle = 0;
239   gs->gs_filename = 0;
240   gs->gs_filename_dsc = 0;
241   gs->gs_filename_unc = 0;
242
243   broken_pipe = FALSE;
244
245   gs->structured_doc = FALSE;
246   gs->reading_from_pipe = FALSE;
247   gs->send_filename_to_gs = FALSE;
248
249   gs->doc = NULL;
250   gs->loaded = FALSE;
251
252   gs->interpreter_input = -1;
253   gs->interpreter_output = -1;
254   gs->interpreter_err = -1;
255   gs->interpreter_input_id = 0;
256   gs->interpreter_output_id = 0;
257   gs->interpreter_error_id = 0;
258
259   gs->ps_input = NULL;
260   gs->input_buffer = NULL;
261   gs->input_buffer_ptr = NULL;
262   gs->bytes_left = 0;
263   gs->buffer_bytes_left = 0;
264
265   gs->llx = 0;
266   gs->lly = 0;
267   gs->urx = 0;
268   gs->ury = 0;
269   gs->xdpi = compute_xdpi();
270   gs->ydpi = compute_ydpi();
271
272   gs->left_margin = 0;
273   gs->top_margin = 0;
274   gs->right_margin = 0;
275   gs->bottom_margin = 0;
276
277   gs->page_x_offset = 0;
278   gs->page_y_offset = 0;
279
280   /* Set user defined defaults */
281   gs->override_orientation = gtk_gs_defaults_get_override_orientation();
282   gs->fallback_orientation = gtk_gs_defaults_get_orientation();
283   gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
284   gs->default_size = gtk_gs_defaults_get_size();
285   gs->antialiased = gtk_gs_defaults_get_antialiased();
286   gs->override_size = gtk_gs_defaults_get_override_size();
287   gs->respect_eof = gtk_gs_defaults_get_respect_eof();
288   gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
289
290   gs->gs_status = _("No document loaded.");
291 }
292
293 static void
294 ps_document_set_property (GObject *object,
295                           guint prop_id,
296                           const GValue *value,
297                           GParamSpec *pspec)
298 {
299         switch (prop_id)
300
301         {
302                 case PROP_TITLE:
303                         /* read only */
304                         break;
305         }
306 }
307
308 static void
309 ps_document_get_property (GObject *object,
310                           guint prop_id,
311                           GValue *value,
312                           GParamSpec *pspec)
313 {
314         PSDocument *ps = PS_DOCUMENT (object);
315
316         switch (prop_id)
317         {
318                 case PROP_TITLE:
319                         if (ps->doc) {
320                                 g_value_set_string (value, ps->doc->title);
321                         } else {
322                                 g_value_set_string (value, NULL);
323                         }
324                         break;
325         }
326 }
327
328 static void
329 ps_document_class_init(PSDocumentClass *klass)
330 {
331   GObjectClass *object_class;
332
333   object_class = (GObjectClass *) klass;
334   parent_class = g_type_class_peek_parent (klass);
335   gs_class = klass;
336
337   object_class->finalize = ps_document_finalize;
338   object_class->get_property = ps_document_get_property;
339   object_class->set_property = ps_document_set_property;
340
341   /* Create atoms */
342   klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
343   klass->next_atom = gdk_atom_intern("NEXT", FALSE);
344   klass->page_atom = gdk_atom_intern("PAGE", FALSE);
345   klass->string_atom = gdk_atom_intern("STRING", FALSE);
346
347   gtk_gs_defaults_load();
348
349   g_object_class_override_property (object_class, PROP_TITLE, "title");
350 }
351
352 /* Clean all memory and temporal files */
353 static void
354 ps_document_cleanup(PSDocument * gs)
355 {
356   g_return_if_fail(gs != NULL);
357   g_return_if_fail(GTK_IS_GS(gs));
358
359   stop_interpreter(gs);
360
361   if(gs->gs_psfile) {
362     fclose(gs->gs_psfile);
363     gs->gs_psfile = NULL;
364   }
365   if(gs->gs_filename) {
366     g_free(gs->gs_filename);
367     gs->gs_filename = NULL;
368   }
369   if(gs->doc) {
370     psfree(gs->doc);
371     gs->doc = NULL;
372   }
373   if(gs->gs_filename_dsc) {
374     unlink(gs->gs_filename_dsc);
375     g_free(gs->gs_filename_dsc);
376     gs->gs_filename_dsc = NULL;
377   }
378   if(gs->gs_filename_unc) {
379     unlink(gs->gs_filename_unc);
380     g_free(gs->gs_filename_unc);
381     gs->gs_filename_unc = NULL;
382   }
383   gs->current_page = 0;
384   gs->loaded = FALSE;
385   gs->llx = 0;
386   gs->lly = 0;
387   gs->urx = 0;
388   gs->ury = 0;
389   set_up_page(gs);
390 }
391
392 static gboolean
393 ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
394 {
395         PSDocument *gs = (PSDocument *) data;
396
397         if(event->type != GDK_CLIENT_EVENT)
398                 return FALSE;
399
400         gs->message_window = event->client.data.l[0];
401
402         if (event->client.message_type == gs_class->page_atom) {
403                 LOG ("GS rendered the document");
404                 gs->busy = FALSE;
405
406                 if (gs->scaling) {
407                         ev_document_scale_changed (EV_DOCUMENT (gs));
408                         gs->scaling = FALSE;
409                 } else {
410                         ev_document_page_changed (EV_DOCUMENT (gs));
411                 }
412         }
413
414         return TRUE;
415 }
416
417 static void
418 ps_document_set_target (EvDocument  *document,
419                         GdkDrawable *target)
420 {
421         PSDocument *gs = PS_DOCUMENT (document);
422         GtkWidget *widget;
423         gpointer data;
424
425         if (gs->pstarget) {
426                 gdk_window_get_user_data (gs->pstarget, &data);
427                 g_return_if_fail (GTK_IS_WIDGET (data));
428
429                 widget = GTK_WIDGET (data);
430                 g_signal_handlers_disconnect_by_func
431                         (widget, ps_document_widget_event, document);
432         }
433
434         gs->pstarget = target;
435
436         if (gs->pstarget) {
437                 gdk_window_get_user_data (gs->pstarget, &data);
438                 g_return_if_fail (GTK_IS_WIDGET (data));
439
440                 widget = GTK_WIDGET (data);
441                 g_signal_connect (widget, "event",
442                                   G_CALLBACK (ps_document_widget_event),
443                                   document);
444         }
445
446         ps_document_goto_page (gs, gs->current_page);
447 }
448
449 static void
450 ps_document_finalize (GObject * object)
451 {
452         PSDocument *gs;
453
454         g_return_if_fail (object != NULL);
455         g_return_if_fail (GTK_IS_GS (object));
456
457         LOG ("Finalize");
458
459         gs = PS_DOCUMENT (object);
460
461         ps_document_cleanup (gs);
462         stop_interpreter (gs);
463
464         ps_document_set_target (EV_DOCUMENT (object), NULL);
465
466         if(gs->input_buffer) {
467                 g_free(gs->input_buffer);
468                 gs->input_buffer = NULL;
469         }
470
471         (*G_OBJECT_CLASS(parent_class)->finalize) (object);
472 }
473
474 static void
475 send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close)
476 {
477   struct record_list *ps_new;
478
479   if(gs->interpreter_input < 0) {
480     g_critical("No pipe to gs: error in send_ps().");
481     return;
482   }
483
484   ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
485   ps_new->fp = gs->gs_psfile;
486   ps_new->begin = begin;
487   ps_new->len = len;
488   ps_new->seek_needed = TRUE;
489   ps_new->close = close;
490   ps_new->next = NULL;
491
492   if(gs->input_buffer == NULL) {
493     gs->input_buffer = g_malloc(MAX_BUFSIZE);
494   }
495
496   if(gs->ps_input == NULL) {
497     gs->input_buffer_ptr = gs->input_buffer;
498     gs->bytes_left = len;
499     gs->buffer_bytes_left = 0;
500     gs->ps_input = ps_new;
501     gs->interpreter_input_id =
502       gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
503   }
504   else {
505     struct record_list *p = gs->ps_input;
506     while(p->next != NULL) {
507       p = p->next;
508     }
509     p->next = ps_new;
510   }
511 }
512
513 static gint
514 ps_document_get_orientation(PSDocument * gs)
515 {
516   g_return_val_if_fail(gs != NULL, -1);
517   g_return_val_if_fail(GTK_IS_GS(gs), -1);
518
519   if(gs->doc) {
520     if(gs->structured_doc) {
521       if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
522          GTK_GS_ORIENTATION_NONE)
523         gs->real_orientation =
524           gs->doc->pages[MAX(gs->current_page, 0)].orientation;
525       else
526         gs->real_orientation = gs->doc->default_page_orientation;
527     }
528
529     if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
530       gs->real_orientation = gs->doc->orientation;
531   }
532
533   if(gs->override_orientation ||
534      gs->real_orientation == GTK_GS_ORIENTATION_NONE)
535     return gs->fallback_orientation;
536   else
537     return gs->real_orientation;
538 }
539
540 static void
541 set_up_page(PSDocument * gs)
542 {
543   guint orientation;
544   char buf[1024];
545   //GdkColormap *colormap;
546   GdkGC *fill;
547   GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
548   GdkColormap *colormap;
549   gboolean size_changed;
550
551   LOG ("Setup the page");
552
553 #ifdef HAVE_LOCALE_H
554   char *savelocale;
555 #endif
556
557   size_changed = compute_size (gs);
558
559   if (gs->pstarget == NULL)
560     return;
561
562   /* Do we have to check if the actual geometry changed? */
563
564   stop_interpreter(gs);
565
566   orientation = ps_document_get_orientation(gs);
567
568   if (size_changed || gs->bpixmap == NULL) {
569     gdk_flush();
570
571     /* clear new pixmap (set to white) */
572     fill = gdk_gc_new(gs->pstarget);
573     if(fill) {
574       colormap = gdk_drawable_get_colormap(gs->pstarget);
575       gdk_color_alloc (colormap, &white);
576       gdk_gc_set_foreground(fill, &white);
577
578       if(gs->width > 0 && gs->height > 0) {
579         if(gs->bpixmap) {
580           gdk_drawable_unref(gs->bpixmap);
581           gs->bpixmap = NULL;
582         }
583
584         LOG ("Create our internal pixmap");
585         gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
586
587         gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
588                            0, 0, gs->width, gs->height);
589       }
590       else {
591         gdk_draw_rectangle(gs->pstarget, fill, TRUE,
592                            0, 0, gs->width, gs->height);
593       }
594       gdk_gc_unref(fill);
595
596       gdk_flush();
597     }
598   }
599
600 #ifdef HAVE_LOCALE_H
601   /* gs needs floating point parameters with '.' as decimal point
602    * while some (european) locales use ',' instead, so we set the 
603    * locale for this snprintf to "C".
604    */
605   savelocale = setlocale(LC_NUMERIC, "C");
606 #endif
607
608   g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
609              0L,
610              orientation * 90,
611              gs->llx,
612              gs->lly,
613              gs->urx,
614              gs->ury,
615              gs->xdpi * gs->zoom_factor,
616              gs->ydpi * gs->zoom_factor,
617              gs->left_margin,
618              gs->bottom_margin, gs->right_margin, gs->top_margin);
619
620   LOG ("GS property %s", buf);
621
622 #ifdef HAVE_LOCALE_H
623   setlocale(LC_NUMERIC, savelocale);
624 #endif
625   gdk_property_change(gs->pstarget,
626                       gs_class->gs_atom,
627                       gs_class->string_atom,
628                       8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
629   gdk_flush();
630 }
631
632 static void
633 close_pipe(int p[2])
634 {
635   if(p[0] != -1)
636     close(p[0]);
637   if(p[1] != -1)
638     close(p[1]);
639 }
640
641 static gboolean
642 is_interpreter_ready(PSDocument * gs)
643 {
644   return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
645 }
646
647 static void
648 interpreter_failed(PSDocument * gs)
649 {
650   stop_interpreter(gs);
651 }
652
653 static void
654 output(gpointer data, gint source, GdkInputCondition condition)
655 {
656   char buf[MAX_BUFSIZE + 1], *msg;
657   guint bytes = 0;
658   PSDocument *gs = PS_DOCUMENT(data);
659
660   if(source == gs->interpreter_output) {
661     bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
662     if(bytes == 0) {            /* EOF occurred */
663       close(gs->interpreter_output);
664       gs->interpreter_output = -1;
665       gdk_input_remove(gs->interpreter_output_id);
666       return;
667     }
668     else if(bytes == -1) {
669       /* trouble... */
670       interpreter_failed(gs);
671       return;
672     }
673     if(gs->interpreter_err == -1) {
674       stop_interpreter(gs);
675     }
676   }
677   else if(source == gs->interpreter_err) {
678     bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
679     if(bytes == 0) {            /* EOF occurred */
680       close(gs->interpreter_err);
681       gs->interpreter_err = -1;
682       gdk_input_remove(gs->interpreter_error_id);
683       return;
684     }
685     else if(bytes == -1) {
686       /* trouble... */
687       interpreter_failed(gs);
688       return;
689     }
690     if(gs->interpreter_output == -1) {
691       stop_interpreter(gs);
692     }
693   }
694   if(bytes > 0) {
695     buf[bytes] = '\0';
696     msg = g_strdup(buf);
697     ps_document_emit_error_msg (gs, msg);   
698   }
699 }
700
701 static void
702 input(gpointer data, gint source, GdkInputCondition condition)
703 {
704   PSDocument *gs = PS_DOCUMENT(data);
705   int bytes_written;
706   void (*oldsig) (int);
707   oldsig = signal(SIGPIPE, catchPipe);
708
709   do {
710     if(gs->buffer_bytes_left == 0) {
711       /* Get a new section if required */
712       if(gs->ps_input && gs->bytes_left == 0) {
713         struct record_list *ps_old = gs->ps_input;
714         gs->ps_input = ps_old->next;
715         if(ps_old->close && NULL != ps_old->fp)
716           fclose(ps_old->fp);
717         g_free((char *) ps_old);
718       }
719       /* Have to seek at the beginning of each section */
720       if(gs->ps_input && gs->ps_input->seek_needed) {
721         fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
722         gs->ps_input->seek_needed = FALSE;
723         gs->bytes_left = gs->ps_input->len;
724       }
725
726       if(gs->bytes_left > MAX_BUFSIZE) {
727         gs->buffer_bytes_left =
728           fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
729       }
730       else if(gs->bytes_left > 0) {
731         gs->buffer_bytes_left =
732           fread(gs->input_buffer,
733                 sizeof(char), gs->bytes_left, gs->ps_input->fp);
734       }
735       else {
736         gs->buffer_bytes_left = 0;
737       }
738       if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
739         interpreter_failed(gs); /* Error occurred */
740       }
741       gs->input_buffer_ptr = gs->input_buffer;
742       gs->bytes_left -= gs->buffer_bytes_left;
743     }
744
745     if(gs->buffer_bytes_left > 0) {
746       /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
747
748       bytes_written = write(gs->interpreter_input,
749                             gs->input_buffer_ptr, gs->buffer_bytes_left);
750
751       if(broken_pipe) {
752         ps_document_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
753         broken_pipe = FALSE;
754         interpreter_failed(gs);
755       }
756       else if(bytes_written == -1) {
757         if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
758           interpreter_failed(gs);   /* Something bad happened */
759         }
760       }
761       else {
762         gs->buffer_bytes_left -= bytes_written;
763         gs->input_buffer_ptr += bytes_written;
764       }
765     }
766   }
767   while(gs->ps_input && gs->buffer_bytes_left == 0);
768
769   signal(SIGPIPE, oldsig);
770
771   if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
772     if(gs->interpreter_input_id != 0) {
773       gdk_input_remove(gs->interpreter_input_id);
774       gs->interpreter_input_id = 0;
775     }
776   }
777 }
778
779 static int
780 start_interpreter(PSDocument * gs)
781 {
782   int std_in[2] = { -1, -1 };   /* pipe to interp stdin */
783   int std_out[2];               /* pipe from interp stdout */
784   int std_err[2];               /* pipe from interp stderr */
785
786   LOG ("Start the interpreter");
787
788 #define NUM_ARGS    100
789 #define NUM_GS_ARGS (NUM_ARGS - 20)
790 #define NUM_ALPHA_ARGS 10
791
792   char *argv[NUM_ARGS], *dir, *gv_env;
793   char **gs_args, **alpha_args = NULL;
794   int argc = 0, i;
795
796   if(!gs->gs_filename)
797     return 0;
798
799   stop_interpreter(gs);
800
801   if(gs->disable_start == TRUE)
802     return 0;
803
804   /* set up the args... */
805   gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
806   for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
807     argv[argc] = gs_args[i];
808
809   if(gs->antialiased) {
810     if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
811       alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
812     else
813       alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
814                               " ", NUM_ALPHA_ARGS);
815     for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
816       argv[argc] = alpha_args[i];
817   }
818   else
819     argv[argc++] = "-sDEVICE=x11";
820   argv[argc++] = "-dNOPAUSE";
821   argv[argc++] = "-dQUIET";
822   /* I assume we do _not_ want to change this... (: */
823   argv[argc++] = "-dSAFER";
824
825   /* set up the pipes */
826   if(gs->send_filename_to_gs) {
827     argv[argc++] = PS_DOCUMENT_GET_PS_FILE(gs);
828     argv[argc++] = "-c";
829     argv[argc++] = "quit";
830   }
831   else
832     argv[argc++] = "-";
833
834   argv[argc++] = NULL;
835
836   if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
837     if(pipe(std_in) == -1) {
838       g_critical("Unable to open pipe to Ghostscript.");
839       return -1;
840     }
841   }
842   if(pipe(std_out) == -1) {
843     close_pipe(std_in);
844     return -1;
845   }
846   if(pipe(std_err) == -1) {
847     close_pipe(std_in);
848     close_pipe(std_out);
849     return -1;
850   }
851
852   gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld",
853                            gdk_x11_drawable_get_xid(gs->pstarget),
854                            gdk_x11_drawable_get_xid(gs->bpixmap));
855
856   LOG ("Launching ghostview with env %s", gv_env);
857
858   gs->busy = TRUE;
859   gs->interpreter_pid = fork();
860   switch (gs->interpreter_pid) {
861   case -1:                     /* error */
862     close_pipe(std_in);
863     close_pipe(std_out);
864     close_pipe(std_err);
865     return -2;
866     break;
867   case 0:                      /* child */
868     close(std_out[0]);
869     dup2(std_out[1], 1);
870     close(std_out[1]);
871
872     close(std_err[0]);
873     dup2(std_err[1], 2);
874     close(std_err[1]);
875
876     if(!gs->reading_from_pipe) {
877       if(gs->send_filename_to_gs) {
878         int stdinfd;
879         /* just in case gs tries to read from stdin */
880         stdinfd = open("/dev/null", O_RDONLY);
881         if(stdinfd != 0) {
882           dup2(stdinfd, 0);
883           close(stdinfd);
884         }
885       }
886       else {
887         close(std_in[1]);
888         dup2(std_in[0], 0);
889         close(std_in[0]);
890       }
891     }
892
893     putenv(gv_env);
894
895     /* change to directory where the input file is. This helps
896      * with postscript-files which include other files using
897      * a relative path */
898     dir = g_path_get_dirname(gs->gs_filename);
899     chdir(dir);
900     g_free(dir);
901
902     execvp(argv[0], argv);
903
904     /* Notify error */
905     g_print("Unable to execute [%s]\n", argv[0]);
906     g_strfreev(gs_args);
907     g_free(gv_env);
908     if(alpha_args)
909       g_strfreev(alpha_args);
910     _exit(1);
911     break;
912   default:                     /* parent */
913     if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
914       int result;
915       close(std_in[0]);
916       /* use non-blocking IO for pipe to ghostscript */
917       result = fcntl(std_in[1], F_GETFL, 0);
918       fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
919       gs->interpreter_input = std_in[1];
920     }
921     else {
922       gs->interpreter_input = -1;
923     }
924     close(std_out[1]);
925     gs->interpreter_output = std_out[0];
926     close(std_err[1]);
927     gs->interpreter_err = std_err[0];
928     gs->interpreter_output_id =
929       gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
930     gs->interpreter_error_id =
931       gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
932     break;
933   }
934   return TRUE;
935 }
936
937 static void
938 stop_interpreter(PSDocument * gs)
939 {
940   if(gs->interpreter_pid > 0) {
941     int status = 0;
942     LOG ("Stop the interpreter");
943     kill(gs->interpreter_pid, SIGTERM);
944     while((wait(&status) == -1) && (errno == EINTR)) ;
945     gs->interpreter_pid = -1;
946     if(status == 1) {
947       ps_document_cleanup(gs);
948       gs->gs_status = _("Interpreter failed.");
949     }
950   }
951
952   if(gs->interpreter_input >= 0) {
953     close(gs->interpreter_input);
954     gs->interpreter_input = -1;
955     if(gs->interpreter_input_id != 0) {
956       gdk_input_remove(gs->interpreter_input_id);
957       gs->interpreter_input_id = 0;
958     }
959     while(gs->ps_input) {
960       struct record_list *ps_old = gs->ps_input;
961       gs->ps_input = gs->ps_input->next;
962       if(ps_old->close && NULL != ps_old->fp)
963         fclose(ps_old->fp);
964       g_free((char *) ps_old);
965     }
966   }
967
968   if(gs->interpreter_output >= 0) {
969     close(gs->interpreter_output);
970     gs->interpreter_output = -1;
971     if(gs->interpreter_output_id) {
972       gdk_input_remove(gs->interpreter_output_id);
973       gs->interpreter_output_id = 0;
974     }
975   }
976
977   if(gs->interpreter_err >= 0) {
978     close(gs->interpreter_err);
979     gs->interpreter_err = -1;
980     if(gs->interpreter_error_id) {
981       gdk_input_remove(gs->interpreter_error_id);
982       gs->interpreter_error_id = 0;
983     }
984   }
985
986   gs->busy = FALSE;
987 }
988
989 /* If file exists and is a regular file then return its length, else -1 */
990 static gint
991 file_length(const gchar * filename)
992 {
993   struct stat stat_rec;
994
995   if(filename && (stat(filename, &stat_rec) == 0)
996      && S_ISREG(stat_rec.st_mode))
997     return stat_rec.st_size;
998   else
999     return -1;
1000 }
1001
1002 /* Test if file exists, is a regular file and its length is > 0 */
1003 static gboolean
1004 file_readable(const char *filename)
1005 {
1006   return (file_length(filename) > 0);
1007 }
1008
1009 /*
1010  * Decompress gs->gs_filename if necessary
1011  * Set gs->filename_unc to the name of the uncompressed file or NULL.
1012  * Error reporting via signal 'interpreter_message'
1013  * Return name of input file to use or NULL on error..
1014  */
1015 static gchar *
1016 check_filecompressed(PSDocument * gs)
1017 {
1018   FILE *file;
1019   gchar buf[1024];
1020   gchar *filename, *filename_unc, *filename_err, *cmdline;
1021   const gchar *cmd;
1022   int fd;
1023
1024   cmd = NULL;
1025
1026   if((file = fopen(gs->gs_filename, "r"))
1027      && (fread(buf, sizeof(gchar), 3, file) == 3)) {
1028     if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
1029       /* file is gzipped or compressed */
1030       cmd = gtk_gs_defaults_get_ungzip_cmd();
1031     }
1032     else if(strncmp(buf, "BZh", 3) == 0) {
1033       /* file is compressed with bzip2 */
1034       cmd = gtk_gs_defaults_get_unbzip2_cmd();
1035     }
1036   }
1037   if(NULL != file)
1038     fclose(file);
1039
1040   if(!cmd)
1041     return gs->gs_filename;
1042
1043   /* do the decompression */
1044   filename = g_shell_quote(gs->gs_filename);
1045   filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1046   if((fd = mkstemp(filename_unc)) < 0) {
1047     g_free(filename_unc);
1048     g_free(filename);
1049     return NULL;
1050   }
1051   close(fd);
1052   filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1053   if((fd = mkstemp(filename_err)) < 0) {
1054     g_free(filename_err);
1055     g_free(filename_unc);
1056     g_free(filename);
1057     return NULL;
1058   }
1059   close(fd);
1060   cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1061                             filename, filename_unc, filename_err);
1062   if((system(cmdline) == 0)
1063      && file_readable(filename_unc)
1064      && (file_length(filename_err) == 0)) {
1065     /* sucessfully uncompressed file */
1066     gs->gs_filename_unc = filename_unc;
1067   }
1068   else {
1069     /* report error */
1070     g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1071                gs->gs_filename);
1072     ps_document_emit_error_msg(gs, buf);
1073     if(file_length(filename_err) > 0) {
1074       FILE *err;
1075       if((err = fopen(filename_err, "r"))) {
1076         /* print file to message window */
1077         while(fgets(buf, 1024, err))
1078           ps_document_emit_error_msg(gs, buf);
1079         fclose(err);
1080       }
1081     }
1082     unlink(filename_unc);
1083     g_free(filename_unc);
1084     filename_unc = NULL;
1085   }
1086   unlink(filename_err);
1087   g_free(filename_err);
1088   g_free(cmdline);
1089   g_free(filename);
1090   return filename_unc;
1091 }
1092
1093 /*
1094  * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1095  * pdf file if necessary.
1096  * Set gs->filename_dsc to the name of the dsc file or NULL.
1097  * Error reporting via signal 'interpreter_message'.
1098  */
1099 static gchar *
1100 check_pdf(PSDocument * gs)
1101 {
1102   FILE *file;
1103   gchar buf[1024], *filename;
1104   int fd;
1105
1106   /* use uncompressed file as input if necessary */
1107   filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1108
1109   if((file = fopen(filename, "r"))
1110      && (fread(buf, sizeof(char), 5, file) == 5)
1111      && (strncmp(buf, "%PDF-", 5) == 0)) {
1112     /* we found a PDF file */
1113     gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1114     filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1115     if((fd = mkstemp(filename_dsc)) < 0) {
1116       return NULL;
1117     }
1118     close(fd);
1119     filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1120     if((fd = mkstemp(filename_err)) < 0) {
1121       g_free(filename_dsc);
1122       return NULL;
1123     }
1124     close(fd);
1125     fname = g_shell_quote(filename);
1126     cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1127     g_free(fname);
1128     /* this command (sometimes?) prints error messages to stdout! */
1129     cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1130     g_free(cmd);
1131
1132     if((system(cmdline) == 0) && file_readable(filename_dsc)) {
1133
1134       /* success */
1135       filename = gs->gs_filename_dsc = filename_dsc;
1136
1137       if(file_length(filename_err) > 0) {
1138         gchar *err_msg = " ";
1139         GtkWidget *dialog;
1140         FILE *err;
1141         GdkColor color;
1142
1143         if((err = fopen(filename_err, "r"))) {
1144
1145           /* print the content of the file to a message box */
1146           while(fgets(buf, 1024, err))
1147             err_msg = g_strconcat(err_msg, buf, NULL);
1148
1149           /* FIXME The dialog is not yet set to modal, difficult to 
1150            * get the parent of the dialog box here 
1151            */
1152
1153           dialog = gtk_message_dialog_new(NULL,
1154                                           GTK_DIALOG_MODAL,
1155                                           GTK_MESSAGE_WARNING,
1156                                           GTK_BUTTONS_OK,
1157                                           ("There was an error while scaning the file: %s \n%s"),
1158                                           gs->gs_filename, err_msg);
1159
1160           gdk_color_parse("white", &color);
1161           gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1162
1163           g_signal_connect(G_OBJECT(dialog), "response",
1164                            G_CALLBACK(gtk_widget_destroy), NULL);
1165
1166           gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1167           gtk_widget_show(dialog);
1168           g_free(err_msg);
1169         }
1170       }
1171
1172     }
1173     else {
1174       /* report error */
1175       g_snprintf(buf, 1024,
1176                  _("Error while converting pdf file %s:\n"), filename);
1177       ps_document_emit_error_msg(gs, buf);
1178
1179       if(file_length(filename_err) > 0) {
1180         FILE *err;
1181         if((err = fopen(filename_err, "r"))) {
1182           /* print file to message window */
1183           while(fgets(buf, 1024, err))
1184             ps_document_emit_error_msg(gs, buf);
1185         }
1186       }
1187       unlink(filename_dsc);
1188       g_free(filename_dsc);
1189       filename = NULL;
1190     }
1191     unlink(filename_err);
1192     g_free(filename_err);
1193     g_free(cmdline);
1194   }
1195   if(NULL != file)
1196     fclose(file);
1197   return filename;
1198 }
1199
1200 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1201 /* never mind this patch: a properly working X server should take care of
1202    calculating the proper values. */
1203 static float
1204 compute_xdpi(void)
1205 {
1206 #   ifndef HAVE_XINERAMA
1207   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1208 #   else
1209   Display *dpy;
1210   dpy = (Display *) GDK_DISPLAY();
1211   if(XineramaIsActive(dpy)) {
1212     int num_heads;
1213     XineramaScreenInfo *head_info;
1214     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1215     /* fake it with dimensions of the first head for now */
1216     return 25.4 * head_info[0].width / gdk_screen_width_mm();
1217   }
1218   else {
1219     return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1220   }
1221 #   endif
1222   /* HAVE_XINERAMA */
1223 }
1224
1225 static float
1226 compute_ydpi(void)
1227 {
1228 #   ifndef HAVE_XINERAMA
1229   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1230 #   else
1231   Display *dpy;
1232   dpy = (Display *) GDK_DISPLAY();
1233   if(XineramaIsActive(dpy)) {
1234     int num_heads;
1235     XineramaScreenInfo *head_info;
1236     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1237     /* fake it with dimensions of the first head for now */
1238     return 25.4 * head_info[0].height / gdk_screen_height_mm();
1239   }
1240   else {
1241     return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1242   }
1243 #   endif
1244   /* HAVE_XINERAMA */
1245 }
1246 #else
1247 static float
1248 compute_xdpi(void)
1249 {
1250   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1251 }
1252
1253 static float
1254 compute_ydpi(void)
1255 {
1256   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1257 }
1258 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1259
1260 /* Compute new size of window, sets xdpi and ydpi if necessary.
1261  * returns True if new window size is different */
1262 static gboolean
1263 compute_size(PSDocument * gs)
1264 {
1265   guint new_width = 1;
1266   guint new_height = 1;
1267   gboolean change = FALSE;
1268   gint orientation;
1269
1270   /* width and height can be changed, calculate window size according */
1271   /* to xpdi and ydpi */
1272   orientation = ps_document_get_orientation(gs);
1273
1274   switch (orientation) {
1275   case GTK_GS_ORIENTATION_PORTRAIT:
1276   case GTK_GS_ORIENTATION_UPSIDEDOWN:
1277     new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1278     new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1279     break;
1280   case GTK_GS_ORIENTATION_LANDSCAPE:
1281   case GTK_GS_ORIENTATION_SEASCAPE:
1282     new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1283     new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1284     break;
1285   }
1286
1287   change = (new_width != gs->width * gs->zoom_factor)
1288     || (new_height != gs->height * gs->zoom_factor);
1289   gs->width = (gint) (new_width * gs->zoom_factor);
1290   gs->height = (gint) (new_height * gs->zoom_factor);
1291
1292   return (change);
1293 }
1294
1295 static gint
1296 ps_document_enable_interpreter(PSDocument * gs)
1297 {
1298   g_return_val_if_fail(gs != NULL, FALSE);
1299   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1300
1301   if(!gs->gs_filename)
1302     return 0;
1303
1304   gs->disable_start = FALSE;
1305   
1306   return start_interpreter(gs);
1307 }
1308
1309 /* publicly accessible functions */
1310
1311 GType
1312 ps_document_get_type(void)
1313 {
1314   static GType gs_type = 0;
1315   if(!gs_type) {
1316     GTypeInfo gs_info = {
1317       sizeof(PSDocumentClass),
1318       (GBaseInitFunc) NULL,
1319       (GBaseFinalizeFunc) NULL,
1320       (GClassInitFunc) ps_document_class_init,
1321       (GClassFinalizeFunc) NULL,
1322       NULL,                     /* class_data */
1323       sizeof(PSDocument),
1324       0,                        /* n_preallocs */
1325       (GInstanceInitFunc) ps_document_init
1326     };
1327
1328     static const GInterfaceInfo document_info =
1329     {
1330         (GInterfaceInitFunc) ps_document_document_iface_init,
1331         NULL,
1332         NULL
1333     };
1334
1335     gs_type = g_type_register_static(G_TYPE_OBJECT,
1336                                      "PSDocument", &gs_info, 0);
1337
1338     g_type_add_interface_static (gs_type,
1339                                  EV_TYPE_DOCUMENT,
1340                                  &document_info);
1341   }
1342   return gs_type;
1343
1344
1345 }
1346
1347 /*
1348  * Show error message -> send signal "interpreter_message"
1349  */
1350 static void
1351 ps_document_emit_error_msg(PSDocument * gs, const gchar * msg)
1352 {
1353   gdk_pointer_ungrab(GDK_CURRENT_TIME);
1354   if(strstr(msg, "Error:")) {
1355     gs->gs_status = _("File is not a valid PostScript document.");
1356     ps_document_cleanup(gs);
1357   }
1358 }
1359
1360 static gboolean
1361 document_load(PSDocument * gs, const gchar * fname)
1362 {
1363   g_return_val_if_fail(gs != NULL, FALSE);
1364   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1365
1366   LOG ("Load the document");
1367
1368   /* clean up previous document */
1369   ps_document_cleanup(gs);
1370
1371   if(fname == NULL) {
1372     gs->gs_status = "";
1373     return FALSE;
1374   }
1375
1376   /* prepare this document */
1377
1378   /* default values: no dsc information available  */
1379   gs->structured_doc = FALSE;
1380   gs->send_filename_to_gs = TRUE;
1381   gs->current_page = 0;
1382   gs->loaded = FALSE;
1383   if(*fname == '/') {
1384     /* an absolute path */
1385     gs->gs_filename = g_strdup(fname);
1386   }
1387   else {
1388     /* path relative to our cwd: make it absolute */
1389     gchar *cwd = g_get_current_dir();
1390     gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1391     g_free(cwd);
1392   }
1393
1394   if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1395     gs->send_filename_to_gs = FALSE;
1396   }
1397   else {
1398     /*
1399      * We need to make sure that the file is loadable/exists!
1400      * otherwise we want to exit without loading new stuff...
1401      */
1402     gchar *filename = NULL;
1403
1404     if(!file_readable(fname)) {
1405       gchar buf[1024];
1406       g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1407       ps_document_emit_error_msg(gs, buf);
1408       gs->gs_status = _("File is not readable.");
1409     }
1410     else {
1411       filename = check_filecompressed(gs);
1412       if(filename)
1413         filename = check_pdf(gs);
1414     }
1415
1416     if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1417       ps_document_cleanup(gs);
1418       return FALSE;
1419     }
1420
1421     /* we grab the vital statistics!!! */
1422     gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1423
1424     g_object_notify (G_OBJECT (gs), "title");
1425
1426     if(gs->doc == NULL) {
1427       /* File does not seem to be a Postscript one */
1428       gchar buf[1024];
1429       g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1430       ps_document_emit_error_msg(gs, buf);
1431       ps_document_cleanup(gs);
1432       gs->gs_status = _("The file is not a PostScript document.");
1433       return FALSE;
1434     }
1435
1436     if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1437        (gs->doc->epsf && gs->doc->numpages > 1)) {
1438       gs->structured_doc = TRUE;
1439       gs->send_filename_to_gs = FALSE;
1440     }
1441
1442     /* We have to set up the orientation of the document */
1443
1444
1445     /* orientation can only be portrait, and landscape or none.
1446        This is the document default. A document can have
1447        pages in landscape and some in portrait */
1448     if(gs->override_orientation) {
1449       /* If the orientation should be override... 
1450          then gs->orientation has already the correct
1451          value (it was set when the widget was created */
1452       /* So do nothing */
1453
1454     }
1455     else {
1456       /* Otherwise, set the proper orientation for the doc */
1457       gs->real_orientation = gs->doc->orientation;
1458     }
1459   }
1460   ps_document_set_page_size(gs, -1, gs->current_page);
1461   gs->loaded = TRUE;
1462
1463   gs->gs_status = _("Document loaded.");
1464
1465   return gs->loaded;
1466 }
1467
1468
1469 static gboolean
1470 ps_document_next_page(PSDocument * gs)
1471 {
1472   XEvent event;
1473
1474   LOG ("Make ghostscript render next page");
1475
1476   g_return_val_if_fail(gs != NULL, FALSE);
1477   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1478
1479   if(gs->interpreter_pid == 0) {    /* no interpreter active */
1480     return FALSE;
1481   }
1482
1483   if(gs->busy) {                /* interpreter is busy */
1484     return FALSE;
1485   }
1486
1487   gs->busy = TRUE;
1488
1489   event.xclient.type = ClientMessage;
1490   event.xclient.display = gdk_display;
1491   event.xclient.window = gs->message_window;
1492   event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1493   event.xclient.format = 32;
1494
1495   gdk_error_trap_push();
1496   XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1497   gdk_flush();
1498   gdk_error_trap_pop();
1499
1500   return TRUE;
1501 }
1502
1503 static gboolean
1504 ps_document_goto_page(PSDocument * gs, gint page)
1505 {
1506   g_return_val_if_fail(gs != NULL, FALSE);
1507   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1508
1509   LOG ("Go to page %d", page);
1510
1511   if(!gs->gs_filename) {
1512     return FALSE;
1513   }
1514
1515   /* range checking... */
1516   if(page < 0)
1517     page = 0;
1518
1519   if(gs->structured_doc && gs->doc) {
1520
1521     LOG ("It's a structured document, let's send one page to gs");
1522
1523     if(page >= gs->doc->numpages)
1524       page = gs->doc->numpages - 1;
1525
1526     if(page == gs->current_page && !gs->changed)
1527       return TRUE;
1528
1529     gs->current_page = page;
1530
1531     if(gs->doc->pages[page].orientation != NONE &&
1532        !gs->override_orientation &&
1533        gs->doc->pages[page].orientation != gs->real_orientation) {
1534       gs->real_orientation = gs->doc->pages[page].orientation;
1535       gs->changed = TRUE;
1536     }
1537
1538     ps_document_set_page_size(gs, -1, page);
1539
1540     gs->changed = FALSE;
1541
1542     if(is_interpreter_ready(gs)) {
1543       ps_document_next_page(gs);
1544     }
1545     else {
1546       ps_document_enable_interpreter(gs);
1547       send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1548       send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1549     }
1550
1551     send_ps(gs, gs->doc->pages[gs->current_page].begin,
1552             gs->doc->pages[gs->current_page].len, FALSE);
1553   }
1554   else {
1555     /* Unstructured document */
1556     /* In the case of non structured documents,
1557        GS read the PS from the  actual file (via command
1558        line. Hence, ggv only send a signal next page.
1559        If ghostview is not running it is usually because
1560        the last page of the file was displayed. In that
1561        case, ggv restarts GS again and the first page is displayed.
1562      */
1563
1564     LOG ("It's an unstructured document, gs will just read the file");
1565
1566     if(page == gs->current_page && !gs->changed)
1567       return TRUE;
1568
1569     ps_document_set_page_size(gs, -1, page);
1570
1571     if(!is_interpreter_ready(gs))
1572       ps_document_enable_interpreter(gs);
1573
1574     gs->current_page = page;
1575
1576     ps_document_next_page(gs);
1577   }
1578   return TRUE;
1579 }
1580
1581 /*
1582  * set pagesize sets the size from
1583  * if new_pagesize is -1, then it is set to either
1584  *  a) the default settings of pageid, if they exist, or if pageid != -1.
1585  *  b) the default setting of the document, if it exists.
1586  *  c) the default setting of the widget.
1587  * otherwise, the new_pagesize is used as the pagesize
1588  */
1589 static gboolean
1590 ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid)
1591 {
1592   gint new_llx = 0;
1593   gint new_lly = 0;
1594   gint new_urx = 0;
1595   gint new_ury = 0;
1596   GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1597
1598   LOG ("Set the page size");
1599
1600   g_return_val_if_fail(gs != NULL, FALSE);
1601   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1602
1603   if(new_pagesize == -1) {
1604     if(gs->default_size > 0)
1605       new_pagesize = gs->default_size;
1606     if(!gs->override_size && gs->doc) {
1607       /* If we have a document:
1608          We use -- the page size (if specified)
1609          or the doc. size (if specified)
1610          or the page bbox (if specified)
1611          or the bounding box
1612        */
1613       if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1614          (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1615         new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1616       }
1617       else if(gs->doc->default_page_size != NULL) {
1618         new_pagesize = gs->doc->default_page_size - gs->doc->size;
1619       }
1620       else if((pageid >= 0) &&
1621               (gs->doc->numpages > pageid) &&
1622               (gs->doc->pages) &&
1623               (gs->doc->pages[pageid].boundingbox[URX] >
1624                gs->doc->pages[pageid].boundingbox[LLX]) &&
1625               (gs->doc->pages[pageid].boundingbox[URY] >
1626                gs->doc->pages[pageid].boundingbox[LLY])) {
1627         new_pagesize = -1;
1628       }
1629       else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1630               (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1631         new_pagesize = -1;
1632       }
1633     }
1634   }
1635
1636   /* Compute bounding box */
1637   if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) {    /* epsf or bbox */
1638     if((pageid >= 0) &&
1639        (gs->doc->pages) &&
1640        (gs->doc->pages[pageid].boundingbox[URX] >
1641         gs->doc->pages[pageid].boundingbox[LLX])
1642        && (gs->doc->pages[pageid].boundingbox[URY] >
1643            gs->doc->pages[pageid].boundingbox[LLY])) {
1644       /* use page bbox */
1645       new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1646       new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1647       new_urx = gs->doc->pages[pageid].boundingbox[URX];
1648       new_ury = gs->doc->pages[pageid].boundingbox[URY];
1649     }
1650     else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1651             (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1652       /* use doc bbox */
1653       new_llx = gs->doc->boundingbox[LLX];
1654       new_lly = gs->doc->boundingbox[LLY];
1655       new_urx = gs->doc->boundingbox[URX];
1656       new_ury = gs->doc->boundingbox[URY];
1657     }
1658   }
1659   else {
1660     if(new_pagesize < 0)
1661       new_pagesize = gs->default_size;
1662     new_llx = new_lly = 0;
1663     if(gs->doc && !gs->override_size && gs->doc->size &&
1664        (new_pagesize < gs->doc->numsizes)) {
1665       new_urx = gs->doc->size[new_pagesize].width;
1666       new_ury = gs->doc->size[new_pagesize].height;
1667     }
1668     else {
1669       new_urx = papersizes[new_pagesize].width;
1670       new_ury = papersizes[new_pagesize].height;
1671     }
1672   }
1673
1674   if(new_urx <= new_llx)
1675     new_urx = papersizes[12].width;
1676   if(new_ury <= new_lly)
1677     new_ury = papersizes[12].height;
1678
1679   /* If bounding box changed, setup for new size. */
1680   /* ps_document_disable_interpreter (gs); */
1681   if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1682      (new_urx != gs->urx) || (new_ury != gs->ury)) {
1683     gs->llx = new_llx;
1684     gs->lly = new_lly;
1685     gs->urx = new_urx;
1686     gs->ury = new_ury;
1687     gs->changed = TRUE;
1688   }
1689
1690   if(gs->changed) {
1691     set_up_page(gs);
1692     return TRUE;
1693   }
1694
1695   return FALSE;
1696 }
1697
1698 static void
1699 ps_document_set_zoom (PSDocument * gs, gfloat zoom)
1700 {
1701         g_return_if_fail (gs != NULL);
1702
1703         gs->zoom_factor = zoom;
1704
1705         if (gs->pstarget != NULL) {
1706                 set_up_page(gs);
1707                 gs->changed = TRUE;
1708                 gs->scaling = TRUE;
1709                 ps_document_goto_page (gs, gs->current_page);
1710         }
1711 }
1712
1713 static gboolean
1714 ps_document_load (EvDocument  *document,
1715                   const char  *uri,
1716                   GError     **error)
1717 {
1718         gboolean result;
1719         char *filename;
1720
1721         filename = g_filename_from_uri (uri, NULL, error);
1722         if (!filename)
1723                 return FALSE;
1724
1725         result = document_load (PS_DOCUMENT (document), filename);
1726         if (!result) {
1727                 g_set_error (error, G_FILE_ERROR,
1728                              G_FILE_ERROR_FAILED,
1729                              "Failed to load document '%s'\n",
1730                              uri);
1731         }
1732
1733         g_free (filename);
1734
1735         return result;
1736 }
1737
1738 static gboolean
1739 ps_document_save (EvDocument  *document,
1740                   const char  *uri,
1741                   GError     **error)
1742 {
1743         g_warning ("ps_document_save not implemented"); /* FIXME */
1744         return TRUE;
1745 }
1746
1747 static int
1748 ps_document_get_n_pages (EvDocument  *document)
1749 {
1750         PSDocument *ps = PS_DOCUMENT (document);
1751
1752         g_return_val_if_fail (ps != NULL, -1);
1753
1754         if (!ps->gs_filename || !ps->doc) {
1755                 return -1;
1756         }
1757
1758         return ps->structured_doc ? ps->doc->numpages : 1;
1759 }
1760
1761 static void
1762 ps_document_set_page (EvDocument  *document,
1763                        int          page)
1764 {
1765         ps_document_goto_page (PS_DOCUMENT (document), page - 1);
1766 }
1767
1768 static int
1769 ps_document_get_page (EvDocument  *document)
1770 {
1771         PSDocument *ps = PS_DOCUMENT (document);
1772
1773         g_return_val_if_fail (ps != NULL, -1);
1774
1775         return ps->current_page + 1;
1776 }
1777
1778 static void
1779 ps_document_set_scale (EvDocument  *document,
1780                         double       scale)
1781 {
1782         ps_document_set_zoom (PS_DOCUMENT (document), scale);
1783 }
1784
1785 static void
1786 ps_document_set_page_offset (EvDocument  *document,
1787                               int          x,
1788                               int          y)
1789 {
1790         PSDocument *gs = PS_DOCUMENT (document);
1791
1792         gs->page_x_offset = x;
1793         gs->page_y_offset = y;
1794 }
1795
1796 static void
1797 ps_document_get_page_size (EvDocument   *document,
1798                            int           page,
1799                            int          *width,
1800                            int          *height)
1801 {
1802         /* Post script documents never vary in size */
1803
1804         PSDocument *gs = PS_DOCUMENT (document);
1805
1806         if (width) {
1807                 *width = gs->width;
1808         }
1809
1810         if (height) {
1811                 *height = gs->height;
1812         }
1813 }
1814
1815 static void
1816 ps_document_render (EvDocument  *document,
1817                     int          clip_x,
1818                     int          clip_y,
1819                     int          clip_width,
1820                     int          clip_height)
1821 {
1822         PSDocument *gs = PS_DOCUMENT (document);
1823         GdkRectangle page;
1824         GdkRectangle draw;
1825         GdkGC *gc;
1826
1827         if (gs->pstarget == NULL ||
1828             gs->bpixmap == NULL) {
1829                 return;
1830         }
1831
1832         page.x = gs->page_x_offset;
1833         page.y = gs->page_y_offset;
1834         page.width = gs->width;
1835         page.height = gs->height;
1836
1837         draw.x = clip_x;
1838         draw.y = clip_y;
1839         draw.width = clip_width;
1840         draw.height = clip_height;
1841
1842         gc = gdk_gc_new (gs->pstarget);
1843
1844         gdk_draw_drawable (gs->pstarget, gc,
1845                            gs->bpixmap,
1846                            draw.x - page.x, draw.y - page.y,
1847                            draw.x, draw.y,
1848                            draw.width, draw.height);
1849
1850         LOG ("Copy the internal pixmap: %d %d %d %d %d %d",
1851              draw.x - page.x, draw.y - page.y,
1852              draw.x, draw.y, draw.width, draw.height);
1853
1854         g_object_unref (gc);
1855 }
1856
1857 static char *
1858 ps_document_get_text (EvDocument *document, GdkRectangle *rect)
1859 {
1860         g_warning ("ps_document_get_text not implemented"); /* FIXME ? */
1861         return NULL;
1862 }
1863
1864 static EvLink *
1865 ps_document_get_link (EvDocument *document,
1866                       int         x,
1867                       int         y)
1868 {
1869         return NULL;
1870 }
1871
1872 static void
1873 ps_document_document_iface_init (EvDocumentIface *iface)
1874 {
1875         iface->load = ps_document_load;
1876         iface->save = ps_document_save;
1877         iface->get_text = ps_document_get_text;
1878         iface->get_link = ps_document_get_link;
1879         iface->get_n_pages = ps_document_get_n_pages;
1880         iface->set_page = ps_document_set_page;
1881         iface->get_page = ps_document_get_page;
1882         iface->set_scale = ps_document_set_scale;
1883         iface->set_target = ps_document_set_target;
1884         iface->set_page_offset = ps_document_set_page_offset;
1885         iface->get_page_size = ps_document_get_page_size;
1886         iface->render = ps_document_render;
1887 }