]> www.fi.muni.cz Git - evince.git/blob - ps/gtkgs.c
Cleanup headers dependencies
[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 #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 "ev-document.h"
153 #include "gtkgs.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 /* If file exists and is a regular file then return its length, else -1 */
930 static gint
931 file_length(const gchar * filename)
932 {
933   struct stat stat_rec;
934
935   if(filename && (stat(filename, &stat_rec) == 0)
936      && S_ISREG(stat_rec.st_mode))
937     return stat_rec.st_size;
938   else
939     return -1;
940 }
941
942 /* Test if file exists, is a regular file and its length is > 0 */
943 static gboolean
944 file_readable(const char *filename)
945 {
946   return (file_length(filename) > 0);
947 }
948
949 /*
950  * Decompress gs->gs_filename if necessary
951  * Set gs->filename_unc to the name of the uncompressed file or NULL.
952  * Error reporting via signal 'interpreter_message'
953  * Return name of input file to use or NULL on error..
954  */
955 static gchar *
956 check_filecompressed(GtkGS * gs)
957 {
958   FILE *file;
959   gchar buf[1024];
960   gchar *filename, *filename_unc, *filename_err, *cmdline;
961   const gchar *cmd;
962   int fd;
963
964   cmd = NULL;
965
966   if((file = fopen(gs->gs_filename, "r"))
967      && (fread(buf, sizeof(gchar), 3, file) == 3)) {
968     if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
969       /* file is gzipped or compressed */
970       cmd = gtk_gs_defaults_get_ungzip_cmd();
971     }
972     else if(strncmp(buf, "BZh", 3) == 0) {
973       /* file is compressed with bzip2 */
974       cmd = gtk_gs_defaults_get_unbzip2_cmd();
975     }
976   }
977   if(NULL != file)
978     fclose(file);
979
980   if(!cmd)
981     return gs->gs_filename;
982
983   /* do the decompression */
984   filename = g_shell_quote(gs->gs_filename);
985   filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
986   if((fd = mkstemp(filename_unc)) < 0) {
987     g_free(filename_unc);
988     g_free(filename);
989     return NULL;
990   }
991   close(fd);
992   filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
993   if((fd = mkstemp(filename_err)) < 0) {
994     g_free(filename_err);
995     g_free(filename_unc);
996     g_free(filename);
997     return NULL;
998   }
999   close(fd);
1000   cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1001                             filename, filename_unc, filename_err);
1002   if((system(cmdline) == 0)
1003      && file_readable(filename_unc)
1004      && (file_length(filename_err) == 0)) {
1005     /* sucessfully uncompressed file */
1006     gs->gs_filename_unc = filename_unc;
1007   }
1008   else {
1009     /* report error */
1010     g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1011                gs->gs_filename);
1012     gtk_gs_emit_error_msg(gs, buf);
1013     if(file_length(filename_err) > 0) {
1014       FILE *err;
1015       if((err = fopen(filename_err, "r"))) {
1016         /* print file to message window */
1017         while(fgets(buf, 1024, err))
1018           gtk_gs_emit_error_msg(gs, buf);
1019         fclose(err);
1020       }
1021     }
1022     unlink(filename_unc);
1023     g_free(filename_unc);
1024     filename_unc = NULL;
1025   }
1026   unlink(filename_err);
1027   g_free(filename_err);
1028   g_free(cmdline);
1029   g_free(filename);
1030   return filename_unc;
1031 }
1032
1033 /*
1034  * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1035  * pdf file if necessary.
1036  * Set gs->filename_dsc to the name of the dsc file or NULL.
1037  * Error reporting via signal 'interpreter_message'.
1038  */
1039 static gchar *
1040 check_pdf(GtkGS * gs)
1041 {
1042   FILE *file;
1043   gchar buf[1024], *filename;
1044   int fd;
1045
1046   /* use uncompressed file as input if necessary */
1047   filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1048
1049   if((file = fopen(filename, "r"))
1050      && (fread(buf, sizeof(char), 5, file) == 5)
1051      && (strncmp(buf, "%PDF-", 5) == 0)) {
1052     /* we found a PDF file */
1053     gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1054     filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1055     if((fd = mkstemp(filename_dsc)) < 0) {
1056       return NULL;
1057     }
1058     close(fd);
1059     filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1060     if((fd = mkstemp(filename_err)) < 0) {
1061       g_free(filename_dsc);
1062       return NULL;
1063     }
1064     close(fd);
1065     fname = g_shell_quote(filename);
1066     cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1067     g_free(fname);
1068     /* this command (sometimes?) prints error messages to stdout! */
1069     cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1070     g_free(cmd);
1071
1072     if((system(cmdline) == 0) && file_readable(filename_dsc)) {
1073
1074       /* success */
1075       filename = gs->gs_filename_dsc = filename_dsc;
1076
1077       if(file_length(filename_err) > 0) {
1078         gchar *err_msg = " ";
1079         GtkWidget *dialog;
1080         FILE *err;
1081         GdkColor color;
1082
1083         if((err = fopen(filename_err, "r"))) {
1084
1085           /* print the content of the file to a message box */
1086           while(fgets(buf, 1024, err))
1087             err_msg = g_strconcat(err_msg, buf, NULL);
1088
1089           /* FIXME The dialog is not yet set to modal, difficult to 
1090            * get the parent of the dialog box here 
1091            */
1092
1093           dialog = gtk_message_dialog_new(NULL,
1094                                           GTK_DIALOG_MODAL,
1095                                           GTK_MESSAGE_WARNING,
1096                                           GTK_BUTTONS_OK,
1097                                           ("There was an error while scaning the file: %s \n%s"),
1098                                           gs->gs_filename, err_msg);
1099
1100           gdk_color_parse("white", &color);
1101           gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1102
1103           g_signal_connect(G_OBJECT(dialog), "response",
1104                            G_CALLBACK(gtk_widget_destroy), NULL);
1105
1106           gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1107           gtk_widget_show(dialog);
1108           g_free(err_msg);
1109         }
1110       }
1111
1112     }
1113     else {
1114       /* report error */
1115       g_snprintf(buf, 1024,
1116                  _("Error while converting pdf file %s:\n"), filename);
1117       gtk_gs_emit_error_msg(gs, buf);
1118
1119       if(file_length(filename_err) > 0) {
1120         FILE *err;
1121         if((err = fopen(filename_err, "r"))) {
1122           /* print file to message window */
1123           while(fgets(buf, 1024, err))
1124             gtk_gs_emit_error_msg(gs, buf);
1125         }
1126       }
1127       unlink(filename_dsc);
1128       g_free(filename_dsc);
1129       filename = NULL;
1130     }
1131     unlink(filename_err);
1132     g_free(filename_err);
1133     g_free(cmdline);
1134   }
1135   if(NULL != file)
1136     fclose(file);
1137   return filename;
1138 }
1139
1140 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1141 /* never mind this patch: a properly working X server should take care of
1142    calculating the proper values. */
1143 static float
1144 compute_xdpi(void)
1145 {
1146 #   ifndef HAVE_XINERAMA
1147   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1148 #   else
1149   Display *dpy;
1150   dpy = (Display *) GDK_DISPLAY();
1151   if(XineramaIsActive(dpy)) {
1152     int num_heads;
1153     XineramaScreenInfo *head_info;
1154     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1155     /* fake it with dimensions of the first head for now */
1156     return 25.4 * head_info[0].width / gdk_screen_width_mm();
1157   }
1158   else {
1159     return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1160   }
1161 #   endif
1162   /* HAVE_XINERAMA */
1163 }
1164
1165 static float
1166 compute_ydpi(void)
1167 {
1168 #   ifndef HAVE_XINERAMA
1169   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1170 #   else
1171   Display *dpy;
1172   dpy = (Display *) GDK_DISPLAY();
1173   if(XineramaIsActive(dpy)) {
1174     int num_heads;
1175     XineramaScreenInfo *head_info;
1176     head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1177     /* fake it with dimensions of the first head for now */
1178     return 25.4 * head_info[0].height / gdk_screen_height_mm();
1179   }
1180   else {
1181     return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1182   }
1183 #   endif
1184   /* HAVE_XINERAMA */
1185 }
1186 #else
1187 static float
1188 compute_xdpi(void)
1189 {
1190   return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1191 }
1192
1193 static float
1194 compute_ydpi(void)
1195 {
1196   return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1197 }
1198 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1199
1200 /* Compute new size of window, sets xdpi and ydpi if necessary.
1201  * returns True if new window size is different */
1202 static gboolean
1203 compute_size(GtkGS * gs)
1204 {
1205   guint new_width = 1;
1206   guint new_height = 1;
1207   gboolean change = FALSE;
1208   gint orientation;
1209
1210   /* width and height can be changed, calculate window size according */
1211   /* to xpdi and ydpi */
1212   orientation = gtk_gs_get_orientation(gs);
1213
1214   switch (orientation) {
1215   case GTK_GS_ORIENTATION_PORTRAIT:
1216   case GTK_GS_ORIENTATION_UPSIDEDOWN:
1217     new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1218     new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1219     break;
1220   case GTK_GS_ORIENTATION_LANDSCAPE:
1221   case GTK_GS_ORIENTATION_SEASCAPE:
1222     new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1223     new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1224     break;
1225   }
1226
1227   change = (new_width != gs->width * gs->zoom_factor)
1228     || (new_height != gs->height * gs->zoom_factor);
1229   gs->width = (gint) (new_width * gs->zoom_factor);
1230   gs->height = (gint) (new_height * gs->zoom_factor);
1231
1232   return (change);
1233 }
1234
1235 gint
1236 gtk_gs_enable_interpreter(GtkGS * gs)
1237 {
1238   g_return_val_if_fail(gs != NULL, FALSE);
1239   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1240
1241   if(!gs->gs_filename)
1242     return 0;
1243
1244   gs->disable_start = FALSE;
1245   
1246   return start_interpreter(gs);
1247 }
1248
1249 /* publicly accessible functions */
1250
1251 GType
1252 gtk_gs_get_type(void)
1253 {
1254   static GType gs_type = 0;
1255   if(!gs_type) {
1256     GTypeInfo gs_info = {
1257       sizeof(GtkGSClass),
1258       (GBaseInitFunc) NULL,
1259       (GBaseFinalizeFunc) NULL,
1260       (GClassInitFunc) gtk_gs_class_init,
1261       (GClassFinalizeFunc) NULL,
1262       NULL,                     /* class_data */
1263       sizeof(GtkGS),
1264       0,                        /* n_preallocs */
1265       (GInstanceInitFunc) gtk_gs_init
1266     };
1267
1268     static const GInterfaceInfo document_info =
1269     {
1270         (GInterfaceInitFunc) ps_document_document_iface_init,
1271         NULL,
1272         NULL
1273     };
1274
1275     gs_type = g_type_register_static(G_TYPE_OBJECT,
1276                                      "GtkGS", &gs_info, 0);
1277
1278     g_type_add_interface_static (gs_type,
1279                                  EV_TYPE_DOCUMENT,
1280                                  &document_info);
1281   }
1282   return gs_type;
1283
1284
1285 }
1286
1287 GObject *
1288 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1289 {
1290   GObject *gs;
1291
1292   gs = g_object_new(GTK_GS_TYPE, NULL);
1293
1294   return gs;
1295 }
1296
1297
1298 GObject *
1299 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1300 {
1301   GObject *gs = gtk_gs_new(hadj, vadj);
1302   gtk_gs_load(GTK_GS(gs), fname);
1303   return gs;
1304 }
1305
1306 void
1307 gtk_gs_reload(GtkGS * gs)
1308 {
1309   gchar *fname;
1310   gint page;
1311
1312   if(!gs->gs_filename)
1313     return;
1314
1315   page = gtk_gs_get_current_page(gs);
1316   fname = g_strdup(gs->gs_filename);
1317   gtk_gs_load(gs, fname);
1318   gtk_gs_goto_page(gs, page);
1319   g_free(fname);
1320 }
1321
1322
1323 /*
1324  * Show error message -> send signal "interpreter_message"
1325  */
1326 static void
1327 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1328 {
1329   g_signal_emit (G_OBJECT(gs),
1330                  gtk_gs_signals[INTERPRETER_MESSAGE], 0, g_strdup(msg));
1331 }
1332
1333 void
1334 gtk_gs_disable_interpreter(GtkGS * gs)
1335 {
1336   g_return_if_fail(gs != NULL);
1337   g_return_if_fail(GTK_IS_GS(gs));
1338
1339   gs->disable_start = TRUE;
1340
1341   stop_interpreter(gs);
1342 }
1343
1344 gboolean
1345 gtk_gs_load(GtkGS * gs, const gchar * fname)
1346 {
1347   g_return_val_if_fail(gs != NULL, FALSE);
1348   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1349
1350   /* clean up previous document */
1351   gtk_gs_cleanup(gs);
1352
1353   if(fname == NULL) {
1354     gs->gs_status = "";
1355     return FALSE;
1356   }
1357
1358   /* prepare this document */
1359
1360   /* default values: no dsc information available  */
1361   gs->structured_doc = FALSE;
1362   gs->send_filename_to_gs = TRUE;
1363   gs->current_page = -2;
1364   gs->loaded = FALSE;
1365   if(*fname == '/') {
1366     /* an absolute path */
1367     gs->gs_filename = g_strdup(fname);
1368   }
1369   else {
1370     /* path relative to our cwd: make it absolute */
1371     gchar *cwd = g_get_current_dir();
1372     gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1373     g_free(cwd);
1374   }
1375
1376   if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1377     gs->send_filename_to_gs = FALSE;
1378   }
1379   else {
1380     /*
1381      * We need to make sure that the file is loadable/exists!
1382      * otherwise we want to exit without loading new stuff...
1383      */
1384     gchar *filename = NULL;
1385
1386     if(!file_readable(fname)) {
1387       gchar buf[1024];
1388       g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1389       gtk_gs_emit_error_msg(gs, buf);
1390       gs->gs_status = _("File is not readable.");
1391     }
1392     else {
1393       filename = check_filecompressed(gs);
1394       if(filename)
1395         filename = check_pdf(gs);
1396     }
1397
1398     if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1399       gtk_gs_cleanup(gs);
1400       return FALSE;
1401     }
1402
1403     /* we grab the vital statistics!!! */
1404     gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1405
1406     if(gs->doc == NULL) {
1407       /* File does not seem to be a Postscript one */
1408       gchar buf[1024];
1409       g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1410       gtk_gs_emit_error_msg(gs, buf);
1411       gtk_gs_cleanup(gs);
1412       gs->gs_status = _("The file is not a PostScript document.");
1413       return FALSE;
1414     }
1415
1416     if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1417        (gs->doc->epsf && gs->doc->numpages > 1)) {
1418       gs->structured_doc = TRUE;
1419       gs->send_filename_to_gs = FALSE;
1420     }
1421
1422     /* We have to set up the orientation of the document */
1423
1424
1425     /* orientation can only be portrait, and landscape or none.
1426        This is the document default. A document can have
1427        pages in landscape and some in portrait */
1428     if(gs->override_orientation) {
1429       /* If the orientation should be override... 
1430          then gs->orientation has already the correct
1431          value (it was set when the widget was created */
1432       /* So do nothing */
1433
1434     }
1435     else {
1436       /* Otherwise, set the proper orientation for the doc */
1437       gs->real_orientation = gs->doc->orientation;
1438     }
1439   }
1440   gtk_gs_set_page_size(gs, -1, gs->current_page);
1441   gs->loaded = TRUE;
1442
1443   gs->gs_status = _("Document loaded.");
1444
1445   return gs->loaded;
1446 }
1447
1448
1449 gboolean
1450 gtk_gs_next_page(GtkGS * gs)
1451 {
1452   XEvent event;
1453
1454   g_return_val_if_fail(gs != NULL, FALSE);
1455   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1456
1457   if(gs->interpreter_pid == 0) {    /* no interpreter active */
1458     return FALSE;
1459   }
1460
1461   if(gs->busy) {                /* interpreter is busy */
1462     return FALSE;
1463   }
1464
1465   gs->busy = TRUE;
1466
1467   event.xclient.type = ClientMessage;
1468   event.xclient.display = gdk_display;
1469   event.xclient.window = gs->message_window;
1470   event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1471   event.xclient.format = 32;
1472
1473   gdk_error_trap_push();
1474   XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1475   gdk_flush();
1476   gdk_error_trap_pop();
1477
1478   return TRUE;
1479 }
1480
1481 gint
1482 gtk_gs_get_current_page(GtkGS * gs)
1483 {
1484   g_return_val_if_fail(gs != NULL, -1);
1485   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1486
1487   return gs->current_page;
1488 }
1489
1490 gint
1491 gtk_gs_get_page_count(GtkGS * gs)
1492 {
1493   if(!gs->gs_filename)
1494     return 0;
1495
1496   if(gs->doc) {
1497     if(gs->structured_doc)
1498       return gs->doc->numpages;
1499     else
1500       return G_MAXINT;
1501   }
1502   else
1503     return 0;
1504 }
1505
1506 gboolean
1507 gtk_gs_goto_page(GtkGS * gs, gint page)
1508 {
1509   g_return_val_if_fail(gs != NULL, FALSE);
1510   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1511
1512   if(!gs->gs_filename) {
1513     return FALSE;
1514   }
1515
1516   /* range checking... */
1517   if(page < 0)
1518     page = 0;
1519
1520   if(gs->structured_doc && gs->doc) {
1521     if(page >= gs->doc->numpages)
1522       page = gs->doc->numpages - 1;
1523
1524     if(page == gs->current_page && !gs->changed)
1525       return TRUE;
1526
1527     gs->current_page = page;
1528
1529     if(gs->doc->pages[page].orientation != NONE &&
1530        !gs->override_orientation &&
1531        gs->doc->pages[page].orientation != gs->real_orientation) {
1532       gs->real_orientation = gs->doc->pages[page].orientation;
1533       gs->changed = TRUE;
1534     }
1535
1536     gtk_gs_set_page_size(gs, -1, page);
1537
1538     gs->changed = FALSE;
1539
1540     if(is_interpreter_ready(gs)) {
1541       gtk_gs_next_page(gs);
1542     }
1543     else {
1544       gtk_gs_enable_interpreter(gs);
1545       send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1546       send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1547     }
1548
1549     send_ps(gs, gs->doc->pages[gs->current_page].begin,
1550             gs->doc->pages[gs->current_page].len, FALSE);
1551   }
1552   else {
1553     /* Unstructured document */
1554     /* In the case of non structured documents,
1555        GS read the PS from the  actual file (via command
1556        line. Hence, ggv only send a signal next page.
1557        If ghostview is not running it is usually because
1558        the last page of the file was displayed. In that
1559        case, ggv restarts GS again and the first page is displayed.
1560      */
1561     if(page == gs->current_page && !gs->changed)
1562       return TRUE;
1563
1564     if(!is_interpreter_ready(gs))
1565       gtk_gs_enable_interpreter(gs);
1566
1567     gs->current_page = page;
1568
1569     gtk_gs_next_page(gs);
1570   }
1571   return TRUE;
1572 }
1573
1574 /*
1575  * set pagesize sets the size from
1576  * if new_pagesize is -1, then it is set to either
1577  *  a) the default settings of pageid, if they exist, or if pageid != -1.
1578  *  b) the default setting of the document, if it exists.
1579  *  c) the default setting of the widget.
1580  * otherwise, the new_pagesize is used as the pagesize
1581  */
1582 gboolean
1583 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1584 {
1585   gint new_llx = 0;
1586   gint new_lly = 0;
1587   gint new_urx = 0;
1588   gint new_ury = 0;
1589   GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1590
1591   g_return_val_if_fail(gs != NULL, FALSE);
1592   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1593
1594   if(new_pagesize == -1) {
1595     if(gs->default_size > 0)
1596       new_pagesize = gs->default_size;
1597     if(!gs->override_size && gs->doc) {
1598       /* If we have a document:
1599          We use -- the page size (if specified)
1600          or the doc. size (if specified)
1601          or the page bbox (if specified)
1602          or the bounding box
1603        */
1604       if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1605          (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1606         new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1607       }
1608       else if(gs->doc->default_page_size != NULL) {
1609         new_pagesize = gs->doc->default_page_size - gs->doc->size;
1610       }
1611       else if((pageid >= 0) &&
1612               (gs->doc->numpages > pageid) &&
1613               (gs->doc->pages) &&
1614               (gs->doc->pages[pageid].boundingbox[URX] >
1615                gs->doc->pages[pageid].boundingbox[LLX]) &&
1616               (gs->doc->pages[pageid].boundingbox[URY] >
1617                gs->doc->pages[pageid].boundingbox[LLY])) {
1618         new_pagesize = -1;
1619       }
1620       else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1621               (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1622         new_pagesize = -1;
1623       }
1624     }
1625   }
1626
1627   /* Compute bounding box */
1628   if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) {    /* epsf or bbox */
1629     if((pageid >= 0) &&
1630        (gs->doc->pages) &&
1631        (gs->doc->pages[pageid].boundingbox[URX] >
1632         gs->doc->pages[pageid].boundingbox[LLX])
1633        && (gs->doc->pages[pageid].boundingbox[URY] >
1634            gs->doc->pages[pageid].boundingbox[LLY])) {
1635       /* use page bbox */
1636       new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1637       new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1638       new_urx = gs->doc->pages[pageid].boundingbox[URX];
1639       new_ury = gs->doc->pages[pageid].boundingbox[URY];
1640     }
1641     else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1642             (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1643       /* use doc bbox */
1644       new_llx = gs->doc->boundingbox[LLX];
1645       new_lly = gs->doc->boundingbox[LLY];
1646       new_urx = gs->doc->boundingbox[URX];
1647       new_ury = gs->doc->boundingbox[URY];
1648     }
1649   }
1650   else {
1651     if(new_pagesize < 0)
1652       new_pagesize = gs->default_size;
1653     new_llx = new_lly = 0;
1654     if(gs->doc && !gs->override_size && gs->doc->size &&
1655        (new_pagesize < gs->doc->numsizes)) {
1656       new_urx = gs->doc->size[new_pagesize].width;
1657       new_ury = gs->doc->size[new_pagesize].height;
1658     }
1659     else {
1660       new_urx = papersizes[new_pagesize].width;
1661       new_ury = papersizes[new_pagesize].height;
1662     }
1663   }
1664
1665   if(new_urx <= new_llx)
1666     new_urx = papersizes[12].width;
1667   if(new_ury <= new_lly)
1668     new_ury = papersizes[12].height;
1669
1670   /* If bounding box changed, setup for new size. */
1671   /* gtk_gs_disable_interpreter (gs); */
1672   if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1673      (new_urx != gs->urx) || (new_ury != gs->ury)) {
1674     gs->llx = new_llx;
1675     gs->lly = new_lly;
1676     gs->urx = new_urx;
1677     gs->ury = new_ury;
1678     gs->changed = TRUE;
1679   }
1680
1681   if(gs->changed) {
1682     set_up_page(gs);
1683     return TRUE;
1684   }
1685
1686   return FALSE;
1687 }
1688
1689 void
1690 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1691 {
1692   gint iOldOrientation;
1693
1694   g_return_if_fail(gs != NULL);
1695   g_return_if_fail(GTK_IS_GS(gs));
1696
1697   iOldOrientation = gtk_gs_get_orientation(gs);
1698
1699   gs->override_orientation = bNewOverride;
1700
1701   /* If the current orientation is different from the 
1702      new orientation  then redisplay */
1703   if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1704     gs->changed = TRUE;
1705     set_up_page(gs);
1706   }
1707 }
1708
1709 gboolean
1710 gtk_gs_get_override_orientation(GtkGS * gs)
1711 {
1712   g_return_val_if_fail(gs != NULL, FALSE);
1713   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1714
1715   return gs->override_orientation;
1716 }
1717
1718 void
1719 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1720 {
1721   g_return_if_fail(gs != NULL);
1722   g_return_if_fail(GTK_IS_GS(gs));
1723
1724   if(f != gs->override_size) {
1725     gs->override_size = f;
1726     gs->changed = TRUE;
1727     gtk_gs_set_page_size(gs, -1, gs->current_page);
1728     set_up_page(gs);
1729   }
1730 }
1731
1732 gboolean
1733 gtk_gs_get_override_size(GtkGS * gs)
1734 {
1735   g_return_val_if_fail(gs != NULL, FALSE);
1736   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1737
1738   return gs->override_size;
1739 }
1740
1741 void
1742 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1743 {
1744   g_return_if_fail(gs != NULL);
1745   g_return_if_fail(GTK_IS_GS(gs));
1746
1747   switch (gs->zoom_mode) {
1748   case GTK_GS_ZOOM_FIT_WIDTH:
1749     zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1750     break;
1751   case GTK_GS_ZOOM_FIT_PAGE:
1752     zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1753     break;
1754   case GTK_GS_ZOOM_ABSOLUTE:
1755   default:
1756     break;
1757   }
1758
1759   if(fabs(gs->zoom_factor - zoom) > 0.001) {
1760     gs->zoom_factor = zoom;
1761     set_up_page(gs);
1762     gs->changed = TRUE;
1763   }
1764
1765   gtk_gs_goto_page(gs, gs->current_page);
1766 }
1767
1768 gfloat
1769 gtk_gs_get_zoom(GtkGS * gs)
1770 {
1771   g_return_val_if_fail(gs != NULL, 0.0);
1772   g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1773
1774   return gs->zoom_factor;
1775 }
1776
1777 gfloat
1778 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1779 {
1780   gint new_y;
1781   gfloat new_zoom;
1782   guint avail_w, avail_h;
1783
1784   g_return_val_if_fail(gs != NULL, 0.0);
1785   g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1786
1787   avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1788   avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1789
1790   new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1791   if(!fit_width) {
1792     new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1793     if(new_y > avail_h)
1794       new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1795   }
1796
1797   return new_zoom;
1798 }
1799
1800 gboolean
1801 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1802 {
1803   gint iOldOrientation;
1804
1805   g_return_val_if_fail(gs != NULL, FALSE);
1806   g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1807   g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1808                        (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1809                        (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1810                        (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1811
1812   iOldOrientation = gtk_gs_get_orientation(gs);
1813   gs->fallback_orientation = orientation;
1814
1815   /* We are setting the fallback orientation */
1816   if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1817     gs->changed = TRUE;
1818     set_up_page(gs);
1819     return TRUE;
1820   }
1821
1822   return FALSE;
1823 }
1824
1825 gint
1826 gtk_gs_get_default_orientation(GtkGS * gs)
1827 {
1828   g_return_val_if_fail(gs != NULL, -1);
1829   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1830
1831   return gs->fallback_orientation;
1832 }
1833
1834 gint
1835 gtk_gs_get_orientation(GtkGS * gs)
1836 {
1837   g_return_val_if_fail(gs != NULL, -1);
1838   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1839
1840   if(gs->doc) {
1841     if(gs->structured_doc) {
1842       if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1843          GTK_GS_ORIENTATION_NONE)
1844         gs->real_orientation =
1845           gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1846       else
1847         gs->real_orientation = gs->doc->default_page_orientation;
1848     }
1849
1850     if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1851       gs->real_orientation = gs->doc->orientation;
1852   }
1853
1854   if(gs->override_orientation ||
1855      gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1856     return gs->fallback_orientation;
1857   else
1858     return gs->real_orientation;
1859 }
1860
1861 void
1862 gtk_gs_set_default_size(GtkGS * gs, gint size)
1863 {
1864   g_return_if_fail(gs != NULL);
1865   g_return_if_fail(GTK_IS_GS(gs));
1866
1867   gs->default_size = size;
1868   gtk_gs_set_page_size(gs, -1, gs->current_page);
1869 }
1870
1871 gint
1872 gtk_gs_get_default_size(GtkGS * gs)
1873 {
1874   g_return_val_if_fail(gs != NULL, -1);
1875   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1876
1877   return gs->default_size;
1878 }
1879
1880 void
1881 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
1882 {
1883   g_return_if_fail(gs != NULL);
1884   g_return_if_fail(GTK_IS_GS(gs));
1885
1886   if(gs->respect_eof == f)
1887     return;
1888
1889   gs->respect_eof = f;
1890   gtk_gs_set_page_size(gs, -1, gs->current_page);
1891 }
1892
1893 gint
1894 gtk_gs_get_respect_eof(GtkGS * gs)
1895 {
1896   g_return_val_if_fail(gs != NULL, -1);
1897   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1898
1899   return gs->respect_eof;
1900 }
1901
1902 void
1903 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
1904 {
1905   g_return_if_fail(gs != NULL);
1906   g_return_if_fail(GTK_IS_GS(gs));
1907
1908   if(gs->antialiased == f)
1909     return;
1910
1911   gs->antialiased = f;
1912   gs->changed = TRUE;
1913   start_interpreter(gs);
1914   gtk_gs_goto_page(gs, gs->current_page);
1915 }
1916
1917 gint
1918 gtk_gs_get_antialiasing(GtkGS * gs)
1919 {
1920   g_return_val_if_fail(gs != NULL, -1);
1921   g_return_val_if_fail(GTK_IS_GS(gs), -1);
1922
1923   return gs->antialiased;
1924 }
1925
1926 const gchar *
1927 gtk_gs_get_document_title(GtkGS * gs)
1928 {
1929   g_return_val_if_fail(gs != NULL, NULL);
1930   g_return_val_if_fail(GTK_IS_GS(gs), NULL);
1931
1932   if(gs->doc && gs->doc->title)
1933     return gs->doc->title;
1934
1935   return NULL;
1936 }
1937
1938 guint
1939 gtk_gs_get_document_numpages(GtkGS * widget)
1940 {
1941   g_return_val_if_fail(widget != NULL, 0);
1942   g_return_val_if_fail(GTK_IS_GS(widget), 0);
1943
1944   if(widget->doc)
1945     return widget->doc->numpages;
1946
1947   return 0;
1948 }
1949
1950 const gchar *
1951 gtk_gs_get_document_page_label(GtkGS * widget, int page)
1952 {
1953   g_return_val_if_fail(widget != NULL, NULL);
1954   g_return_val_if_fail(GTK_IS_GS(widget), NULL);
1955
1956   if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
1957     return widget->doc->pages[page - 1].label;
1958
1959   return NULL;
1960 }
1961
1962 gint
1963 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
1964 {
1965   guint idx = 0;
1966
1967   while(size[idx].name != NULL) {
1968     if(strcmp(size[idx].name, string) == 0)
1969       return idx;
1970     idx++;
1971   }
1972
1973   return -1;
1974 }
1975
1976 gchar *
1977 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
1978 {
1979   GtkGSDocSink *sink;
1980   gchar *doc;
1981   gboolean free_pages = FALSE;
1982
1983   if(pages == NULL) {
1984     if(!gs->structured_doc) {
1985       FILE *f;
1986       struct stat sb;
1987
1988       if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
1989         return NULL;
1990       doc = g_new(gchar, sb.st_size);
1991       if(!doc)
1992         return NULL;
1993       f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
1994       if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
1995         g_free(doc);
1996         doc = NULL;
1997       }
1998       if(NULL != f)
1999         fclose(f);
2000       return doc;
2001     }
2002     else {
2003       int i, n = gtk_gs_get_page_count(gs);
2004       pages = g_new0(gint, n);
2005       for(i = 0; i < n; i++)
2006         pages[i] = TRUE;
2007       free_pages = TRUE;
2008     }
2009   }
2010
2011   sink = gtk_gs_doc_sink_new();
2012
2013   if(GTK_GS_IS_PDF(gs)) {
2014     gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2015     gchar *cmd, *fname;
2016     int tmpfd;
2017
2018     if((tmpfd = mkstemp(tmpn)) < 0) {
2019       g_free(tmpn);
2020       return NULL;
2021     }
2022     close(tmpfd);
2023     fname = g_shell_quote (gs->gs_filename_unc ?
2024                            gs->gs_filename_unc : gs->gs_filename);
2025     cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2026     g_free(fname);
2027     if((system(cmd) == 0) && file_readable(tmpn)) {
2028       GObject *tmp_gs;
2029       tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2030       if(NULL != tmp_gs) {
2031         if(GTK_GS(tmp_gs)->loaded)
2032           pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2033         g_object_unref(tmp_gs);
2034       }
2035     }
2036     g_free(cmd);
2037     g_free(tmpn);
2038   }
2039   else {
2040     /* Use uncompressed file if necessary */
2041     pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2042   }
2043   if(free_pages)
2044     g_free(pages);
2045   doc = gtk_gs_doc_sink_get_buffer(sink);
2046   gtk_gs_doc_sink_free(sink);
2047   return doc;
2048 }
2049
2050 void
2051 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2052 {
2053   if(zoom_mode != gs->zoom_mode) {
2054     gs->zoom_mode = zoom_mode;
2055     gtk_gs_set_zoom(gs, 1.0);
2056   }
2057   gtk_gs_goto_page(gs, gs->current_page);
2058 }
2059
2060 GtkGSZoomMode
2061 gtk_gs_get_zoom_mode(GtkGS * gs)
2062 {
2063   return gs->zoom_mode;
2064 }
2065
2066 void
2067 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2068 {
2069   gs->avail_w = avail_w;
2070   gs->avail_h = avail_h;
2071   if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2072     gtk_gs_set_zoom(gs, 0.0);
2073   }
2074 }
2075
2076 static gboolean
2077 ps_document_load (EvDocument  *document,
2078                    const char  *uri,
2079                    GError     **error)
2080 {
2081         gboolean result;
2082         char *filename;
2083
2084         filename = g_filename_from_uri (uri, NULL, error);
2085         if (!filename)
2086                 return FALSE;
2087
2088         result = gtk_gs_load (GTK_GS (document), filename);
2089
2090         g_free (filename);
2091
2092         return result;
2093 }
2094
2095 static int
2096 ps_document_get_n_pages (EvDocument  *document)
2097 {
2098         return gtk_gs_get_page_count (GTK_GS (document));
2099 }
2100
2101 static void
2102 ps_document_set_page (EvDocument  *document,
2103                        int          page)
2104 {
2105         gtk_gs_goto_page (GTK_GS (document), page);
2106 }
2107
2108 static int
2109 ps_document_get_page (EvDocument  *document)
2110 {
2111         return gtk_gs_get_current_page (GTK_GS (document));
2112 }
2113
2114 static gboolean
2115 gtk_gs_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
2116 {
2117         GtkGS *gs = (GtkGS *) data;
2118
2119         if(event->type != GDK_CLIENT_EVENT)
2120                 return FALSE;
2121
2122         if (event->client.message_type == gs_class->page_atom) {
2123                 gs->busy = FALSE;
2124                 ev_document_changed (EV_DOCUMENT (gs));
2125         }
2126
2127         return TRUE;
2128 }
2129
2130 static void
2131 ps_document_set_target (EvDocument  *document,
2132                         GdkDrawable *target)
2133 {
2134         GtkGS *gs = GTK_GS (document);
2135         GtkWidget *widget;
2136         gpointer data;
2137
2138         gs->pstarget = target;
2139
2140         if (gs->pstarget) {
2141                 gdk_window_get_user_data (gs->pstarget, &data);
2142                 g_return_if_fail (GTK_IS_WIDGET (data));
2143
2144                 widget = GTK_WIDGET (data);
2145                 g_signal_connect (widget, "event",
2146                                   G_CALLBACK (gtk_gs_widget_event),
2147                                   document);
2148         }
2149
2150         gtk_gs_goto_page (gs, gs->current_page);
2151 }
2152
2153 static void
2154 ps_document_set_scale (EvDocument  *document,
2155                         double       scale)
2156 {
2157         gtk_gs_set_zoom (GTK_GS (document), scale);
2158 }
2159
2160 static void
2161 ps_document_set_page_offset (EvDocument  *document,
2162                               int          x,
2163                               int          y)
2164 {
2165 }
2166
2167 static void
2168 ps_document_get_page_size (EvDocument   *document,
2169                             int          *width,
2170                             int          *height)
2171 {
2172         GtkGS *gs = GTK_GS (document);
2173
2174         if (width) {
2175                 *width = gs->width;
2176         }
2177
2178         if (height) {
2179                 *height = gs->height;
2180         }
2181 }
2182
2183 static void
2184 ps_document_render (EvDocument  *document,
2185                     int          clip_x,
2186                     int          clip_y,
2187                     int          clip_width,
2188                     int          clip_height)
2189 {
2190         GtkGS *gs = GTK_GS (document);
2191         GdkGC *gc;
2192
2193         if (gs->pstarget == NULL ||
2194             gs->bpixmap == NULL) {
2195                 return;
2196         }
2197
2198         gc = gdk_gc_new (gs->pstarget);
2199
2200         gdk_draw_drawable (gs->pstarget, gc,
2201                            gs->bpixmap,
2202                            clip_x, clip_y,
2203                            clip_x, clip_y,
2204                            clip_width, clip_height);
2205
2206         g_object_unref (gc);
2207 }
2208
2209 static void
2210 ps_document_document_iface_init (EvDocumentIface *iface)
2211 {
2212         iface->load = ps_document_load;
2213         iface->get_n_pages = ps_document_get_n_pages;
2214         iface->set_page = ps_document_set_page;
2215         iface->get_page = ps_document_get_page;
2216         iface->set_scale = ps_document_set_scale;
2217         iface->set_target = ps_document_set_target;
2218         iface->set_page_offset = ps_document_set_page_offset;
2219         iface->get_page_size = ps_document_get_page_size;
2220         iface->render = ps_document_render;
2221 }