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>
152 #include "ggvutils.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_destroy(GtkObject * object);
184 static void gtk_gs_realize(GtkWidget * widget);
185 static void gtk_gs_size_request(GtkWidget * widget,
186 GtkRequisition * requisition);
187 static void gtk_gs_size_allocate(GtkWidget * widget,
188 GtkAllocation * allocation);
189 static gint gtk_gs_widget_event(GtkWidget * widget, GdkEvent * event,
191 static void gtk_gs_value_adjustment_changed(GtkAdjustment * adjustment,
193 static void gtk_gs_interpreter_message(GtkGS * gs, gchar * msg,
195 static void gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg);
196 static void gtk_gs_set_adjustments(GtkGS * gs, GtkAdjustment * hadj,
197 GtkAdjustment * vadj);
198 static void send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close);
199 static void set_up_page(GtkGS * gs);
200 static void close_pipe(int p[2]);
201 static void interpreter_failed(GtkGS * gs);
202 static float compute_xdpi(void);
203 static float compute_ydpi(void);
204 static gboolean compute_size(GtkGS * gs);
205 static void output(gpointer data, gint source, GdkInputCondition condition);
206 static void input(gpointer data, gint source, GdkInputCondition condition);
207 static void stop_interpreter(GtkGS * gs);
208 static gint start_interpreter(GtkGS * gs);
209 gboolean computeSize(void);
211 static GtkWidgetClass *parent_class = NULL;
213 static GtkGSClass *gs_class = NULL;
215 static gint gtk_gs_signals[LAST_SIGNAL] = { 0 };
217 /* Static, private functions */
220 ggv_marshaller_VOID__POINTER(GClosure * closure,
221 GValue * return_value,
222 guint n_param_values,
223 const GValue * param_values,
224 gpointer invocation_hint, gpointer marshal_data)
226 typedef void (*GMarshalFunc_VOID__POINTER) (gpointer data1,
227 gpointer arg_1, gpointer data2);
228 register GMarshalFunc_VOID__POINTER callback;
229 register GCClosure *cc = (GCClosure *) closure;
230 register gpointer data1, data2;
232 g_return_if_fail(n_param_values == 2);
234 if(G_CCLOSURE_SWAP_DATA(closure)) {
235 data1 = closure->data;
236 data2 = g_value_peek_pointer(param_values + 0);
239 data1 = g_value_peek_pointer(param_values + 0);
240 data2 = closure->data;
243 (GMarshalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
245 callback(data1, g_value_get_pointer(param_values + 1), data2);
249 ggv_marshaller_VOID__INT(GClosure * closure,
250 GValue * return_value,
251 guint n_param_values,
252 const GValue * param_values,
253 gpointer invocation_hint, gpointer marshal_data)
255 typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
256 gint arg_1, gpointer data2);
257 register GMarshalFunc_VOID__INT callback;
258 register GCClosure *cc = (GCClosure *) closure;
259 register gpointer data1, data2;
261 g_return_if_fail(n_param_values == 2);
263 if(G_CCLOSURE_SWAP_DATA(closure)) {
264 data1 = closure->data;
265 data2 = g_value_peek_pointer(param_values + 0);
268 data1 = g_value_peek_pointer(param_values + 0);
269 data2 = closure->data;
272 (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
274 callback(data1, g_value_get_int(param_values + 1), data2);
278 ggv_marshaller_VOID__POINTER_POINTER(GClosure * closure,
279 GValue * return_value,
280 guint n_param_values,
281 const GValue * param_values,
282 gpointer invocation_hint,
283 gpointer marshal_data)
285 typedef void (*GMarshalFunc_VOID__POINTER_POINTER) (gpointer data1,
289 register GMarshalFunc_VOID__POINTER_POINTER callback;
290 register GCClosure *cc = (GCClosure *) closure;
291 register gpointer data1, data2;
293 g_return_if_fail(n_param_values == 3);
295 if(G_CCLOSURE_SWAP_DATA(closure)) {
296 data1 = closure->data;
297 data2 = g_value_peek_pointer(param_values + 0);
300 data1 = g_value_peek_pointer(param_values + 0);
301 data2 = closure->data;
304 (GMarshalFunc_VOID__POINTER_POINTER) (marshal_data ? marshal_data : cc->
308 g_value_get_pointer(param_values + 1),
309 g_value_get_pointer(param_values + 2), data2);
313 gtk_gs_init(GtkGS * gs)
316 gs->use_bpixmap = TRUE;
318 gs->current_page = -2;
319 gs->disable_start = FALSE;
320 gs->interpreter_pid = -1;
326 gs->gs_scanstyle = 0;
328 gs->gs_filename_dsc = 0;
329 gs->gs_filename_unc = 0;
333 gs->structured_doc = FALSE;
334 gs->reading_from_pipe = FALSE;
335 gs->send_filename_to_gs = FALSE;
340 gs->interpreter_input = -1;
341 gs->interpreter_output = -1;
342 gs->interpreter_err = -1;
343 gs->interpreter_input_id = 0;
344 gs->interpreter_output_id = 0;
345 gs->interpreter_error_id = 0;
348 gs->input_buffer = NULL;
349 gs->input_buffer_ptr = NULL;
351 gs->buffer_bytes_left = 0;
357 gs->xdpi = compute_xdpi();
358 gs->ydpi = compute_ydpi();
362 gs->right_margin = 0;
363 gs->bottom_margin = 0;
365 /* Set user defined defaults */
366 gs->override_orientation = gtk_gs_defaults_get_override_orientation();
367 gs->fallback_orientation = gtk_gs_defaults_get_orientation();
368 gs->zoom_factor = gtk_gs_defaults_get_zoom_factor();
369 gs->default_size = gtk_gs_defaults_get_size();
370 gs->antialiased = gtk_gs_defaults_get_antialiased();
371 gs->override_size = gtk_gs_defaults_get_override_size();
372 gs->respect_eof = gtk_gs_defaults_get_respect_eof();
373 gs->show_scroll_rect = gtk_gs_defaults_get_show_scroll_rect();
374 gs->scroll_step = gtk_gs_defaults_get_scroll_step();
375 gs->zoom_mode = gtk_gs_defaults_get_zoom_mode();
377 gs->scroll_start_x = gs->scroll_start_y = -1;
379 gs->gs_status = _("No document loaded.");
383 gtk_gs_class_init(GtkGSClass * klass)
385 GtkObjectClass *object_class;
386 GObjectClass *gobject_class;
387 GtkWidgetClass *widget_class;
389 object_class = (GtkObjectClass *) klass;
390 gobject_class = (GObjectClass *) klass;
391 widget_class = (GtkWidgetClass *) klass;
392 parent_class = gtk_type_class(gtk_widget_get_type());
395 gtk_gs_signals[INTERPRETER_MESSAGE] = g_signal_new("interpreter_message",
401 interpreter_message),
403 ggv_marshaller_VOID__POINTER,
406 gtk_gs_signals[INTERPRETER_ERROR] =
407 g_signal_new("interpreter_error", G_TYPE_FROM_CLASS(object_class),
408 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkGSClass,
410 NULL, NULL, ggv_marshaller_VOID__INT, G_TYPE_NONE, 1,
413 object_class->destroy = gtk_gs_destroy;
415 widget_class->realize = gtk_gs_realize;
416 widget_class->size_request = gtk_gs_size_request;
417 widget_class->size_allocate = gtk_gs_size_allocate;
418 widget_class->set_scroll_adjustments_signal =
419 g_signal_new("set_scroll_adjustments",
420 G_TYPE_FROM_CLASS(object_class),
422 G_STRUCT_OFFSET(GtkGSClass, set_scroll_adjustments),
425 ggv_marshaller_VOID__POINTER_POINTER,
426 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
429 klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
430 klass->gs_colors_atom = gdk_atom_intern("GHOSTVIEW_COLORS", FALSE);
431 klass->next_atom = gdk_atom_intern("NEXT", FALSE);
432 klass->page_atom = gdk_atom_intern("PAGE", FALSE);
433 klass->done_atom = gdk_atom_intern("DONE", FALSE);
434 klass->string_atom = gdk_atom_intern("STRING", FALSE);
436 /* a default handler for "interpreter_message" signal */
437 klass->interpreter_message = gtk_gs_interpreter_message;
438 /* supply a scrollable interface */
439 klass->set_scroll_adjustments = gtk_gs_set_adjustments;
441 gtk_gs_defaults_load();
444 /* Clean all memory and temporal files */
446 gtk_gs_cleanup(GtkGS * gs)
448 g_return_if_fail(gs != NULL);
449 g_return_if_fail(GTK_IS_GS(gs));
451 stop_interpreter(gs);
454 fclose(gs->gs_psfile);
455 gs->gs_psfile = NULL;
457 if(gs->gs_filename) {
458 g_free(gs->gs_filename);
459 gs->gs_filename = NULL;
465 if(gs->gs_filename_dsc) {
466 unlink(gs->gs_filename_dsc);
467 g_free(gs->gs_filename_dsc);
468 gs->gs_filename_dsc = NULL;
470 if(gs->gs_filename_unc) {
471 unlink(gs->gs_filename_unc);
472 g_free(gs->gs_filename_unc);
473 gs->gs_filename_unc = NULL;
475 if(gs->pstarget && gdk_window_is_visible(gs->pstarget))
476 gdk_window_hide(gs->pstarget);
477 gs->current_page = -1;
486 /* free message as it was allocated in output() */
488 gtk_gs_interpreter_message(GtkGS * gs, gchar * msg, gpointer user_data)
490 gdk_pointer_ungrab(GDK_CURRENT_TIME);
491 if(strstr(msg, "Error:")) {
492 gs->gs_status = _("File is not a valid PostScript document.");
494 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", 1, NULL);
500 gtk_gs_destroy(GtkObject * object)
504 g_return_if_fail(object != NULL);
505 g_return_if_fail(GTK_IS_GS(object));
511 if(gs->input_buffer) {
512 g_free(gs->input_buffer);
513 gs->input_buffer = NULL;
516 g_signal_handlers_disconnect_matched(G_OBJECT(gs->hadj),
518 0, 0, NULL, NULL, gs);
519 gtk_object_unref(GTK_OBJECT(gs->hadj));
523 g_signal_handlers_disconnect_matched(G_OBJECT(gs->vadj),
525 0, 0, NULL, NULL, gs);
526 gtk_object_unref(GTK_OBJECT(gs->vadj));
530 if(GTK_OBJECT_CLASS(parent_class)->destroy)
531 (*GTK_OBJECT_CLASS(parent_class)->destroy) (object);
534 /* FIXME: I'm not sure if all this is supposed to be here
535 * this is just a quick hack so that this can be called whenever
539 gtk_gs_munge_adjustments(GtkGS * gs)
543 gdk_window_get_position(gs->pstarget, &x, &y);
546 * This is a bit messy:
547 * we want to make sure that we do the right thing if dragged.
549 if(gs->widget.allocation.width >= gs->width ||
550 gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
551 x = (gs->widget.allocation.width - gs->width) / 2;
552 gs->hadj->value = 0.0;
553 gs->hadj->page_size = 1.0;
554 gs->hadj->step_increment = 1.0;
559 else if(gs->widget.allocation.width > x + gs->width)
560 x = gs->widget.allocation.width - gs->width;
561 gs->hadj->page_size = ((gfloat) gs->widget.allocation.width) / gs->width;
562 gs->hadj->page_increment = gs->hadj->page_size * 0.9;
563 gs->hadj->step_increment = gs->scroll_step * gs->hadj->page_size;
564 gs->hadj->value = -((gfloat) x) / gs->width;
566 if(gs->widget.allocation.height >= gs->height ||
567 gs->zoom_mode == GTK_GS_ZOOM_FIT_PAGE) {
568 y = (gs->widget.allocation.height - gs->height) / 2;
569 gs->vadj->value = 0.0;
570 gs->vadj->page_size = 1.0;
571 gs->vadj->step_increment = 1.0;
576 else if(gs->widget.allocation.height > y + gs->height)
577 y = gs->widget.allocation.height - gs->height;
578 gs->vadj->page_size = ((gfloat) gs->widget.allocation.height) / gs->height;
579 gs->vadj->page_increment = gs->vadj->page_size * 0.9;
580 gs->vadj->step_increment = gs->scroll_step * gs->vadj->page_size;
581 gs->vadj->value = -((gfloat) y) / gs->height;
584 gdk_window_move(gs->pstarget, x, y);
586 gtk_adjustment_changed(gs->hadj);
587 gtk_adjustment_changed(gs->vadj);
591 gtk_gs_realize(GtkWidget * widget)
594 GdkWindowAttr attributes;
595 gint attributes_mask;
597 g_return_if_fail(widget != NULL);
598 g_return_if_fail(GTK_IS_GS(widget));
602 /* we set up the main widget! */
603 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
604 attributes.window_type = GDK_WINDOW_CHILD;
605 attributes.x = widget->allocation.x;
606 attributes.y = widget->allocation.y;
607 attributes.width = widget->allocation.width;
608 attributes.height = widget->allocation.height;
609 attributes.wclass = GDK_INPUT_OUTPUT;
610 attributes.visual = gtk_widget_get_visual(widget);
611 attributes.colormap = gtk_widget_get_colormap(widget);
612 attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
613 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
616 gdk_window_new(widget->parent->window, &attributes, attributes_mask);
617 gdk_window_set_user_data(widget->window, gs);
618 widget->style = gtk_style_attach(widget->style, widget->window);
619 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
621 /* now we set up the child window. This is the one that ps actually draws too. */
625 gs->pstarget = gdk_window_new(widget->window, &attributes, attributes_mask);
626 gdk_window_set_user_data(gs->pstarget, widget);
627 gdk_window_clear(gs->pstarget);
628 gtk_style_set_background(widget->style, gs->pstarget, GTK_STATE_ACTIVE);
629 gs->psgc = gdk_gc_new(gs->pstarget);
630 gdk_gc_set_function(gs->psgc, GDK_INVERT);
635 gtk_gs_set_page_size(gs, -1, 0);
637 if((gs->width > 0) && (gs->height > 0) && GTK_WIDGET_REALIZED(gs)) {
638 gtk_gs_munge_adjustments(gs);
641 g_signal_connect(G_OBJECT(widget), "event",
642 G_CALLBACK(gtk_gs_widget_event), gs);
644 gtk_gs_goto_page(gs, gs->current_page);
648 gtk_gs_size_request(GtkWidget * widget, GtkRequisition * requisition)
650 GtkGS *gs = GTK_GS(widget);
653 requisition->width = gs->width;
654 requisition->height = gs->height;
658 gtk_gs_size_allocate(GtkWidget * widget, GtkAllocation * allocation)
660 GtkGS *gs = GTK_GS(widget);
661 GdkEventConfigure event;
663 g_return_if_fail(widget != NULL);
664 g_return_if_fail(GTK_IS_GS(widget));
665 g_return_if_fail(allocation != NULL);
667 widget->allocation = *allocation;
668 if(GTK_WIDGET_REALIZED(widget)) {
669 gdk_window_move_resize(widget->window,
670 allocation->x, allocation->y,
671 allocation->width, allocation->height);
673 event.type = GDK_CONFIGURE;
674 event.window = widget->window;
675 event.x = allocation->x;
676 event.y = allocation->y;
677 event.width = allocation->width;
678 event.height = allocation->height;
679 gtk_widget_event(widget, (GdkEvent *) & event);
683 * update the adjustment if necessary (ie. a resize);
686 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
687 gtk_gs_set_zoom(gs, 0.0);
691 if(GTK_WIDGET_REALIZED(gs)) {
692 gtk_gs_munge_adjustments(gs);
695 gtk_gs_goto_page(gs, gs->current_page);
699 gtk_gs_widget_event(GtkWidget * widget, GdkEvent * event, gpointer data)
701 GtkGS *gs = (GtkGS *) data;
702 if(event->type != GDK_CLIENT_EVENT)
705 /* the first long is the window to communicate with gs,
706 only if event if client_event */
707 gs->message_window = event->client.data.l[0];
709 if(event->client.message_type == gs_class->page_atom) {
717 gtk_gs_value_adjustment_changed(GtkAdjustment * adjustment, gpointer data)
720 gint x, y, width, height, depth;
723 g_return_if_fail(adjustment != NULL);
724 g_return_if_fail(data != NULL);
726 if(gs->bpixmap == NULL)
730 g_print("Adjustment %c: val = %f, page = %f, upper = %f, lower = %f\n",
731 (adjustment == gs->hadj) ? 'H' : 'V',
732 adjustment->value, adjustment->page_size,
733 adjustment->upper, adjustment->lower);
736 gdk_window_get_geometry(gs->pstarget, &x, &y, &width, &height, &depth);
737 if(gs->width <= gs->widget.allocation.width)
738 newx = (gs->widget.allocation.width - gs->width) / 2;
740 newx = -gs->hadj->value * gs->width;
741 if(gs->height <= gs->widget.allocation.height)
742 newy = (gs->widget.allocation.height - gs->height) / 2;
744 newy = -gs->vadj->value * gs->height;
746 gdk_window_move(gs->pstarget, newx, newy);
750 gtk_gs_set_center(GtkGS * gs, gfloat hval, gfloat vval)
752 if(hval <= gs->hadj->upper - gs->hadj->page_size / 2 &&
753 hval >= gs->hadj->lower + gs->hadj->page_size / 2)
754 gtk_adjustment_set_value(gs->hadj, hval);
755 if(vval <= gs->vadj->upper - gs->vadj->page_size / 2 &&
756 vval >= gs->vadj->lower + gs->vadj->page_size / 2)
757 gtk_adjustment_set_value(gs->vadj, vval);
761 send_ps(GtkGS * gs, long begin, unsigned int len, gboolean close)
763 struct record_list *ps_new;
765 if(gs->interpreter_input < 0) {
766 g_critical("No pipe to gs: error in send_ps().");
770 ps_new = (struct record_list *) g_malloc(sizeof(struct record_list));
771 ps_new->fp = gs->gs_psfile;
772 ps_new->begin = begin;
774 ps_new->seek_needed = TRUE;
775 ps_new->close = close;
778 if(gs->input_buffer == NULL) {
779 gs->input_buffer = g_malloc(MAX_BUFSIZE);
782 if(gs->ps_input == NULL) {
783 gs->input_buffer_ptr = gs->input_buffer;
784 gs->bytes_left = len;
785 gs->buffer_bytes_left = 0;
786 gs->ps_input = ps_new;
787 gs->interpreter_input_id =
788 gdk_input_add(gs->interpreter_input, GDK_INPUT_WRITE, input, gs);
791 struct record_list *p = gs->ps_input;
792 while(p->next != NULL) {
800 set_up_page(GtkGS * gs)
802 * This is used to prepare the widget internally for
803 * a new document. It sets gs->pstarget to the
804 * correct size and position, and updates the
805 * adjustments appropriately.
807 * It is not meant to be used every time a specific page
810 * NOTE: It expects the widget is realized.
816 GdkColormap *colormap;
818 GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */
824 if(!GTK_WIDGET_REALIZED(gs))
827 /* Do we have to check if the actual geometry changed? */
829 stop_interpreter(gs);
831 orientation = gtk_gs_get_orientation(gs);
833 if(compute_size(gs)) {
836 /* clear new pixmap (set to white) */
837 fill = gdk_gc_new(gs->pstarget);
839 colormap = gtk_widget_get_colormap(GTK_WIDGET(gs));
840 gdk_color_alloc(colormap, &white);
841 gdk_gc_set_foreground(fill, &white);
843 if(gs->use_bpixmap && gs->width > 0 && gs->height > 0) {
845 gdk_drawable_unref(gs->bpixmap);
849 gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
851 gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
852 0, 0, gs->width, gs->height);
854 gdk_window_set_back_pixmap(gs->pstarget, gs->bpixmap, FALSE);
857 gdk_draw_rectangle(gs->pstarget, fill, TRUE,
858 0, 0, gs->width, gs->height);
862 gdk_window_resize(gs->pstarget, gs->width, gs->height);
869 /* gs needs floating point parameters with '.' as decimal point
870 * while some (european) locales use ',' instead, so we set the
871 * locale for this snprintf to "C".
873 savelocale = setlocale(LC_NUMERIC, "C");
875 pprivate = (GdkPixmap *) gs->bpixmap;
877 g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
878 pprivate ? gdk_x11_drawable_get_xid(pprivate) : 0L,
884 gs->xdpi * gs->zoom_factor,
885 gs->ydpi * gs->zoom_factor,
887 gs->bottom_margin, gs->right_margin, gs->top_margin);
890 setlocale(LC_NUMERIC, savelocale);
892 gdk_property_change(gs->pstarget,
894 gs_class->string_atom,
895 8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
909 is_interpreter_ready(GtkGS * gs)
911 return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
915 interpreter_failed(GtkGS * gs)
917 stop_interpreter(gs);
921 output(gpointer data, gint source, GdkInputCondition condition)
923 char buf[MAX_BUFSIZE + 1], *msg;
925 GtkGS *gs = GTK_GS(data);
927 if(source == gs->interpreter_output) {
928 bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE);
929 if(bytes == 0) { /* EOF occurred */
930 close(gs->interpreter_output);
931 gs->interpreter_output = -1;
932 gdk_input_remove(gs->interpreter_output_id);
935 else if(bytes == -1) {
937 interpreter_failed(gs);
940 if(gs->interpreter_err == -1) {
941 stop_interpreter(gs);
944 else if(source == gs->interpreter_err) {
945 bytes = read(gs->interpreter_err, buf, MAX_BUFSIZE);
946 if(bytes == 0) { /* EOF occurred */
947 close(gs->interpreter_err);
948 gs->interpreter_err = -1;
949 gdk_input_remove(gs->interpreter_error_id);
952 else if(bytes == -1) {
954 interpreter_failed(gs);
957 if(gs->interpreter_output == -1) {
958 stop_interpreter(gs);
964 gtk_signal_emit(GTK_OBJECT(gs), gtk_gs_signals[INTERPRETER_MESSAGE], msg);
969 input(gpointer data, gint source, GdkInputCondition condition)
971 GtkGS *gs = GTK_GS(data);
973 void (*oldsig) (int);
974 oldsig = signal(SIGPIPE, catchPipe);
977 if(gs->buffer_bytes_left == 0) {
978 /* Get a new section if required */
979 if(gs->ps_input && gs->bytes_left == 0) {
980 struct record_list *ps_old = gs->ps_input;
981 gs->ps_input = ps_old->next;
982 if(ps_old->close && NULL != ps_old->fp)
984 g_free((char *) ps_old);
986 /* Have to seek at the beginning of each section */
987 if(gs->ps_input && gs->ps_input->seek_needed) {
988 fseek(gs->ps_input->fp, gs->ps_input->begin, SEEK_SET);
989 gs->ps_input->seek_needed = FALSE;
990 gs->bytes_left = gs->ps_input->len;
993 if(gs->bytes_left > MAX_BUFSIZE) {
994 gs->buffer_bytes_left =
995 fread(gs->input_buffer, sizeof(char), MAX_BUFSIZE, gs->ps_input->fp);
997 else if(gs->bytes_left > 0) {
998 gs->buffer_bytes_left =
999 fread(gs->input_buffer,
1000 sizeof(char), gs->bytes_left, gs->ps_input->fp);
1003 gs->buffer_bytes_left = 0;
1005 if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
1006 interpreter_failed(gs); /* Error occurred */
1008 gs->input_buffer_ptr = gs->input_buffer;
1009 gs->bytes_left -= gs->buffer_bytes_left;
1012 if(gs->buffer_bytes_left > 0) {
1013 /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
1015 bytes_written = write(gs->interpreter_input,
1016 gs->input_buffer_ptr, gs->buffer_bytes_left);
1019 gtk_gs_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
1020 broken_pipe = FALSE;
1021 interpreter_failed(gs);
1023 else if(bytes_written == -1) {
1024 if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
1025 interpreter_failed(gs); /* Something bad happened */
1029 gs->buffer_bytes_left -= bytes_written;
1030 gs->input_buffer_ptr += bytes_written;
1034 while(gs->ps_input && gs->buffer_bytes_left == 0);
1036 signal(SIGPIPE, oldsig);
1038 if(gs->ps_input == NULL && gs->buffer_bytes_left == 0) {
1039 if(gs->interpreter_input_id != 0) {
1040 gdk_input_remove(gs->interpreter_input_id);
1041 gs->interpreter_input_id = 0;
1047 start_interpreter(GtkGS * gs)
1049 int std_in[2] = { -1, -1 }; /* pipe to interp stdin */
1050 int std_out[2]; /* pipe from interp stdout */
1051 int std_err[2]; /* pipe from interp stderr */
1053 #define NUM_ARGS 100
1054 #define NUM_GS_ARGS (NUM_ARGS - 20)
1055 #define NUM_ALPHA_ARGS 10
1057 char *argv[NUM_ARGS], *dir, *gv_env;
1058 char **gs_args, **alpha_args = NULL;
1061 if(!gs->gs_filename)
1064 stop_interpreter(gs);
1066 if(gs->disable_start == TRUE)
1069 /* set up the args... */
1070 gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
1071 for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
1072 argv[argc] = gs_args[i];
1074 if(gs->antialiased) {
1075 if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
1076 alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
1078 alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
1079 " ", NUM_ALPHA_ARGS);
1080 for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
1081 argv[argc] = alpha_args[i];
1084 argv[argc++] = "-sDEVICE=x11";
1085 argv[argc++] = "-dNOPAUSE";
1086 argv[argc++] = "-dQUIET";
1087 /* I assume we do _not_ want to change this... (: */
1088 argv[argc++] = "-dSAFER";
1090 /* set up the pipes */
1091 if(gs->send_filename_to_gs) {
1092 argv[argc++] = GTK_GS_GET_PS_FILE(gs);
1093 argv[argc++] = "-c";
1094 argv[argc++] = "quit";
1099 argv[argc++] = NULL;
1101 if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
1102 if(pipe(std_in) == -1) {
1103 g_critical("Unable to open pipe to Ghostscript.");
1107 if(pipe(std_out) == -1) {
1111 if(pipe(std_err) == -1) {
1113 close_pipe(std_out);
1118 gs->interpreter_pid = fork();
1119 switch (gs->interpreter_pid) {
1120 case -1: /* error */
1122 close_pipe(std_out);
1123 close_pipe(std_err);
1128 dup2(std_out[1], 1);
1132 dup2(std_err[1], 2);
1135 if(!gs->reading_from_pipe) {
1136 if(gs->send_filename_to_gs) {
1138 /* just in case gs tries to read from stdin */
1139 stdinfd = open("/dev/null", O_RDONLY);
1152 gv_env = g_strdup_printf("GHOSTVIEW=%ld",
1153 gdk_x11_drawable_get_xid(gs->pstarget));
1156 /* change to directory where the input file is. This helps
1157 * with postscript-files which include other files using
1158 * a relative path */
1159 dir = g_path_get_dirname(gs->gs_filename);
1163 execvp(argv[0], argv);
1166 g_print("Unable to execute [%s]\n", argv[0]);
1167 g_strfreev(gs_args);
1170 g_strfreev(alpha_args);
1173 default: /* parent */
1174 if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
1177 /* use non-blocking IO for pipe to ghostscript */
1178 result = fcntl(std_in[1], F_GETFL, 0);
1179 fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
1180 gs->interpreter_input = std_in[1];
1183 gs->interpreter_input = -1;
1186 gs->interpreter_output = std_out[0];
1188 gs->interpreter_err = std_err[0];
1189 gs->interpreter_output_id =
1190 gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
1191 gs->interpreter_error_id =
1192 gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
1199 stop_interpreter(GtkGS * gs)
1201 if(gs->interpreter_pid > 0) {
1203 kill(gs->interpreter_pid, SIGTERM);
1204 while((wait(&status) == -1) && (errno == EINTR)) ;
1205 gs->interpreter_pid = -1;
1208 gs->gs_status = _("Interpreter failed.");
1209 g_signal_emit_by_name(G_OBJECT(gs), "interpreter_error", status);
1213 if(gs->interpreter_input >= 0) {
1214 close(gs->interpreter_input);
1215 gs->interpreter_input = -1;
1216 if(gs->interpreter_input_id != 0) {
1217 gdk_input_remove(gs->interpreter_input_id);
1218 gs->interpreter_input_id = 0;
1220 while(gs->ps_input) {
1221 struct record_list *ps_old = gs->ps_input;
1222 gs->ps_input = gs->ps_input->next;
1223 if(ps_old->close && NULL != ps_old->fp)
1225 g_free((char *) ps_old);
1229 if(gs->interpreter_output >= 0) {
1230 close(gs->interpreter_output);
1231 gs->interpreter_output = -1;
1232 if(gs->interpreter_output_id) {
1233 gdk_input_remove(gs->interpreter_output_id);
1234 gs->interpreter_output_id = 0;
1238 if(gs->interpreter_err >= 0) {
1239 close(gs->interpreter_err);
1240 gs->interpreter_err = -1;
1241 if(gs->interpreter_error_id) {
1242 gdk_input_remove(gs->interpreter_error_id);
1243 gs->interpreter_error_id = 0;
1252 * Decompress gs->gs_filename if necessary
1253 * Set gs->filename_unc to the name of the uncompressed file or NULL.
1254 * Error reporting via signal 'interpreter_message'
1255 * Return name of input file to use or NULL on error..
1258 check_filecompressed(GtkGS * gs)
1262 gchar *filename, *filename_unc, *filename_err, *cmdline;
1268 if((file = fopen(gs->gs_filename, "r"))
1269 && (fread(buf, sizeof(gchar), 3, file) == 3)) {
1270 if((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) {
1271 /* file is gzipped or compressed */
1272 cmd = gtk_gs_defaults_get_ungzip_cmd();
1274 else if(strncmp(buf, "BZh", 3) == 0) {
1275 /* file is compressed with bzip2 */
1276 cmd = gtk_gs_defaults_get_unbzip2_cmd();
1283 return gs->gs_filename;
1285 /* do the decompression */
1286 filename = ggv_quote_filename(gs->gs_filename);
1287 filename_unc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1288 if((fd = mkstemp(filename_unc)) < 0) {
1289 g_free(filename_unc);
1294 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1295 if((fd = mkstemp(filename_err)) < 0) {
1296 g_free(filename_err);
1297 g_free(filename_unc);
1302 cmdline = g_strdup_printf("%s %s >%s 2>%s", cmd,
1303 filename, filename_unc, filename_err);
1304 if((system(cmdline) == 0)
1305 && ggv_file_readable(filename_unc)
1306 && (ggv_file_length(filename_err) == 0)) {
1307 /* sucessfully uncompressed file */
1308 gs->gs_filename_unc = filename_unc;
1312 g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
1314 gtk_gs_emit_error_msg(gs, buf);
1315 if(ggv_file_length(filename_err) > 0) {
1317 if((err = fopen(filename_err, "r"))) {
1318 /* print file to message window */
1319 while(fgets(buf, 1024, err))
1320 gtk_gs_emit_error_msg(gs, buf);
1324 unlink(filename_unc);
1325 g_free(filename_unc);
1326 filename_unc = NULL;
1328 unlink(filename_err);
1329 g_free(filename_err);
1332 return filename_unc;
1336 * Check if gs->gs_filename or gs->gs_filename_unc is a pdf file and scan
1337 * pdf file if necessary.
1338 * Set gs->filename_dsc to the name of the dsc file or NULL.
1339 * Error reporting via signal 'interpreter_message'.
1342 check_pdf(GtkGS * gs)
1345 gchar buf[1024], *filename;
1348 /* use uncompressed file as input if necessary */
1349 filename = (gs->gs_filename_unc ? gs->gs_filename_unc : gs->gs_filename);
1351 if((file = fopen(filename, "r"))
1352 && (fread(buf, sizeof(char), 5, file) == 5)
1353 && (strncmp(buf, "%PDF-", 5) == 0)) {
1354 /* we found a PDF file */
1355 gchar *fname, *filename_dsc, *filename_err, *cmd, *cmdline;
1356 filename_dsc = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1357 if((fd = mkstemp(filename_dsc)) < 0) {
1361 filename_err = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
1362 if((fd = mkstemp(filename_err)) < 0) {
1363 g_free(filename_dsc);
1367 fname = ggv_quote_filename(filename);
1368 cmd = g_strdup_printf(gtk_gs_defaults_get_dsc_cmd(), filename_dsc, fname);
1370 /* this command (sometimes?) prints error messages to stdout! */
1371 cmdline = g_strdup_printf("%s >%s 2>&1", cmd, filename_err);
1374 if((system(cmdline) == 0) && ggv_file_readable(filename_dsc)) {
1377 filename = gs->gs_filename_dsc = filename_dsc;
1379 if(ggv_file_length(filename_err) > 0) {
1380 gchar *err_msg = " ";
1385 if((err = fopen(filename_err, "r"))) {
1387 /* print the content of the file to a message box */
1388 while(fgets(buf, 1024, err))
1389 err_msg = g_strconcat(err_msg, buf, NULL);
1391 /* FIXME The dialog is not yet set to modal, difficult to
1392 * get the parent of the dialog box here
1395 dialog = gtk_message_dialog_new(NULL,
1397 GTK_MESSAGE_WARNING,
1399 ("There was an error while scaning the file: %s \n%s"),
1400 gs->gs_filename, err_msg);
1402 gdk_color_parse("white", &color);
1403 gtk_widget_modify_bg(GTK_WIDGET(dialog), GTK_STATE_NORMAL, &color);
1405 g_signal_connect(G_OBJECT(dialog), "response",
1406 G_CALLBACK(gtk_widget_destroy), NULL);
1408 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1409 gtk_widget_show(dialog);
1417 g_snprintf(buf, 1024,
1418 _("Error while converting pdf file %s:\n"), filename);
1419 gtk_gs_emit_error_msg(gs, buf);
1421 if(ggv_file_length(filename_err) > 0) {
1423 if((err = fopen(filename_err, "r"))) {
1424 /* print file to message window */
1425 while(fgets(buf, 1024, err))
1426 gtk_gs_emit_error_msg(gs, buf);
1429 unlink(filename_dsc);
1430 g_free(filename_dsc);
1433 unlink(filename_err);
1434 g_free(filename_err);
1442 #ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
1443 /* never mind this patch: a properly working X server should take care of
1444 calculating the proper values. */
1448 # ifndef HAVE_XINERAMA
1449 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1452 dpy = (Display *) GDK_DISPLAY();
1453 if(XineramaIsActive(dpy)) {
1455 XineramaScreenInfo *head_info;
1456 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1457 /* fake it with dimensions of the first head for now */
1458 return 25.4 * head_info[0].width / gdk_screen_width_mm();
1461 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1470 # ifndef HAVE_XINERAMA
1471 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1474 dpy = (Display *) GDK_DISPLAY();
1475 if(XineramaIsActive(dpy)) {
1477 XineramaScreenInfo *head_info;
1478 head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
1479 /* fake it with dimensions of the first head for now */
1480 return 25.4 * head_info[0].height / gdk_screen_height_mm();
1483 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1492 return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
1498 return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
1500 #endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
1502 /* Compute new size of window, sets xdpi and ydpi if necessary.
1503 * returns True if new window size is different */
1505 compute_size(GtkGS * gs)
1507 guint new_width = 1;
1508 guint new_height = 1;
1509 gboolean change = FALSE;
1512 /* width and height can be changed, calculate window size according */
1513 /* to xpdi and ydpi */
1514 orientation = gtk_gs_get_orientation(gs);
1516 switch (orientation) {
1517 case GTK_GS_ORIENTATION_PORTRAIT:
1518 case GTK_GS_ORIENTATION_UPSIDEDOWN:
1519 new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
1520 new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
1522 case GTK_GS_ORIENTATION_LANDSCAPE:
1523 case GTK_GS_ORIENTATION_SEASCAPE:
1524 new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
1525 new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
1529 change = (new_width != gs->width * gs->zoom_factor)
1530 || (new_height != gs->height * gs->zoom_factor);
1531 gs->width = (gint) (new_width * gs->zoom_factor);
1532 gs->height = (gint) (new_height * gs->zoom_factor);
1533 if(GTK_WIDGET_REALIZED(gs)) {
1535 if(gdk_window_is_visible(gs->pstarget))
1536 gdk_window_hide(gs->pstarget);
1539 if(!gdk_window_is_visible(gs->pstarget) && gs->width > 0
1541 gdk_window_show(gs->pstarget);
1543 gtk_gs_munge_adjustments(gs);
1550 gtk_gs_enable_interpreter(GtkGS * gs)
1552 g_return_val_if_fail(gs != NULL, FALSE);
1553 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1555 if(!gs->gs_filename)
1558 gs->disable_start = FALSE;
1559 if(GTK_WIDGET_REALIZED(gs)) {
1560 return start_interpreter(gs);
1567 /* publicly accessible functions */
1570 gtk_gs_get_type(void)
1572 static GType gs_type = 0;
1574 GTypeInfo gs_info = {
1576 (GBaseInitFunc) NULL,
1577 (GBaseFinalizeFunc) NULL,
1578 (GClassInitFunc) gtk_gs_class_init,
1579 (GClassFinalizeFunc) NULL,
1580 NULL, /* class_data */
1582 0, /* n_preallocs */
1583 (GInstanceInitFunc) gtk_gs_init
1586 gs_type = g_type_register_static(gtk_widget_get_type(),
1587 "GtkGS", &gs_info, 0);
1595 gtk_gs_new(GtkAdjustment * hadj, GtkAdjustment * vadj)
1600 hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.1, 0.09));
1602 vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.1, 0.09));
1604 gs = (GtkGS *) gtk_type_new(gtk_gs_get_type());
1606 gtk_gs_set_adjustments(gs, hadj, vadj);
1608 return GTK_WIDGET(gs);
1613 gtk_gs_new_from_file(GtkAdjustment * hadj, GtkAdjustment * vadj, char *fname)
1615 GtkWidget *gs = gtk_gs_new(hadj, vadj);
1616 gtk_gs_load(GTK_GS(gs), fname);
1621 gtk_gs_reload(GtkGS * gs)
1624 gfloat hval = gs->hadj->value;
1625 gfloat vval = gs->vadj->value;
1628 if(!gs->gs_filename)
1631 page = gtk_gs_get_current_page(gs);
1632 fname = g_strdup(gs->gs_filename);
1633 gtk_gs_load(gs, fname);
1634 gtk_gs_goto_page(gs, page);
1635 gtk_adjustment_set_value(gs->hadj, hval);
1636 gtk_adjustment_set_value(gs->vadj, vval);
1642 * Show error message -> send signal "interpreter_message"
1645 gtk_gs_emit_error_msg(GtkGS * gs, const gchar * msg)
1647 gtk_signal_emit(GTK_OBJECT(gs),
1648 gtk_gs_signals[INTERPRETER_MESSAGE], g_strdup(msg));
1653 gtk_gs_center_page(GtkGS * gs)
1655 g_return_if_fail(gs != NULL);
1656 g_return_if_fail(GTK_IS_GS(gs));
1658 gdk_window_move(gs->pstarget,
1659 (gs->widget.allocation.width - gs->width) / 2,
1660 (gs->widget.allocation.height - gs->height) / 2);
1661 gs->hadj->page_size = ((gfloat) gs->widget.allocation.width) / gs->width;
1662 gs->hadj->page_size = MIN(gs->hadj->page_size, 1.0);
1663 gs->vadj->page_size = ((gfloat) gs->widget.allocation.height) / gs->height;
1664 gs->vadj->page_size = MIN(gs->vadj->page_size, 1.0);
1665 gs->hadj->value = 0.5 - gs->hadj->page_size / 2;
1666 gs->vadj->value = 0.5 - gs->vadj->page_size / 2;
1667 gtk_adjustment_changed(gs->hadj);
1668 gtk_adjustment_changed(gs->vadj);
1672 gtk_gs_scroll(GtkGS * gs, gint x_delta, gint y_delta)
1676 g_return_if_fail(gs != NULL);
1677 g_return_if_fail(GTK_IS_GS(gs));
1679 hval = gs->hadj->value + ((gfloat) x_delta) / gs->width;
1680 vval = gs->vadj->value + ((gfloat) y_delta) / gs->height;
1681 if(hval <= gs->hadj->upper - gs->hadj->page_size && hval >= gs->hadj->lower)
1682 gtk_adjustment_set_value(gs->hadj, hval);
1683 if(vval <= gs->vadj->upper - gs->vadj->page_size && vval >= gs->vadj->lower)
1684 gtk_adjustment_set_value(gs->vadj, vval);
1688 gtk_gs_disable_interpreter(GtkGS * gs)
1690 g_return_if_fail(gs != NULL);
1691 g_return_if_fail(GTK_IS_GS(gs));
1693 gs->disable_start = TRUE;
1694 if(GTK_WIDGET_REALIZED(GTK_WIDGET(gs)))
1695 stop_interpreter(gs);
1699 gtk_gs_load(GtkGS * gs, const gchar * fname)
1701 g_return_val_if_fail(gs != NULL, FALSE);
1702 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1704 /* clean up previous document */
1708 if(gs->pstarget != NULL && gdk_window_is_visible(gs->pstarget))
1709 gdk_window_hide(gs->pstarget);
1714 /* prepare this document */
1716 /* default values: no dsc information available */
1717 gs->structured_doc = FALSE;
1718 gs->send_filename_to_gs = TRUE;
1719 gs->current_page = -2;
1722 /* an absolute path */
1723 gs->gs_filename = g_strdup(fname);
1726 /* path relative to our cwd: make it absolute */
1727 gchar *cwd = g_get_current_dir();
1728 gs->gs_filename = g_strconcat(cwd, "/", fname, NULL);
1732 if((gs->reading_from_pipe = (strcmp(fname, "-") == 0))) {
1733 gs->send_filename_to_gs = FALSE;
1737 * We need to make sure that the file is loadable/exists!
1738 * otherwise we want to exit without loading new stuff...
1740 gchar *filename = NULL;
1742 if(!ggv_file_readable(fname)) {
1744 g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
1745 gtk_gs_emit_error_msg(gs, buf);
1746 gs->gs_status = _("File is not readable.");
1749 filename = check_filecompressed(gs);
1751 filename = check_pdf(gs);
1754 if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
1759 /* we grab the vital statistics!!! */
1760 gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
1762 if(gs->doc == NULL) {
1763 /* File does not seem to be a Postscript one */
1765 g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
1766 gtk_gs_emit_error_msg(gs, buf);
1768 gs->gs_status = _("The file is not a PostScript document.");
1772 if((!gs->doc->epsf && gs->doc->numpages > 0) ||
1773 (gs->doc->epsf && gs->doc->numpages > 1)) {
1774 gs->structured_doc = TRUE;
1775 gs->send_filename_to_gs = FALSE;
1778 /* We have to set up the orientation of the document */
1781 /* orientation can only be portrait, and landscape or none.
1782 This is the document default. A document can have
1783 pages in landscape and some in portrait */
1784 if(gs->override_orientation) {
1785 /* If the orientation should be override...
1786 then gs->orientation has already the correct
1787 value (it was set when the widget was created */
1792 /* Otherwise, set the proper orientation for the doc */
1793 gs->real_orientation = gs->doc->orientation;
1796 gtk_gs_set_page_size(gs, -1, gs->current_page);
1797 gtk_widget_queue_resize(&(gs->widget));
1800 gs->gs_status = _("Document loaded.");
1807 gtk_gs_next_page(GtkGS * gs)
1811 g_return_val_if_fail(gs != NULL, FALSE);
1812 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1814 if(gs->interpreter_pid == 0) { /* no interpreter active */
1818 if(gs->busy) { /* interpreter is busy */
1824 event.xclient.type = ClientMessage;
1825 event.xclient.display = gdk_display;
1826 event.xclient.window = gs->message_window;
1827 event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
1828 event.xclient.format = 32;
1830 gdk_error_trap_push();
1831 XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
1833 gdk_error_trap_pop();
1839 gtk_gs_get_current_page(GtkGS * gs)
1841 g_return_val_if_fail(gs != NULL, -1);
1842 g_return_val_if_fail(GTK_IS_GS(gs), -1);
1844 return gs->current_page;
1848 gtk_gs_get_page_count(GtkGS * gs)
1850 if(!gs->gs_filename)
1854 if(gs->structured_doc)
1855 return gs->doc->numpages;
1864 gtk_gs_goto_page(GtkGS * gs, gint page)
1866 g_return_val_if_fail(gs != NULL, FALSE);
1867 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1869 if(!gs->gs_filename) {
1873 /* range checking... */
1877 if(gs->structured_doc && gs->doc) {
1878 if(page >= gs->doc->numpages)
1879 page = gs->doc->numpages - 1;
1881 if(page == gs->current_page && !gs->changed)
1884 gs->current_page = page;
1886 if(!GTK_WIDGET_REALIZED(gs))
1889 if(gs->doc->pages[page].orientation != NONE &&
1890 !gs->override_orientation &&
1891 gs->doc->pages[page].orientation != gs->real_orientation) {
1892 gs->real_orientation = gs->doc->pages[page].orientation;
1896 gtk_gs_set_page_size(gs, -1, page);
1898 gs->changed = FALSE;
1900 if(is_interpreter_ready(gs)) {
1901 gtk_gs_next_page(gs);
1904 gtk_gs_enable_interpreter(gs);
1905 send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
1906 send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
1909 send_ps(gs, gs->doc->pages[gs->current_page].begin,
1910 gs->doc->pages[gs->current_page].len, FALSE);
1913 /* Unstructured document */
1914 /* In the case of non structured documents,
1915 GS read the PS from the actual file (via command
1916 line. Hence, ggv only send a signal next page.
1917 If ghostview is not running it is usually because
1918 the last page of the file was displayed. In that
1919 case, ggv restarts GS again and the first page is displayed.
1921 if(page == gs->current_page && !gs->changed)
1924 if(!GTK_WIDGET_REALIZED(gs))
1927 if(!is_interpreter_ready(gs))
1928 gtk_gs_enable_interpreter(gs);
1930 gs->current_page = page;
1932 gtk_gs_next_page(gs);
1938 * set pagesize sets the size from
1939 * if new_pagesize is -1, then it is set to either
1940 * a) the default settings of pageid, if they exist, or if pageid != -1.
1941 * b) the default setting of the document, if it exists.
1942 * c) the default setting of the widget.
1943 * otherwise, the new_pagesize is used as the pagesize
1946 gtk_gs_set_page_size(GtkGS * gs, gint new_pagesize, gint pageid)
1952 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
1954 g_return_val_if_fail(gs != NULL, FALSE);
1955 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
1957 if(new_pagesize == -1) {
1958 if(gs->default_size > 0)
1959 new_pagesize = gs->default_size;
1960 if(!gs->override_size && gs->doc) {
1961 /* If we have a document:
1962 We use -- the page size (if specified)
1963 or the doc. size (if specified)
1964 or the page bbox (if specified)
1967 if((pageid >= 0) && (gs->doc->numpages > pageid) &&
1968 (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
1969 new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
1971 else if(gs->doc->default_page_size != NULL) {
1972 new_pagesize = gs->doc->default_page_size - gs->doc->size;
1974 else if((pageid >= 0) &&
1975 (gs->doc->numpages > pageid) &&
1977 (gs->doc->pages[pageid].boundingbox[URX] >
1978 gs->doc->pages[pageid].boundingbox[LLX]) &&
1979 (gs->doc->pages[pageid].boundingbox[URY] >
1980 gs->doc->pages[pageid].boundingbox[LLY])) {
1983 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
1984 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
1990 /* Compute bounding box */
1991 if(gs->doc && ((gs->doc->epsf && !gs->override_size) || new_pagesize == -1)) { /* epsf or bbox */
1994 (gs->doc->pages[pageid].boundingbox[URX] >
1995 gs->doc->pages[pageid].boundingbox[LLX])
1996 && (gs->doc->pages[pageid].boundingbox[URY] >
1997 gs->doc->pages[pageid].boundingbox[LLY])) {
1999 new_llx = gs->doc->pages[pageid].boundingbox[LLX];
2000 new_lly = gs->doc->pages[pageid].boundingbox[LLY];
2001 new_urx = gs->doc->pages[pageid].boundingbox[URX];
2002 new_ury = gs->doc->pages[pageid].boundingbox[URY];
2004 else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
2005 (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
2007 new_llx = gs->doc->boundingbox[LLX];
2008 new_lly = gs->doc->boundingbox[LLY];
2009 new_urx = gs->doc->boundingbox[URX];
2010 new_ury = gs->doc->boundingbox[URY];
2014 if(new_pagesize < 0)
2015 new_pagesize = gs->default_size;
2016 new_llx = new_lly = 0;
2017 if(gs->doc && !gs->override_size && gs->doc->size &&
2018 (new_pagesize < gs->doc->numsizes)) {
2019 new_urx = gs->doc->size[new_pagesize].width;
2020 new_ury = gs->doc->size[new_pagesize].height;
2023 new_urx = papersizes[new_pagesize].width;
2024 new_ury = papersizes[new_pagesize].height;
2028 if(new_urx <= new_llx)
2029 new_urx = papersizes[12].width;
2030 if(new_ury <= new_lly)
2031 new_ury = papersizes[12].height;
2033 /* If bounding box changed, setup for new size. */
2034 /* gtk_gs_disable_interpreter (gs); */
2035 if((new_llx != gs->llx) || (new_lly != gs->lly) ||
2036 (new_urx != gs->urx) || (new_ury != gs->ury)) {
2045 if(GTK_WIDGET_REALIZED(gs)) {
2047 gtk_widget_queue_resize(&(gs->widget));
2056 gtk_gs_set_override_orientation(GtkGS * gs, gboolean bNewOverride)
2058 gint iOldOrientation;
2060 g_return_if_fail(gs != NULL);
2061 g_return_if_fail(GTK_IS_GS(gs));
2063 iOldOrientation = gtk_gs_get_orientation(gs);
2065 gs->override_orientation = bNewOverride;
2067 /* If the current orientation is different from the
2068 new orientation then redisplay */
2069 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
2071 if(GTK_WIDGET_REALIZED(gs))
2074 gtk_widget_queue_resize(&(gs->widget));
2078 gtk_gs_get_override_orientation(GtkGS * gs)
2080 g_return_val_if_fail(gs != NULL, FALSE);
2081 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2083 return gs->override_orientation;
2087 gtk_gs_set_override_size(GtkGS * gs, gboolean f)
2089 g_return_if_fail(gs != NULL);
2090 g_return_if_fail(GTK_IS_GS(gs));
2092 if(f != gs->override_size) {
2093 gs->override_size = f;
2095 gtk_gs_set_page_size(gs, -1, gs->current_page);
2096 if(GTK_WIDGET_REALIZED(gs))
2099 gtk_widget_queue_resize(&(gs->widget));
2103 gtk_gs_get_override_size(GtkGS * gs)
2105 g_return_val_if_fail(gs != NULL, FALSE);
2106 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2108 return gs->override_size;
2112 gtk_gs_set_zoom(GtkGS * gs, gfloat zoom)
2114 g_return_if_fail(gs != NULL);
2115 g_return_if_fail(GTK_IS_GS(gs));
2117 switch (gs->zoom_mode) {
2118 case GTK_GS_ZOOM_FIT_WIDTH:
2119 zoom = gtk_gs_zoom_to_fit(gs, TRUE);
2121 case GTK_GS_ZOOM_FIT_PAGE:
2122 zoom = gtk_gs_zoom_to_fit(gs, FALSE);
2124 case GTK_GS_ZOOM_ABSOLUTE:
2128 if(zoom < ggv_zoom_levels[0])
2129 zoom = ggv_zoom_levels[0];
2130 else if(zoom > ggv_zoom_levels[ggv_max_zoom_levels])
2131 zoom = ggv_zoom_levels[ggv_max_zoom_levels];
2132 if(fabs(gs->zoom_factor - zoom) > 0.001) {
2133 gs->zoom_factor = zoom;
2134 if(GTK_WIDGET_REALIZED(gs))
2137 gtk_widget_queue_resize(&(gs->widget));
2142 gtk_gs_get_zoom(GtkGS * gs)
2144 g_return_val_if_fail(gs != NULL, 0.0);
2145 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
2147 return gs->zoom_factor;
2151 gtk_gs_zoom_to_fit(GtkGS * gs, gboolean fit_width)
2155 guint avail_w, avail_h;
2157 g_return_val_if_fail(gs != NULL, 0.0);
2158 g_return_val_if_fail(GTK_IS_GS(gs), 0.0);
2160 avail_w = (gs->avail_w > 0) ? gs->avail_w : gs->width;
2161 avail_h = (gs->avail_h > 0) ? gs->avail_h : gs->height;
2163 new_zoom = ((gfloat) avail_w) / ((gfloat) gs->width) * gs->zoom_factor;
2165 new_y = new_zoom * ((gfloat) gs->height) / gs->zoom_factor;
2167 new_zoom = ((gfloat) avail_h) / ((gfloat) gs->height) * gs->zoom_factor;
2174 gtk_gs_set_default_orientation(GtkGS * gs, gint orientation)
2176 gint iOldOrientation;
2178 g_return_val_if_fail(gs != NULL, FALSE);
2179 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2180 g_return_val_if_fail((orientation == GTK_GS_ORIENTATION_PORTRAIT) ||
2181 (orientation == GTK_GS_ORIENTATION_LANDSCAPE) ||
2182 (orientation == GTK_GS_ORIENTATION_UPSIDEDOWN) ||
2183 (orientation == GTK_GS_ORIENTATION_SEASCAPE), FALSE);
2185 iOldOrientation = gtk_gs_get_orientation(gs);
2186 gs->fallback_orientation = orientation;
2188 /* We are setting the fallback orientation */
2189 if(iOldOrientation != gtk_gs_get_orientation(gs)) {
2191 if(GTK_WIDGET_REALIZED(gs))
2193 gtk_widget_queue_resize(&(gs->widget));
2201 gtk_gs_get_default_orientation(GtkGS * gs)
2203 g_return_val_if_fail(gs != NULL, -1);
2204 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2206 return gs->fallback_orientation;
2210 gtk_gs_get_orientation(GtkGS * gs)
2212 g_return_val_if_fail(gs != NULL, -1);
2213 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2216 if(gs->structured_doc) {
2217 if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
2218 GTK_GS_ORIENTATION_NONE)
2219 gs->real_orientation =
2220 gs->doc->pages[MAX(gs->current_page, 0)].orientation;
2222 gs->real_orientation = gs->doc->default_page_orientation;
2225 if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
2226 gs->real_orientation = gs->doc->orientation;
2229 if(gs->override_orientation ||
2230 gs->real_orientation == GTK_GS_ORIENTATION_NONE)
2231 return gs->fallback_orientation;
2233 return gs->real_orientation;
2237 gtk_gs_set_default_size(GtkGS * gs, gint size)
2239 g_return_if_fail(gs != NULL);
2240 g_return_if_fail(GTK_IS_GS(gs));
2242 gs->default_size = size;
2243 gtk_gs_set_page_size(gs, -1, gs->current_page);
2247 gtk_gs_get_default_size(GtkGS * gs)
2249 g_return_val_if_fail(gs != NULL, -1);
2250 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2252 return gs->default_size;
2256 gtk_gs_set_respect_eof(GtkGS * gs, gboolean f)
2258 g_return_if_fail(gs != NULL);
2259 g_return_if_fail(GTK_IS_GS(gs));
2261 if(gs->respect_eof == f)
2264 gs->respect_eof = f;
2265 gtk_gs_set_page_size(gs, -1, gs->current_page);
2269 gtk_gs_get_respect_eof(GtkGS * gs)
2271 g_return_val_if_fail(gs != NULL, -1);
2272 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2274 return gs->respect_eof;
2278 gtk_gs_set_antialiasing(GtkGS * gs, gboolean f)
2280 g_return_if_fail(gs != NULL);
2281 g_return_if_fail(GTK_IS_GS(gs));
2283 if(gs->antialiased == f)
2286 gs->antialiased = f;
2288 if(GTK_WIDGET_REALIZED(gs))
2289 start_interpreter(gs);
2290 gtk_gs_goto_page(gs, gs->current_page);
2294 gtk_gs_get_antialiasing(GtkGS * gs)
2296 g_return_val_if_fail(gs != NULL, -1);
2297 g_return_val_if_fail(GTK_IS_GS(gs), -1);
2299 return gs->antialiased;
2303 gtk_gs_get_document_title(GtkGS * gs)
2305 g_return_val_if_fail(gs != NULL, NULL);
2306 g_return_val_if_fail(GTK_IS_GS(gs), NULL);
2308 if(gs->doc && gs->doc->title)
2309 return gs->doc->title;
2315 gtk_gs_get_document_numpages(GtkGS * widget)
2317 g_return_val_if_fail(widget != NULL, 0);
2318 g_return_val_if_fail(GTK_IS_GS(widget), 0);
2321 return widget->doc->numpages;
2327 gtk_gs_get_document_page_label(GtkGS * widget, int page)
2329 g_return_val_if_fail(widget != NULL, NULL);
2330 g_return_val_if_fail(GTK_IS_GS(widget), NULL);
2332 if(widget->doc && widget->doc->pages && (widget->doc->numpages >= page))
2333 return widget->doc->pages[page - 1].label;
2339 gtk_gs_get_size_index(const gchar * string, GtkGSPaperSize * size)
2343 while(size[idx].name != NULL) {
2344 if(strcmp(size[idx].name, string) == 0)
2353 gtk_gs_start_scroll(GtkGS * gs)
2357 if(!GTK_WIDGET_REALIZED(gs) || !gs->show_scroll_rect)
2360 gdk_window_get_geometry(gs->pstarget, &x, &y, &w, &h, NULL);
2361 gs->scroll_start_x = MAX(-x, 0);
2362 gs->scroll_start_y = MAX(-y, 0);
2363 gs->scroll_width = MIN(gs->widget.allocation.width - 1, w - 1);
2364 gs->scroll_height = MIN(gs->widget.allocation.height - 1, h - 1);
2368 rect.x = gs->scroll_start_x;
2369 rect.y = gs->scroll_start_y;
2370 rect.width = gs->scroll_width + 1;
2371 rect.height = gs->scroll_height + 1;
2372 gdk_draw_rectangle(gs->bpixmap, gs->psgc, FALSE,
2373 gs->scroll_start_x, gs->scroll_start_y,
2374 gs->scroll_width, gs->scroll_height);
2376 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2377 rect.x = gs->scroll_start_x + gs->scroll_width;
2378 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2379 rect.x = gs->scroll_start_x + 1;
2380 rect.width = gs->scroll_start_x + gs->scroll_width - 1;
2382 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2383 rect.y = gs->scroll_start_y + gs->scroll_height;
2384 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2389 gtk_gs_end_scroll(GtkGS * gs)
2391 if(!GTK_WIDGET_REALIZED(gs) || !gs->show_scroll_rect)
2394 if(gs->scroll_start_x == -1 || gs->scroll_start_y == -1)
2399 rect.x = gs->scroll_start_x;
2400 rect.y = gs->scroll_start_y;
2401 rect.width = gs->scroll_width + 1;
2402 rect.height = gs->scroll_height + 1;
2403 gdk_draw_rectangle(gs->bpixmap, gs->psgc, FALSE,
2404 gs->scroll_start_x, gs->scroll_start_y,
2405 gs->scroll_width, gs->scroll_height);
2407 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2408 rect.x = gs->scroll_start_x + gs->scroll_width;
2409 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2410 rect.x = gs->scroll_start_x + 1;
2411 rect.width = gs->scroll_start_x + gs->scroll_width - 1;
2413 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2414 rect.y = gs->scroll_start_y + gs->scroll_height;
2415 gdk_window_invalidate_rect(gs->pstarget, &rect, TRUE);
2417 gs->scroll_start_x = -1;
2418 gs->scroll_start_y = -1;
2422 gtk_gs_set_show_scroll_rect(GtkGS * gs, gboolean f)
2424 gs->show_scroll_rect = f;
2428 gtk_gs_get_show_scroll_rect(GtkGS * gs)
2430 return gs->show_scroll_rect;
2434 gtk_gs_scroll_to_edge(GtkGS * gs, GtkPositionType vertical,
2435 GtkPositionType horizontal)
2437 g_return_val_if_fail(gs != NULL, FALSE);
2438 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2442 gs->vadj->value = gs->vadj->lower;
2443 gtk_adjustment_value_changed(gs->vadj);
2445 case GTK_POS_BOTTOM:
2446 gs->vadj->value = gs->vadj->upper - gs->vadj->page_size;
2447 gtk_adjustment_value_changed(gs->vadj);
2450 g_assert(0); /* Illegal parameter error */
2454 switch (horizontal) {
2456 gs->hadj->value = gs->hadj->lower;
2457 gtk_adjustment_value_changed(gs->hadj);
2459 case GTK_POS_BOTTOM:
2460 gs->hadj->value = gs->hadj->upper - gs->hadj->page_size;
2461 gtk_adjustment_value_changed(gs->hadj);
2464 g_assert(0); /* Illegal parameter error */
2471 gtk_gs_scroll_step(GtkGS * gs, GtkScrollType direction, gboolean dowrap)
2473 GtkAdjustment *MainAdj; /* We will move this adjustment */
2474 GtkAdjustment *SecoAdj; /* And this _only_ if we can't move MainAdj (ie. we're edge)
2475 and there is wrapping */
2477 gboolean MoveHorizontal = TRUE; /* Positive if we move horizontal */
2478 gboolean DirectionFlag = TRUE; /* Positive if we move towards upper */
2479 g_return_val_if_fail(gs != NULL, FALSE);
2480 g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
2482 #define EPSILON 0.00005
2484 #define CHECK_THERE_IS_NO_LOWER_SPACE(adj) \
2485 ((adj)->value - (EPSILON) <= (adj)->lower)
2486 #define CHECK_THERE_IS_NO_UPPER_SPACE(adj) \
2487 ((adj)->value + (EPSILON) >= (adj)->upper - (adj)->page_size)
2489 #define CHECK_THERE_IS_NO_SPACE_FOR_STEP(adj,dir) \
2490 (dir?CHECK_THERE_IS_NO_UPPER_SPACE(adj):CHECK_THERE_IS_NO_LOWER_SPACE(adj))
2492 /* To make code more readable, we make a macro */
2493 #define ADVANCE_TOWARDS_LOWER(adj) \
2494 (adj->value -= gs->scroll_step * (adj->page_size))
2495 #define ADVANCE_TOWARDS_UPPER(adj) \
2496 (adj->value += gs->scroll_step * (adj->page_size))
2498 #define ADVANCE_STEP(adj,dir) \
2499 (dir?ADVANCE_TOWARDS_UPPER(adj):ADVANCE_TOWARDS_LOWER(adj))
2501 #define MOVE_TO_LOWER_EDGE(adj) \
2502 (adj->value = adj->lower)
2503 #define MOVE_TO_UPPER_EDGE(adj) \
2504 (adj->value = adj->upper - adj->page_size)
2506 /* if upper is 1 goto upper, otherwise to lower */
2507 #define MOVE_TO_EDGE(adj,upper) (upper?MOVE_TO_UPPER_EDGE(adj):MOVE_TO_LOWER_EDGE(adj))
2509 /* These variables make our life easier */
2510 switch (direction) {
2511 case GTK_SCROLL_STEP_RIGHT:
2512 MoveHorizontal = TRUE;
2513 DirectionFlag = TRUE;
2515 case GTK_SCROLL_STEP_LEFT:
2516 MoveHorizontal = TRUE;
2517 DirectionFlag = FALSE;
2519 case GTK_SCROLL_STEP_DOWN:
2520 MoveHorizontal = FALSE;
2521 DirectionFlag = TRUE;
2523 case GTK_SCROLL_STEP_UP:
2524 MoveHorizontal = FALSE;
2525 DirectionFlag = FALSE;
2528 g_warning("Illegal scroll step direction.");
2531 if(MoveHorizontal) {
2540 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(MainAdj, DirectionFlag)) {
2543 /* Move in the oposite axis */
2544 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(SecoAdj, DirectionFlag)) {
2545 /* there is no place to move, we need a new page */
2548 ADVANCE_STEP(SecoAdj, DirectionFlag);
2550 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(SecoAdj, DirectionFlag)) {
2551 /* We move it too far, lets move it to the edge */
2552 MOVE_TO_EDGE(SecoAdj, DirectionFlag);
2554 /* now move to edge (other axis) in oposite direction */
2555 MOVE_TO_EDGE(MainAdj, !DirectionFlag);
2556 gtk_adjustment_value_changed(SecoAdj);
2560 /* Now we know we can move in the direction sought */
2561 ADVANCE_STEP(MainAdj, DirectionFlag);
2563 if(CHECK_THERE_IS_NO_SPACE_FOR_STEP(MainAdj, DirectionFlag)) {
2564 /* We move it too far, lets move it to the edge */
2565 MOVE_TO_EDGE(MainAdj, DirectionFlag);
2567 gtk_adjustment_value_changed(MainAdj);
2573 gtk_gs_get_postscript(GtkGS * gs, gint * pages)
2577 gboolean free_pages = FALSE;
2580 if(!gs->structured_doc) {
2584 if(stat(GTK_GS_GET_PS_FILE(gs), &sb))
2586 doc = g_new(gchar, sb.st_size);
2589 f = fopen(GTK_GS_GET_PS_FILE(gs), "r");
2590 if(NULL != f && fread(doc, sb.st_size, 1, f) != 1) {
2599 int i, n = gtk_gs_get_page_count(gs);
2600 pages = g_new0(gint, n);
2601 for(i = 0; i < n; i++)
2607 sink = gtk_gs_doc_sink_new();
2609 if(GTK_GS_IS_PDF(gs)) {
2610 gchar *tmpn = g_strconcat(g_get_tmp_dir(), "/ggvXXXXXX", NULL);
2614 if((tmpfd = mkstemp(tmpn)) < 0) {
2619 fname = ggv_quote_filename(gs->gs_filename_unc ?
2620 gs->gs_filename_unc : gs->gs_filename);
2621 cmd = g_strdup_printf(gtk_gs_defaults_get_convert_pdf_cmd(), tmpn, fname);
2623 if((system(cmd) == 0) && ggv_file_readable(tmpn)) {
2625 tmp_gs = gtk_gs_new_from_file(NULL, NULL, tmpn);
2626 if(NULL != tmp_gs) {
2627 if(GTK_GS(tmp_gs)->loaded)
2628 pscopydoc(sink, tmpn, GTK_GS(tmp_gs)->doc, pages);
2629 gtk_widget_destroy(tmp_gs);
2636 /* Use uncompressed file if necessary */
2637 pscopydoc(sink, GTK_GS_GET_PS_FILE(gs), gs->doc, pages);
2641 doc = gtk_gs_doc_sink_get_buffer(sink);
2642 gtk_gs_doc_sink_free(sink);
2647 gtk_gs_set_adjustments(GtkGS * gs, GtkAdjustment * hadj, GtkAdjustment * vadj)
2649 g_return_if_fail(gs != NULL);
2650 g_return_if_fail(GTK_IS_GS(gs));
2652 g_return_if_fail(GTK_IS_ADJUSTMENT(hadj));
2654 hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.0, 0.0, 1.0));
2656 g_return_if_fail(GTK_IS_ADJUSTMENT(vadj));
2658 vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.0, 0.0, 1.0));
2660 if(gs->hadj && (gs->hadj != hadj)) {
2661 g_signal_handlers_disconnect_matched(G_OBJECT(gs->hadj),
2662 G_SIGNAL_MATCH_DATA,
2663 0, 0, NULL, NULL, gs);
2664 gtk_object_unref(GTK_OBJECT(gs->hadj));
2666 if(gs->vadj && (gs->vadj != vadj)) {
2667 g_signal_handlers_disconnect_matched(G_OBJECT(gs->vadj),
2668 G_SIGNAL_MATCH_DATA,
2669 0, 0, NULL, NULL, gs);
2670 gtk_object_unref(GTK_OBJECT(gs->vadj));
2672 if(gs->hadj != hadj) {
2676 hadj->page_size = 1.0;
2677 hadj->page_increment = 1.0;
2679 gtk_object_ref(GTK_OBJECT(gs->hadj));
2680 gtk_object_sink(GTK_OBJECT(gs->hadj));
2682 g_signal_connect(G_OBJECT(hadj), "value_changed",
2683 G_CALLBACK(gtk_gs_value_adjustment_changed),
2686 if(gs->vadj != vadj) {
2690 vadj->page_size = 1.0;
2691 vadj->page_increment = 1.0;
2693 gtk_object_ref(GTK_OBJECT(gs->vadj));
2694 gtk_object_sink(GTK_OBJECT(gs->vadj));
2696 g_signal_connect(G_OBJECT(vadj), "value_changed",
2697 G_CALLBACK(gtk_gs_value_adjustment_changed),
2700 if(GTK_WIDGET_REALIZED(gs))
2701 gtk_gs_munge_adjustments(gs);
2706 gtk_gs_set_scroll_step(GtkGS * gs, gfloat scroll_step)
2708 gs->scroll_step = scroll_step;
2712 gtk_gs_get_scroll_step(GtkGS * gs)
2714 return gs->scroll_step;
2718 gtk_gs_set_zoom_mode(GtkGS * gs, GtkGSZoomMode zoom_mode)
2720 if(zoom_mode != gs->zoom_mode) {
2721 gs->zoom_mode = zoom_mode;
2722 gtk_gs_set_zoom(gs, 1.0);
2727 gtk_gs_get_zoom_mode(GtkGS * gs)
2729 return gs->zoom_mode;
2733 gtk_gs_set_available_size(GtkGS * gs, guint avail_w, guint avail_h)
2735 gs->avail_w = avail_w;
2736 gs->avail_h = avail_h;
2737 if(gs->zoom_mode != GTK_GS_ZOOM_ABSOLUTE) {
2738 gtk_gs_set_zoom(gs, 0.0);