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_value_adjustment_changed(GtkAdjustment * adjustment,
186 static void gtk_gs_interpreter_message(GtkGS * gs, gchar * msg,
188 static void gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg);
189 static void gtk_gs_set_adjustments(GtkGS * gs, GtkAdjustment * hadj,
190 GtkAdjustment * vadj);
191 static void gtk_gs_finalize(GObject * object);
192 static void send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close);
193 static void set_up_page(GtkGS * gs);
194 static void close_pipe(int p[2]);
195 static void interpreter_failed(GtkGS * gs);
196 static float compute_xdpi(void);
197 static float compute_ydpi(void);
198 static gboolean compute_size(GtkGS * gs);
199 static void output(gpointer data, gint source, GdkInputCondition condition);
200 static void input(gpointer data, gint source, GdkInputCondition condition);
201 static void stop_interpreter(GtkGS * gs);
202 static gint start_interpreter(GtkGS * gs);
203 gboolean computeSize(void);
204 static void ps_document_document_iface_init (EvDocumentIface *iface);
206 static GObjectClass *parent_class = NULL;
208 static GtkGSClass *gs_class = NULL;
210 static gint gtk_gs_signals[LAST_SIGNAL] = { 0 };
212 /* Static, private functions */
215 ggv_marshaller_VOID__POINTER(GClosure * closure,
216 GValue * return_value,
217 guint n_param_values,
218 const GValue * param_values,
219 gpointer invocation_hint, gpointer marshal_data)
221 typedef void (*GMarshalFunc_VOID__POINTER) (gpointer data1,
222 gpointer arg_1, gpointer data2);
223 register GMarshalFunc_VOID__POINTER callback;
224 register GCClosure *cc = (GCClosure *) closure;
225 register gpointer data1, data2;
227 g_return_if_fail(n_param_values == 2);
229 if(G_CCLOSURE_SWAP_DATA(closure)) {
230 data1 = closure->data;
231 data2 = g_value_peek_pointer(param_values + 0);
234 data1 = g_value_peek_pointer(param_values + 0);
235 data2 = closure->data;
238 (GMarshalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
240 callback(data1, g_value_get_pointer(param_values + 1), data2);
244 ggv_marshaller_VOID__INT(GClosure * closure,
245 GValue * return_value,
246 guint n_param_values,
247 const GValue * param_values,
248 gpointer invocation_hint, gpointer marshal_data)
250 typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
251 gint arg_1, gpointer data2);
252 register GMarshalFunc_VOID__INT callback;
253 register GCClosure *cc = (GCClosure *) closure;
254 register gpointer data1, data2;
256 g_return_if_fail(n_param_values == 2);
258 if(G_CCLOSURE_SWAP_DATA(closure)) {
259 data1 = closure->data;
260 data2 = g_value_peek_pointer(param_values + 0);
263 data1 = g_value_peek_pointer(param_values + 0);
264 data2 = closure->data;
267 (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
269 callback(data1, g_value_get_int(param_values + 1), data2);
273 gtk_gs_init(GtkGS * gs)
276 gs->use_bpixmap = TRUE;
278 gs->current_page = -2;
279 gs->disable_start = FALSE;
280 gs->interpreter_pid = -1;
286 gs->gs_scanstyle = 0;
288 gs->gs_filename_dsc = 0;
289 gs->gs_filename_unc = 0;
293 gs->structured_doc = FALSE;
294 gs->reading_from_pipe = FALSE;
295 gs->send_filename_to_gs = FALSE;
300 gs->interpreter_input = -1;
301 gs->interpreter_output = -1;
302 gs->interpreter_err = -1;
303 gs->interpreter_input_id = 0;
304 gs->interpreter_output_id = 0;
305 gs->interpreter_error_id = 0;
308 gs->input_buffer = NULL;
309 gs->input_buffer_ptr = NULL;
311 gs->buffer_bytes_left = 0;
317 gs->xdpi = compute_xdpi();
318 gs->ydpi = compute_ydpi();
322 gs->right_margin = 0;
323 gs->bottom_margin = 0;
325 /* Set user defined defaults */
326 gs->override_orientation = gtk_gs_defaults_get_override_orientation();
327 gs->fallback_orientation = gtk_gs_defaults_get_orientation();
328 gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
329 gs->default_size = gtk_gs_defaults_get_size();
330 gs->antialiased = gtk_gs_defaults_get_antialiased();
331 gs->override_size = gtk_gs_defaults_get_override_size();
332 gs->respect_eof = gtk_gs_defaults_get_respect_eof();
333 gs->show_scroll_rect = gtk_gs_defaults_get_show_scroll_rect();
334 gs->scroll_step = gtk_gs_defaults_get_scroll_step();
335 gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
337 gs->scroll_start_x = gs->scroll_start_y = -1;
339 gs->gs_status = _("No document loaded.");
343 gtk_gs_class_init(GtkGSClass * klass)
345 GObjectClass *object_class;
347 object_class = (GObjectClass *) klass;
348 parent_class = gtk_type_class(gtk_widget_get_type());
351 gtk_gs_signals[INTERPRETER_MESSAGE] = g_signal_new("interpreter_message",
357 interpreter_message),
359 ggv_marshaller_VOID__POINTER,
362 gtk_gs_signals[INTERPRETER_ERROR] =
363 g_signal_new("interpreter_error", G_TYPE_FROM_CLASS(object_class),
364 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkGSClass,
366 NULL, NULL, ggv_marshaller_VOID__INT, G_TYPE_NONE, 1,
369 object_class->finalize = gtk_gs_finalize;
372 klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
373 klass->gs_colors_atom = gdk_atom_intern("GHOSTVIEW_COLORS", FALSE);
374 klass->next_atom = gdk_atom_intern("NEXT", FALSE);
375 klass->page_atom = gdk_atom_intern("PAGE", FALSE);
376 klass->done_atom = gdk_atom_intern("DONE", FALSE);
377 klass->string_atom = gdk_atom_intern("STRING", FALSE);
379 /* a default handler for "interpreter_message" signal */
380 klass->interpreter_message = gtk_gs_interpreter_message;
381 /* supply a scrollable interface */
382 klass->set_scroll_adjustments = gtk_gs_set_adjustments;
384 gtk_gs_defaults_load();
387 /* Clean all memory and temporal files */
389 gtk_gs_cleanup(GtkGS * gs)
391 g_return_if_fail(gs != NULL);
392 g_return_if_fail(GTK_IS_GS(gs));
394 stop_interpreter(gs);
397 fclose(gs->gs_psfile);
398 gs->gs_psfile = NULL;
400 if(gs->gs_filename) {
401 g_free(gs->gs_filename);
402 gs->gs_filename = NULL;
408 if(gs->gs_filename_dsc) {
409 unlink(gs->gs_filename_dsc);
410 g_free(gs->gs_filename_dsc);
411 gs->gs_filename_dsc = NULL;
413 if(gs->gs_filename_unc) {
414 unlink(gs->gs_filename_unc);
415 g_free(gs->gs_filename_unc);
416 gs->gs_filename_unc = NULL;
418 if(gs->pstarget && gdk_window_is_visible(gs->pstarget))
419 gdk_window_hide(gs->pstarget);
420 gs->current_page = -1;
429 /* free message as it was allocated in output() */
431 gtk_gs_interpreter_message(GtkGS * gs, gchar * msg, gpointer user_data)
433 gdk_pointer_ungrab(GDK_CURRENT_TIME);
434 if(strstr(msg, "Error:")) {
435 gs->gs_status = _("File is not a valid PostScript document.");
437 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", 1, NULL);
443 gtk_gs_finalize(GObject * object)
447 g_return_if_fail(object != NULL);
448 g_return_if_fail(GTK_IS_GS(object));
454 if(gs->input_buffer) {
455 g_free(gs->input_buffer);
456 gs->input_buffer = NULL;
459 g_signal_handlers_disconnect_matched(G_OBJECT(gs->hadj),
461 0, 0, NULL, NULL, gs);
462 gtk_object_unref(GTK_OBJECT(gs->hadj));
466 g_signal_handlers_disconnect_matched(G_OBJECT(gs->vadj),
468 0, 0, NULL, NULL, gs);
469 gtk_object_unref(GTK_OBJECT(gs->vadj));
473 (*G_OBJECT_CLASS(parent_class)->finalize) (object);
477 gtk_gs_value_adjustment_changed(GtkAdjustment * adjustment, gpointer data)
481 gint x, y, width, height, depth;
484 g_return_if_fail(adjustment != NULL);
485 g_return_if_fail(data != NULL);
487 if(gs->bpixmap == NULL)
491 g_print("Adjustment %c: val = %f, page = %f, upper = %f, lower = %f\n",
492 (adjustment == gs->hadj) ? 'H' : 'V',
493 adjustment->value, adjustment->page_size,
494 adjustment->upper, adjustment->lower);
497 gdk_window_get_geometry(gs->pstarget, &x, &y, &width, &height, &depth);
498 if(gs->width <= gs->widget.allocation.width)
499 newx = (gs->widget.allocation.width - gs->width) / 2;
501 newx = -gs->hadj->value * gs->width;
502 if(gs->height <= gs->widget.allocation.height)
503 newy = (gs->widget.allocation.height - gs->height) / 2;
505 newy = -gs->vadj->value * gs->height;
507 gdk_window_move(gs->pstarget, newx, newy);
512 gtk_gs_set_center(GtkGS * gs, gfloat hval, gfloat vval)
514 if(hval <= gs->hadj->upper - gs->hadj->page_size / 2 &&
515 hval >= gs->hadj->lower + gs->hadj->page_size / 2)
516 gtk_adjustment_set_value(gs->hadj, hval);
517 if(vval <= gs->vadj->upper - gs->vadj->page_size / 2 &&
518 vval >= gs->vadj->lower + gs->vadj->page_size / 2)
519 gtk_adjustment_set_value(gs->vadj, vval);
523 send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close)
525 struct record_list *ps_new;
527 if(gs->interpreter_input < 0) {
528 g_critical("No pipe to gs: error in send_ps().");
532 ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
533 ps_new->fp = gs->gs_psfile;
534 ps_new->begin = begin;
536 ps_new->seek_needed = TRUE;
537 ps_new->close = close;
540 if(gs->input_buffer == NULL) {
541 gs->input_buffer = g_malloc(MAX_BUFSIZE);
544 if(gs->ps_input == NULL) {
545 gs->input_buffer_ptr = gs->input_buffer;
546 gs->bytes_left = len;
547 gs->buffer_bytes_left = 0;
548 gs->ps_input = ps_new;
549 gs->interpreter_input_id =
550 gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
553 struct record_list *p = gs->ps_input;
554 while(p->next != NULL) {
562 set_up_page(GtkGS * gs)
564 * This is used to prepare the widget internally for
565 * a new document. It sets gs->pstarget to the
566 * correct size and position, and updates the
567 * adjustments appropriately.
569 * It is not meant to be used every time a specific page
572 * NOTE: It expects the widget is realized.
578 GdkColormap *colormap;
580 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */
586 if(!GTK_WIDGET_REALIZED(gs))
589 /* Do we have to check if the actual geometry changed? */
591 stop_interpreter(gs);
593 orientation = gtk_gs_get_orientation(gs);
595 if(compute_size(gs)) {
598 /* clear new pixmap (set to white) */
599 fill = gdk_gc_new(gs->pstarget);
601 colormap = gtk_widget_get_colormap(GTK_WIDGET(gs));
602 gdk_color_alloc(colormap, &white);
603 gdk_gc_set_foreground(fill, &white);
605 if(gs->use_bpixmap && gs->width > 0 && gs->height > 0) {
607 gdk_drawable_unref(gs->bpixmap);
611 gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
613 gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
614 0, 0, gs->width, gs->height);
616 gdk_window_set_back_pixmap(gs->pstarget, gs->bpixmap, FALSE);
619 gdk_draw_rectangle(gs->pstarget, fill, TRUE,
620 0, 0, gs->width, gs->height);
624 gdk_window_resize(gs->pstarget, gs->width, gs->height);
631 /* gs needs floating point parameters with '.' as decimal point
632 * while some (european) locales use ',' instead, so we set the
633 * locale for this snprintf to "C".
635 savelocale = setlocale(LC_NUMERIC, "C");
637 pprivate = (GdkPixmap *) gs->bpixmap;
639 g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
640 pprivate ? gdk_x11_drawable_get_xid(pprivate) : 0L,
646 gs->xdpi * gs->zoom_factor,
647 gs->ydpi * gs->zoom_factor,
649 gs->bottom_margin, gs->right_margin, gs->top_margin);
652 setlocale(LC_NUMERIC, savelocale);
654 gdk_property_change(gs->pstarget,
656 gs_class->string_atom,
657 8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
671 is_interpreter_ready(GtkGS * gs)
673 return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
677 interpreter_failed(GtkGS * gs)
679 stop_interpreter(gs);
683 output(gpointer data, gint source, GdkInputCondition condition)
685 char buf[MAX_BUFSIZE + 1], *msg;
687 GtkGS *gs = GTK_GS(data);
689 if(source == gs->interpreter_output) {
690 bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
691 if(bytes == 0) { /* EOF occurred */
692 close(gs->interpreter_output);
693 gs->interpreter_output = -1;
694 gdk_input_remove(gs->interpreter_output_id);
697 else if(bytes == -1) {
699 interpreter_failed(gs);
702 if(gs->interpreter_err == -1) {
703 stop_interpreter(gs);
706 else if(source == gs->interpreter_err) {
707 bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
708 if(bytes == 0) { /* EOF occurred */
709 close(gs->interpreter_err);
710 gs->interpreter_err = -1;
711 gdk_input_remove(gs->interpreter_error_id);
714 else if(bytes == -1) {
716 interpreter_failed(gs);
719 if(gs->interpreter_output == -1) {
720 stop_interpreter(gs);
726 gtk_signal_emit(GTK_OBJECT(gs), gtk_gs_signals[INTERPRETER_MESSAGE], msg);
731 input(gpointer data, gint source, GdkInputCondition condition)
733 GtkGS *gs = GTK_GS(data);
735 void (*oldsig) (int);
736 oldsig = signal(SIGPIPE, catchPipe);
739 if(gs->buffer_bytes_left == 0) {
740 /* Get a new section if required */
741 if(gs->ps_input && gs->bytes_left == 0) {
742 struct record_list *ps_old = gs->ps_input;
743 gs->ps_input = ps_old->next;
744 if(ps_old->close && NULL != ps_old->fp)
746 g_free((char *) ps_old);
748 /* Have to seek at the beginning of each section */
749 if(gs->ps_input && gs->ps_input->seek_needed) {
750 fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
751 gs->ps_input->seek_needed = FALSE;
752 gs->bytes_left = gs->ps_input->len;
755 if(gs->bytes_left > MAX_BUFSIZE) {
756 gs->buffer_bytes_left =
757 fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
759 else if(gs->bytes_left > 0) {
760 gs->buffer_bytes_left =
761 fread(gs->input_buffer,
762 sizeof(char), gs->bytes_left, gs->ps_input->fp);
765 gs->buffer_bytes_left = 0;
767 if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
768 interpreter_failed(gs); /* Error occurred */
770 gs->input_buffer_ptr = gs->input_buffer;
771 gs->bytes_left -= gs->buffer_bytes_left;
774 if(gs->buffer_bytes_left > 0) {
775 /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
777 bytes_written = write(gs->interpreter_input,
778 gs->input_buffer_ptr, gs->buffer_bytes_left);
781 gtk_gs_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
783 interpreter_failed(gs);
785 else if(bytes_written == -1) {
786 if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
787 interpreter_failed(gs); /* Something bad happened */
791 gs->buffer_bytes_left -= bytes_written;
792 gs->input_buffer_ptr += bytes_written;
796 while(gs->ps_input && gs->buffer_bytes_left == 0);
798 signal(SIGPIPE, oldsig);
800 if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
801 if(gs->interpreter_input_id != 0) {
802 gdk_input_remove(gs->interpreter_input_id);
803 gs->interpreter_input_id = 0;
809 start_interpreter(GtkGS * gs)
811 int std_in[2] = { -1, -1 }; /* pipe to interp stdin */
812 int std_out[2]; /* pipe from interp stdout */
813 int std_err[2]; /* pipe from interp stderr */
816 #define NUM_GS_ARGS (NUM_ARGS - 20)
817 #define NUM_ALPHA_ARGS 10
819 char *argv[NUM_ARGS], *dir, *gv_env;
820 char **gs_args, **alpha_args = NULL;
826 stop_interpreter(gs);
828 if(gs->disable_start == TRUE)
831 /* set up the args... */
832 gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
833 for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
834 argv[argc] = gs_args[i];
836 if(gs->antialiased) {
837 if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
838 alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
840 alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
841 " ", NUM_ALPHA_ARGS);
842 for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
843 argv[argc] = alpha_args[i];
846 argv[argc++] = "-sDEVICE=x11";
847 argv[argc++] = "-dNOPAUSE";
848 argv[argc++] = "-dQUIET";
849 /* I assume we do _not_ want to change this... (: */
850 argv[argc++] = "-dSAFER";
852 /* set up the pipes */
853 if(gs->send_filename_to_gs) {
854 argv[argc++] = GTK_GS_GET_PS_FILE(gs);
856 argv[argc++] = "quit";
863 if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
864 if(pipe(std_in) == -1) {
865 g_critical("Unable to open pipe to Ghostscript.");
869 if(pipe(std_out) == -1) {
873 if(pipe(std_err) == -1) {
880 gs->interpreter_pid = fork();
881 switch (gs->interpreter_pid) {
897 if(!gs->reading_from_pipe) {
898 if(gs->send_filename_to_gs) {
900 /* just in case gs tries to read from stdin */
901 stdinfd = open("/dev/null", O_RDONLY);
914 gv_env = g_strdup_printf("GHOSTVIEW=%ld",
915 gdk_x11_drawable_get_xid(gs->pstarget));
918 /* change to directory where the input file is. This helps
919 * with postscript-files which include other files using
921 dir = g_path_get_dirname(gs->gs_filename);
925 execvp(argv[0], argv);
928 g_print("Unable to execute [%s]\n", argv[0]);
932 g_strfreev(alpha_args);
935 default: /* parent */
936 if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
939 /* use non-blocking IO for pipe to ghostscript */
940 result = fcntl(std_in[1], F_GETFL, 0);
941 fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
942 gs->interpreter_input = std_in[1];
945 gs->interpreter_input = -1;
948 gs->interpreter_output = std_out[0];
950 gs->interpreter_err = std_err[0];
951 gs->interpreter_output_id =
952 gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
953 gs->interpreter_error_id =
954 gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
961 stop_interpreter(GtkGS * gs)
963 if(gs->interpreter_pid > 0) {
965 kill(gs->interpreter_pid, SIGTERM);
966 while((wait(&status) == -1) && (errno == EINTR)) ;
967 gs->interpreter_pid = -1;
970 gs->gs_status = _("Interpreter failed.");
971 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", status);
975 if(gs->interpreter_input >= 0) {
976 close(gs->interpreter_input);
977 gs->interpreter_input = -1;
978 if(gs->interpreter_input_id != 0) {
979 gdk_input_remove(gs->interpreter_input_id);
980 gs->interpreter_input_id = 0;
982 while(gs->ps_input) {
983 struct record_list *ps_old = gs->ps_input;
984 gs->ps_input = gs->ps_input->next;
985 if(ps_old->close && NULL != ps_old->fp)
987 g_free((char *) ps_old);
991 if(gs->interpreter_output >= 0) {
992 close(gs->interpreter_output);
993 gs->interpreter_output = -1;
994 if(gs->interpreter_output_id) {
995 gdk_input_remove(gs->interpreter_output_id);
996 gs->interpreter_output_id = 0;
1000 if(gs->interpreter_err >= 0) {
1001 close(gs->interpreter_err);
1002 gs->interpreter_err = -1;
1003 if(gs->interpreter_error_id) {
1004 gdk_input_remove(gs->interpreter_error_id);
1005 gs->interpreter_error_id = 0;
1014 * Decompress gs->gs_filename if necessary
1015 * Set gs->filename_unc to the name of the uncompressed file or NULL.
1016 * Error reporting via signal 'interpreter_message'
1017 * Return name of input file to use or NULL on error..
1020 check_filecompressed(GtkGS * gs)
1024 gchar *filename, *filename_unc, *filename_err, *cmdline;
1030 if((file = fopen(gs->gs_filename, "r"))
1031 && (fread(buf, sizeof(gchar), 3, file) == 3)) {
1032 if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
1033 /* file is gzipped or compressed */
1034 cmd = gtk_gs_defaults_get_ungzip_cmd();
1036 else if(strncmp(buf, "BZh", 3) == 0) {
1037 /* file is compressed with bzip2 */
1038 cmd = gtk_gs_defaults_get_unbzip2_cmd();
1045 return gs->gs_filename;
1047 /* do the decompression */
1048 filename = ggv_quote_filename(gs->gs_filename);
1049 filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1050 if((fd = mkstemp(filename_unc)) < 0) {
1051 g_free(filename_unc);
1056 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1057 if((fd = mkstemp(filename_err)) < 0) {
1058 g_free(filename_err);
1059 g_free(filename_unc);
1064 cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1065 filename, filename_unc, filename_err);
1066 if((system(cmdline) == 0)
1067 && ggv_file_readable(filename_unc)
1068 && (ggv_file_length(filename_err) == 0)) {
1069 /* sucessfully uncompressed file */
1070 gs->gs_filename_unc = filename_unc;
1074 g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1076 gtk_gs_emit_error_msg(gs, buf);
1077 if(ggv_file_length(filename_err) > 0) {
1079 if((err = fopen(filename_err, "r"))) {
1080 /* print file to message window */
1081 while(fgets(buf, 1024, err))
1082 gtk_gs_emit_error_msg(gs, buf);
1086 unlink(filename_unc);
1087 g_free(filename_unc);
1088 filename_unc = NULL;
1090 unlink(filename_err);
1091 g_free(filename_err);
1094 return filename_unc;
1098 * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1099 * pdf file if necessary.
1100 * Set gs->filename_dsc to the name of the dsc file or NULL.
1101 * Error reporting via signal 'interpreter_message'.
1104 check_pdf(GtkGS * gs)
1107 gchar buf[1024], *filename;
1110 /* use uncompressed file as input if necessary */
1111 filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1113 if((file = fopen(filename, "r"))
1114 && (fread(buf, sizeof(char), 5, file) == 5)
1115 && (strncmp(buf, "%PDF-", 5) == 0)) {
1116 /* we found a PDF file */
1117 gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1118 filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1119 if((fd = mkstemp(filename_dsc)) < 0) {
1123 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1124 if((fd = mkstemp(filename_err)) < 0) {
1125 g_free(filename_dsc);
1129 fname = ggv_quote_filename(filename);
1130 cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1132 /* this command (sometimes?) prints error messages to stdout! */
1133 cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1136 if((system(cmdline) == 0) && ggv_file_readable(filename_dsc)) {
1139 filename = gs->gs_filename_dsc = filename_dsc;
1141 if(ggv_file_length(filename_err) > 0) {
1142 gchar *err_msg = " ";
1147 if((err = fopen(filename_err, "r"))) {
1149 /* print the content of the file to a message box */
1150 while(fgets(buf, 1024, err))
1151 err_msg = g_strconcat(err_msg, buf, NULL);
1153 /* FIXME The dialog is not yet set to modal, difficult to
1154 * get the parent of the dialog box here
1157 dialog = gtk_message_dialog_new(NULL,
1159 GTK_MESSAGE_WARNING,
1161 ("There was an error while scaning the file: %s \n%s"),
1162 gs->gs_filename, err_msg);
1164 gdk_color_parse("white", &color);
1165 gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1167 g_signal_connect(G_OBJECT(dialog), "response",
1168 G_CALLBACK(gtk_widget_destroy), NULL);
1170 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1171 gtk_widget_show(dialog);
1179 g_snprintf(buf, 1024,
1180 _("Error while converting pdf file %s:\n"), filename);
1181 gtk_gs_emit_error_msg(gs, buf);
1183 if(ggv_file_length(filename_err) > 0) {
1185 if((err = fopen(filename_err, "r"))) {
1186 /* print file to message window */
1187 while(fgets(buf, 1024, err))
1188 gtk_gs_emit_error_msg(gs, buf);
1191 unlink(filename_dsc);
1192 g_free(filename_dsc);
1195 unlink(filename_err);
1196 g_free(filename_err);
1204 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1205 /* never mind this patch: a properly working X server should take care of
1206 calculating the proper values. */
1210 # ifndef HAVE_XINERAMA
1211 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1214 dpy = (Display *) GDK_DISPLAY();
1215 if(XineramaIsActive(dpy)) {
1217 XineramaScreenInfo *head_info;
1218 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1219 /* fake it with dimensions of the first head for now */
1220 return 25.4 * head_info[0].width / gdk_screen_width_mm();
1223 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1232 # ifndef HAVE_XINERAMA
1233 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1236 dpy = (Display *) GDK_DISPLAY();
1237 if(XineramaIsActive(dpy)) {
1239 XineramaScreenInfo *head_info;
1240 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1241 /* fake it with dimensions of the first head for now */
1242 return 25.4 * head_info[0].height / gdk_screen_height_mm();
1245 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1254 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1260 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1262 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1264 /* Compute new size of window, sets xdpi and ydpi if necessary.
1265 * returns True if new window size is different */
1267 compute_size(GtkGS * gs)
1269 guint new_width = 1;
1270 guint new_height = 1;
1271 gboolean change = FALSE;
1274 /* width and height can be changed, calculate window size according */
1275 /* to xpdi and ydpi */
1276 orientation = gtk_gs_get_orientation(gs);
1278 switch (orientation) {
1279 case GTK_GS_ORIENTATION_PORTRAIT:
1280 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1281 new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1282 new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1284 case GTK_GS_ORIENTATION_LANDSCAPE:
1285 case GTK_GS_ORIENTATION_SEASCAPE:
1286 new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1287 new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1291 change = (new_width != gs->width * gs->zoom_factor)
1292 || (new_height != gs->height * gs->zoom_factor);
1293 gs->width = (gint) (new_width * gs->zoom_factor);
1294 gs->height = (gint) (new_height * gs->zoom_factor);
1295 if(GTK_WIDGET_REALIZED(gs)) {
1297 if(gdk_window_is_visible(gs->pstarget))
1298 gdk_window_hide(gs->pstarget);
1301 if(!gdk_window_is_visible(gs->pstarget) && gs->width > 0
1303 gdk_window_show(gs->pstarget);
1305 //gtk_gs_munge_adjustments(gs);
1312 gtk_gs_enable_interpreter(GtkGS * gs)
1314 g_return_val_if_fail(gs != NULL, FALSE);
1315 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1317 if(!gs->gs_filename)
1320 gs->disable_start = FALSE;
1321 if(GTK_WIDGET_REALIZED(gs)) {
1322 return start_interpreter(gs);
1329 /* publicly accessible functions */
1332 gtk_gs_get_type(void)
1334 static GType gs_type = 0;
1336 GTypeInfo gs_info = {
1338 (GBaseInitFunc) NULL,
1339 (GBaseFinalizeFunc) NULL,
1340 (GClassInitFunc) gtk_gs_class_init,
1341 (GClassFinalizeFunc) NULL,
1342 NULL, /* class_data */
1344 0, /* n_preallocs */
1345 (GInstanceInitFunc) gtk_gs_init
1348 static const GInterfaceInfo document_info =
1350 (GInterfaceInitFunc) ps_document_document_iface_init,
1355 gs_type = g_type_register_static(gtk_widget_get_type(),
1356 "GtkGS", &gs_info, 0);
1358 g_type_add_interface_static (gs_type,
1368 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1373 hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.1, 0.09));
1375 vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.1, 0.09));
1377 gs = g_object_new(GTK_GS_TYPE, NULL);
1379 //gtk_gs_set_adjustments(gs, hadj, vadj);
1386 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1388 GObject *gs = gtk_gs_new(hadj, vadj);
1389 gtk_gs_load(GTK_GS(gs), fname);
1394 gtk_gs_reload(GtkGS * gs)
1397 gfloat hval = gs->hadj->value;
1398 gfloat vval = gs->vadj->value;
1401 if(!gs->gs_filename)
1404 page = gtk_gs_get_current_page(gs);
1405 fname = g_strdup(gs->gs_filename);
1406 gtk_gs_load(gs, fname);
1407 gtk_gs_goto_page(gs, page);
1408 gtk_adjustment_set_value(gs->hadj, hval);
1409 gtk_adjustment_set_value(gs->vadj, vval);
1415 * Show error message -> send signal "interpreter_message"
1418 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1420 gtk_signal_emit(GTK_OBJECT(gs),
1421 gtk_gs_signals[INTERPRETER_MESSAGE], g_strdup(msg));
1426 gtk_gs_center_page(GtkGS * gs)
1429 g_return_if_fail(gs != NULL);
1430 g_return_if_fail(GTK_IS_GS(gs));
1432 gdk_window_move(gs->pstarget,
1433 (gs->widget.allocation.width - gs->width) / 2,
1434 (gs->widget.allocation.height - gs->height) / 2);
1435 gs->hadj->page_size = ((gfloat) gs->widget.allocation.width) / gs->width;
1436 gs->hadj->page_size = MIN(gs->hadj->page_size, 1.0);
1437 gs->vadj->page_size = ((gfloat) gs->widget.allocation.height) / gs->height;
1438 gs->vadj->page_size = MIN(gs->vadj->page_size, 1.0);
1439 gs->hadj->value = 0.5 - gs->hadj->page_size / 2;
1440 gs->vadj->value = 0.5 - gs->vadj->page_size / 2;
1441 gtk_adjustment_changed(gs->hadj);
1442 gtk_adjustment_changed(gs->vadj);
1447 gtk_gs_scroll(GtkGS * gs, gint x_delta, gint y_delta)
1451 g_return_if_fail(gs != NULL);
1452 g_return_if_fail(GTK_IS_GS(gs));
1454 hval = gs->hadj->value + ((gfloat) x_delta) / gs->width;
1455 vval = gs->vadj->value + ((gfloat) y_delta) / gs->height;
1456 if(hval <= gs->hadj->upper - gs->hadj->page_size && hval >= gs->hadj->lower)
1457 gtk_adjustment_set_value(gs->hadj, hval);
1458 if(vval <= gs->vadj->upper - gs->vadj->page_size && vval >= gs->vadj->lower)
1459 gtk_adjustment_set_value(gs->vadj, vval);
1463 gtk_gs_disable_interpreter(GtkGS * gs)
1465 g_return_if_fail(gs != NULL);
1466 g_return_if_fail(GTK_IS_GS(gs));
1468 gs->disable_start = TRUE;
1469 if(GTK_WIDGET_REALIZED(GTK_WIDGET(gs)))
1470 stop_interpreter(gs);
1474 gtk_gs_load(GtkGS * gs, const gchar * fname)
1476 g_return_val_if_fail(gs != NULL, FALSE);
1477 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1479 /* clean up previous document */
1483 if(gs->pstarget != NULL && gdk_window_is_visible(gs->pstarget))
1484 gdk_window_hide(gs->pstarget);
1489 /* prepare this document */
1491 /* default values: no dsc information available */
1492 gs->structured_doc = FALSE;
1493 gs->send_filename_to_gs = TRUE;
1494 gs->current_page = -2;
1497 /* an absolute path */
1498 gs->gs_filename = g_strdup(fname);
1501 /* path relative to our cwd: make it absolute */
1502 gchar *cwd = g_get_current_dir();
1503 gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1507 if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1508 gs->send_filename_to_gs = FALSE;
1512 * We need to make sure that the file is loadable/exists!
1513 * otherwise we want to exit without loading new stuff...
1515 gchar *filename = NULL;
1517 if(!ggv_file_readable(fname)) {
1519 g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1520 gtk_gs_emit_error_msg(gs, buf);
1521 gs->gs_status = _("File is not readable.");
1524 filename = check_filecompressed(gs);
1526 filename = check_pdf(gs);
1529 if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1534 /* we grab the vital statistics!!! */
1535 gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1537 if(gs->doc == NULL) {
1538 /* File does not seem to be a Postscript one */
1540 g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1541 gtk_gs_emit_error_msg(gs, buf);
1543 gs->gs_status = _("The file is not a PostScript document.");
1547 if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1548 (gs->doc->epsf && gs->doc->numpages > 1)) {
1549 gs->structured_doc = TRUE;
1550 gs->send_filename_to_gs = FALSE;
1553 /* We have to set up the orientation of the document */
1556 /* orientation can only be portrait, and landscape or none.
1557 This is the document default. A document can have
1558 pages in landscape and some in portrait */
1559 if(gs->override_orientation) {
1560 /* If the orientation should be override...
1561 then gs->orientation has already the correct
1562 value (it was set when the widget was created */
1567 /* Otherwise, set the proper orientation for the doc */
1568 gs->real_orientation = gs->doc->orientation;
1571 gtk_gs_set_page_size(gs, -1, gs->current_page);
1574 gs->gs_status = _("Document loaded.");
1581 gtk_gs_next_page(GtkGS * gs)
1585 g_return_val_if_fail(gs != NULL, FALSE);
1586 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1588 if(gs->interpreter_pid == 0) { /* no interpreter active */
1592 if(gs->busy) { /* interpreter is busy */
1598 event.xclient.type = ClientMessage;
1599 event.xclient.display = gdk_display;
1600 event.xclient.window = gs->message_window;
1601 event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1602 event.xclient.format = 32;
1604 gdk_error_trap_push();
1605 XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1607 gdk_error_trap_pop();
1613 gtk_gs_get_current_page(GtkGS * gs)
1615 g_return_val_if_fail(gs != NULL, -1);
1616 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1618 return gs->current_page;
1622 gtk_gs_get_page_count(GtkGS * gs)
1624 if(!gs->gs_filename)
1628 if(gs->structured_doc)
1629 return gs->doc->numpages;
1638 gtk_gs_goto_page(GtkGS * gs, gint page)
1640 g_return_val_if_fail(gs != NULL, FALSE);
1641 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1643 if(!gs->gs_filename) {
1647 /* range checking... */
1651 if(gs->structured_doc && gs->doc) {
1652 if(page >= gs->doc->numpages)
1653 page = gs->doc->numpages - 1;
1655 if(page == gs->current_page && !gs->changed)
1658 gs->current_page = page;
1660 if(!GTK_WIDGET_REALIZED(gs))
1663 if(gs->doc->pages[page].orientation != NONE &&
1664 !gs->override_orientation &&
1665 gs->doc->pages[page].orientation != gs->real_orientation) {
1666 gs->real_orientation = gs->doc->pages[page].orientation;
1670 gtk_gs_set_page_size(gs, -1, page);
1672 gs->changed = FALSE;
1674 if(is_interpreter_ready(gs)) {
1675 gtk_gs_next_page(gs);
1678 gtk_gs_enable_interpreter(gs);
1679 send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1680 send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1683 send_ps(gs, gs->doc->pages[gs->current_page].begin,
1684 gs->doc->pages[gs->current_page].len, FALSE);
1687 /* Unstructured document */
1688 /* In the case of non structured documents,
1689 GS read the PS from the actual file (via command
1690 line. Hence, ggv only send a signal next page.
1691 If ghostview is not running it is usually because
1692 the last page of the file was displayed. In that
1693 case, ggv restarts GS again and the first page is displayed.
1695 if(page == gs->current_page && !gs->changed)
1698 if(!GTK_WIDGET_REALIZED(gs))
1701 if(!is_interpreter_ready(gs))
1702 gtk_gs_enable_interpreter(gs);
1704 gs->current_page = page;
1706 gtk_gs_next_page(gs);
1712 * set pagesize sets the size from
1713 * if new_pagesize is -1, then it is set to either
1714 * a) the default settings of pageid, if they exist, or if pageid != -1.
1715 * b) the default setting of the document, if it exists.
1716 * c) the default setting of the widget.
1717 * otherwise, the new_pagesize is used as the pagesize
1720 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1726 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1728 g_return_val_if_fail(gs != NULL, FALSE);
1729 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1731 if(new_pagesize == -1) {
1732 if(gs->default_size > 0)
1733 new_pagesize = gs->default_size;
1734 if(!gs->override_size && gs->doc) {
1735 /* If we have a document:
1736 We use -- the page size (if specified)
1737 or the doc. size (if specified)
1738 or the page bbox (if specified)
1741 if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1742 (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1743 new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1745 else if(gs->doc->default_page_size != NULL) {
1746 new_pagesize = gs->doc->default_page_size - gs->doc->size;
1748 else if((pageid >= 0) &&
1749 (gs->doc->numpages > pageid) &&
1751 (gs->doc->pages[pageid].boundingbox[URX] >
1752 gs->doc->pages[pageid].boundingbox[LLX]) &&
1753 (gs->doc->pages[pageid].boundingbox[URY] >
1754 gs->doc->pages[pageid].boundingbox[LLY])) {
1757 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1758 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1764 /* Compute bounding box */
1765 if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) { /* epsf or bbox */
1768 (gs->doc->pages[pageid].boundingbox[URX] >
1769 gs->doc->pages[pageid].boundingbox[LLX])
1770 && (gs->doc->pages[pageid].boundingbox[URY] >
1771 gs->doc->pages[pageid].boundingbox[LLY])) {
1773 new_llx = gs->doc->pages[pageid].boundingbox[LLX];
1774 new_lly = gs->doc->pages[pageid].boundingbox[LLY];
1775 new_urx = gs->doc->pages[pageid].boundingbox[URX];
1776 new_ury = gs->doc->pages[pageid].boundingbox[URY];
1778 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1779 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1781 new_llx = gs->doc->boundingbox[LLX];
1782 new_lly = gs->doc->boundingbox[LLY];
1783 new_urx = gs->doc->boundingbox[URX];
1784 new_ury = gs->doc->boundingbox[URY];
1788 if(new_pagesize < 0)
1789 new_pagesize = gs->default_size;
1790 new_llx = new_lly = 0;
1791 if(gs->doc && !gs->override_size && gs->doc->size &&
1792 (new_pagesize < gs->doc->numsizes)) {
1793 new_urx = gs->doc->size[new_pagesize].width;
1794 new_ury = gs->doc->size[new_pagesize].height;
1797 new_urx = papersizes[new_pagesize].width;
1798 new_ury = papersizes[new_pagesize].height;
1802 if(new_urx <= new_llx)
1803 new_urx = papersizes[12].width;
1804 if(new_ury <= new_lly)
1805 new_ury = papersizes[12].height;
1807 /* If bounding box changed, setup for new size. */
1808 /* gtk_gs_disable_interpreter (gs); */
1809 if((new_llx != gs->llx) || (new_lly != gs->lly) ||
1810 (new_urx != gs->urx) || (new_ury != gs->ury)) {
1819 if(GTK_WIDGET_REALIZED(gs)) {
1821 //gtk_widget_queue_resize(&(gs->widget));
1830 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
1832 gint iOldOrientation;
1834 g_return_if_fail(gs != NULL);
1835 g_return_if_fail(GTK_IS_GS(gs));
1837 iOldOrientation = gtk_gs_get_orientation(gs);
1839 gs->override_orientation = bNewOverride;
1841 /* If the current orientation is different from the
1842 new orientation then redisplay */
1843 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1845 if(GTK_WIDGET_REALIZED(gs))
1848 //gtk_widget_queue_resize(&(gs->widget));
1852 gtk_gs_get_override_orientation(GtkGS * gs)
1854 g_return_val_if_fail(gs != NULL, FALSE);
1855 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1857 return gs->override_orientation;
1861 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
1863 g_return_if_fail(gs != NULL);
1864 g_return_if_fail(GTK_IS_GS(gs));
1866 if(f != gs->override_size) {
1867 gs->override_size = f;
1869 gtk_gs_set_page_size(gs, -1, gs->current_page);
1870 if(GTK_WIDGET_REALIZED(gs))
1873 //gtk_widget_queue_resize(&(gs->widget));
1877 gtk_gs_get_override_size(GtkGS * gs)
1879 g_return_val_if_fail(gs != NULL, FALSE);
1880 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1882 return gs->override_size;
1886 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
1888 g_return_if_fail(gs != NULL);
1889 g_return_if_fail(GTK_IS_GS(gs));
1891 switch (gs->zoom_mode) {
1892 case GTK_GS_ZOOM_FIT_WIDTH:
1893 zoom = gtk_gs_zoom_to_fit(gs, TRUE);
1895 case GTK_GS_ZOOM_FIT_PAGE:
1896 zoom = gtk_gs_zoom_to_fit(gs, FALSE);
1898 case GTK_GS_ZOOM_ABSOLUTE:
1902 if(zoom < ggv_zoom_levels[0])
1903 zoom = ggv_zoom_levels[0];
1904 else if(zoom > ggv_zoom_levels[ggv_max_zoom_levels])
1905 zoom = ggv_zoom_levels[ggv_max_zoom_levels];
1906 if(fabs(gs->zoom_factor - zoom) > 0.001) {
1907 gs->zoom_factor = zoom;
1908 if(GTK_WIDGET_REALIZED(gs))
1911 //gtk_widget_queue_resize(&(gs->widget));
1916 gtk_gs_get_zoom(GtkGS * gs)
1918 g_return_val_if_fail(gs != NULL, 0.0);
1919 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1921 return gs->zoom_factor;
1925 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
1929 guint avail_w, avail_h;
1931 g_return_val_if_fail(gs != NULL, 0.0);
1932 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
1934 avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
1935 avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
1937 new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
1939 new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
1941 new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
1948 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
1950 gint iOldOrientation;
1952 g_return_val_if_fail(gs != NULL, FALSE);
1953 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1954 g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
1955 (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
1956 (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
1957 (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
1959 iOldOrientation = gtk_gs_get_orientation(gs);
1960 gs->fallback_orientation = orientation;
1962 /* We are setting the fallback orientation */
1963 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
1965 if(GTK_WIDGET_REALIZED(gs))
1967 //gtk_widget_queue_resize(&(gs->widget));
1975 gtk_gs_get_default_orientation(GtkGS * gs)
1977 g_return_val_if_fail(gs != NULL, -1);
1978 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1980 return gs->fallback_orientation;
1984 gtk_gs_get_orientation(GtkGS * gs)
1986 g_return_val_if_fail(gs != NULL, -1);
1987 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1990 if(gs->structured_doc) {
1991 if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
1992 GTK_GS_ORIENTATION_NONE)
1993 gs->real_orientation =
1994 gs->doc->pages[MAX(gs->current_page, 0)].orientation;
1996 gs->real_orientation = gs->doc->default_page_orientation;
1999 if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
2000 gs->real_orientation = gs->doc->orientation;
2003 if(gs->override_orientation ||
2004 gs->real_orientation == GTK_GS_ORIENTATION_NONE)
2005 return gs->fallback_orientation;
2007 return gs->real_orientation;
2011 gtk_gs_set_default_size(GtkGS * gs, gint size)
2013 g_return_if_fail(gs != NULL);
2014 g_return_if_fail(GTK_IS_GS(gs));
2016 gs->default_size = size;
2017 gtk_gs_set_page_size(gs, -1, gs->current_page);
2021 gtk_gs_get_default_size(GtkGS * gs)
2023 g_return_val_if_fail(gs != NULL, -1);
2024 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2026 return gs->default_size;
2030 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
2032 g_return_if_fail(gs != NULL);
2033 g_return_if_fail(GTK_IS_GS(gs));
2035 if(gs->respect_eof == f)
2038 gs->respect_eof = f;
2039 gtk_gs_set_page_size(gs, -1, gs->current_page);
2043 gtk_gs_get_respect_eof(GtkGS * gs)
2045 g_return_val_if_fail(gs != NULL, -1);
2046 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2048 return gs->respect_eof;
2052 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
2054 g_return_if_fail(gs != NULL);
2055 g_return_if_fail(GTK_IS_GS(gs));
2057 if(gs->antialiased == f)
2060 gs->antialiased = f;
2062 if(GTK_WIDGET_REALIZED(gs))
2063 start_interpreter(gs);
2064 gtk_gs_goto_page(gs, gs->current_page);
2068 gtk_gs_get_antialiasing(GtkGS * gs)
2070 g_return_val_if_fail(gs != NULL, -1);
2071 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2073 return gs->antialiased;
2077 gtk_gs_get_document_title(GtkGS * gs)
2079 g_return_val_if_fail(gs != NULL, NULL);
2080 g_return_val_if_fail(GTK_IS_GS(gs), NULL);
2082 if(gs->doc && gs->doc->title)
2083 return gs->doc->title;
2089 gtk_gs_get_document_numpages(GtkGS * widget)
2091 g_return_val_if_fail(widget != NULL, 0);
2092 g_return_val_if_fail(GTK_IS_GS(widget), 0);
2095 return widget->doc->numpages;
2101 gtk_gs_get_document_page_label(GtkGS * widget, int page)
2103 g_return_val_if_fail(widget != NULL, NULL);
2104 g_return_val_if_fail(GTK_IS_GS(widget), NULL);
2106 if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
2107 return widget->doc->pages[page - 1].label;
2113 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
2117 while(size[idx].name != NULL) {
2118 if(strcmp(size[idx].name, string) == 0)
2127 gtk_gs_start_scroll(GtkGS * gs)
2131 if(!GTK_WIDGET_REALIZED(gs) || !gs->show_scroll_rect)
2134 gdk_window_get_geometry(gs->pstarget, &x, &y, &w, &h, NULL);
2135 gs->scroll_start_x = MAX(-x, 0);
2136 gs->scroll_start_y = MAX(-y, 0);
2137 //gs->scroll_width = MIN(gs->widget.allocation.width - 1, w - 1);
2138 //gs->scroll_height = MIN(gs->widget.allocation.height - 1, h - 1);
2142 rect.x = gs->scroll_start_x;
2143 rect.y = gs->scroll_start_y;
2144 rect.width = gs->scroll_width + 1;
2145 rect.height = gs->scroll_height + 1;
2146 gdk_draw_rectangle(gs->bpixmap, gs->psgc, FALSE,
2147 gs->scroll_start_x, gs->scroll_start_y,
2148 gs->scroll_width, gs->scroll_height);
2150 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2151 rect.x = gs->scroll_start_x + gs->scroll_width;
2152 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2153 rect.x = gs->scroll_start_x + 1;
2154 rect.width = gs->scroll_start_x + gs->scroll_width - 1;
2156 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2157 rect.y = gs->scroll_start_y + gs->scroll_height;
2158 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2163 gtk_gs_end_scroll(GtkGS * gs)
2165 if(!GTK_WIDGET_REALIZED(gs) || !gs->show_scroll_rect)
2168 if(gs->scroll_start_x == -1 || gs->scroll_start_y == -1)
2173 rect.x = gs->scroll_start_x;
2174 rect.y = gs->scroll_start_y;
2175 rect.width = gs->scroll_width + 1;
2176 rect.height = gs->scroll_height + 1;
2177 gdk_draw_rectangle(gs->bpixmap, gs->psgc, FALSE,
2178 gs->scroll_start_x, gs->scroll_start_y,
2179 gs->scroll_width, gs->scroll_height);
2181 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2182 rect.x = gs->scroll_start_x + gs->scroll_width;
2183 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2184 rect.x = gs->scroll_start_x + 1;
2185 rect.width = gs->scroll_start_x + gs->scroll_width - 1;
2187 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2188 rect.y = gs->scroll_start_y + gs->scroll_height;
2189 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2191 gs->scroll_start_x = -1;
2192 gs->scroll_start_y = -1;
2196 gtk_gs_set_show_scroll_rect(GtkGS * gs, gboolean f)
2198 gs->show_scroll_rect = f;
2202 gtk_gs_get_show_scroll_rect(GtkGS * gs)
2204 return gs->show_scroll_rect;
2208 gtk_gs_scroll_to_edge(GtkGS * gs, GtkPositionType vertical,
2209 GtkPositionType horizontal)
2211 g_return_val_if_fail(gs != NULL, FALSE);
2212 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2216 gs->vadj->value = gs->vadj->lower;
2217 gtk_adjustment_value_changed(gs->vadj);
2219 case GTK_POS_BOTTOM:
2220 gs->vadj->value = gs->vadj->upper - gs->vadj->page_size;
2221 gtk_adjustment_value_changed(gs->vadj);
2224 g_assert(0); /* Illegal parameter error */
2228 switch (horizontal) {
2230 gs->hadj->value = gs->hadj->lower;
2231 gtk_adjustment_value_changed(gs->hadj);
2233 case GTK_POS_BOTTOM:
2234 gs->hadj->value = gs->hadj->upper - gs->hadj->page_size;
2235 gtk_adjustment_value_changed(gs->hadj);
2238 g_assert(0); /* Illegal parameter error */
2245 gtk_gs_scroll_step(GtkGS * gs, GtkScrollType direction, gboolean dowrap)
2247 GtkAdjustment *MainAdj; /* We will move this adjustment */
2248 GtkAdjustment *SecoAdj; /* And this _only_ if we can't move MainAdj (ie. we're edge)
2249 and there is wrapping */
2251 gboolean MoveHorizontal = TRUE; /* Positive if we move horizontal */
2252 gboolean DirectionFlag = TRUE; /* Positive if we move towards upper */
2253 g_return_val_if_fail(gs != NULL, FALSE);
2254 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2256 #define EPSILON 0.00005
2258 #define CHECK_THERE_IS_NO_LOWER_SPACE(adj) \
2259 ((adj)->value - (EPSILON) <= (adj)->lower)
2260 #define CHECK_THERE_IS_NO_UPPER_SPACE(adj) \
2261 ((adj)->value + (EPSILON) >= (adj)->upper - (adj)->page_size)
2263 #define CHECK_THERE_IS_NO_SPACE_FOR_STEP(adj,dir) \
2264 (dir?CHECK_THERE_IS_NO_UPPER_SPACE(adj):CHECK_THERE_IS_NO_LOWER_SPACE(adj))
2266 /* To make code more readable, we make a macro */
2267 #define ADVANCE_TOWARDS_LOWER(adj) \
2268 (adj->value -= gs->scroll_step * (adj->page_size))
2269 #define ADVANCE_TOWARDS_UPPER(adj) \
2270 (adj->value += gs->scroll_step * (adj->page_size))
2272 #define ADVANCE_STEP(adj,dir) \
2273 (dir?ADVANCE_TOWARDS_UPPER(adj):ADVANCE_TOWARDS_LOWER(adj))
2275 #define MOVE_TO_LOWER_EDGE(adj) \
2276 (adj->value = adj->lower)
2277 #define MOVE_TO_UPPER_EDGE(adj) \
2278 (adj->value = adj->upper - adj->page_size)
2280 /* if upper is 1 goto upper, otherwise to lower */
2281 #define MOVE_TO_EDGE(adj,upper) (upper?MOVE_TO_UPPER_EDGE(adj):MOVE_TO_LOWER_EDGE(adj))
2283 /* These variables make our life easier */
2284 switch (direction) {
2285 case GTK_SCROLL_STEP_RIGHT:
2286 MoveHorizontal = TRUE;
2287 DirectionFlag = TRUE;
2289 case GTK_SCROLL_STEP_LEFT:
2290 MoveHorizontal = TRUE;
2291 DirectionFlag = FALSE;
2293 case GTK_SCROLL_STEP_DOWN:
2294 MoveHorizontal = FALSE;
2295 DirectionFlag = TRUE;
2297 case GTK_SCROLL_STEP_UP:
2298 MoveHorizontal = FALSE;
2299 DirectionFlag = FALSE;
2302 g_warning("Illegal scroll step direction.");
2305 if(MoveHorizontal) {
2314 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(MainAdj, DirectionFlag)) {
2317 /* Move in the oposite axis */
2318 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(SecoAdj, DirectionFlag)) {
2319 /* there is no place to move, we need a new page */
2322 ADVANCE_STEP(SecoAdj, DirectionFlag);
2324 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(SecoAdj, DirectionFlag)) {
2325 /* We move it too far, lets move it to the edge */
2326 MOVE_TO_EDGE(SecoAdj, DirectionFlag);
2328 /* now move to edge (other axis) in oposite direction */
2329 MOVE_TO_EDGE(MainAdj, !DirectionFlag);
2330 gtk_adjustment_value_changed(SecoAdj);
2334 /* Now we know we can move in the direction sought */
2335 ADVANCE_STEP(MainAdj, DirectionFlag);
2337 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(MainAdj, DirectionFlag)) {
2338 /* We move it too far, lets move it to the edge */
2339 MOVE_TO_EDGE(MainAdj, DirectionFlag);
2341 gtk_adjustment_value_changed(MainAdj);
2347 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
2351 gboolean free_pages = FALSE;
2354 if(!gs->structured_doc) {
2358 if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
2360 doc = g_new(gchar, sb.st_size);
2363 f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
2364 if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
2373 int i, n = gtk_gs_get_page_count(gs);
2374 pages = g_new0(gint, n);
2375 for(i = 0; i < n; i++)
2381 sink = gtk_gs_doc_sink_new();
2383 if(GTK_GS_IS_PDF(gs)) {
2384 gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2388 if((tmpfd = mkstemp(tmpn)) < 0) {
2393 fname = ggv_quote_filename(gs->gs_filename_unc ?
2394 gs->gs_filename_unc : gs->gs_filename);
2395 cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2397 if((system(cmd) == 0) && ggv_file_readable(tmpn)) {
2399 tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2400 if(NULL != tmp_gs) {
2401 if(GTK_GS(tmp_gs)->loaded)
2402 pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2403 g_object_unref(tmp_gs);
2410 /* Use uncompressed file if necessary */
2411 pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2415 doc = gtk_gs_doc_sink_get_buffer(sink);
2416 gtk_gs_doc_sink_free(sink);
2421 gtk_gs_set_adjustments(GtkGS * gs, GtkAdjustment * hadj, GtkAdjustment * vadj)
2423 g_return_if_fail(gs != NULL);
2424 g_return_if_fail(GTK_IS_GS(gs));
2426 g_return_if_fail(GTK_IS_ADJUSTMENT(hadj));
2428 hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.0, 0.0, 1.0));
2430 g_return_if_fail(GTK_IS_ADJUSTMENT(vadj));
2432 vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.0, 0.0, 1.0));
2434 if(gs->hadj && (gs->hadj != hadj)) {
2435 g_signal_handlers_disconnect_matched(G_OBJECT(gs->hadj),
2436 G_SIGNAL_MATCH_DATA,
2437 0, 0, NULL, NULL, gs);
2438 gtk_object_unref(GTK_OBJECT(gs->hadj));
2440 if(gs->vadj && (gs->vadj != vadj)) {
2441 g_signal_handlers_disconnect_matched(G_OBJECT(gs->vadj),
2442 G_SIGNAL_MATCH_DATA,
2443 0, 0, NULL, NULL, gs);
2444 gtk_object_unref(GTK_OBJECT(gs->vadj));
2446 if(gs->hadj != hadj) {
2450 hadj->page_size = 1.0;
2451 hadj->page_increment = 1.0;
2453 gtk_object_ref(GTK_OBJECT(gs->hadj));
2454 gtk_object_sink(GTK_OBJECT(gs->hadj));
2456 g_signal_connect(G_OBJECT(hadj), "value_changed",
2457 G_CALLBACK(gtk_gs_value_adjustment_changed),
2460 if(gs->vadj != vadj) {
2464 vadj->page_size = 1.0;
2465 vadj->page_increment = 1.0;
2467 gtk_object_ref(GTK_OBJECT(gs->vadj));
2468 gtk_object_sink(GTK_OBJECT(gs->vadj));
2470 g_signal_connect(G_OBJECT(vadj), "value_changed",
2471 G_CALLBACK(gtk_gs_value_adjustment_changed),
2474 //if(GTK_WIDGET_REALIZED(gs))
2475 //gtk_gs_munge_adjustments(gs);
2480 gtk_gs_set_scroll_step(GtkGS * gs, gfloat scroll_step)
2482 gs->scroll_step = scroll_step;
2486 gtk_gs_get_scroll_step(GtkGS * gs)
2488 return gs->scroll_step;
2492 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2494 if(zoom_mode != gs->zoom_mode) {
2495 gs->zoom_mode = zoom_mode;
2496 gtk_gs_set_zoom(gs, 1.0);
2501 gtk_gs_get_zoom_mode(GtkGS * gs)
2503 return gs->zoom_mode;
2507 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2509 gs->avail_w = avail_w;
2510 gs->avail_h = avail_h;
2511 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2512 gtk_gs_set_zoom(gs, 0.0);
2517 ps_document_load (EvDocument *document,
2521 return gtk_gs_load (GTK_GS (document), uri);
2525 ps_document_get_n_pages (EvDocument *document)
2527 return gtk_gs_get_page_count (GTK_GS (document));
2531 ps_document_set_page (EvDocument *document,
2534 gtk_gs_goto_page (GTK_GS (document), page);
2538 ps_document_get_page (EvDocument *document)
2540 return gtk_gs_get_current_page (GTK_GS (document));
2544 ps_document_set_target (EvDocument *document,
2545 GdkDrawable *target)
2547 GTK_GS (document)->pstarget = target;
2551 ps_document_set_scale (EvDocument *document,
2554 gtk_gs_set_zoom (GTK_GS (document), scale);
2558 ps_document_set_page_offset (EvDocument *document,
2565 ps_document_get_page_size (EvDocument *document,
2572 ps_document_render (EvDocument *document,
2578 GtkGS *gs = GTK_GS (document);
2580 start_interpreter(gs);
2581 gtk_gs_goto_page(gs, gs->current_page);
2585 ps_document_begin_find (EvDocument *document,
2586 const char *search_string,
2587 gboolean case_sensitive)
2592 ps_document_end_find (EvDocument *document)
2597 ps_document_document_iface_init (EvDocumentIface *iface)
2599 iface->load = ps_document_load;
2600 iface->get_n_pages = ps_document_get_n_pages;
2601 iface->set_page = ps_document_set_page;
2602 iface->get_page = ps_document_get_page;
2603 iface->set_scale = ps_document_set_scale;
2604 iface->set_target = ps_document_set_target;
2605 iface->set_page_offset = ps_document_set_page_offset;
2606 iface->get_page_size = ps_document_get_page_size;
2607 iface->render = ps_document_render;
2608 iface->begin_find = ps_document_begin_find;
2609 iface->end_find = ps_document_end_find;