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