]> www.fi.muni.cz Git - evince.git/blob - backend/ps/ps-interpreter.c
55f55d4032f084fef37ef454621703fe4f3a7bd8
[evince.git] / backend / ps / ps-interpreter.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
4  *  Copyright 1998 - 2005 The Free Software Foundation
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include <glib/gstdio.h>
24 #include <glib/gi18n.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkwindow.h>
27 #include <gdk/gdk.h>
28 #include <gdk/gdkx.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <sys/wait.h>
32 #include <errno.h>
33
34 #include "ps-interpreter.h"
35 #include "ps.h"
36
37 #define MAX_BUFSIZE 1024
38
39 enum {
40         PAGE_RENDERED,
41         LAST_SIGNAL
42 };
43
44 /* structure to describe section of file to send to ghostscript */
45 typedef struct {
46         FILE *fp;
47         glong begin;
48         guint len;
49         gboolean seek_needed;
50         gboolean close;
51 } PSSection;
52
53 struct _PSInterpreter {
54         GObject object;
55
56         GtkWidget *target_window;
57         GdkWindow *pstarget;
58         GdkPixmap *bpixmap;
59         glong message_window;          /* Used by ghostview to receive messages from app */
60
61         GPid pid;               /* PID of interpreter, -1 if none  */
62         GIOChannel *input;      /* stdin of interpreter            */
63         GIOChannel *output;     /* stdout of interpreter           */
64         GIOChannel *error;        /* stderr of interpreter           */
65         guint input_id;
66         guint output_id;
67         guint error_id;
68
69         gboolean busy;                /* Is gs busy drawing? */
70         gboolean structured_doc;
71
72         GQueue *ps_input;
73         gchar *input_buffer_ptr;
74         guint bytes_left;
75         guint buffer_bytes_left;
76
77         FILE *psfile;              /* the currently loaded FILE */
78         gchar *psfilename;           /* the currently loaded filename */
79         gchar *input_buffer;
80         gboolean send_filename_to_gs; /* True if gs should read from file directly */
81         const struct document *doc;
82 };
83
84 struct _PSInterpreterClass {
85         GObjectClass parent_class;
86
87         void (* page_rendered) (PSInterpreter *gs,
88                                 GdkPixbuf     *pixbuf);
89         
90         GdkAtom gs_atom;
91         GdkAtom next_atom;
92         GdkAtom page_atom;
93         GdkAtom string_atom;
94 };
95
96 static void     ps_interpreter_start    (PSInterpreter *gs);
97 static void     ps_interpreter_stop     (PSInterpreter *gs);
98 static void     ps_interpreter_failed   (PSInterpreter *gs,
99                                          const gchar   *msg);
100 static gboolean ps_interpreter_is_ready (PSInterpreter *gs);
101
102 static void     push_pixbuf             (PSInterpreter *gs);
103
104 G_DEFINE_TYPE (PSInterpreter, ps_interpreter, G_TYPE_OBJECT)
105
106 static guint gs_signals[LAST_SIGNAL];
107
108 static void
109 ps_section_free (PSSection *section)
110 {
111         if (!section)
112                 return;
113
114         if (section->close && section->fp)
115                 fclose (section->fp);
116
117         g_free (section);
118 }
119
120 static void
121 ps_interpreter_init (PSInterpreter *gs)
122 {
123         gs->pid = -1;
124         gs->ps_input = g_queue_new ();
125 }
126
127 static void
128 ps_interpreter_dispose (GObject *object)
129 {
130         PSInterpreter *gs = PS_INTERPRETER (object);
131
132         gs->doc = NULL;
133         
134         if (gs->psfile) {
135                 fclose (gs->psfile);
136                 gs->psfile = NULL;
137         }
138
139         if (gs->psfilename) {
140                 g_free (gs->psfilename);
141                 gs->psfilename = NULL;
142         }
143
144         if (gs->bpixmap) {
145                 g_object_unref (gs->bpixmap);
146                 gs->bpixmap = NULL;
147         }
148
149         if (gs->input_buffer) {
150                 g_free (gs->input_buffer);
151                 gs->input_buffer = NULL;
152         }
153
154         if (gs->target_window) {
155                 gtk_widget_destroy (gs->target_window);
156                 gs->target_window = NULL;
157                 gs->pstarget = NULL;
158         }
159
160         if (gs->ps_input) {
161                 g_queue_foreach (gs->ps_input, (GFunc)ps_section_free, NULL);
162                 g_queue_free (gs->ps_input);
163                 gs->ps_input = NULL;
164         }
165
166         ps_interpreter_stop (gs);
167
168         G_OBJECT_CLASS (ps_interpreter_parent_class)->dispose (object);
169 }
170
171 static void
172 ps_interpreter_class_init (PSInterpreterClass *klass)
173 {
174         GObjectClass *object_class;
175
176         object_class = G_OBJECT_CLASS (klass);
177
178         gs_signals[PAGE_RENDERED] =
179                 g_signal_new ("page_rendered",
180                               PS_TYPE_INTERPRETER,
181                               G_SIGNAL_RUN_LAST,
182                               G_STRUCT_OFFSET (PSInterpreterClass, page_rendered),
183                               NULL, NULL,
184                               g_cclosure_marshal_VOID__OBJECT,
185                               G_TYPE_NONE,
186                               1,
187                               GDK_TYPE_PIXBUF);
188         
189         klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE);
190         klass->next_atom = gdk_atom_intern ("NEXT", FALSE);
191         klass->page_atom = gdk_atom_intern ("PAGE", FALSE);
192         klass->string_atom = gdk_atom_intern ("STRING", FALSE);
193
194         object_class->dispose = ps_interpreter_dispose;
195 }
196
197 static gboolean
198 ps_interpreter_input (GIOChannel    *io,
199                       GIOCondition   condition,
200                       PSInterpreter *gs)
201 {
202         PSSection *section = NULL;
203
204         do {
205                 if (gs->buffer_bytes_left == 0) {
206                         /* Get a new section if required */
207                         if (gs->bytes_left == 0) {
208                                 ps_section_free (section);
209                                 section = NULL;
210                                 g_queue_pop_tail (gs->ps_input);
211                         }
212                         
213                         if (section == NULL) {
214                                 section = g_queue_peek_tail (gs->ps_input);
215                         }
216
217                         /* Have to seek at the beginning of each section */
218                         if (section && section->seek_needed) {
219                                 fseek (section->fp, section->begin, SEEK_SET);
220                                 section->seek_needed = FALSE;
221                                 gs->bytes_left = section->len;
222                         }
223
224                         if (gs->bytes_left > MAX_BUFSIZE) {
225                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof (char),
226                                                                MAX_BUFSIZE, section->fp);
227                         } else if (gs->bytes_left > 0) {
228                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof (char),
229                                                                gs->bytes_left, section->fp);
230                         } else {
231                                 gs->buffer_bytes_left = 0;
232                         }
233                         
234                         if (gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
235                                 ps_interpreter_failed (gs, NULL); /* Error occurred */
236                         }
237                         
238                         gs->input_buffer_ptr = gs->input_buffer;
239                         gs->bytes_left -= gs->buffer_bytes_left;
240                 }
241
242                 if (gs->buffer_bytes_left > 0) {
243                         GIOStatus status;
244                         gsize bytes_written;
245                         GError *error = NULL;
246
247                         status = g_io_channel_write_chars (gs->input,
248                                                            gs->input_buffer_ptr,
249                                                            gs->buffer_bytes_left,
250                                                            &bytes_written,
251                                                            &error);
252                         switch (status) {
253                         case G_IO_STATUS_NORMAL:
254                                 gs->buffer_bytes_left -= bytes_written;
255                                 gs->input_buffer_ptr += bytes_written;
256
257                                 break;
258                         case G_IO_STATUS_ERROR:
259                                 ps_interpreter_failed (gs, error->message);
260                                 g_error_free (error);
261                                         
262                                 break;
263                         case G_IO_STATUS_AGAIN:
264                         default:
265                                 break;
266                         }
267                 }
268         } while (!g_queue_is_empty (gs->ps_input) && gs->buffer_bytes_left == 0);
269
270         if (g_queue_is_empty (gs->ps_input) && gs->buffer_bytes_left == 0) {
271                 GIOFlags flags;
272
273                 flags = g_io_channel_get_flags (gs->input);
274                 
275                 g_io_channel_set_flags (gs->input,
276                                         flags & ~G_IO_FLAG_NONBLOCK, NULL);
277                 g_io_channel_flush (gs->input, NULL);
278                 g_io_channel_set_flags (gs->input,
279                                         flags | G_IO_FLAG_NONBLOCK, NULL);
280                 
281                 gs->input_id = 0;
282                 
283                 return FALSE;
284         }
285         
286         return TRUE;
287 }
288
289 static gboolean
290 ps_interpreter_output (GIOChannel    *io,
291                        GIOCondition   condition,
292                        PSInterpreter *gs)
293 {
294         gchar buf[MAX_BUFSIZE + 1];
295         gsize bytes = 0;
296         GIOStatus status;
297         GError *error = NULL;
298
299         status = g_io_channel_read_chars (io, buf, MAX_BUFSIZE,
300                                           &bytes, &error);
301         switch (status) {
302         case G_IO_STATUS_NORMAL:
303                 if (bytes > 0) {
304                         buf[bytes] = '\0';
305                         g_print ("%s", buf);
306                 }
307                 break;
308         case G_IO_STATUS_EOF:
309                 g_io_channel_unref (gs->output);
310                 gs->output = NULL;
311                 gs->output_id = 0;
312                         
313                 return FALSE;
314         case G_IO_STATUS_ERROR:
315                 ps_interpreter_failed (gs, error->message);
316                 g_error_free (error);
317                 gs->output_id = 0;
318                         
319                 return FALSE;
320         default:
321                 break;
322         }
323         
324         if (!gs->error) {
325                 ps_interpreter_failed (gs, NULL);
326         }
327
328         return TRUE;
329 }
330
331 static gboolean
332 ps_interpreter_error (GIOChannel    *io,
333                       GIOCondition   condition,
334                       PSInterpreter *gs)
335 {
336         gchar buf[MAX_BUFSIZE + 1];
337         gsize bytes = 0;
338         GIOStatus status;
339         GError *error = NULL;
340
341         status = g_io_channel_read_chars (io, buf, MAX_BUFSIZE,
342                                           &bytes, &error);
343         switch (status) {
344         case G_IO_STATUS_NORMAL:
345                 if (bytes > 0) {
346                         buf[bytes] = '\0';
347                         g_print ("%s", buf);
348                 }
349                         
350                 break;
351         case G_IO_STATUS_EOF:
352                 g_io_channel_unref (gs->error);
353                 gs->error = NULL;
354                 gs->error_id = 0;
355                         
356                 return FALSE;
357         case G_IO_STATUS_ERROR:
358                 ps_interpreter_failed (gs, error->message);
359                 g_error_free (error);
360                 gs->error_id = 0;
361                         
362                 break;
363         default:
364                 break;
365         }
366         
367         if (!gs->output) {
368                 ps_interpreter_failed (gs, NULL);
369         }
370
371         return TRUE;
372 }
373
374 static void
375 ps_interpreter_finished (GPid           pid,
376                          gint           status,
377                          PSInterpreter *gs)
378 {
379         g_spawn_close_pid (gs->pid);
380         gs->pid = -1;
381         ps_interpreter_failed (gs, NULL);
382 }
383
384 #define NUM_ARGS    100
385 #define NUM_GS_ARGS (NUM_ARGS - 20)
386 #define NUM_ALPHA_ARGS 10
387
388 static void
389 setup_interpreter_env (gchar **envp)
390 {
391         gint i;
392
393         for (i = 0; envp[i]; i++)
394                 putenv (envp[i]);
395 }
396
397 static void
398 ps_interpreter_start (PSInterpreter *gs)
399 {
400         gchar *argv[NUM_ARGS], *dir, *gv_env, *gs_path;
401         gchar **gs_args, **alpha_args = NULL;
402         gchar **envp;
403         gint pin, pout, perr;
404         gint argc = 0, i;
405         GError *error = NULL;
406
407         g_assert (gs->psfilename != NULL);
408
409         ps_interpreter_stop (gs);
410
411         dir = g_path_get_dirname (gs->psfilename);
412
413         /* set up the args... */
414         gs_path = g_find_program_in_path ("gs");
415         gs_args = g_strsplit (gs_path, " ", NUM_GS_ARGS);
416         g_free (gs_path);
417         for (i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) {
418                 argv[argc] = gs_args[i];
419         }
420
421         alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
422         for (i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) {
423                 argv[argc] = alpha_args[i];
424         }
425
426         argv[argc++] = "-dNOPAUSE";
427         argv[argc++] = "-dQUIET";
428         argv[argc++] = "-dSAFER";
429
430         if (gs->send_filename_to_gs) {
431                 argv[argc++] = gs->psfilename;
432                 argv[argc++] = "-c";
433                 argv[argc++] = "quit";
434         } else {
435                 argv[argc++] = "-";
436         }
437
438         argv[argc++] = NULL;
439
440         gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld;DISPLAY=%s",
441                                   gdk_x11_drawable_get_xid (gs->pstarget),
442                                   gdk_x11_drawable_get_xid (gs->bpixmap),
443                                   gdk_display_get_name (gdk_drawable_get_display (gs->pstarget)));
444         envp = g_strsplit (gv_env, ";", 2);
445         g_free (gv_env);
446
447         if (g_spawn_async_with_pipes (dir, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
448                                       (GSpawnChildSetupFunc)setup_interpreter_env, envp,
449                                       &(gs->pid), &pin, &pout, &perr,
450                                       &error)) {
451                 GIOFlags flags;
452
453                 g_child_watch_add (gs->pid,
454                                    (GChildWatchFunc)ps_interpreter_finished, 
455                                    gs);
456
457                 gs->input = g_io_channel_unix_new (pin);
458                 g_io_channel_set_encoding (gs->input, NULL, NULL);
459                 flags = g_io_channel_get_flags (gs->input);
460                 g_io_channel_set_flags (gs->input, flags | G_IO_FLAG_NONBLOCK, NULL);
461
462                 
463                 gs->output = g_io_channel_unix_new (pout);
464                 flags = g_io_channel_get_flags (gs->output);
465                 g_io_channel_set_flags (gs->output, flags | G_IO_FLAG_NONBLOCK, NULL);
466                 gs->output_id = g_io_add_watch (gs->output, G_IO_IN,
467                                                 (GIOFunc)ps_interpreter_output,
468                                                 gs);
469                 
470                 gs->error = g_io_channel_unix_new (perr);
471                 flags = g_io_channel_get_flags (gs->error);
472                 g_io_channel_set_flags (gs->error, flags | G_IO_FLAG_NONBLOCK, NULL);
473                 gs->error_id = g_io_add_watch (gs->error, G_IO_IN,
474                                                (GIOFunc)ps_interpreter_error,
475                                                gs);
476         } else {
477                 g_warning (error->message);
478                 g_error_free (error);
479         }
480
481         g_free (dir);
482         g_strfreev (envp);
483         g_strfreev (gs_args);
484         g_strfreev (alpha_args);
485 }
486
487 static void
488 ps_interpreter_stop (PSInterpreter *gs)
489 {
490         if (gs->pid > 0) {
491                 gint status = 0;
492                 
493                 kill (gs->pid, SIGTERM);
494                 while ((wait (&status) == -1) && (errno == EINTR));
495                 g_spawn_close_pid (gs->pid);
496                 gs->pid = -1;
497         }
498
499         if (gs->input) {
500                 g_io_channel_unref (gs->input);
501                 gs->input = NULL;
502
503                 if (gs->input_id > 0) {
504                         g_source_remove (gs->input_id);
505                         gs->input_id = 0;
506                 }
507                 
508                 if (gs->ps_input) {
509                         g_queue_foreach (gs->ps_input, (GFunc)ps_section_free, NULL);
510                         g_queue_free (gs->ps_input);
511                         gs->ps_input = g_queue_new ();
512                 }
513         }
514
515         if (gs->output) {
516                 g_io_channel_unref (gs->output);
517                 gs->output = NULL;
518
519                 if (gs->output_id > 0) {
520                         g_source_remove (gs->output_id);
521                         gs->output_id = 0;
522                 }
523         }
524
525         if (gs->error) {
526                 g_io_channel_unref (gs->error);
527                 gs->error = NULL;
528                 
529                 if (gs->error_id > 0) {
530                         g_source_remove (gs->error_id);
531                         gs->error_id = 0;
532                 }
533         }
534
535         gs->busy = FALSE;
536 }
537
538 static void
539 ps_interpreter_failed (PSInterpreter *gs, const char *msg)
540 {
541         g_warning (msg ? msg : _("Interpreter failed."));
542
543         push_pixbuf (gs);
544         ps_interpreter_stop (gs);
545 }
546
547 static gboolean
548 ps_interpreter_is_ready (PSInterpreter *gs)
549 {
550         return (gs->pid != -1 && !gs->busy &&
551                 (g_queue_is_empty (gs->ps_input)));
552 }
553
554 static void
555 setup_page (PSInterpreter *gs, int page, double scale, int rotation)
556 {
557         gchar *buf;
558         char scaled_dpi[G_ASCII_DTOSTR_BUF_SIZE];       
559         int urx, ury, llx, lly;
560         PSInterpreterClass *gs_class = PS_INTERPRETER_GET_CLASS (gs);
561
562         psgetpagebox (gs->doc, page, &urx, &ury, &llx, &lly);
563         g_ascii_dtostr (scaled_dpi, G_ASCII_DTOSTR_BUF_SIZE, 72.0 * scale);
564
565         buf = g_strdup_printf ("%ld %d %d %d %d %d %s %s %d %d %d %d",
566                                0L, rotation, llx, lly, urx, ury,
567                                scaled_dpi, scaled_dpi,
568                                0, 0, 0, 0);
569         
570         gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom,
571                              8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen (buf));
572         g_free (buf);
573         
574         gdk_flush ();
575 }
576
577 static void
578 setup_pixmap (PSInterpreter *gs, int page, double scale, int rotation)
579 {
580         GdkGC *fill;
581         GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
582         GdkColormap *colormap;
583         double width, height;
584         int pixmap_width, pixmap_height;
585         int urx, ury, llx, lly;
586
587         psgetpagebox (gs->doc, page, &urx, &ury, &llx, &lly);
588         width = (urx - llx) + 0.5;
589         height = (ury - lly) + 0.5;
590
591         if (rotation == 90 || rotation == 270) {
592                 pixmap_height = width * scale + 0.5;
593                 pixmap_width = height * scale + 0.5;
594         } else {
595                 pixmap_width = width * scale + 0.5;
596                 pixmap_height = height * scale + 0.5;
597         }
598
599         if (gs->bpixmap) {
600                 gint w, h;
601
602                 gdk_drawable_get_size (gs->bpixmap, &w, &h);
603
604                 if (pixmap_width != w || h != pixmap_height) {
605                         g_object_unref (gs->bpixmap);
606                         gs->bpixmap = NULL;
607                         ps_interpreter_stop (gs);
608                 }
609         }
610
611         if (!gs->bpixmap) {
612                 fill = gdk_gc_new (gs->pstarget);
613                 colormap = gdk_drawable_get_colormap (gs->pstarget);
614                 gdk_colormap_alloc_color (colormap, &white, FALSE, TRUE);
615                 gdk_gc_set_foreground (fill, &white);
616                 gs->bpixmap = gdk_pixmap_new (gs->pstarget, pixmap_width,
617                                               pixmap_height, -1);
618                 gdk_draw_rectangle (gs->bpixmap, fill, TRUE,
619                                     0, 0, pixmap_width, pixmap_height);
620         }
621 }
622
623 static void
624 push_pixbuf (PSInterpreter *gs)
625 {
626         GdkColormap *cmap;
627         GdkPixbuf *pixbuf;
628         gint width, height;
629
630         if (gs->pstarget == NULL)
631                 return;
632
633         cmap = gdk_drawable_get_colormap (gs->pstarget);
634         gdk_drawable_get_size (gs->bpixmap, &width, &height);
635         pixbuf = gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap,
636                                                0, 0, 0, 0,
637                                                width, height);
638         g_signal_emit (gs, gs_signals[PAGE_RENDERED], 0, pixbuf);
639         g_object_unref (pixbuf);
640 }
641
642 static gboolean
643 ps_interpreter_widget_event (GtkWidget     *widget,
644                              GdkEvent      *event,
645                              PSInterpreter *gs)
646 {
647         PSInterpreterClass *gs_class = PS_INTERPRETER_GET_CLASS (gs);
648
649         if (event->type != GDK_CLIENT_EVENT)
650                 return FALSE;
651
652         gs->message_window = event->client.data.l[0];
653
654         if (event->client.message_type == gs_class->page_atom) {
655                 gs->busy = FALSE;
656
657                 push_pixbuf (gs);
658         }
659
660         return TRUE;
661 }
662
663 static void
664 send_ps (PSInterpreter *gs, glong begin, guint len, gboolean close)
665 {
666         PSSection *ps_new;
667
668         g_assert (gs->psfile != NULL);
669         
670         if (!gs->input) {
671                 g_critical ("No pipe to gs: error in send_ps().");
672                 return;
673         }
674
675         ps_new = g_new0 (PSSection, 1);
676         ps_new->fp = gs->psfile;
677         ps_new->begin = begin;
678         ps_new->len = len;
679         ps_new->seek_needed = TRUE;
680         ps_new->close = close;
681
682         if (gs->input_buffer == NULL) {
683                 gs->input_buffer = g_malloc (MAX_BUFSIZE);
684         }
685
686         if (g_queue_is_empty (gs->ps_input)) {
687                 gs->input_buffer_ptr = gs->input_buffer;
688                 gs->bytes_left = len;
689                 gs->buffer_bytes_left = 0;
690                 g_queue_push_head (gs->ps_input, ps_new);
691                 gs->input_id = g_io_add_watch (gs->input, G_IO_OUT,
692                                                (GIOFunc)ps_interpreter_input,
693                                                gs);
694         } else {
695                 g_queue_push_head (gs->ps_input, ps_new);
696         }
697 }
698
699 static void
700 ps_interpreter_next_page (PSInterpreter *gs)
701 {
702         XEvent              event;
703         GdkScreen          *screen;
704         GdkDisplay         *display;
705         Display            *dpy;
706         PSInterpreterClass *gs_class = PS_INTERPRETER_GET_CLASS (gs);
707
708         g_assert (gs->pid != 0);
709         g_assert (gs->busy != TRUE);
710
711         gs->busy = TRUE;
712
713         screen = gtk_window_get_screen (GTK_WINDOW (gs->target_window));
714         display = gdk_screen_get_display (screen);
715         dpy = gdk_x11_display_get_xdisplay (display);
716
717         event.xclient.type = ClientMessage;
718         event.xclient.display = dpy;
719         event.xclient.window = gs->message_window;
720         event.xclient.message_type =
721                 gdk_x11_atom_to_xatom_for_display (display,
722                                                    gs_class->next_atom);
723         event.xclient.format = 32;
724
725         gdk_error_trap_push ();
726         XSendEvent (dpy, gs->message_window, FALSE, 0, &event);
727         gdk_flush ();
728         gdk_error_trap_pop ();
729 }
730
731 static void
732 render_page (PSInterpreter *gs, gint page)
733 {
734         if (gs->structured_doc && gs->doc) {
735                 if (ps_interpreter_is_ready (gs)) {
736                         ps_interpreter_next_page (gs);
737                 } else {
738                         ps_interpreter_start (gs);
739                         send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
740                         send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
741                 }
742
743                 send_ps (gs, gs->doc->pages[page].begin,
744                          gs->doc->pages[page].len, FALSE);
745         } else {
746                 /* Unstructured document
747                  *
748                  * In the case of non structured documents,
749                  * GS read the PS from the  actual file (via command
750                  * line. Hence, ggv only send a signal next page.
751                  * If ghostview is not running it is usually because
752                  * the last page of the file was displayed. In that
753                  * case, ggv restarts GS again and the first page is displayed.
754                  */
755
756                 if (!ps_interpreter_is_ready (gs)) {
757                         ps_interpreter_start (gs);
758                 }
759                 ps_interpreter_next_page (gs);
760         }
761 }
762
763 /* Public methods */
764 PSInterpreter *
765 ps_interpreter_new (const gchar           *filename,
766                     const struct document *doc)
767 {
768         PSInterpreter *gs;
769
770         g_return_val_if_fail (filename != NULL, NULL);
771         g_return_val_if_fail (doc != NULL, NULL);
772
773         gs = PS_INTERPRETER (g_object_new (PS_TYPE_INTERPRETER, NULL));
774
775         gs->psfilename = g_strdup (filename);
776         gs->doc = doc;
777         gs->structured_doc = FALSE;
778         gs->send_filename_to_gs = TRUE;
779         gs->psfile = fopen (gs->psfilename, "r");
780
781         if ((!gs->doc->epsf && gs->doc->numpages > 0) ||
782             (gs->doc->epsf && gs->doc->numpages > 1)) {
783                 gs->structured_doc = TRUE;
784                 gs->send_filename_to_gs = FALSE;
785         }
786
787         return gs;
788 }
789
790 void
791 ps_interpreter_render_page (PSInterpreter *gs,
792                             gint           page,
793                             gdouble        scale,
794                             gint           rotation)
795 {
796         g_return_if_fail (PS_IS_INTERPRETER (gs));
797
798         if (gs->pstarget == NULL) {
799                 gs->target_window = gtk_window_new (GTK_WINDOW_POPUP);
800                 gtk_widget_realize (gs->target_window);
801                 gs->pstarget = gs->target_window->window;
802
803                 g_assert (gs->pstarget != NULL);
804
805                 g_signal_connect (gs->target_window, "event",
806                                   G_CALLBACK (ps_interpreter_widget_event),
807                                   gs);
808         }
809
810         setup_pixmap (gs, page, scale, rotation);
811         setup_page (gs, page, scale, rotation);
812
813         render_page (gs, page);
814 }