1
by Sebastien Bacher
Import upstream version 0.4.0 |
1 |
/* Ghostscript widget for GTK/GNOME
|
2 |
*
|
|
3 |
* Copyright (C) 1998 - 2005 the Free Software Foundation
|
|
4 |
*
|
|
5 |
* Authors: Jonathan Blandford, Jaka Mocnik
|
|
6 |
*
|
|
7 |
* Based on code by: Federico Mena (Quartic), Szekeres Istvan (Pista)
|
|
8 |
*
|
|
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.
|
|
13 |
*
|
|
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.
|
|
18 |
*
|
|
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.
|
|
23 |
*/
|
|
24 |
||
25 |
#include "config.h" |
|
26 |
#include <string.h> |
|
27 |
#include <stdlib.h> |
|
28 |
#include <signal.h> |
|
29 |
#include <gtk/gtk.h> |
|
30 |
#include <gtk/gtkobject.h> |
|
31 |
#include <gdk/gdkprivate.h> |
|
32 |
#include <gdk/gdkx.h> |
|
33 |
#include <gdk/gdk.h> |
|
34 |
#include <glib/gi18n.h> |
|
35 |
#include <X11/Intrinsic.h> |
|
36 |
#include <unistd.h> |
|
37 |
#include <fcntl.h> |
|
38 |
#include <stdlib.h> |
|
39 |
#include <errno.h> |
|
40 |
#include <sys/stat.h> |
|
41 |
#include <sys/types.h> |
|
42 |
#include <sys/wait.h> |
|
43 |
#include <stdio.h> |
|
44 |
#include <math.h> |
|
45 |
||
46 |
#include "ps-document.h" |
|
47 |
#include "ev-debug.h" |
|
48 |
#include "gsdefaults.h" |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
49 |
#include "ev-file-exporter.h" |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
50 |
#include "ev-async-renderer.h" |
51 |
||
52 |
#define MAX_BUFSIZE 1024
|
|
53 |
||
54 |
#define PS_DOCUMENT_IS_COMPRESSED(gs) (PS_DOCUMENT(gs)->gs_filename_unc != NULL)
|
|
55 |
#define PS_DOCUMENT_GET_PS_FILE(gs) (PS_DOCUMENT_IS_COMPRESSED(gs) ? \
|
|
56 |
PS_DOCUMENT(gs)->gs_filename_unc : \
|
|
57 |
PS_DOCUMENT(gs)->gs_filename)
|
|
58 |
||
59 |
/* structure to describe section of file to send to ghostscript */
|
|
60 |
struct record_list |
|
61 |
{
|
|
62 |
FILE *fp; |
|
63 |
long begin; |
|
64 |
guint len; |
|
65 |
gboolean seek_needed; |
|
66 |
gboolean close; |
|
67 |
struct record_list *next; |
|
68 |
};
|
|
69 |
||
70 |
static gboolean broken_pipe = FALSE; |
|
71 |
||
72 |
/* Forward declarations */
|
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
73 |
static void ps_document_init (PSDocument *gs); |
74 |
static void ps_document_class_init (PSDocumentClass *klass); |
|
75 |
static void send_ps (PSDocument *gs, |
|
76 |
long begin, |
|
77 |
unsigned int len, |
|
78 |
gboolean close); |
|
79 |
static void output (gpointer data, |
|
80 |
gint source, |
|
81 |
GdkInputCondition condition); |
|
82 |
static void input (gpointer data, |
|
83 |
gint source, |
|
84 |
GdkInputCondition condition); |
|
85 |
static void stop_interpreter (PSDocument *gs); |
|
86 |
static gint start_interpreter (PSDocument *gs); |
|
87 |
static void ps_document_document_iface_init (EvDocumentIface *iface); |
|
88 |
static void ps_document_file_exporter_iface_init (EvFileExporterIface *iface); |
|
89 |
static void ps_async_renderer_iface_init (EvAsyncRendererIface *iface); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
90 |
|
91 |
G_DEFINE_TYPE_WITH_CODE (PSDocument, ps_document, G_TYPE_OBJECT, |
|
92 |
{
|
|
93 |
G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, |
|
94 |
ps_document_document_iface_init); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
95 |
G_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER, |
96 |
ps_document_file_exporter_iface_init); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
97 |
G_IMPLEMENT_INTERFACE (EV_TYPE_ASYNC_RENDERER, |
98 |
ps_async_renderer_iface_init); |
|
99 |
});
|
|
100 |
||
101 |
static GObjectClass *parent_class = NULL; |
|
102 |
static PSDocumentClass *gs_class = NULL; |
|
103 |
||
104 |
static void |
|
105 |
ps_document_init (PSDocument *gs) |
|
106 |
{
|
|
107 |
gs->bpixmap = NULL; |
|
108 |
||
109 |
gs->interpreter_pid = -1; |
|
110 |
||
111 |
gs->busy = FALSE; |
|
112 |
gs->gs_filename = 0; |
|
113 |
gs->gs_filename_unc = 0; |
|
114 |
||
115 |
broken_pipe = FALSE; |
|
116 |
||
117 |
gs->structured_doc = FALSE; |
|
118 |
gs->reading_from_pipe = FALSE; |
|
119 |
gs->send_filename_to_gs = FALSE; |
|
120 |
||
121 |
gs->doc = NULL; |
|
122 |
||
123 |
gs->interpreter_input = -1; |
|
124 |
gs->interpreter_output = -1; |
|
125 |
gs->interpreter_err = -1; |
|
126 |
gs->interpreter_input_id = 0; |
|
127 |
gs->interpreter_output_id = 0; |
|
128 |
gs->interpreter_error_id = 0; |
|
129 |
||
130 |
gs->ps_input = NULL; |
|
131 |
gs->input_buffer = NULL; |
|
132 |
gs->input_buffer_ptr = NULL; |
|
133 |
gs->bytes_left = 0; |
|
134 |
gs->buffer_bytes_left = 0; |
|
135 |
||
136 |
gs->gs_status = _("No document loaded."); |
|
137 |
||
138 |
gs->ps_export_pagelist = NULL; |
|
139 |
gs->ps_export_filename = NULL; |
|
140 |
}
|
|
141 |
||
142 |
static void |
|
143 |
ps_document_dispose (GObject *object) |
|
144 |
{
|
|
145 |
PSDocument *gs = PS_DOCUMENT (object); |
|
146 |
||
147 |
g_return_if_fail (gs != NULL); |
|
148 |
||
149 |
if (gs->gs_psfile) { |
|
150 |
fclose (gs->gs_psfile); |
|
151 |
gs->gs_psfile = NULL; |
|
152 |
}
|
|
153 |
||
154 |
if (gs->gs_filename) { |
|
155 |
g_free (gs->gs_filename); |
|
156 |
gs->gs_filename = NULL; |
|
157 |
}
|
|
158 |
||
159 |
if (gs->doc) { |
|
160 |
psfree (gs->doc); |
|
161 |
gs->doc = NULL; |
|
162 |
}
|
|
163 |
||
164 |
if (gs->gs_filename_unc) { |
|
165 |
unlink(gs->gs_filename_unc); |
|
166 |
g_free(gs->gs_filename_unc); |
|
167 |
gs->gs_filename_unc = NULL; |
|
168 |
}
|
|
169 |
||
170 |
if (gs->bpixmap) { |
|
171 |
gdk_drawable_unref (gs->bpixmap); |
|
172 |
}
|
|
173 |
||
174 |
if(gs->input_buffer) { |
|
175 |
g_free(gs->input_buffer); |
|
176 |
gs->input_buffer = NULL; |
|
177 |
}
|
|
178 |
||
179 |
if (gs->target_window) { |
|
180 |
gtk_widget_destroy (gs->target_window); |
|
181 |
gs->target_window = NULL; |
|
182 |
gs->pstarget = NULL; |
|
183 |
}
|
|
184 |
||
185 |
stop_interpreter (gs); |
|
186 |
||
187 |
G_OBJECT_CLASS (parent_class)->dispose (object); |
|
188 |
}
|
|
189 |
||
190 |
static void |
|
191 |
ps_document_class_init(PSDocumentClass *klass) |
|
192 |
{
|
|
193 |
GObjectClass *object_class; |
|
194 |
||
195 |
object_class = (GObjectClass *) klass; |
|
196 |
parent_class = g_type_class_peek_parent (klass); |
|
197 |
gs_class = klass; |
|
198 |
||
199 |
object_class->dispose = ps_document_dispose; |
|
200 |
||
201 |
klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE); |
|
202 |
klass->next_atom = gdk_atom_intern ("NEXT", FALSE); |
|
203 |
klass->page_atom = gdk_atom_intern ("PAGE", FALSE); |
|
204 |
klass->string_atom = gdk_atom_intern ("STRING", FALSE); |
|
205 |
}
|
|
206 |
||
207 |
static void |
|
208 |
push_pixbuf (PSDocument *gs) |
|
209 |
{
|
|
210 |
GdkColormap *cmap; |
|
211 |
GdkPixbuf *pixbuf; |
|
212 |
int width, height; |
|
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
213 |
|
214 |
if (gs->pstarget == NULL) |
|
215 |
return; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
216 |
|
217 |
cmap = gdk_window_get_colormap (gs->pstarget); |
|
218 |
gdk_drawable_get_size (gs->bpixmap, &width, &height); |
|
219 |
LOG ("Get from drawable\n"); |
|
220 |
pixbuf = gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap, |
|
221 |
0, 0, 0, 0, |
|
222 |
width, height); |
|
223 |
LOG ("Get from drawable done\n"); |
|
224 |
g_signal_emit_by_name (gs, "render_finished", pixbuf); |
|
225 |
g_object_unref (pixbuf); |
|
226 |
}
|
|
227 |
||
228 |
static void |
|
229 |
interpreter_failed (PSDocument *gs, char *msg) |
|
230 |
{
|
|
231 |
LOG ("Interpreter failed %s", msg); |
|
232 |
||
233 |
push_pixbuf (gs); |
|
234 |
||
235 |
stop_interpreter (gs); |
|
236 |
}
|
|
237 |
||
238 |
static gboolean |
|
239 |
ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data) |
|
240 |
{
|
|
241 |
PSDocument *gs = (PSDocument *) data; |
|
242 |
||
243 |
if(event->type != GDK_CLIENT_EVENT) |
|
244 |
return FALSE; |
|
245 |
||
246 |
gs->message_window = event->client.data.l[0]; |
|
247 |
||
248 |
if (event->client.message_type == gs_class->page_atom) { |
|
249 |
LOG ("GS rendered the document"); |
|
250 |
gs->busy = FALSE; |
|
251 |
||
252 |
push_pixbuf (gs); |
|
253 |
LOG ("Pixbuf pushed"); |
|
254 |
}
|
|
255 |
||
256 |
return TRUE; |
|
257 |
}
|
|
258 |
||
259 |
static void |
|
260 |
send_ps (PSDocument *gs, long begin, unsigned int len, gboolean close) |
|
261 |
{
|
|
262 |
struct record_list *ps_new; |
|
263 |
||
264 |
if (gs->interpreter_input < 0) { |
|
265 |
g_critical("No pipe to gs: error in send_ps()."); |
|
266 |
return; |
|
267 |
}
|
|
268 |
||
269 |
ps_new = g_new0 (struct record_list, 1); |
|
270 |
ps_new->fp = gs->gs_psfile; |
|
271 |
ps_new->begin = begin; |
|
272 |
ps_new->len = len; |
|
273 |
ps_new->seek_needed = TRUE; |
|
274 |
ps_new->close = close; |
|
275 |
ps_new->next = NULL; |
|
276 |
||
277 |
if (gs->input_buffer == NULL) { |
|
278 |
gs->input_buffer = g_malloc(MAX_BUFSIZE); |
|
279 |
}
|
|
280 |
||
281 |
if (gs->ps_input == NULL) { |
|
282 |
gs->input_buffer_ptr = gs->input_buffer; |
|
283 |
gs->bytes_left = len; |
|
284 |
gs->buffer_bytes_left = 0; |
|
285 |
gs->ps_input = ps_new; |
|
286 |
gs->interpreter_input_id = gdk_input_add |
|
287 |
(gs->interpreter_input, GDK_INPUT_WRITE, input, gs); |
|
288 |
} else { |
|
289 |
struct record_list *p = gs->ps_input; |
|
290 |
while (p->next != NULL) { |
|
291 |
p = p->next; |
|
292 |
}
|
|
293 |
p->next = ps_new; |
|
294 |
}
|
|
295 |
}
|
|
296 |
||
297 |
static void |
|
298 |
setup_pixmap (PSDocument *gs, int page, double scale, int rotation) |
|
299 |
{
|
|
300 |
GdkGC *fill; |
|
301 |
GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */ |
|
302 |
GdkColormap *colormap; |
|
303 |
double width, height; |
|
304 |
int pixmap_width, pixmap_height; |
|
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
305 |
|
306 |
if (gs->pstarget == NULL) |
|
307 |
return; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
308 |
|
309 |
ev_document_get_page_size (EV_DOCUMENT (gs), page, &width, &height); |
|
310 |
||
311 |
if (rotation == 90 || rotation == 270) { |
|
312 |
pixmap_height = width * scale + 0.5; |
|
313 |
pixmap_width = height * scale + 0.5; |
|
314 |
} else { |
|
315 |
pixmap_width = width * scale + 0.5; |
|
316 |
pixmap_height = height * scale + 0.5; |
|
317 |
}
|
|
318 |
||
319 |
if(gs->bpixmap) { |
|
320 |
int w, h; |
|
321 |
||
322 |
gdk_drawable_get_size (gs->bpixmap, &w, &h); |
|
323 |
||
324 |
if (pixmap_width != w || h != pixmap_height) { |
|
325 |
gdk_drawable_unref (gs->bpixmap); |
|
326 |
gs->bpixmap = NULL; |
|
327 |
stop_interpreter (gs); |
|
328 |
}
|
|
329 |
}
|
|
330 |
||
331 |
if (!gs->bpixmap) { |
|
332 |
LOG ("Create pixmap"); |
|
333 |
||
334 |
fill = gdk_gc_new (gs->pstarget); |
|
335 |
colormap = gdk_drawable_get_colormap (gs->pstarget); |
|
336 |
gdk_color_alloc (colormap, &white); |
|
337 |
gdk_gc_set_foreground (fill, &white); |
|
338 |
gs->bpixmap = gdk_pixmap_new (gs->pstarget, pixmap_width, |
|
339 |
pixmap_height, -1); |
|
340 |
gdk_draw_rectangle (gs->bpixmap, fill, TRUE, |
|
341 |
0, 0, pixmap_width, pixmap_height); |
|
342 |
}
|
|
343 |
}
|
|
344 |
||
345 |
#define DEFAULT_PAGE_SIZE 1
|
|
346 |
||
347 |
static void |
|
348 |
get_page_box (PSDocument *gs, int page, int *urx, int *ury, int *llx, int *lly) |
|
349 |
{
|
|
350 |
gint new_llx = 0; |
|
351 |
gint new_lly = 0; |
|
352 |
gint new_urx = 0; |
|
353 |
gint new_ury = 0; |
|
354 |
GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes (); |
|
355 |
int new_pagesize = -1; |
|
356 |
||
357 |
g_return_if_fail (PS_IS_DOCUMENT (gs)); |
|
358 |
||
359 |
if (new_pagesize == -1) { |
|
360 |
new_pagesize = DEFAULT_PAGE_SIZE; |
|
361 |
if (gs->doc) { |
|
362 |
/* If we have a document:
|
|
363 |
* We use -- the page size (if specified)
|
|
364 |
* or the doc. size (if specified)
|
|
365 |
* or the page bbox (if specified)
|
|
366 |
* or the bounding box
|
|
367 |
*/
|
|
368 |
if ((page >= 0) && (gs->doc->numpages > page) && |
|
369 |
(gs->doc->pages) && (gs->doc->pages[page].size)) { |
|
370 |
new_pagesize = gs->doc->pages[page].size - gs->doc->size; |
|
371 |
} else if (gs->doc->default_page_size != NULL) { |
|
372 |
new_pagesize = gs->doc->default_page_size - gs->doc->size; |
|
373 |
} else if ((page >= 0) && |
|
374 |
(gs->doc->numpages > page) && |
|
375 |
(gs->doc->pages) && |
|
376 |
(gs->doc->pages[page].boundingbox[URX] > |
|
377 |
gs->doc->pages[page].boundingbox[LLX]) && |
|
378 |
(gs->doc->pages[page].boundingbox[URY] > |
|
379 |
gs->doc->pages[page].boundingbox[LLY])) { |
|
380 |
new_pagesize = -1; |
|
381 |
} else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && |
|
382 |
(gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { |
|
383 |
new_pagesize = -1; |
|
384 |
}
|
|
385 |
}
|
|
386 |
}
|
|
387 |
||
388 |
/* Compute bounding box */
|
|
389 |
if (gs->doc && (gs->doc->epsf || new_pagesize == -1)) { /* epsf or bbox */ |
|
390 |
if ((page >= 0) && |
|
391 |
(gs->doc->pages) && |
|
392 |
(gs->doc->pages[page].boundingbox[URX] > |
|
393 |
gs->doc->pages[page].boundingbox[LLX]) && |
|
394 |
(gs->doc->pages[page].boundingbox[URY] > |
|
395 |
gs->doc->pages[page].boundingbox[LLY])) { |
|
396 |
/* use page bbox */
|
|
397 |
new_llx = gs->doc->pages[page].boundingbox[LLX]; |
|
398 |
new_lly = gs->doc->pages[page].boundingbox[LLY]; |
|
399 |
new_urx = gs->doc->pages[page].boundingbox[URX]; |
|
400 |
new_ury = gs->doc->pages[page].boundingbox[URY]; |
|
401 |
} else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && |
|
402 |
(gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { |
|
403 |
/* use doc bbox */
|
|
404 |
new_llx = gs->doc->boundingbox[LLX]; |
|
405 |
new_lly = gs->doc->boundingbox[LLY]; |
|
406 |
new_urx = gs->doc->boundingbox[URX]; |
|
407 |
new_ury = gs->doc->boundingbox[URY]; |
|
408 |
}
|
|
409 |
} else { |
|
410 |
if (new_pagesize < 0) |
|
411 |
new_pagesize = DEFAULT_PAGE_SIZE; |
|
412 |
new_llx = new_lly = 0; |
|
413 |
if (gs->doc && gs->doc->size && |
|
414 |
(new_pagesize < gs->doc->numsizes)) { |
|
415 |
new_urx = gs->doc->size[new_pagesize].width; |
|
416 |
new_ury = gs->doc->size[new_pagesize].height; |
|
417 |
} else { |
|
418 |
new_urx = papersizes[new_pagesize].width; |
|
419 |
new_ury = papersizes[new_pagesize].height; |
|
420 |
}
|
|
421 |
}
|
|
422 |
||
423 |
if (new_urx <= new_llx) |
|
424 |
new_urx = papersizes[12].width; |
|
425 |
if (new_ury <= new_lly) |
|
426 |
new_ury = papersizes[12].height; |
|
427 |
||
428 |
*urx = new_urx; |
|
429 |
*ury = new_ury; |
|
430 |
*llx = new_llx; |
|
431 |
*lly = new_lly; |
|
432 |
}
|
|
433 |
||
434 |
static void |
|
435 |
setup_page (PSDocument *gs, int page, double scale, int rotation) |
|
436 |
{
|
|
437 |
gchar *buf; |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
438 |
char scaled_dpi[G_ASCII_DTOSTR_BUF_SIZE]; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
439 |
int urx, ury, llx, lly; |
440 |
||
441 |
LOG ("Setup the page"); |
|
442 |
||
443 |
get_page_box (gs, page, &urx, &ury, &llx, &lly); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
444 |
g_ascii_dtostr (scaled_dpi, G_ASCII_DTOSTR_BUF_SIZE, 72.0 * scale); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
445 |
|
446 |
buf = g_strdup_printf ("%ld %d %d %d %d %d %s %s %d %d %d %d", |
|
447 |
0L, rotation, llx, lly, urx, ury, |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
448 |
scaled_dpi, scaled_dpi, |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
449 |
0, 0, 0, 0); |
450 |
LOG ("GS property %s", buf); |
|
451 |
||
452 |
gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom, |
|
453 |
8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen(buf)); |
|
454 |
g_free (buf); |
|
455 |
||
456 |
gdk_flush (); |
|
457 |
}
|
|
458 |
||
459 |
static void |
|
460 |
close_pipe (int p[2]) |
|
461 |
{
|
|
462 |
if (p[0] != -1) { |
|
463 |
close (p[0]); |
|
464 |
}
|
|
465 |
if (p[1] != -1) { |
|
466 |
close (p[1]); |
|
467 |
}
|
|
468 |
}
|
|
469 |
||
470 |
static gboolean |
|
471 |
is_interpreter_ready (PSDocument *gs) |
|
472 |
{
|
|
473 |
return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL); |
|
474 |
}
|
|
475 |
||
476 |
static void |
|
477 |
output (gpointer data, gint source, GdkInputCondition condition) |
|
478 |
{
|
|
479 |
char buf[MAX_BUFSIZE + 1]; |
|
480 |
guint bytes = 0; |
|
481 |
PSDocument *gs = PS_DOCUMENT(data); |
|
482 |
||
483 |
if (source == gs->interpreter_output) { |
|
484 |
bytes = read(gs->interpreter_output, buf, MAX_BUFSIZE); |
|
485 |
if (bytes == 0) { /* EOF occurred */ |
|
486 |
close (gs->interpreter_output); |
|
487 |
gs->interpreter_output = -1; |
|
488 |
gdk_input_remove (gs->interpreter_output_id); |
|
489 |
return; |
|
490 |
} else if (bytes == -1) { |
|
491 |
/* trouble... */
|
|
492 |
interpreter_failed (gs, NULL); |
|
493 |
return; |
|
494 |
}
|
|
495 |
if (gs->interpreter_err == -1) { |
|
496 |
interpreter_failed (gs, NULL); |
|
497 |
}
|
|
498 |
} else if (source == gs->interpreter_err) { |
|
499 |
bytes = read (gs->interpreter_err, buf, MAX_BUFSIZE); |
|
500 |
if (bytes == 0) { /* EOF occurred */ |
|
501 |
close (gs->interpreter_err); |
|
502 |
gs->interpreter_err = -1; |
|
503 |
gdk_input_remove (gs->interpreter_error_id); |
|
504 |
return; |
|
505 |
} else if (bytes == -1) { |
|
506 |
/* trouble... */
|
|
507 |
interpreter_failed (gs, NULL); |
|
508 |
return; |
|
509 |
}
|
|
510 |
if (gs->interpreter_output == -1) { |
|
511 |
interpreter_failed(gs, NULL); |
|
512 |
}
|
|
513 |
}
|
|
514 |
||
515 |
if (bytes > 0) { |
|
516 |
buf[bytes] = '\0'; |
|
517 |
printf ("%s", buf); |
|
518 |
}
|
|
519 |
}
|
|
520 |
||
521 |
static void |
|
522 |
catchPipe (int i) |
|
523 |
{
|
|
524 |
broken_pipe = True; |
|
525 |
}
|
|
526 |
||
527 |
static void |
|
528 |
input(gpointer data, gint source, GdkInputCondition condition) |
|
529 |
{
|
|
530 |
PSDocument *gs = PS_DOCUMENT(data); |
|
531 |
int bytes_written; |
|
532 |
void (*oldsig) (int); |
|
533 |
oldsig = signal(SIGPIPE, catchPipe); |
|
534 |
||
535 |
LOG ("Input"); |
|
536 |
||
537 |
do { |
|
538 |
if (gs->buffer_bytes_left == 0) { |
|
539 |
/* Get a new section if required */
|
|
540 |
if (gs->ps_input && gs->bytes_left == 0) { |
|
541 |
struct record_list *ps_old = gs->ps_input; |
|
542 |
gs->ps_input = ps_old->next; |
|
543 |
if (ps_old->close && NULL != ps_old->fp) |
|
544 |
fclose (ps_old->fp); |
|
545 |
g_free (ps_old); |
|
546 |
}
|
|
547 |
||
548 |
/* Have to seek at the beginning of each section */
|
|
549 |
if (gs->ps_input && gs->ps_input->seek_needed) { |
|
550 |
fseek (gs->ps_input->fp, gs->ps_input->begin, SEEK_SET); |
|
551 |
gs->ps_input->seek_needed = FALSE; |
|
552 |
gs->bytes_left = gs->ps_input->len; |
|
553 |
}
|
|
554 |
||
555 |
if (gs->bytes_left > MAX_BUFSIZE) { |
|
556 |
gs->buffer_bytes_left = fread (gs->input_buffer, sizeof(char), |
|
557 |
MAX_BUFSIZE, gs->ps_input->fp); |
|
558 |
} else if (gs->bytes_left > 0) { |
|
559 |
gs->buffer_bytes_left = fread (gs->input_buffer, sizeof(char), |
|
560 |
gs->bytes_left, gs->ps_input->fp); |
|
561 |
} else { |
|
562 |
gs->buffer_bytes_left = 0; |
|
563 |
}
|
|
564 |
if (gs->bytes_left > 0 && gs->buffer_bytes_left == 0) { |
|
565 |
interpreter_failed (gs, NULL); /* Error occurred */ |
|
566 |
}
|
|
567 |
gs->input_buffer_ptr = gs->input_buffer; |
|
568 |
gs->bytes_left -= gs->buffer_bytes_left; |
|
569 |
}
|
|
570 |
||
571 |
if (gs->buffer_bytes_left > 0) { |
|
572 |
bytes_written = write (gs->interpreter_input, |
|
573 |
gs->input_buffer_ptr, gs->buffer_bytes_left); |
|
574 |
||
575 |
if (broken_pipe) { |
|
576 |
interpreter_failed (gs, g_strdup(_("Broken pipe."))); |
|
577 |
broken_pipe = FALSE; |
|
578 |
interpreter_failed (gs, NULL); |
|
579 |
} else if (bytes_written == -1) { |
|
580 |
if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) { |
|
581 |
interpreter_failed (gs, NULL); /* Something bad happened */ |
|
582 |
}
|
|
583 |
} else { |
|
584 |
gs->buffer_bytes_left -= bytes_written; |
|
585 |
gs->input_buffer_ptr += bytes_written; |
|
586 |
}
|
|
587 |
}
|
|
588 |
} while (gs->ps_input && gs->buffer_bytes_left == 0); |
|
589 |
||
590 |
signal (SIGPIPE, oldsig); |
|
591 |
||
592 |
if (gs->ps_input == NULL && gs->buffer_bytes_left == 0) { |
|
593 |
if (gs->interpreter_input_id != 0) { |
|
594 |
gdk_input_remove (gs->interpreter_input_id); |
|
595 |
gs->interpreter_input_id = 0; |
|
596 |
}
|
|
597 |
}
|
|
598 |
}
|
|
599 |
||
600 |
static int |
|
601 |
start_interpreter (PSDocument *gs) |
|
602 |
{
|
|
603 |
int std_in[2] = { -1, -1 }; /* pipe to interp stdin */ |
|
604 |
int std_out[2]; /* pipe from interp stdout */ |
|
605 |
int std_err[2]; /* pipe from interp stderr */ |
|
606 |
||
607 |
#define NUM_ARGS 100
|
|
608 |
#define NUM_GS_ARGS (NUM_ARGS - 20)
|
|
609 |
#define NUM_ALPHA_ARGS 10
|
|
610 |
||
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
611 |
char *argv[NUM_ARGS], *dir, *gv_env, *gs_path; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
612 |
char **gs_args, **alpha_args = NULL; |
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
613 |
char **gv_env_vars = NULL; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
614 |
int argc = 0, i; |
615 |
||
616 |
LOG ("Start the interpreter"); |
|
617 |
||
618 |
if(!gs->gs_filename) |
|
619 |
return 0; |
|
620 |
||
621 |
stop_interpreter(gs); |
|
622 |
||
623 |
/* set up the args... */
|
|
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
624 |
gs_path = g_find_program_in_path ("gs"); |
625 |
gs_args = g_strsplit (gs_path, " ", NUM_GS_ARGS); |
|
626 |
g_free (gs_path); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
627 |
for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) { |
628 |
argv[argc] = gs_args[i]; |
|
629 |
}
|
|
630 |
||
631 |
alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS); |
|
632 |
for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) { |
|
633 |
argv[argc] = alpha_args[i]; |
|
634 |
}
|
|
635 |
||
636 |
argv[argc++] = "-dNOPAUSE"; |
|
637 |
argv[argc++] = "-dQUIET"; |
|
638 |
argv[argc++] = "-dSAFER"; |
|
639 |
||
640 |
/* set up the pipes */
|
|
641 |
if (gs->send_filename_to_gs) { |
|
642 |
argv[argc++] = PS_DOCUMENT_GET_PS_FILE (gs); |
|
643 |
argv[argc++] = "-c"; |
|
644 |
argv[argc++] = "quit"; |
|
645 |
} else { |
|
646 |
argv[argc++] = "-"; |
|
647 |
}
|
|
648 |
||
649 |
argv[argc++] = NULL; |
|
650 |
||
651 |
if (!gs->reading_from_pipe && !gs->send_filename_to_gs) { |
|
652 |
if (pipe (std_in) == -1) { |
|
653 |
g_critical ("Unable to open pipe to Ghostscript."); |
|
654 |
return -1; |
|
655 |
}
|
|
656 |
}
|
|
657 |
||
658 |
if (pipe (std_out) == -1) { |
|
659 |
close_pipe (std_in); |
|
660 |
return -1; |
|
661 |
}
|
|
662 |
||
663 |
if (pipe(std_err) == -1) { |
|
664 |
close_pipe (std_in); |
|
665 |
close_pipe (std_out); |
|
666 |
return -1; |
|
667 |
}
|
|
668 |
||
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
669 |
gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld;DISPLAY=%s", |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
670 |
gdk_x11_drawable_get_xid (gs->pstarget), |
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
671 |
gdk_x11_drawable_get_xid (gs->bpixmap), |
672 |
gdk_display_get_name (gdk_drawable_get_display (gs->pstarget))); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
673 |
LOG ("Launching ghostview with env %s", gv_env); |
674 |
||
675 |
gs->interpreter_pid = fork (); |
|
676 |
switch (gs->interpreter_pid) { |
|
677 |
case -1: /* error */ |
|
678 |
close_pipe (std_in); |
|
679 |
close_pipe (std_out); |
|
680 |
close_pipe (std_err); |
|
681 |
return -2; |
|
682 |
break; |
|
683 |
case 0: /* child */ |
|
684 |
close (std_out[0]); |
|
685 |
dup2 (std_out[1], 1); |
|
686 |
close (std_out[1]); |
|
687 |
||
688 |
close (std_err[0]); |
|
689 |
dup2 (std_err[1], 2); |
|
690 |
close (std_err[1]); |
|
691 |
||
692 |
if (!gs->reading_from_pipe) { |
|
693 |
if (gs->send_filename_to_gs) { |
|
694 |
int stdinfd; |
|
695 |
/* just in case gs tries to read from stdin */
|
|
696 |
stdinfd = open("/dev/null", O_RDONLY); |
|
697 |
if (stdinfd != 0) { |
|
698 |
dup2(stdinfd, 0); |
|
699 |
close(stdinfd); |
|
700 |
}
|
|
701 |
} else { |
|
702 |
close (std_in[1]); |
|
703 |
dup2 (std_in[0], 0); |
|
704 |
close (std_in[0]); |
|
705 |
}
|
|
706 |
}
|
|
707 |
||
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
708 |
gv_env_vars = g_strsplit (gv_env, ";", -1); |
709 |
g_free (gv_env); |
|
710 |
for (i = 0; gv_env_vars[i]; i++) { |
|
711 |
putenv (gv_env_vars[i]); |
|
712 |
}
|
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
713 |
|
714 |
/* change to directory where the input file is. This helps
|
|
715 |
* with postscript-files which include other files using
|
|
716 |
* a relative path */
|
|
717 |
dir = g_path_get_dirname (gs->gs_filename); |
|
718 |
chdir (dir); |
|
719 |
g_free (dir); |
|
720 |
||
721 |
execvp (argv[0], argv); |
|
722 |
||
723 |
/* Notify error */
|
|
724 |
g_critical ("Unable to execute [%s]\n", argv[0]); |
|
725 |
g_strfreev (gs_args); |
|
726 |
g_strfreev (alpha_args); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
727 |
g_strfreev (gv_env_vars); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
728 |
_exit (1); |
729 |
break; |
|
730 |
default: /* parent */ |
|
731 |
if (!gs->send_filename_to_gs && !gs->reading_from_pipe) { |
|
732 |
int result; |
|
733 |
close (std_in[0]); |
|
734 |
/* use non-blocking IO for pipe to ghostscript */
|
|
735 |
result = fcntl (std_in[1], F_GETFL, 0); |
|
736 |
fcntl (std_in[1], F_SETFL, result | O_NONBLOCK); |
|
737 |
gs->interpreter_input = std_in[1]; |
|
738 |
} else { |
|
739 |
gs->interpreter_input = -1; |
|
740 |
}
|
|
741 |
close (std_out[1]); |
|
742 |
||
743 |
gs->interpreter_output = std_out[0]; |
|
744 |
close (std_err[1]); |
|
745 |
gs->interpreter_err = std_err[0]; |
|
746 |
gs->interpreter_output_id = |
|
747 |
gdk_input_add (std_out[0], GDK_INPUT_READ, output, gs); |
|
748 |
gs->interpreter_error_id = |
|
749 |
gdk_input_add (std_err[0], GDK_INPUT_READ, output, gs); |
|
750 |
break; |
|
751 |
}
|
|
752 |
||
753 |
return TRUE; |
|
754 |
}
|
|
755 |
||
756 |
static void |
|
757 |
stop_interpreter(PSDocument * gs) |
|
758 |
{
|
|
759 |
if (gs->interpreter_pid > 0) { |
|
760 |
int status = 0; |
|
761 |
LOG ("Stop the interpreter"); |
|
762 |
kill (gs->interpreter_pid, SIGTERM); |
|
763 |
while ((wait(&status) == -1) && (errno == EINTR)); |
|
764 |
gs->interpreter_pid = -1; |
|
765 |
if (status == 1) { |
|
766 |
gs->gs_status = _("Interpreter failed."); |
|
767 |
}
|
|
768 |
}
|
|
769 |
||
770 |
if (gs->interpreter_input >= 0) { |
|
771 |
close (gs->interpreter_input); |
|
772 |
gs->interpreter_input = -1; |
|
773 |
if (gs->interpreter_input_id != 0) { |
|
774 |
gdk_input_remove(gs->interpreter_input_id); |
|
775 |
gs->interpreter_input_id = 0; |
|
776 |
}
|
|
777 |
while (gs->ps_input) { |
|
778 |
struct record_list *ps_old = gs->ps_input; |
|
779 |
gs->ps_input = gs->ps_input->next; |
|
780 |
if (ps_old->close && NULL != ps_old->fp) |
|
781 |
fclose (ps_old->fp); |
|
782 |
g_free (ps_old); |
|
783 |
}
|
|
784 |
}
|
|
785 |
||
786 |
if (gs->interpreter_output >= 0) { |
|
787 |
close (gs->interpreter_output); |
|
788 |
gs->interpreter_output = -1; |
|
789 |
if (gs->interpreter_output_id) { |
|
790 |
gdk_input_remove (gs->interpreter_output_id); |
|
791 |
gs->interpreter_output_id = 0; |
|
792 |
}
|
|
793 |
}
|
|
794 |
||
795 |
if (gs->interpreter_err >= 0) { |
|
796 |
close (gs->interpreter_err); |
|
797 |
gs->interpreter_err = -1; |
|
798 |
if (gs->interpreter_error_id) { |
|
799 |
gdk_input_remove (gs->interpreter_error_id); |
|
800 |
gs->interpreter_error_id = 0; |
|
801 |
}
|
|
802 |
}
|
|
803 |
||
804 |
gs->busy = FALSE; |
|
805 |
}
|
|
806 |
||
807 |
/* If file exists and is a regular file then return its length, else -1 */
|
|
808 |
static gint |
|
809 |
file_length (const gchar * filename) |
|
810 |
{
|
|
811 |
struct stat stat_rec; |
|
812 |
||
813 |
if (filename && (stat (filename, &stat_rec) == 0) && S_ISREG (stat_rec.st_mode)) |
|
814 |
return stat_rec.st_size; |
|
815 |
else
|
|
816 |
return -1; |
|
817 |
}
|
|
818 |
||
819 |
/* Test if file exists, is a regular file and its length is > 0 */
|
|
820 |
static gboolean |
|
821 |
file_readable(const char *filename) |
|
822 |
{
|
|
823 |
return (file_length (filename) > 0); |
|
824 |
}
|
|
825 |
||
826 |
/*
|
|
827 |
* Decompress gs->gs_filename if necessary
|
|
828 |
* Set gs->filename_unc to the name of the uncompressed file or NULL.
|
|
829 |
* Error reporting via signal 'interpreter_message'
|
|
830 |
* Return name of input file to use or NULL on error..
|
|
831 |
*/
|
|
832 |
static gchar * |
|
833 |
check_filecompressed (PSDocument * gs) |
|
834 |
{
|
|
835 |
FILE *file; |
|
836 |
gchar buf[1024]; |
|
837 |
gchar *filename, *filename_unc, *filename_err, *cmdline; |
|
838 |
const gchar *cmd; |
|
839 |
int fd; |
|
840 |
||
841 |
cmd = NULL; |
|
842 |
||
843 |
if ((file = fopen(gs->gs_filename, "r")) && |
|
844 |
(fread (buf, sizeof(gchar), 3, file) == 3)) { |
|
845 |
if ((buf[0] == '\037') && ((buf[1] == '\235') || (buf[1] == '\213'))) { |
|
846 |
/* file is gzipped or compressed */
|
|
847 |
cmd = gtk_gs_defaults_get_ungzip_cmd (); |
|
848 |
} else if (strncmp (buf, "BZh", 3) == 0) { |
|
849 |
/* file is compressed with bzip2 */
|
|
850 |
cmd = gtk_gs_defaults_get_unbzip2_cmd (); |
|
851 |
}
|
|
852 |
}
|
|
853 |
||
854 |
if (NULL != file) |
|
855 |
fclose(file); |
|
856 |
||
857 |
if (!cmd) |
|
858 |
return gs->gs_filename; |
|
859 |
||
860 |
/* do the decompression */
|
|
861 |
filename = g_shell_quote (gs->gs_filename); |
|
862 |
filename_unc = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL); |
|
863 |
if ((fd = mkstemp (filename_unc)) < 0) { |
|
864 |
g_free (filename_unc); |
|
865 |
g_free (filename); |
|
866 |
return NULL; |
|
867 |
}
|
|
868 |
close (fd); |
|
869 |
||
870 |
filename_err = g_strconcat (g_get_tmp_dir (), "/evinceXXXXXX", NULL); |
|
871 |
if ((fd = mkstemp(filename_err)) < 0) { |
|
872 |
g_free (filename_err); |
|
873 |
g_free (filename_unc); |
|
874 |
g_free (filename); |
|
875 |
return NULL; |
|
876 |
}
|
|
877 |
close (fd); |
|
878 |
||
879 |
cmdline = g_strdup_printf ("%s %s >%s 2>%s", cmd, |
|
880 |
filename, filename_unc, filename_err); |
|
881 |
if (system (cmdline) == 0 && |
|
882 |
file_readable (filename_unc) && |
|
883 |
file_length (filename_err) == 0) { |
|
884 |
/* sucessfully uncompressed file */
|
|
885 |
gs->gs_filename_unc = filename_unc; |
|
886 |
} else { |
|
887 |
gchar *filename_dsp; |
|
888 |
gchar *msg; |
|
889 |
||
890 |
/* report error */
|
|
891 |
filename_dsp = g_filename_display_name (gs->gs_filename); |
|
1.1.5
by Sebastien Bacher
Import upstream version 0.5.4 |
892 |
msg = g_strdup_printf (_("Error while decompressing file “%s”:\n"), filename_dsp); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
893 |
g_free (filename_dsp); |
894 |
||
895 |
interpreter_failed (gs, msg); |
|
896 |
g_free (msg); |
|
897 |
unlink (filename_unc); |
|
898 |
g_free (filename_unc); |
|
899 |
filename_unc = NULL; |
|
900 |
}
|
|
901 |
||
902 |
unlink (filename_err); |
|
903 |
g_free (filename_err); |
|
904 |
g_free (cmdline); |
|
905 |
g_free (filename); |
|
906 |
||
907 |
return filename_unc; |
|
908 |
}
|
|
909 |
||
910 |
static gint |
|
911 |
ps_document_enable_interpreter(PSDocument *gs) |
|
912 |
{
|
|
913 |
g_return_val_if_fail (PS_IS_DOCUMENT (gs), FALSE); |
|
914 |
||
915 |
if (!gs->gs_filename) |
|
916 |
return 0; |
|
917 |
||
918 |
return start_interpreter (gs); |
|
919 |
}
|
|
920 |
||
921 |
static gboolean |
|
922 |
document_load (PSDocument *gs, const gchar *fname) |
|
923 |
{
|
|
924 |
g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE); |
|
925 |
||
926 |
LOG ("Load the document"); |
|
927 |
||
928 |
if (fname == NULL) { |
|
929 |
gs->gs_status = ""; |
|
930 |
return FALSE; |
|
931 |
}
|
|
932 |
||
933 |
/* prepare this document */
|
|
934 |
gs->structured_doc = FALSE; |
|
935 |
gs->send_filename_to_gs = TRUE; |
|
936 |
gs->gs_filename = g_strdup (fname); |
|
937 |
||
938 |
if ((gs->reading_from_pipe = (strcmp (fname, "-") == 0))) { |
|
939 |
gs->send_filename_to_gs = FALSE; |
|
940 |
} else { |
|
941 |
/*
|
|
942 |
* We need to make sure that the file is loadable/exists!
|
|
943 |
* otherwise we want to exit without loading new stuff...
|
|
944 |
*/
|
|
945 |
gchar *filename = NULL; |
|
946 |
||
947 |
if (!file_readable(fname)) { |
|
948 |
gchar *filename_dsp; |
|
949 |
gchar *msg; |
|
950 |
||
951 |
filename_dsp = g_filename_display_name (fname); |
|
1.1.5
by Sebastien Bacher
Import upstream version 0.5.4 |
952 |
msg = g_strdup_printf (_("Cannot open file “%s”.\n"), filename_dsp); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
953 |
g_free (filename_dsp); |
954 |
||
955 |
interpreter_failed (gs, msg); |
|
956 |
g_free (msg); |
|
957 |
gs->gs_status = _("File is not readable."); |
|
958 |
} else { |
|
959 |
filename = check_filecompressed(gs); |
|
960 |
}
|
|
961 |
||
962 |
if (!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) { |
|
963 |
interpreter_failed (gs, NULL); |
|
964 |
return FALSE; |
|
965 |
}
|
|
966 |
||
967 |
/* we grab the vital statistics!!! */
|
|
968 |
gs->doc = psscan(gs->gs_psfile, TRUE, filename); |
|
969 |
||
970 |
if ((!gs->doc->epsf && gs->doc->numpages > 0) || |
|
971 |
(gs->doc->epsf && gs->doc->numpages > 1)) { |
|
972 |
gs->structured_doc = TRUE; |
|
973 |
gs->send_filename_to_gs = FALSE; |
|
974 |
}
|
|
975 |
}
|
|
976 |
||
977 |
gs->gs_status = _("Document loaded."); |
|
978 |
||
979 |
return TRUE; |
|
980 |
}
|
|
981 |
||
982 |
static gboolean |
|
983 |
ps_document_next_page (PSDocument *gs) |
|
984 |
{
|
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
985 |
XEvent event; |
986 |
GdkScreen *screen; |
|
987 |
GdkDisplay *display; |
|
988 |
Display *dpy; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
989 |
|
990 |
LOG ("Make ghostscript render next page"); |
|
991 |
||
992 |
g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE); |
|
993 |
g_return_val_if_fail (gs->interpreter_pid != 0, FALSE); |
|
994 |
g_return_val_if_fail (gs->busy != TRUE, FALSE); |
|
995 |
||
996 |
gs->busy = TRUE; |
|
997 |
||
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
998 |
screen = gtk_window_get_screen (GTK_WINDOW (gs->target_window)); |
999 |
display = gdk_screen_get_display (screen); |
|
1000 |
dpy = gdk_x11_display_get_xdisplay (display); |
|
1001 |
||
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1002 |
event.xclient.type = ClientMessage; |
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1003 |
event.xclient.display = dpy; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1004 |
event.xclient.window = gs->message_window; |
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1005 |
event.xclient.message_type = |
1006 |
gdk_x11_atom_to_xatom_for_display (display, |
|
1007 |
gs_class->next_atom); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1008 |
event.xclient.format = 32; |
1009 |
||
1010 |
gdk_error_trap_push (); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1011 |
XSendEvent (dpy, gs->message_window, FALSE, 0, &event); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1012 |
gdk_flush (); |
1013 |
gdk_error_trap_pop (); |
|
1014 |
||
1015 |
return TRUE; |
|
1016 |
}
|
|
1017 |
||
1018 |
static gboolean |
|
1019 |
render_page (PSDocument *gs, int page) |
|
1020 |
{
|
|
1021 |
g_return_val_if_fail(gs != NULL, FALSE); |
|
1022 |
g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE); |
|
1023 |
||
1024 |
if(!gs->gs_filename) { |
|
1025 |
return FALSE; |
|
1026 |
}
|
|
1027 |
||
1028 |
if (gs->structured_doc && gs->doc) { |
|
1029 |
LOG ("It's a structured document, let's send one page to gs"); |
|
1030 |
||
1031 |
if (is_interpreter_ready (gs)) { |
|
1032 |
ps_document_next_page (gs); |
|
1033 |
} else { |
|
1034 |
ps_document_enable_interpreter (gs); |
|
1035 |
send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE); |
|
1036 |
send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE); |
|
1037 |
}
|
|
1038 |
||
1039 |
send_ps (gs, gs->doc->pages[page].begin, |
|
1040 |
gs->doc->pages[page].len, FALSE); |
|
1041 |
} else { |
|
1042 |
/* Unstructured document
|
|
1043 |
*
|
|
1044 |
* In the case of non structured documents,
|
|
1045 |
* GS read the PS from the actual file (via command
|
|
1046 |
* line. Hence, ggv only send a signal next page.
|
|
1047 |
* If ghostview is not running it is usually because
|
|
1048 |
* the last page of the file was displayed. In that
|
|
1049 |
* case, ggv restarts GS again and the first page is displayed.
|
|
1050 |
*/
|
|
1051 |
||
1052 |
LOG ("It's an unstructured document, gs will just read the file"); |
|
1053 |
||
1054 |
if (!is_interpreter_ready (gs)) { |
|
1055 |
ps_document_enable_interpreter(gs); |
|
1056 |
}
|
|
1057 |
ps_document_next_page(gs); |
|
1058 |
}
|
|
1059 |
||
1060 |
return TRUE; |
|
1061 |
}
|
|
1062 |
||
1063 |
static gboolean |
|
1064 |
ps_document_load (EvDocument *document, |
|
1065 |
const char *uri, |
|
1066 |
GError **error) |
|
1067 |
{
|
|
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
1068 |
char *filename; |
1069 |
char *gs_path; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1070 |
gboolean result; |
1071 |
||
1072 |
filename = g_filename_from_uri (uri, NULL, error); |
|
1073 |
if (!filename) |
|
1074 |
return FALSE; |
|
1075 |
||
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
1076 |
gs_path = g_find_program_in_path ("gs"); |
1077 |
if (!gs_path) { |
|
1078 |
gchar *filename_dsp; |
|
1079 |
filename_dsp = g_filename_display_name (filename); |
|
1080 |
g_set_error(error, |
|
1081 |
G_FILE_ERROR, |
|
1082 |
G_FILE_ERROR_NOENT, |
|
1.1.5
by Sebastien Bacher
Import upstream version 0.5.4 |
1083 |
_("Failed to load document “%s”. Ghostscript interpreter was not found in path"), |
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
1084 |
filename); |
1085 |
g_free (filename_dsp); |
|
1086 |
result = FALSE; |
|
1087 |
} else { |
|
1088 |
result = document_load (PS_DOCUMENT (document), filename); |
|
1089 |
if (!result) { |
|
1090 |
gchar *filename_dsp; |
|
1091 |
filename_dsp = g_filename_display_name (filename); |
|
1092 |
||
1093 |
g_set_error (error, G_FILE_ERROR, |
|
1094 |
G_FILE_ERROR_FAILED, |
|
1.1.5
by Sebastien Bacher
Import upstream version 0.5.4 |
1095 |
_("Failed to load document “%s”"), |
1.1.2
by Sebastien Bacher
Import upstream version 0.5.1 |
1096 |
filename_dsp); |
1097 |
g_free (filename_dsp); |
|
1098 |
}
|
|
1099 |
g_free (gs_path); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1100 |
}
|
1101 |
g_free (filename); |
|
1102 |
||
1103 |
return result; |
|
1104 |
}
|
|
1105 |
||
1106 |
static gboolean |
|
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1107 |
save_document (PSDocument *document, const char *filename) |
1108 |
{
|
|
1109 |
gboolean result = TRUE; |
|
1110 |
GtkGSDocSink *sink = gtk_gs_doc_sink_new (); |
|
1111 |
FILE *f, *src_file; |
|
1112 |
gchar *buf; |
|
1113 |
||
1114 |
src_file = fopen (PS_DOCUMENT_GET_PS_FILE(document), "r"); |
|
1115 |
if (src_file) { |
|
1116 |
struct stat stat_rec; |
|
1117 |
||
1118 |
if (stat (PS_DOCUMENT_GET_PS_FILE(document), &stat_rec) == 0) { |
|
1119 |
pscopy (src_file, sink, 0, stat_rec.st_size - 1); |
|
1120 |
}
|
|
1121 |
||
1122 |
fclose (src_file); |
|
1123 |
}
|
|
1124 |
||
1125 |
buf = gtk_gs_doc_sink_get_buffer (sink); |
|
1126 |
if (buf == NULL) { |
|
1127 |
return FALSE; |
|
1128 |
}
|
|
1129 |
||
1130 |
f = fopen (filename, "w"); |
|
1131 |
if (f) { |
|
1132 |
fputs (buf, f); |
|
1133 |
fclose (f); |
|
1134 |
} else { |
|
1135 |
result = FALSE; |
|
1136 |
}
|
|
1137 |
||
1138 |
g_free (buf); |
|
1139 |
gtk_gs_doc_sink_free (sink); |
|
1140 |
g_free (sink); |
|
1141 |
||
1142 |
return result; |
|
1143 |
}
|
|
1144 |
||
1145 |
static gboolean |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1146 |
save_page_list (PSDocument *document, int *page_list, const char *filename) |
1147 |
{
|
|
1148 |
gboolean result = TRUE; |
|
1149 |
GtkGSDocSink *sink = gtk_gs_doc_sink_new (); |
|
1150 |
FILE *f; |
|
1151 |
gchar *buf; |
|
1152 |
||
1153 |
pscopydoc (sink, PS_DOCUMENT_GET_PS_FILE(document), |
|
1154 |
document->doc, page_list); |
|
1155 |
||
1156 |
buf = gtk_gs_doc_sink_get_buffer (sink); |
|
1157 |
||
1158 |
f = fopen (filename, "w"); |
|
1159 |
if (f) { |
|
1160 |
fputs (buf, f); |
|
1161 |
fclose (f); |
|
1162 |
} else { |
|
1163 |
result = FALSE; |
|
1164 |
}
|
|
1165 |
||
1166 |
g_free (buf); |
|
1167 |
gtk_gs_doc_sink_free (sink); |
|
1168 |
g_free (sink); |
|
1169 |
||
1170 |
return result; |
|
1171 |
}
|
|
1172 |
||
1173 |
static gboolean |
|
1174 |
ps_document_save (EvDocument *document, |
|
1175 |
const char *uri, |
|
1176 |
GError **error) |
|
1177 |
{
|
|
1178 |
PSDocument *ps = PS_DOCUMENT (document); |
|
1179 |
gboolean result; |
|
1180 |
char *filename; |
|
1181 |
||
1182 |
filename = g_filename_from_uri (uri, NULL, error); |
|
1183 |
if (!filename) |
|
1184 |
return FALSE; |
|
1185 |
||
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1186 |
result = save_document (ps, filename); |
1187 |
||
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1188 |
g_free (filename); |
1189 |
||
1190 |
return result; |
|
1191 |
}
|
|
1192 |
||
1193 |
static int |
|
1194 |
ps_document_get_n_pages (EvDocument *document) |
|
1195 |
{
|
|
1196 |
PSDocument *ps = PS_DOCUMENT (document); |
|
1197 |
||
1198 |
g_return_val_if_fail (ps != NULL, -1); |
|
1199 |
||
1200 |
if (!ps->gs_filename || !ps->doc) { |
|
1201 |
return -1; |
|
1202 |
}
|
|
1203 |
||
1204 |
return ps->structured_doc ? ps->doc->numpages : 1; |
|
1205 |
}
|
|
1206 |
||
1207 |
static void |
|
1208 |
ps_document_get_page_size (EvDocument *document, |
|
1209 |
int page, |
|
1210 |
double *width, |
|
1211 |
double *height) |
|
1212 |
{
|
|
1213 |
PSDocument *gs = PS_DOCUMENT (document); |
|
1214 |
int urx, ury, llx, lly; |
|
1215 |
||
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1216 |
get_page_box (gs, page, &urx, &ury, &llx, &lly); |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1217 |
|
1218 |
if (width) { |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1219 |
*width = (urx - llx) + 0.5; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1220 |
}
|
1221 |
||
1222 |
if (height) { |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1223 |
*height = (ury - lly) + 0.5; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1224 |
}
|
1225 |
}
|
|
1226 |
||
1227 |
static gboolean |
|
1228 |
ps_document_can_get_text (EvDocument *document) |
|
1229 |
{
|
|
1230 |
return FALSE; |
|
1231 |
}
|
|
1232 |
||
1233 |
static void |
|
1234 |
ps_async_renderer_render_pixbuf (EvAsyncRenderer *renderer, int page, double scale, int rotation) |
|
1235 |
{
|
|
1236 |
PSDocument *gs = PS_DOCUMENT (renderer); |
|
1237 |
||
1238 |
if (gs->pstarget == NULL) { |
|
1239 |
gs->target_window = gtk_window_new (GTK_WINDOW_POPUP); |
|
1240 |
gtk_widget_realize (gs->target_window); |
|
1241 |
gs->pstarget = gs->target_window->window; |
|
1242 |
||
1243 |
g_assert (gs->pstarget != NULL); |
|
1244 |
||
1245 |
g_signal_connect (gs->target_window, "event", |
|
1246 |
G_CALLBACK (ps_document_widget_event), |
|
1247 |
gs); |
|
1248 |
}
|
|
1249 |
||
1250 |
setup_pixmap (gs, page, scale, rotation); |
|
1251 |
setup_page (gs, page, scale, rotation); |
|
1252 |
||
1253 |
render_page (gs, page); |
|
1254 |
}
|
|
1255 |
||
1256 |
static EvDocumentInfo * |
|
1257 |
ps_document_get_info (EvDocument *document) |
|
1258 |
{
|
|
1259 |
EvDocumentInfo *info; |
|
1260 |
PSDocument *ps = PS_DOCUMENT (document); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1261 |
int urx, ury, llx, lly; |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1262 |
|
1263 |
info = g_new0 (EvDocumentInfo, 1); |
|
1264 |
info->fields_mask = EV_DOCUMENT_INFO_TITLE | |
|
1265 |
EV_DOCUMENT_INFO_FORMAT | |
|
1266 |
EV_DOCUMENT_INFO_CREATOR | |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1267 |
EV_DOCUMENT_INFO_N_PAGES | |
1268 |
EV_DOCUMENT_INFO_PAPER_SIZE; |
|
1269 |
||
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1270 |
info->title = g_strdup (ps->doc->title); |
1271 |
info->format = ps->doc->epsf ? g_strdup (_("Encapsulated PostScript")) |
|
1272 |
: g_strdup (_("PostScript")); |
|
1273 |
info->creator = g_strdup (ps->doc->creator); |
|
1274 |
info->n_pages = ev_document_get_n_pages (document); |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1275 |
|
1276 |
get_page_box (PS_DOCUMENT (document), 0, &urx, &ury, &llx, &lly); |
|
1277 |
||
1278 |
info->paper_width = (urx - llx) / 72.0f * 25.4f; |
|
1279 |
info->paper_height = (ury - lly) / 72.0f * 25.4f; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1280 |
|
1281 |
return info; |
|
1282 |
}
|
|
1283 |
||
1284 |
static void |
|
1285 |
ps_document_document_iface_init (EvDocumentIface *iface) |
|
1286 |
{
|
|
1287 |
iface->load = ps_document_load; |
|
1288 |
iface->save = ps_document_save; |
|
1289 |
iface->can_get_text = ps_document_can_get_text; |
|
1290 |
iface->get_n_pages = ps_document_get_n_pages; |
|
1291 |
iface->get_page_size = ps_document_get_page_size; |
|
1292 |
iface->get_info = ps_document_get_info; |
|
1293 |
}
|
|
1294 |
||
1295 |
static void |
|
1296 |
ps_async_renderer_iface_init (EvAsyncRendererIface *iface) |
|
1297 |
{
|
|
1298 |
iface->render_pixbuf = ps_async_renderer_render_pixbuf; |
|
1299 |
}
|
|
1300 |
||
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1301 |
static gboolean |
1302 |
ps_document_file_exporter_format_supported (EvFileExporter *exporter, |
|
1303 |
EvFileExporterFormat format) |
|
1304 |
{
|
|
1305 |
return (format == EV_FILE_FORMAT_PS); |
|
1306 |
}
|
|
1307 |
||
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1308 |
static void |
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1309 |
ps_document_file_exporter_begin (EvFileExporter *exporter, |
1310 |
EvFileExporterFormat format, |
|
1311 |
const char *filename, |
|
1312 |
int first_page, |
|
1313 |
int last_page, |
|
1314 |
double width, |
|
1315 |
double height, |
|
1316 |
gboolean duplex) |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1317 |
{
|
1318 |
PSDocument *document = PS_DOCUMENT (exporter); |
|
1319 |
||
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1320 |
if (document->structured_doc) { |
1321 |
g_free (document->ps_export_pagelist); |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1322 |
|
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1323 |
document->ps_export_pagelist = g_new0 (int, document->doc->numpages); |
1324 |
}
|
|
1325 |
||
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1326 |
document->ps_export_filename = g_strdup (filename); |
1327 |
}
|
|
1328 |
||
1329 |
static void |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1330 |
ps_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc) |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1331 |
{
|
1332 |
PSDocument *document = PS_DOCUMENT (exporter); |
|
1333 |
||
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1334 |
if (document->structured_doc) { |
1335 |
document->ps_export_pagelist[rc->page] = 1; |
|
1336 |
}
|
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1337 |
}
|
1338 |
||
1339 |
static void |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1340 |
ps_document_file_exporter_end (EvFileExporter *exporter) |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1341 |
{
|
1342 |
PSDocument *document = PS_DOCUMENT (exporter); |
|
1343 |
||
1.1.1
by Sebastien Bacher
Import upstream version 0.5.0 |
1344 |
if (!document->structured_doc) { |
1345 |
save_document (document, document->ps_export_filename); |
|
1346 |
} else { |
|
1347 |
save_page_list (document, document->ps_export_pagelist, |
|
1348 |
document->ps_export_filename); |
|
1349 |
g_free (document->ps_export_pagelist); |
|
1350 |
g_free (document->ps_export_filename); |
|
1351 |
document->ps_export_pagelist = NULL; |
|
1352 |
document->ps_export_filename = NULL; |
|
1353 |
}
|
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1354 |
}
|
1355 |
||
1356 |
static void |
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1357 |
ps_document_file_exporter_iface_init (EvFileExporterIface *iface) |
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1358 |
{
|
1.1.9
by Sebastien Bacher
Import upstream version 0.7.0 |
1359 |
iface->format_supported = ps_document_file_exporter_format_supported; |
1360 |
iface->begin = ps_document_file_exporter_begin; |
|
1361 |
iface->do_page = ps_document_file_exporter_do_page; |
|
1362 |
iface->end = ps_document_file_exporter_end; |
|
1
by Sebastien Bacher
Import upstream version 0.4.0 |
1363 |
}
|