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