]> www.fi.muni.cz Git - evince.git/blob - ps/gtkgs.c
Add a changed event that is emitted when the page content changes. This is
[evince.git] / ps / gtkgs.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 #ifdef  HAVE_XINERAMA
137 #   include <gdk/gdkx.h>
138 #   include <X11/extensions/Xinerama.h>
139 #endif /* HAVE_XINERAMA */
140 #include <X11/Intrinsic.h>
141 #include <unistd.h>
142 #include <fcntl.h>
143 #include <stdlib.h>
144 #include <errno.h>
145 #include <sys/stat.h>
146 #include <sys/types.h>
147 #include <sys/wait.h>
148 #include <stdio.h>
149 #include <math.h>
150
151 #include "ev-document.h"
152 #include "gtkgs.h"
153 #include "ggvutils.h"
154 #include "ps.h"
155 #include "gsdefaults.h"
156
157 #ifdef HAVE_LOCALE_H
158 #   include <locale.h>
159 #endif
160
161 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
162 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
163 #   define O_NONBLOCK O_NDELAY
164 #endif
165
166 #define GTK_GS_WATCH_INTERVAL 1000
167 #define GTK_GS_WATCH_TIMEOUT  2
168
169 #define MAX_BUFSIZE 1024
170
171 enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL };
172
173 static gboolean broken_pipe = FALSE;
174
175 static void
176 catchPipe(int i)
177 {
178   broken_pipe = True;
179 }
180
181 /* Forward declarations */
182 static void gtk_gs_init(GtkGS * gs);
183 static void gtk_gs_class_init(GtkGSClass * klass);
184 static void gtk_gs_interpreter_message(GtkGS * gs, gchar * msg,
185                                        gpointer user_data);
186 static void gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg);
187 static void gtk_gs_finalize(GObject * object);
188 static void send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close);
189 static void set_up_page(GtkGS * gs);
190 static void close_pipe(int p[2]);
191 static void interpreter_failed(GtkGS * gs);
192 static float compute_xdpi(void);
193 static float compute_ydpi(void);
194 static gboolean compute_size(GtkGS * gs);
195 static void output(gpointer data, gint source, GdkInputCondition condition);
196 static void input(gpointer data, gint source, GdkInputCondition condition);
197 static void stop_interpreter(GtkGS * gs);
198 static gint start_interpreter(GtkGS * gs);
199 gboolean computeSize(void);
200 static void ps_document_document_iface_init (EvDocumentIface *iface);
201
202 static GObjectClass *parent_class = NULL;
203
204 static GtkGSClass *gs_class = NULL;
205
206 static gint gtk_gs_signals[LAST_SIGNAL] = { 0 };
207
208 /* Static, private functions */
209
210 static void
211 ggv_marshaller_VOID__POINTER(GClosure * closure,
212                              GValue * return_value,
213                              guint n_param_values,
214                              const GValue * param_values,
215                              gpointer invocation_hint, gpointer marshal_data)
216 {
217   typedef void (*GMarshalFunc_VOID__POINTER) (gpointer data1,
218                                               gpointer arg_1, gpointer data2);
219   register GMarshalFunc_VOID__POINTER callback;
220   register GCClosure *cc = (GCClosure *) closure;
221   register gpointer data1, data2;
222
223   g_return_if_fail(n_param_values == 2);
224
225   if(G_CCLOSURE_SWAP_DATA(closure)) {
226     data1 = closure->data;
227     data2 = g_value_peek_pointer(param_values + 0);
228   }
229   else {
230     data1 = g_value_peek_pointer(param_values + 0);
231     data2 = closure->data;
232   }
233   callback =
234     (GMarshalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
235
236   callback(data1, g_value_get_pointer(param_values + 1), data2);
237 }
238
239 static void
240 ggv_marshaller_VOID__INT(GClosure * closure,
241                          GValue * return_value,
242                          guint n_param_values,
243                          const GValue * param_values,
244                          gpointer invocation_hint, gpointer marshal_data)
245 {
246   typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
247                                           gint arg_1, gpointer data2);
248   register GMarshalFunc_VOID__INT callback;
249   register GCClosure *cc = (GCClosure *) closure;
250   register gpointer data1, data2;
251
252   g_return_if_fail(n_param_values == 2);
253
254   if(G_CCLOSURE_SWAP_DATA(closure)) {
255     data1 = closure->data;
256     data2 = g_value_peek_pointer(param_values + 0);
257   }
258   else {
259     data1 = g_value_peek_pointer(param_values + 0);
260     data2 = closure->data;
261   }
262   callback =
263     (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
264
265   callback(data1, g_value_get_int(param_values + 1), data2);
266 }
267
268 static void
269 gtk_gs_init(GtkGS * gs)
270 {
271   gs->bpixmap = NULL;
272
273   gs->current_page = -2;
274   gs->disable_start = FALSE;
275   gs->interpreter_pid = -1;
276
277   gs->width = -1;
278   gs->height = -1;
279   gs->busy = FALSE;
280   gs->changed = FALSE;
281   gs->gs_scanstyle = 0;
282   gs->gs_filename = 0;
283   gs->gs_filename_dsc = 0;
284   gs->gs_filename_unc = 0;
285
286   broken_pipe = FALSE;
287
288   gs->structured_doc = FALSE;
289   gs->reading_from_pipe = FALSE;
290   gs->send_filename_to_gs = FALSE;
291
292   gs->doc = NULL;
293   gs->loaded = FALSE;
294
295   gs->interpreter_input = -1;
296   gs->interpreter_output = -1;
297   gs->interpreter_err = -1;
298   gs->interpreter_input_id = 0;
299   gs->interpreter_output_id = 0;
300   gs->interpreter_error_id = 0;
301
302   gs->ps_input = NULL;
303   gs->input_buffer = NULL;
304   gs->input_buffer_ptr = NULL;
305   gs->bytes_left = 0;
306   gs->buffer_bytes_left = 0;
307
308   gs->llx = 0;
309   gs->lly = 0;
310   gs->urx = 0;
311   gs->ury = 0;
312   gs->xdpi = compute_xdpi();
313   gs->ydpi = compute_ydpi();
314
315   gs->left_margin = 0;
316   gs->top_margin = 0;
317   gs->right_margin = 0;
318   gs->bottom_margin = 0;
319
320   /* Set user defined defaults */
321   gs->override_orientation = gtk_gs_defaults_get_override_orientation();
322   gs->fallback_orientation = gtk_gs_defaults_get_orientation();
323   gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
324   gs->default_size = gtk_gs_defaults_get_size();
325   gs->antialiased = gtk_gs_defaults_get_antialiased();
326   gs->override_size = gtk_gs_defaults_get_override_size();
327   gs->respect_eof = gtk_gs_defaults_get_respect_eof();
328   gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
329
330   gs->gs_status = _("No document loaded.");
331 }
332
333 static void
334 gtk_gs_class_init(GtkGSClass * klass)
335 {
336   GObjectClass *object_class;
337
338   object_class = (GObjectClass *) klass;
339   parent_class = gtk_type_class(gtk_widget_get_type());
340   gs_class = klass;
341
342   gtk_gs_signals[INTERPRETER_MESSAGE] = g_signal_new("interpreter_message",
343                                                      G_TYPE_FROM_CLASS
344                                                      (object_class),
345                                                      G_SIGNAL_RUN_LAST,
346                                                      G_STRUCT_OFFSET
347                                                      (GtkGSClass,
348                                                       interpreter_message),
349                                                      NULL, NULL,
350                                                      ggv_marshaller_VOID__POINTER,
351                                                      G_TYPE_NONE, 1,
352                                                      G_TYPE_POINTER);
353   gtk_gs_signals[INTERPRETER_ERROR] =
354     g_signal_new("interpreter_error", G_TYPE_FROM_CLASS(object_class),
355                  G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkGSClass,
356                                                     interpreter_error),
357                  NULL, NULL, ggv_marshaller_VOID__INT, G_TYPE_NONE, 1,
358                  G_TYPE_INT);
359
360   object_class->finalize = gtk_gs_finalize;
361
362   /* Create atoms */
363   klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
364   klass->gs_colors_atom = gdk_atom_intern("GHOSTVIEW_COLORS", FALSE);
365   klass->next_atom = gdk_atom_intern("NEXT", FALSE);
366   klass->page_atom = gdk_atom_intern("PAGE", FALSE);
367   klass->done_atom = gdk_atom_intern("DONE", FALSE);
368   klass->string_atom = gdk_atom_intern("STRING", FALSE);
369
370   /* a default handler for "interpreter_message" signal */
371   klass->interpreter_message = gtk_gs_interpreter_message;
372
373   gtk_gs_defaults_load();
374 }
375
376 /* Clean all memory and temporal files */
377 static void
378 gtk_gs_cleanup(GtkGS * gs)
379 {
380   g_return_if_fail(gs != NULL);
381   g_return_if_fail(GTK_IS_GS(gs));
382
383   stop_interpreter(gs);
384
385   if(gs->gs_psfile) {
386     fclose(gs->gs_psfile);
387     gs->gs_psfile = NULL;
388   }
389   if(gs->gs_filename) {
390     g_free(gs->gs_filename);
391     gs->gs_filename = NULL;
392   }
393   if(gs->doc) {
394     psfree(gs->doc);
395     gs->doc = NULL;
396   }
397   if(gs->gs_filename_dsc) {
398     unlink(gs->gs_filename_dsc);
399     g_free(gs->gs_filename_dsc);
400     gs->gs_filename_dsc = NULL;
401   }
402   if(gs->gs_filename_unc) {
403     unlink(gs->gs_filename_unc);
404     g_free(gs->gs_filename_unc);
405     gs->gs_filename_unc = NULL;
406   }
407   gs->current_page = -1;
408   gs->loaded = FALSE;
409   gs->llx = 0;
410   gs->lly = 0;
411   gs->urx = 0;
412   gs->ury = 0;
413   set_up_page(gs);
414 }
415
416 /* free message as it was allocated in output() */
417 static void
418 gtk_gs_interpreter_message(GtkGS * gs, gchar * msg, gpointer user_data)
419 {
420   gdk_pointer_ungrab(GDK_CURRENT_TIME);
421   if(strstr(msg, "Error:")) {
422     gs->gs_status = _("File is not a valid PostScript document.");
423     gtk_gs_cleanup(gs);
424     g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", 1, NULL);
425   }
426   g_free(msg);
427 }
428
429 static void
430 gtk_gs_finalize(GObject * object)
431 {
432   GtkGS *gs;
433
434   g_return_if_fail(object != NULL);
435   g_return_if_fail(GTK_IS_GS(object));
436
437   gs = GTK_GS(object);
438
439   gtk_gs_cleanup(gs);
440
441   if(gs->input_buffer) {
442     g_free(gs->input_buffer);
443     gs->input_buffer = NULL;
444   }
445
446   (*G_OBJECT_CLASS(parent_class)->finalize) (object);
447 }
448
449 void
450 gtk_gs_set_center(GtkGS * gs, gfloat hval, gfloat vval)
451 {
452 }
453
454 static void
455 send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close)
456 {
457   struct record_list *ps_new;
458
459   if(gs->interpreter_input < 0) {
460     g_critical("No pipe to gs: error in send_ps().");
461     return;
462   }
463
464   ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
465   ps_new->fp = gs->gs_psfile;
466   ps_new->begin = begin;
467   ps_new->len = len;
468   ps_new->seek_needed = TRUE;
469   ps_new->close = close;
470   ps_new->next = NULL;
471
472   if(gs->input_buffer == NULL) {
473     gs->input_buffer = g_malloc(MAX_BUFSIZE);
474   }
475
476   if(gs->ps_input == NULL) {
477     gs->input_buffer_ptr = gs->input_buffer;
478     gs->bytes_left = len;
479     gs->buffer_bytes_left = 0;
480     gs->ps_input = ps_new;
481     gs->interpreter_input_id =
482       gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
483   }
484   else {
485     struct record_list *p = gs->ps_input;
486     while(p->next != NULL) {
487       p = p->next;
488     }
489     p->next = ps_new;
490   }
491 }
492
493 static void
494 set_up_page(GtkGS * gs)
495 {
496   guint orientation;
497   char buf[1024];
498   //GdkColormap *colormap;
499   GdkGC *fill;
500   GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
501   GdkColormap *colormap;
502
503 #ifdef HAVE_LOCALE_H
504   char *savelocale;
505 #endif
506
507   if (gs->pstarget == NULL)
508     return;
509
510   /* Do we have to check if the actual geometry changed? */
511
512   stop_interpreter(gs);
513
514   orientation = gtk_gs_get_orientation(gs);
515
516   if(compute_size(gs)) {
517     gdk_flush();
518
519     /* clear new pixmap (set to white) */
520     fill = gdk_gc_new(gs->pstarget);
521     if(fill) {
522       colormap = gdk_drawable_get_colormap(gs->pstarget);
523       gdk_color_alloc (colormap, &white);
524       gdk_gc_set_foreground(fill, &white);
525
526       if(gs->width > 0 && gs->height > 0) {
527         if(gs->bpixmap) {
528           gdk_drawable_unref(gs->bpixmap);
529           gs->bpixmap = NULL;
530         }
531
532         gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
533
534         gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
535                            0, 0, gs->width, gs->height);
536       }
537       else {
538         gdk_draw_rectangle(gs->pstarget, fill, TRUE,
539                            0, 0, gs->width, gs->height);
540       }
541       gdk_gc_unref(fill);
542
543       gdk_flush();
544     }
545   }
546
547 #ifdef HAVE_LOCALE_H
548   /* gs needs floating point parameters with '.' as decimal point
549    * while some (european) locales use ',' instead, so we set the 
550    * locale for this snprintf to "C".
551    */
552   savelocale = setlocale(LC_NUMERIC, "C");
553 #endif
554
555   g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
556              0L,
557              orientation * 90,
558              gs->llx,
559              gs->lly,
560              gs->urx,
561              gs->ury,
562              gs->xdpi * gs->zoom_factor,
563              gs->ydpi * gs->zoom_factor,
564              gs->left_margin,
565              gs->bottom_margin, gs->right_margin, gs->top_margin);
566
567 #ifdef HAVE_LOCALE_H
568   setlocale(LC_NUMERIC, savelocale);
569 #endif
570   gdk_property_change(gs->pstarget,
571                       gs_class->gs_atom,
572                       gs_class->string_atom,
573                       8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
574   gdk_flush();
575 }
576
577 static void
578 close_pipe(int p[2])
579 {
580   if(p[0] != -1)
581     close(p[0]);
582   if(p[1] != -1)
583     close(p[1]);
584 }
585
586 static gboolean
587 is_interpreter_ready(GtkGS * gs)
588 {
589   return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
590 }
591
592 static void
593 interpreter_failed(GtkGS * gs)
594 {
595   stop_interpreter(gs);
596 }
597
598 static void
599 output(gpointer data, gint source, GdkInputCondition condition)
600 {
601   char buf[MAX_BUFSIZE + 1], *msg;
602   guint bytes = 0;
603   GtkGS *gs = GTK_GS(data);
604
605   if(source == gs->interpreter_output) {
606     bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
607     if(bytes == 0) {            /* EOF occurred */
608       close(gs->interpreter_output);
609       gs->interpreter_output = -1;
610       gdk_input_remove(gs->interpreter_output_id);
611       return;
612     }
613     else if(bytes == -1) {
614       /* trouble... */
615       interpreter_failed(gs);
616       return;
617     }
618     if(gs->interpreter_err == -1) {
619       stop_interpreter(gs);
620     }
621   }
622   else if(source == gs->interpreter_err) {
623     bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
624     if(bytes == 0) {            /* EOF occurred */
625       close(gs->interpreter_err);
626       gs->interpreter_err = -1;
627       gdk_input_remove(gs->interpreter_error_id);
628       return;
629     }
630     else if(bytes == -1) {
631       /* trouble... */
632       interpreter_failed(gs);
633       return;
634     }
635     if(gs->interpreter_output == -1) {
636       stop_interpreter(gs);
637     }
638   }
639   if(bytes > 0) {
640     buf[bytes] = '\0';
641     msg = g_strdup(buf);
642     g_signal_emit (G_OBJECT(gs), gtk_gs_signals[INTERPRETER_MESSAGE], 0, msg);
643   }
644 }
645
646 static void
647 input(gpointer data, gint source, GdkInputCondition condition)
648 {
649   GtkGS *gs = GTK_GS(data);
650   int bytes_written;
651   void (*oldsig) (int);
652   oldsig = signal(SIGPIPE, catchPipe);
653
654   do {
655     if(gs->buffer_bytes_left == 0) {
656       /* Get a new section if required */
657       if(gs->ps_input && gs->bytes_left == 0) {
658         struct record_list *ps_old = gs->ps_input;
659         gs->ps_input = ps_old->next;
660         if(ps_old->close && NULL != ps_old->fp)
661           fclose(ps_old->fp);
662         g_free((char *) ps_old);
663       }
664       /* Have to seek at the beginning of each section */
665       if(gs->ps_input && gs->ps_input->seek_needed) {
666         fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
667         gs->ps_input->seek_needed = FALSE;
668         gs->bytes_left = gs->ps_input->len;
669       }
670
671       if(gs->bytes_left > MAX_BUFSIZE) {
672         gs->buffer_bytes_left =
673           fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
674       }
675       else if(gs->bytes_left > 0) {
676         gs->buffer_bytes_left =
677           fread(gs->input_buffer,
678                 sizeof(char), gs->bytes_left, gs->ps_input->fp);
679       }
680       else {
681         gs->buffer_bytes_left = 0;
682       }
683       if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
684         interpreter_failed(gs); /* Error occurred */
685       }
686       gs->input_buffer_ptr = gs->input_buffer;
687       gs->bytes_left -= gs->buffer_bytes_left;
688     }
689
690     if(gs->buffer_bytes_left > 0) {
691       /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
692
693       bytes_written = write(gs->interpreter_input,
694                             gs->input_buffer_ptr, gs->buffer_bytes_left);
695
696       if(broken_pipe) {
697         gtk_gs_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
698         broken_pipe = FALSE;
699         interpreter_failed(gs);
700       }
701       else if(bytes_written == -1) {
702         if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
703           interpreter_failed(gs);   /* Something bad happened */
704         }
705       }
706       else {
707         gs->buffer_bytes_left -= bytes_written;
708         gs->input_buffer_ptr += bytes_written;
709       }
710     }
711   }
712   while(gs->ps_input && gs->buffer_bytes_left == 0);
713
714   signal(SIGPIPE, oldsig);
715
716   if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
717     if(gs->interpreter_input_id != 0) {
718       gdk_input_remove(gs->interpreter_input_id);
719       gs->interpreter_input_id = 0;
720     }
721   }
722 }
723
724 static int
725 start_interpreter(GtkGS * gs)
726 {
727   int std_in[2] = { -1, -1 };   /* pipe to interp stdin */
728   int std_out[2];               /* pipe from interp stdout */
729   int std_err[2];               /* pipe from interp stderr */
730
731 #define NUM_ARGS    100
732 #define NUM_GS_ARGS (NUM_ARGS - 20)
733 #define NUM_ALPHA_ARGS 10
734
735   char *argv[NUM_ARGS], *dir, *gv_env;
736   char **gs_args, **alpha_args = NULL;
737   int argc = 0, i;
738
739   if(!gs->gs_filename)
740     return 0;
741
742   stop_interpreter(gs);
743
744   if(gs->disable_start == TRUE)
745     return 0;
746
747   /* set up the args... */
748   gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
749   for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
750     argv[argc] = gs_args[i];
751
752   if(gs->antialiased) {
753     if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
754       alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
755     else
756       alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
757                               " ", NUM_ALPHA_ARGS);
758     for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
759       argv[argc] = alpha_args[i];
760   }
761   else
762     argv[argc++] = "-sDEVICE=x11";
763   argv[argc++] = "-dNOPAUSE";
764   argv[argc++] = "-dQUIET";
765   /* I assume we do _not_ want to change this... (: */
766   argv[argc++] = "-dSAFER";
767
768   /* set up the pipes */
769   if(gs->send_filename_to_gs) {
770     argv[argc++] = GTK_GS_GET_PS_FILE(gs);
771     argv[argc++] = "-c";
772     argv[argc++] = "quit";
773   }
774   else
775     argv[argc++] = "-";
776
777   argv[argc++] = NULL;
778
779   if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
780     if(pipe(std_in) == -1) {
781       g_critical("Unable to open pipe to Ghostscript.");
782       return -1;
783     }
784   }
785   if(pipe(std_out) == -1) {
786     close_pipe(std_in);
787     return -1;
788   }
789   if(pipe(std_err) == -1) {
790     close_pipe(std_in);
791     close_pipe(std_out);
792     return -1;
793   }
794
795   gs->busy = TRUE;
796   gs->interpreter_pid = fork();
797   switch (gs->interpreter_pid) {
798   case -1:                     /* error */
799     close_pipe(std_in);
800     close_pipe(std_out);
801     close_pipe(std_err);
802     return -2;
803     break;
804   case 0:                      /* child */
805     close(std_out[0]);
806     dup2(std_out[1], 1);
807     close(std_out[1]);
808
809     close(std_err[0]);
810     dup2(std_err[1], 2);
811     close(std_err[1]);
812
813     if(!gs->reading_from_pipe) {
814       if(gs->send_filename_to_gs) {
815         int stdinfd;
816         /* just in case gs tries to read from stdin */
817         stdinfd = open("/dev/null", O_RDONLY);
818         if(stdinfd != 0) {
819           dup2(stdinfd, 0);
820           close(stdinfd);
821         }
822       }
823       else {
824         close(std_in[1]);
825         dup2(std_in[0], 0);
826         close(std_in[0]);
827       }
828     }
829
830     gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld",
831                              gdk_x11_drawable_get_xid(gs->pstarget),
832                              gdk_x11_drawable_get_xid(gs->bpixmap));
833     putenv(gv_env);
834
835     /* change to directory where the input file is. This helps
836      * with postscript-files which include other files using
837      * a relative path */
838     dir = g_path_get_dirname(gs->gs_filename);
839     chdir(dir);
840     g_free(dir);
841
842     execvp(argv[0], argv);
843
844     /* Notify error */
845     g_print("Unable to execute [%s]\n", argv[0]);
846     g_strfreev(gs_args);
847     g_free(gv_env);
848     if(alpha_args)
849       g_strfreev(alpha_args);
850     _exit(1);
851     break;
852   default:                     /* parent */
853     if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
854       int result;
855       close(std_in[0]);
856       /* use non-blocking IO for pipe to ghostscript */
857       result = fcntl(std_in[1], F_GETFL, 0);
858       fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
859       gs->interpreter_input = std_in[1];
860     }
861     else {
862       gs->interpreter_input = -1;
863     }
864     close(std_out[1]);
865     gs->interpreter_output = std_out[0];
866     close(std_err[1]);
867     gs->interpreter_err = std_err[0];
868     gs->interpreter_output_id =
869       gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
870     gs->interpreter_error_id =
871       gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
872     break;
873   }
874   return TRUE;
875 }
876
877 static void
878 stop_interpreter(GtkGS * gs)
879 {
880   if(gs->interpreter_pid > 0) {
881     int status = 0;
882     kill(gs->interpreter_pid, SIGTERM);
883     while((wait(&status) == -1) && (errno == EINTR)) ;
884     gs->interpreter_pid = -1;
885     if(status == 1) {
886       gtk_gs_cleanup(gs);
887       gs->gs_status = _("Interpreter failed.");
888       g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", status);
889     }
890   }
891
892   if(gs->interpreter_input >= 0) {
893     close(gs->interpreter_input);
894     gs->interpreter_input = -1;
895     if(gs->interpreter_input_id != 0) {
896       gdk_input_remove(gs->interpreter_input_id);
897       gs->interpreter_input_id = 0;
898     }
899     while(gs->ps_input) {
900       struct record_list *ps_old = gs->ps_input;
901       gs->ps_input = gs->ps_input->next;
902       if(ps_old->close && NULL != ps_old->fp)
903         fclose(ps_old->fp);
904       g_free((char *) ps_old);
905     }
906   }
907
908   if(gs->interpreter_output >= 0) {
909     close(gs->interpreter_output);
910     gs->interpreter_output = -1;
911     if(gs->interpreter_output_id) {
912       gdk_input_remove(gs->interpreter_output_id);
913       gs->interpreter_output_id = 0;
914     }
915   }
916
917   if(gs->interpreter_err >= 0) {
918     close(gs->interpreter_err);
919     gs->interpreter_err = -1;
920     if(gs->interpreter_error_id) {
921       gdk_input_remove(gs->interpreter_error_id);
922       gs->interpreter_error_id = 0;
923     }
924   }
925
926   gs->busy = FALSE;
927 }
928
929
930 /*
931  * Decompress gs->gs_filename if necessary
932  * Set gs->filename_unc to the name of the uncompressed file or NULL.
933  * Error reporting via signal 'interpreter_message'
934  * Return name of input file to use or NULL on error..
935  */
936 static gchar *
937 check_filecompressed(GtkGS * gs)
938 {
939   FILE *file;
940   gchar buf[1024];
941   gchar *filename, *filename_unc, *filename_err, *cmdline;
942   const gchar *cmd;
943   int fd;
944
945   cmd = NULL;
946
947   if((file = fopen(gs->gs_filename, "r"))
948      && (fread(buf, sizeof(gchar), 3, file) == 3)) {
949     if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
950       /* file is gzipped or compressed */
951       cmd = gtk_gs_defaults_get_ungzip_cmd();
952     }
953     else if(strncmp(buf, "BZh", 3) == 0) {
954       /* file is compressed with bzip2 */
955       cmd = gtk_gs_defaults_get_unbzip2_cmd();
956     }
957   }
958   if(NULL != file)
959     fclose(file);
960
961   if(!cmd)
962     return gs->gs_filename;
963
964   /* do the decompression */
965   filename = g_shell_quote(gs->gs_filename);
966   filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
967   if((fd = mkstemp(filename_unc)) < 0) {
968     g_free(filename_unc);
969     g_free(filename);
970     return NULL;
971   }
972   close(fd);
973   filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
974   if((fd = mkstemp(filename_err)) < 0) {
975     g_free(filename_err);
976     g_free(filename_unc);
977     g_free(filename);
978     return NULL;
979   }
980   close(fd);
981   cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
982                             filename, filename_unc, filename_err);
983   if((system(cmdline) == 0)
984      && ggv_file_readable(filename_unc)
985      && (ggv_file_length(filename_err) == 0)) {
986     /* sucessfully uncompressed file */
987     gs->gs_filename_unc = filename_unc;
988   }
989   else {
990     /* report error */
991     g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
992                gs->gs_filename);
993     gtk_gs_emit_error_msg(gs, buf);
994     if(ggv_file_length(filename_err) > 0) {
995       FILE *err;
996       if((err = fopen(filename_err, "r"))) {
997         /* print file to message window */
998         while(fgets(buf, 1024, err))
999           gtk_gs_emit_error_msg(gs, buf);
1000         fclose(err);
1001       }
1002     }
1003     unlink(filename_unc);
1004     g_free(filename_unc);
1005     filename_unc = NULL;
1006   }
1007   unlink(filename_err);
1008   g_free(filename_err);
1009   g_free(cmdline);
1010   g_free(filename);
1011   return filename_unc;
1012 }
1013
1014 /*
1015  * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1016  * pdf file if necessary.
1017  * Set gs->filename_dsc to the name of the dsc file or NULL.
1018  * Error reporting via signal 'interpreter_message'.
1019  */
1020 static gchar *
1021 check_pdf(GtkGS * gs)
1022 {
1023   FILE *file;
1024   gchar buf[1024], *filename;
1025   int fd;
1026
1027   /* use uncompressed file as input if necessary */
1028   filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1029
1030   if((file = fopen(filename, "r"))
1031      && (fread(buf, sizeof(char), 5, file) == 5)
1032      && (strncmp(buf, "%PDF-", 5) == 0)) {
1033     /* we found a PDF file */
1034     gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1035     filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1036     if((fd = mkstemp(filename_dsc)) < 0) {
1037       return NULL;
1038     }
1039     close(fd);
1040     filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1041     if((fd = mkstemp(filename_err)) < 0) {
1042       g_free(filename_dsc);
1043       return NULL;
1044     }
1045     close(fd);
1046     fname = g_shell_quote(filename);
1047     cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1048     g_free(fname);
1049     /* this command (sometimes?) prints error messages to stdout! */
1050     cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1051     g_free(cmd);
1052
1053     if((system(cmdline) == 0) && ggv_file_readable(filename_dsc)) {
1054
1055       /* success */
1056       filename = gs->gs_filename_dsc = filename_dsc;
1057
1058       if(ggv_file_length(filename_err) > 0) {
1059         gchar *err_msg = " ";
1060         GtkWidget *dialog;
1061         FILE *err;
1062         GdkColor color;
1063
1064         if((err = fopen(filename_err, "r"))) {
1065
1066           /* print the content of the file to a message box */
1067           while(fgets(buf, 1024, err))
1068             err_msg = g_strconcat(err_msg, buf, NULL);
1069
1070           /* FIXME The dialog is not yet set to modal, difficult to 
1071            * get the parent of the dialog box here 
1072            */
1073
1074           dialog = gtk_message_dialog_new(NULL,
1075                                           GTK_DIALOG_MODAL,
1076                                           GTK_MESSAGE_WARNING,
1077                                           GTK_BUTTONS_OK,
1078                                           ("There was an error while scaning the file: %s \n%s"),
1079                                           gs->gs_filename, err_msg);
1080
1081           gdk_color_parse("white", &color);
1082           gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1083
1084           g_signal_connect(G_OBJECT(dialog), "response",
1085                            G_CALLBACK(gtk_widget_destroy), NULL);
1086
1087           gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1088           gtk_widget_show(dialog);
1089           g_free(err_msg);
1090         }
1091       }
1092
1093     }
1094     else {
1095       /* report error */
1096       g_snprintf(buf, 1024,
1097                  _("Error while converting pdf file %s:\n"), filename);
1098       gtk_gs_emit_error_msg(gs, buf);
1099
1100       if(ggv_file_length(filename_err) > 0) {
1101         FILE *err;
1102         if((err = fopen(filename_err, "r"))) {
1103           /* print file to message window */
1104           while(fgets(buf, 1024, err))
1105             gtk_gs_emit_error_msg(gs, buf);
1106         }
1107       }
1108       unlink(filename_dsc);
1109       g_free(filename_dsc);
1110       filename = NULL;
1111     }
1112     unlink(filename_err);
1113     g_free(filename_err);
1114     g_free(cmdline);
1115   }
1116   if(NULL != file)
1117     fclose(file);
1118   return filename;
1119 }
1120
1121 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1122 /* never mind this patch: a properly working X server should take care of
1123    calculating the proper values. */
1124 static float
1125 compute_xdpi(void)
1126 {
1127 #   ifndef HAVE_XINERAMA
1128   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1129 #   else
1130   Display *dpy;
1131   dpy = (Display *) GDK_DISPLAY();
1132   if(XineramaIsActive(dpy)) {
1133     int num_heads;
1134     XineramaScreenInfo *head_info;
1135     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1136     /* fake it with dimensions of the first head for now */
1137     return 25.4 * head_info[0].width / gdk_screen_width_mm();
1138   }
1139   else {
1140     return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1141   }
1142 #   endif
1143   /* HAVE_XINERAMA */
1144 }
1145
1146 static float
1147 compute_ydpi(void)
1148 {
1149 #   ifndef HAVE_XINERAMA
1150   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1151 #   else
1152   Display *dpy;
1153   dpy = (Display *) GDK_DISPLAY();
1154   if(XineramaIsActive(dpy)) {
1155     int num_heads;
1156     XineramaScreenInfo *head_info;
1157     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1158     /* fake it with dimensions of the first head for now */
1159     return 25.4 * head_info[0].height / gdk_screen_height_mm();
1160   }
1161   else {
1162     return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1163   }
1164 #   endif
1165   /* HAVE_XINERAMA */
1166 }
1167 #else
1168 static float
1169 compute_xdpi(void)
1170 {
1171   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1172 }
1173
1174 static float
1175 compute_ydpi(void)
1176 {
1177   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1178 }
1179 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1180
1181 /* Compute new size of window, sets xdpi and ydpi if necessary.
1182  * returns True if new window size is different */
1183 static gboolean
1184 compute_size(GtkGS * gs)
1185 {
1186   guint new_width = 1;
1187   guint new_height = 1;
1188   gboolean change = FALSE;
1189   gint orientation;
1190
1191   /* width and height can be changed, calculate window size according */
1192   /* to xpdi and ydpi */
1193   orientation = gtk_gs_get_orientation(gs);
1194
1195   switch (orientation) {
1196   case GTK_GS_ORIENTATION_PORTRAIT:
1197   case GTK_GS_ORIENTATION_UPSIDEDOWN:
1198     new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1199     new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1200     break;
1201   case GTK_GS_ORIENTATION_LANDSCAPE:
1202   case GTK_GS_ORIENTATION_SEASCAPE:
1203     new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1204     new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1205     break;
1206   }
1207
1208   change = (new_width != gs->width * gs->zoom_factor)
1209     || (new_height != gs->height * gs->zoom_factor);
1210   gs->width = (gint) (new_width * gs->zoom_factor);
1211   gs->height = (gint) (new_height * gs->zoom_factor);
1212
1213   return (change);
1214 }
1215
1216 gint
1217 gtk_gs_enable_interpreter(GtkGS * gs)
1218 {
1219   g_return_val_if_fail(gs != NULL, FALSE);
1220   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1221
1222   if(!gs->gs_filename)
1223     return 0;
1224
1225   gs->disable_start = FALSE;
1226   
1227   return start_interpreter(gs);
1228 }
1229
1230 /* publicly accessible functions */
1231
1232 GType
1233 gtk_gs_get_type(void)
1234 {
1235   static GType gs_type = 0;
1236   if(!gs_type) {
1237     GTypeInfo gs_info = {
1238       sizeof(GtkGSClass),
1239       (GBaseInitFunc) NULL,
1240       (GBaseFinalizeFunc) NULL,
1241       (GClassInitFunc) gtk_gs_class_init,
1242       (GClassFinalizeFunc) NULL,
1243       NULL,                     /* class_data */
1244       sizeof(GtkGS),
1245       0,                        /* n_preallocs */
1246       (GInstanceInitFunc) gtk_gs_init
1247     };
1248
1249     static const GInterfaceInfo document_info =
1250     {
1251         (GInterfaceInitFunc) ps_document_document_iface_init,
1252         NULL,
1253         NULL
1254     };
1255
1256     gs_type = g_type_register_static(G_TYPE_OBJECT,
1257                                      "GtkGS", &gs_info, 0);
1258
1259     g_type_add_interface_static (gs_type,
1260                                  EV_TYPE_DOCUMENT,
1261                                  &document_info);
1262   }
1263   return gs_type;
1264
1265
1266 }
1267
1268 GObject *
1269 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1270 {
1271   GObject *gs;
1272
1273   gs = g_object_new(GTK_GS_TYPE, NULL);
1274
1275   return gs;
1276 }
1277
1278
1279 GObject *
1280 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1281 {
1282   GObject *gs = gtk_gs_new(hadj, vadj);
1283   gtk_gs_load(GTK_GS(gs), fname);
1284   return gs;
1285 }
1286
1287 void
1288 gtk_gs_reload(GtkGS * gs)
1289 {
1290   gchar *fname;
1291   gint page;
1292
1293   if(!gs->gs_filename)
1294     return;
1295
1296   page = gtk_gs_get_current_page(gs);
1297   fname = g_strdup(gs->gs_filename);
1298   gtk_gs_load(gs, fname);
1299   gtk_gs_goto_page(gs, page);
1300   g_free(fname);
1301 }
1302
1303
1304 /*
1305  * Show error message -> send signal "interpreter_message"
1306  */
1307 static void
1308 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1309 {
1310   g_signal_emit (G_OBJECT(gs),
1311                  gtk_gs_signals[INTERPRETER_MESSAGE], 0, g_strdup(msg));
1312 }
1313
1314 void
1315 gtk_gs_disable_interpreter(GtkGS * gs)
1316 {
1317   g_return_if_fail(gs != NULL);
1318   g_return_if_fail(GTK_IS_GS(gs));
1319
1320   gs->disable_start = TRUE;
1321
1322   stop_interpreter(gs);
1323 }
1324
1325 gboolean
1326 gtk_gs_load(GtkGS * gs, const gchar * fname)
1327 {
1328   g_return_val_if_fail(gs != NULL, FALSE);
1329   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1330
1331   /* clean up previous document */
1332   gtk_gs_cleanup(gs);
1333
1334   if(fname == NULL) {
1335     gs->gs_status = "";
1336     return FALSE;
1337   }
1338
1339   /* prepare this document */
1340
1341   /* default values: no dsc information available  */
1342   gs->structured_doc = FALSE;
1343   gs->send_filename_to_gs = TRUE;
1344   gs->current_page = -2;
1345   gs->loaded = FALSE;
1346   if(*fname == '/') {
1347     /* an absolute path */
1348     gs->gs_filename = g_strdup(fname);
1349   }
1350   else {
1351     /* path relative to our cwd: make it absolute */
1352     gchar *cwd = g_get_current_dir();
1353     gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1354     g_free(cwd);
1355   }
1356
1357   if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1358     gs->send_filename_to_gs = FALSE;
1359   }
1360   else {
1361     /*
1362      * We need to make sure that the file is loadable/exists!
1363      * otherwise we want to exit without loading new stuff...
1364      */
1365     gchar *filename = NULL;
1366
1367     if(!ggv_file_readable(fname)) {
1368       gchar buf[1024];
1369       g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1370       gtk_gs_emit_error_msg(gs, buf);
1371       gs->gs_status = _("File is not readable.");
1372     }
1373     else {
1374       filename = check_filecompressed(gs);
1375       if(filename)
1376         filename = check_pdf(gs);
1377     }
1378
1379     if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1380       gtk_gs_cleanup(gs);
1381       return FALSE;
1382     }
1383
1384     /* we grab the vital statistics!!! */
1385     gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1386
1387     if(gs->doc == NULL) {
1388       /* File does not seem to be a Postscript one */
1389       gchar buf[1024];
1390       g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1391       gtk_gs_emit_error_msg(gs, buf);
1392       gtk_gs_cleanup(gs);
1393       gs->gs_status = _("The file is not a PostScript document.");
1394       return FALSE;
1395     }
1396
1397     if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1398        (gs->doc->epsf && gs->doc->numpages > 1)) {
1399       gs->structured_doc = TRUE;
1400       gs->send_filename_to_gs = FALSE;
1401     }
1402
1403     /* We have to set up the orientation of the document */
1404
1405
1406     /* orientation can only be portrait, and landscape or none.
1407        This is the document default. A document can have
1408        pages in landscape and some in portrait */
1409     if(gs->override_orientation) {
1410       /* If the orientation should be override... 
1411          then gs->orientation has already the correct
1412          value (it was set when the widget was created */
1413       /* So do nothing */
1414
1415     }
1416     else {
1417       /* Otherwise, set the proper orientation for the doc */
1418       gs->real_orientation = gs->doc->orientation;
1419     }
1420   }
1421   gtk_gs_set_page_size(gs, -1, gs->current_page);
1422   gs->loaded = TRUE;
1423
1424   gs->gs_status = _("Document loaded.");
1425
1426   return gs->loaded;
1427 }
1428
1429
1430 gboolean
1431 gtk_gs_next_page(GtkGS * gs)
1432 {
1433   XEvent event;
1434
1435   g_return_val_if_fail(gs != NULL, FALSE);
1436   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1437
1438   if(gs->interpreter_pid == 0) {    /* no interpreter active */
1439     return FALSE;
1440   }
1441
1442   if(gs->busy) {                /* interpreter is busy */
1443     return FALSE;
1444   }
1445
1446   gs->busy = TRUE;
1447
1448   event.xclient.type = ClientMessage;
1449   event.xclient.display = gdk_display;
1450   event.xclient.window = gs->message_window;
1451   event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1452   event.xclient.format = 32;
1453
1454   gdk_error_trap_push();
1455   XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1456   gdk_flush();
1457   gdk_error_trap_pop();
1458
1459   return TRUE;
1460 }
1461
1462 gint
1463 gtk_gs_get_current_page(GtkGS * gs)
1464 {
1465   g_return_val_if_fail(gs != NULL, -1);
1466   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1467
1468   return gs->current_page;
1469 }
1470
1471 gint
1472 gtk_gs_get_page_count(GtkGS * gs)
1473 {
1474   if(!gs->gs_filename)
1475     return 0;
1476
1477   if(gs->doc) {
1478     if(gs->structured_doc)
1479       return gs->doc->numpages;
1480     else
1481       return G_MAXINT;
1482   }
1483   else
1484     return 0;
1485 }
1486
1487 gboolean
1488 gtk_gs_goto_page(GtkGS * gs, gint page)
1489 {
1490   g_return_val_if_fail(gs != NULL, FALSE);
1491   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1492
1493   if(!gs->gs_filename) {
1494     return FALSE;
1495   }
1496
1497   /* range checking... */
1498   if(page < 0)
1499     page = 0;
1500
1501   if(gs->structured_doc && gs->doc) {
1502     if(page >= gs->doc->numpages)
1503       page = gs->doc->numpages - 1;
1504
1505     if(page == gs->current_page && !gs->changed)
1506       return TRUE;
1507
1508     gs->current_page = page;
1509
1510     if(gs->doc->pages[page].orientation != NONE &&
1511        !gs->override_orientation &&
1512        gs->doc->pages[page].orientation != gs->real_orientation) {
1513       gs->real_orientation = gs->doc->pages[page].orientation;
1514       gs->changed = TRUE;
1515     }
1516
1517     gtk_gs_set_page_size(gs, -1, page);
1518
1519     gs->changed = FALSE;
1520
1521     if(is_interpreter_ready(gs)) {
1522       gtk_gs_next_page(gs);
1523     }
1524     else {
1525       gtk_gs_enable_interpreter(gs);
1526       send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1527       send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1528     }
1529
1530     send_ps(gs, gs->doc->pages[gs->current_page].begin,
1531             gs->doc->pages[gs->current_page].len, FALSE);
1532   }
1533   else {
1534     /* Unstructured document */
1535     /* In the case of non structured documents,
1536        GS read the PS from the  actual file (via command
1537        line. Hence, ggv only send a signal next page.
1538        If ghostview is not running it is usually because
1539        the last page of the file was displayed. In that
1540        case, ggv restarts GS again and the first page is displayed.
1541      */
1542     if(page == gs->current_page && !gs->changed)
1543       return TRUE;
1544
1545     if(!is_interpreter_ready(gs))
1546       gtk_gs_enable_interpreter(gs);
1547
1548     gs->current_page = page;
1549
1550     gtk_gs_next_page(gs);
1551   }
1552   return TRUE;
1553 }
1554
1555 /*
1556  * set pagesize sets the size from
1557  * if new_pagesize is -1, then it is set to either
1558  *  a) the default settings of pageid, if they exist, or if pageid != -1.
1559  *  b) the default setting of the document, if it exists.
1560  *  c) the default setting of the widget.
1561  * otherwise, the new_pagesize is used as the pagesize
1562  */
1563 gboolean
1564 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1565 {
1566   gint new_llx = 0;
1567   gint new_lly = 0;
1568   gint new_urx = 0;
1569   gint new_ury = 0;
1570   GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1571
1572   g_return_val_if_fail(gs != NULL, FALSE);
1573   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1574
1575   if(new_pagesize == -1) {
1576     if(gs->default_size > 0)
1577       new_pagesize = gs->default_size;
1578     if(!gs->override_size && gs->doc) {
1579       /* If we have a document:
1580          We use -- the page size (if specified)
1581          or the doc. size (if specified)
1582          or the page bbox (if specified)
1583          or the bounding box
1584        */
1585       if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1586          (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1587         new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1588       }
1589       else if(gs->doc->default_page_size != NULL) {
1590         new_pagesize = gs->doc->default_page_size - gs->doc->size;
1591       }
1592       else if((pageid >= 0) &&
1593               (gs->doc->numpages > pageid) &&
1594               (gs->doc->pages) &&
1595               (gs->doc->pages[pageid].boundingbox[URX] >
1596                gs->doc->pages[pageid].boundingbox[LLX]) &&
1597               (gs->doc->pages[pageid].boundingbox[URY] >
1598                gs->doc->pages[pageid].boundingbox[LLY])) {
1599         new_pagesize = -1;
1600       }
1601       else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1602               (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1603         new_pagesize = -1;
1604       }
1605     }
1606   }
1607
1608   /* Compute bounding box */
1609   if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) {    /* epsf or bbox */
1610     if((pageid >= 0) &&
1611        (gs->doc->pages) &&
1612        (gs->doc->pages[pageid].boundingbox[URX] >
1613         gs->doc->pages[pageid].boundingbox[LLX])
1614        && (gs->doc->pages[pageid].boundingbox[URY] >
1615            gs->doc->pages[pageid].boundingbox[LLY])) {
1616       /* use page bbox */
1617       new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1618       new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1619       new_urx = gs->doc->pages[pageid].boundingbox[URX];
1620       new_ury = gs->doc->pages[pageid].boundingbox[URY];
1621     }
1622     else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1623             (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1624       /* use doc bbox */
1625       new_llx = gs->doc->boundingbox[LLX];
1626       new_lly = gs->doc->boundingbox[LLY];
1627       new_urx = gs->doc->boundingbox[URX];
1628       new_ury = gs->doc->boundingbox[URY];
1629     }
1630   }
1631   else {
1632     if(new_pagesize < 0)
1633       new_pagesize = gs->default_size;
1634     new_llx = new_lly = 0;
1635     if(gs->doc && !gs->override_size && gs->doc->size &&
1636        (new_pagesize < gs->doc->numsizes)) {
1637       new_urx = gs->doc->size[new_pagesize].width;
1638       new_ury = gs->doc->size[new_pagesize].height;
1639     }
1640     else {
1641       new_urx = papersizes[new_pagesize].width;
1642       new_ury = papersizes[new_pagesize].height;
1643     }
1644   }
1645
1646   if(new_urx <= new_llx)
1647     new_urx = papersizes[12].width;
1648   if(new_ury <= new_lly)
1649     new_ury = papersizes[12].height;
1650
1651   /* If bounding box changed, setup for new size. */
1652   /* gtk_gs_disable_interpreter (gs); */
1653   if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1654      (new_urx != gs->urx) || (new_ury != gs->ury)) {
1655     gs->llx = new_llx;
1656     gs->lly = new_lly;
1657     gs->urx = new_urx;
1658     gs->ury = new_ury;
1659     gs->changed = TRUE;
1660   }
1661
1662   if(gs->changed) {
1663     set_up_page(gs);
1664     return TRUE;
1665   }
1666
1667   return FALSE;
1668 }
1669
1670 void
1671 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1672 {
1673   gint iOldOrientation;
1674
1675   g_return_if_fail(gs != NULL);
1676   g_return_if_fail(GTK_IS_GS(gs));
1677
1678   iOldOrientation = gtk_gs_get_orientation(gs);
1679
1680   gs->override_orientation = bNewOverride;
1681
1682   /* If the current orientation is different from the 
1683      new orientation  then redisplay */
1684   if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1685     gs->changed = TRUE;
1686     set_up_page(gs);
1687   }
1688 }
1689
1690 gboolean
1691 gtk_gs_get_override_orientation(GtkGS * gs)
1692 {
1693   g_return_val_if_fail(gs != NULL, FALSE);
1694   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1695
1696   return gs->override_orientation;
1697 }
1698
1699 void
1700 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1701 {
1702   g_return_if_fail(gs != NULL);
1703   g_return_if_fail(GTK_IS_GS(gs));
1704
1705   if(f != gs->override_size) {
1706     gs->override_size = f;
1707     gs->changed = TRUE;
1708     gtk_gs_set_page_size(gs, -1, gs->current_page);
1709     set_up_page(gs);
1710   }
1711 }
1712
1713 gboolean
1714 gtk_gs_get_override_size(GtkGS * gs)
1715 {
1716   g_return_val_if_fail(gs != NULL, FALSE);
1717   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1718
1719   return gs->override_size;
1720 }
1721
1722 void
1723 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1724 {
1725   g_return_if_fail(gs != NULL);
1726   g_return_if_fail(GTK_IS_GS(gs));
1727
1728   switch (gs->zoom_mode) {
1729   case GTK_GS_ZOOM_FIT_WIDTH:
1730     zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1731     break;
1732   case GTK_GS_ZOOM_FIT_PAGE:
1733     zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1734     break;
1735   case GTK_GS_ZOOM_ABSOLUTE:
1736   default:
1737     break;
1738   }
1739   if(zoom < ggv_zoom_levels[0])
1740     zoom = ggv_zoom_levels[0];
1741   else if(zoom > ggv_zoom_levels[ggv_max_zoom_levels])
1742     zoom = ggv_zoom_levels[ggv_max_zoom_levels];
1743   if(fabs(gs->zoom_factor - zoom) > 0.001) {
1744     gs->zoom_factor = zoom;
1745     set_up_page(gs);
1746     gs->changed = TRUE;
1747   }
1748 }
1749
1750 gfloat
1751 gtk_gs_get_zoom(GtkGS * gs)
1752 {
1753   g_return_val_if_fail(gs != NULL, 0.0);
1754   g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1755
1756   return gs->zoom_factor;
1757 }
1758
1759 gfloat
1760 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1761 {
1762   gint new_y;
1763   gfloat new_zoom;
1764   guint avail_w, avail_h;
1765
1766   g_return_val_if_fail(gs != NULL, 0.0);
1767   g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1768
1769   avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1770   avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1771
1772   new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1773   if(!fit_width) {
1774     new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1775     if(new_y > avail_h)
1776       new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1777   }
1778
1779   return new_zoom;
1780 }
1781
1782 gboolean
1783 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1784 {
1785   gint iOldOrientation;
1786
1787   g_return_val_if_fail(gs != NULL, FALSE);
1788   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1789   g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1790                        (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1791                        (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1792                        (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1793
1794   iOldOrientation = gtk_gs_get_orientation(gs);
1795   gs->fallback_orientation = orientation;
1796
1797   /* We are setting the fallback orientation */
1798   if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1799     gs->changed = TRUE;
1800     set_up_page(gs);
1801     return TRUE;
1802   }
1803
1804   return FALSE;
1805 }
1806
1807 gint
1808 gtk_gs_get_default_orientation(GtkGS * gs)
1809 {
1810   g_return_val_if_fail(gs != NULL, -1);
1811   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1812
1813   return gs->fallback_orientation;
1814 }
1815
1816 gint
1817 gtk_gs_get_orientation(GtkGS * gs)
1818 {
1819   g_return_val_if_fail(gs != NULL, -1);
1820   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1821
1822   if(gs->doc) {
1823     if(gs->structured_doc) {
1824       if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1825          GTK_GS_ORIENTATION_NONE)
1826         gs->real_orientation =
1827           gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1828       else
1829         gs->real_orientation = gs->doc->default_page_orientation;
1830     }
1831
1832     if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1833       gs->real_orientation = gs->doc->orientation;
1834   }
1835
1836   if(gs->override_orientation ||
1837      gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1838     return gs->fallback_orientation;
1839   else
1840     return gs->real_orientation;
1841 }
1842
1843 void
1844 gtk_gs_set_default_size(GtkGS * gs, gint size)
1845 {
1846   g_return_if_fail(gs != NULL);
1847   g_return_if_fail(GTK_IS_GS(gs));
1848
1849   gs->default_size = size;
1850   gtk_gs_set_page_size(gs, -1, gs->current_page);
1851 }
1852
1853 gint
1854 gtk_gs_get_default_size(GtkGS * gs)
1855 {
1856   g_return_val_if_fail(gs != NULL, -1);
1857   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1858
1859   return gs->default_size;
1860 }
1861
1862 void
1863 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
1864 {
1865   g_return_if_fail(gs != NULL);
1866   g_return_if_fail(GTK_IS_GS(gs));
1867
1868   if(gs->respect_eof == f)
1869     return;
1870
1871   gs->respect_eof = f;
1872   gtk_gs_set_page_size(gs, -1, gs->current_page);
1873 }
1874
1875 gint
1876 gtk_gs_get_respect_eof(GtkGS * gs)
1877 {
1878   g_return_val_if_fail(gs != NULL, -1);
1879   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1880
1881   return gs->respect_eof;
1882 }
1883
1884 void
1885 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
1886 {
1887   g_return_if_fail(gs != NULL);
1888   g_return_if_fail(GTK_IS_GS(gs));
1889
1890   if(gs->antialiased == f)
1891     return;
1892
1893   gs->antialiased = f;
1894   gs->changed = TRUE;
1895   start_interpreter(gs);
1896   gtk_gs_goto_page(gs, gs->current_page);
1897 }
1898
1899 gint
1900 gtk_gs_get_antialiasing(GtkGS * gs)
1901 {
1902   g_return_val_if_fail(gs != NULL, -1);
1903   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1904
1905   return gs->antialiased;
1906 }
1907
1908 const gchar *
1909 gtk_gs_get_document_title(GtkGS * gs)
1910 {
1911   g_return_val_if_fail(gs != NULL, NULL);
1912   g_return_val_if_fail(GTK_IS_GS(gs), NULL);
1913
1914   if(gs->doc && gs->doc->title)
1915     return gs->doc->title;
1916
1917   return NULL;
1918 }
1919
1920 guint
1921 gtk_gs_get_document_numpages(GtkGS * widget)
1922 {
1923   g_return_val_if_fail(widget != NULL, 0);
1924   g_return_val_if_fail(GTK_IS_GS(widget), 0);
1925
1926   if(widget->doc)
1927     return widget->doc->numpages;
1928
1929   return 0;
1930 }
1931
1932 const gchar *
1933 gtk_gs_get_document_page_label(GtkGS * widget, int page)
1934 {
1935   g_return_val_if_fail(widget != NULL, NULL);
1936   g_return_val_if_fail(GTK_IS_GS(widget), NULL);
1937
1938   if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
1939     return widget->doc->pages[page - 1].label;
1940
1941   return NULL;
1942 }
1943
1944 gint
1945 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
1946 {
1947   guint idx = 0;
1948
1949   while(size[idx].name != NULL) {
1950     if(strcmp(size[idx].name, string) == 0)
1951       return idx;
1952     idx++;
1953   }
1954
1955   return -1;
1956 }
1957
1958 gchar *
1959 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
1960 {
1961   GtkGSDocSink *sink;
1962   gchar *doc;
1963   gboolean free_pages = FALSE;
1964
1965   if(pages == NULL) {
1966     if(!gs->structured_doc) {
1967       FILE *f;
1968       struct stat sb;
1969
1970       if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
1971         return NULL;
1972       doc = g_new(gchar, sb.st_size);
1973       if(!doc)
1974         return NULL;
1975       f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
1976       if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
1977         g_free(doc);
1978         doc = NULL;
1979       }
1980       if(NULL != f)
1981         fclose(f);
1982       return doc;
1983     }
1984     else {
1985       int i, n = gtk_gs_get_page_count(gs);
1986       pages = g_new0(gint, n);
1987       for(i = 0; i < n; i++)
1988         pages[i] = TRUE;
1989       free_pages = TRUE;
1990     }
1991   }
1992
1993   sink = gtk_gs_doc_sink_new();
1994
1995   if(GTK_GS_IS_PDF(gs)) {
1996     gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1997     gchar *cmd, *fname;
1998     int tmpfd;
1999
2000     if((tmpfd = mkstemp(tmpn)) < 0) {
2001       g_free(tmpn);
2002       return NULL;
2003     }
2004     close(tmpfd);
2005     fname = g_shell_quote (gs->gs_filename_unc ?
2006                            gs->gs_filename_unc : gs->gs_filename);
2007     cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2008     g_free(fname);
2009     if((system(cmd) == 0) && ggv_file_readable(tmpn)) {
2010       GObject *tmp_gs;
2011       tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2012       if(NULL != tmp_gs) {
2013         if(GTK_GS(tmp_gs)->loaded)
2014           pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2015         g_object_unref(tmp_gs);
2016       }
2017     }
2018     g_free(cmd);
2019     g_free(tmpn);
2020   }
2021   else {
2022     /* Use uncompressed file if necessary */
2023     pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2024   }
2025   if(free_pages)
2026     g_free(pages);
2027   doc = gtk_gs_doc_sink_get_buffer(sink);
2028   gtk_gs_doc_sink_free(sink);
2029   return doc;
2030 }
2031
2032 void
2033 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2034 {
2035   if(zoom_mode != gs->zoom_mode) {
2036     gs->zoom_mode = zoom_mode;
2037     gtk_gs_set_zoom(gs, 1.0);
2038   }
2039 }
2040
2041 GtkGSZoomMode
2042 gtk_gs_get_zoom_mode(GtkGS * gs)
2043 {
2044   return gs->zoom_mode;
2045 }
2046
2047 void
2048 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2049 {
2050   gs->avail_w = avail_w;
2051   gs->avail_h = avail_h;
2052   if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2053     gtk_gs_set_zoom(gs, 0.0);
2054   }
2055 }
2056
2057 static gboolean
2058 ps_document_load (EvDocument  *document,
2059                    const char  *uri,
2060                    GError     **error)
2061 {
2062         gboolean result;
2063         char *filename;
2064
2065         filename = g_filename_from_uri (uri, NULL, error);
2066         if (!filename)
2067                 return FALSE;
2068
2069         result = gtk_gs_load (GTK_GS (document), filename);
2070
2071         g_free (filename);
2072
2073         return result;
2074 }
2075
2076 static int
2077 ps_document_get_n_pages (EvDocument  *document)
2078 {
2079         return gtk_gs_get_page_count (GTK_GS (document));
2080 }
2081
2082 static void
2083 ps_document_set_page (EvDocument  *document,
2084                        int          page)
2085 {
2086         gtk_gs_goto_page (GTK_GS (document), page);
2087 }
2088
2089 static int
2090 ps_document_get_page (EvDocument  *document)
2091 {
2092         return gtk_gs_get_current_page (GTK_GS (document));
2093 }
2094
2095 static gboolean
2096 gtk_gs_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
2097 {
2098         GtkGS *gs = (GtkGS *) data;
2099
2100         if(event->type != GDK_CLIENT_EVENT)
2101                 return FALSE;
2102
2103         if (event->client.message_type == gs_class->page_atom) {
2104                 gs->busy = FALSE;
2105                 ev_document_changed (EV_DOCUMENT (gs));
2106         }
2107
2108         return TRUE;
2109 }
2110
2111 static void
2112 ps_document_set_target (EvDocument  *document,
2113                         GdkDrawable *target)
2114 {
2115         GtkGS *gs = GTK_GS (document);
2116         GtkWidget *widget;
2117         gpointer data;
2118
2119         gs->pstarget = target;
2120
2121         if (gs->pstarget) {
2122                 gdk_window_get_user_data (gs->pstarget, &data);
2123                 g_return_if_fail (GTK_IS_WIDGET (data));
2124
2125                 widget = GTK_WIDGET (data);
2126                 g_signal_connect (widget, "event",
2127                                   G_CALLBACK (gtk_gs_widget_event),
2128                                   document);
2129         }
2130
2131         gtk_gs_goto_page (gs, gs->current_page);
2132 }
2133
2134 static void
2135 ps_document_set_scale (EvDocument  *document,
2136                         double       scale)
2137 {
2138         gtk_gs_set_zoom (GTK_GS (document), scale);
2139 }
2140
2141 static void
2142 ps_document_set_page_offset (EvDocument  *document,
2143                               int          x,
2144                               int          y)
2145 {
2146 }
2147
2148 static void
2149 ps_document_get_page_size (EvDocument   *document,
2150                             int          *width,
2151                             int          *height)
2152 {
2153         GtkGS *gs = GTK_GS (document);
2154
2155         if (width) {
2156                 *width = gs->width;
2157         }
2158
2159         if (height) {
2160                 *height = gs->height;
2161         }
2162 }
2163
2164 static void
2165 ps_document_render (EvDocument  *document,
2166                     int          clip_x,
2167                     int          clip_y,
2168                     int          clip_width,
2169                     int          clip_height)
2170 {
2171         GtkGS *gs = GTK_GS (document);
2172         GdkGC *gc;
2173
2174         if (gs->pstarget == NULL ||
2175             gs->bpixmap == NULL) {
2176                 return;
2177         }
2178
2179         gc = gdk_gc_new (gs->pstarget);
2180
2181         gdk_draw_drawable (gs->pstarget, gc,
2182                            gs->bpixmap,
2183                            clip_x, clip_y,
2184                            clip_x, clip_y,
2185                            clip_width, clip_height);
2186
2187         g_object_unref (gc);
2188 }
2189
2190 static void
2191 ps_document_document_iface_init (EvDocumentIface *iface)
2192 {
2193         iface->load = ps_document_load;
2194         iface->get_n_pages = ps_document_get_n_pages;
2195         iface->set_page = ps_document_set_page;
2196         iface->get_page = ps_document_get_page;
2197         iface->set_scale = ps_document_set_scale;
2198         iface->set_target = ps_document_set_target;
2199         iface->set_page_offset = ps_document_set_page_offset;
2200         iface->get_page_size = ps_document_get_page_size;
2201         iface->render = ps_document_render;
2202 }