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>
137 # include <gdk/gdkx.h>
138 # include <X11/extensions/Xinerama.h>
139 #endif /* HAVE_XINERAMA */
140 #include <X11/Intrinsic.h>
145 #include <sys/stat.h>
146 #include <sys/types.h>
147 #include <sys/wait.h>
151 #include "ev-document.h"
153 #include "ggvutils.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;
931 * Decompress gs->gs_filename if necessary
932 * Set gs->filename_unc to the name of the uncompressed file or NULL.
933 * Error reporting via signal 'interpreter_message'
934 * Return name of input file to use or NULL on error..
937 check_filecompressed(GtkGS * gs)
941 gchar *filename, *filename_unc, *filename_err, *cmdline;
947 if((file = fopen(gs->gs_filename, "r"))
948 && (fread(buf, sizeof(gchar), 3, file) == 3)) {
949 if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
950 /* file is gzipped or compressed */
951 cmd = gtk_gs_defaults_get_ungzip_cmd();
953 else if(strncmp(buf, "BZh", 3) == 0) {
954 /* file is compressed with bzip2 */
955 cmd = gtk_gs_defaults_get_unbzip2_cmd();
962 return gs->gs_filename;
964 /* do the decompression */
965 filename = g_shell_quote(gs->gs_filename);
966 filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
967 if((fd = mkstemp(filename_unc)) < 0) {
968 g_free(filename_unc);
973 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
974 if((fd = mkstemp(filename_err)) < 0) {
975 g_free(filename_err);
976 g_free(filename_unc);
981 cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
982 filename, filename_unc, filename_err);
983 if((system(cmdline) == 0)
984 && ggv_file_readable(filename_unc)
985 && (ggv_file_length(filename_err) == 0)) {
986 /* sucessfully uncompressed file */
987 gs->gs_filename_unc = filename_unc;
991 g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
993 gtk_gs_emit_error_msg(gs, buf);
994 if(ggv_file_length(filename_err) > 0) {
996 if((err = fopen(filename_err, "r"))) {
997 /* print file to message window */
998 while(fgets(buf, 1024, err))
999 gtk_gs_emit_error_msg(gs, buf);
1003 unlink(filename_unc);
1004 g_free(filename_unc);
1005 filename_unc = NULL;
1007 unlink(filename_err);
1008 g_free(filename_err);
1011 return filename_unc;
1015 * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1016 * pdf file if necessary.
1017 * Set gs->filename_dsc to the name of the dsc file or NULL.
1018 * Error reporting via signal 'interpreter_message'.
1021 check_pdf(GtkGS * gs)
1024 gchar buf[1024], *filename;
1027 /* use uncompressed file as input if necessary */
1028 filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1030 if((file = fopen(filename, "r"))
1031 && (fread(buf, sizeof(char), 5, file) == 5)
1032 && (strncmp(buf, "%PDF-", 5) == 0)) {
1033 /* we found a PDF file */
1034 gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1035 filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1036 if((fd = mkstemp(filename_dsc)) < 0) {
1040 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1041 if((fd = mkstemp(filename_err)) < 0) {
1042 g_free(filename_dsc);
1046 fname = g_shell_quote(filename);
1047 cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1049 /* this command (sometimes?) prints error messages to stdout! */
1050 cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1053 if((system(cmdline) == 0) && ggv_file_readable(filename_dsc)) {
1056 filename = gs->gs_filename_dsc = filename_dsc;
1058 if(ggv_file_length(filename_err) > 0) {
1059 gchar *err_msg = " ";
1064 if((err = fopen(filename_err, "r"))) {
1066 /* print the content of the file to a message box */
1067 while(fgets(buf, 1024, err))
1068 err_msg = g_strconcat(err_msg, buf, NULL);
1070 /* FIXME The dialog is not yet set to modal, difficult to
1071 * get the parent of the dialog box here
1074 dialog = gtk_message_dialog_new(NULL,
1076 GTK_MESSAGE_WARNING,
1078 ("There was an error while scaning the file: %s \n%s"),
1079 gs->gs_filename, err_msg);
1081 gdk_color_parse("white", &color);
1082 gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1084 g_signal_connect(G_OBJECT(dialog), "response",
1085 G_CALLBACK(gtk_widget_destroy), NULL);
1087 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1088 gtk_widget_show(dialog);
1096 g_snprintf(buf, 1024,
1097 _("Error while converting pdf file %s:\n"), filename);
1098 gtk_gs_emit_error_msg(gs, buf);
1100 if(ggv_file_length(filename_err) > 0) {
1102 if((err = fopen(filename_err, "r"))) {
1103 /* print file to message window */
1104 while(fgets(buf, 1024, err))
1105 gtk_gs_emit_error_msg(gs, buf);
1108 unlink(filename_dsc);
1109 g_free(filename_dsc);
1112 unlink(filename_err);
1113 g_free(filename_err);
1121 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1122 /* never mind this patch: a properly working X server should take care of
1123 calculating the proper values. */
1127 # ifndef HAVE_XINERAMA
1128 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1131 dpy = (Display *) GDK_DISPLAY();
1132 if(XineramaIsActive(dpy)) {
1134 XineramaScreenInfo *head_info;
1135 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1136 /* fake it with dimensions of the first head for now */
1137 return 25.4 * head_info[0].width / gdk_screen_width_mm();
1140 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1149 # ifndef HAVE_XINERAMA
1150 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1153 dpy = (Display *) GDK_DISPLAY();
1154 if(XineramaIsActive(dpy)) {
1156 XineramaScreenInfo *head_info;
1157 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1158 /* fake it with dimensions of the first head for now */
1159 return 25.4 * head_info[0].height / gdk_screen_height_mm();
1162 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1171 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1177 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1179 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1181 /* Compute new size of window, sets xdpi and ydpi if necessary.
1182 * returns True if new window size is different */
1184 compute_size(GtkGS * gs)
1186 guint new_width = 1;
1187 guint new_height = 1;
1188 gboolean change = FALSE;
1191 /* width and height can be changed, calculate window size according */
1192 /* to xpdi and ydpi */
1193 orientation = gtk_gs_get_orientation(gs);
1195 switch (orientation) {
1196 case GTK_GS_ORIENTATION_PORTRAIT:
1197 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1198 new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1199 new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1201 case GTK_GS_ORIENTATION_LANDSCAPE:
1202 case GTK_GS_ORIENTATION_SEASCAPE:
1203 new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1204 new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1208 change = (new_width != gs->width * gs->zoom_factor)
1209 || (new_height != gs->height * gs->zoom_factor);
1210 gs->width = (gint) (new_width * gs->zoom_factor);
1211 gs->height = (gint) (new_height * gs->zoom_factor);
1217 gtk_gs_enable_interpreter(GtkGS * gs)
1219 g_return_val_if_fail(gs != NULL, FALSE);
1220 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1222 if(!gs->gs_filename)
1225 gs->disable_start = FALSE;
1227 return start_interpreter(gs);
1230 /* publicly accessible functions */
1233 gtk_gs_get_type(void)
1235 static GType gs_type = 0;
1237 GTypeInfo gs_info = {
1239 (GBaseInitFunc) NULL,
1240 (GBaseFinalizeFunc) NULL,
1241 (GClassInitFunc) gtk_gs_class_init,
1242 (GClassFinalizeFunc) NULL,
1243 NULL, /* class_data */
1245 0, /* n_preallocs */
1246 (GInstanceInitFunc) gtk_gs_init
1249 static const GInterfaceInfo document_info =
1251 (GInterfaceInitFunc) ps_document_document_iface_init,
1256 gs_type = g_type_register_static(G_TYPE_OBJECT,
1257 "GtkGS", &gs_info, 0);
1259 g_type_add_interface_static (gs_type,
1269 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1273 gs = g_object_new(GTK_GS_TYPE, NULL);
1280 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1282 GObject *gs = gtk_gs_new(hadj, vadj);
1283 gtk_gs_load(GTK_GS(gs), fname);
1288 gtk_gs_reload(GtkGS * gs)
1293 if(!gs->gs_filename)
1296 page = gtk_gs_get_current_page(gs);
1297 fname = g_strdup(gs->gs_filename);
1298 gtk_gs_load(gs, fname);
1299 gtk_gs_goto_page(gs, page);
1305 * Show error message -> send signal "interpreter_message"
1308 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1310 g_signal_emit (G_OBJECT(gs),
1311 gtk_gs_signals[INTERPRETER_MESSAGE], 0, g_strdup(msg));
1315 gtk_gs_disable_interpreter(GtkGS * gs)
1317 g_return_if_fail(gs != NULL);
1318 g_return_if_fail(GTK_IS_GS(gs));
1320 gs->disable_start = TRUE;
1322 stop_interpreter(gs);
1326 gtk_gs_load(GtkGS * gs, const gchar * fname)
1328 g_return_val_if_fail(gs != NULL, FALSE);
1329 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1331 /* clean up previous document */
1339 /* prepare this document */
1341 /* default values: no dsc information available */
1342 gs->structured_doc = FALSE;
1343 gs->send_filename_to_gs = TRUE;
1344 gs->current_page = -2;
1347 /* an absolute path */
1348 gs->gs_filename = g_strdup(fname);
1351 /* path relative to our cwd: make it absolute */
1352 gchar *cwd = g_get_current_dir();
1353 gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1357 if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1358 gs->send_filename_to_gs = FALSE;
1362 * We need to make sure that the file is loadable/exists!
1363 * otherwise we want to exit without loading new stuff...
1365 gchar *filename = NULL;
1367 if(!ggv_file_readable(fname)) {
1369 g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1370 gtk_gs_emit_error_msg(gs, buf);
1371 gs->gs_status = _("File is not readable.");
1374 filename = check_filecompressed(gs);
1376 filename = check_pdf(gs);
1379 if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1384 /* we grab the vital statistics!!! */
1385 gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1387 if(gs->doc == NULL) {
1388 /* File does not seem to be a Postscript one */
1390 g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1391 gtk_gs_emit_error_msg(gs, buf);
1393 gs->gs_status = _("The file is not a PostScript document.");
1397 if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1398 (gs->doc->epsf && gs->doc->numpages > 1)) {
1399 gs->structured_doc = TRUE;
1400 gs->send_filename_to_gs = FALSE;
1403 /* We have to set up the orientation of the document */
1406 /* orientation can only be portrait, and landscape or none.
1407 This is the document default. A document can have
1408 pages in landscape and some in portrait */
1409 if(gs->override_orientation) {
1410 /* If the orientation should be override...
1411 then gs->orientation has already the correct
1412 value (it was set when the widget was created */
1417 /* Otherwise, set the proper orientation for the doc */
1418 gs->real_orientation = gs->doc->orientation;
1421 gtk_gs_set_page_size(gs, -1, gs->current_page);
1424 gs->gs_status = _("Document loaded.");
1431 gtk_gs_next_page(GtkGS * gs)
1435 g_return_val_if_fail(gs != NULL, FALSE);
1436 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1438 if(gs->interpreter_pid == 0) { /* no interpreter active */
1442 if(gs->busy) { /* interpreter is busy */
1448 event.xclient.type = ClientMessage;
1449 event.xclient.display = gdk_display;
1450 event.xclient.window = gs->message_window;
1451 event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1452 event.xclient.format = 32;
1454 gdk_error_trap_push();
1455 XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1457 gdk_error_trap_pop();
1463 gtk_gs_get_current_page(GtkGS * gs)
1465 g_return_val_if_fail(gs != NULL, -1);
1466 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1468 return gs->current_page;
1472 gtk_gs_get_page_count(GtkGS * gs)
1474 if(!gs->gs_filename)
1478 if(gs->structured_doc)
1479 return gs->doc->numpages;
1488 gtk_gs_goto_page(GtkGS * gs, gint page)
1490 g_return_val_if_fail(gs != NULL, FALSE);
1491 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1493 if(!gs->gs_filename) {
1497 /* range checking... */
1501 if(gs->structured_doc && gs->doc) {
1502 if(page >= gs->doc->numpages)
1503 page = gs->doc->numpages - 1;
1505 if(page == gs->current_page && !gs->changed)
1508 gs->current_page = page;
1510 if(gs->doc->pages[page].orientation != NONE &&
1511 !gs->override_orientation &&
1512 gs->doc->pages[page].orientation != gs->real_orientation) {
1513 gs->real_orientation = gs->doc->pages[page].orientation;
1517 gtk_gs_set_page_size(gs, -1, page);
1519 gs->changed = FALSE;
1521 if(is_interpreter_ready(gs)) {
1522 gtk_gs_next_page(gs);
1525 gtk_gs_enable_interpreter(gs);
1526 send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1527 send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1530 send_ps(gs, gs->doc->pages[gs->current_page].begin,
1531 gs->doc->pages[gs->current_page].len, FALSE);
1534 /* Unstructured document */
1535 /* In the case of non structured documents,
1536 GS read the PS from the actual file (via command
1537 line. Hence, ggv only send a signal next page.
1538 If ghostview is not running it is usually because
1539 the last page of the file was displayed. In that
1540 case, ggv restarts GS again and the first page is displayed.
1542 if(page == gs->current_page && !gs->changed)
1545 if(!is_interpreter_ready(gs))
1546 gtk_gs_enable_interpreter(gs);
1548 gs->current_page = page;
1550 gtk_gs_next_page(gs);
1556 * set pagesize sets the size from
1557 * if new_pagesize is -1, then it is set to either
1558 * a) the default settings of pageid, if they exist, or if pageid != -1.
1559 * b) the default setting of the document, if it exists.
1560 * c) the default setting of the widget.
1561 * otherwise, the new_pagesize is used as the pagesize
1564 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1570 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1572 g_return_val_if_fail(gs != NULL, FALSE);
1573 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1575 if(new_pagesize == -1) {
1576 if(gs->default_size > 0)
1577 new_pagesize = gs->default_size;
1578 if(!gs->override_size && gs->doc) {
1579 /* If we have a document:
1580 We use -- the page size (if specified)
1581 or the doc. size (if specified)
1582 or the page bbox (if specified)
1585 if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1586 (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1587 new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1589 else if(gs->doc->default_page_size != NULL) {
1590 new_pagesize = gs->doc->default_page_size - gs->doc->size;
1592 else if((pageid >= 0) &&
1593 (gs->doc->numpages > pageid) &&
1595 (gs->doc->pages[pageid].boundingbox[URX] >
1596 gs->doc->pages[pageid].boundingbox[LLX]) &&
1597 (gs->doc->pages[pageid].boundingbox[URY] >
1598 gs->doc->pages[pageid].boundingbox[LLY])) {
1601 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1602 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1608 /* Compute bounding box */
1609 if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) { /* epsf or bbox */
1612 (gs->doc->pages[pageid].boundingbox[URX] >
1613 gs->doc->pages[pageid].boundingbox[LLX])
1614 && (gs->doc->pages[pageid].boundingbox[URY] >
1615 gs->doc->pages[pageid].boundingbox[LLY])) {
1617 new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1618 new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1619 new_urx = gs->doc->pages[pageid].boundingbox[URX];
1620 new_ury = gs->doc->pages[pageid].boundingbox[URY];
1622 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1623 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1625 new_llx = gs->doc->boundingbox[LLX];
1626 new_lly = gs->doc->boundingbox[LLY];
1627 new_urx = gs->doc->boundingbox[URX];
1628 new_ury = gs->doc->boundingbox[URY];
1632 if(new_pagesize < 0)
1633 new_pagesize = gs->default_size;
1634 new_llx = new_lly = 0;
1635 if(gs->doc && !gs->override_size && gs->doc->size &&
1636 (new_pagesize < gs->doc->numsizes)) {
1637 new_urx = gs->doc->size[new_pagesize].width;
1638 new_ury = gs->doc->size[new_pagesize].height;
1641 new_urx = papersizes[new_pagesize].width;
1642 new_ury = papersizes[new_pagesize].height;
1646 if(new_urx <= new_llx)
1647 new_urx = papersizes[12].width;
1648 if(new_ury <= new_lly)
1649 new_ury = papersizes[12].height;
1651 /* If bounding box changed, setup for new size. */
1652 /* gtk_gs_disable_interpreter (gs); */
1653 if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1654 (new_urx != gs->urx) || (new_ury != gs->ury)) {
1671 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1673 gint iOldOrientation;
1675 g_return_if_fail(gs != NULL);
1676 g_return_if_fail(GTK_IS_GS(gs));
1678 iOldOrientation = gtk_gs_get_orientation(gs);
1680 gs->override_orientation = bNewOverride;
1682 /* If the current orientation is different from the
1683 new orientation then redisplay */
1684 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1691 gtk_gs_get_override_orientation(GtkGS * gs)
1693 g_return_val_if_fail(gs != NULL, FALSE);
1694 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1696 return gs->override_orientation;
1700 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1702 g_return_if_fail(gs != NULL);
1703 g_return_if_fail(GTK_IS_GS(gs));
1705 if(f != gs->override_size) {
1706 gs->override_size = f;
1708 gtk_gs_set_page_size(gs, -1, gs->current_page);
1714 gtk_gs_get_override_size(GtkGS * gs)
1716 g_return_val_if_fail(gs != NULL, FALSE);
1717 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1719 return gs->override_size;
1723 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1725 g_return_if_fail(gs != NULL);
1726 g_return_if_fail(GTK_IS_GS(gs));
1728 switch (gs->zoom_mode) {
1729 case GTK_GS_ZOOM_FIT_WIDTH:
1730 zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1732 case GTK_GS_ZOOM_FIT_PAGE:
1733 zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1735 case GTK_GS_ZOOM_ABSOLUTE:
1739 if(zoom < ggv_zoom_levels[0])
1740 zoom = ggv_zoom_levels[0];
1741 else if(zoom > ggv_zoom_levels[ggv_max_zoom_levels])
1742 zoom = ggv_zoom_levels[ggv_max_zoom_levels];
1743 if(fabs(gs->zoom_factor - zoom) > 0.001) {
1744 gs->zoom_factor = zoom;
1751 gtk_gs_get_zoom(GtkGS * gs)
1753 g_return_val_if_fail(gs != NULL, 0.0);
1754 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1756 return gs->zoom_factor;
1760 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1764 guint avail_w, avail_h;
1766 g_return_val_if_fail(gs != NULL, 0.0);
1767 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1769 avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1770 avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1772 new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1774 new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1776 new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1783 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1785 gint iOldOrientation;
1787 g_return_val_if_fail(gs != NULL, FALSE);
1788 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1789 g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1790 (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1791 (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1792 (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1794 iOldOrientation = gtk_gs_get_orientation(gs);
1795 gs->fallback_orientation = orientation;
1797 /* We are setting the fallback orientation */
1798 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1808 gtk_gs_get_default_orientation(GtkGS * gs)
1810 g_return_val_if_fail(gs != NULL, -1);
1811 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1813 return gs->fallback_orientation;
1817 gtk_gs_get_orientation(GtkGS * gs)
1819 g_return_val_if_fail(gs != NULL, -1);
1820 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1823 if(gs->structured_doc) {
1824 if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1825 GTK_GS_ORIENTATION_NONE)
1826 gs->real_orientation =
1827 gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1829 gs->real_orientation = gs->doc->default_page_orientation;
1832 if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1833 gs->real_orientation = gs->doc->orientation;
1836 if(gs->override_orientation ||
1837 gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1838 return gs->fallback_orientation;
1840 return gs->real_orientation;
1844 gtk_gs_set_default_size(GtkGS * gs, gint size)
1846 g_return_if_fail(gs != NULL);
1847 g_return_if_fail(GTK_IS_GS(gs));
1849 gs->default_size = size;
1850 gtk_gs_set_page_size(gs, -1, gs->current_page);
1854 gtk_gs_get_default_size(GtkGS * gs)
1856 g_return_val_if_fail(gs != NULL, -1);
1857 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1859 return gs->default_size;
1863 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
1865 g_return_if_fail(gs != NULL);
1866 g_return_if_fail(GTK_IS_GS(gs));
1868 if(gs->respect_eof == f)
1871 gs->respect_eof = f;
1872 gtk_gs_set_page_size(gs, -1, gs->current_page);
1876 gtk_gs_get_respect_eof(GtkGS * gs)
1878 g_return_val_if_fail(gs != NULL, -1);
1879 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1881 return gs->respect_eof;
1885 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
1887 g_return_if_fail(gs != NULL);
1888 g_return_if_fail(GTK_IS_GS(gs));
1890 if(gs->antialiased == f)
1893 gs->antialiased = f;
1895 start_interpreter(gs);
1896 gtk_gs_goto_page(gs, gs->current_page);
1900 gtk_gs_get_antialiasing(GtkGS * gs)
1902 g_return_val_if_fail(gs != NULL, -1);
1903 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1905 return gs->antialiased;
1909 gtk_gs_get_document_title(GtkGS * gs)
1911 g_return_val_if_fail(gs != NULL, NULL);
1912 g_return_val_if_fail(GTK_IS_GS(gs), NULL);
1914 if(gs->doc && gs->doc->title)
1915 return gs->doc->title;
1921 gtk_gs_get_document_numpages(GtkGS * widget)
1923 g_return_val_if_fail(widget != NULL, 0);
1924 g_return_val_if_fail(GTK_IS_GS(widget), 0);
1927 return widget->doc->numpages;
1933 gtk_gs_get_document_page_label(GtkGS * widget, int page)
1935 g_return_val_if_fail(widget != NULL, NULL);
1936 g_return_val_if_fail(GTK_IS_GS(widget), NULL);
1938 if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
1939 return widget->doc->pages[page - 1].label;
1945 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
1949 while(size[idx].name != NULL) {
1950 if(strcmp(size[idx].name, string) == 0)
1959 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
1963 gboolean free_pages = FALSE;
1966 if(!gs->structured_doc) {
1970 if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
1972 doc = g_new(gchar, sb.st_size);
1975 f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
1976 if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
1985 int i, n = gtk_gs_get_page_count(gs);
1986 pages = g_new0(gint, n);
1987 for(i = 0; i < n; i++)
1993 sink = gtk_gs_doc_sink_new();
1995 if(GTK_GS_IS_PDF(gs)) {
1996 gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2000 if((tmpfd = mkstemp(tmpn)) < 0) {
2005 fname = g_shell_quote (gs->gs_filename_unc ?
2006 gs->gs_filename_unc : gs->gs_filename);
2007 cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2009 if((system(cmd) == 0) && ggv_file_readable(tmpn)) {
2011 tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2012 if(NULL != tmp_gs) {
2013 if(GTK_GS(tmp_gs)->loaded)
2014 pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2015 g_object_unref(tmp_gs);
2022 /* Use uncompressed file if necessary */
2023 pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2027 doc = gtk_gs_doc_sink_get_buffer(sink);
2028 gtk_gs_doc_sink_free(sink);
2033 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2035 if(zoom_mode != gs->zoom_mode) {
2036 gs->zoom_mode = zoom_mode;
2037 gtk_gs_set_zoom(gs, 1.0);
2042 gtk_gs_get_zoom_mode(GtkGS * gs)
2044 return gs->zoom_mode;
2048 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2050 gs->avail_w = avail_w;
2051 gs->avail_h = avail_h;
2052 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2053 gtk_gs_set_zoom(gs, 0.0);
2058 ps_document_load (EvDocument *document,
2065 filename = g_filename_from_uri (uri, NULL, error);
2069 result = gtk_gs_load (GTK_GS (document), filename);
2077 ps_document_get_n_pages (EvDocument *document)
2079 return gtk_gs_get_page_count (GTK_GS (document));
2083 ps_document_set_page (EvDocument *document,
2086 gtk_gs_goto_page (GTK_GS (document), page);
2090 ps_document_get_page (EvDocument *document)
2092 return gtk_gs_get_current_page (GTK_GS (document));
2096 gtk_gs_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
2098 GtkGS *gs = (GtkGS *) data;
2100 if(event->type != GDK_CLIENT_EVENT)
2103 if (event->client.message_type == gs_class->page_atom) {
2105 ev_document_changed (EV_DOCUMENT (gs));
2112 ps_document_set_target (EvDocument *document,
2113 GdkDrawable *target)
2115 GtkGS *gs = GTK_GS (document);
2119 gs->pstarget = target;
2122 gdk_window_get_user_data (gs->pstarget, &data);
2123 g_return_if_fail (GTK_IS_WIDGET (data));
2125 widget = GTK_WIDGET (data);
2126 g_signal_connect (widget, "event",
2127 G_CALLBACK (gtk_gs_widget_event),
2131 gtk_gs_goto_page (gs, gs->current_page);
2135 ps_document_set_scale (EvDocument *document,
2138 gtk_gs_set_zoom (GTK_GS (document), scale);
2142 ps_document_set_page_offset (EvDocument *document,
2149 ps_document_get_page_size (EvDocument *document,
2153 GtkGS *gs = GTK_GS (document);
2160 *height = gs->height;
2165 ps_document_render (EvDocument *document,
2171 GtkGS *gs = GTK_GS (document);
2174 if (gs->pstarget == NULL ||
2175 gs->bpixmap == NULL) {
2179 gc = gdk_gc_new (gs->pstarget);
2181 gdk_draw_drawable (gs->pstarget, gc,
2185 clip_width, clip_height);
2187 g_object_unref (gc);
2191 ps_document_document_iface_init (EvDocumentIface *iface)
2193 iface->load = ps_document_load;
2194 iface->get_n_pages = ps_document_get_n_pages;
2195 iface->set_page = ps_document_set_page;
2196 iface->get_page = ps_document_get_page;
2197 iface->set_scale = ps_document_set_scale;
2198 iface->set_target = ps_document_set_target;
2199 iface->set_page_offset = ps_document_set_page_offset;
2200 iface->get_page_size = ps_document_get_page_size;
2201 iface->render = ps_document_render;