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