New cisco icons, and a fix in element.h
[dia.git] / app / paginate_psprint.c
blobf3714dc49a0dba1d35e5891e465ce2a63960d81e
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998, 1999 Alexander Larsson
4 * paginate_psprint.[ch] -- pagination code for the postscript backend
5 * Copyright (C) 1999 James Henstridge
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <string.h> /* strlen */
28 #include <signal.h>
29 #include <errno.h>
31 #include "intl.h"
32 #include "message.h"
33 #include "diagram.h"
34 #include "diagramdata.h"
35 #include "render_eps.h"
36 #include "diapsrenderer.h"
37 #include "paginate_psprint.h"
38 #include "diapagelayout.h"
39 #include "persistence.h"
41 #include <gtk/gtk.h>
43 #ifdef G_OS_WIN32
44 #include <io.h>
45 #include "win32print.h"
46 #define pclose(file) win32_printer_close (file)
47 #endif
49 /* keep track of print options between prints */
50 typedef struct _dia_print_options {
51 int printer;
52 } dia_print_options;
54 static dia_print_options last_print_options =
59 static void
60 count_objs(DiaObject *obj, DiaRenderer *renderer, int active_layer, guint *nobjs)
62 (*nobjs)++;
65 static guint
66 print_page(DiagramData *data, DiaRenderer *diarend, Rectangle *bounds)
68 DiaPsRenderer *rend = DIA_PS_RENDERER(diarend);
69 guint nobjs = 0;
70 gfloat tmargin = data->paper.tmargin, bmargin = data->paper.bmargin;
71 gfloat lmargin = data->paper.lmargin;
72 gfloat scale = data->paper.scaling;
73 gchar d1_buf[G_ASCII_DTOSTR_BUF_SIZE];
74 gchar d2_buf[G_ASCII_DTOSTR_BUF_SIZE];
76 rend->paper = data->paper.name;
77 rend->is_portrait = data->paper.is_portrait;
79 /* count the number of objects in this region */
80 data_render(data, diarend, bounds,
81 (ObjectRenderer) count_objs, &nobjs);
83 if (nobjs == 0)
84 return nobjs;
86 /* output a page number comment */
87 fprintf(rend->file, "%%%%Page: %d %d\n", rend->pagenum, rend->pagenum);
88 rend->pagenum++;
90 /* save print context */
91 fprintf(rend->file, "gs\n");
93 /* transform coordinate system */
94 if (data->paper.is_portrait) {
95 fprintf(rend->file, "%s %s scale\n",
96 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", 28.346457*scale),
97 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", -28.346457*scale) );
98 fprintf(rend->file, "%s %s translate\n",
99 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", lmargin/scale - bounds->left),
100 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", -bmargin/scale - bounds->bottom) );
101 } else {
102 fprintf(rend->file, "90 rotate\n");
103 fprintf(rend->file, "%s %s scale\n",
104 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", 28.346457*scale),
105 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", -28.346457*scale) );
106 fprintf(rend->file, "%s %s translate\n",
107 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", lmargin/scale - bounds->left),
108 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", tmargin/scale - bounds->top) );
111 /* set up clip mask */
112 fprintf(rend->file, "n %s %s m ",
113 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", bounds->left),
114 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", bounds->top) );
115 fprintf(rend->file, "%s %s l ",
116 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", bounds->right),
117 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", bounds->top) );
118 fprintf(rend->file, "%s %s l ",
119 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", bounds->right),
120 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", bounds->bottom) );
121 fprintf(rend->file, "%s %s l ",
122 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", bounds->left),
123 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", bounds->bottom) );
124 fprintf(rend->file, "%s %s l ",
125 g_ascii_formatd(d1_buf, sizeof(d1_buf), "%f", bounds->left),
126 g_ascii_formatd(d2_buf, sizeof(d2_buf), "%f", bounds->top) );
127 /* Tip from Dov Grobgeld: Clip does not destroy the path, so we should
128 do a newpath afterwards */
129 fprintf(rend->file, "clip n\n");
131 /* render the region */
132 data_render(data, diarend, bounds, NULL, NULL);
134 /* restore print context */
135 fprintf(rend->file, "gr\n");
137 /* print the page */
138 fprintf(rend->file, "showpage\n\n");
140 return nobjs;
143 void
144 paginate_psprint(Diagram *dia, FILE *file)
146 DiaRenderer *rend;
147 Rectangle *extents;
148 gfloat width, height;
149 gfloat x, y, initx, inity;
150 guint nobjs = 0;
152 rend = new_psprint_renderer(dia, file);
154 #ifdef DIA_PS_RENDERER_DUAL_PASS
155 /* Prepare the prolog (with fonts etc) */
156 data_render(dia->data, DIA_RENDERER(rend), NULL, NULL, NULL);
157 eps_renderer_prolog_done(rend);
158 #endif
160 /* the usable area of the page */
161 width = dia->data->paper.width;
162 height = dia->data->paper.height;
164 /* get extents, and make them multiples of width / height */
165 extents = &dia->data->extents;
166 initx = extents->left;
167 inity = extents->top;
168 /* make page boundaries align with origin */
169 if (!dia->data->paper.fitto) {
170 initx = floor(initx / width) * width;
171 inity = floor(inity / height) * height;
174 /* iterate through all the pages in the diagram */
175 for (y = inity; y < extents->bottom; y += height)
176 for (x = initx; x < extents->right; x += width) {
177 Rectangle page_bounds;
179 page_bounds.left = x;
180 page_bounds.right = x + width;
181 page_bounds.top = y;
182 page_bounds.bottom = y + height;
184 nobjs += print_page(dia->data,rend, &page_bounds);
187 g_object_unref(rend);
191 static void
192 change_entry_state(GtkToggleButton *radio, GtkWidget *entry)
194 gtk_widget_set_sensitive(entry, gtk_toggle_button_get_active(radio));
197 static void
198 ok_pressed(GtkButton *button, gboolean *flag)
200 *flag = TRUE;
201 gtk_main_quit();
204 static gboolean sigpipe_received = FALSE;
205 static void
206 pipe_handler(int signum)
208 sigpipe_received = TRUE;
211 static gboolean
212 diagram_print_destroy(GtkWidget *widget)
214 Diagram *dia;
216 if ((dia = gtk_object_get_user_data(GTK_OBJECT(widget))) != NULL) {
217 g_object_unref(dia);
218 gtk_object_set_user_data(GTK_OBJECT(widget), NULL);
221 return FALSE;
224 void
225 diagram_print_ps(Diagram *dia)
227 GtkWidget *dialog;
228 GtkWidget *vbox, *frame, *table, *box, *button;
229 GtkWidget *iscmd, *isofile;
230 GtkWidget *cmd, *ofile;
231 gboolean cont = FALSE;
232 gchar *printcmd = NULL;
233 gchar *orig_command, *orig_file;
235 FILE *file;
236 gboolean is_pipe;
237 #ifndef G_OS_WIN32
238 /* all the signal stuff below doesn't compile on win32, but it isn't
239 * needed anymore because the pipe handling - which never worked on win32
240 * anyway - is replace by "native" postscript printing now ...
242 void *old_action;
243 #endif
245 /* create the dialog */
246 dialog = gtk_dialog_new();
247 /* the dialog has it's own reference to the diagram */
248 g_object_ref(dia);
249 gtk_object_set_user_data(GTK_OBJECT(dialog), dia);
250 g_signal_connect(GTK_OBJECT(dialog), "destroy",
251 G_CALLBACK(diagram_print_destroy), NULL);
252 g_signal_connect(GTK_OBJECT(dialog), "delete_event",
253 G_CALLBACK(gtk_main_quit), NULL);
254 g_signal_connect(GTK_OBJECT(dialog), "delete_event",
255 G_CALLBACK(gtk_true), NULL);
256 vbox = GTK_DIALOG(dialog)->vbox;
258 frame = gtk_frame_new(_("Select Printer"));
259 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
260 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
261 gtk_widget_show(frame);
263 table = gtk_table_new(2, 2, FALSE);
264 gtk_container_set_border_width(GTK_CONTAINER(table), 5);
265 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
266 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
267 gtk_container_add(GTK_CONTAINER(frame), table);
268 gtk_widget_show(table);
270 iscmd = gtk_radio_button_new_with_label(NULL, _("Printer"));
271 gtk_table_attach(GTK_TABLE(table), iscmd, 0,1, 0,1,
272 GTK_FILL, GTK_FILL|GTK_EXPAND, 0, 0);
273 gtk_widget_show(iscmd);
275 cmd = gtk_entry_new();
276 gtk_table_attach(GTK_TABLE(table), cmd, 1,2, 0,1,
277 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
278 gtk_widget_show(cmd);
280 g_signal_connect(GTK_OBJECT(iscmd), "toggled",
281 G_CALLBACK(change_entry_state), cmd);
283 isofile = gtk_radio_button_new_with_label(GTK_RADIO_BUTTON(iscmd)->group,
284 _("File"));
285 gtk_table_attach(GTK_TABLE(table), isofile, 0,1, 1,2,
286 GTK_FILL, GTK_FILL|GTK_EXPAND, 0, 0);
287 gtk_widget_show(isofile);
289 ofile = gtk_entry_new();
290 gtk_widget_set_sensitive(ofile, FALSE);
291 gtk_table_attach(GTK_TABLE(table), ofile, 1,2, 1,2,
292 GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
293 gtk_widget_show(ofile);
294 g_signal_connect(GTK_OBJECT(isofile), "toggled",
295 G_CALLBACK(change_entry_state), ofile);
297 box = GTK_DIALOG(dialog)->action_area;
299 button = gtk_button_new_with_label(_("OK"));
300 g_signal_connect(GTK_OBJECT(button), "clicked",
301 G_CALLBACK(ok_pressed), &cont);
302 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
303 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
304 gtk_widget_grab_default(button);
305 gtk_widget_show(button);
307 button = gtk_button_new_with_label(_("Cancel"));
308 g_signal_connect(GTK_OBJECT(button), "clicked",
309 G_CALLBACK(gtk_main_quit), NULL);
310 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
311 gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
312 gtk_widget_show(button);
314 /* Set default or old dialog values: */
315 #ifdef G_OS_WIN32
316 gtk_entry_set_text(GTK_ENTRY(cmd), win32_printer_default ());
317 #else
319 const gchar *printer = g_getenv("PRINTER");
321 if (printer) {
322 printcmd = g_strdup_printf("lpr -P%s", printer);
323 } else {
324 printcmd = g_strdup("lpr");
327 gtk_entry_set_text(GTK_ENTRY(cmd), printcmd);
328 g_free(printcmd);
329 printcmd = NULL;
331 #endif
332 printf("Print dialog?\n");
333 persistence_register_string_entry("printer-command", cmd);
334 printcmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(cmd)));
335 orig_command = printcmd;
336 /* Ought to use filename+extension here */
337 gtk_entry_set_text(GTK_ENTRY(ofile), "output.ps");
338 persistence_register_string_entry("printer-file", ofile);
339 orig_file = g_strdup(gtk_entry_get_text(GTK_ENTRY(ofile)));
341 /* Scaling is already set at creation. */
342 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iscmd), last_print_options.printer);
343 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(isofile), !last_print_options.printer);
345 gtk_widget_show(dialog);
346 gtk_main();
348 if(!dia) {
349 gtk_widget_destroy(dialog);
350 return;
353 if (!cont) {
354 persistence_change_string_entry("printer-command", orig_command, cmd);
355 persistence_change_string_entry("printer-file", orig_file, ofile);
356 gtk_widget_destroy(dialog);
357 g_free(orig_command);
358 g_free(orig_file);
359 return;
362 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iscmd))) {
363 printcmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(cmd)));
364 #ifdef G_OS_WIN32
365 file = win32_printer_open (printcmd);
366 #else
367 file = popen(printcmd, "w");
368 #endif
369 is_pipe = TRUE;
370 } else {
371 const gchar *filename = gtk_entry_get_text(GTK_ENTRY(ofile));
372 if (!g_path_is_absolute(filename)) {
373 char *dirname;
374 char *full_filename;
376 dirname = g_path_get_dirname(dia->filename);
377 full_filename = g_build_filename(dirname, filename, NULL);
378 file = fopen(full_filename, "w");
379 g_free(full_filename);
380 g_free(dirname);
381 } else {
382 file = fopen(filename, "w");
384 is_pipe = FALSE;
387 /* Store dialog values */
388 g_free(orig_command);
389 g_free(orig_file);
390 last_print_options.printer = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(iscmd));
392 if (!file) {
393 if (is_pipe) {
394 message_warning(_("Could not run command '%s': %s"), printcmd, strerror(errno));
395 g_free(printcmd);
396 } else
397 message_warning(_("Could not open '%s' for writing: %s"),
398 gtk_entry_get_text(GTK_ENTRY(ofile)), strerror(errno));
399 gtk_widget_destroy(dialog);
400 return;
403 #ifndef G_OS_WIN32
404 /* set up a SIGPIPE handler to catch IO errors, rather than segfaulting */
405 sigpipe_received = FALSE;
406 old_action = signal(SIGPIPE, pipe_handler);
407 #endif
409 paginate_psprint(dia, file);
410 gtk_widget_destroy(dialog);
411 if (is_pipe) {
412 int exitval = pclose(file);
413 if (exitval != 0) {
414 message_error(_("Printing error: command '%s' returned %d\n"),
415 printcmd, exitval);
417 } else
418 fclose(file);
420 #ifndef G_OS_WIN32
421 /* restore original behaviour */
422 signal(SIGPIPE, old_action);
423 #endif
424 if (sigpipe_received)
425 message_error(_("Printing error: command '%s' caused sigpipe."),
426 printcmd);
428 if (is_pipe) g_free(printcmd);