From 1c0d19bd22598eca159c3febdcdaf4168891cb8f Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 23 Mar 2005 11:07:32 +0000 Subject: merge evince-threads branch --- (limited to 'ps') diff --git a/ps/gsdefaults.c b/ps/gsdefaults.c index faa4d06..a0c61d5 100644 --- a/ps/gsdefaults.c +++ b/ps/gsdefaults.c @@ -61,12 +61,6 @@ gtk_gs_defaults_get_interpreter_cmd() } const gchar * -gtk_gs_defaults_get_alpha_parameters (void) -{ - return ALPHA_PARAMS; -} - -const gchar * gtk_gs_defaults_get_ungzip_cmd (void) { return "gzip -cd"; diff --git a/ps/gsdefaults.h b/ps/gsdefaults.h index e8f4779..08431ff 100644 --- a/ps/gsdefaults.h +++ b/ps/gsdefaults.h @@ -32,7 +32,6 @@ G_BEGIN_DECLS GtkGSPaperSize *gtk_gs_defaults_get_paper_sizes(void); const gchar *gtk_gs_defaults_get_interpreter_cmd(void); -const gchar *gtk_gs_defaults_get_alpha_parameters(void); const gchar *gtk_gs_defaults_get_ungzip_cmd(void); const gchar *gtk_gs_defaults_get_unbzip2_cmd(void); diff --git a/ps/ps-document.c b/ps/ps-document.c index 958d768..4dd344b 100644 --- a/ps/ps-document.c +++ b/ps/ps-document.c @@ -22,108 +22,6 @@ * Boston, MA 02111-1307, USA. */ -/* -Ghostview interface to ghostscript - -When the GHOSTVIEW environment variable is set, ghostscript draws on -an existing drawable rather than creating its own window. Ghostscript -can be directed to draw on either a window or a pixmap. - -Drawing on a Window - -The GHOSTVIEW environment variable contains the window id of the target -window. The window id is an integer. Ghostscript will use the attributes -of the window to obtain the width, height, colormap, screen, and visual of -the window. The remainder of the information is gotten from the GHOSTVIEW -property on that window. - - -Drawing on a Pixmap - -The GHOSTVIEW environment variable contains a window id and a pixmap id. -They are integers separated by white space. Ghostscript will use the -attributes of the window to obtain the colormap, screen, and visual to use. -The width and height will be obtained from the pixmap. The remainder of the -information, is gotten from the GHOSTVIEW property on the window. In this -case, the property is deleted when read. - -The GHOSTVIEW environment variable - -parameters: window-id [pixmap-id] - -scanf format: "%d %d" - -explanation of parameters: - - window-id: tells ghostscript where to - - read the GHOSTVIEW property - - send events - If pixmap-id is not present, - ghostscript will draw on this window. - - pixmap-id: If present, tells ghostscript that a pixmap will be used - as the final destination for drawing. The window will - not be touched for drawing purposes. - -The GHOSTVIEW property - -type: STRING - -parameters: - - bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right] - -scanf format: "%d %d %d %d %d %d %f %f %d %d %d %d" - -explanation of parameters: - - bpixmap: pixmap id of the backing pixmap for the window. If no - pixmap is to be used, this parameter should be zero. This - parameter must be zero when drawing on a pixmap. - - orient: orientation of the page. The number represents clockwise - rotation of the paper in degrees. Permitted values are - 0, 90, 180, 270. - - llx, lly, urx, ury: Bounding box of the drawable. The bounding box - is specified in PostScript points in default user coordinates. - - xdpi, ydpi: Resolution of window. (This can be derived from the - other parameters, but not without roundoff error. These - values are included to avoid this error.) - - left, bottom, top, right: (optional) - Margins around the window. The margins extend the imageable - area beyond the boundaries of the window. This is primarily - used for popup zoom windows. I have encountered several - instances of PostScript programs that position themselves - with respect to the imageable area. The margins are specified - in PostScript points. If omitted, the margins are assumed to - be 0. - -Events from ghostscript - -If the final destination is a pixmap, the client will get a property notify -event when ghostscript reads the GHOSTVIEW property causing it to be deleted. - -Ghostscript sends events to the window where it read the GHOSTVIEW property. -These events are of type ClientMessage. The message_type is set to -either PAGE or DONE. The first long data value gives the window to be used -to send replies to ghostscript. The second long data value gives the primary -drawable. If rendering to a pixmap, it is the primary drawable. If rendering -to a window, the backing pixmap is the primary drawable. If no backing pixmap -is employed, then the window is the primary drawable. This field is necessary -to distinguish multiple ghostscripts rendering to separate pixmaps where the -GHOSTVIEW property was placed on the same window. - -The PAGE message indicates that a "page" has completed. Ghostscript will -wait until it receives a ClientMessage whose message_type is NEXT before -continuing. - -The DONE message indicates that ghostscript has finished processing. - -*/ - #include "config.h" #include #include @@ -134,10 +32,6 @@ The DONE message indicates that ghostscript has finished processing. #include #include #include -#ifdef HAVE_XINERAMA -# include -# include -#endif /* HAVE_XINERAMA */ #include #include #include @@ -162,9 +56,6 @@ The DONE message indicates that ghostscript has finished processing. # define O_NONBLOCK O_NDELAY #endif -#define PS_DOCUMENT_WATCH_INTERVAL 1000 -#define PS_DOCUMENT_WATCH_TIMEOUT 2 - #define MAX_BUFSIZE 1024 #define PS_DOCUMENT_IS_COMPRESSED(gs) (PS_DOCUMENT(gs)->gs_filename_unc != NULL) @@ -172,7 +63,9 @@ The DONE message indicates that ghostscript has finished processing. PS_DOCUMENT(gs)->gs_filename_unc : \ PS_DOCUMENT(gs)->gs_filename) -enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL }; +GCond* pixbuf_cond = NULL; +GMutex* pixbuf_mutex = NULL; +GdkPixbuf *current_pixbuf = NULL; enum { PROP_0, @@ -191,100 +84,67 @@ struct record_list { static gboolean broken_pipe = FALSE; -static void -catchPipe(int i) -{ - broken_pipe = True; -} - /* Forward declarations */ static void ps_document_init(PSDocument * gs); static void ps_document_class_init(PSDocumentClass * klass); -static void ps_document_emit_error_msg(PSDocument * gs, const gchar * msg); static void ps_document_finalize(GObject * object); static void send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close); -static void set_up_page(PSDocument * gs); static void close_pipe(int p[2]); -static void interpreter_failed(PSDocument * gs); -static float compute_xdpi(void); -static float compute_ydpi(void); -static gboolean compute_size(PSDocument * gs); static void output(gpointer data, gint source, GdkInputCondition condition); static void input(gpointer data, gint source, GdkInputCondition condition); static void stop_interpreter(PSDocument * gs); static gint start_interpreter(PSDocument * gs); -gboolean computeSize(void); -static gboolean ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid); static void ps_document_document_iface_init (EvDocumentIface *iface); -static gboolean ps_document_goto_page(PSDocument * gs, gint page); +static gboolean ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data); static GObjectClass *parent_class = NULL; static PSDocumentClass *gs_class = NULL; static void -ps_document_init(PSDocument * gs) +ps_document_init (PSDocument *gs) { - gs->bpixmap = NULL; + gs->bpixmap = NULL; - gs->current_page = 0; - gs->disable_start = FALSE; - gs->interpreter_pid = -1; + gs->current_page = 0; + gs->interpreter_pid = -1; - gs->width = -1; - gs->height = -1; - gs->busy = FALSE; - gs->changed = FALSE; - gs->gs_scanstyle = 0; - gs->gs_filename = 0; - gs->gs_filename_dsc = 0; - gs->gs_filename_unc = 0; + gs->width = -1; + gs->height = -1; + gs->busy = FALSE; + gs->gs_filename = 0; + gs->gs_filename_unc = 0; - broken_pipe = FALSE; + broken_pipe = FALSE; - gs->structured_doc = FALSE; - gs->reading_from_pipe = FALSE; - gs->send_filename_to_gs = FALSE; + gs->structured_doc = FALSE; + gs->reading_from_pipe = FALSE; + gs->send_filename_to_gs = FALSE; - gs->doc = NULL; - gs->loaded = FALSE; + gs->doc = NULL; + gs->loaded = FALSE; + + gs->interpreter_input = -1; + gs->interpreter_output = -1; + gs->interpreter_err = -1; + gs->interpreter_input_id = 0; + gs->interpreter_output_id = 0; + gs->interpreter_error_id = 0; + + gs->ps_input = NULL; + gs->input_buffer = NULL; + gs->input_buffer_ptr = NULL; + gs->bytes_left = 0; + gs->buffer_bytes_left = 0; - gs->interpreter_input = -1; - gs->interpreter_output = -1; - gs->interpreter_err = -1; - gs->interpreter_input_id = 0; - gs->interpreter_output_id = 0; - gs->interpreter_error_id = 0; - - gs->ps_input = NULL; - gs->input_buffer = NULL; - gs->input_buffer_ptr = NULL; - gs->bytes_left = 0; - gs->buffer_bytes_left = 0; - - gs->llx = 0; - gs->lly = 0; - gs->urx = 0; - gs->ury = 0; - gs->xdpi = compute_xdpi(); - gs->ydpi = compute_ydpi(); - - gs->left_margin = 0; - gs->top_margin = 0; - gs->right_margin = 0; - gs->bottom_margin = 0; - - gs->page_x_offset = 0; - gs->page_y_offset = 0; - - /* Set user defined defaults */ - gs->fallback_orientation = GTK_GS_ORIENTATION_PORTRAIT; - gs->zoom_factor = 1.0; - gs->default_size = 1; - gs->antialiased = TRUE; - gs->respect_eof = TRUE; - - gs->gs_status = _("No document loaded."); + gs->page_x_offset = 0; + gs->page_y_offset = 0; + gs->zoom_factor = 1.0; + + gs->gs_status = _("No document loaded."); + + pixbuf_cond = g_cond_new (); + pixbuf_mutex = g_mutex_new (); } static void @@ -325,63 +185,85 @@ ps_document_get_property (GObject *object, static void ps_document_class_init(PSDocumentClass *klass) { - GObjectClass *object_class; + GObjectClass *object_class; - object_class = (GObjectClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gs_class = klass; + object_class = (GObjectClass *) klass; + parent_class = g_type_class_peek_parent (klass); + gs_class = klass; - object_class->finalize = ps_document_finalize; - object_class->get_property = ps_document_get_property; - object_class->set_property = ps_document_set_property; + object_class->finalize = ps_document_finalize; + object_class->get_property = ps_document_get_property; + object_class->set_property = ps_document_set_property; - /* Create atoms */ - klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE); - klass->next_atom = gdk_atom_intern("NEXT", FALSE); - klass->page_atom = gdk_atom_intern("PAGE", FALSE); - klass->string_atom = gdk_atom_intern("STRING", FALSE); + klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE); + klass->next_atom = gdk_atom_intern ("NEXT", FALSE); + klass->page_atom = gdk_atom_intern ("PAGE", FALSE); + klass->string_atom = gdk_atom_intern ("STRING", FALSE); - g_object_class_override_property (object_class, PROP_TITLE, "title"); + g_object_class_override_property (object_class, PROP_TITLE, "title"); } -/* Clean all memory and temporal files */ static void -ps_document_cleanup(PSDocument * gs) +push_pixbuf (PSDocument *gs) { - g_return_if_fail(gs != NULL); - g_return_if_fail(GTK_IS_GS(gs)); + GdkColormap *cmap; + GdkPixbuf *pixbuf; + + cmap = gdk_window_get_colormap (gs->pstarget); + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap, + 0, 0, 0, 0, + gs->width, gs->height); + g_mutex_lock (pixbuf_mutex); + current_pixbuf = pixbuf; + g_cond_signal (pixbuf_cond); + g_mutex_unlock (pixbuf_mutex); - stop_interpreter(gs); +} - if(gs->gs_psfile) { - fclose(gs->gs_psfile); - gs->gs_psfile = NULL; - } - if(gs->gs_filename) { - g_free(gs->gs_filename); - gs->gs_filename = NULL; - } - if(gs->doc) { - psfree(gs->doc); - gs->doc = NULL; - } - if(gs->gs_filename_dsc) { - unlink(gs->gs_filename_dsc); - g_free(gs->gs_filename_dsc); - gs->gs_filename_dsc = NULL; - } - if(gs->gs_filename_unc) { - unlink(gs->gs_filename_unc); - g_free(gs->gs_filename_unc); - gs->gs_filename_unc = NULL; - } - gs->current_page = 0; - gs->loaded = FALSE; - gs->llx = 0; - gs->lly = 0; - gs->urx = 0; - gs->ury = 0; - set_up_page(gs); +static void +interpreter_failed (PSDocument *gs, char *msg) +{ + LOG ("Interpreter failed %s", msg); + + push_pixbuf (gs); + + stop_interpreter (gs); +} + +static void +ps_document_cleanup (PSDocument *gs) +{ + g_return_if_fail (gs != NULL); + g_return_if_fail (PS_IS_DOCUMENT (gs)); + + LOG ("Cleanup\n"); + + stop_interpreter (gs); + + if (gs->gs_psfile) { + fclose (gs->gs_psfile); + gs->gs_psfile = NULL; + } + + if (gs->gs_filename) { + g_free (gs->gs_filename); + gs->gs_filename = NULL; + } + + if (gs->doc) { + psfree (gs->doc); + gs->doc = NULL; + } + + if (gs->gs_filename_unc) { + unlink(gs->gs_filename_unc); + g_free(gs->gs_filename_unc); + gs->gs_filename_unc = NULL; + } + + gs->current_page = 0; + gs->loaded = FALSE; } static gboolean @@ -398,56 +280,19 @@ ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data) LOG ("GS rendered the document"); gs->busy = FALSE; - if (gs->scaling) { - ev_document_scale_changed (EV_DOCUMENT (gs)); - gs->scaling = FALSE; - } else { - ev_document_page_changed (EV_DOCUMENT (gs)); - } + push_pixbuf (gs); } return TRUE; } static void -ps_document_set_target (EvDocument *document, - GdkDrawable *target) -{ - PSDocument *gs = PS_DOCUMENT (document); - GtkWidget *widget; - gpointer data; - - if (gs->pstarget) { - gdk_window_get_user_data (gs->pstarget, &data); - g_return_if_fail (GTK_IS_WIDGET (data)); - - widget = GTK_WIDGET (data); - g_signal_handlers_disconnect_by_func - (widget, ps_document_widget_event, document); - } - - gs->pstarget = target; - - if (gs->pstarget) { - gdk_window_get_user_data (gs->pstarget, &data); - g_return_if_fail (GTK_IS_WIDGET (data)); - - widget = GTK_WIDGET (data); - g_signal_connect (widget, "event", - G_CALLBACK (ps_document_widget_event), - document); - } - - ps_document_goto_page (gs, gs->current_page); -} - -static void ps_document_finalize (GObject * object) { PSDocument *gs; g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_GS (object)); + g_return_if_fail (PS_IS_DOCUMENT (object)); LOG ("Finalize"); @@ -456,14 +301,12 @@ ps_document_finalize (GObject * object) ps_document_cleanup (gs); stop_interpreter (gs); - ps_document_set_target (EV_DOCUMENT (object), NULL); - if(gs->input_buffer) { g_free(gs->input_buffer); gs->input_buffer = NULL; } - (*G_OBJECT_CLASS(parent_class)->finalize) (object); + (*G_OBJECT_CLASS (parent_class)->finalize) (object); } static void @@ -505,143 +348,88 @@ send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close) } } -static gint -ps_document_get_orientation(PSDocument * gs) +static float +get_xdpi (PSDocument *gs) { - g_return_val_if_fail(gs != NULL, -1); - g_return_val_if_fail(GTK_IS_GS(gs), -1); - - if(gs->doc) { - if(gs->structured_doc) { - if(gs->doc->pages[MAX(gs->current_page, 0)].orientation != - GTK_GS_ORIENTATION_NONE) - gs->real_orientation = - gs->doc->pages[MAX(gs->current_page, 0)].orientation; - else - gs->real_orientation = gs->doc->default_page_orientation; - } - - if(gs->real_orientation == GTK_GS_ORIENTATION_NONE) - gs->real_orientation = gs->doc->orientation; - } + return 25.4 * gdk_screen_width() / gdk_screen_width_mm(); +} - if(gs->real_orientation == GTK_GS_ORIENTATION_NONE) - return gs->fallback_orientation; - else - return gs->real_orientation; +static float +get_ydpi (PSDocument *gs) +{ + return 25.4 * gdk_screen_height() / gdk_screen_height_mm(); } static void -set_up_page(PSDocument * gs) +setup_pixmap (PSDocument *gs) { - guint orientation; - char buf[1024]; - //GdkColormap *colormap; - GdkGC *fill; - GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */ - GdkColormap *colormap; - gboolean size_changed; - -#ifdef HAVE_LOCALE_H - char *savelocale; -#endif - - LOG ("Setup the page"); - - size_changed = compute_size (gs); - - if (gs->pstarget == NULL) - return; - - /* Do we have to check if the actual geometry changed? */ - - stop_interpreter(gs); - - orientation = ps_document_get_orientation(gs); - - if (size_changed || gs->bpixmap == NULL) { - gdk_flush(); - - /* clear new pixmap (set to white) */ - fill = gdk_gc_new(gs->pstarget); - if(fill) { - colormap = gdk_drawable_get_colormap(gs->pstarget); - gdk_color_alloc (colormap, &white); - gdk_gc_set_foreground(fill, &white); - - if(gs->width > 0 && gs->height > 0) { - if(gs->bpixmap) { - gdk_drawable_unref(gs->bpixmap); - gs->bpixmap = NULL; - } + GdkGC *fill; + GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */ + GdkColormap *colormap; LOG ("Create our internal pixmap"); - gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1); - gdk_draw_rectangle(gs->bpixmap, fill, TRUE, - 0, 0, gs->width, gs->height); - } - else { - gdk_draw_rectangle(gs->pstarget, fill, TRUE, - 0, 0, gs->width, gs->height); - } - gdk_gc_unref(fill); + if(gs->bpixmap) { + gdk_drawable_unref(gs->bpixmap); + } - gdk_flush(); - } - } + fill = gdk_gc_new (gs->pstarget); + colormap = gdk_drawable_get_colormap (gs->pstarget); + gdk_color_alloc (colormap, &white); + gdk_gc_set_foreground (fill, &white); + gs->bpixmap = gdk_pixmap_new (gs->pstarget, gs->width, gs->height, -1); + gdk_draw_rectangle (gs->bpixmap, fill, TRUE, + 0, 0, gs->width, gs->height); +} +static void +setup_page (PSDocument *gs) +{ + char buf[1024]; #ifdef HAVE_LOCALE_H - /* gs needs floating point parameters with '.' as decimal point - * while some (european) locales use ',' instead, so we set the - * locale for this snprintf to "C". - */ - savelocale = setlocale(LC_NUMERIC, "C"); + char *savelocale; #endif - g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d", - 0L, - orientation * 90, - gs->llx, - gs->lly, - gs->urx, - gs->ury, - gs->xdpi * gs->zoom_factor, - gs->ydpi * gs->zoom_factor, - gs->left_margin, - gs->bottom_margin, gs->right_margin, gs->top_margin); + LOG ("Setup the page"); - LOG ("GS property %s", buf); +#ifdef HAVE_LOCALE_H + /* gs needs floating point parameters with '.' as decimal point + * while some (european) locales use ',' instead, so we set the + * locale for this snprintf to "C". + */ + savelocale = setlocale (LC_NUMERIC, "C"); +#endif + + g_snprintf (buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d", + 0L, gs->orientation * 90, gs->llx, gs->lly, gs->urx, gs->ury, + get_xdpi (gs) * gs->zoom_factor, + get_ydpi (gs) * gs->zoom_factor, + 0, 0, 0, 0); + LOG ("GS property %s", buf); #ifdef HAVE_LOCALE_H - setlocale(LC_NUMERIC, savelocale); + setlocale(LC_NUMERIC, savelocale); #endif - gdk_property_change(gs->pstarget, - gs_class->gs_atom, - gs_class->string_atom, - 8, GDK_PROP_MODE_REPLACE, buf, strlen(buf)); - gdk_flush(); + gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom, + 8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen(buf)); + gdk_flush (); } static void -close_pipe(int p[2]) +close_pipe (int p[2]) { - if(p[0] != -1) - close(p[0]); - if(p[1] != -1) - close(p[1]); + if (p[0] != -1) { + close (p[0]); + } + if (p[1] != -1) { + close (p[1]); + } } static gboolean -is_interpreter_ready(PSDocument * gs) +is_interpreter_ready (PSDocument *gs) { - return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL); -} - -static void -interpreter_failed(PSDocument * gs) -{ - stop_interpreter(gs); + return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL); } static void @@ -661,11 +449,11 @@ output(gpointer data, gint source, GdkInputCondition condition) } else if(bytes == -1) { /* trouble... */ - interpreter_failed(gs); + interpreter_failed(gs, NULL); return; } if(gs->interpreter_err == -1) { - stop_interpreter(gs); + interpreter_failed(gs, NULL); } } else if(source == gs->interpreter_err) { @@ -678,21 +466,27 @@ output(gpointer data, gint source, GdkInputCondition condition) } else if(bytes == -1) { /* trouble... */ - interpreter_failed(gs); + interpreter_failed(gs, NULL); return; } if(gs->interpreter_output == -1) { - stop_interpreter(gs); + interpreter_failed(gs, NULL); } } if(bytes > 0) { buf[bytes] = '\0'; msg = g_strdup(buf); - ps_document_emit_error_msg (gs, msg); + interpreter_failed (gs, msg); } } static void +catchPipe(int i) +{ + broken_pipe = True; +} + +static void input(gpointer data, gint source, GdkInputCondition condition) { PSDocument *gs = PS_DOCUMENT(data); @@ -700,6 +494,8 @@ input(gpointer data, gint source, GdkInputCondition condition) void (*oldsig) (int); oldsig = signal(SIGPIPE, catchPipe); + LOG ("Input"); + do { if(gs->buffer_bytes_left == 0) { /* Get a new section if required */ @@ -730,26 +526,24 @@ input(gpointer data, gint source, GdkInputCondition condition) gs->buffer_bytes_left = 0; } if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) { - interpreter_failed(gs); /* Error occurred */ + interpreter_failed (gs, NULL); /* Error occurred */ } gs->input_buffer_ptr = gs->input_buffer; gs->bytes_left -= gs->buffer_bytes_left; } if(gs->buffer_bytes_left > 0) { - /* g_print (" writing: %s\n",gs->input_buffer_ptr); */ - bytes_written = write(gs->interpreter_input, gs->input_buffer_ptr, gs->buffer_bytes_left); if(broken_pipe) { - ps_document_emit_error_msg(gs, g_strdup(_("Broken pipe."))); + interpreter_failed (gs, g_strdup(_("Broken pipe."))); broken_pipe = FALSE; - interpreter_failed(gs); + interpreter_failed (gs, NULL); } else if(bytes_written == -1) { if((errno != EWOULDBLOCK) && (errno != EAGAIN)) { - interpreter_failed(gs); /* Something bad happened */ + interpreter_failed (gs, NULL); /* Something bad happened */ } } else { @@ -771,161 +565,149 @@ input(gpointer data, gint source, GdkInputCondition condition) } static int -start_interpreter(PSDocument * gs) +start_interpreter (PSDocument *gs) { - int std_in[2] = { -1, -1 }; /* pipe to interp stdin */ - int std_out[2]; /* pipe from interp stdout */ - int std_err[2]; /* pipe from interp stderr */ + int std_in[2] = { -1, -1 }; /* pipe to interp stdin */ + int std_out[2]; /* pipe from interp stdout */ + int std_err[2]; /* pipe from interp stderr */ #define NUM_ARGS 100 #define NUM_GS_ARGS (NUM_ARGS - 20) #define NUM_ALPHA_ARGS 10 - char *argv[NUM_ARGS], *dir, *gv_env; - char **gs_args, **alpha_args = NULL; - int argc = 0, i; + char *argv[NUM_ARGS], *dir, *gv_env; + char **gs_args, **alpha_args = NULL; + int argc = 0, i; - LOG ("Start the interpreter"); + LOG ("Start the interpreter"); - if(!gs->gs_filename) - return 0; + if(!gs->gs_filename) + return 0; - stop_interpreter(gs); + stop_interpreter(gs); - if(gs->disable_start == TRUE) - return 0; + /* set up the args... */ + gs_args = g_strsplit (gtk_gs_defaults_get_interpreter_cmd (), " ", NUM_GS_ARGS); + for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) { + argv[argc] = gs_args[i]; + } - /* set up the args... */ - gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS); - for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) - argv[argc] = gs_args[i]; - - if(gs->antialiased) { - if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0) - alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS); - else - alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(), - " ", NUM_ALPHA_ARGS); - for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) - argv[argc] = alpha_args[i]; - } - else - argv[argc++] = "-sDEVICE=x11"; - argv[argc++] = "-dNOPAUSE"; - argv[argc++] = "-dQUIET"; - /* I assume we do _not_ want to change this... (: */ - argv[argc++] = "-dSAFER"; - - /* set up the pipes */ - if(gs->send_filename_to_gs) { - argv[argc++] = PS_DOCUMENT_GET_PS_FILE(gs); - argv[argc++] = "-c"; - argv[argc++] = "quit"; - } - else - argv[argc++] = "-"; + alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS); - argv[argc++] = NULL; + argv[argc++] = "-dNOPAUSE"; + argv[argc++] = "-dQUIET"; + argv[argc++] = "-dSAFER"; - if(!gs->reading_from_pipe && !gs->send_filename_to_gs) { - if(pipe(std_in) == -1) { - g_critical("Unable to open pipe to Ghostscript."); - return -1; - } - } - if(pipe(std_out) == -1) { - close_pipe(std_in); - return -1; - } - if(pipe(std_err) == -1) { - close_pipe(std_in); - close_pipe(std_out); - return -1; - } + /* set up the pipes */ + if (gs->send_filename_to_gs) { + argv[argc++] = PS_DOCUMENT_GET_PS_FILE (gs); + argv[argc++] = "-c"; + argv[argc++] = "quit"; + } else { + argv[argc++] = "-"; + } - gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld", - gdk_x11_drawable_get_xid(gs->pstarget), - gdk_x11_drawable_get_xid(gs->bpixmap)); - - LOG ("Launching ghostview with env %s", gv_env); - - gs->busy = TRUE; - gs->interpreter_pid = fork(); - switch (gs->interpreter_pid) { - case -1: /* error */ - close_pipe(std_in); - close_pipe(std_out); - close_pipe(std_err); - return -2; - break; - case 0: /* child */ - close(std_out[0]); - dup2(std_out[1], 1); - close(std_out[1]); - - close(std_err[0]); - dup2(std_err[1], 2); - close(std_err[1]); - - if(!gs->reading_from_pipe) { - if(gs->send_filename_to_gs) { - int stdinfd; - /* just in case gs tries to read from stdin */ - stdinfd = open("/dev/null", O_RDONLY); - if(stdinfd != 0) { - dup2(stdinfd, 0); - close(stdinfd); - } - } - else { - close(std_in[1]); - dup2(std_in[0], 0); - close(std_in[0]); - } - } + argv[argc++] = NULL; - putenv(gv_env); - - /* change to directory where the input file is. This helps - * with postscript-files which include other files using - * a relative path */ - dir = g_path_get_dirname(gs->gs_filename); - chdir(dir); - g_free(dir); - - execvp(argv[0], argv); - - /* Notify error */ - g_print("Unable to execute [%s]\n", argv[0]); - g_strfreev(gs_args); - g_free(gv_env); - if(alpha_args) - g_strfreev(alpha_args); - _exit(1); - break; - default: /* parent */ - if(!gs->send_filename_to_gs && !gs->reading_from_pipe) { - int result; - close(std_in[0]); - /* use non-blocking IO for pipe to ghostscript */ - result = fcntl(std_in[1], F_GETFL, 0); - fcntl(std_in[1], F_SETFL, result | O_NONBLOCK); - gs->interpreter_input = std_in[1]; - } - else { - gs->interpreter_input = -1; - } - close(std_out[1]); - gs->interpreter_output = std_out[0]; - close(std_err[1]); - gs->interpreter_err = std_err[0]; - gs->interpreter_output_id = - gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs); - gs->interpreter_error_id = - gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs); - break; - } - return TRUE; + if (!gs->reading_from_pipe && !gs->send_filename_to_gs) { + if (pipe (std_in) == -1) { + g_critical ("Unable to open pipe to Ghostscript."); + return -1; + } + } + + if (pipe (std_out) == -1) { + close_pipe (std_in); + return -1; + } + + if (pipe(std_err) == -1) { + close_pipe (std_in); + close_pipe (std_out); + return -1; + } + + gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld", + gdk_x11_drawable_get_xid (gs->pstarget), + gdk_x11_drawable_get_xid (gs->bpixmap)); + LOG ("Launching ghostview with env %s", gv_env); + + gs->busy = TRUE; + gs->interpreter_pid = fork (); + switch (gs->interpreter_pid) { + case -1: /* error */ + close_pipe (std_in); + close_pipe (std_out); + close_pipe (std_err); + return -2; + break; + case 0: /* child */ + close (std_out[0]); + dup2 (std_out[1], 1); + close (std_out[1]); + + close (std_err[0]); + dup2 (std_err[1], 2); + close (std_err[1]); + + if (!gs->reading_from_pipe) { + if (gs->send_filename_to_gs) { + int stdinfd; + /* just in case gs tries to read from stdin */ + stdinfd = open("/dev/null", O_RDONLY); + if (stdinfd != 0) { + dup2(stdinfd, 0); + close(stdinfd); + } + } else { + close (std_in[1]); + dup2 (std_in[0], 0); + close (std_in[0]); + } + } + + putenv(gv_env); + + /* change to directory where the input file is. This helps + * with postscript-files which include other files using + * a relative path */ + dir = g_path_get_dirname (gs->gs_filename); + chdir (dir); + g_free (dir); + + execvp (argv[0], argv); + + /* Notify error */ + g_critical ("Unable to execute [%s]\n", argv[0]); + g_strfreev (gs_args); + g_free (gv_env); + g_strfreev (alpha_args); + _exit (1); + break; + default: /* parent */ + if (!gs->send_filename_to_gs && !gs->reading_from_pipe) { + int result; + close (std_in[0]); + /* use non-blocking IO for pipe to ghostscript */ + result = fcntl (std_in[1], F_GETFL, 0); + fcntl (std_in[1], F_SETFL, result | O_NONBLOCK); + gs->interpreter_input = std_in[1]; + } else { + gs->interpreter_input = -1; + } + close (std_out[1]); + + gs->interpreter_output = std_out[0]; + close (std_err[1]); + gs->interpreter_err = std_err[0]; + gs->interpreter_output_id = + gdk_input_add (std_out[0], GDK_INPUT_READ, output, gs); + gs->interpreter_error_id = + gdk_input_add (std_err[0], GDK_INPUT_READ, output, gs); + break; + } + + return TRUE; } static void @@ -1063,16 +845,7 @@ check_filecompressed(PSDocument * gs) /* report error */ g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"), gs->gs_filename); - ps_document_emit_error_msg(gs, buf); - if(file_length(filename_err) > 0) { - FILE *err; - if((err = fopen(filename_err, "r"))) { - /* print file to message window */ - while(fgets(buf, 1024, err)) - ps_document_emit_error_msg(gs, buf); - fclose(err); - } - } + interpreter_failed (gs, buf); unlink(filename_unc); g_free(filename_unc); filename_unc = NULL; @@ -1084,112 +857,100 @@ check_filecompressed(PSDocument * gs) return filename_unc; } -#ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED -/* never mind this patch: a properly working X server should take care of - calculating the proper values. */ -static float -compute_xdpi(void) -{ -# ifndef HAVE_XINERAMA - return 25.4 * gdk_screen_width() / gdk_screen_width_mm(); -# else - Display *dpy; - dpy = (Display *) GDK_DISPLAY(); - if(XineramaIsActive(dpy)) { - int num_heads; - XineramaScreenInfo *head_info; - head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads); - /* fake it with dimensions of the first head for now */ - return 25.4 * head_info[0].width / gdk_screen_width_mm(); - } - else { - return 25.4 * gdk_screen_width() / gdk_screen_width_mm(); - } -# endif - /* HAVE_XINERAMA */ -} - -static float -compute_ydpi(void) -{ -# ifndef HAVE_XINERAMA - return 25.4 * gdk_screen_height() / gdk_screen_height_mm(); -# else - Display *dpy; - dpy = (Display *) GDK_DISPLAY(); - if(XineramaIsActive(dpy)) { - int num_heads; - XineramaScreenInfo *head_info; - head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads); - /* fake it with dimensions of the first head for now */ - return 25.4 * head_info[0].height / gdk_screen_height_mm(); - } - else { - return 25.4 * gdk_screen_height() / gdk_screen_height_mm(); - } -# endif - /* HAVE_XINERAMA */ -} -#else -static float -compute_xdpi(void) -{ - return 25.4 * gdk_screen_width() / gdk_screen_width_mm(); -} - -static float -compute_ydpi(void) +static void +compute_dimensions (PSDocument *gs, int page) { - return 25.4 * gdk_screen_height() / gdk_screen_height_mm(); -} -#endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */ + GtkGSPaperSize *paper_sizes = gtk_gs_defaults_get_paper_sizes (); + int urx, ury, llx, lly; + int width, height; + int orientation; + + g_return_if_fail (PS_IS_DOCUMENT (gs)); + g_return_if_fail (gs->doc != NULL); + g_return_if_fail (page >= 0); + g_return_if_fail (gs->doc->numpages > page); + + orientation = GTK_GS_ORIENTATION_NONE; + if (gs->structured_doc) { + orientation = gs->doc->pages[gs->current_page].orientation; + } + if (orientation == GTK_GS_ORIENTATION_NONE) { + orientation = GTK_GS_ORIENTATION_PORTRAIT; + } -/* Compute new size of window, sets xdpi and ydpi if necessary. - * returns True if new window size is different */ -static gboolean -compute_size(PSDocument * gs) -{ - guint new_width = 1; - guint new_height = 1; - gboolean change = FALSE; - gint orientation; - - /* width and height can be changed, calculate window size according */ - /* to xpdi and ydpi */ - orientation = ps_document_get_orientation(gs); - - switch (orientation) { - case GTK_GS_ORIENTATION_PORTRAIT: - case GTK_GS_ORIENTATION_UPSIDEDOWN: - new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5; - new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5; - break; - case GTK_GS_ORIENTATION_LANDSCAPE: - case GTK_GS_ORIENTATION_SEASCAPE: - new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5; - new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5; - break; - } + if (gs->doc->pages && gs->doc->pages[page].size) { + int page_size; + + page_size = gs->doc->pages[page].size - gs->doc->size; + llx = lly = 0; + urx = gs->doc->size[page_size].width; + ury = gs->doc->size[page_size].height; + } else if (gs->doc->pages && + (gs->doc->pages[page].boundingbox[URX] > + gs->doc->pages[page].boundingbox[LLX]) && + (gs->doc->pages[page].boundingbox[URY] > + gs->doc->pages[page].boundingbox[LLY])) { + llx = gs->doc->pages[page].boundingbox[LLX]; + lly = gs->doc->pages[page].boundingbox[LLY]; + urx = gs->doc->pages[page].boundingbox[URX]; + ury = gs->doc->pages[page].boundingbox[URY]; + } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && + (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { + llx = gs->doc->boundingbox[LLX]; + lly = gs->doc->boundingbox[LLY]; + urx = gs->doc->boundingbox[URX]; + ury = gs->doc->boundingbox[URY]; + } else { + /* Fallback to A4 */ + llx = lly = 0; + urx = paper_sizes[12].width; + ury = paper_sizes[12].height; + } - change = (new_width != gs->width * gs->zoom_factor) - || (new_height != gs->height * gs->zoom_factor); - gs->width = (gint) (new_width * gs->zoom_factor); - gs->height = (gint) (new_height * gs->zoom_factor); + switch (orientation) { + case GTK_GS_ORIENTATION_PORTRAIT: + case GTK_GS_ORIENTATION_UPSIDEDOWN: + width = (urx - llx) / 72.0 * get_xdpi (gs) + 0.5; + height = (ury - lly) / 72.0 * get_ydpi (gs) + 0.5; + break; + case GTK_GS_ORIENTATION_LANDSCAPE: + case GTK_GS_ORIENTATION_SEASCAPE: + width = (ury - lly) / 72.0 * get_xdpi (gs) + 0.5; + height = (urx - llx) / 72.0 * get_ydpi (gs) + 0.5; + break; + default: + width = height = 0; + g_assert_not_reached (); + break; + } - return (change); + width = width * gs->zoom_factor; + height = height * gs->zoom_factor; + + if (llx != gs->llx || lly != gs->lly || + urx != gs->urx || ury != gs->ury || + gs->width != width || gs->height != height || + orientation != gs->orientation) { + gs->llx = llx; + gs->lly = lly; + gs->urx = urx; + gs->ury = ury; + gs->width = width; + gs->height = height; + gs->orientation = orientation; + gs->changed = TRUE; + } } static gint ps_document_enable_interpreter(PSDocument * gs) { g_return_val_if_fail(gs != NULL, FALSE); - g_return_val_if_fail(GTK_IS_GS(gs), FALSE); + g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE); if(!gs->gs_filename) return 0; - gs->disable_start = FALSE; - return start_interpreter(gs); } @@ -1231,24 +992,11 @@ ps_document_get_type(void) } -/* - * Show error message -> send signal "interpreter_message" - */ -static void -ps_document_emit_error_msg(PSDocument * gs, const gchar * msg) -{ - gdk_pointer_ungrab(GDK_CURRENT_TIME); - if(strstr(msg, "Error:")) { - gs->gs_status = _("File is not a valid PostScript document."); - ps_document_cleanup(gs); - } -} - static gboolean document_load(PSDocument * gs, const gchar * fname) { g_return_val_if_fail(gs != NULL, FALSE); - g_return_val_if_fail(GTK_IS_GS(gs), FALSE); + g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE); LOG ("Load the document"); @@ -1261,8 +1009,6 @@ document_load(PSDocument * gs, const gchar * fname) } /* prepare this document */ - - /* default values: no dsc information available */ gs->structured_doc = FALSE; gs->send_filename_to_gs = TRUE; gs->current_page = 0; @@ -1291,7 +1037,7 @@ document_load(PSDocument * gs, const gchar * fname) if(!file_readable(fname)) { gchar buf[1024]; g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname); - ps_document_emit_error_msg(gs, buf); + interpreter_failed (gs, buf); gs->gs_status = _("File is not readable."); } else { @@ -1299,12 +1045,13 @@ document_load(PSDocument * gs, const gchar * fname) } if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) { + interpreter_failed (gs, NULL); ps_document_cleanup(gs); return FALSE; } /* we grab the vital statistics!!! */ - gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename); + gs->doc = psscan(gs->gs_psfile, TRUE, filename); g_object_notify (G_OBJECT (gs), "title"); @@ -1312,7 +1059,7 @@ document_load(PSDocument * gs, const gchar * fname) /* File does not seem to be a Postscript one */ gchar buf[1024]; g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname); - ps_document_emit_error_msg(gs, buf); + interpreter_failed (gs, buf); ps_document_cleanup(gs); gs->gs_status = _("The file is not a PostScript document."); return FALSE; @@ -1323,12 +1070,9 @@ document_load(PSDocument * gs, const gchar * fname) gs->structured_doc = TRUE; gs->send_filename_to_gs = FALSE; } - - /* We have to set up the orientation of the document */ - gs->real_orientation = gs->doc->orientation; } - ps_document_set_page_size(gs, -1, gs->current_page); gs->loaded = TRUE; + compute_dimensions (gs, gs->current_page); gs->gs_status = _("Document loaded."); @@ -1337,246 +1081,75 @@ document_load(PSDocument * gs, const gchar * fname) static gboolean -ps_document_next_page(PSDocument * gs) +ps_document_next_page (PSDocument *gs) { - XEvent event; - - LOG ("Make ghostscript render next page"); - - g_return_val_if_fail(gs != NULL, FALSE); - g_return_val_if_fail(GTK_IS_GS(gs), FALSE); - - if(gs->interpreter_pid == 0) { /* no interpreter active */ - return FALSE; - } - - if(gs->busy) { /* interpreter is busy */ - return FALSE; - } - - gs->busy = TRUE; - - event.xclient.type = ClientMessage; - event.xclient.display = gdk_display; - event.xclient.window = gs->message_window; - event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom); - event.xclient.format = 32; - - gdk_error_trap_push(); - XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event); - gdk_flush(); - gdk_error_trap_pop(); - - return TRUE; -} - -static gboolean -ps_document_goto_page(PSDocument * gs, gint page) -{ - g_return_val_if_fail(gs != NULL, FALSE); - g_return_val_if_fail(GTK_IS_GS(gs), FALSE); - - LOG ("Go to page %d", page); - - if(!gs->gs_filename) { - return FALSE; - } - - /* range checking... */ - if(page < 0) - page = 0; - - if(gs->structured_doc && gs->doc) { - - LOG ("It's a structured document, let's send one page to gs"); - - if(page >= gs->doc->numpages) - page = gs->doc->numpages - 1; - - if(page == gs->current_page && !gs->changed) - return TRUE; - - gs->current_page = page; - - if(gs->doc->pages[page].orientation != NONE && - gs->doc->pages[page].orientation != gs->real_orientation) { - gs->real_orientation = gs->doc->pages[page].orientation; - gs->changed = TRUE; - } - - ps_document_set_page_size(gs, -1, page); + XEvent event; - gs->changed = FALSE; + LOG ("Make ghostscript render next page"); - if(is_interpreter_ready(gs)) { - ps_document_next_page(gs); - } - else { - ps_document_enable_interpreter(gs); - send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE); - send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE); - } + g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE); + g_return_val_if_fail (gs->interpreter_pid != 0, FALSE); + g_return_val_if_fail (gs->busy != TRUE, FALSE); - send_ps(gs, gs->doc->pages[gs->current_page].begin, - gs->doc->pages[gs->current_page].len, FALSE); - } - else { - /* Unstructured document */ - /* In the case of non structured documents, - GS read the PS from the actual file (via command - line. Hence, ggv only send a signal next page. - If ghostview is not running it is usually because - the last page of the file was displayed. In that - case, ggv restarts GS again and the first page is displayed. - */ + gs->busy = TRUE; - LOG ("It's an unstructured document, gs will just read the file"); + event.xclient.type = ClientMessage; + event.xclient.display = gdk_display; + event.xclient.window = gs->message_window; + event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom); + event.xclient.format = 32; - if(page == gs->current_page && !gs->changed) - return TRUE; + gdk_error_trap_push (); + XSendEvent (gdk_display, gs->message_window, FALSE, 0, &event); + gdk_flush (); + gdk_error_trap_pop (); - ps_document_set_page_size(gs, -1, page); - - if(!is_interpreter_ready(gs)) - ps_document_enable_interpreter(gs); - - gs->current_page = page; - - ps_document_next_page(gs); - } - return TRUE; + return TRUE; } -/* - * set pagesize sets the size from - * if new_pagesize is -1, then it is set to either - * a) the default settings of pageid, if they exist, or if pageid != -1. - * b) the default setting of the document, if it exists. - * c) the default setting of the widget. - * otherwise, the new_pagesize is used as the pagesize - */ static gboolean -ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid) +render_page (PSDocument *gs) { - gint new_llx = 0; - gint new_lly = 0; - gint new_urx = 0; - gint new_ury = 0; - GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes(); - - LOG ("Set the page size"); - - g_return_val_if_fail(gs != NULL, FALSE); - g_return_val_if_fail(GTK_IS_GS(gs), FALSE); - - if(new_pagesize == -1) { - if(gs->default_size > 0) - new_pagesize = gs->default_size; - if(gs->doc) { - /* If we have a document: - We use -- the page size (if specified) - or the doc. size (if specified) - or the page bbox (if specified) - or the bounding box - */ - if((pageid >= 0) && (gs->doc->numpages > pageid) && - (gs->doc->pages) && (gs->doc->pages[pageid].size)) { - new_pagesize = gs->doc->pages[pageid].size - gs->doc->size; - } - else if(gs->doc->default_page_size != NULL) { - new_pagesize = gs->doc->default_page_size - gs->doc->size; - } - else if((pageid >= 0) && - (gs->doc->numpages > pageid) && - (gs->doc->pages) && - (gs->doc->pages[pageid].boundingbox[URX] > - gs->doc->pages[pageid].boundingbox[LLX]) && - (gs->doc->pages[pageid].boundingbox[URY] > - gs->doc->pages[pageid].boundingbox[LLY])) { - new_pagesize = -1; - } - else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && - (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { - new_pagesize = -1; - } - } - } + g_return_val_if_fail(gs != NULL, FALSE); + g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE); - /* Compute bounding box */ - if(gs->doc && (gs->doc->epsf || new_pagesize == -1)) { /* epsf or bbox */ - if((pageid >= 0) && - (gs->doc->pages) && - (gs->doc->pages[pageid].boundingbox[URX] > - gs->doc->pages[pageid].boundingbox[LLX]) - && (gs->doc->pages[pageid].boundingbox[URY] > - gs->doc->pages[pageid].boundingbox[LLY])) { - /* use page bbox */ - new_llx = gs->doc->pages[pageid].boundingbox[LLX]; - new_lly = gs->doc->pages[pageid].boundingbox[LLY]; - new_urx = gs->doc->pages[pageid].boundingbox[URX]; - new_ury = gs->doc->pages[pageid].boundingbox[URY]; - } - else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && - (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { - /* use doc bbox */ - new_llx = gs->doc->boundingbox[LLX]; - new_lly = gs->doc->boundingbox[LLY]; - new_urx = gs->doc->boundingbox[URX]; - new_ury = gs->doc->boundingbox[URY]; - } - } - else { - if(new_pagesize < 0) - new_pagesize = gs->default_size; - new_llx = new_lly = 0; - if(gs->doc && gs->doc->size && - (new_pagesize < gs->doc->numsizes)) { - new_urx = gs->doc->size[new_pagesize].width; - new_ury = gs->doc->size[new_pagesize].height; - } - else { - new_urx = papersizes[new_pagesize].width; - new_ury = papersizes[new_pagesize].height; - } - } - - if(new_urx <= new_llx) - new_urx = papersizes[12].width; - if(new_ury <= new_lly) - new_ury = papersizes[12].height; - - /* If bounding box changed, setup for new size. */ - /* ps_document_disable_interpreter (gs); */ - if((new_llx != gs->llx) || (new_lly != gs->lly) || - (new_urx != gs->urx) || (new_ury != gs->ury)) { - gs->llx = new_llx; - gs->lly = new_lly; - gs->urx = new_urx; - gs->ury = new_ury; - gs->changed = TRUE; - } - - if(gs->changed) { - set_up_page(gs); - return TRUE; - } + if(!gs->gs_filename) { + return FALSE; + } - return FALSE; -} + if (gs->structured_doc && gs->doc) { + LOG ("It's a structured document, let's send one page to gs"); -static void -ps_document_set_zoom (PSDocument * gs, gfloat zoom) -{ - g_return_if_fail (gs != NULL); - - gs->zoom_factor = zoom; + if (is_interpreter_ready (gs)) { + ps_document_next_page (gs); + } else { + ps_document_enable_interpreter (gs); + send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE); + send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE); + } - if (gs->pstarget != NULL) { - set_up_page(gs); - gs->changed = TRUE; - gs->scaling = TRUE; - ps_document_goto_page (gs, gs->current_page); + send_ps (gs, gs->doc->pages[gs->current_page].begin, + gs->doc->pages[gs->current_page].len, FALSE); + } else { + /* Unstructured document + * + * In the case of non structured documents, + * GS read the PS from the actual file (via command + * line. Hence, ggv only send a signal next page. + * If ghostview is not running it is usually because + * the last page of the file was displayed. In that + * case, ggv restarts GS again and the first page is displayed. + */ + + LOG ("It's an unstructured document, gs will just read the file"); + + if (!is_interpreter_ready (gs)) { + ps_document_enable_interpreter(gs); + } + ps_document_next_page(gs); } + + return TRUE; } static gboolean @@ -1631,7 +1204,12 @@ static void ps_document_set_page (EvDocument *document, int page) { - ps_document_goto_page (PS_DOCUMENT (document), page - 1); + PSDocument *gs = PS_DOCUMENT (document); + + LOG ("Set document page %d\n", page); + + gs->current_page = page - 1; + compute_dimensions (gs, page); } static int @@ -1648,7 +1226,10 @@ static void ps_document_set_scale (EvDocument *document, double scale) { - ps_document_set_zoom (PS_DOCUMENT (document), scale); + PSDocument *gs = PS_DOCUMENT (document); + + gs->zoom_factor = scale; + compute_dimensions (gs, gs->current_page); } static void @@ -1681,48 +1262,6 @@ ps_document_get_page_size (EvDocument *document, } } -static void -ps_document_render (EvDocument *document, - int clip_x, - int clip_y, - int clip_width, - int clip_height) -{ - PSDocument *gs = PS_DOCUMENT (document); - GdkRectangle page; - GdkRectangle draw; - GdkGC *gc; - - if (gs->pstarget == NULL || - gs->bpixmap == NULL) { - return; - } - - page.x = gs->page_x_offset; - page.y = gs->page_y_offset; - page.width = gs->width; - page.height = gs->height; - - draw.x = clip_x; - draw.y = clip_y; - draw.width = clip_width; - draw.height = clip_height; - - gc = gdk_gc_new (gs->pstarget); - - gdk_draw_drawable (gs->pstarget, gc, - gs->bpixmap, - draw.x - page.x, draw.y - page.y, - draw.x, draw.y, - draw.width, draw.height); - - LOG ("Copy the internal pixmap: %d %d %d %d %d %d", - draw.x - page.x, draw.y - page.y, - draw.x, draw.y, draw.width, draw.height); - - g_object_unref (gc); -} - static char * ps_document_get_text (EvDocument *document, GdkRectangle *rect) { @@ -1738,6 +1277,56 @@ ps_document_get_link (EvDocument *document, return NULL; } +static gboolean +render_pixbuf_idle (EvDocument *document) +{ + PSDocument *gs = PS_DOCUMENT (document); + + if (gs->pstarget == NULL) { + GtkWidget *widget; + + widget = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_realize (widget); + gs->pstarget = widget->window; + + g_assert (gs->pstarget != NULL); + + g_signal_connect (widget, "event", + G_CALLBACK (ps_document_widget_event), + gs); + } + + if (gs->changed) { + stop_interpreter (gs); + setup_pixmap (gs); + setup_page (gs); + gs->changed = FALSE; + } + + render_page (PS_DOCUMENT (document)); + + return FALSE; +} + +static GdkPixbuf * +ps_document_render_pixbuf (EvDocument *document) +{ + GdkPixbuf *pixbuf; + + g_idle_add ((GSourceFunc)render_pixbuf_idle, document); + + g_mutex_lock (pixbuf_mutex); + while (!current_pixbuf) + g_cond_wait (pixbuf_cond, pixbuf_mutex); + pixbuf = current_pixbuf; + current_pixbuf = NULL; + g_mutex_unlock (pixbuf_mutex); + + LOG ("Pixbuf rendered %p\n", pixbuf); + + return pixbuf; +} + static void ps_document_document_iface_init (EvDocumentIface *iface) { @@ -1749,8 +1338,7 @@ ps_document_document_iface_init (EvDocumentIface *iface) iface->set_page = ps_document_set_page; iface->get_page = ps_document_get_page; iface->set_scale = ps_document_set_scale; - iface->set_target = ps_document_set_target; iface->set_page_offset = ps_document_set_page_offset; iface->get_page_size = ps_document_get_page_size; - iface->render = ps_document_render; + iface->render_pixbuf = ps_document_render_pixbuf; } diff --git a/ps/ps-document.h b/ps/ps-document.h index f7c8e92..1c6761b 100644 --- a/ps/ps-document.h +++ b/ps/ps-document.h @@ -35,23 +35,18 @@ G_BEGIN_DECLS #define PS_TYPE_DOCUMENT (ps_document_get_type()) #define PS_DOCUMENT(obj) GTK_CHECK_CAST (obj, ps_document_get_type (), PSDocument) #define PS_DOCUMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ps_document_get_type (), PSDocumentClass) -#define GTK_IS_GS(obj) GTK_CHECK_TYPE (obj, ps_document_get_type()) +#define PS_IS_DOCUMENT(obj) GTK_CHECK_TYPE (obj, ps_document_get_type()) typedef struct _PSDocument PSDocument; typedef struct _PSDocumentClass PSDocumentClass; struct _PSDocument { GObject object; - GdkWindow *pstarget; /* the window passed to gv - * it is a child of widget... - */ - GdkGC *psgc; - - GdkPixmap *bpixmap; /* Backing pixmap */ + GdkWindow *pstarget; + GdkPixmap *bpixmap; long message_window; /* Used by ghostview to receive messages from app */ - int disable_start; /* Can the interpreter be started? */ pid_t interpreter_pid; /* PID of interpreter, -1 if none */ int interpreter_input; /* stdin of interpreter */ int interpreter_output; /* stdout of interpreter */ @@ -60,22 +55,19 @@ struct _PSDocument { guint interpreter_output_id; guint interpreter_error_id; + gint width; /* Size of window at last setup() */ gint llx; gint lly; gint urx; gint ury; - gint left_margin; - gint right_margin; - gint top_margin; - gint bottom_margin; - gint width; /* Size of window at last setup() */ gint height; + gint orientation; gboolean busy; /* Is gs busy drawing? */ - gboolean changed; /* Anything changed since setup */ gfloat zoom_factor; gint current_page; gboolean structured_doc; gboolean loaded; + gboolean changed; struct record_list *ps_input; gchar *input_buffer_ptr; @@ -84,30 +76,16 @@ struct _PSDocument { FILE *gs_psfile; /* the currently loaded FILE */ gchar *gs_filename; /* the currently loaded filename */ - gchar *gs_filename_dsc; /* Used to browse PDF to PS */ gchar *gs_filename_unc; /* Uncompressed file */ gchar *input_buffer; - gint gs_scanstyle; gboolean send_filename_to_gs; /* True if gs should read from file directly */ gboolean reading_from_pipe; /* True if ggv is reading input from pipe */ struct document *doc; - /* User selected options... */ - gboolean antialiased; /* Using antialiased display */ - gboolean respect_eof; /* respect EOF comments? */ - gint default_size; - gfloat xdpi, ydpi; - gint fallback_orientation; /* Orientation to use if override */ - gint real_orientation; /* Real orientation from the document */ - const gchar *gs_status; /* PSDocument status */ - guint avail_w, avail_h; - int page_x_offset; int page_y_offset; - - gboolean scaling; }; struct _PSDocumentClass { -- cgit v0.9.1