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