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"
154 #include "gsdefaults.h"
160 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
161 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
162 # define O_NONBLOCK O_NDELAY
165 #define GTK_GS_WATCH_INTERVAL 1000
166 #define GTK_GS_WATCH_TIMEOUT 2
168 #define MAX_BUFSIZE 1024
170 enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL };
172 static gboolean broken_pipe = FALSE;
180 /* Forward declarations */
181 static void gtk_gs_init(GtkGS * gs);
182 static void gtk_gs_class_init(GtkGSClass * klass);
183 static void gtk_gs_interpreter_message(GtkGS * gs, gchar * msg,
185 static void gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg);
186 static void gtk_gs_finalize(GObject * object);
187 static void send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close);
188 static void set_up_page(GtkGS * gs);
189 static void close_pipe(int p[2]);
190 static void interpreter_failed(GtkGS * gs);
191 static float compute_xdpi(void);
192 static float compute_ydpi(void);
193 static gboolean compute_size(GtkGS * gs);
194 static void output(gpointer data, gint source, GdkInputCondition condition);
195 static void input(gpointer data, gint source, GdkInputCondition condition);
196 static void stop_interpreter(GtkGS * gs);
197 static gint start_interpreter(GtkGS * gs);
198 gboolean computeSize(void);
199 static void ps_document_document_iface_init (EvDocumentIface *iface);
201 static GObjectClass *parent_class = NULL;
203 static GtkGSClass *gs_class = NULL;
205 static gint gtk_gs_signals[LAST_SIGNAL] = { 0 };
207 /* Static, private functions */
210 ggv_marshaller_VOID__POINTER(GClosure * closure,
211 GValue * return_value,
212 guint n_param_values,
213 const GValue * param_values,
214 gpointer invocation_hint, gpointer marshal_data)
216 typedef void (*GMarshalFunc_VOID__POINTER) (gpointer data1,
217 gpointer arg_1, gpointer data2);
218 register GMarshalFunc_VOID__POINTER callback;
219 register GCClosure *cc = (GCClosure *) closure;
220 register gpointer data1, data2;
222 g_return_if_fail(n_param_values == 2);
224 if(G_CCLOSURE_SWAP_DATA(closure)) {
225 data1 = closure->data;
226 data2 = g_value_peek_pointer(param_values + 0);
229 data1 = g_value_peek_pointer(param_values + 0);
230 data2 = closure->data;
233 (GMarshalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
235 callback(data1, g_value_get_pointer(param_values + 1), data2);
239 ggv_marshaller_VOID__INT(GClosure * closure,
240 GValue * return_value,
241 guint n_param_values,
242 const GValue * param_values,
243 gpointer invocation_hint, gpointer marshal_data)
245 typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
246 gint arg_1, gpointer data2);
247 register GMarshalFunc_VOID__INT callback;
248 register GCClosure *cc = (GCClosure *) closure;
249 register gpointer data1, data2;
251 g_return_if_fail(n_param_values == 2);
253 if(G_CCLOSURE_SWAP_DATA(closure)) {
254 data1 = closure->data;
255 data2 = g_value_peek_pointer(param_values + 0);
258 data1 = g_value_peek_pointer(param_values + 0);
259 data2 = closure->data;
262 (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
264 callback(data1, g_value_get_int(param_values + 1), data2);
268 gtk_gs_init(GtkGS * gs)
272 gs->current_page = -2;
273 gs->disable_start = FALSE;
274 gs->interpreter_pid = -1;
280 gs->gs_scanstyle = 0;
282 gs->gs_filename_dsc = 0;
283 gs->gs_filename_unc = 0;
287 gs->structured_doc = FALSE;
288 gs->reading_from_pipe = FALSE;
289 gs->send_filename_to_gs = FALSE;
294 gs->interpreter_input = -1;
295 gs->interpreter_output = -1;
296 gs->interpreter_err = -1;
297 gs->interpreter_input_id = 0;
298 gs->interpreter_output_id = 0;
299 gs->interpreter_error_id = 0;
302 gs->input_buffer = NULL;
303 gs->input_buffer_ptr = NULL;
305 gs->buffer_bytes_left = 0;
311 gs->xdpi = compute_xdpi();
312 gs->ydpi = compute_ydpi();
316 gs->right_margin = 0;
317 gs->bottom_margin = 0;
319 /* Set user defined defaults */
320 gs->override_orientation = gtk_gs_defaults_get_override_orientation();
321 gs->fallback_orientation = gtk_gs_defaults_get_orientation();
322 gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
323 gs->default_size = gtk_gs_defaults_get_size();
324 gs->antialiased = gtk_gs_defaults_get_antialiased();
325 gs->override_size = gtk_gs_defaults_get_override_size();
326 gs->respect_eof = gtk_gs_defaults_get_respect_eof();
327 gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
329 gs->gs_status = _("No document loaded.");
333 gtk_gs_class_init(GtkGSClass * klass)
335 GObjectClass *object_class;
337 object_class = (GObjectClass *) klass;
338 parent_class = gtk_type_class(gtk_widget_get_type());
341 gtk_gs_signals[INTERPRETER_MESSAGE] = g_signal_new("interpreter_message",
347 interpreter_message),
349 ggv_marshaller_VOID__POINTER,
352 gtk_gs_signals[INTERPRETER_ERROR] =
353 g_signal_new("interpreter_error", G_TYPE_FROM_CLASS(object_class),
354 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkGSClass,
356 NULL, NULL, ggv_marshaller_VOID__INT, G_TYPE_NONE, 1,
359 object_class->finalize = gtk_gs_finalize;
362 klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
363 klass->gs_colors_atom = gdk_atom_intern("GHOSTVIEW_COLORS", FALSE);
364 klass->next_atom = gdk_atom_intern("NEXT", FALSE);
365 klass->page_atom = gdk_atom_intern("PAGE", FALSE);
366 klass->done_atom = gdk_atom_intern("DONE", FALSE);
367 klass->string_atom = gdk_atom_intern("STRING", FALSE);
369 /* a default handler for "interpreter_message" signal */
370 klass->interpreter_message = gtk_gs_interpreter_message;
372 gtk_gs_defaults_load();
375 /* Clean all memory and temporal files */
377 gtk_gs_cleanup(GtkGS * gs)
379 g_return_if_fail(gs != NULL);
380 g_return_if_fail(GTK_IS_GS(gs));
382 stop_interpreter(gs);
385 fclose(gs->gs_psfile);
386 gs->gs_psfile = NULL;
388 if(gs->gs_filename) {
389 g_free(gs->gs_filename);
390 gs->gs_filename = NULL;
396 if(gs->gs_filename_dsc) {
397 unlink(gs->gs_filename_dsc);
398 g_free(gs->gs_filename_dsc);
399 gs->gs_filename_dsc = NULL;
401 if(gs->gs_filename_unc) {
402 unlink(gs->gs_filename_unc);
403 g_free(gs->gs_filename_unc);
404 gs->gs_filename_unc = NULL;
406 gs->current_page = -1;
415 /* free message as it was allocated in output() */
417 gtk_gs_interpreter_message(GtkGS * gs, gchar * msg, gpointer user_data)
419 gdk_pointer_ungrab(GDK_CURRENT_TIME);
420 if(strstr(msg, "Error:")) {
421 gs->gs_status = _("File is not a valid PostScript document.");
423 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", 1, NULL);
429 gtk_gs_finalize(GObject * object)
433 g_return_if_fail(object != NULL);
434 g_return_if_fail(GTK_IS_GS(object));
440 if(gs->input_buffer) {
441 g_free(gs->input_buffer);
442 gs->input_buffer = NULL;
445 (*G_OBJECT_CLASS(parent_class)->finalize) (object);
449 gtk_gs_set_center(GtkGS * gs, gfloat hval, gfloat vval)
454 send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close)
456 struct record_list *ps_new;
458 if(gs->interpreter_input < 0) {
459 g_critical("No pipe to gs: error in send_ps().");
463 ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
464 ps_new->fp = gs->gs_psfile;
465 ps_new->begin = begin;
467 ps_new->seek_needed = TRUE;
468 ps_new->close = close;
471 if(gs->input_buffer == NULL) {
472 gs->input_buffer = g_malloc(MAX_BUFSIZE);
475 if(gs->ps_input == NULL) {
476 gs->input_buffer_ptr = gs->input_buffer;
477 gs->bytes_left = len;
478 gs->buffer_bytes_left = 0;
479 gs->ps_input = ps_new;
480 gs->interpreter_input_id =
481 gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
484 struct record_list *p = gs->ps_input;
485 while(p->next != NULL) {
493 set_up_page(GtkGS * gs)
497 //GdkColormap *colormap;
499 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */
500 GdkColormap *colormap;
506 if (gs->pstarget == NULL)
509 /* Do we have to check if the actual geometry changed? */
511 stop_interpreter(gs);
513 orientation = gtk_gs_get_orientation(gs);
515 if(compute_size(gs)) {
518 /* clear new pixmap (set to white) */
519 fill = gdk_gc_new(gs->pstarget);
521 colormap = gdk_drawable_get_colormap(gs->pstarget);
522 gdk_color_alloc (colormap, &white);
523 gdk_gc_set_foreground(fill, &white);
525 if(gs->width > 0 && gs->height > 0) {
527 gdk_drawable_unref(gs->bpixmap);
531 gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
533 gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
534 0, 0, gs->width, gs->height);
537 gdk_draw_rectangle(gs->pstarget, fill, TRUE,
538 0, 0, gs->width, gs->height);
547 /* gs needs floating point parameters with '.' as decimal point
548 * while some (european) locales use ',' instead, so we set the
549 * locale for this snprintf to "C".
551 savelocale = setlocale(LC_NUMERIC, "C");
554 g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
561 gs->xdpi * gs->zoom_factor,
562 gs->ydpi * gs->zoom_factor,
564 gs->bottom_margin, gs->right_margin, gs->top_margin);
567 setlocale(LC_NUMERIC, savelocale);
569 gdk_property_change(gs->pstarget,
571 gs_class->string_atom,
572 8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
586 is_interpreter_ready(GtkGS * gs)
588 return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
592 interpreter_failed(GtkGS * gs)
594 stop_interpreter(gs);
598 output(gpointer data, gint source, GdkInputCondition condition)
600 char buf[MAX_BUFSIZE + 1], *msg;
602 GtkGS *gs = GTK_GS(data);
604 if(source == gs->interpreter_output) {
605 bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
606 if(bytes == 0) { /* EOF occurred */
607 close(gs->interpreter_output);
608 gs->interpreter_output = -1;
609 gdk_input_remove(gs->interpreter_output_id);
612 else if(bytes == -1) {
614 interpreter_failed(gs);
617 if(gs->interpreter_err == -1) {
618 stop_interpreter(gs);
621 else if(source == gs->interpreter_err) {
622 bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
623 if(bytes == 0) { /* EOF occurred */
624 close(gs->interpreter_err);
625 gs->interpreter_err = -1;
626 gdk_input_remove(gs->interpreter_error_id);
629 else if(bytes == -1) {
631 interpreter_failed(gs);
634 if(gs->interpreter_output == -1) {
635 stop_interpreter(gs);
641 g_signal_emit (G_OBJECT(gs), gtk_gs_signals[INTERPRETER_MESSAGE], 0, msg);
646 input(gpointer data, gint source, GdkInputCondition condition)
648 GtkGS *gs = GTK_GS(data);
650 void (*oldsig) (int);
651 oldsig = signal(SIGPIPE, catchPipe);
654 if(gs->buffer_bytes_left == 0) {
655 /* Get a new section if required */
656 if(gs->ps_input && gs->bytes_left == 0) {
657 struct record_list *ps_old = gs->ps_input;
658 gs->ps_input = ps_old->next;
659 if(ps_old->close && NULL != ps_old->fp)
661 g_free((char *) ps_old);
663 /* Have to seek at the beginning of each section */
664 if(gs->ps_input && gs->ps_input->seek_needed) {
665 fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
666 gs->ps_input->seek_needed = FALSE;
667 gs->bytes_left = gs->ps_input->len;
670 if(gs->bytes_left > MAX_BUFSIZE) {
671 gs->buffer_bytes_left =
672 fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
674 else if(gs->bytes_left > 0) {
675 gs->buffer_bytes_left =
676 fread(gs->input_buffer,
677 sizeof(char), gs->bytes_left, gs->ps_input->fp);
680 gs->buffer_bytes_left = 0;
682 if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
683 interpreter_failed(gs); /* Error occurred */
685 gs->input_buffer_ptr = gs->input_buffer;
686 gs->bytes_left -= gs->buffer_bytes_left;
689 if(gs->buffer_bytes_left > 0) {
690 /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
692 bytes_written = write(gs->interpreter_input,
693 gs->input_buffer_ptr, gs->buffer_bytes_left);
696 gtk_gs_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
698 interpreter_failed(gs);
700 else if(bytes_written == -1) {
701 if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
702 interpreter_failed(gs); /* Something bad happened */
706 gs->buffer_bytes_left -= bytes_written;
707 gs->input_buffer_ptr += bytes_written;
711 while(gs->ps_input && gs->buffer_bytes_left == 0);
713 signal(SIGPIPE, oldsig);
715 if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
716 if(gs->interpreter_input_id != 0) {
717 gdk_input_remove(gs->interpreter_input_id);
718 gs->interpreter_input_id = 0;
724 start_interpreter(GtkGS * gs)
726 int std_in[2] = { -1, -1 }; /* pipe to interp stdin */
727 int std_out[2]; /* pipe from interp stdout */
728 int std_err[2]; /* pipe from interp stderr */
731 #define NUM_GS_ARGS (NUM_ARGS - 20)
732 #define NUM_ALPHA_ARGS 10
734 char *argv[NUM_ARGS], *dir, *gv_env;
735 char **gs_args, **alpha_args = NULL;
741 stop_interpreter(gs);
743 if(gs->disable_start == TRUE)
746 /* set up the args... */
747 gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
748 for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
749 argv[argc] = gs_args[i];
751 if(gs->antialiased) {
752 if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
753 alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
755 alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
756 " ", NUM_ALPHA_ARGS);
757 for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
758 argv[argc] = alpha_args[i];
761 argv[argc++] = "-sDEVICE=x11";
762 argv[argc++] = "-dNOPAUSE";
763 argv[argc++] = "-dQUIET";
764 /* I assume we do _not_ want to change this... (: */
765 argv[argc++] = "-dSAFER";
767 /* set up the pipes */
768 if(gs->send_filename_to_gs) {
769 argv[argc++] = GTK_GS_GET_PS_FILE(gs);
771 argv[argc++] = "quit";
778 if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
779 if(pipe(std_in) == -1) {
780 g_critical("Unable to open pipe to Ghostscript.");
784 if(pipe(std_out) == -1) {
788 if(pipe(std_err) == -1) {
795 gs->interpreter_pid = fork();
796 switch (gs->interpreter_pid) {
812 if(!gs->reading_from_pipe) {
813 if(gs->send_filename_to_gs) {
815 /* just in case gs tries to read from stdin */
816 stdinfd = open("/dev/null", O_RDONLY);
829 gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld",
830 gdk_x11_drawable_get_xid(gs->pstarget),
831 gdk_x11_drawable_get_xid(gs->bpixmap));
834 /* change to directory where the input file is. This helps
835 * with postscript-files which include other files using
837 dir = g_path_get_dirname(gs->gs_filename);
841 execvp(argv[0], argv);
844 g_print("Unable to execute [%s]\n", argv[0]);
848 g_strfreev(alpha_args);
851 default: /* parent */
852 if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
855 /* use non-blocking IO for pipe to ghostscript */
856 result = fcntl(std_in[1], F_GETFL, 0);
857 fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
858 gs->interpreter_input = std_in[1];
861 gs->interpreter_input = -1;
864 gs->interpreter_output = std_out[0];
866 gs->interpreter_err = std_err[0];
867 gs->interpreter_output_id =
868 gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
869 gs->interpreter_error_id =
870 gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
877 stop_interpreter(GtkGS * gs)
879 if(gs->interpreter_pid > 0) {
881 kill(gs->interpreter_pid, SIGTERM);
882 while((wait(&status) == -1) && (errno == EINTR)) ;
883 gs->interpreter_pid = -1;
886 gs->gs_status = _("Interpreter failed.");
887 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", status);
891 if(gs->interpreter_input >= 0) {
892 close(gs->interpreter_input);
893 gs->interpreter_input = -1;
894 if(gs->interpreter_input_id != 0) {
895 gdk_input_remove(gs->interpreter_input_id);
896 gs->interpreter_input_id = 0;
898 while(gs->ps_input) {
899 struct record_list *ps_old = gs->ps_input;
900 gs->ps_input = gs->ps_input->next;
901 if(ps_old->close && NULL != ps_old->fp)
903 g_free((char *) ps_old);
907 if(gs->interpreter_output >= 0) {
908 close(gs->interpreter_output);
909 gs->interpreter_output = -1;
910 if(gs->interpreter_output_id) {
911 gdk_input_remove(gs->interpreter_output_id);
912 gs->interpreter_output_id = 0;
916 if(gs->interpreter_err >= 0) {
917 close(gs->interpreter_err);
918 gs->interpreter_err = -1;
919 if(gs->interpreter_error_id) {
920 gdk_input_remove(gs->interpreter_error_id);
921 gs->interpreter_error_id = 0;
928 /* If file exists and is a regular file then return its length, else -1 */
930 file_length(const gchar * filename)
932 struct stat stat_rec;
934 if(filename && (stat(filename, &stat_rec) == 0)
935 && S_ISREG(stat_rec.st_mode))
936 return stat_rec.st_size;
941 /* Test if file exists, is a regular file and its length is > 0 */
943 file_readable(const char *filename)
945 return (file_length(filename) > 0);
949 * Decompress gs->gs_filename if necessary
950 * Set gs->filename_unc to the name of the uncompressed file or NULL.
951 * Error reporting via signal 'interpreter_message'
952 * Return name of input file to use or NULL on error..
955 check_filecompressed(GtkGS * gs)
959 gchar *filename, *filename_unc, *filename_err, *cmdline;
965 if((file = fopen(gs->gs_filename, "r"))
966 && (fread(buf, sizeof(gchar), 3, file) == 3)) {
967 if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
968 /* file is gzipped or compressed */
969 cmd = gtk_gs_defaults_get_ungzip_cmd();
971 else if(strncmp(buf, "BZh", 3) == 0) {
972 /* file is compressed with bzip2 */
973 cmd = gtk_gs_defaults_get_unbzip2_cmd();
980 return gs->gs_filename;
982 /* do the decompression */
983 filename = g_shell_quote(gs->gs_filename);
984 filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
985 if((fd = mkstemp(filename_unc)) < 0) {
986 g_free(filename_unc);
991 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
992 if((fd = mkstemp(filename_err)) < 0) {
993 g_free(filename_err);
994 g_free(filename_unc);
999 cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1000 filename, filename_unc, filename_err);
1001 if((system(cmdline) == 0)
1002 && file_readable(filename_unc)
1003 && (file_length(filename_err) == 0)) {
1004 /* sucessfully uncompressed file */
1005 gs->gs_filename_unc = filename_unc;
1009 g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1011 gtk_gs_emit_error_msg(gs, buf);
1012 if(file_length(filename_err) > 0) {
1014 if((err = fopen(filename_err, "r"))) {
1015 /* print file to message window */
1016 while(fgets(buf, 1024, err))
1017 gtk_gs_emit_error_msg(gs, buf);
1021 unlink(filename_unc);
1022 g_free(filename_unc);
1023 filename_unc = NULL;
1025 unlink(filename_err);
1026 g_free(filename_err);
1029 return filename_unc;
1033 * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1034 * pdf file if necessary.
1035 * Set gs->filename_dsc to the name of the dsc file or NULL.
1036 * Error reporting via signal 'interpreter_message'.
1039 check_pdf(GtkGS * gs)
1042 gchar buf[1024], *filename;
1045 /* use uncompressed file as input if necessary */
1046 filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1048 if((file = fopen(filename, "r"))
1049 && (fread(buf, sizeof(char), 5, file) == 5)
1050 && (strncmp(buf, "%PDF-", 5) == 0)) {
1051 /* we found a PDF file */
1052 gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1053 filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1054 if((fd = mkstemp(filename_dsc)) < 0) {
1058 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1059 if((fd = mkstemp(filename_err)) < 0) {
1060 g_free(filename_dsc);
1064 fname = g_shell_quote(filename);
1065 cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1067 /* this command (sometimes?) prints error messages to stdout! */
1068 cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1071 if((system(cmdline) == 0) && file_readable(filename_dsc)) {
1074 filename = gs->gs_filename_dsc = filename_dsc;
1076 if(file_length(filename_err) > 0) {
1077 gchar *err_msg = " ";
1082 if((err = fopen(filename_err, "r"))) {
1084 /* print the content of the file to a message box */
1085 while(fgets(buf, 1024, err))
1086 err_msg = g_strconcat(err_msg, buf, NULL);
1088 /* FIXME The dialog is not yet set to modal, difficult to
1089 * get the parent of the dialog box here
1092 dialog = gtk_message_dialog_new(NULL,
1094 GTK_MESSAGE_WARNING,
1096 ("There was an error while scaning the file: %s \n%s"),
1097 gs->gs_filename, err_msg);
1099 gdk_color_parse("white", &color);
1100 gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1102 g_signal_connect(G_OBJECT(dialog), "response",
1103 G_CALLBACK(gtk_widget_destroy), NULL);
1105 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1106 gtk_widget_show(dialog);
1114 g_snprintf(buf, 1024,
1115 _("Error while converting pdf file %s:\n"), filename);
1116 gtk_gs_emit_error_msg(gs, buf);
1118 if(file_length(filename_err) > 0) {
1120 if((err = fopen(filename_err, "r"))) {
1121 /* print file to message window */
1122 while(fgets(buf, 1024, err))
1123 gtk_gs_emit_error_msg(gs, buf);
1126 unlink(filename_dsc);
1127 g_free(filename_dsc);
1130 unlink(filename_err);
1131 g_free(filename_err);
1139 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1140 /* never mind this patch: a properly working X server should take care of
1141 calculating the proper values. */
1145 # ifndef HAVE_XINERAMA
1146 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1149 dpy = (Display *) GDK_DISPLAY();
1150 if(XineramaIsActive(dpy)) {
1152 XineramaScreenInfo *head_info;
1153 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1154 /* fake it with dimensions of the first head for now */
1155 return 25.4 * head_info[0].width / gdk_screen_width_mm();
1158 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1167 # ifndef HAVE_XINERAMA
1168 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1171 dpy = (Display *) GDK_DISPLAY();
1172 if(XineramaIsActive(dpy)) {
1174 XineramaScreenInfo *head_info;
1175 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1176 /* fake it with dimensions of the first head for now */
1177 return 25.4 * head_info[0].height / gdk_screen_height_mm();
1180 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1189 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1195 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1197 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1199 /* Compute new size of window, sets xdpi and ydpi if necessary.
1200 * returns True if new window size is different */
1202 compute_size(GtkGS * gs)
1204 guint new_width = 1;
1205 guint new_height = 1;
1206 gboolean change = FALSE;
1209 /* width and height can be changed, calculate window size according */
1210 /* to xpdi and ydpi */
1211 orientation = gtk_gs_get_orientation(gs);
1213 switch (orientation) {
1214 case GTK_GS_ORIENTATION_PORTRAIT:
1215 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1216 new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1217 new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1219 case GTK_GS_ORIENTATION_LANDSCAPE:
1220 case GTK_GS_ORIENTATION_SEASCAPE:
1221 new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1222 new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1226 change = (new_width != gs->width * gs->zoom_factor)
1227 || (new_height != gs->height * gs->zoom_factor);
1228 gs->width = (gint) (new_width * gs->zoom_factor);
1229 gs->height = (gint) (new_height * gs->zoom_factor);
1235 gtk_gs_enable_interpreter(GtkGS * gs)
1237 g_return_val_if_fail(gs != NULL, FALSE);
1238 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1240 if(!gs->gs_filename)
1243 gs->disable_start = FALSE;
1245 return start_interpreter(gs);
1248 /* publicly accessible functions */
1251 gtk_gs_get_type(void)
1253 static GType gs_type = 0;
1255 GTypeInfo gs_info = {
1257 (GBaseInitFunc) NULL,
1258 (GBaseFinalizeFunc) NULL,
1259 (GClassInitFunc) gtk_gs_class_init,
1260 (GClassFinalizeFunc) NULL,
1261 NULL, /* class_data */
1263 0, /* n_preallocs */
1264 (GInstanceInitFunc) gtk_gs_init
1267 static const GInterfaceInfo document_info =
1269 (GInterfaceInitFunc) ps_document_document_iface_init,
1274 gs_type = g_type_register_static(G_TYPE_OBJECT,
1275 "GtkGS", &gs_info, 0);
1277 g_type_add_interface_static (gs_type,
1287 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1291 gs = g_object_new(GTK_GS_TYPE, NULL);
1298 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1300 GObject *gs = gtk_gs_new(hadj, vadj);
1301 gtk_gs_load(GTK_GS(gs), fname);
1306 gtk_gs_reload(GtkGS * gs)
1311 if(!gs->gs_filename)
1314 page = gtk_gs_get_current_page(gs);
1315 fname = g_strdup(gs->gs_filename);
1316 gtk_gs_load(gs, fname);
1317 gtk_gs_goto_page(gs, page);
1323 * Show error message -> send signal "interpreter_message"
1326 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1328 g_signal_emit (G_OBJECT(gs),
1329 gtk_gs_signals[INTERPRETER_MESSAGE], 0, g_strdup(msg));
1333 gtk_gs_disable_interpreter(GtkGS * gs)
1335 g_return_if_fail(gs != NULL);
1336 g_return_if_fail(GTK_IS_GS(gs));
1338 gs->disable_start = TRUE;
1340 stop_interpreter(gs);
1344 gtk_gs_load(GtkGS * gs, const gchar * fname)
1346 g_return_val_if_fail(gs != NULL, FALSE);
1347 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1349 /* clean up previous document */
1357 /* prepare this document */
1359 /* default values: no dsc information available */
1360 gs->structured_doc = FALSE;
1361 gs->send_filename_to_gs = TRUE;
1362 gs->current_page = -2;
1365 /* an absolute path */
1366 gs->gs_filename = g_strdup(fname);
1369 /* path relative to our cwd: make it absolute */
1370 gchar *cwd = g_get_current_dir();
1371 gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1375 if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1376 gs->send_filename_to_gs = FALSE;
1380 * We need to make sure that the file is loadable/exists!
1381 * otherwise we want to exit without loading new stuff...
1383 gchar *filename = NULL;
1385 if(!file_readable(fname)) {
1387 g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1388 gtk_gs_emit_error_msg(gs, buf);
1389 gs->gs_status = _("File is not readable.");
1392 filename = check_filecompressed(gs);
1394 filename = check_pdf(gs);
1397 if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1402 /* we grab the vital statistics!!! */
1403 gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1405 if(gs->doc == NULL) {
1406 /* File does not seem to be a Postscript one */
1408 g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1409 gtk_gs_emit_error_msg(gs, buf);
1411 gs->gs_status = _("The file is not a PostScript document.");
1415 if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1416 (gs->doc->epsf && gs->doc->numpages > 1)) {
1417 gs->structured_doc = TRUE;
1418 gs->send_filename_to_gs = FALSE;
1421 /* We have to set up the orientation of the document */
1424 /* orientation can only be portrait, and landscape or none.
1425 This is the document default. A document can have
1426 pages in landscape and some in portrait */
1427 if(gs->override_orientation) {
1428 /* If the orientation should be override...
1429 then gs->orientation has already the correct
1430 value (it was set when the widget was created */
1435 /* Otherwise, set the proper orientation for the doc */
1436 gs->real_orientation = gs->doc->orientation;
1439 gtk_gs_set_page_size(gs, -1, gs->current_page);
1442 gs->gs_status = _("Document loaded.");
1449 gtk_gs_next_page(GtkGS * gs)
1453 g_return_val_if_fail(gs != NULL, FALSE);
1454 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1456 if(gs->interpreter_pid == 0) { /* no interpreter active */
1460 if(gs->busy) { /* interpreter is busy */
1466 event.xclient.type = ClientMessage;
1467 event.xclient.display = gdk_display;
1468 event.xclient.window = gs->message_window;
1469 event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1470 event.xclient.format = 32;
1472 gdk_error_trap_push();
1473 XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1475 gdk_error_trap_pop();
1481 gtk_gs_get_current_page(GtkGS * gs)
1483 g_return_val_if_fail(gs != NULL, -1);
1484 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1486 return gs->current_page;
1490 gtk_gs_get_page_count(GtkGS * gs)
1492 if(!gs->gs_filename)
1496 if(gs->structured_doc)
1497 return gs->doc->numpages;
1506 gtk_gs_goto_page(GtkGS * gs, gint page)
1508 g_return_val_if_fail(gs != NULL, FALSE);
1509 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1511 if(!gs->gs_filename) {
1515 /* range checking... */
1519 if(gs->structured_doc && gs->doc) {
1520 if(page >= gs->doc->numpages)
1521 page = gs->doc->numpages - 1;
1523 if(page == gs->current_page && !gs->changed)
1526 gs->current_page = page;
1528 if(gs->doc->pages[page].orientation != NONE &&
1529 !gs->override_orientation &&
1530 gs->doc->pages[page].orientation != gs->real_orientation) {
1531 gs->real_orientation = gs->doc->pages[page].orientation;
1535 gtk_gs_set_page_size(gs, -1, page);
1537 gs->changed = FALSE;
1539 if(is_interpreter_ready(gs)) {
1540 gtk_gs_next_page(gs);
1543 gtk_gs_enable_interpreter(gs);
1544 send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1545 send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1548 send_ps(gs, gs->doc->pages[gs->current_page].begin,
1549 gs->doc->pages[gs->current_page].len, FALSE);
1552 /* Unstructured document */
1553 /* In the case of non structured documents,
1554 GS read the PS from the actual file (via command
1555 line. Hence, ggv only send a signal next page.
1556 If ghostview is not running it is usually because
1557 the last page of the file was displayed. In that
1558 case, ggv restarts GS again and the first page is displayed.
1560 if(page == gs->current_page && !gs->changed)
1563 if(!is_interpreter_ready(gs))
1564 gtk_gs_enable_interpreter(gs);
1566 gs->current_page = page;
1568 gtk_gs_next_page(gs);
1574 * set pagesize sets the size from
1575 * if new_pagesize is -1, then it is set to either
1576 * a) the default settings of pageid, if they exist, or if pageid != -1.
1577 * b) the default setting of the document, if it exists.
1578 * c) the default setting of the widget.
1579 * otherwise, the new_pagesize is used as the pagesize
1582 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1588 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1590 g_return_val_if_fail(gs != NULL, FALSE);
1591 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1593 if(new_pagesize == -1) {
1594 if(gs->default_size > 0)
1595 new_pagesize = gs->default_size;
1596 if(!gs->override_size && gs->doc) {
1597 /* If we have a document:
1598 We use -- the page size (if specified)
1599 or the doc. size (if specified)
1600 or the page bbox (if specified)
1603 if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1604 (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1605 new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1607 else if(gs->doc->default_page_size != NULL) {
1608 new_pagesize = gs->doc->default_page_size - gs->doc->size;
1610 else if((pageid >= 0) &&
1611 (gs->doc->numpages > pageid) &&
1613 (gs->doc->pages[pageid].boundingbox[URX] >
1614 gs->doc->pages[pageid].boundingbox[LLX]) &&
1615 (gs->doc->pages[pageid].boundingbox[URY] >
1616 gs->doc->pages[pageid].boundingbox[LLY])) {
1619 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1620 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1626 /* Compute bounding box */
1627 if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) { /* epsf or bbox */
1630 (gs->doc->pages[pageid].boundingbox[URX] >
1631 gs->doc->pages[pageid].boundingbox[LLX])
1632 && (gs->doc->pages[pageid].boundingbox[URY] >
1633 gs->doc->pages[pageid].boundingbox[LLY])) {
1635 new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1636 new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1637 new_urx = gs->doc->pages[pageid].boundingbox[URX];
1638 new_ury = gs->doc->pages[pageid].boundingbox[URY];
1640 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1641 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1643 new_llx = gs->doc->boundingbox[LLX];
1644 new_lly = gs->doc->boundingbox[LLY];
1645 new_urx = gs->doc->boundingbox[URX];
1646 new_ury = gs->doc->boundingbox[URY];
1650 if(new_pagesize < 0)
1651 new_pagesize = gs->default_size;
1652 new_llx = new_lly = 0;
1653 if(gs->doc && !gs->override_size && gs->doc->size &&
1654 (new_pagesize < gs->doc->numsizes)) {
1655 new_urx = gs->doc->size[new_pagesize].width;
1656 new_ury = gs->doc->size[new_pagesize].height;
1659 new_urx = papersizes[new_pagesize].width;
1660 new_ury = papersizes[new_pagesize].height;
1664 if(new_urx <= new_llx)
1665 new_urx = papersizes[12].width;
1666 if(new_ury <= new_lly)
1667 new_ury = papersizes[12].height;
1669 /* If bounding box changed, setup for new size. */
1670 /* gtk_gs_disable_interpreter (gs); */
1671 if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1672 (new_urx != gs->urx) || (new_ury != gs->ury)) {
1689 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1691 gint iOldOrientation;
1693 g_return_if_fail(gs != NULL);
1694 g_return_if_fail(GTK_IS_GS(gs));
1696 iOldOrientation = gtk_gs_get_orientation(gs);
1698 gs->override_orientation = bNewOverride;
1700 /* If the current orientation is different from the
1701 new orientation then redisplay */
1702 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1709 gtk_gs_get_override_orientation(GtkGS * gs)
1711 g_return_val_if_fail(gs != NULL, FALSE);
1712 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1714 return gs->override_orientation;
1718 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1720 g_return_if_fail(gs != NULL);
1721 g_return_if_fail(GTK_IS_GS(gs));
1723 if(f != gs->override_size) {
1724 gs->override_size = f;
1726 gtk_gs_set_page_size(gs, -1, gs->current_page);
1732 gtk_gs_get_override_size(GtkGS * gs)
1734 g_return_val_if_fail(gs != NULL, FALSE);
1735 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1737 return gs->override_size;
1741 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1743 g_return_if_fail(gs != NULL);
1744 g_return_if_fail(GTK_IS_GS(gs));
1746 switch (gs->zoom_mode) {
1747 case GTK_GS_ZOOM_FIT_WIDTH:
1748 zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1750 case GTK_GS_ZOOM_FIT_PAGE:
1751 zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1753 case GTK_GS_ZOOM_ABSOLUTE:
1758 if(fabs(gs->zoom_factor - zoom) > 0.001) {
1759 gs->zoom_factor = zoom;
1764 gtk_gs_goto_page(gs, gs->current_page);
1768 gtk_gs_get_zoom(GtkGS * gs)
1770 g_return_val_if_fail(gs != NULL, 0.0);
1771 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1773 return gs->zoom_factor;
1777 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1781 guint avail_w, avail_h;
1783 g_return_val_if_fail(gs != NULL, 0.0);
1784 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1786 avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1787 avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1789 new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1791 new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1793 new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1800 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1802 gint iOldOrientation;
1804 g_return_val_if_fail(gs != NULL, FALSE);
1805 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1806 g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1807 (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1808 (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1809 (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1811 iOldOrientation = gtk_gs_get_orientation(gs);
1812 gs->fallback_orientation = orientation;
1814 /* We are setting the fallback orientation */
1815 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1825 gtk_gs_get_default_orientation(GtkGS * gs)
1827 g_return_val_if_fail(gs != NULL, -1);
1828 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1830 return gs->fallback_orientation;
1834 gtk_gs_get_orientation(GtkGS * gs)
1836 g_return_val_if_fail(gs != NULL, -1);
1837 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1840 if(gs->structured_doc) {
1841 if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1842 GTK_GS_ORIENTATION_NONE)
1843 gs->real_orientation =
1844 gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1846 gs->real_orientation = gs->doc->default_page_orientation;
1849 if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1850 gs->real_orientation = gs->doc->orientation;
1853 if(gs->override_orientation ||
1854 gs->real_orientation == GTK_GS_ORIENTATION_NONE)
1855 return gs->fallback_orientation;
1857 return gs->real_orientation;
1861 gtk_gs_set_default_size(GtkGS * gs, gint size)
1863 g_return_if_fail(gs != NULL);
1864 g_return_if_fail(GTK_IS_GS(gs));
1866 gs->default_size = size;
1867 gtk_gs_set_page_size(gs, -1, gs->current_page);
1871 gtk_gs_get_default_size(GtkGS * gs)
1873 g_return_val_if_fail(gs != NULL, -1);
1874 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1876 return gs->default_size;
1880 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
1882 g_return_if_fail(gs != NULL);
1883 g_return_if_fail(GTK_IS_GS(gs));
1885 if(gs->respect_eof == f)
1888 gs->respect_eof = f;
1889 gtk_gs_set_page_size(gs, -1, gs->current_page);
1893 gtk_gs_get_respect_eof(GtkGS * gs)
1895 g_return_val_if_fail(gs != NULL, -1);
1896 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1898 return gs->respect_eof;
1902 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
1904 g_return_if_fail(gs != NULL);
1905 g_return_if_fail(GTK_IS_GS(gs));
1907 if(gs->antialiased == f)
1910 gs->antialiased = f;
1912 start_interpreter(gs);
1913 gtk_gs_goto_page(gs, gs->current_page);
1917 gtk_gs_get_antialiasing(GtkGS * gs)
1919 g_return_val_if_fail(gs != NULL, -1);
1920 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1922 return gs->antialiased;
1926 gtk_gs_get_document_title(GtkGS * gs)
1928 g_return_val_if_fail(gs != NULL, NULL);
1929 g_return_val_if_fail(GTK_IS_GS(gs), NULL);
1931 if(gs->doc && gs->doc->title)
1932 return gs->doc->title;
1938 gtk_gs_get_document_numpages(GtkGS * widget)
1940 g_return_val_if_fail(widget != NULL, 0);
1941 g_return_val_if_fail(GTK_IS_GS(widget), 0);
1944 return widget->doc->numpages;
1950 gtk_gs_get_document_page_label(GtkGS * widget, int page)
1952 g_return_val_if_fail(widget != NULL, NULL);
1953 g_return_val_if_fail(GTK_IS_GS(widget), NULL);
1955 if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
1956 return widget->doc->pages[page - 1].label;
1962 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
1966 while(size[idx].name != NULL) {
1967 if(strcmp(size[idx].name, string) == 0)
1976 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
1980 gboolean free_pages = FALSE;
1983 if(!gs->structured_doc) {
1987 if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
1989 doc = g_new(gchar, sb.st_size);
1992 f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
1993 if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
2002 int i, n = gtk_gs_get_page_count(gs);
2003 pages = g_new0(gint, n);
2004 for(i = 0; i < n; i++)
2010 sink = gtk_gs_doc_sink_new();
2012 if(GTK_GS_IS_PDF(gs)) {
2013 gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2017 if((tmpfd = mkstemp(tmpn)) < 0) {
2022 fname = g_shell_quote (gs->gs_filename_unc ?
2023 gs->gs_filename_unc : gs->gs_filename);
2024 cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2026 if((system(cmd) == 0) && file_readable(tmpn)) {
2028 tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2029 if(NULL != tmp_gs) {
2030 if(GTK_GS(tmp_gs)->loaded)
2031 pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2032 g_object_unref(tmp_gs);
2039 /* Use uncompressed file if necessary */
2040 pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2044 doc = gtk_gs_doc_sink_get_buffer(sink);
2045 gtk_gs_doc_sink_free(sink);
2050 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2052 if(zoom_mode != gs->zoom_mode) {
2053 gs->zoom_mode = zoom_mode;
2054 gtk_gs_set_zoom(gs, 1.0);
2056 gtk_gs_goto_page(gs, gs->current_page);
2060 gtk_gs_get_zoom_mode(GtkGS * gs)
2062 return gs->zoom_mode;
2066 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2068 gs->avail_w = avail_w;
2069 gs->avail_h = avail_h;
2070 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2071 gtk_gs_set_zoom(gs, 0.0);
2076 ps_document_load (EvDocument *document,
2083 filename = g_filename_from_uri (uri, NULL, error);
2087 result = gtk_gs_load (GTK_GS (document), filename);
2095 ps_document_get_n_pages (EvDocument *document)
2097 return gtk_gs_get_page_count (GTK_GS (document));
2101 ps_document_set_page (EvDocument *document,
2104 gtk_gs_goto_page (GTK_GS (document), page);
2108 ps_document_get_page (EvDocument *document)
2110 return gtk_gs_get_current_page (GTK_GS (document));
2114 gtk_gs_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
2116 GtkGS *gs = (GtkGS *) data;
2118 if(event->type != GDK_CLIENT_EVENT)
2121 if (event->client.message_type == gs_class->page_atom) {
2123 ev_document_changed (EV_DOCUMENT (gs));
2130 ps_document_set_target (EvDocument *document,
2131 GdkDrawable *target)
2133 GtkGS *gs = GTK_GS (document);
2137 gs->pstarget = target;
2140 gdk_window_get_user_data (gs->pstarget, &data);
2141 g_return_if_fail (GTK_IS_WIDGET (data));
2143 widget = GTK_WIDGET (data);
2144 g_signal_connect (widget, "event",
2145 G_CALLBACK (gtk_gs_widget_event),
2149 gtk_gs_goto_page (gs, gs->current_page);
2153 ps_document_set_scale (EvDocument *document,
2156 gtk_gs_set_zoom (GTK_GS (document), scale);
2160 ps_document_set_page_offset (EvDocument *document,
2167 ps_document_get_page_size (EvDocument *document,
2171 GtkGS *gs = GTK_GS (document);
2178 *height = gs->height;
2183 ps_document_render (EvDocument *document,
2189 GtkGS *gs = GTK_GS (document);
2192 if (gs->pstarget == NULL ||
2193 gs->bpixmap == NULL) {
2197 gc = gdk_gc_new (gs->pstarget);
2199 gdk_draw_drawable (gs->pstarget, gc,
2203 clip_width, clip_height);
2205 g_object_unref (gc);
2209 ps_document_document_iface_init (EvDocumentIface *iface)
2211 iface->load = ps_document_load;
2212 iface->get_n_pages = ps_document_get_n_pages;
2213 iface->set_page = ps_document_set_page;
2214 iface->get_page = ps_document_get_page;
2215 iface->set_scale = ps_document_set_scale;
2216 iface->set_target = ps_document_set_target;
2217 iface->set_page_offset = ps_document_set_page_offset;
2218 iface->get_page_size = ps_document_get_page_size;
2219 iface->render = ps_document_render;