]> www.fi.muni.cz Git - evince.git/blob - backend/ps/ps-document.c
05533c37da32837b6e907663cedb972ec2aa7404
[evince.git] / backend / ps / ps-document.c
1 /* Ghostscript widget for GTK/GNOME
2  *
3  * Copyright (C) 1998 - 2005 the Free Software Foundation
4  *
5  * Authors: Jonathan Blandford, Jaka Mocnik, Carlos Garcia Campos
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 #include "config.h"
26
27 #include <glib/gstdio.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtkwidget.h>
30 #include <gtk/gtkwindow.h>
31 #include <gdk/gdk.h>
32 #include <gdk/gdkx.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/wait.h>
36 #include <errno.h>
37
38 #include "ps-document.h"
39 #include "ps.h"
40 #include "gstypes.h"
41 #include "gsdefaults.h"
42 #include "ev-file-exporter.h"
43 #include "ev-async-renderer.h"
44
45 #define MAX_BUFSIZE 1024
46
47 /* structure to describe section of file to send to ghostscript */
48 typedef struct {
49         FILE *fp;
50         glong begin;
51         guint len;
52         gboolean seek_needed;
53         gboolean close;
54 } PSSection;
55
56 struct _PSDocument {
57         GObject object;
58
59         GtkWidget *target_window;
60         GdkWindow *pstarget;
61         GdkPixmap *bpixmap;
62         glong message_window;          /* Used by ghostview to receive messages from app */
63
64         GPid interpreter_pid;               /* PID of interpreter, -1 if none  */
65         GIOChannel *interpreter_input;      /* stdin of interpreter            */
66         GIOChannel *interpreter_output;     /* stdout of interpreter           */
67         GIOChannel *interpreter_err;        /* stderr of interpreter           */
68         guint interpreter_input_id;
69         guint interpreter_output_id;
70         guint interpreter_error_id;
71
72         gboolean busy;                /* Is gs busy drawing? */
73         gboolean structured_doc;
74
75         GQueue *ps_input;
76         gchar *input_buffer_ptr;
77         guint bytes_left;
78         guint buffer_bytes_left;
79
80         FILE *gs_psfile;              /* the currently loaded FILE */
81         gchar *gs_filename;           /* the currently loaded filename */
82         gchar *input_buffer;
83         gboolean send_filename_to_gs; /* True if gs should read from file directly */
84         struct document *doc;
85
86         gint  *ps_export_pagelist;
87         gchar *ps_export_filename;
88 };
89
90 struct _PSDocumentClass {
91         GObjectClass parent_class;
92         
93         GdkAtom gs_atom;
94         GdkAtom next_atom;
95         GdkAtom page_atom;
96         GdkAtom string_atom;
97 }; 
98
99 static void     ps_document_document_iface_init      (EvDocumentIface      *iface);
100 static void     ps_document_file_exporter_iface_init (EvFileExporterIface  *iface);
101 static void     ps_async_renderer_iface_init         (EvAsyncRendererIface *iface);
102
103 static void     ps_interpreter_start                 (PSDocument           *gs);
104 static void     ps_interpreter_stop                  (PSDocument           *gs);
105 static void     ps_interpreter_failed                (PSDocument           *gs,
106                                                       const gchar          *msg);
107 static gboolean ps_interpreter_is_ready              (PSDocument           *gs);
108
109 static void     push_pixbuf                          (PSDocument           *gs);
110
111
112 G_DEFINE_TYPE_WITH_CODE (PSDocument, ps_document, G_TYPE_OBJECT,
113                          {
114                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
115                                                         ps_document_document_iface_init);
116                                  G_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
117                                                         ps_document_file_exporter_iface_init);
118                                  G_IMPLEMENT_INTERFACE (EV_TYPE_ASYNC_RENDERER,
119                                                         ps_async_renderer_iface_init);
120                          });
121
122 static void
123 ps_section_free (PSSection *section)
124 {
125         if (!section)
126                 return;
127
128         if (section->close && section->fp)
129                 fclose (section->fp);
130
131         g_free (section);
132 }
133
134 /* PSDocument */
135 static void
136 ps_document_init (PSDocument *gs)
137 {
138         gs->bpixmap = NULL;
139         gs->interpreter_pid = -1;
140
141         gs->busy = FALSE;
142         gs->gs_filename = NULL;
143
144         gs->structured_doc = FALSE;
145         gs->send_filename_to_gs = FALSE;
146
147         gs->doc = NULL;
148
149         gs->interpreter_input = NULL;
150         gs->interpreter_output = NULL;
151         gs->interpreter_err = NULL;
152         gs->interpreter_input_id = 0;
153         gs->interpreter_output_id = 0;
154         gs->interpreter_error_id = 0;
155
156         gs->ps_input = g_queue_new ();
157         gs->input_buffer = NULL;
158         gs->input_buffer_ptr = NULL;
159         gs->bytes_left = 0;
160         gs->buffer_bytes_left = 0;
161
162         gs->ps_export_pagelist = NULL;
163         gs->ps_export_filename = NULL;
164 }
165
166 static void
167 ps_document_dispose (GObject *object)
168 {
169         PSDocument *gs = PS_DOCUMENT (object);
170         
171         if (gs->gs_psfile) {
172                 fclose (gs->gs_psfile);
173                 gs->gs_psfile = NULL;
174         }
175
176         if (gs->gs_filename) {
177                 g_free (gs->gs_filename);
178                 gs->gs_filename = NULL;
179         }
180
181         if (gs->doc) {
182                 psfree (gs->doc);
183                 gs->doc = NULL;
184         }
185
186         if (gs->bpixmap) {
187                 g_object_unref (gs->bpixmap);
188                 gs->bpixmap = NULL;
189         }
190
191         if (gs->input_buffer) {
192                 g_free (gs->input_buffer);
193                 gs->input_buffer = NULL;
194         }
195
196         if (gs->target_window) {
197                 gtk_widget_destroy (gs->target_window);
198                 gs->target_window = NULL;
199                 gs->pstarget = NULL;
200         }
201
202         if (gs->ps_input) {
203                 g_queue_foreach (gs->ps_input, (GFunc)ps_section_free, NULL);
204                 g_queue_free (gs->ps_input);
205                 gs->ps_input = NULL;
206         }
207
208         ps_interpreter_stop (gs);
209
210         G_OBJECT_CLASS (ps_document_parent_class)->dispose (object);
211 }
212
213 static void
214 ps_document_class_init (PSDocumentClass *klass)
215 {
216         GObjectClass *object_class;
217
218         object_class = G_OBJECT_CLASS (klass);
219
220         object_class->dispose = ps_document_dispose;
221
222         klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE);
223         klass->next_atom = gdk_atom_intern ("NEXT", FALSE);
224         klass->page_atom = gdk_atom_intern ("PAGE", FALSE);
225         klass->string_atom = gdk_atom_intern ("STRING", FALSE);
226 }
227
228 /* PSInterpreter */
229 static gboolean
230 ps_interpreter_input (GIOChannel   *io,
231                       GIOCondition condition,
232                       PSDocument  *gs)
233 {
234         PSSection *section = NULL;
235
236         do {
237                 if (gs->buffer_bytes_left == 0) {
238                         /* Get a new section if required */
239                         if (gs->bytes_left == 0) {
240                                 ps_section_free (section);
241                                 section = NULL;
242                                 g_queue_pop_tail (gs->ps_input);
243                         }
244                         
245                         if (section == NULL) {
246                                 section = g_queue_peek_tail (gs->ps_input);
247                         }
248
249                         /* Have to seek at the beginning of each section */
250                         if (section && section->seek_needed) {
251                                 fseek (section->fp, section->begin, SEEK_SET);
252                                 section->seek_needed = FALSE;
253                                 gs->bytes_left = section->len;
254                         }
255
256                         if (gs->bytes_left > MAX_BUFSIZE) {
257                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof (char),
258                                                                MAX_BUFSIZE, section->fp);
259                         } else if (gs->bytes_left > 0) {
260                                 gs->buffer_bytes_left = fread (gs->input_buffer, sizeof (char),
261                                                                gs->bytes_left, section->fp);
262                         } else {
263                                 gs->buffer_bytes_left = 0;
264                         }
265                         
266                         if (gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
267                                 ps_interpreter_failed (gs, NULL); /* Error occurred */
268                         }
269                         
270                         gs->input_buffer_ptr = gs->input_buffer;
271                         gs->bytes_left -= gs->buffer_bytes_left;
272                 }
273
274                 if (gs->buffer_bytes_left > 0) {
275                         GIOStatus status;
276                         gsize bytes_written;
277                         GError *error = NULL;
278
279                         status = g_io_channel_write_chars (gs->interpreter_input,
280                                                            gs->input_buffer_ptr,
281                                                            gs->buffer_bytes_left,
282                                                            &bytes_written,
283                                                            &error);
284                         switch (status) {
285                                 case G_IO_STATUS_NORMAL:
286                                         gs->buffer_bytes_left -= bytes_written;
287                                         gs->input_buffer_ptr += bytes_written;
288
289                                         break;
290                                 case G_IO_STATUS_ERROR:
291                                         ps_interpreter_failed (gs, error->message);
292                                         g_error_free (error);
293                                         
294                                         break;
295                                 case G_IO_STATUS_AGAIN:
296                                 default:
297                                         break;
298                         }
299                 }
300         } while (!g_queue_is_empty (gs->ps_input) && gs->buffer_bytes_left == 0);
301
302         if (g_queue_is_empty (gs->ps_input) && gs->buffer_bytes_left == 0) {
303                 GIOFlags flags;
304
305                 flags = g_io_channel_get_flags (gs->interpreter_input);
306                 
307                 g_io_channel_set_flags (gs->interpreter_input,
308                                         flags & ~G_IO_FLAG_NONBLOCK, NULL);
309                 g_io_channel_flush (gs->interpreter_input, NULL);
310                 g_io_channel_set_flags (gs->interpreter_input,
311                                         flags | G_IO_FLAG_NONBLOCK, NULL);
312                 
313                 gs->interpreter_input_id = 0;
314                 
315                 return FALSE;
316         }
317         
318         return TRUE;
319 }
320
321 static gboolean
322 ps_interpreter_output (GIOChannel   *io,
323                        GIOCondition condition,
324                        PSDocument  *gs)
325 {
326         gchar buf[MAX_BUFSIZE + 1];
327         gsize bytes = 0;
328         GIOStatus status;
329         GError *error = NULL;
330
331         status = g_io_channel_read_chars (io, buf, MAX_BUFSIZE,
332                                           &bytes, &error);
333         switch (status) {
334                 case G_IO_STATUS_NORMAL:
335                         if (bytes > 0) {
336                                 buf[bytes] = '\0';
337                                 g_print ("%s", buf);
338                         }
339                         break;
340                 case G_IO_STATUS_EOF:
341                         g_io_channel_unref (gs->interpreter_output);
342                         gs->interpreter_output = NULL;
343                         gs->interpreter_output_id = 0;
344                         
345                         return FALSE;
346                 case G_IO_STATUS_ERROR:
347                         ps_interpreter_failed (gs, error->message);
348                         g_error_free (error);
349                         gs->interpreter_output_id = 0;
350                         
351                         return FALSE;
352                 default:
353                         break;
354         }
355         
356         if (!gs->interpreter_err) {
357                 ps_interpreter_failed (gs, NULL);
358         }
359
360         return TRUE;
361 }
362
363 static gboolean
364 ps_interpreter_error (GIOChannel   *io,
365                        GIOCondition condition,
366                        PSDocument  *gs)
367 {
368         gchar buf[MAX_BUFSIZE + 1];
369         gsize bytes = 0;
370         GIOStatus status;
371         GError *error = NULL;
372
373         status = g_io_channel_read_chars (io, buf, MAX_BUFSIZE,
374                                           &bytes, &error);
375         switch (status) {
376                 case G_IO_STATUS_NORMAL:
377                         if (bytes > 0) {
378                                 buf[bytes] = '\0';
379                                 g_print ("%s", buf);
380                         }
381                         
382                         break;
383                 case G_IO_STATUS_EOF:
384                         g_io_channel_unref (gs->interpreter_err);
385                         gs->interpreter_err = NULL;
386                         gs->interpreter_error_id = 0;
387                         
388                         return FALSE;
389                 case G_IO_STATUS_ERROR:
390                         ps_interpreter_failed (gs, error->message);
391                         g_error_free (error);
392                         gs->interpreter_error_id = 0;
393                         
394                         break;
395                 default:
396                         break;
397         }
398         
399         if (!gs->interpreter_output) {
400                 ps_interpreter_failed (gs, NULL);
401         }
402
403         return TRUE;
404 }
405
406 static void
407 ps_interpreter_finished (GPid        pid,
408                          gint        status,
409                          PSDocument *gs)
410 {
411         g_spawn_close_pid (gs->interpreter_pid);
412         gs->interpreter_pid = -1;
413         ps_interpreter_failed (gs, NULL);
414 }
415
416 #define NUM_ARGS    100
417 #define NUM_GS_ARGS (NUM_ARGS - 20)
418 #define NUM_ALPHA_ARGS 10
419
420 static void
421 setup_interpreter_env (gchar **envp)
422 {
423         gint i;
424
425         for (i = 0; envp[i]; i++)
426                 putenv (envp[i]);
427 }
428
429 static void
430 ps_interpreter_start (PSDocument *gs)
431 {
432         gchar *argv[NUM_ARGS], *dir, *gv_env, *gs_path;
433         gchar **gs_args, **alpha_args = NULL;
434         gchar **envp;
435         gint pin, pout, perr;
436         gint argc = 0, i;
437         GError *error = NULL;
438         
439         if (!gs->gs_filename)
440                 return;
441
442         ps_interpreter_stop (gs);
443
444         dir = g_path_get_dirname (gs->gs_filename);
445
446         /* set up the args... */
447         gs_path = g_find_program_in_path ("gs");
448         gs_args = g_strsplit (gs_path, " ", NUM_GS_ARGS);
449         g_free (gs_path);
450         for (i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) {
451                 argv[argc] = gs_args[i];
452         }
453
454         alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
455         for (i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) {
456                 argv[argc] = alpha_args[i];
457         }
458
459         argv[argc++] = "-dNOPAUSE";
460         argv[argc++] = "-dQUIET";
461         argv[argc++] = "-dSAFER";
462
463         if (gs->send_filename_to_gs) {
464                 argv[argc++] = gs->gs_filename;
465                 argv[argc++] = "-c";
466                 argv[argc++] = "quit";
467         } else {
468                 argv[argc++] = "-";
469         }
470
471         argv[argc++] = NULL;
472
473         gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld;DISPLAY=%s",
474                                   gdk_x11_drawable_get_xid (gs->pstarget),
475                                   gdk_x11_drawable_get_xid (gs->bpixmap),
476                                   gdk_display_get_name (gdk_drawable_get_display (gs->pstarget)));
477         envp = g_strsplit (gv_env, ";", 2);
478         g_free (gv_env);
479
480         if (g_spawn_async_with_pipes (dir, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
481                                       (GSpawnChildSetupFunc)setup_interpreter_env, envp,
482                                       &(gs->interpreter_pid),
483                                       &pin, &pout, &perr,
484                                       &error)) {
485                 GIOFlags flags;
486
487                 g_child_watch_add (gs->interpreter_pid,
488                                    (GChildWatchFunc)ps_interpreter_finished, 
489                                    gs);
490
491                 gs->interpreter_input = g_io_channel_unix_new (pin);
492                 g_io_channel_set_encoding (gs->interpreter_input, NULL, NULL);
493                 flags = g_io_channel_get_flags (gs->interpreter_input);
494                 g_io_channel_set_flags (gs->interpreter_input,
495                                         flags | G_IO_FLAG_NONBLOCK, NULL);
496
497                 
498                 gs->interpreter_output = g_io_channel_unix_new (pout);
499                 flags = g_io_channel_get_flags (gs->interpreter_output);
500                 g_io_channel_set_flags (gs->interpreter_output,
501                                         flags | G_IO_FLAG_NONBLOCK, NULL);
502                 gs->interpreter_output_id =
503                         g_io_add_watch (gs->interpreter_output, G_IO_IN,
504                                         (GIOFunc)ps_interpreter_output,
505                                         gs);
506                 
507                 gs->interpreter_err = g_io_channel_unix_new (perr);
508                 flags = g_io_channel_get_flags (gs->interpreter_err);
509                 g_io_channel_set_flags (gs->interpreter_err,
510                                         flags | G_IO_FLAG_NONBLOCK, NULL);
511                 gs->interpreter_error_id =
512                         g_io_add_watch (gs->interpreter_err, G_IO_IN,
513                                         (GIOFunc)ps_interpreter_error,
514                                         gs);
515         } else {
516                 g_warning (error->message);
517                 g_error_free (error);
518         }
519
520         g_free (dir);
521         g_strfreev (envp);
522         g_strfreev (gs_args);
523         g_strfreev (alpha_args);
524 }
525
526 static void
527 ps_interpreter_stop (PSDocument *gs)
528 {
529         if (gs->interpreter_pid > 0) {
530                 gint status = 0;
531                 
532                 kill (gs->interpreter_pid, SIGTERM);
533                 while ((wait (&status) == -1) && (errno == EINTR));
534                 g_spawn_close_pid (gs->interpreter_pid);
535                 gs->interpreter_pid = -1;
536         }
537
538         if (gs->interpreter_input) {
539                 g_io_channel_unref (gs->interpreter_input);
540                 gs->interpreter_input = NULL;
541
542                 if (gs->interpreter_input_id > 0) {
543                         g_source_remove (gs->interpreter_input_id);
544                         gs->interpreter_input_id = 0;
545                 }
546                 
547                 if (gs->ps_input) {
548                         g_queue_foreach (gs->ps_input, (GFunc)ps_section_free, NULL);
549                         g_queue_free (gs->ps_input);
550                         gs->ps_input = g_queue_new ();
551                 }
552         }
553
554         if (gs->interpreter_output) {
555                 g_io_channel_unref (gs->interpreter_output);
556                 gs->interpreter_output = NULL;
557
558                 if (gs->interpreter_output_id > 0) {
559                         g_source_remove (gs->interpreter_output_id);
560                         gs->interpreter_output_id = 0;
561                 }
562         }
563
564         if (gs->interpreter_err) {
565                 g_io_channel_unref (gs->interpreter_err);
566                 gs->interpreter_err = NULL;
567                 
568                 if (gs->interpreter_error_id > 0) {
569                         g_source_remove (gs->interpreter_error_id);
570                         gs->interpreter_error_id = 0;
571                 }
572         }
573
574         gs->busy = FALSE;
575 }
576
577 static void
578 ps_interpreter_failed (PSDocument *gs, const char *msg)
579 {
580         g_warning (msg ? msg : _("Interpreter failed."));
581         
582         push_pixbuf (gs);
583         ps_interpreter_stop (gs);
584 }
585
586 static gboolean
587 ps_interpreter_is_ready (PSDocument *gs)
588 {
589         return (gs->interpreter_pid != -1 &&
590                 !gs->busy &&
591                 (g_queue_is_empty (gs->ps_input)));
592 }
593
594 /* EvDocumentIface */
595 static gboolean
596 document_load (PSDocument *gs, const gchar *fname, GError **error)
597 {
598         /* prepare this document */
599         gs->structured_doc = FALSE;
600         gs->send_filename_to_gs = TRUE;
601         gs->gs_filename = g_strdup (fname);
602
603         /*
604          * We need to make sure that the file is loadable/exists!
605          * otherwise we want to exit without loading new stuff...
606          */
607         if (!g_file_test (fname, G_FILE_TEST_IS_REGULAR)) {
608                 gchar *filename_dsp;
609
610                 filename_dsp = g_filename_display_name (fname);
611                 g_set_error (error,
612                              G_FILE_ERROR,
613                              G_FILE_ERROR_NOENT,
614                              _("Cannot open file “%s”.\n"), /* FIXME: remove \n after freeze */
615                              filename_dsp);
616                 g_free (filename_dsp);
617                 
618                 ps_interpreter_failed (gs, NULL);
619                 return FALSE;
620         }
621
622         if (!gs->gs_filename || (gs->gs_psfile = fopen (gs->gs_filename, "r")) == NULL) {
623                 gchar *filename_dsp;
624
625                 filename_dsp = g_filename_display_name (fname);
626                 g_set_error (error,
627                              G_FILE_ERROR,
628                              G_FILE_ERROR_NOENT,
629                              _("Cannot open file “%s”.\n"), /* FIXME: remove \n after freeze */
630                              filename_dsp);
631                 g_free (filename_dsp);
632                 
633                 ps_interpreter_failed (gs, NULL);
634                 return FALSE;
635         }
636         
637         /* we grab the vital statistics!!! */
638         gs->doc = psscan (gs->gs_psfile, TRUE, gs->gs_filename);
639         if (!gs->doc)
640                 return FALSE;
641         
642         
643         if ((!gs->doc->epsf && gs->doc->numpages > 0) ||
644             (gs->doc->epsf && gs->doc->numpages > 1)) {
645                 gs->structured_doc = TRUE;
646                 gs->send_filename_to_gs = FALSE;
647         }
648
649         return TRUE;
650 }
651
652 static gboolean
653 ps_document_load (EvDocument  *document,
654                   const char  *uri,
655                   GError     **error)
656 {
657         char *filename;
658         char *gs_path;
659         gboolean result;
660
661         filename = g_filename_from_uri (uri, NULL, error);
662         if (!filename)
663                 return FALSE;
664
665         gs_path = g_find_program_in_path ("gs");
666         if (!gs_path) {
667                 gchar *filename_dsp;
668                 
669                 filename_dsp = g_filename_display_name (filename);
670                 g_set_error (error,
671                              G_FILE_ERROR,
672                              G_FILE_ERROR_NOENT,
673                              _("Failed to load document “%s”. Ghostscript interpreter was not found in path"),
674                              filename);
675                 g_free (filename_dsp);
676                 g_free (filename);
677                 
678                 return FALSE;
679         }
680
681         result = document_load (PS_DOCUMENT (document), filename, error);
682         if (!result && !(*error)) {
683                 gchar *filename_dsp;
684                 
685                 filename_dsp = g_filename_display_name (filename);
686                 g_set_error (error,
687                              G_FILE_ERROR,
688                              G_FILE_ERROR_FAILED,
689                              _("Failed to load document “%s”"),
690                              filename_dsp);
691                 g_free (filename_dsp);
692         }
693         
694         g_free (gs_path);
695         g_free (filename);
696
697         return result;
698 }
699
700 static gboolean
701 save_document (PSDocument *document, const char *filename)
702 {
703         gboolean result = TRUE;
704         GtkGSDocSink *sink = gtk_gs_doc_sink_new ();
705         FILE *f, *src_file;
706         gchar *buf;
707
708         src_file = fopen (document->gs_filename, "r");
709         if (src_file) {
710                 struct stat stat_rec;
711
712                 if (stat (document->gs_filename, &stat_rec) == 0) {
713                         pscopy (src_file, sink, 0, stat_rec.st_size - 1);
714                 }
715
716                 fclose (src_file);
717         }
718         
719         buf = gtk_gs_doc_sink_get_buffer (sink);
720         if (buf == NULL) {
721                 return FALSE;
722         }
723         
724         f = fopen (filename, "w");
725         if (f) {
726                 fputs (buf, f);
727                 fclose (f);
728         } else {
729                 result = FALSE;
730         }
731
732         g_free (buf);
733         gtk_gs_doc_sink_free (sink);
734         g_free (sink);
735
736         return result;
737 }
738
739 static gboolean
740 save_page_list (PSDocument *document, int *page_list, const char *filename)
741 {
742         gboolean result = TRUE;
743         GtkGSDocSink *sink = gtk_gs_doc_sink_new ();
744         FILE *f;
745         gchar *buf;
746
747         pscopydoc (sink, document->gs_filename, 
748                    document->doc, page_list);
749         
750         buf = gtk_gs_doc_sink_get_buffer (sink);
751         
752         f = fopen (filename, "w");
753         if (f) {
754                 fputs (buf, f);
755                 fclose (f);
756         } else {
757                 result = FALSE;
758         }
759
760         g_free (buf);
761         gtk_gs_doc_sink_free (sink);
762         g_free (sink);
763
764         return result;
765 }
766
767 static gboolean
768 ps_document_save (EvDocument  *document,
769                   const char  *uri,
770                   GError     **error)
771 {
772         PSDocument *ps = PS_DOCUMENT (document);
773         gboolean result;
774         char *filename;
775
776         filename = g_filename_from_uri (uri, NULL, error);
777         if (!filename)
778                 return FALSE;
779
780         result = save_document (ps, filename);
781
782         g_free (filename);
783
784         return result;
785 }
786
787 static int
788 ps_document_get_n_pages (EvDocument *document)
789 {
790         PSDocument *ps = PS_DOCUMENT (document);
791
792         if (!ps->gs_filename || !ps->doc) {
793                 return -1;
794         }
795
796         return ps->structured_doc ? ps->doc->numpages : 1;
797 }
798
799 #define DEFAULT_PAGE_SIZE 1
800
801 static void
802 get_page_box (PSDocument *gs, int page, int *urx, int *ury, int *llx, int *lly)
803 {
804         gint new_llx = 0;
805         gint new_lly = 0;
806         gint new_urx = 0;
807         gint new_ury = 0;
808         GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes ();
809         int new_pagesize = -1;
810
811         if (new_pagesize == -1) {
812                 new_pagesize = DEFAULT_PAGE_SIZE;
813                 if (gs->doc) {
814                         /* If we have a document:
815                          * We use -- the page size (if specified)       
816                          * or the doc. size (if specified)      
817                          * or the page bbox (if specified)      
818                          * or the bounding box  
819                          */
820                         if ((page >= 0) && (gs->doc->numpages > page) &&
821                             (gs->doc->pages) && (gs->doc->pages[page].size)) {
822                                 new_pagesize = gs->doc->pages[page].size - gs->doc->size;
823                         } else if (gs->doc->default_page_size != NULL) {
824                                 new_pagesize = gs->doc->default_page_size - gs->doc->size;
825                         } else if ((page >= 0) &&
826                                    (gs->doc->numpages > page) &&
827                                    (gs->doc->pages) &&
828                                    (gs->doc->pages[page].boundingbox[URX] >
829                                     gs->doc->pages[page].boundingbox[LLX]) &&
830                                    (gs->doc->pages[page].boundingbox[URY] >
831                                     gs->doc->pages[page].boundingbox[LLY])) {
832                                 new_pagesize = -1;
833                         } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
834                                    (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
835                                 new_pagesize = -1;
836                         }
837                 }
838         }
839
840         /* Compute bounding box */
841         if (gs->doc && (gs->doc->epsf || new_pagesize == -1)) {    /* epsf or bbox */
842                 if ((page >= 0) &&
843                     (gs->doc->pages) &&
844                     (gs->doc->pages[page].boundingbox[URX] >
845                      gs->doc->pages[page].boundingbox[LLX]) &&
846                     (gs->doc->pages[page].boundingbox[URY] >
847                      gs->doc->pages[page].boundingbox[LLY])) {
848                         /* use page bbox */
849                         new_llx = gs->doc->pages[page].boundingbox[LLX];
850                         new_lly = gs->doc->pages[page].boundingbox[LLY];
851                         new_urx = gs->doc->pages[page].boundingbox[URX];
852                         new_ury = gs->doc->pages[page].boundingbox[URY];
853                 } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
854                            (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
855                         /* use doc bbox */
856                         new_llx = gs->doc->boundingbox[LLX];
857                         new_lly = gs->doc->boundingbox[LLY];
858                         new_urx = gs->doc->boundingbox[URX];
859                         new_ury = gs->doc->boundingbox[URY];
860                 }
861         } else {
862                 if (new_pagesize < 0)
863                         new_pagesize = DEFAULT_PAGE_SIZE;
864                 new_llx = new_lly = 0;
865                 if (gs->doc && gs->doc->size &&
866                     (new_pagesize < gs->doc->numsizes)) {
867                         new_urx = gs->doc->size[new_pagesize].width;
868                         new_ury = gs->doc->size[new_pagesize].height;
869                 } else {
870                         new_urx = papersizes[new_pagesize].width;
871                         new_ury = papersizes[new_pagesize].height;
872                 }
873         }
874
875         if (new_urx <= new_llx)
876                 new_urx = papersizes[12].width;
877         if (new_ury <= new_lly)
878                 new_ury = papersizes[12].height;
879
880         *urx = new_urx;
881         *ury = new_ury;
882         *llx = new_llx;
883         *lly = new_lly;
884 }
885
886 static void
887 ps_document_get_page_size (EvDocument *document,
888                            int         page,
889                            double     *width,
890                            double     *height)
891 {
892         PSDocument *gs = PS_DOCUMENT (document);
893         int urx, ury, llx, lly;
894
895         get_page_box (gs, page, &urx, &ury, &llx, &lly);
896
897         if (width) {
898                 *width = (urx - llx) + 0.5;
899         }
900
901         if (height) {
902                 *height = (ury - lly) + 0.5;
903         }
904 }
905
906 static gboolean
907 ps_document_can_get_text (EvDocument *document)
908 {
909         return FALSE;
910 }
911
912 static EvDocumentInfo *
913 ps_document_get_info (EvDocument *document)
914 {
915         EvDocumentInfo *info;
916         PSDocument *ps = PS_DOCUMENT (document);
917         int urx, ury, llx, lly;
918
919         info = g_new0 (EvDocumentInfo, 1);
920         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
921                             EV_DOCUMENT_INFO_FORMAT |
922                             EV_DOCUMENT_INFO_CREATOR |
923                             EV_DOCUMENT_INFO_N_PAGES |
924                             EV_DOCUMENT_INFO_PAPER_SIZE;
925
926         info->title = g_strdup (ps->doc->title);
927         info->format = ps->doc->epsf ? g_strdup (_("Encapsulated PostScript"))
928                                      : g_strdup (_("PostScript"));
929         info->creator = g_strdup (ps->doc->creator);
930         info->n_pages = ev_document_get_n_pages (document);
931         
932         get_page_box (PS_DOCUMENT (document), 0, &urx, &ury, &llx, &lly);
933
934         info->paper_width  = (urx - llx) / 72.0f * 25.4f;
935         info->paper_height = (ury - lly) / 72.0f * 25.4f;
936
937         return info;
938 }
939
940 static void
941 ps_document_document_iface_init (EvDocumentIface *iface)
942 {
943         iface->load = ps_document_load;
944         iface->save = ps_document_save;
945         iface->can_get_text = ps_document_can_get_text;
946         iface->get_n_pages = ps_document_get_n_pages;
947         iface->get_page_size = ps_document_get_page_size;
948         iface->get_info = ps_document_get_info;
949 }
950
951 /* EvAsyncRendererIface */
952 static void
953 setup_page (PSDocument *gs, int page, double scale, int rotation)
954 {
955         gchar *buf;
956         char scaled_dpi[G_ASCII_DTOSTR_BUF_SIZE];       
957         int urx, ury, llx, lly;
958         PSDocumentClass *gs_class;
959
960         gs_class = PS_DOCUMENT_GET_CLASS (gs);
961
962         get_page_box (gs, page, &urx, &ury, &llx, &lly);
963         g_ascii_dtostr (scaled_dpi, G_ASCII_DTOSTR_BUF_SIZE, 72.0 * scale);
964
965         buf = g_strdup_printf ("%ld %d %d %d %d %d %s %s %d %d %d %d",
966                                0L, rotation, llx, lly, urx, ury,
967                                scaled_dpi, scaled_dpi,
968                                0, 0, 0, 0);
969         
970         gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom,
971                              8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen (buf));
972         g_free (buf);
973         
974         gdk_flush ();
975 }
976
977 static void
978 setup_pixmap (PSDocument *gs, int page, double scale, int rotation)
979 {
980         GdkGC *fill;
981         GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
982         GdkColormap *colormap;
983         double width, height;
984         int pixmap_width, pixmap_height;
985         
986         if (gs->pstarget == NULL)
987                 return;
988
989         ev_document_get_page_size (EV_DOCUMENT (gs), page, &width, &height);
990
991         if (rotation == 90 || rotation == 270) {
992                 pixmap_height = width * scale + 0.5;
993                 pixmap_width = height * scale + 0.5;
994         } else {
995                 pixmap_width = width * scale + 0.5;
996                 pixmap_height = height * scale + 0.5;
997         }
998
999         if (gs->bpixmap) {
1000                 gint w, h;
1001
1002                 gdk_drawable_get_size (gs->bpixmap, &w, &h);
1003
1004                 if (pixmap_width != w || h != pixmap_height) {
1005                         g_object_unref (gs->bpixmap);
1006                         gs->bpixmap = NULL;
1007                         ps_interpreter_stop (gs);
1008                 }
1009         }
1010
1011         if (!gs->bpixmap) {
1012                 fill = gdk_gc_new (gs->pstarget);
1013                 colormap = gdk_drawable_get_colormap (gs->pstarget);
1014                 gdk_colormap_alloc_color (colormap, &white, FALSE, TRUE);
1015                 gdk_gc_set_foreground (fill, &white);
1016                 gs->bpixmap = gdk_pixmap_new (gs->pstarget, pixmap_width,
1017                                               pixmap_height, -1);
1018                 gdk_draw_rectangle (gs->bpixmap, fill, TRUE,
1019                                     0, 0, pixmap_width, pixmap_height);
1020         }
1021 }
1022
1023 static void
1024 push_pixbuf (PSDocument *gs)
1025 {
1026         GdkColormap *cmap;
1027         GdkPixbuf *pixbuf;
1028         gint width, height;
1029
1030         if (gs->pstarget == NULL)
1031                 return;
1032
1033         cmap = gdk_drawable_get_colormap (gs->pstarget);
1034         gdk_drawable_get_size (gs->bpixmap, &width, &height);
1035         pixbuf = gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap,
1036                                                0, 0, 0, 0,
1037                                                width, height);
1038         g_signal_emit_by_name (gs, "render_finished", pixbuf);
1039         g_object_unref (pixbuf);
1040 }
1041
1042 static gboolean
1043 ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
1044 {
1045         PSDocument *gs = (PSDocument *) data;
1046         PSDocumentClass *gs_class;
1047
1048         if (event->type != GDK_CLIENT_EVENT)
1049                 return FALSE;
1050
1051         gs_class = PS_DOCUMENT_GET_CLASS (gs);
1052         
1053         gs->message_window = event->client.data.l[0];
1054
1055         if (event->client.message_type == gs_class->page_atom) {
1056                 gs->busy = FALSE;
1057
1058                 push_pixbuf (gs);
1059         }
1060
1061         return TRUE;
1062 }
1063
1064 static void
1065 send_ps (PSDocument *gs, long begin, unsigned int len, gboolean close)
1066 {
1067         PSSection *ps_new;
1068
1069         if (!gs->interpreter_input) {
1070                 g_critical ("No pipe to gs: error in send_ps().");
1071                 return;
1072         }
1073
1074         ps_new = g_new0 (PSSection, 1);
1075         ps_new->fp = gs->gs_psfile;
1076         ps_new->begin = begin;
1077         ps_new->len = len;
1078         ps_new->seek_needed = TRUE;
1079         ps_new->close = close;
1080
1081         if (gs->input_buffer == NULL) {
1082                 gs->input_buffer = g_malloc (MAX_BUFSIZE);
1083         }
1084
1085         if (g_queue_is_empty (gs->ps_input)) {
1086                 gs->input_buffer_ptr = gs->input_buffer;
1087                 gs->bytes_left = len;
1088                 gs->buffer_bytes_left = 0;
1089                 g_queue_push_head (gs->ps_input, ps_new);
1090                 gs->interpreter_input_id =
1091                         g_io_add_watch (gs->interpreter_input,
1092                                         G_IO_OUT/* | G_IO_HUP | G_IO_ERR | G_IO_NVAL*/,
1093                                         (GIOFunc)ps_interpreter_input,
1094                                         gs);
1095         } else {
1096                 g_queue_push_head (gs->ps_input, ps_new);
1097         }
1098 }
1099
1100 static void
1101 ps_document_next_page (PSDocument *gs)
1102 {
1103         XEvent      event;
1104         GdkScreen  *screen;
1105         GdkDisplay *display;
1106         Display    *dpy;
1107         PSDocumentClass *gs_class;
1108
1109         g_assert (gs->interpreter_pid != 0);
1110         g_assert (gs->busy != TRUE);
1111
1112         gs_class = PS_DOCUMENT_GET_CLASS (gs);
1113         
1114         gs->busy = TRUE;
1115
1116         screen = gtk_window_get_screen (GTK_WINDOW (gs->target_window));
1117         display = gdk_screen_get_display (screen);
1118         dpy = gdk_x11_display_get_xdisplay (display);
1119
1120         event.xclient.type = ClientMessage;
1121         event.xclient.display = dpy;
1122         event.xclient.window = gs->message_window;
1123         event.xclient.message_type =
1124                 gdk_x11_atom_to_xatom_for_display (display,
1125                                                    gs_class->next_atom);
1126         event.xclient.format = 32;
1127
1128         gdk_error_trap_push ();
1129         XSendEvent (dpy, gs->message_window, FALSE, 0, &event);
1130         gdk_flush ();
1131         gdk_error_trap_pop ();
1132 }
1133
1134 static gboolean
1135 render_page (PSDocument *gs, int page)
1136 {
1137         g_assert (gs != NULL);
1138
1139         if (!gs->gs_filename) {
1140                 return FALSE;
1141         }
1142
1143         if (gs->structured_doc && gs->doc) {
1144                 if (ps_interpreter_is_ready (gs)) {
1145                         ps_document_next_page (gs);
1146                 } else {
1147                         ps_interpreter_start (gs);
1148                         send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1149                         send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1150                 }
1151
1152                 send_ps (gs, gs->doc->pages[page].begin,
1153                          gs->doc->pages[page].len, FALSE);
1154         } else {
1155                 /* Unstructured document
1156                  *
1157                  * In the case of non structured documents,
1158                  * GS read the PS from the  actual file (via command
1159                  * line. Hence, ggv only send a signal next page.
1160                  * If ghostview is not running it is usually because
1161                  * the last page of the file was displayed. In that
1162                  * case, ggv restarts GS again and the first page is displayed.
1163                  */
1164
1165                 if (!ps_interpreter_is_ready (gs)) {
1166                         ps_interpreter_start (gs);
1167                 }
1168                 ps_document_next_page (gs);
1169         }
1170
1171         return TRUE;
1172 }
1173
1174 static void
1175 ps_async_renderer_render_pixbuf (EvAsyncRenderer *renderer,
1176                                  gint             page,
1177                                  gdouble          scale,
1178                                  gint             rotation)
1179 {
1180         PSDocument *gs = PS_DOCUMENT (renderer);
1181
1182         if (gs->pstarget == NULL) {
1183                 gs->target_window = gtk_window_new (GTK_WINDOW_POPUP);
1184                 gtk_widget_realize (gs->target_window);
1185                 gs->pstarget = gs->target_window->window;
1186
1187                 g_assert (gs->pstarget != NULL);
1188
1189                 g_signal_connect (gs->target_window, "event",
1190                                   G_CALLBACK (ps_document_widget_event),
1191                                   gs);
1192         }
1193
1194         setup_pixmap (gs, page, scale, rotation);
1195         setup_page (gs, page, scale, rotation);
1196
1197         render_page (gs, page);
1198 }
1199
1200 static void
1201 ps_async_renderer_iface_init (EvAsyncRendererIface *iface)
1202 {
1203         iface->render_pixbuf = ps_async_renderer_render_pixbuf;
1204 }
1205
1206 /* EvFileExporterIface */
1207 static gboolean
1208 ps_document_file_exporter_format_supported (EvFileExporter      *exporter,
1209                                             EvFileExporterFormat format)
1210 {
1211         return (format == EV_FILE_FORMAT_PS);
1212 }
1213
1214 static void
1215 ps_document_file_exporter_begin (EvFileExporter      *exporter,
1216                                  EvFileExporterFormat format,
1217                                  const char          *filename,
1218                                  int                  first_page,
1219                                  int                  last_page,
1220                                  double               width,
1221                                  double               height,
1222                                  gboolean             duplex)
1223 {
1224         PSDocument *document = PS_DOCUMENT (exporter);
1225
1226         if (document->structured_doc) {
1227                 g_free (document->ps_export_pagelist);
1228         
1229                 document->ps_export_pagelist = g_new0 (int, document->doc->numpages);
1230         }
1231
1232         document->ps_export_filename = g_strdup (filename);
1233 }
1234
1235 static void
1236 ps_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
1237 {
1238         PSDocument *document = PS_DOCUMENT (exporter);
1239         
1240         if (document->structured_doc) {
1241                 document->ps_export_pagelist[rc->page] = 1;
1242         }
1243 }
1244
1245 static void
1246 ps_document_file_exporter_end (EvFileExporter *exporter)
1247 {
1248         PSDocument *document = PS_DOCUMENT (exporter);
1249
1250         if (!document->structured_doc) {
1251                 save_document (document, document->ps_export_filename);
1252         } else {
1253                 save_page_list (document, document->ps_export_pagelist,
1254                                 document->ps_export_filename);
1255                 g_free (document->ps_export_pagelist);
1256                 g_free (document->ps_export_filename);  
1257                 document->ps_export_pagelist = NULL;
1258                 document->ps_export_filename = NULL;
1259         }
1260 }
1261
1262 static void
1263 ps_document_file_exporter_iface_init (EvFileExporterIface *iface)
1264 {
1265         iface->format_supported = ps_document_file_exporter_format_supported;
1266         iface->begin = ps_document_file_exporter_begin;
1267         iface->do_page = ps_document_file_exporter_do_page;
1268         iface->end = ps_document_file_exporter_end;
1269 }