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