1 /* Ghostscript widget for GTK/GNOME
3 * Copyright (C) 1998 - 2005 the Free Software Foundation
5 * Authors: Jonathan Blandford, Jaka Mocnik
7 * Based on code by: Federico Mena (Quartic), Szekeres Istvan (Pista)
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.
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.
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.
26 Ghostview interface to ghostscript
28 When the GHOSTVIEW environment variable is set, ghostscript draws on
29 an existing drawable rather than creating its own window. Ghostscript
30 can be directed to draw on either a window or a pixmap.
34 The GHOSTVIEW environment variable contains the window id of the target
35 window. The window id is an integer. Ghostscript will use the attributes
36 of the window to obtain the width, height, colormap, screen, and visual of
37 the window. The remainder of the information is gotten from the GHOSTVIEW
38 property on that window.
43 The GHOSTVIEW environment variable contains a window id and a pixmap id.
44 They are integers separated by white space. Ghostscript will use the
45 attributes of the window to obtain the colormap, screen, and visual to use.
46 The width and height will be obtained from the pixmap. The remainder of the
47 information, is gotten from the GHOSTVIEW property on the window. In this
48 case, the property is deleted when read.
50 The GHOSTVIEW environment variable
52 parameters: window-id [pixmap-id]
56 explanation of parameters:
58 window-id: tells ghostscript where to
59 - read the GHOSTVIEW property
61 If pixmap-id is not present,
62 ghostscript will draw on this window.
64 pixmap-id: If present, tells ghostscript that a pixmap will be used
65 as the final destination for drawing. The window will
66 not be touched for drawing purposes.
68 The GHOSTVIEW property
74 bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right]
76 scanf format: "%d %d %d %d %d %d %f %f %d %d %d %d"
78 explanation of parameters:
80 bpixmap: pixmap id of the backing pixmap for the window. If no
81 pixmap is to be used, this parameter should be zero. This
82 parameter must be zero when drawing on a pixmap.
84 orient: orientation of the page. The number represents clockwise
85 rotation of the paper in degrees. Permitted values are
88 llx, lly, urx, ury: Bounding box of the drawable. The bounding box
89 is specified in PostScript points in default user coordinates.
91 xdpi, ydpi: Resolution of window. (This can be derived from the
92 other parameters, but not without roundoff error. These
93 values are included to avoid this error.)
95 left, bottom, top, right: (optional)
96 Margins around the window. The margins extend the imageable
97 area beyond the boundaries of the window. This is primarily
98 used for popup zoom windows. I have encountered several
99 instances of PostScript programs that position themselves
100 with respect to the imageable area. The margins are specified
101 in PostScript points. If omitted, the margins are assumed to
104 Events from ghostscript
106 If the final destination is a pixmap, the client will get a property notify
107 event when ghostscript reads the GHOSTVIEW property causing it to be deleted.
109 Ghostscript sends events to the window where it read the GHOSTVIEW property.
110 These events are of type ClientMessage. The message_type is set to
111 either PAGE or DONE. The first long data value gives the window to be used
112 to send replies to ghostscript. The second long data value gives the primary
113 drawable. If rendering to a pixmap, it is the primary drawable. If rendering
114 to a window, the backing pixmap is the primary drawable. If no backing pixmap
115 is employed, then the window is the primary drawable. This field is necessary
116 to distinguish multiple ghostscripts rendering to separate pixmaps where the
117 GHOSTVIEW property was placed on the same window.
119 The PAGE message indicates that a "page" has completed. Ghostscript will
120 wait until it receives a ClientMessage whose message_type is NEXT before
123 The DONE message indicates that ghostscript has finished processing.
132 #include <gtk/gtkobject.h>
133 #include <gdk/gdkprivate.h>
134 #include <gdk/gdkx.h>
136 #include <glib/gi18n.h>
138 # include <gdk/gdkx.h>
139 # include <X11/extensions/Xinerama.h>
140 #endif /* HAVE_XINERAMA */
141 #include <X11/Intrinsic.h>
146 #include <sys/stat.h>
147 #include <sys/types.h>
148 #include <sys/wait.h>
152 #include "ev-document.h"
155 #include "gsdefaults.h"
161 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
162 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
163 # define O_NONBLOCK O_NDELAY
166 #define GTK_GS_WATCH_INTERVAL 1000
167 #define GTK_GS_WATCH_TIMEOUT 2
169 #define MAX_BUFSIZE 1024
171 enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL };
173 static gboolean broken_pipe = FALSE;
181 /* Forward declarations */
182 static void gtk_gs_init(GtkGS * gs);
183 static void gtk_gs_class_init(GtkGSClass * klass);
184 static void gtk_gs_interpreter_message(GtkGS * gs, gchar * msg,
186 static void gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg);
187 static void gtk_gs_finalize(GObject * object);
188 static void send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close);
189 static void set_up_page(GtkGS * gs);
190 static void close_pipe(int p[2]);
191 static void interpreter_failed(GtkGS * gs);
192 static float compute_xdpi(void);
193 static float compute_ydpi(void);
194 static gboolean compute_size(GtkGS * gs);
195 static void output(gpointer data, gint source, GdkInputCondition condition);
196 static void input(gpointer data, gint source, GdkInputCondition condition);
197 static void stop_interpreter(GtkGS * gs);
198 static gint start_interpreter(GtkGS * gs);
199 gboolean computeSize(void);
200 static void ps_document_document_iface_init (EvDocumentIface *iface);
202 static GObjectClass *parent_class = NULL;
204 static GtkGSClass *gs_class = NULL;
206 static gint gtk_gs_signals[LAST_SIGNAL] = { 0 };
208 /* Static, private functions */
211 ggv_marshaller_VOID__POINTER(GClosure * closure,
212 GValue * return_value,
213 guint n_param_values,
214 const GValue * param_values,
215 gpointer invocation_hint, gpointer marshal_data)
217 typedef void (*GMarshalFunc_VOID__POINTER) (gpointer data1,
218 gpointer arg_1, gpointer data2);
219 register GMarshalFunc_VOID__POINTER callback;
220 register GCClosure *cc = (GCClosure *) closure;
221 register gpointer data1, data2;
223 g_return_if_fail(n_param_values == 2);
225 if(G_CCLOSURE_SWAP_DATA(closure)) {
226 data1 = closure->data;
227 data2 = g_value_peek_pointer(param_values + 0);
230 data1 = g_value_peek_pointer(param_values + 0);
231 data2 = closure->data;
234 (GMarshalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
236 callback(data1, g_value_get_pointer(param_values + 1), data2);
240 ggv_marshaller_VOID__INT(GClosure * closure,
241 GValue * return_value,
242 guint n_param_values,
243 const GValue * param_values,
244 gpointer invocation_hint, gpointer marshal_data)
246 typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
247 gint arg_1, gpointer data2);
248 register GMarshalFunc_VOID__INT callback;
249 register GCClosure *cc = (GCClosure *) closure;
250 register gpointer data1, data2;
252 g_return_if_fail(n_param_values == 2);
254 if(G_CCLOSURE_SWAP_DATA(closure)) {
255 data1 = closure->data;
256 data2 = g_value_peek_pointer(param_values + 0);
259 data1 = g_value_peek_pointer(param_values + 0);
260 data2 = closure->data;
263 (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
265 callback(data1, g_value_get_int(param_values + 1), data2);
269 gtk_gs_init(GtkGS * gs)
273 gs->current_page = -2;
274 gs->disable_start = FALSE;
275 gs->interpreter_pid = -1;
281 gs->gs_scanstyle = 0;
283 gs->gs_filename_dsc = 0;
284 gs->gs_filename_unc = 0;
288 gs->structured_doc = FALSE;
289 gs->reading_from_pipe = FALSE;
290 gs->send_filename_to_gs = FALSE;
295 gs->interpreter_input = -1;
296 gs->interpreter_output = -1;
297 gs->interpreter_err = -1;
298 gs->interpreter_input_id = 0;
299 gs->interpreter_output_id = 0;
300 gs->interpreter_error_id = 0;
303 gs->input_buffer = NULL;
304 gs->input_buffer_ptr = NULL;
306 gs->buffer_bytes_left = 0;
312 gs->xdpi = compute_xdpi();
313 gs->ydpi = compute_ydpi();
317 gs->right_margin = 0;
318 gs->bottom_margin = 0;
320 /* Set user defined defaults */
321 gs->override_orientation = gtk_gs_defaults_get_override_orientation();
322 gs->fallback_orientation = gtk_gs_defaults_get_orientation();
323 gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
324 gs->default_size = gtk_gs_defaults_get_size();
325 gs->antialiased = gtk_gs_defaults_get_antialiased();
326 gs->override_size = gtk_gs_defaults_get_override_size();
327 gs->respect_eof = gtk_gs_defaults_get_respect_eof();
328 gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
330 gs->gs_status = _("No document loaded.");
334 gtk_gs_class_init(GtkGSClass * klass)
336 GObjectClass *object_class;
338 object_class = (GObjectClass *) klass;
339 parent_class = gtk_type_class(gtk_widget_get_type());
342 gtk_gs_signals[INTERPRETER_MESSAGE] = g_signal_new("interpreter_message",
348 interpreter_message),
350 ggv_marshaller_VOID__POINTER,
353 gtk_gs_signals[INTERPRETER_ERROR] =
354 g_signal_new("interpreter_error", G_TYPE_FROM_CLASS(object_class),
355 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkGSClass,
357 NULL, NULL, ggv_marshaller_VOID__INT, G_TYPE_NONE, 1,
360 object_class->finalize = gtk_gs_finalize;
363 klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
364 klass->gs_colors_atom = gdk_atom_intern("GHOSTVIEW_COLORS", FALSE);
365 klass->next_atom = gdk_atom_intern("NEXT", FALSE);
366 klass->page_atom = gdk_atom_intern("PAGE", FALSE);
367 klass->done_atom = gdk_atom_intern("DONE", FALSE);
368 klass->string_atom = gdk_atom_intern("STRING", FALSE);
370 /* a default handler for "interpreter_message" signal */
371 klass->interpreter_message = gtk_gs_interpreter_message;
373 gtk_gs_defaults_load();
376 /* Clean all memory and temporal files */
378 gtk_gs_cleanup(GtkGS * gs)
380 g_return_if_fail(gs != NULL);
381 g_return_if_fail(GTK_IS_GS(gs));
383 stop_interpreter(gs);
386 fclose(gs->gs_psfile);
387 gs->gs_psfile = NULL;
389 if(gs->gs_filename) {
390 g_free(gs->gs_filename);
391 gs->gs_filename = NULL;
397 if(gs->gs_filename_dsc) {
398 unlink(gs->gs_filename_dsc);
399 g_free(gs->gs_filename_dsc);
400 gs->gs_filename_dsc = NULL;
402 if(gs->gs_filename_unc) {
403 unlink(gs->gs_filename_unc);
404 g_free(gs->gs_filename_unc);
405 gs->gs_filename_unc = NULL;
407 gs->current_page = -1;
416 /* free message as it was allocated in output() */
418 gtk_gs_interpreter_message(GtkGS * gs, gchar * msg, gpointer user_data)
420 gdk_pointer_ungrab(GDK_CURRENT_TIME);
421 if(strstr(msg, "Error:")) {
422 gs->gs_status = _("File is not a valid PostScript document.");
424 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", 1, NULL);
430 gtk_gs_finalize(GObject * object)
434 g_return_if_fail(object != NULL);
435 g_return_if_fail(GTK_IS_GS(object));
441 if(gs->input_buffer) {
442 g_free(gs->input_buffer);
443 gs->input_buffer = NULL;
446 (*G_OBJECT_CLASS(parent_class)->finalize) (object);
450 gtk_gs_set_center(GtkGS * gs, gfloat hval, gfloat vval)
455 send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close)
457 struct record_list *ps_new;
459 if(gs->interpreter_input < 0) {
460 g_critical("No pipe to gs: error in send_ps().");
464 ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
465 ps_new->fp = gs->gs_psfile;
466 ps_new->begin = begin;
468 ps_new->seek_needed = TRUE;
469 ps_new->close = close;
472 if(gs->input_buffer == NULL) {
473 gs->input_buffer = g_malloc(MAX_BUFSIZE);
476 if(gs->ps_input == NULL) {
477 gs->input_buffer_ptr = gs->input_buffer;
478 gs->bytes_left = len;
479 gs->buffer_bytes_left = 0;
480 gs->ps_input = ps_new;
481 gs->interpreter_input_id =
482 gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
485 struct record_list *p = gs->ps_input;
486 while(p->next != NULL) {
494 set_up_page(GtkGS * gs)
498 //GdkColormap *colormap;
500 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */
501 GdkColormap *colormap;
507 if (gs->pstarget == NULL)
510 /* Do we have to check if the actual geometry changed? */
512 stop_interpreter(gs);
514 orientation = gtk_gs_get_orientation(gs);
516 if(compute_size(gs)) {
519 /* clear new pixmap (set to white) */
520 fill = gdk_gc_new(gs->pstarget);
522 colormap = gdk_drawable_get_colormap(gs->pstarget);
523 gdk_color_alloc (colormap, &white);
524 gdk_gc_set_foreground(fill, &white);
526 if(gs->width > 0 && gs->height > 0) {
528 gdk_drawable_unref(gs->bpixmap);
532 gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
534 gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
535 0, 0, gs->width, gs->height);
538 gdk_draw_rectangle(gs->pstarget, fill, TRUE,
539 0, 0, gs->width, gs->height);
548 /* gs needs floating point parameters with '.' as decimal point
549 * while some (european) locales use ',' instead, so we set the
550 * locale for this snprintf to "C".
552 savelocale = setlocale(LC_NUMERIC, "C");
555 g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
562 gs->xdpi * gs->zoom_factor,
563 gs->ydpi * gs->zoom_factor,
565 gs->bottom_margin, gs->right_margin, gs->top_margin);
568 setlocale(LC_NUMERIC, savelocale);
570 gdk_property_change(gs->pstarget,
572 gs_class->string_atom,
573 8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
587 is_interpreter_ready(GtkGS * gs)
589 return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
593 interpreter_failed(GtkGS * gs)
595 stop_interpreter(gs);
599 output(gpointer data, gint source, GdkInputCondition condition)
601 char buf[MAX_BUFSIZE + 1], *msg;
603 GtkGS *gs = GTK_GS(data);
605 if(source == gs->interpreter_output) {
606 bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
607 if(bytes == 0) { /* EOF occurred */
608 close(gs->interpreter_output);
609 gs->interpreter_output = -1;
610 gdk_input_remove(gs->interpreter_output_id);
613 else if(bytes == -1) {
615 interpreter_failed(gs);
618 if(gs->interpreter_err == -1) {
619 stop_interpreter(gs);
622 else if(source == gs->interpreter_err) {
623 bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
624 if(bytes == 0) { /* EOF occurred */
625 close(gs->interpreter_err);
626 gs->interpreter_err = -1;
627 gdk_input_remove(gs->interpreter_error_id);
630 else if(bytes == -1) {
632 interpreter_failed(gs);
635 if(gs->interpreter_output == -1) {
636 stop_interpreter(gs);
642 g_signal_emit (G_OBJECT(gs), gtk_gs_signals[INTERPRETER_MESSAGE], 0, msg);
647 input(gpointer data, gint source, GdkInputCondition condition)
649 GtkGS *gs = GTK_GS(data);
651 void (*oldsig) (int);
652 oldsig = signal(SIGPIPE, catchPipe);
655 if(gs->buffer_bytes_left == 0) {
656 /* Get a new section if required */
657 if(gs->ps_input && gs->bytes_left == 0) {
658 struct record_list *ps_old = gs->ps_input;
659 gs->ps_input = ps_old->next;
660 if(ps_old->close && NULL != ps_old->fp)
662 g_free((char *) ps_old);
664 /* Have to seek at the beginning of each section */
665 if(gs->ps_input && gs->ps_input->seek_needed) {
666 fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
667 gs->ps_input->seek_needed = FALSE;
668 gs->bytes_left = gs->ps_input->len;
671 if(gs->bytes_left > MAX_BUFSIZE) {
672 gs->buffer_bytes_left =
673 fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
675 else if(gs->bytes_left > 0) {
676 gs->buffer_bytes_left =
677 fread(gs->input_buffer,
678 sizeof(char), gs->bytes_left, gs->ps_input->fp);
681 gs->buffer_bytes_left = 0;
683 if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
684 interpreter_failed(gs); /* Error occurred */
686 gs->input_buffer_ptr = gs->input_buffer;
687 gs->bytes_left -= gs->buffer_bytes_left;
690 if(gs->buffer_bytes_left > 0) {
691 /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
693 bytes_written = write(gs->interpreter_input,
694 gs->input_buffer_ptr, gs->buffer_bytes_left);
697 gtk_gs_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
699 interpreter_failed(gs);
701 else if(bytes_written == -1) {
702 if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
703 interpreter_failed(gs); /* Something bad happened */
707 gs->buffer_bytes_left -= bytes_written;
708 gs->input_buffer_ptr += bytes_written;
712 while(gs->ps_input && gs->buffer_bytes_left == 0);
714 signal(SIGPIPE, oldsig);
716 if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
717 if(gs->interpreter_input_id != 0) {
718 gdk_input_remove(gs->interpreter_input_id);
719 gs->interpreter_input_id = 0;
725 start_interpreter(GtkGS * gs)
727 int std_in[2] = { -1, -1 }; /* pipe to interp stdin */
728 int std_out[2]; /* pipe from interp stdout */
729 int std_err[2]; /* pipe from interp stderr */
732 #define NUM_GS_ARGS (NUM_ARGS - 20)
733 #define NUM_ALPHA_ARGS 10
735 char *argv[NUM_ARGS], *dir, *gv_env;
736 char **gs_args, **alpha_args = NULL;
742 stop_interpreter(gs);
744 if(gs->disable_start == TRUE)
747 /* set up the args... */
748 gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
749 for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
750 argv[argc] = gs_args[i];
752 if(gs->antialiased) {
753 if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
754 alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
756 alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
757 " ", NUM_ALPHA_ARGS);
758 for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
759 argv[argc] = alpha_args[i];
762 argv[argc++] = "-sDEVICE=x11";
763 argv[argc++] = "-dNOPAUSE";
764 argv[argc++] = "-dQUIET";
765 /* I assume we do _not_ want to change this... (: */
766 argv[argc++] = "-dSAFER";
768 /* set up the pipes */
769 if(gs->send_filename_to_gs) {
770 argv[argc++] = GTK_GS_GET_PS_FILE(gs);
772 argv[argc++] = "quit";
779 if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
780 if(pipe(std_in) == -1) {
781 g_critical("Unable to open pipe to Ghostscript.");
785 if(pipe(std_out) == -1) {
789 if(pipe(std_err) == -1) {
796 gs->interpreter_pid = fork();
797 switch (gs->interpreter_pid) {
813 if(!gs->reading_from_pipe) {
814 if(gs->send_filename_to_gs) {
816 /* just in case gs tries to read from stdin */
817 stdinfd = open("/dev/null", O_RDONLY);
830 gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld",
831 gdk_x11_drawable_get_xid(gs->pstarget),
832 gdk_x11_drawable_get_xid(gs->bpixmap));
835 /* change to directory where the input file is. This helps
836 * with postscript-files which include other files using
838 dir = g_path_get_dirname(gs->gs_filename);
842 execvp(argv[0], argv);
845 g_print("Unable to execute [%s]\n", argv[0]);
849 g_strfreev(alpha_args);
852 default: /* parent */
853 if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
856 /* use non-blocking IO for pipe to ghostscript */
857 result = fcntl(std_in[1], F_GETFL, 0);
858 fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
859 gs->interpreter_input = std_in[1];
862 gs->interpreter_input = -1;
865 gs->interpreter_output = std_out[0];
867 gs->interpreter_err = std_err[0];
868 gs->interpreter_output_id =
869 gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
870 gs->interpreter_error_id =
871 gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
878 stop_interpreter(GtkGS * gs)
880 if(gs->interpreter_pid > 0) {
882 kill(gs->interpreter_pid, SIGTERM);
883 while((wait(&status) == -1) && (errno == EINTR)) ;
884 gs->interpreter_pid = -1;
887 gs->gs_status = _("Interpreter failed.");
888 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", status);
892 if(gs->interpreter_input >= 0) {
893 close(gs->interpreter_input);
894 gs->interpreter_input = -1;
895 if(gs->interpreter_input_id != 0) {
896 gdk_input_remove(gs->interpreter_input_id);
897 gs->interpreter_input_id = 0;
899 while(gs->ps_input) {
900 struct record_list *ps_old = gs->ps_input;
901 gs->ps_input = gs->ps_input->next;
902 if(ps_old->close && NULL != ps_old->fp)
904 g_free((char *) ps_old);
908 if(gs->interpreter_output >= 0) {
909 close(gs->interpreter_output);
910 gs->interpreter_output = -1;
911 if(gs->interpreter_output_id) {
912 gdk_input_remove(gs->interpreter_output_id);
913 gs->interpreter_output_id = 0;
917 if(gs->interpreter_err >= 0) {
918 close(gs->interpreter_err);
919 gs->interpreter_err = -1;
920 if(gs->interpreter_error_id) {
921 gdk_input_remove(gs->interpreter_error_id);
922 gs->interpreter_error_id = 0;
929 /* If file exists and is a regular file then return its length, else -1 */
931 file_length(const gchar * filename)
933 struct stat stat_rec;
935 if(filename && (stat(filename, &stat_rec) == 0)
936 && S_ISREG(stat_rec.st_mode))
937 return stat_rec.st_size;
942 /* Test if file exists, is a regular file and its length is > 0 */
944 file_readable(const char *filename)
946 return (file_length(filename) > 0);
950 * Decompress gs->gs_filename if necessary
951 * Set gs->filename_unc to the name of the uncompressed file or NULL.
952 * Error reporting via signal 'interpreter_message'
953 * Return name of input file to use or NULL on error..
956 check_filecompressed(GtkGS * gs)
960 gchar *filename, *filename_unc, *filename_err, *cmdline;
966 if((file = fopen(gs->gs_filename, "r"))
967 && (fread(buf, sizeof(gchar), 3, file) == 3)) {
968 if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
969 /* file is gzipped or compressed */
970 cmd = gtk_gs_defaults_get_ungzip_cmd();
972 else if(strncmp(buf, "BZh", 3) == 0) {
973 /* file is compressed with bzip2 */
974 cmd = gtk_gs_defaults_get_unbzip2_cmd();
981 return gs->gs_filename;
983 /* do the decompression */
984 filename = g_shell_quote(gs->gs_filename);
985 filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
986 if((fd = mkstemp(filename_unc)) < 0) {
987 g_free(filename_unc);
992 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
993 if((fd = mkstemp(filename_err)) < 0) {
994 g_free(filename_err);
995 g_free(filename_unc);
1000 cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1001 filename, filename_unc, filename_err);
1002 if((system(cmdline) == 0)
1003 && file_readable(filename_unc)
1004 && (file_length(filename_err) == 0)) {
1005 /* sucessfully uncompressed file */
1006 gs->gs_filename_unc = filename_unc;
1010 g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1012 gtk_gs_emit_error_msg(gs, buf);
1013 if(file_length(filename_err) > 0) {
1015 if((err = fopen(filename_err, "r"))) {
1016 /* print file to message window */
1017 while(fgets(buf, 1024, err))
1018 gtk_gs_emit_error_msg(gs, buf);
1022 unlink(filename_unc);
1023 g_free(filename_unc);
1024 filename_unc = NULL;
1026 unlink(filename_err);
1027 g_free(filename_err);
1030 return filename_unc;
1034 * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1035 * pdf file if necessary.
1036 * Set gs->filename_dsc to the name of the dsc file or NULL.
1037 * Error reporting via signal 'interpreter_message'.
1040 check_pdf(GtkGS * gs)
1043 gchar buf[1024], *filename;
1046 /* use uncompressed file as input if necessary */
1047 filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1049 if((file = fopen(filename, "r"))
1050 && (fread(buf, sizeof(char), 5, file) == 5)
1051 && (strncmp(buf, "%PDF-", 5) == 0)) {
1052 /* we found a PDF file */
1053 gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1054 filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1055 if((fd = mkstemp(filename_dsc)) < 0) {
1059 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1060 if((fd = mkstemp(filename_err)) < 0) {
1061 g_free(filename_dsc);
1065 fname = g_shell_quote(filename);
1066 cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1068 /* this command (sometimes?) prints error messages to stdout! */
1069 cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1072 if((system(cmdline) == 0) && file_readable(filename_dsc)) {
1075 filename = gs->gs_filename_dsc = filename_dsc;
1077 if(file_length(filename_err) > 0) {
1078 gchar *err_msg = " ";
1083 if((err = fopen(filename_err, "r"))) {
1085 /* print the content of the file to a message box */
1086 while(fgets(buf, 1024, err))
1087 err_msg = g_strconcat(err_msg, buf, NULL);
1089 /* FIXME The dialog is not yet set to modal, difficult to
1090 * get the parent of the dialog box here
1093 dialog = gtk_message_dialog_new(NULL,
1095 GTK_MESSAGE_WARNING,
1097 ("There was an error while scaning the file: %s \n%s"),
1098 gs->gs_filename, err_msg);
1100 gdk_color_parse("white", &color);
1101 gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1103 g_signal_connect(G_OBJECT(dialog), "response",
1104 G_CALLBACK(gtk_widget_destroy), NULL);
1106 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1107 gtk_widget_show(dialog);
1115 g_snprintf(buf, 1024,
1116 _("Error while converting pdf file %s:\n"), filename);
1117 gtk_gs_emit_error_msg(gs, buf);
1119 if(file_length(filename_err) > 0) {
1121 if((err = fopen(filename_err, "r"))) {
1122 /* print file to message window */
1123 while(fgets(buf, 1024, err))
1124 gtk_gs_emit_error_msg(gs, buf);
1127 unlink(filename_dsc);
1128 g_free(filename_dsc);
1131 unlink(filename_err);
1132 g_free(filename_err);
1140 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1141 /* never mind this patch: a properly working X server should take care of
1142 calculating the proper values. */
1146 # ifndef HAVE_XINERAMA
1147 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1150 dpy = (Display *) GDK_DISPLAY();
1151 if(XineramaIsActive(dpy)) {
1153 XineramaScreenInfo *head_info;
1154 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1155 /* fake it with dimensions of the first head for now */
1156 return 25.4 * head_info[0].width / gdk_screen_width_mm();
1159 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1168 # ifndef HAVE_XINERAMA
1169 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1172 dpy = (Display *) GDK_DISPLAY();
1173 if(XineramaIsActive(dpy)) {
1175 XineramaScreenInfo *head_info;
1176 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1177 /* fake it with dimensions of the first head for now */
1178 return 25.4 * head_info[0].height / gdk_screen_height_mm();
1181 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1190 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1196 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1198 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1200 /* Compute new size of window, sets xdpi and ydpi if necessary.
1201 * returns True if new window size is different */
1203 compute_size(GtkGS * gs)
1205 guint new_width = 1;
1206 guint new_height = 1;
1207 gboolean change = FALSE;
1210 /* width and height can be changed, calculate window size according */
1211 /* to xpdi and ydpi */
1212 orientation = gtk_gs_get_orientation(gs);
1214 switch (orientation) {
1215 case GTK_GS_ORIENTATION_PORTRAIT:
1216 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1217 new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1218 new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1220 case GTK_GS_ORIENTATION_LANDSCAPE:
1221 case GTK_GS_ORIENTATION_SEASCAPE:
1222 new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1223 new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1227 change = (new_width != gs->width * gs->zoom_factor)
1228 || (new_height != gs->height * gs->zoom_factor);
1229 gs->width = (gint) (new_width * gs->zoom_factor);
1230 gs->height = (gint) (new_height * gs->zoom_factor);
1236 gtk_gs_enable_interpreter(GtkGS * gs)
1238 g_return_val_if_fail(gs != NULL, FALSE);
1239 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1241 if(!gs->gs_filename)
1244 gs->disable_start = FALSE;
1246 return start_interpreter(gs);
1249 /* publicly accessible functions */
1252 gtk_gs_get_type(void)
1254 static GType gs_type = 0;
1256 GTypeInfo gs_info = {
1258 (GBaseInitFunc) NULL,
1259 (GBaseFinalizeFunc) NULL,
1260 (GClassInitFunc) gtk_gs_class_init,
1261 (GClassFinalizeFunc) NULL,
1262 NULL, /* class_data */
1264 0, /* n_preallocs */
1265 (GInstanceInitFunc) gtk_gs_init
1268 static const GInterfaceInfo document_info =
1270 (GInterfaceInitFunc) ps_document_document_iface_init,
1275 gs_type = g_type_register_static(G_TYPE_OBJECT,
1276 "GtkGS", &gs_info, 0);
1278 g_type_add_interface_static (gs_type,
1288 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1292 gs = g_object_new(GTK_GS_TYPE, NULL);
1299 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1301 GObject *gs = gtk_gs_new(hadj, vadj);
1302 gtk_gs_load(GTK_GS(gs), fname);
1307 gtk_gs_reload(GtkGS * gs)
1312 if(!gs->gs_filename)
1315 page = gtk_gs_get_current_page(gs);
1316 fname = g_strdup(gs->gs_filename);
1317 gtk_gs_load(gs, fname);
1318 gtk_gs_goto_page(gs, page);
1324 * Show error message -> send signal "interpreter_message"
1327 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1329 g_signal_emit (G_OBJECT(gs),
1330 gtk_gs_signals[INTERPRETER_MESSAGE], 0, g_strdup(msg));
1334 gtk_gs_disable_interpreter(GtkGS * gs)
1336 g_return_if_fail(gs != NULL);
1337 g_return_if_fail(GTK_IS_GS(gs));
1339 gs->disable_start = TRUE;
1341 stop_interpreter(gs);
1345 gtk_gs_load(GtkGS * gs, const gchar * fname)
1347 g_return_val_if_fail(gs != NULL, FALSE);
1348 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1350 /* clean up previous document */
1358 /* prepare this document */
1360 /* default values: no dsc information available */
1361 gs->structured_doc = FALSE;
1362 gs->send_filename_to_gs = TRUE;
1363 gs->current_page = -2;
1366 /* an absolute path */
1367 gs->gs_filename = g_strdup(fname);
1370 /* path relative to our cwd: make it absolute */
1371 gchar *cwd = g_get_current_dir();
1372 gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1376 if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1377 gs->send_filename_to_gs = FALSE;
1381 * We need to make sure that the file is loadable/exists!
1382 * otherwise we want to exit without loading new stuff...
1384 gchar *filename = NULL;
1386 if(!file_readable(fname)) {
1388 g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1389 gtk_gs_emit_error_msg(gs, buf);
1390 gs->gs_status = _("File is not readable.");
1393 filename = check_filecompressed(gs);
1395 filename = check_pdf(gs);
1398 if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1403 /* we grab the vital statistics!!! */
1404 gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1406 if(gs->doc == NULL) {
1407 /* File does not seem to be a Postscript one */
1409 g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1410 gtk_gs_emit_error_msg(gs, buf);
1412 gs->gs_status = _("The file is not a PostScript document.");
1416 if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1417 (gs->doc->epsf && gs->doc->numpages > 1)) {
1418 gs->structured_doc = TRUE;
1419 gs->send_filename_to_gs = FALSE;
1422 /* We have to set up the orientation of the document */
1425 /* orientation can only be portrait, and landscape or none.
1426 This is the document default. A document can have
1427 pages in landscape and some in portrait */
1428 if(gs->override_orientation) {
1429 /* If the orientation should be override...
1430 then gs->orientation has already the correct
1431 value (it was set when the widget was created */
1436 /* Otherwise, set the proper orientation for the doc */
1437 gs->real_orientation = gs->doc->orientation;
1440 gtk_gs_set_page_size(gs, -1, gs->current_page);
1443 gs->gs_status = _("Document loaded.");
1450 gtk_gs_next_page(GtkGS * gs)
1454 g_return_val_if_fail(gs != NULL, FALSE);
1455 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1457 if(gs->interpreter_pid == 0) { /* no interpreter active */
1461 if(gs->busy) { /* interpreter is busy */
1467 event.xclient.type = ClientMessage;
1468 event.xclient.display = gdk_display;
1469 event.xclient.window = gs->message_window;
1470 event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1471 event.xclient.format = 32;
1473 gdk_error_trap_push();
1474 XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1476 gdk_error_trap_pop();
1482 gtk_gs_get_current_page(GtkGS * gs)
1484 g_return_val_if_fail(gs != NULL, -1);
1485 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1487 return gs->current_page;
1491 gtk_gs_get_page_count(GtkGS * gs)
1493 if(!gs->gs_filename)
1497 if(gs->structured_doc)
1498 return gs->doc->numpages;
1507 gtk_gs_goto_page(GtkGS * gs, gint page)
1509 g_return_val_if_fail(gs != NULL, FALSE);
1510 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1512 if(!gs->gs_filename) {
1516 /* range checking... */
1520 if(gs->structured_doc && gs->doc) {
1521 if(page >= gs->doc->numpages)
1522 page = gs->doc->numpages - 1;
1524 if(page == gs->current_page && !gs->changed)
1527 gs->current_page = page;
1529 if(gs->doc->pages[page].orientation != NONE &&
1530 !gs->override_orientation &&
1531 gs->doc->pages[page].orientation != gs->real_orientation) {
1532 gs->real_orientation = gs->doc->pages[page].orientation;
1536 gtk_gs_set_page_size(gs, -1, page);
1538 gs->changed = FALSE;
1540 if(is_interpreter_ready(gs)) {
1541 gtk_gs_next_page(gs);
1544 gtk_gs_enable_interpreter(gs);
1545 send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1546 send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1549 send_ps(gs, gs->doc->pages[gs->current_page].begin,
1550 gs->doc->pages[gs->current_page].len, FALSE);
1553 /* Unstructured document */
1554 /* In the case of non structured documents,
1555 GS read the PS from the actual file (via command
1556 line. Hence, ggv only send a signal next page.
1557 If ghostview is not running it is usually because
1558 the last page of the file was displayed. In that
1559 case, ggv restarts GS again and the first page is displayed.
1561 if(page == gs->current_page && !gs->changed)
1564 if(!is_interpreter_ready(gs))
1565 gtk_gs_enable_interpreter(gs);
1567 gs->current_page = page;
1569 gtk_gs_next_page(gs);
1575 * set pagesize sets the size from
1576 * if new_pagesize is -1, then it is set to either
1577 * a) the default settings of pageid, if they exist, or if pageid != -1.
1578 * b) the default setting of the document, if it exists.
1579 * c) the default setting of the widget.
1580 * otherwise, the new_pagesize is used as the pagesize
1583 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1589 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1591 g_return_val_if_fail(gs != NULL, FALSE);
1592 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1594 if(new_pagesize == -1) {
1595 if(gs->default_size > 0)
1596 new_pagesize = gs->default_size;
1597 if(!gs->override_size && gs->doc) {
1598 /* If we have a document:
1599 We use -- the page size (if specified)
1600 or the doc. size (if specified)
1601 or the page bbox (if specified)
1604 if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1605 (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1606 new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1608 else if(gs->doc->default_page_size != NULL) {
1609 new_pagesize = gs->doc->default_page_size - gs->doc->size;
1611 else if((pageid >= 0) &&
1612 (gs->doc->numpages > pageid) &&
1614 (gs->doc->pages[pageid].boundingbox[URX] >
1615 gs->doc->pages[pageid].boundingbox[LLX]) &&
1616 (gs->doc->pages[pageid].boundingbox[URY] >
1617 gs->doc->pages[pageid].boundingbox[LLY])) {
1620 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1621 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1627 /* Compute bounding box */
1628 if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) { /* epsf or bbox */
1631 (gs->doc->pages[pageid].boundingbox[URX] >
1632 gs->doc->pages[pageid].boundingbox[LLX])
1633 && (gs->doc->pages[pageid].boundingbox[URY] >
1634 gs->doc->pages[pageid].boundingbox[LLY])) {
1636 new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1637 new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1638 new_urx = gs->doc->pages[pageid].boundingbox[URX];
1639 new_ury = gs->doc->pages[pageid].boundingbox[URY];
1641 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1642 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1644 new_llx = gs->doc->boundingbox[LLX];
1645 new_lly = gs->doc->boundingbox[LLY];
1646 new_urx = gs->doc->boundingbox[URX];
1647 new_ury = gs->doc->boundingbox[URY];
1651 if(new_pagesize < 0)
1652 new_pagesize = gs->default_size;
1653 new_llx = new_lly = 0;
1654 if(gs->doc && !gs->override_size && gs->doc->size &&
1655 (new_pagesize < gs->doc->numsizes)) {
1656 new_urx = gs->doc->size[new_pagesize].width;
1657 new_ury = gs->doc->size[new_pagesize].height;
1660 new_urx = papersizes[new_pagesize].width;
1661 new_ury = papersizes[new_pagesize].height;
1665 if(new_urx <= new_llx)
1666 new_urx = papersizes[12].width;
1667 if(new_ury <= new_lly)
1668 new_ury = papersizes[12].height;
1670 /* If bounding box changed, setup for new size. */
1671 /* gtk_gs_disable_interpreter (gs); */
1672 if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1673 (new_urx != gs->urx) || (new_ury != gs->ury)) {
1690 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1692 gint iOldOrientation;
1694 g_return_if_fail(gs != NULL);
1695 g_return_if_fail(GTK_IS_GS(gs));
1697 iOldOrientation = gtk_gs_get_orientation(gs);
1699 gs->override_orientation = bNewOverride;
1701 /* If the current orientation is different from the
1702 new orientation then redisplay */
1703 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1710 gtk_gs_get_override_orientation(GtkGS * gs)
1712 g_return_val_if_fail(gs != NULL, FALSE);
1713 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1715 return gs->override_orientation;
1719 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1721 g_return_if_fail(gs != NULL);
1722 g_return_if_fail(GTK_IS_GS(gs));
1724 if(f != gs->override_size) {
1725 gs->override_size = f;
1727 gtk_gs_set_page_size(gs, -1, gs->current_page);
1733 gtk_gs_get_override_size(GtkGS * gs)
1735 g_return_val_if_fail(gs != NULL, FALSE);
1736 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1738 return gs->override_size;
1742 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1744 g_return_if_fail(gs != NULL);
1745 g_return_if_fail(GTK_IS_GS(gs));
1747 switch (gs->zoom_mode) {
1748 case GTK_GS_ZOOM_FIT_WIDTH:
1749 zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1751 case GTK_GS_ZOOM_FIT_PAGE:
1752 zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1754 case GTK_GS_ZOOM_ABSOLUTE:
1759 if(fabs(gs->zoom_factor - zoom) > 0.001) {
1760 gs->zoom_factor = zoom;
1765 gtk_gs_goto_page(gs, gs->current_page);
1769 gtk_gs_get_zoom(GtkGS * gs)
1771 g_return_val_if_fail(gs != NULL, 0.0);
1772 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1774 return gs->zoom_factor;
1778 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1782 guint avail_w, avail_h;
1784 g_return_val_if_fail(gs != NULL, 0.0);
1785 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1787 avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1788 avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1790 new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1792 new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1794 new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1801 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1803 gint iOldOrientation;
1805 g_return_val_if_fail(gs != NULL, FALSE);
1806 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1807 g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1808 (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1809 (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1810 (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1812 iOldOrientation = gtk_gs_get_orientation(gs);
1813 gs->fallback_orientation = orientation;
1815 /* We are setting the fallback orientation */
1816 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1826 gtk_gs_get_default_orientation(GtkGS * gs)
1828 g_return_val_if_fail(gs != NULL, -1);
1829 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1831 return gs->fallback_orientation;
1835 gtk_gs_get_orientation(GtkGS * gs)
1837 g_return_val_if_fail(gs != NULL, -1);
1838 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1841 if(gs->structured_doc) {
1842 if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1843 GTK_GS_ORIENTATION_NONE)
1844 gs->real_orientation =
1845 gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1847 gs->real_orientation = gs->doc->default_page_orientation;
1850 if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1851 gs->real_orientation = gs->doc->orientation;
1854 if(gs->override_orientation ||
1855 gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1856 return gs->fallback_orientation;
1858 return gs->real_orientation;
1862 gtk_gs_set_default_size(GtkGS * gs, gint size)
1864 g_return_if_fail(gs != NULL);
1865 g_return_if_fail(GTK_IS_GS(gs));
1867 gs->default_size = size;
1868 gtk_gs_set_page_size(gs, -1, gs->current_page);
1872 gtk_gs_get_default_size(GtkGS * gs)
1874 g_return_val_if_fail(gs != NULL, -1);
1875 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1877 return gs->default_size;
1881 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
1883 g_return_if_fail(gs != NULL);
1884 g_return_if_fail(GTK_IS_GS(gs));
1886 if(gs->respect_eof == f)
1889 gs->respect_eof = f;
1890 gtk_gs_set_page_size(gs, -1, gs->current_page);
1894 gtk_gs_get_respect_eof(GtkGS * gs)
1896 g_return_val_if_fail(gs != NULL, -1);
1897 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1899 return gs->respect_eof;
1903 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
1905 g_return_if_fail(gs != NULL);
1906 g_return_if_fail(GTK_IS_GS(gs));
1908 if(gs->antialiased == f)
1911 gs->antialiased = f;
1913 start_interpreter(gs);
1914 gtk_gs_goto_page(gs, gs->current_page);
1918 gtk_gs_get_antialiasing(GtkGS * gs)
1920 g_return_val_if_fail(gs != NULL, -1);
1921 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1923 return gs->antialiased;
1927 gtk_gs_get_document_title(GtkGS * gs)
1929 g_return_val_if_fail(gs != NULL, NULL);
1930 g_return_val_if_fail(GTK_IS_GS(gs), NULL);
1932 if(gs->doc && gs->doc->title)
1933 return gs->doc->title;
1939 gtk_gs_get_document_numpages(GtkGS * widget)
1941 g_return_val_if_fail(widget != NULL, 0);
1942 g_return_val_if_fail(GTK_IS_GS(widget), 0);
1945 return widget->doc->numpages;
1951 gtk_gs_get_document_page_label(GtkGS * widget, int page)
1953 g_return_val_if_fail(widget != NULL, NULL);
1954 g_return_val_if_fail(GTK_IS_GS(widget), NULL);
1956 if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
1957 return widget->doc->pages[page - 1].label;
1963 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
1967 while(size[idx].name != NULL) {
1968 if(strcmp(size[idx].name, string) == 0)
1977 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
1981 gboolean free_pages = FALSE;
1984 if(!gs->structured_doc) {
1988 if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
1990 doc = g_new(gchar, sb.st_size);
1993 f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
1994 if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
2003 int i, n = gtk_gs_get_page_count(gs);
2004 pages = g_new0(gint, n);
2005 for(i = 0; i < n; i++)
2011 sink = gtk_gs_doc_sink_new();
2013 if(GTK_GS_IS_PDF(gs)) {
2014 gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2018 if((tmpfd = mkstemp(tmpn)) < 0) {
2023 fname = g_shell_quote (gs->gs_filename_unc ?
2024 gs->gs_filename_unc : gs->gs_filename);
2025 cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2027 if((system(cmd) == 0) && file_readable(tmpn)) {
2029 tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2030 if(NULL != tmp_gs) {
2031 if(GTK_GS(tmp_gs)->loaded)
2032 pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2033 g_object_unref(tmp_gs);
2040 /* Use uncompressed file if necessary */
2041 pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2045 doc = gtk_gs_doc_sink_get_buffer(sink);
2046 gtk_gs_doc_sink_free(sink);
2051 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2053 if(zoom_mode != gs->zoom_mode) {
2054 gs->zoom_mode = zoom_mode;
2055 gtk_gs_set_zoom(gs, 1.0);
2057 gtk_gs_goto_page(gs, gs->current_page);
2061 gtk_gs_get_zoom_mode(GtkGS * gs)
2063 return gs->zoom_mode;
2067 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2069 gs->avail_w = avail_w;
2070 gs->avail_h = avail_h;
2071 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2072 gtk_gs_set_zoom(gs, 0.0);
2077 ps_document_load (EvDocument *document,
2084 filename = g_filename_from_uri (uri, NULL, error);
2088 result = gtk_gs_load (GTK_GS (document), filename);
2096 ps_document_get_n_pages (EvDocument *document)
2098 return gtk_gs_get_page_count (GTK_GS (document));
2102 ps_document_set_page (EvDocument *document,
2105 gtk_gs_goto_page (GTK_GS (document), page);
2109 ps_document_get_page (EvDocument *document)
2111 return gtk_gs_get_current_page (GTK_GS (document));
2115 gtk_gs_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
2117 GtkGS *gs = (GtkGS *) data;
2119 if(event->type != GDK_CLIENT_EVENT)
2122 if (event->client.message_type == gs_class->page_atom) {
2124 ev_document_changed (EV_DOCUMENT (gs));
2131 ps_document_set_target (EvDocument *document,
2132 GdkDrawable *target)
2134 GtkGS *gs = GTK_GS (document);
2138 gs->pstarget = target;
2141 gdk_window_get_user_data (gs->pstarget, &data);
2142 g_return_if_fail (GTK_IS_WIDGET (data));
2144 widget = GTK_WIDGET (data);
2145 g_signal_connect (widget, "event",
2146 G_CALLBACK (gtk_gs_widget_event),
2150 gtk_gs_goto_page (gs, gs->current_page);
2154 ps_document_set_scale (EvDocument *document,
2157 gtk_gs_set_zoom (GTK_GS (document), scale);
2161 ps_document_set_page_offset (EvDocument *document,
2168 ps_document_get_page_size (EvDocument *document,
2172 GtkGS *gs = GTK_GS (document);
2179 *height = gs->height;
2184 ps_document_render (EvDocument *document,
2190 GtkGS *gs = GTK_GS (document);
2193 if (gs->pstarget == NULL ||
2194 gs->bpixmap == NULL) {
2198 gc = gdk_gc_new (gs->pstarget);
2200 gdk_draw_drawable (gs->pstarget, gc,
2204 clip_width, clip_height);
2206 g_object_unref (gc);
2210 ps_document_document_iface_init (EvDocumentIface *iface)
2212 iface->load = ps_document_load;
2213 iface->get_n_pages = ps_document_get_n_pages;
2214 iface->set_page = ps_document_set_page;
2215 iface->get_page = ps_document_get_page;
2216 iface->set_scale = ps_document_set_scale;
2217 iface->set_target = ps_document_set_target;
2218 iface->set_page_offset = ps_document_set_page_offset;
2219 iface->get_page_size = ps_document_get_page_size;
2220 iface->render = ps_document_render;