comparison src/print.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children 17acca639a86
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQview
3 * (C) 2004 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12
13 #include "gqview.h"
14 #include "print.h"
15
16 #include "filelist.h"
17 #include "image.h"
18 #include "image-load.h"
19 #include "pixbuf_util.h"
20 #include "thumb.h"
21 #include "utilops.h"
22 #include "ui_bookmark.h"
23 #include "ui_menu.h"
24 #include "ui_misc.h"
25 #include "ui_utildlg.h"
26 #include "ui_fileops.h"
27 #include "ui_spinner.h"
28 #include "ui_tabcomp.h"
29
30
31 #include <locale.h>
32 #include <signal.h>
33
34
35 #define PRINT_LPR_COMMAND "lpr"
36 #define PRINT_LPR_CUSTOM "lpr -P %s"
37 #define PRINT_LPR_QUERY "lpstat -p"
38
39 #define PRINT_DLG_WIDTH 600
40 #define PRINT_DLG_HEIGHT 400
41
42 #define PRINT_DLG_PREVIEW_WIDTH 270
43 #define PRINT_DLG_PREVIEW_HEIGHT -1
44
45 /* these are in point units */
46 #define PRINT_MIN_WIDTH 100
47 #define PRINT_MIN_HEIGHT 100
48 #define PRINT_MAX_WIDTH 4000
49 #define PRINT_MAX_HEIGHT 4000
50
51 #define PRINT_MARGIN_DEFAULT 36
52
53 #define PRINT_PROOF_MIN_SIZE 8
54 #define PRINT_PROOF_MAX_SIZE 720
55 #define PRINT_PROOF_DEFAULT_SIZE 144
56 #define PRINT_PROOF_MARGIN 5
57
58 /* default page size */
59 #define PAGE_LAYOUT_WIDTH 850
60 #define PAGE_LAYOUT_HEIGHT 1100
61
62 /* preview uses 1 pixel = PRINT_PREVIEW_SCALE points */
63 #define PRINT_PREVIEW_SCALE 4
64
65 /* default dpi to use for printing ps image data */
66 #define PRINT_PS_DPI_DEFAULT 300.0
67 #define PRINT_PS_DPI_MIN 150.0
68 /* method to use when scaling down image data */
69 #define PRINT_PS_MAX_INTERP GDK_INTERP_BILINEAR
70
71 /* padding between objects */
72 #define PRINT_TEXT_PADDING 3.0
73
74 /* locale for postscript portability */
75 #define POSTSCRIPT_LOCALE "C"
76
77
78 /* group and keys for saving prefs */
79 #define PRINT_PREF_GROUP "print_settings"
80
81 #define PRINT_PREF_SAVE "save_settings"
82
83 #define PRINT_PREF_OUTPUT "output"
84 #define PRINT_PREF_FORMAT "format"
85 #define PRINT_PREF_DPI "dpi"
86 #define PRINT_PREF_UNITS "units"
87 #define PRINT_PREF_SIZE "size"
88 #define PRINT_PREF_ORIENTATION "orientation"
89
90 #define PRINT_PREF_CUSTOM_WIDTH "custom_width"
91 #define PRINT_PREF_CUSTOM_HEIGHT "custom_height"
92 #define PRINT_PREF_MARGIN_LEFT "margin_left"
93 #define PRINT_PREF_MARGIN_RIGHT "margin_right"
94 #define PRINT_PREF_MARGIN_TOP "margin_top"
95 #define PRINT_PREF_MARGIN_BOTTOM "margin_bottom"
96 #define PRINT_PREF_PROOF_WIDTH "proof_width"
97 #define PRINT_PREF_PROOF_HEIGHT "proof_height"
98
99 #define PRINT_PREF_PRINTERC "custom_printer"
100
101
102 typedef enum {
103 PRINT_SOURCE_IMAGE = 0,
104 PRINT_SOURCE_SELECTION,
105 PRINT_SOURCE_ALL,
106 PRINT_SOURCE_COUNT
107 } PrintSource;
108
109 const gchar *print_source_text[] = {
110 N_("Image"),
111 N_("Selection"),
112 N_("All"),
113 NULL
114 };
115
116 typedef enum {
117 PRINT_LAYOUT_IMAGE = 0,
118 PRINT_LAYOUT_PROOF,
119 PRINT_LAYOUT_COUNT
120 } PrintLayout;
121
122 const gchar *print_layout_text[] = {
123 N_("One image per page"),
124 N_("Proof sheet"),
125 NULL
126 };
127
128 typedef enum {
129 PRINT_OUTPUT_PS_LPR = 0,
130 PRINT_OUTPUT_PS_CUSTOM,
131 PRINT_OUTPUT_PS_FILE,
132 PRINT_OUTPUT_RGB_FILE,
133 PRINT_OUTPUT_COUNT
134 } PrintOutput;
135
136 const gchar *print_output_text[] = {
137 N_("Default printer"),
138 N_("Custom printer"),
139 N_("PostScript file"),
140 N_("Image file"),
141 NULL,
142 NULL
143 };
144
145 typedef enum {
146 PRINT_FILE_JPG_LOW = 0,
147 PRINT_FILE_JPG_NORMAL,
148 PRINT_FILE_JPG_HIGH,
149 PRINT_FILE_PNG,
150 PRINT_FILE_COUNT
151 } PrintFileFormat;
152
153 const gchar *print_file_format_text[] = {
154 N_("jpeg, low quality"),
155 N_("jpeg, normal quality"),
156 N_("jpeg, high quality"),
157 "png",
158 NULL
159 };
160
161 typedef enum {
162 RENDER_FORMAT_PREVIEW,
163 RENDER_FORMAT_RGB,
164 RENDER_FORMAT_PS
165 } RenderFormat;
166
167 typedef enum {
168 TEXT_INFO_FILENAME = 1 << 0,
169 TEXT_INFO_FILEDATE = 1 << 1,
170 TEXT_INFO_FILESIZE = 1 << 2,
171 TEXT_INFO_DIMENSIONS = 1 << 3
172 } TextInfo;
173
174 typedef struct _PrintWindow PrintWindow;
175 struct _PrintWindow
176 {
177 GenericDialog *dialog;
178
179 gchar *source_path;
180 GList *source_selection;
181 GList *source_list;
182
183 PrintSource source;
184 PrintLayout layout;
185 PrintOutput output;
186
187 gchar *output_path;
188 gchar *output_custom;
189
190 PrintFileFormat output_format;
191
192 gdouble max_dpi;
193
194 GtkWidget *notebook;
195
196 GtkWidget *path_entry;
197 GtkWidget *custom_entry;
198 GtkWidget *path_format_menu;
199 GtkWidget *max_dpi_menu;
200
201 ImageWindow *layout_image;
202 gdouble layout_width;
203 gdouble layout_height;
204
205 gint layout_idle_id;
206
207 gint image_scale;
208
209 GtkWidget *image_scale_spin;
210
211 gdouble proof_width;
212 gdouble proof_height;
213 gint proof_columns;
214 gint proof_rows;
215 GList *proof_point;
216 gint proof_position;
217 gint proof_page;
218
219 GtkWidget *proof_group;
220 GtkWidget *proof_width_spin;
221 GtkWidget *proof_height_spin;
222
223 GtkWidget *paper_menu;
224 GtkWidget *paper_width_spin;
225 GtkWidget *paper_height_spin;
226 GtkWidget *paper_units_menu;
227 GtkWidget *paper_orientation_menu;
228
229 GtkWidget *margin_left_spin;
230 GtkWidget *margin_right_spin;
231 GtkWidget *margin_top_spin;
232 GtkWidget *margin_bottom_spin;
233
234 gint paper_units;
235 gint paper_size;
236 gdouble paper_width;
237 gdouble paper_height;
238 gint paper_orientation;
239
240 gdouble margin_left;
241 gdouble margin_right;
242 gdouble margin_top;
243 gdouble margin_bottom;
244
245 GtkWidget *button_back;
246 GtkWidget *button_next;
247 GtkWidget *page_label;
248 GtkWidget *print_button;
249
250 gdouble single_scale;
251 gdouble single_x;
252 gdouble single_y;
253
254 GtkWidget *single_scale_spin;
255
256 TextInfo text_fields;
257 gint text_points;
258 guint8 text_r;
259 guint8 text_g;
260 guint8 text_b;
261
262 gint save_settings;
263
264 /* job printing */
265
266 GenericDialog *job_dialog;
267 GtkWidget *job_progress;
268 GtkWidget *job_progress_label;
269
270 RenderFormat job_format;
271 PrintOutput job_output;
272
273 FILE *job_file;
274 FILE *job_pipe;
275 gchar *job_path;
276
277 GdkPixbuf *job_pixbuf;
278
279 gint job_page;
280 ImageLoader *job_loader;
281 };
282
283
284 static void print_job_throw_error(PrintWindow *pw, const gchar *message);
285 static gint print_job_start(PrintWindow *pw, RenderFormat format, PrintOutput output);
286 static void print_job_close(PrintWindow *pw, gint error);
287 static void print_window_close(PrintWindow *pw);
288
289
290 /* misc utils */
291
292 static gint clip_region(gdouble x1, gdouble y1, gdouble w1, gdouble h1,
293 gdouble x2, gdouble y2, gdouble w2, gdouble h2,
294 gdouble *rx, gdouble *ry, gdouble *rw, gdouble *rh)
295 {
296 if (x2 + w2 <= x1 || x2 >= x1 + w1 ||
297 y2 + h2 <= y1 || y2 >= y1 + h1)
298 {
299 return FALSE;
300 }
301
302 *rx = MAX(x1, x2);
303 *rw = MIN((x1 + w1), (x2 + w2)) - *rx;
304
305 *ry = MAX(y1, y2);
306 *rh = MIN((y1 + h1), (y2 + h2)) - *ry;
307
308 return TRUE;
309 }
310
311 static const gchar *print_output_name(PrintOutput output)
312 {
313 if (output < 0 || output >= PRINT_OUTPUT_COUNT) return "";
314
315 return _(print_output_text[output]);
316 }
317
318
319 /*
320 *-----------------------------------------------------------------------------
321 * data
322 *-----------------------------------------------------------------------------
323 */
324
325
326 typedef enum {
327 PAPER_UNIT_POINTS = 0,
328 PAPER_UNIT_MM,
329 PAPER_UNIT_CM,
330 PAPER_UNIT_INCH,
331 PAPER_UNIT_PICAS,
332 PAPER_UNIT_COUNT
333 } PaperUnits;
334
335 typedef enum {
336 PAPER_ORIENTATION_PORTRAIT = 0,
337 PAPER_ORIENTATION_LANDSCAPE,
338 PAPER_ORIENTATION_COUNT
339 } PaperOrientation;
340
341 typedef struct _PaperSize PaperSize;
342 struct _PaperSize {
343 gchar *description;
344 gint width;
345 gint height;
346 PaperOrientation orientation;
347 };
348
349 const gchar *print_paper_units[] = {
350 N_("points"),
351 N_("millimeters"),
352 N_("centimeters"),
353 N_("inches"),
354 N_("picas"),
355 NULL
356 };
357
358 const gchar *print_paper_orientation[] = {
359 N_("Portrait"),
360 N_("Landscape"),
361 NULL
362 };
363
364 PaperSize print_paper_sizes[] = {
365 { N_("Custom"), 360, 720, PAPER_ORIENTATION_PORTRAIT },
366 { N_("Letter"), 612, 792, PAPER_ORIENTATION_PORTRAIT }, /* in 8.5 x 11 */
367 { N_("Legal"), 612, 1008, PAPER_ORIENTATION_PORTRAIT }, /* in 8.5 x 14 */
368 { N_("Executive"), 522, 756, PAPER_ORIENTATION_PORTRAIT }, /* in 7.25x 10.5 */
369 { "A0", 2384, 3370, PAPER_ORIENTATION_PORTRAIT }, /* mm 841 x 1189 */
370 { "A1", 1684, 2384, PAPER_ORIENTATION_PORTRAIT }, /* mm 594 x 841 */
371 { "A2", 1191, 1684, PAPER_ORIENTATION_PORTRAIT }, /* mm 420 x 594 */
372 { "A3", 842, 1191, PAPER_ORIENTATION_PORTRAIT }, /* mm 297 x 420 */
373 { "A4", 595, 842, PAPER_ORIENTATION_PORTRAIT }, /* mm 210 x 297 */
374 { "A5", 420, 595, PAPER_ORIENTATION_PORTRAIT }, /* mm 148 x 210 */
375 { "A6", 298, 420, PAPER_ORIENTATION_PORTRAIT }, /* mm 105 x 148 */
376 { "B3", 1001, 1417, PAPER_ORIENTATION_PORTRAIT }, /* mm 353 x 500 */
377 { "B4", 709, 1001, PAPER_ORIENTATION_PORTRAIT }, /* mm 250 x 353 */
378 { "B5", 499, 709, PAPER_ORIENTATION_PORTRAIT }, /* mm 176 x 250 */
379 { "B6", 354, 499, PAPER_ORIENTATION_PORTRAIT }, /* mm 125 x 176 */
380 { N_("Envelope #10"), 297, 684, PAPER_ORIENTATION_LANDSCAPE }, /* in 4.125 x 9.5 */
381 { N_("Envelope #9"), 279, 639, PAPER_ORIENTATION_LANDSCAPE }, /* in 3.875 x 8.875 */
382 { N_("Envelope C4"), 649, 918, PAPER_ORIENTATION_LANDSCAPE }, /* mm 229 x 324 */
383 { N_("Envelope C5"), 459, 649, PAPER_ORIENTATION_LANDSCAPE }, /* mm 162 x 229 */
384 { N_("Envelope C6"), 323, 459, PAPER_ORIENTATION_LANDSCAPE }, /* mm 114 x 162 */
385 { N_("Photo 6x4"), 432, 288, PAPER_ORIENTATION_PORTRAIT }, /* in 6 x 4 */
386 { N_("Photo 8x10"), 576, 720, PAPER_ORIENTATION_PORTRAIT }, /* in 8 x 10 */
387 { N_("Postcard"), 284, 419, PAPER_ORIENTATION_LANDSCAPE }, /* mm 100 x 148 */
388 { N_("Tabloid"), 792, 1224, PAPER_ORIENTATION_PORTRAIT }, /* in 11 x 17 */
389 { NULL, 0, 0, 0 }
390 };
391
392
393 static PaperSize *print_paper_size_nth(gint n)
394 {
395 PaperSize *ps = NULL;
396 gint i = 0;
397
398 while (i <= n && print_paper_sizes[i].description)
399 {
400 ps = &print_paper_sizes[i];
401 i++;
402 }
403
404 return ps;
405 }
406
407 static gint print_paper_size_lookup(gint n, gdouble *width, gdouble *height)
408 {
409 PaperSize *ps;
410 gdouble w, h;
411
412 ps = print_paper_size_nth(n);
413 if (!ps) return FALSE;
414
415 if (ps->orientation == PAPER_ORIENTATION_PORTRAIT)
416 {
417 w = ps->width;
418 h = ps->height;
419 }
420 else
421 {
422 h = ps->width;
423 w = ps->height;
424 }
425
426 if (width) *width = w;
427 if (height) *height = h;
428
429 return TRUE;
430 }
431
432 static gdouble print_paper_size_convert_units(gdouble value, PaperUnits src, PaperUnits dst)
433 {
434 gdouble ret;
435
436 if (src == dst) return value;
437
438 switch (src)
439 {
440 case PAPER_UNIT_MM:
441 ret = value / 25.4 * 72.0;
442 break;
443 case PAPER_UNIT_CM:
444 ret = value / 2.54 * 72.0;
445 break;
446 case PAPER_UNIT_INCH:
447 ret = value * 72.0;
448 break;
449 case PAPER_UNIT_PICAS:
450 ret = value * 12.0;
451 break;
452 case PAPER_UNIT_POINTS:
453 default:
454 ret = value;
455 break;
456 }
457
458 switch (dst)
459 {
460 case PAPER_UNIT_MM:
461 ret = ret / 72.0 * 25.4;
462 break;
463 case PAPER_UNIT_CM:
464 ret = ret / 72.0 * 2.54;
465 break;
466 case PAPER_UNIT_INCH:
467 ret = ret / 72.0;
468 break;
469 case PAPER_UNIT_PICAS:
470 ret = ret / 12.0;
471 break;
472 case PAPER_UNIT_POINTS:
473 default:
474 break;
475 }
476
477 return ret;
478 }
479
480 static PaperUnits paper_unit_default(void)
481 {
482 const char *result;
483 #if 0
484 /* this is not used because it is not even slightly portable */
485 #include <langinfo.h>
486
487 result = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
488 if (result[0] == '2') return PAPER_UNIT_INCH;
489 #endif
490
491 #ifdef LC_MEASUREMENT
492 result = setlocale(LC_MEASUREMENT, NULL);
493 #else
494 result = setlocale(LC_ALL, NULL);
495 #endif
496 if (result &&
497 (strstr(result, "_US") || strstr(result, "_PR")) )
498 {
499 return PAPER_UNIT_INCH;
500 }
501
502 return PAPER_UNIT_CM;
503 }
504
505 /*
506 *-----------------------------------------------------------------------------
507 * the layout window
508 *-----------------------------------------------------------------------------
509 */
510
511 static gint print_layout_page_count(PrintWindow *pw);
512
513
514 static gint print_preview_unit(gdouble points)
515 {
516 return (int)(points / PRINT_PREVIEW_SCALE);
517 }
518
519 static void print_proof_size(PrintWindow *pw, gdouble *width, gdouble *height)
520 {
521 if (width) *width = pw->proof_width + PRINT_PROOF_MARGIN * 2;
522 if (height)
523 {
524 gdouble h;
525
526 h = pw->proof_height + PRINT_PROOF_MARGIN * 2;
527 if (pw->text_fields != 0) h += PRINT_TEXT_PADDING;
528 if (pw->text_fields & TEXT_INFO_FILENAME) h+= (gdouble)pw->text_points * 1.25;
529 if (pw->text_fields & TEXT_INFO_DIMENSIONS) h+= (gdouble)pw->text_points * 1.25;
530 if (pw->text_fields & TEXT_INFO_FILEDATE) h+= (gdouble)pw->text_points * 1.25;
531 if (pw->text_fields & TEXT_INFO_FILESIZE) h+= (gdouble)pw->text_points * 1.25;
532 *height = h;
533 }
534 }
535
536 static void print_window_layout_status(PrintWindow *pw)
537 {
538 gint total;
539 gchar *buf;
540
541 total = print_layout_page_count(pw);
542 pw->proof_page = CLAMP(pw->proof_page, 0, total - 1);
543
544 buf = g_strdup_printf(_("page %d of %d"), pw->proof_page + 1, (total > 0) ? total : 1);
545 gtk_label_set_text(GTK_LABEL(pw->page_label), buf);
546 g_free(buf);
547
548 gtk_widget_set_sensitive(pw->page_label, (total > 0));
549
550 gtk_widget_set_sensitive(pw->button_back, (pw->proof_page > 0));
551 gtk_widget_set_sensitive(pw->button_next, (pw->proof_page < total - 1));
552
553 gtk_widget_set_sensitive(pw->print_button, total > 0);
554 }
555
556 static void print_window_layout_render_stop(PrintWindow *pw)
557 {
558 if (pw->layout_idle_id != -1)
559 {
560 g_source_remove(pw->layout_idle_id);
561 pw->layout_idle_id = -1;
562 }
563 }
564
565 static gboolean print_window_layout_render_idle(gpointer data)
566 {
567 PrintWindow *pw = data;
568
569 print_job_close(pw, FALSE);
570 print_job_start(pw, RENDER_FORMAT_PREVIEW, 0);
571
572 pw->layout_idle_id = -1;
573 return FALSE;
574 }
575
576 static void print_window_layout_render(PrintWindow *pw)
577 {
578 gdouble proof_w, proof_h;
579
580 print_proof_size(pw, &proof_w, &proof_h);
581 pw->proof_columns = (pw->layout_width - pw->margin_left - pw->margin_right) / proof_w;
582 pw->proof_rows = (pw->layout_height - pw->margin_top - pw->margin_bottom) / proof_h;
583
584 print_window_layout_status(pw);
585
586 if (pw->layout_idle_id == -1)
587 {
588 pw->layout_idle_id = g_idle_add(print_window_layout_render_idle, pw);
589 }
590 }
591
592 static void print_window_layout_size(PrintWindow *pw)
593 {
594 GdkPixbuf *pixbuf;
595 gdouble width;
596 gdouble height;
597 gint sw, sh;
598
599 if (!pw->layout_image) return;
600
601 if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
602 {
603 width = pw->paper_height;
604 height = pw->paper_width;
605 }
606 else
607 {
608 width = pw->paper_width;
609 height = pw->paper_height;
610 }
611
612 pw->layout_width = width;
613 pw->layout_height = height;
614
615 sw = print_preview_unit(width);
616 sh = print_preview_unit(height);
617 pixbuf = pw->layout_image->pixbuf;
618 if (!pixbuf ||
619 gdk_pixbuf_get_width(pixbuf) != sw ||
620 gdk_pixbuf_get_height(pixbuf) != sh)
621 {
622 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, sw, sh);
623 image_change_pixbuf(pw->layout_image, pixbuf, 0.0);
624 g_object_unref(pixbuf);
625 }
626
627 print_window_layout_render(pw);
628 print_window_layout_status(pw);
629 }
630
631 static gint print_layout_page_count(PrintWindow *pw)
632 {
633 gint images;
634 gint images_per_page;
635 gint pages;
636
637 if (pw->layout_width - pw->margin_left - pw->margin_right <= 0.0 ||
638 pw->layout_height - pw->margin_top - pw->margin_bottom <= 0.0)
639 {
640 return 0;
641 }
642
643 switch (pw->source)
644 {
645 case PRINT_SOURCE_ALL:
646 images = g_list_length(pw->source_list);
647 break;
648 case PRINT_SOURCE_SELECTION:
649 images = g_list_length(pw->source_selection);
650 break;
651 case PRINT_SOURCE_IMAGE:
652 default:
653 images = (pw->source_path) ? 1 : 0;
654 break;
655 }
656
657 switch (pw->layout)
658 {
659 case PRINT_LAYOUT_PROOF:
660 images_per_page = pw->proof_columns * pw->proof_rows;
661 break;
662 case PRINT_LAYOUT_IMAGE:
663 default:
664 images_per_page = 1;
665 break;
666 }
667
668 if (images < 1 || images_per_page < 1) return 0;
669
670 pages = images / images_per_page;
671 if (pages * images_per_page < images) pages++;
672
673 return pages;
674 }
675
676 static void print_layout_page_step(PrintWindow *pw, gint step)
677 {
678 gint max;
679 gint page;
680
681 max = print_layout_page_count(pw);
682 page = pw->proof_page + step;
683
684 if (page >= max) page = max - 1;
685 if (page < 0) page = 0;
686
687 if (page == pw->proof_page) return;
688
689 pw->proof_page = page;
690 print_window_layout_size(pw);
691 }
692
693 static void print_layout_page_back_cb(GtkWidget *widget, gpointer data)
694 {
695 PrintWindow *pw = data;
696
697 print_layout_page_step(pw, -1);
698 }
699
700 static void print_layout_page_next_cb(GtkWidget *widget, gpointer data)
701 {
702 PrintWindow *pw = data;
703
704 print_layout_page_step(pw, 1);
705 }
706
707 static void print_layout_zoom_in_cb(GtkWidget *widget, gpointer data)
708 {
709 PrintWindow *pw = data;
710 image_zoom_adjust(pw->layout_image, 0.25);
711 }
712
713 static void print_layout_zoom_out_cb(GtkWidget *widget, gpointer data)
714 {
715 PrintWindow *pw = data;
716 image_zoom_adjust(pw->layout_image, -0.25);
717 }
718
719 static void print_layout_zoom_original_cb(GtkWidget *widget, gpointer data)
720 {
721 PrintWindow *pw = data;
722 gdouble zoom;
723
724 zoom = image_zoom_get(pw->layout_image);
725 image_zoom_set(pw->layout_image, (zoom == 1.0) ? 0.0 : 1.0);
726 }
727
728 static GtkWidget *print_window_layout_setup(PrintWindow *pw, GtkWidget *box)
729 {
730 GtkWidget *vbox;
731 GtkWidget *hbox;
732 GtkWidget *group;
733 GtkWidget *button;
734
735 vbox = pref_box_new(box, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
736 group = pref_frame_new(vbox, TRUE, _("Preview"), GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
737
738 pw->layout_idle_id = -1;
739
740 pw->layout_image = image_new(FALSE);
741 gtk_widget_set_size_request(pw->layout_image->widget, PRINT_DLG_PREVIEW_WIDTH, PRINT_DLG_PREVIEW_HEIGHT);
742
743 gtk_box_pack_start(GTK_BOX(group), pw->layout_image->widget, TRUE, TRUE, 0);
744 gtk_widget_show(pw->layout_image->widget);
745
746 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
747 pw->button_back = pref_button_new(hbox, GTK_STOCK_GO_BACK, NULL, TRUE,
748 G_CALLBACK(print_layout_page_back_cb), pw);
749 pw->button_next = pref_button_new(hbox, GTK_STOCK_GO_FORWARD, NULL, TRUE,
750 G_CALLBACK(print_layout_page_next_cb), pw);
751 pw->page_label = pref_label_new(hbox, "");
752
753 button = pref_button_new(NULL, GTK_STOCK_ZOOM_OUT, NULL, TRUE,
754 G_CALLBACK(print_layout_zoom_out_cb), pw);
755 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
756 gtk_widget_show(button);
757 button = pref_button_new(NULL, GTK_STOCK_ZOOM_IN, NULL, TRUE,
758 G_CALLBACK(print_layout_zoom_in_cb), pw);
759 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
760 gtk_widget_show(button);
761 button = pref_button_new(NULL, GTK_STOCK_ZOOM_100, NULL, TRUE,
762 G_CALLBACK(print_layout_zoom_original_cb), pw);
763 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
764 gtk_widget_show(button);
765
766 print_window_layout_size(pw);
767
768 return vbox;
769 }
770
771 static void print_window_spin_set(GtkSpinButton *spin, gpointer block_data,
772 gdouble value, gdouble min, gdouble max,
773 gdouble step, gdouble page, gint digits)
774 {
775 if (block_data) g_signal_handlers_block_matched(G_OBJECT(spin), G_SIGNAL_MATCH_DATA,
776 0, 0, NULL, NULL, block_data);
777 gtk_spin_button_set_digits(spin, digits);
778 gtk_spin_button_set_increments(spin, step, page);
779 gtk_spin_button_set_range(spin, min, max);
780 gtk_spin_button_set_value(spin, value);
781
782 if (block_data) g_signal_handlers_unblock_matched(G_OBJECT(spin), G_SIGNAL_MATCH_DATA,
783 0, 0, NULL, NULL, block_data);
784 }
785
786 static void print_window_layout_sync_layout(PrintWindow *pw)
787 {
788 gtk_widget_set_sensitive(pw->image_scale_spin, (pw->layout == PRINT_LAYOUT_IMAGE));
789 gtk_widget_set_sensitive(pw->proof_group, (pw->layout == PRINT_LAYOUT_PROOF));
790 }
791
792 static void print_window_layout_sync_paper(PrintWindow *pw)
793 {
794 gdouble width, height;
795 gint digits;
796 gdouble step;
797 gdouble page;
798
799 gtk_widget_set_sensitive(pw->paper_width_spin, (pw->paper_size == 0));
800 gtk_widget_set_sensitive(pw->paper_height_spin, (pw->paper_size == 0));
801
802 width = print_paper_size_convert_units((gdouble)pw->paper_width, PAPER_UNIT_POINTS, pw->paper_units);
803 height = print_paper_size_convert_units((gdouble)pw->paper_height, PAPER_UNIT_POINTS, pw->paper_units);
804
805 switch (pw->paper_units)
806 {
807 case PAPER_UNIT_MM:
808 digits = 1;
809 step = 1.0;
810 page = 10.0;
811 break;
812 case PAPER_UNIT_CM:
813 digits = 2;
814 step = 0.5;
815 page = 1.0;
816 break;
817 case PAPER_UNIT_INCH:
818 digits = 3;
819 step = 0.25;
820 page = 1.0;
821 break;
822 case PAPER_UNIT_PICAS:
823 digits = 2;
824 step = 1.0;
825 page = 6.0;
826 break;
827 case PAPER_UNIT_POINTS:
828 default:
829 digits = 1;
830 step = 1.0;
831 page = 10.0;
832 break;
833 }
834
835 print_window_spin_set(GTK_SPIN_BUTTON(pw->paper_width_spin), pw, width,
836 print_paper_size_convert_units(PRINT_MIN_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
837 print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
838 step, page, digits);
839
840 print_window_spin_set(GTK_SPIN_BUTTON(pw->paper_height_spin), pw, height,
841 print_paper_size_convert_units(PRINT_MIN_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
842 print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
843 step, page, digits);
844
845 print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_left_spin), pw,
846 print_paper_size_convert_units(pw->margin_left, PAPER_UNIT_POINTS, pw->paper_units),
847 0.0,
848 print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
849 step, page, digits);
850
851 print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_right_spin), pw,
852 print_paper_size_convert_units(pw->margin_right, PAPER_UNIT_POINTS, pw->paper_units),
853 0.0,
854 print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
855 step, page, digits);
856
857 print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_top_spin), pw,
858 print_paper_size_convert_units(pw->margin_top, PAPER_UNIT_POINTS, pw->paper_units),
859 0.0,
860 print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
861 step, page, digits);
862
863 print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_bottom_spin), pw,
864 print_paper_size_convert_units(pw->margin_bottom, PAPER_UNIT_POINTS, pw->paper_units),
865 0.0,
866 print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
867 step, page, digits);
868
869 print_window_spin_set(GTK_SPIN_BUTTON(pw->proof_width_spin), pw,
870 print_paper_size_convert_units(pw->proof_width, PAPER_UNIT_POINTS, pw->paper_units),
871 print_paper_size_convert_units(PRINT_PROOF_MIN_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
872 print_paper_size_convert_units(PRINT_PROOF_MAX_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
873 step, page, digits);
874
875 print_window_spin_set(GTK_SPIN_BUTTON(pw->proof_height_spin), pw,
876 print_paper_size_convert_units(pw->proof_height, PAPER_UNIT_POINTS, pw->paper_units),
877 print_paper_size_convert_units(PRINT_PROOF_MIN_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
878 print_paper_size_convert_units(PRINT_PROOF_MAX_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
879 step, page, digits);
880 }
881
882 static void print_window_layout_set_size(PrintWindow *pw, gdouble width, gdouble height)
883 {
884 pw->paper_width = width;
885 pw->paper_height = height;
886
887 print_window_layout_sync_paper(pw);
888
889 print_window_layout_size(pw);
890 }
891
892 static void print_window_layout_set_orientation(PrintWindow *pw, PaperOrientation o)
893 {
894 if (pw->paper_orientation == o) return;
895
896 pw->paper_orientation = o;
897
898 print_window_layout_size(pw);
899 }
900
901 /*
902 *-----------------------------------------------------------------------------
903 * list printers
904 *-----------------------------------------------------------------------------
905 */
906
907 static GList *print_window_list_printers(void)
908 {
909 FILE *p;
910 GList *list = NULL;
911 gchar buffer[2048];
912
913 p = popen(PRINT_LPR_QUERY, "r");
914 if (!p) return NULL;
915
916 while (fgets(buffer, sizeof(buffer), p) != NULL)
917 {
918 gchar *ptr;
919 gchar *end;
920
921 ptr = buffer;
922 if (strncmp(ptr, "printer ", 8) != 0) continue;
923 if (strstr(ptr, "enabled") == NULL) continue;
924 ptr += 8;
925 end = ptr;
926 while (*end != '\0' && *end != '\n' && *end != ' ' && *end != '\t') end++;
927 *end = '\0';
928 list = g_list_append(list, g_strdup(ptr));
929 if (debug) printf("adding printer: %s\n", ptr);
930 }
931
932 pclose(p);
933
934 return list;
935 }
936
937 /*
938 *-----------------------------------------------------------------------------
939 * print ps
940 *-----------------------------------------------------------------------------
941 */
942
943 typedef struct _PipeError PipeError;
944 struct _PipeError {
945 struct sigaction old_action;
946 sig_atomic_t *error;
947 };
948
949 static sig_atomic_t pipe_handler_error = FALSE;
950 static PipeError *pipe_handler_data = NULL;
951
952 static void pipe_handler_sigpipe_cb(int fd)
953 {
954 pipe_handler_error = TRUE;
955 }
956
957 static PipeError *pipe_handler_new(void)
958 {
959 struct sigaction new_action;
960 PipeError *pe;
961
962 if (pipe_handler_data)
963 {
964 printf("warning SIGPIPE handler already in use\n");
965 return NULL;
966 }
967
968 pe = g_new0(PipeError, 1);
969
970 pipe_handler_error = FALSE;
971 pe->error = &pipe_handler_error;
972
973 new_action.sa_handler = pipe_handler_sigpipe_cb;
974 sigemptyset (&new_action.sa_mask);
975 new_action.sa_flags = 0;
976
977 /* setup our signal handler */
978 sigaction (SIGPIPE, &new_action, &pe->old_action);
979
980 pipe_handler_data = pe;
981 return pe;
982 }
983
984 static void pipe_handler_free(PipeError *pe)
985 {
986 if (!pe) return;
987 if (pe != pipe_handler_data) printf("warning SIGPIPE handler not closing same data\n");
988
989 /* restore the original signal handler */
990 sigaction (SIGPIPE, &pe->old_action, NULL);
991
992 pipe_handler_data = NULL;
993 g_free(pe);
994 }
995
996 static gint pipe_handler_check(PipeError *pe)
997 {
998 if (!pe) return FALSE;
999 return *pe->error;
1000 }
1001
1002 static FILE *print_job_ps_fd(PrintWindow *pw)
1003 {
1004 if (pw->job_file) return pw->job_file;
1005 if (pw->job_pipe) return pw->job_pipe;
1006 return NULL;
1007 }
1008
1009 static gint print_job_ps_init(PrintWindow *pw)
1010 {
1011 FILE *f;
1012 PipeError *pe;
1013 const gchar *cmd = NULL;
1014 const gchar *path = NULL;
1015 gchar *lc_pointer;
1016 gint ret;
1017
1018 if (pw->job_file != NULL || pw->job_pipe != NULL) return FALSE;
1019
1020 switch (pw->job_output)
1021 {
1022 case PRINT_OUTPUT_PS_LPR:
1023 cmd = PRINT_LPR_COMMAND;
1024 break;
1025 case PRINT_OUTPUT_PS_CUSTOM:
1026 cmd = pw->output_custom;
1027 break;
1028 case PRINT_OUTPUT_PS_FILE:
1029 path = pw->output_path;
1030 break;
1031 default:
1032 return FALSE;
1033 break;
1034 }
1035
1036 if (cmd)
1037 {
1038 pw->job_pipe = popen(cmd, "w");
1039
1040 if (!pw->job_pipe)
1041 {
1042 gchar *buf;
1043
1044 buf = g_strdup_printf(_("Unable to open pipe for writing.\n\"%s\""), cmd);
1045 print_job_throw_error(pw, buf);
1046 g_free(buf);
1047
1048 return FALSE;
1049 }
1050 }
1051 else if (path)
1052 {
1053 gchar *pathl;
1054
1055 if (isfile(path))
1056 {
1057 gchar *buf;
1058
1059 buf = g_strdup_printf(_("A file with name %s already exists."), path);
1060 print_job_throw_error(pw, buf);
1061 g_free(buf);
1062
1063 return FALSE;
1064 }
1065
1066 pathl = path_from_utf8(path);
1067 pw->job_file = fopen(pathl, "w");
1068 g_free(pathl);
1069
1070 if (!pw->job_file)
1071 {
1072 gchar *buf;
1073
1074 buf = g_strdup_printf(_("Failure writing to file %s"), path);
1075 print_job_throw_error(pw, buf);
1076 g_free(buf);
1077
1078 return FALSE;
1079 }
1080
1081 g_free(pw->job_path);
1082 pw->job_path = g_strdup(path);
1083 }
1084
1085 f = print_job_ps_fd(pw);
1086 if (!f) return FALSE;
1087
1088 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1089 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1090
1091 pe = pipe_handler_new();
1092
1093 /* comments, etc. */
1094 fprintf(f, "%%!PS-Adobe-3.0\n");
1095 fprintf(f, "%%%%Creator: GQview Version %s\n", VERSION);
1096 fprintf(f, "%%%%CreationDate: \n");
1097 fprintf(f, "%%%%LanguageLevel 2\n");
1098 fprintf(f, "%%%%DocumentMedia: \n");
1099 fprintf(f, "%%%%Orientation: %s\n",
1100 (pw->paper_orientation == PAPER_ORIENTATION_PORTRAIT) ? "Portrait" : "Landscape");
1101 fprintf(f, "%%%%BoundingBox: %f %f %f %f\n",
1102 0.0, 0.0, pw->paper_width, pw->paper_height);
1103 fprintf(f, "%%%%Pages: %d\n", print_layout_page_count(pw));
1104 fprintf(f, "%%%%PageOrder: Ascend\n");
1105 fprintf(f, "%%%%Title:\n");
1106
1107 /* setup page size, coordinates (do we really need this?) */
1108 #if 0
1109 fprintf(f, "<<\n");
1110 fprintf(f, "/PageSize [%f %f]\n", pw->layout_width, pw->layout_height);
1111 fprintf(f, "/ImagingBBox [%f %f %f %f]\n", /* l b r t */
1112 pw->margin_left, pw->margin_bottom,
1113 pw->layout_width - pw->margin_right, pw->layout_height - pw->margin_top);
1114 fprintf(f, "/Orientation %d\n",
1115 (pw->paper_orientation == PAPER_ORIENTATION_PORTRAIT) ? 0 : 1);
1116 fprintf(f, ">> setpagedevice\n");
1117 #endif
1118
1119 ret = !pipe_handler_check(pe);
1120 pipe_handler_free(pe);
1121
1122 if (lc_pointer)
1123 {
1124 setlocale(LC_NUMERIC, lc_pointer);
1125 g_free(lc_pointer);
1126 }
1127
1128 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1129
1130 return ret;
1131 }
1132
1133 static gint print_job_ps_page_new(PrintWindow *pw, gint page)
1134 {
1135 FILE *f;
1136 PipeError *pe;
1137 gchar *lc_pointer;
1138 gint ret;
1139
1140 f= print_job_ps_fd(pw);
1141 if (!f) return FALSE;
1142
1143 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1144 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1145
1146 pe = pipe_handler_new();
1147
1148 fprintf(f, "%%%% page %d\n", page + 1);
1149
1150 if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
1151 {
1152 fprintf(f, "/pagelevel save def\n");
1153 fprintf(f, "%d 0 translate 90 rotate\n", (gint)pw->layout_height);
1154 }
1155
1156 ret = !pipe_handler_check(pe);
1157 pipe_handler_free(pe);
1158
1159 if (lc_pointer)
1160 {
1161 setlocale(LC_NUMERIC, lc_pointer);
1162 g_free(lc_pointer);
1163 }
1164
1165 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1166
1167 return ret;
1168 }
1169
1170 static gint print_job_ps_page_done(PrintWindow *pw)
1171 {
1172 FILE *f;
1173 PipeError *pe;
1174 gchar *lc_pointer;
1175 gint ret;
1176
1177 f = print_job_ps_fd(pw);
1178 if (!f) return FALSE;
1179
1180 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1181 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1182
1183 pe = pipe_handler_new();
1184
1185 if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
1186 {
1187 fprintf(f, "pagelevel restore\n");
1188 }
1189
1190 fprintf(f, "showpage\n");
1191
1192 ret = !pipe_handler_check(pe);
1193 pipe_handler_free(pe);
1194
1195 if (lc_pointer)
1196 {
1197 setlocale(LC_NUMERIC, lc_pointer);
1198 g_free(lc_pointer);
1199 }
1200
1201 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1202
1203 return ret;
1204 }
1205
1206 static void print_job_ps_page_image_pixel(FILE *f, guchar *pix)
1207 {
1208 static gchar hex_digits[] = "0123456789abcdef";
1209 gchar text[8];
1210 gint i;
1211
1212 for (i = 0; i < 3; i++)
1213 {
1214 text[i*2] = hex_digits[pix[i] >> 4];
1215 text[i*2+1] = hex_digits[pix[i] & 0xf];
1216 }
1217 text[6] = '\0';
1218
1219 fprintf(f, text);
1220 }
1221 static gint print_job_ps_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
1222 gdouble x, gdouble y, gdouble w, gdouble h,
1223 gdouble offx, gdouble offy)
1224 {
1225 FILE *f;
1226 PipeError *pe;
1227 gchar *lc_pointer;
1228 gint sw, sh;
1229 gint bps;
1230 gint rowstride;
1231 guchar *pix;
1232 gint i, j;
1233 gint c;
1234 guchar *p;
1235 gint ret;
1236
1237 if (!pixbuf) return TRUE;
1238
1239 f = print_job_ps_fd(pw);
1240 if (!f) return FALSE;
1241
1242 sw = gdk_pixbuf_get_width(pixbuf);
1243 sh = gdk_pixbuf_get_height(pixbuf);
1244
1245 if (pw->max_dpi >= PRINT_PS_DPI_MIN &&
1246 sw / pw->max_dpi > w / 72.0)
1247 {
1248 pixbuf = gdk_pixbuf_scale_simple(pixbuf,
1249 (gint)(w / 72.0 * pw->max_dpi),
1250 (gint)(h / 72.0 * pw->max_dpi),
1251 PRINT_PS_MAX_INTERP);
1252 sw = gdk_pixbuf_get_width(pixbuf);
1253 sh = gdk_pixbuf_get_height(pixbuf);
1254 }
1255 else
1256 {
1257 g_object_ref(G_OBJECT(pixbuf));
1258 }
1259
1260 bps = (gdk_pixbuf_get_has_alpha(pixbuf)) ? 4 : 3;
1261 rowstride = gdk_pixbuf_get_rowstride(pixbuf);
1262 pix = gdk_pixbuf_get_pixels(pixbuf);
1263
1264 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1265 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1266
1267 pe = pipe_handler_new();
1268
1269 fprintf(f, "gsave\n");
1270 fprintf(f, "[%f 0 0 %f %f %f] concat\n", w, h, x, pw->layout_height - h - y);
1271 fprintf(f, "/buf %d string def\n", sw * 3);
1272 fprintf(f, "%d %d %d\n", sw, sh, 8);
1273 fprintf(f, "[%d 0 0 -%d 0 %d]\n", sw, sh, sh);
1274 fprintf(f, "{ currentfile buf readhexstring pop }\n");
1275 fprintf(f, "false %d colorimage\n", 3);
1276
1277 c = 0;
1278 for (j = 0; j < sh; j++)
1279 {
1280 p = pix + j * rowstride;
1281 for (i = 0; i < sw; i++)
1282 {
1283 print_job_ps_page_image_pixel(f, p);
1284 p+=bps;
1285 c++;
1286 if (c > 11)
1287 {
1288 fprintf(f, "\n");
1289 c = 0;
1290 }
1291 }
1292 }
1293 if (c > 0) fprintf(f, "\n");
1294 fprintf(f, "grestore\n");
1295
1296 ret = !pipe_handler_check(pe);
1297 pipe_handler_free(pe);
1298
1299 if (lc_pointer)
1300 {
1301 setlocale(LC_NUMERIC, lc_pointer);
1302 g_free(lc_pointer);
1303 }
1304
1305 g_object_unref(G_OBJECT(pixbuf));
1306
1307 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1308
1309 return ret;
1310 }
1311
1312 static const gchar *ps_text_to_hex_array(FILE *f, const gchar *text, gdouble x, gdouble y)
1313 {
1314 static gchar hex_digits[] = "0123456789abcdef";
1315 const gchar *p;
1316
1317 if (!text) return NULL;
1318
1319 fprintf(f, "%f %f moveto\n", x, y);
1320 fprintf(f, "<");
1321
1322 /* fixme: convert utf8 to ascii or proper locale string.. */
1323
1324 p = text;
1325 while (*p != '\0' && *p != '\n')
1326 {
1327 gchar text[3];
1328
1329 text[0] = hex_digits[*p >> 4];
1330 text[1] = hex_digits[*p & 0xf];
1331 text[2] = '\0';
1332
1333 fprintf(f, text);
1334
1335 p++;
1336 }
1337
1338 fprintf(f, ">\n");
1339 fprintf(f, "dup stringwidth pop 2 div neg 0 rmoveto show\n");
1340
1341 return p;
1342 }
1343
1344 static void ps_text_parse(FILE *f, const gchar *text, gdouble x, gdouble y, gdouble point_size)
1345 {
1346 const gchar *p;
1347
1348 if (!text) return;
1349
1350 fprintf(f, "newpath\n");
1351
1352 p = text;
1353 while (p && *p != '\0')
1354 {
1355 p = ps_text_to_hex_array(f, p, x, y);
1356 if (p && *p == '\n') p++;
1357 y -= point_size;
1358 }
1359
1360 fprintf(f, "closepath\n");
1361 }
1362
1363 static gint print_job_ps_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
1364 gdouble x, gdouble y, gdouble width,
1365 guint8 r, guint8 g, guint8 b)
1366 {
1367 FILE *f;
1368 PipeError *pe;
1369 gchar *lc_pointer;
1370 gint ret;
1371
1372 if (!text) return TRUE;
1373
1374 f = print_job_ps_fd(pw);
1375 if (!f) return FALSE;
1376
1377 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1378 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1379
1380 pe = pipe_handler_new();
1381
1382 fprintf(f, "/Sans findfont\n");
1383 fprintf(f, "%f scalefont\n", point_size);
1384 fprintf(f, "setfont\n");
1385
1386 fprintf(f, "%f %f %f setrgbcolor\n", (gdouble)r / 255.0, (gdouble)g / 255.0, (gdouble)b / 255.0);
1387 ps_text_parse(f, text, x, pw->layout_height - y - point_size, point_size);
1388
1389 ret = !pipe_handler_check(pe);
1390 pipe_handler_free(pe);
1391
1392 if (lc_pointer)
1393 {
1394 setlocale(LC_NUMERIC, lc_pointer);
1395 g_free(lc_pointer);
1396 }
1397
1398 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1399
1400 return ret;
1401 }
1402
1403 static gint print_job_ps_end(PrintWindow *pw)
1404 {
1405 FILE *f;
1406 PipeError *pe;
1407 gchar *lc_pointer;
1408 gint ret;
1409
1410 f = print_job_ps_fd(pw);
1411 if (!f) return FALSE;
1412
1413 lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
1414 setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
1415
1416 pe = pipe_handler_new();
1417
1418 fprintf(f, "%%%%EOF\n");
1419
1420 ret = !pipe_handler_check(pe);
1421 pipe_handler_free(pe);
1422
1423 if (lc_pointer)
1424 {
1425 setlocale(LC_NUMERIC, lc_pointer);
1426 g_free(lc_pointer);
1427 }
1428
1429 if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
1430
1431 return ret;
1432 }
1433
1434 /*
1435 *-----------------------------------------------------------------------------
1436 * print rgb
1437 *-----------------------------------------------------------------------------
1438 */
1439
1440 static gint print_job_rgb_page_new(PrintWindow *pw, gint page)
1441 {
1442 gint total;
1443
1444 if (pw->job_pixbuf)
1445 {
1446 pixbuf_set_rect_fill(pw->job_pixbuf, 0, 0,
1447 gdk_pixbuf_get_width(pw->job_pixbuf),
1448 gdk_pixbuf_get_height(pw->job_pixbuf),
1449 255, 255, 255, 255);
1450 }
1451
1452 g_free(pw->job_path);
1453 pw->job_path = NULL;
1454
1455 total = print_layout_page_count(pw);
1456
1457 if (!pw->output_path ||
1458 page < 0 || page >= total) return FALSE;
1459
1460 if (total > 1)
1461 {
1462 const gchar *ext;
1463 gchar *base;
1464
1465 ext = extension_from_path(pw->output_path);
1466
1467 if (ext)
1468 {
1469 base = g_strndup(pw->output_path, ext - pw->output_path);
1470 }
1471 else
1472 {
1473 base = g_strdup(pw->output_path);
1474 ext = "";
1475 }
1476 pw->job_path = g_strdup_printf("%s_%03d%s", base, page + 1, ext);
1477 g_free(base);
1478 }
1479 else
1480 {
1481 pw->job_path = g_strdup(pw->output_path);
1482 }
1483
1484 if (isfile(pw->job_path))
1485 {
1486 gchar *buf;
1487
1488 buf = g_strdup_printf(_("A file with name %s already exists."), pw->job_path);
1489 print_job_throw_error(pw, buf);
1490 g_free(buf);
1491
1492 g_free(pw->job_path);
1493 pw->job_path = NULL;
1494 }
1495
1496 return (pw->job_path != NULL);
1497 }
1498
1499 static gint print_job_rgb_page_done(PrintWindow *pw)
1500 {
1501 gchar *pathl;
1502 gint ret = FALSE;
1503
1504 if (!pw->job_pixbuf) return FALSE;
1505
1506 pathl = path_from_utf8(pw->job_path);
1507
1508 if (pw->output_format == PRINT_FILE_PNG)
1509 {
1510 ret = pixbuf_to_file_as_png(pw->job_pixbuf, pathl);
1511 }
1512 else
1513 {
1514 gint quality = 0;
1515
1516 switch (pw->output_format)
1517 {
1518 case PRINT_FILE_JPG_LOW:
1519 quality = 65;
1520 break;
1521 case PRINT_FILE_JPG_NORMAL:
1522 quality = 80;
1523 break;
1524 case PRINT_FILE_JPG_HIGH:
1525 quality = 95;
1526 break;
1527 default:
1528 break;
1529 }
1530
1531 if (quality > 0)
1532 {
1533 ret = pixbuf_to_file_as_jpg(pw->job_pixbuf, pathl, quality);
1534 }
1535 }
1536
1537 g_free(pathl);
1538
1539 if (!ret)
1540 {
1541 gchar *buf;
1542
1543 buf = g_strdup_printf(_("Failure writing to file %s"), pw->job_path);
1544 print_job_throw_error(pw, buf);
1545 g_free(buf);
1546 }
1547
1548 return ret;
1549 }
1550
1551 static gint print_job_rgb_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
1552 gdouble x, gdouble y, gdouble w, gdouble h,
1553 gdouble offx, gdouble offy)
1554 {
1555 gdouble sw, sh;
1556 gdouble dw, dh;
1557 gdouble rx, ry, rw, rh;
1558
1559 if (!pw->job_pixbuf) return FALSE;
1560 if (!pixbuf) return TRUE;
1561
1562 sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
1563 sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
1564
1565 dw = (gdouble)gdk_pixbuf_get_width(pw->job_pixbuf);
1566 dh = (gdouble)gdk_pixbuf_get_height(pw->job_pixbuf);
1567
1568 if (clip_region(x, y, w, h,
1569 0.0, 0.0, dw, dh,
1570 &rx, &ry, &rw, &rh))
1571 {
1572 gdk_pixbuf_composite(pixbuf, pw->job_pixbuf, rx, ry, rw, rh,
1573 x + offx, y + offy,
1574 w / sw, h / sh,
1575 (w / sw < 0.01 || h / sh < 0.01) ? GDK_INTERP_NEAREST : GDK_INTERP_BILINEAR, 255);
1576 }
1577
1578 return TRUE;
1579 }
1580
1581 static gdouble convert_pango_dpi(gdouble points)
1582 {
1583 static gdouble dpi = 0.0;
1584
1585 if (dpi == 0.0)
1586 {
1587 GtkSettings *settings;
1588 GObjectClass *klass;
1589
1590 settings = gtk_settings_get_default();
1591 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings));
1592 if (g_object_class_find_property(klass, "gtk-xft-dpi"))
1593 {
1594 int int_dpi;
1595 g_object_get(settings, "gtk-xft-dpi", &int_dpi, NULL);
1596 dpi = (gdouble)int_dpi / PANGO_SCALE;
1597 }
1598
1599 if (dpi < 25.0)
1600 {
1601 static gint warned = FALSE;
1602 gdouble fallback_dpi = 96.0;
1603
1604 if (!warned)
1605 {
1606 if (dpi == 0.0)
1607 {
1608 printf("pango dpi unknown, assuming %.0f\n", fallback_dpi);
1609 }
1610 else
1611 {
1612 printf("pango dpi reported as %.0f ignored, assuming %.0f\n", dpi, fallback_dpi);
1613 }
1614 warned = TRUE;
1615 }
1616
1617 dpi = fallback_dpi;
1618 }
1619 }
1620
1621 if (dpi == 0) return points;
1622 return points * 72.0 / dpi;
1623 }
1624
1625 static gint print_job_rgb_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
1626 gdouble x, gdouble y, gdouble width,
1627 guint8 r, guint8 g, guint8 b)
1628 {
1629 PangoLayout *layout;
1630 PangoFontDescription *desc;
1631 gint lw, lh;
1632
1633 if (!pw->job_pixbuf) return FALSE;
1634
1635 layout = gtk_widget_create_pango_layout(pw->dialog->dialog, NULL);
1636
1637 desc = pango_font_description_new();
1638 pango_font_description_set_size(desc, convert_pango_dpi(point_size) * PANGO_SCALE);
1639 pango_layout_set_font_description(layout, desc);
1640 pango_font_description_free(desc);
1641
1642 pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
1643 pango_layout_set_text(layout, text, -1);
1644
1645 pango_layout_get_pixel_size(layout, &lw, &lh);
1646 x = x - (gdouble)lw / 2.0;
1647
1648 pixbuf_draw_layout(pw->job_pixbuf, layout, pw->dialog->dialog, x, y, r, g, b, 255);
1649 g_object_unref(G_OBJECT(layout));
1650
1651 return TRUE;
1652 }
1653
1654 static gint print_job_rgb_init(PrintWindow *pw)
1655 {
1656 if (pw->job_pixbuf) g_object_unref(pw->job_pixbuf);
1657 pw->job_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1658 (gint)pw->layout_width, (gint)pw->layout_height);
1659
1660 return print_job_rgb_page_new(pw, pw->job_page);
1661 }
1662
1663 /*
1664 *-----------------------------------------------------------------------------
1665 * print preview
1666 *-----------------------------------------------------------------------------
1667 */
1668
1669 static gint print_job_preview_page_new(PrintWindow *pw, gint page)
1670 {
1671 GdkPixbuf *pixbuf;
1672 gint w, h;
1673 gint l, r, t, b;
1674
1675 pixbuf = pw->job_pixbuf;
1676 if (!pixbuf) return FALSE;
1677
1678 w = print_preview_unit(pw->layout_width);
1679 h = print_preview_unit(pw->layout_height);
1680 l = print_preview_unit(pw->margin_left);
1681 r = print_preview_unit(pw->margin_right);
1682 t = print_preview_unit(pw->margin_top);
1683 b = print_preview_unit(pw->margin_bottom);
1684
1685 /* fill background */
1686 pixbuf_set_rect_fill(pixbuf, 0, 0, w, h,
1687 255, 255, 255, 255);
1688
1689 /* draw cm or inch grid */
1690 if (TRUE)
1691 {
1692 gdouble i;
1693 gdouble grid;
1694 PaperUnits units;
1695
1696 units = (pw->paper_units == PAPER_UNIT_MM ||
1697 pw->paper_units == PAPER_UNIT_CM) ? PAPER_UNIT_CM : PAPER_UNIT_INCH;
1698
1699 grid = print_paper_size_convert_units(1.0, units, PAPER_UNIT_POINTS);
1700 for (i = grid ; i < pw->layout_width; i += grid)
1701 {
1702 pixbuf_draw_rect_fill(pixbuf, print_preview_unit(i), 0, 1, h, 0, 0, 0, 16);
1703 }
1704 for (i = grid; i < pw->layout_height; i += grid)
1705 {
1706 pixbuf_draw_rect_fill(pixbuf, 0, print_preview_unit(i), w, 1, 0, 0, 0, 16);
1707 }
1708 }
1709
1710 /* proof sheet grid */
1711 if (pw->layout == PRINT_LAYOUT_PROOF)
1712 {
1713 gdouble i, j;
1714 gdouble proof_w, proof_h;
1715 gint uw, uh;
1716
1717 print_proof_size(pw, &proof_w, &proof_h);
1718 uw = print_preview_unit(proof_w + PRINT_PREVIEW_SCALE - 0.1);
1719 uh = print_preview_unit(proof_h + PRINT_PREVIEW_SCALE - 0.1);
1720
1721 for (i = 0; i < pw->proof_columns; i++)
1722 for (j = 0; j < pw->proof_rows; j++)
1723 {
1724 gint x, y;
1725
1726 x = pw->margin_left + (pw->layout_width - pw->margin_left - pw->margin_right - (pw->proof_columns * proof_w)) / 2 + i * proof_w;
1727 y = pw->margin_top + j * proof_h;
1728
1729 pixbuf_draw_rect(pixbuf, print_preview_unit(x), print_preview_unit(y), uw, uh,
1730 255, 0, 0, 64, 1, 1, 1, 1);
1731 }
1732 }
1733
1734 /* non-printable region (margins) */
1735 pixbuf_draw_rect(pixbuf, 0, 0, w, h,
1736 0, 0, 0, 16,
1737 l, r, t, b);
1738
1739 /* margin lines */
1740 pixbuf_draw_rect(pixbuf, l, 0, w - l - r, h,
1741 0, 0, 255, 128,
1742 1, 1, 0, 0);
1743 pixbuf_draw_rect(pixbuf, 0, t, w, h - t - b,
1744 0, 0, 255, 128,
1745 0, 0, 1, 1);
1746
1747 /* border */
1748 pixbuf_draw_rect(pixbuf, 0, 0, w, h,
1749 0, 0, 0, 255,
1750 1, 1, 1, 1);
1751
1752 image_area_changed(pw->layout_image, 0, 0, w, h);
1753
1754 return TRUE;
1755 }
1756
1757 static gint print_job_preview_page_done(PrintWindow *pw)
1758 {
1759 return TRUE;
1760 }
1761
1762 static gint print_job_preview_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
1763 gdouble x, gdouble y, gdouble w, gdouble h,
1764 gdouble offx, gdouble offy)
1765 {
1766 gdouble sw, sh;
1767 gdouble dw, dh;
1768 gdouble rx, ry, rw, rh;
1769
1770 if (!pw->job_pixbuf) return FALSE;
1771 if (!pixbuf) return TRUE;
1772
1773 sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
1774 sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
1775
1776 dw = (gdouble)gdk_pixbuf_get_width(pw->job_pixbuf);
1777 dh = (gdouble)gdk_pixbuf_get_height(pw->job_pixbuf);
1778
1779 x = print_preview_unit(x);
1780 y = print_preview_unit(y);
1781 w = print_preview_unit(w);
1782 h = print_preview_unit(h);
1783 offx = print_preview_unit(offx);
1784 offy = print_preview_unit(offy);
1785
1786 if (clip_region(x, y, w, h,
1787 0.0, 0.0, dw, dh,
1788 &rx, &ry, &rw, &rh))
1789 {
1790 gdk_pixbuf_composite(pixbuf, pw->job_pixbuf, rx, ry, rw, rh,
1791 x + offx, y + offy,
1792 w / sw, h / sh,
1793 (w / sw < 0.01 || h / sh < 0.01) ? GDK_INTERP_NEAREST : GDK_INTERP_BILINEAR, 255);
1794
1795 image_area_changed(pw->layout_image, rx, ry, rw, rh);
1796 }
1797
1798 return TRUE;
1799 }
1800
1801 static gint print_job_preview_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
1802 gdouble x, gdouble y, gdouble width,
1803 guint8 r, guint8 g, guint8 b)
1804 {
1805 PangoLayout *layout;
1806 PangoFontDescription *desc;
1807 gint lw, lh;
1808 GdkPixbuf *pixbuf;
1809
1810 if (!pw->job_pixbuf) return FALSE;
1811
1812 layout = gtk_widget_create_pango_layout(pw->dialog->dialog, NULL);
1813
1814 desc = pango_font_description_new();
1815 pango_font_description_set_size(desc, convert_pango_dpi(point_size) * PANGO_SCALE);
1816 pango_layout_set_font_description(layout, desc);
1817 pango_font_description_free(desc);
1818
1819 pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
1820 pango_layout_set_text(layout, text, -1);
1821
1822 pango_layout_get_pixel_size(layout, &lw, &lh);
1823 x = x - (gdouble)lw / 2.0;
1824
1825 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, lw, lh);
1826 pixbuf_set_rect_fill(pixbuf, 0, 0, lw, lh, 0, 0, 0, 0);
1827 pixbuf_draw_layout(pixbuf, layout, pw->dialog->dialog, 0, 0, r, g, b, 255);
1828 g_object_unref(G_OBJECT(layout));
1829
1830 print_job_preview_page_image(pw, pixbuf, x, y, (gdouble)lw, (gdouble)lh, 0, 0);
1831 g_object_unref(pixbuf);
1832
1833 return TRUE;
1834 }
1835
1836 static gint print_job_preview_init(PrintWindow *pw)
1837 {
1838 if (pw->job_pixbuf) g_object_unref(pw->job_pixbuf);
1839 pw->job_pixbuf = pw->layout_image->pixbuf;
1840 g_object_ref(pw->job_pixbuf);
1841
1842 return print_job_preview_page_new(pw, pw->job_page);
1843 }
1844
1845
1846 /*
1847 *-----------------------------------------------------------------------------
1848 * wrappers
1849 *-----------------------------------------------------------------------------
1850 */
1851
1852 static gint print_job_page_new(PrintWindow *pw)
1853 {
1854 switch (pw->job_format)
1855 {
1856 case RENDER_FORMAT_RGB:
1857 return print_job_rgb_page_new(pw, pw->job_page);
1858 case RENDER_FORMAT_PS:
1859 return print_job_ps_page_new(pw, pw->job_page);
1860 case RENDER_FORMAT_PREVIEW:
1861 return print_job_preview_page_new(pw, pw->job_page);
1862 }
1863
1864 return FALSE;
1865 }
1866
1867 static gint print_job_page_done(PrintWindow *pw)
1868 {
1869 switch (pw->job_format)
1870 {
1871 case RENDER_FORMAT_RGB:
1872 return print_job_rgb_page_done(pw);
1873 case RENDER_FORMAT_PS:
1874 return print_job_ps_page_done(pw);
1875 case RENDER_FORMAT_PREVIEW:
1876 return print_job_preview_page_done(pw);
1877 }
1878
1879 return FALSE;
1880 }
1881
1882 static gint print_job_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
1883 gdouble x, gdouble y, gdouble w, gdouble h,
1884 gdouble offx, gdouble offy)
1885 {
1886 gint success = FALSE;
1887
1888 if (w <= 0.0 || h <= 0.0) return TRUE;
1889
1890 switch (pw->job_format)
1891 {
1892 case RENDER_FORMAT_RGB:
1893 success = print_job_rgb_page_image(pw, pixbuf, x, y, w, h, offx, offy);
1894 break;
1895 case RENDER_FORMAT_PS:
1896 success = print_job_ps_page_image(pw, pixbuf, x, y, w, h, offx, offy);
1897 break;
1898 case RENDER_FORMAT_PREVIEW:
1899 success = print_job_preview_page_image(pw, pixbuf, x, y, w, h, offx, offy);
1900 break;
1901 }
1902
1903 return success;
1904 }
1905
1906 static gint print_job_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
1907 gdouble x, gdouble y, gdouble width,
1908 guint8 r, guint8 g, guint8 b)
1909 {
1910 gint success = TRUE;
1911
1912 if (!text) return TRUE;
1913
1914 switch (pw->job_format)
1915 {
1916 case RENDER_FORMAT_RGB:
1917 success = print_job_rgb_page_text(pw, text, point_size, x, y, width, r, g, b);
1918 break;
1919 case RENDER_FORMAT_PS:
1920 success = print_job_ps_page_text(pw, text, point_size, x, y, width, r, g, b);
1921 break;
1922 case RENDER_FORMAT_PREVIEW:
1923 success = print_job_preview_page_text(pw, text, point_size, x, y, width, r, g, b);
1924 break;
1925 }
1926
1927 return success;
1928 }
1929
1930 /*
1931 *-----------------------------------------------------------------------------
1932 * print ?
1933 *-----------------------------------------------------------------------------
1934 */
1935
1936 static gint print_job_render_image(PrintWindow *pw);
1937 static gint print_job_render_proof(PrintWindow *pw);
1938
1939
1940 static void print_job_status(PrintWindow *pw)
1941 {
1942 gdouble value;
1943 gint page;
1944 gint total;
1945 gchar *buf;
1946
1947 if (!pw->job_progress) return;
1948
1949 page = pw->job_page;
1950 total = print_layout_page_count(pw);
1951
1952 if (pw->layout == PRINT_LAYOUT_PROOF && pw->proof_point)
1953 {
1954 GList *start;
1955
1956 start = g_list_first(pw->proof_point);
1957 value = (gdouble)g_list_position(start, pw->proof_point) / g_list_length(start);
1958 }
1959 else
1960 {
1961 value = (total > 0) ? (gdouble)page / total : 0.0;
1962 }
1963
1964 buf = g_strdup_printf(_("Page %d"), page + 1);
1965 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pw->job_progress), buf);
1966 g_free(buf);
1967
1968 if (pw->job_path && pw->job_progress_label)
1969 {
1970 gtk_label_set_text(GTK_LABEL(pw->job_progress_label), pw->job_path);
1971 }
1972
1973 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pw->job_progress), value);
1974 }
1975
1976 static void print_job_throw_error(PrintWindow *pw, const gchar *message)
1977 {
1978 GenericDialog *gd;
1979 GtkWidget *parent = NULL;
1980 GtkWidget *group;
1981 GtkWidget *label;
1982 gchar *buf;
1983
1984 if (GTK_WIDGET_VISIBLE(pw->dialog->dialog)) parent = pw->dialog->dialog;
1985
1986 gd = generic_dialog_new(_("Printing error"), "GQview", "print_warning",
1987 parent, TRUE, NULL, NULL);
1988 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, NULL, TRUE);
1989
1990 buf = g_strdup_printf(_("An error occured printing to %s."), print_output_name(pw->output));
1991 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_ERROR, _("Printing error"), buf);
1992 g_free(buf);
1993
1994 group = pref_group_new(gd->vbox, FALSE, _("Details"), GTK_ORIENTATION_VERTICAL);
1995 label = pref_label_new(group, message);
1996 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1997
1998 gtk_widget_show(gd->dialog);
1999 }
2000
2001 static void print_job_done(PrintWindow *pw)
2002 {
2003 print_job_close(pw, FALSE);
2004 }
2005
2006 static gint print_job_text_image(PrintWindow *pw, const gchar *path,
2007 gdouble x, gdouble y, gdouble width,
2008 gint sw, gint sh, gint proof)
2009 {
2010 GString *string;
2011 gint space = FALSE;
2012 gint newline = FALSE;
2013 gint ret;
2014
2015 if (pw->text_fields == 0) return TRUE;
2016
2017 string = g_string_new("");
2018 path = pw->job_loader->path;
2019
2020 if (pw->text_fields & TEXT_INFO_FILENAME)
2021 {
2022 g_string_append(string, filename_from_path(path));
2023 newline = TRUE;
2024 }
2025 if (pw->text_fields & TEXT_INFO_DIMENSIONS)
2026 {
2027 if (newline) g_string_append(string, "\n");
2028 g_string_append_printf(string, "%d x %d", (gint)sw, (gint)sh);
2029 newline = proof;
2030 space = !proof;
2031 }
2032 if (pw->text_fields & TEXT_INFO_FILEDATE)
2033 {
2034 if (newline) g_string_append(string, "\n");
2035 if (space) g_string_append(string, " - ");
2036 g_string_append(string, text_from_time(filetime(pw->job_loader->path)));
2037 newline = proof;
2038 space = !proof;
2039 }
2040 if (pw->text_fields & TEXT_INFO_FILESIZE)
2041 {
2042 gchar *size;
2043
2044 if (newline) g_string_append(string, "\n");
2045 if (space) g_string_append(string, " - ");
2046 size = text_from_size_abrev(filesize(pw->job_loader->path));
2047 g_string_append(string, size);
2048 g_free(size);
2049 }
2050
2051 ret = print_job_page_text(pw, string->str, pw->text_points, x, y, width,
2052 pw->text_r, pw->text_g, pw->text_b);
2053
2054 g_string_free(string, TRUE);
2055
2056 return ret;
2057 }
2058
2059 static void print_job_render_image_loader_done(ImageLoader *il, gpointer data)
2060 {
2061 PrintWindow *pw = data;
2062 GdkPixbuf *pixbuf;
2063 gint success = TRUE;
2064
2065 pixbuf = image_loader_get_pixbuf(il);
2066 if (pixbuf)
2067 {
2068 gdouble sw, sh;
2069 gdouble dw, dh;
2070 gdouble x, y, w, h;
2071 gdouble scale;
2072 gdouble offx, offy;
2073
2074 sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
2075 sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
2076
2077 dw = pw->layout_width - pw->margin_left - pw->margin_right;
2078 dh = pw->layout_height - pw->margin_top - pw->margin_bottom;
2079
2080 if (dw / sw < dh / sh)
2081 {
2082 w = dw;
2083 h = dw / sw * sh;
2084 scale = w / sw;
2085 }
2086 else
2087 {
2088 h = dh;
2089 w = dh / sh *sw;
2090 scale = h / sh;
2091 }
2092
2093 if (pw->image_scale >= 5)
2094 {
2095 w = w * (gdouble)pw->image_scale / 100.0;
2096 h = h * (gdouble)pw->image_scale / 100.0;
2097 }
2098
2099 x = pw->margin_left + (dw / 2) - (w / 2);
2100 y = pw->margin_top + (dh / 2) - (h / 2);
2101
2102 offx = offy = 0;
2103
2104 if (x < 0)
2105 {
2106 w += x;
2107 offx = x;
2108 x = 0;
2109 }
2110 if (x + w >= pw->layout_width) w = pw->layout_width - x;
2111
2112 if (y < 0)
2113 {
2114 h += y;
2115 offy = y;
2116 y = 0;
2117 }
2118 if (y + h >= pw->layout_height) h = pw->layout_height - y;
2119
2120 success = (success &&
2121 print_job_page_image(pw, pixbuf, x, y, w, h, offx, offy));
2122
2123 x = x + w / 2;
2124 y = y + h + PRINT_TEXT_PADDING;
2125
2126 success = (success &&
2127 print_job_text_image(pw, pw->job_loader->path, x, y, dw, sw, sh, FALSE));
2128 }
2129
2130 image_loader_free(pw->job_loader);
2131 pw->job_loader = NULL;
2132
2133 if (pw->job_format == RENDER_FORMAT_PREVIEW)
2134 {
2135 print_job_done(pw);
2136 return;
2137 }
2138
2139 success = (success && print_job_page_done(pw));
2140 if (!success)
2141 {
2142 print_job_close(pw, TRUE);
2143 return;
2144 }
2145
2146 pw->job_page++;
2147 print_job_status(pw);
2148
2149 if (print_job_render_image(pw))
2150 {
2151 if (!print_job_page_new(pw)) print_job_close(pw, TRUE);
2152 }
2153 else
2154 {
2155 print_job_done(pw);
2156 }
2157 }
2158
2159 static gint print_job_render_image(PrintWindow *pw)
2160 {
2161 gchar *path = NULL;
2162
2163 switch (pw->source)
2164 {
2165 case PRINT_SOURCE_SELECTION:
2166 path = g_list_nth_data(pw->source_selection, pw->job_page);
2167 break;
2168 case PRINT_SOURCE_ALL:
2169 path = g_list_nth_data(pw->source_list, pw->job_page);
2170 break;
2171 case PRINT_SOURCE_IMAGE:
2172 default:
2173 if (pw->job_page == 0) path = pw->source_path;
2174 break;
2175 }
2176
2177 image_loader_free(pw->job_loader);
2178 pw->job_loader = NULL;
2179
2180 if (!path) return FALSE;
2181
2182 pw->job_loader = image_loader_new(path);
2183 if (!image_loader_start(pw->job_loader, print_job_render_image_loader_done, pw))
2184 {
2185 image_loader_free(pw->job_loader);
2186 pw->job_loader= NULL;
2187 }
2188
2189 return TRUE;
2190 }
2191
2192 static void print_job_render_proof_loader_done(ImageLoader *il, gpointer data)
2193 {
2194 PrintWindow *pw = data;
2195 GdkPixbuf *pixbuf;
2196 gdouble x, y;
2197 gdouble w, h;
2198 gdouble proof_w, proof_h;
2199 gdouble icon_w, icon_h;
2200 gdouble scale;
2201 gint success = TRUE;
2202
2203 if (pw->proof_columns < 1 || pw->proof_rows < 1)
2204 {
2205 image_loader_free(pw->job_loader);
2206 pw->job_loader = NULL;
2207
2208 print_job_done(pw);
2209
2210 return;
2211 }
2212
2213 pixbuf = image_loader_get_pixbuf(il);
2214
2215 w = gdk_pixbuf_get_width(pixbuf);
2216 h = gdk_pixbuf_get_height(pixbuf);
2217
2218 if (pw->proof_width / w < pw->proof_height / h)
2219 {
2220 icon_w = pw->proof_width;
2221 icon_h = pw->proof_width / w * h;
2222 scale = icon_w / w;
2223 }
2224 else
2225 {
2226 icon_h = pw->proof_height;
2227 icon_w = pw->proof_height / h * w;
2228 scale = icon_h / h;
2229 }
2230
2231 y = pw->proof_position / pw->proof_columns;
2232 x = pw->proof_position - (y * pw->proof_columns);
2233
2234 print_proof_size(pw, &proof_w, &proof_h);
2235
2236 x *= proof_w;
2237 y *= proof_h;
2238 x += pw->margin_left + (pw->layout_width - pw->margin_left - pw->margin_right - (pw->proof_columns * proof_w)) / 2 + (proof_w - icon_w) / 2;
2239 y += pw->margin_top + PRINT_PROOF_MARGIN + (pw->proof_height - icon_h) / 2;
2240
2241 success = (success &&
2242 print_job_page_image(pw, pixbuf, x, y, icon_w, icon_h, 0, 0));
2243
2244 x = x + icon_w / 2;
2245 y = y + icon_h + (pw->proof_height - icon_h) / 2 + PRINT_TEXT_PADDING;
2246
2247 success = (success &&
2248 print_job_text_image(pw, pw->job_loader->path, x, y, icon_w + PRINT_PROOF_MARGIN * 2, w, h, TRUE));
2249
2250 if (!success)
2251 {
2252 print_job_close(pw, TRUE);
2253 return;
2254 }
2255
2256 if (pw->proof_point) pw->proof_point = pw->proof_point->next;
2257
2258 pw->proof_position++;
2259 if (pw->proof_position >= pw->proof_columns * pw->proof_rows)
2260 {
2261 if (pw->job_format == RENDER_FORMAT_PREVIEW)
2262 {
2263 print_job_done(pw);
2264 return;
2265 }
2266
2267 if (!print_job_page_done(pw))
2268 {
2269 print_job_close(pw, TRUE);
2270 return;
2271 }
2272
2273 pw->proof_position = 0;
2274 pw->job_page++;
2275 if (print_job_render_proof(pw))
2276 {
2277 if (!print_job_page_new(pw))
2278 {
2279 print_job_close(pw, TRUE);
2280 return;
2281 }
2282 print_job_status(pw);
2283 }
2284 else
2285 {
2286 print_job_done(pw);
2287 }
2288 }
2289 else
2290 {
2291 if (print_job_render_proof(pw))
2292 {
2293 print_job_status(pw);
2294 }
2295 else
2296 {
2297 if (print_job_page_done(pw))
2298 {
2299 print_job_done(pw);
2300 }
2301 else
2302 {
2303 print_job_close(pw, TRUE);
2304 }
2305 }
2306 }
2307 }
2308
2309 static gint print_job_render_proof(PrintWindow *pw)
2310 {
2311 gchar *path = NULL;
2312
2313 if (pw->proof_columns < 1 || pw->proof_rows < 1) return FALSE;
2314
2315 if (!pw->proof_point && pw->proof_position == 0 && pw->source == PRINT_SOURCE_IMAGE)
2316 {
2317 path = pw->source_path;
2318 }
2319 else if (pw->proof_point &&
2320 pw->proof_position < pw->proof_columns * pw->proof_rows)
2321 {
2322 path = pw->proof_point->data;
2323 }
2324
2325 if (!path) return FALSE;
2326
2327 image_loader_free(pw->job_loader);
2328 pw->job_loader = image_loader_new(path);
2329 if (!image_loader_start(pw->job_loader, print_job_render_proof_loader_done, pw))
2330 {
2331 image_loader_free(pw->job_loader);
2332 pw->job_loader = NULL;
2333 }
2334
2335 return TRUE;
2336 }
2337
2338 static void print_job_render(PrintWindow *pw)
2339 {
2340 gdouble proof_w, proof_h;
2341 gint finished;
2342
2343 pw->proof_position = 0;
2344
2345 switch (pw->source)
2346 {
2347 case PRINT_SOURCE_SELECTION:
2348 pw->proof_point = pw->source_selection;
2349 break;
2350 case PRINT_SOURCE_ALL:
2351 pw->proof_point = pw->source_list;
2352 break;
2353 case PRINT_SOURCE_IMAGE:
2354 default:
2355 pw->proof_point = NULL;
2356 break;
2357 }
2358
2359 print_proof_size(pw, &proof_w, &proof_h);
2360 pw->proof_columns = (pw->layout_width - pw->margin_left - pw->margin_right) / proof_w;
2361 pw->proof_rows = (pw->layout_height - pw->margin_top - pw->margin_bottom) / proof_h;
2362
2363 if (pw->job_format == RENDER_FORMAT_PREVIEW)
2364 {
2365 gint total;
2366
2367 total = print_layout_page_count(pw);
2368 if (pw->job_page < 0 || pw->job_page >= total)
2369 {
2370 print_job_done(pw);
2371 return;
2372 }
2373
2374 if (pw->proof_point && pw->job_page > 0)
2375 {
2376 pw->proof_point = g_list_nth(pw->proof_point, pw->job_page * pw->proof_columns * pw->proof_rows);
2377 }
2378 }
2379
2380 if (!print_job_page_new(pw))
2381 {
2382 print_job_close(pw, TRUE);
2383 return;
2384 }
2385
2386 if (pw->layout == PRINT_LAYOUT_IMAGE)
2387 {
2388 finished = !print_job_render_image(pw);
2389 }
2390 else
2391 {
2392 finished = !print_job_render_proof(pw);
2393 }
2394
2395 if (finished) print_job_done(pw);
2396 }
2397
2398 static gint print_job_init(PrintWindow *pw)
2399 {
2400 gint success = FALSE;
2401
2402 pw->job_page = 0;
2403
2404 switch (pw->job_format)
2405 {
2406 case RENDER_FORMAT_RGB:
2407 success = print_job_rgb_init(pw);
2408 break;
2409 case RENDER_FORMAT_PS:
2410 success = print_job_ps_init(pw);
2411 break;
2412 case RENDER_FORMAT_PREVIEW:
2413 pw->job_page = pw->proof_page;
2414 success = print_job_preview_init(pw);
2415 break;
2416 }
2417
2418 return success;
2419 }
2420
2421 static gint print_job_finish(PrintWindow *pw)
2422 {
2423 gint success = FALSE;
2424
2425 switch (pw->job_format)
2426 {
2427 case RENDER_FORMAT_RGB:
2428 success = TRUE;
2429 break;
2430 case RENDER_FORMAT_PS:
2431 print_job_ps_end(pw);
2432 break;
2433 case RENDER_FORMAT_PREVIEW:
2434 success = TRUE;
2435 break;
2436 }
2437
2438 return success;
2439 }
2440
2441 static void print_job_close_file(PrintWindow *pw)
2442 {
2443 if (pw->job_file)
2444 {
2445 fclose(pw->job_file);
2446 pw->job_file = NULL;
2447 }
2448
2449 if (pw->job_pipe)
2450 {
2451 PipeError *pe;
2452
2453 pe = pipe_handler_new();
2454 pclose(pw->job_pipe);
2455 pipe_handler_free(pe);
2456
2457 pw->job_pipe = NULL;
2458 }
2459 }
2460
2461 static gboolean print_job_close_finish_cb(gpointer data)
2462 {
2463 PrintWindow *pw = data;
2464
2465 print_window_close(pw);
2466 return FALSE;
2467 }
2468
2469 static void print_job_close(PrintWindow *pw, gint error)
2470 {
2471 if (!error) print_job_finish(pw);
2472
2473 print_job_close_file(pw);
2474 g_free(pw->job_path);
2475 pw->job_path = NULL;
2476
2477 if (pw->job_dialog)
2478 {
2479 generic_dialog_close(pw->job_dialog);
2480 pw->job_dialog = NULL;
2481 pw->job_progress = NULL;
2482 }
2483
2484 image_loader_free(pw->job_loader);
2485 pw->job_loader = NULL;
2486
2487 if (pw->job_pixbuf)
2488 {
2489 g_object_unref(pw->job_pixbuf);
2490 pw->job_pixbuf = NULL;
2491 }
2492
2493 if (pw->dialog && !GTK_WIDGET_VISIBLE(pw->dialog->dialog))
2494 {
2495 g_idle_add_full(G_PRIORITY_HIGH_IDLE, print_job_close_finish_cb, pw, NULL);
2496 }
2497 }
2498
2499 static void print_job_cancel_cb(GenericDialog *gd, gpointer data)
2500 {
2501 PrintWindow *pw = data;
2502
2503 print_job_close(pw, FALSE);
2504 }
2505
2506 static void print_pref_store(PrintWindow *pw)
2507 {
2508
2509 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_SAVE, pw->save_settings);
2510
2511 if (!pw->save_settings) return;
2512
2513 /* only store values that are actually used in this print job, hence the if()s */
2514
2515 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_OUTPUT, pw->output);
2516
2517 if (pw->output == PRINT_OUTPUT_RGB_FILE)
2518 {
2519 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_FORMAT, pw->output_format);
2520 }
2521
2522 if (pw->job_format == RENDER_FORMAT_PS)
2523 {
2524 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_DPI, pw->max_dpi);
2525 }
2526
2527 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_UNITS, pw->paper_units);
2528 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_SIZE, pw->paper_size);
2529 pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_ORIENTATION, pw->paper_orientation);
2530
2531 if (pw->paper_size == 0)
2532 {
2533 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_CUSTOM_WIDTH, pw->paper_width);
2534 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_CUSTOM_HEIGHT, pw->paper_height);
2535 }
2536
2537 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_LEFT, pw->margin_left);
2538 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_RIGHT, pw->margin_right);
2539 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_TOP, pw->margin_top);
2540 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_BOTTOM, pw->margin_bottom);
2541
2542 if (pw->layout == PRINT_LAYOUT_PROOF)
2543 {
2544 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_PROOF_WIDTH, pw->proof_width);
2545 pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_PROOF_HEIGHT, pw->proof_height);
2546 }
2547
2548 if (pw->output == PRINT_OUTPUT_PS_CUSTOM)
2549 {
2550 pref_list_string_set(PRINT_PREF_GROUP, PRINT_PREF_PRINTERC, pw->output_custom);
2551 }
2552
2553 if (pw->output == PRINT_OUTPUT_RGB_FILE ||
2554 pw->output == PRINT_OUTPUT_PS_FILE)
2555 {
2556 tab_completion_append_to_history(pw->path_entry, pw->output_path);
2557 }
2558 }
2559
2560 static gint print_job_start(PrintWindow *pw, RenderFormat format, PrintOutput output)
2561 {
2562 GtkWidget *hbox;
2563 GtkWidget *spinner;
2564 gchar *msg;
2565
2566 if (pw->job_dialog) return FALSE;
2567
2568 pw->job_format = format;
2569 pw->job_output = output;
2570
2571 if (!print_job_init(pw))
2572 {
2573 print_job_close(pw, TRUE);
2574 return FALSE;
2575 }
2576
2577 if (format == RENDER_FORMAT_PREVIEW)
2578 {
2579 print_job_render(pw);
2580 return TRUE;
2581 }
2582
2583 print_pref_store(pw);
2584
2585 gtk_widget_hide(pw->dialog->dialog);
2586
2587 pw->job_dialog = file_util_gen_dlg(_("Print - GQview"), "gqview", "print_job_dialog",
2588 (GtkWidget *)gtk_window_get_transient_for(GTK_WINDOW(pw->dialog->dialog)), FALSE,
2589 print_job_cancel_cb, pw);
2590
2591 msg = g_strdup_printf(_("Printing %d pages to %s."), print_layout_page_count(pw), print_output_name(pw->output));
2592 generic_dialog_add_message(pw->job_dialog, NULL, msg, NULL);
2593 g_free(msg);
2594
2595 if (pw->job_output == PRINT_OUTPUT_PS_FILE ||
2596 pw->job_output == PRINT_OUTPUT_RGB_FILE)
2597 {
2598 hbox = pref_box_new(pw->job_dialog->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2599 pref_label_new(hbox, _("Filename:"));
2600
2601 pw->job_progress_label = pref_label_new(hbox, "");
2602 }
2603 else
2604 {
2605 pw->job_progress_label = NULL;
2606 }
2607
2608 pref_spacer(pw->job_dialog->vbox, PREF_PAD_SPACE);
2609
2610 hbox = pref_box_new(pw->job_dialog->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2611
2612 pw->job_progress = gtk_progress_bar_new();
2613 gtk_box_pack_start(GTK_BOX(hbox), pw->job_progress, TRUE, TRUE, 0);
2614 gtk_widget_show(pw->job_progress);
2615
2616 spinner = spinner_new(NULL, SPINNER_SPEED);
2617 gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0);
2618 gtk_widget_show(spinner);
2619
2620 gtk_widget_show(pw->job_dialog->dialog);
2621
2622 print_job_render(pw);
2623 print_job_status(pw);
2624
2625 return TRUE;
2626 }
2627
2628 static void print_window_print_start(PrintWindow *pw)
2629 {
2630 RenderFormat format;
2631
2632 switch(pw->output)
2633 {
2634 case PRINT_OUTPUT_RGB_FILE:
2635 format = RENDER_FORMAT_RGB;
2636 break;
2637 case PRINT_OUTPUT_PS_FILE:
2638 case PRINT_OUTPUT_PS_CUSTOM:
2639 case PRINT_OUTPUT_PS_LPR:
2640 default:
2641 format = RENDER_FORMAT_PS;
2642 break;
2643 }
2644
2645 print_job_start(pw, format, pw->output);
2646 }
2647
2648
2649 /*
2650 *-----------------------------------------------------------------------------
2651 * combo box util
2652 *-----------------------------------------------------------------------------
2653 */
2654
2655 static GtkWidget *print_combo_menu(const gchar *text[], gint count, gint preferred,
2656 GCallback func, gpointer data)
2657 {
2658 GtkWidget *combo;
2659 gint i;
2660
2661 combo = gtk_combo_box_new_text();
2662
2663 for (i = 0 ; i < count; i++)
2664 {
2665 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(text[i]));
2666 }
2667
2668 if (preferred >= 0 && preferred < count)
2669 {
2670 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), preferred);
2671 }
2672
2673 if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
2674
2675 return combo;
2676 }
2677
2678
2679 /*
2680 *-----------------------------------------------------------------------------
2681 * paper selection
2682 *-----------------------------------------------------------------------------
2683 */
2684
2685 static GtkWidget *print_paper_menu(GtkWidget *table, gint column, gint row,
2686 gint preferred, GCallback func, gpointer data)
2687 {
2688 GtkWidget *combo;
2689 gint i;
2690
2691 pref_table_label(table, column, row, (_("Format:")), 1.0);
2692
2693 combo = gtk_combo_box_new_text();
2694
2695 i = 0;
2696 while (print_paper_sizes[i].description)
2697 {
2698 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(print_paper_sizes[i].description));
2699 i++;
2700 }
2701
2702 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), preferred);
2703 if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
2704
2705 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2706 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2707 gtk_widget_show(combo);
2708
2709 return combo;
2710 }
2711
2712 static void print_paper_select_cb(GtkWidget *combo, gpointer data)
2713 {
2714 PrintWindow *pw = data;
2715 PaperSize *ps;
2716 gint n;
2717
2718 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
2719 ps = print_paper_size_nth(n);
2720
2721 if (!ps) return;
2722
2723 pw->paper_size = n;
2724
2725 if (pw->paper_size == 0)
2726 {
2727 print_window_layout_sync_paper(pw);
2728 return;
2729 }
2730
2731 if (ps->orientation == PAPER_ORIENTATION_PORTRAIT)
2732 {
2733 print_window_layout_set_size(pw, ps->width, ps->height);
2734 }
2735 else
2736 {
2737 print_window_layout_set_size(pw, ps->height, ps->width);
2738 }
2739 }
2740
2741 static void print_paper_size_cb(GtkWidget *spin, gpointer data)
2742 {
2743 PrintWindow *pw = data;
2744 gdouble value;
2745
2746 value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
2747 pw->paper_units, PAPER_UNIT_POINTS);
2748
2749 if (spin == pw->paper_width_spin)
2750 {
2751 pw->paper_width = value;
2752 }
2753 else
2754 {
2755 pw->paper_height = value;
2756 }
2757
2758 print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
2759 }
2760
2761 static GtkWidget *print_paper_units_menu(GtkWidget *table, gint column, gint row,
2762 PaperUnits units, GCallback func, gpointer data)
2763 {
2764 GtkWidget *combo;
2765
2766 pref_table_label(table, column, row, (_("Units:")), 1.0);
2767
2768 combo = print_combo_menu(print_paper_units, PAPER_UNIT_COUNT, units, func, data);
2769
2770 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2771 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2772 gtk_widget_show(combo);
2773
2774 return combo;
2775 }
2776
2777 static void print_paper_units_set(PrintWindow *pw, PaperUnits units)
2778 {
2779 PaperUnits old_units;
2780
2781 if (units < 0 || units >= PAPER_UNIT_COUNT) return;
2782
2783 old_units = pw->paper_units;
2784 pw->paper_units = units;
2785 print_window_layout_sync_paper(pw);
2786
2787 if ((units == PAPER_UNIT_MM || units == PAPER_UNIT_CM) !=
2788 (old_units == PAPER_UNIT_MM || old_units == PAPER_UNIT_CM))
2789 {
2790 print_window_layout_render(pw);
2791 }
2792 }
2793
2794 static void print_paper_units_cb(GtkWidget *combo, gpointer data)
2795 {
2796 PrintWindow *pw = data;
2797 PaperUnits units;
2798
2799 units = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
2800
2801 print_paper_units_set(pw, units);
2802 }
2803
2804 static GtkWidget *print_paper_orientation_menu(GtkWidget *table, gint column, gint row,
2805 PaperOrientation preferred,
2806 GCallback func, gpointer data)
2807 {
2808 GtkWidget *combo;
2809
2810 pref_table_label(table, column, row, (_("Orientation:")), 1.0);
2811
2812 combo = print_combo_menu(print_paper_orientation, PAPER_ORIENTATION_COUNT, preferred, func, data);
2813
2814 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2815 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2816 gtk_widget_show(combo);
2817
2818 return combo;
2819 }
2820
2821 static void print_paper_orientation_cb(GtkWidget *combo, gpointer data)
2822 {
2823 PrintWindow *pw = data;
2824 PaperOrientation o;
2825
2826 o = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
2827
2828 print_window_layout_set_orientation(pw, o);
2829 }
2830
2831 static void print_paper_margin_cb(GtkWidget *spin, gpointer data)
2832 {
2833 PrintWindow *pw = data;
2834 gdouble value;
2835
2836 value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
2837 pw->paper_units, PAPER_UNIT_POINTS);
2838
2839 if (spin == pw->margin_left_spin)
2840 {
2841 pw->margin_left = CLAMP(value, 0.0, pw->paper_width);
2842 }
2843 else if (spin == pw->margin_right_spin)
2844 {
2845 pw->margin_right = CLAMP(value, 0.0, pw->paper_width);
2846 }
2847 else if (spin == pw->margin_top_spin)
2848 {
2849 pw->margin_top = CLAMP(value, 0.0, pw->paper_height);
2850 }
2851 else if (spin == pw->margin_bottom_spin)
2852 {
2853 pw->margin_bottom = CLAMP(value, 0.0, pw->paper_height);
2854 }
2855
2856 print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
2857 }
2858
2859 static GtkWidget *print_misc_menu(GtkWidget *parent_box, gint preferred,
2860 const gchar *title, const gchar *key,
2861 gint count, const gchar **text,
2862 GCallback func, gpointer data)
2863 {
2864 GtkWidget *box;
2865 GtkWidget *button = NULL;
2866 gint i;
2867
2868 box = pref_group_new(parent_box, FALSE, title, GTK_ORIENTATION_VERTICAL);
2869
2870 for (i = 0; i < count; i++)
2871 {
2872 button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(button), _(text[i]));
2873 if (i == preferred)
2874 {
2875 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
2876 }
2877 g_object_set_data(G_OBJECT(button), key, GINT_TO_POINTER(i));
2878 if (func) g_signal_connect(G_OBJECT(button), "clicked", func, data);
2879 gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
2880 gtk_widget_show(button);
2881 }
2882
2883 return box;
2884 }
2885
2886 static void print_source_select_cb(GtkWidget *widget, gpointer data)
2887 {
2888 PrintWindow *pw = data;
2889
2890 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
2891
2892 pw->source = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "print_source"));
2893 print_window_layout_size(pw);
2894 }
2895
2896 static void print_layout_select_cb(GtkWidget *widget, gpointer data)
2897 {
2898 PrintWindow *pw = data;
2899
2900 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
2901
2902 pw->layout = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "print_layout"));
2903
2904 print_window_layout_sync_layout(pw);
2905 print_window_layout_size(pw);
2906 }
2907
2908 static void print_image_scale_cb(GtkWidget *spin, gpointer data)
2909 {
2910 PrintWindow *pw = data;
2911
2912 pw->image_scale = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
2913
2914 print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
2915 }
2916
2917 static void print_proof_size_cb(GtkWidget *spin, gpointer data)
2918 {
2919 PrintWindow *pw = data;
2920 gdouble value;
2921
2922 value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
2923 pw->paper_units, PAPER_UNIT_POINTS);
2924
2925 if (spin == pw->proof_width_spin)
2926 {
2927 pw->proof_width = value;
2928 }
2929 else
2930 {
2931 pw->proof_height = value;
2932 }
2933
2934 print_window_layout_render(pw);
2935 }
2936
2937 static GtkWidget *print_output_menu(GtkWidget *table, gint column, gint row,
2938 PrintOutput preferred, GCallback func, gpointer data)
2939 {
2940 GtkWidget *combo;
2941
2942 pref_table_label(table, column, row, (_("Destination:")), 1.0);
2943
2944 combo = print_combo_menu(print_output_text, PRINT_OUTPUT_COUNT, preferred, func, data);
2945
2946 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2947 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2948 gtk_widget_show(combo);
2949
2950 return combo;
2951 }
2952
2953 static void print_custom_entry_set(PrintWindow *pw, GtkWidget *combo)
2954 {
2955 GtkListStore *store;
2956 const gchar *text;
2957 GList *list;
2958 GList *work;
2959
2960 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
2961 gtk_list_store_clear(store);
2962
2963 list = print_window_list_printers();
2964 work = list;
2965 while (work)
2966 {
2967 gchar *name;
2968 gchar *buf;
2969
2970 name = work->data;
2971 work = work->next;
2972
2973 buf = g_strdup_printf(PRINT_LPR_CUSTOM, name);
2974 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), buf);
2975 g_free(buf);
2976 }
2977 path_list_free(list);
2978
2979 if (pref_list_string_get(PRINT_PREF_GROUP, PRINT_PREF_PRINTERC, &text))
2980 {
2981 gtk_entry_set_text(GTK_ENTRY(pw->custom_entry), text);
2982 }
2983 else
2984 {
2985 text = gtk_entry_get_text(GTK_ENTRY(pw->custom_entry));
2986 if (!text || strlen(text) == 0)
2987 {
2988 gchar *buf;
2989
2990 buf = g_strdup_printf(PRINT_LPR_CUSTOM, _("<printer name>"));
2991 gtk_entry_set_text(GTK_ENTRY(pw->custom_entry), buf);
2992 g_free(buf);
2993 }
2994 }
2995 }
2996
2997 static void print_output_set(PrintWindow *pw, PrintOutput output)
2998 {
2999 gint use_file = FALSE;
3000 gint use_custom = FALSE;
3001 gint use_format = FALSE;
3002
3003 pw->output = output;
3004
3005 switch (pw->output)
3006 {
3007 case PRINT_OUTPUT_RGB_FILE:
3008 use_file = TRUE;
3009 use_format = TRUE;
3010 break;
3011 case PRINT_OUTPUT_PS_FILE:
3012 use_file = TRUE;
3013 break;
3014 case PRINT_OUTPUT_PS_CUSTOM:
3015 use_custom = TRUE;
3016 break;
3017 case PRINT_OUTPUT_PS_LPR:
3018 default:
3019 break;
3020 }
3021
3022 gtk_widget_set_sensitive(gtk_widget_get_parent(pw->path_entry), use_file);
3023 gtk_widget_set_sensitive(gtk_widget_get_parent(pw->custom_entry), use_custom);
3024 gtk_widget_set_sensitive(pw->path_format_menu, use_format);
3025 gtk_widget_set_sensitive(pw->max_dpi_menu, !use_format);
3026 }
3027
3028 static void print_output_cb(GtkWidget *combo, gpointer data)
3029 {
3030 PrintWindow *pw = data;
3031 PrintOutput output;
3032
3033 output = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
3034
3035 print_output_set(pw, output);
3036 }
3037
3038 static GtkWidget *print_output_format_menu(GtkWidget * table, gint column, gint row,
3039 PrintFileFormat preferred, GCallback func, gpointer data)
3040 {
3041 GtkWidget *combo;
3042
3043 combo = print_combo_menu(print_file_format_text, PRINT_FILE_COUNT, preferred, func, data);
3044
3045 gtk_table_attach(GTK_TABLE(table), combo, column, column + 1, row, row + 1,
3046 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
3047 gtk_widget_show(combo);
3048
3049 return combo;
3050 }
3051
3052 static void print_output_format_cb(GtkWidget *combo, gpointer data)
3053 {
3054 PrintWindow *pw = data;
3055
3056 pw->output_format = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
3057 }
3058
3059 static GtkWidget *print_output_dpi_menu(GtkWidget * table, gint column, gint row,
3060 gdouble dpi, GCallback func, gpointer data)
3061 {
3062 static gint dpilist[] = { 150, 300, 600, 1200, 0, -1};
3063 GtkWidget *combo;
3064 GtkListStore *store;
3065 GtkCellRenderer *renderer;
3066 gint current = 1;
3067 gint i;
3068
3069 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
3070
3071 i = 0;
3072 while (dpilist[i] != -1)
3073 {
3074 GtkTreeIter iter;
3075 gchar *text;
3076
3077 if (dpilist[i] == 0)
3078 {
3079 text = g_strdup(_("Unlimited"));
3080 }
3081 else
3082 {
3083 text = g_strdup_printf("%d", dpilist[i]);
3084 }
3085
3086 gtk_list_store_append(store, &iter);
3087 gtk_list_store_set(store, &iter, 0, text, 1, dpilist[i], -1);
3088 g_free(text);
3089
3090 if (dpi == (gdouble)dpilist[i]) current = i;
3091
3092 i++;
3093 }
3094
3095 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
3096 g_object_unref(store);
3097
3098 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3099 if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
3100
3101 renderer = gtk_cell_renderer_text_new();
3102 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
3103 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", 0, NULL);
3104
3105 gtk_table_attach(GTK_TABLE(table), combo, column, column + 1, row, row + 1,
3106 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
3107 gtk_widget_show(combo);
3108
3109 return combo;
3110 }
3111
3112 static void print_output_dpi_cb(GtkWidget *combo, gpointer data)
3113 {
3114 PrintWindow *pw = data;
3115 GtkTreeModel *store;
3116 GtkTreeIter iter;
3117 gint n = -1;
3118
3119 store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
3120 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) return;
3121 gtk_tree_model_get(store, &iter, 1, &n, -1);
3122
3123 pw->max_dpi = (gdouble)n;
3124 }
3125
3126 static void print_text_field_set(PrintWindow *pw, TextInfo field, gint active)
3127 {
3128 if (active)
3129 {
3130 pw->text_fields |= field;
3131 }
3132 else
3133 {
3134 pw->text_fields &= ~field;
3135 }
3136
3137 print_window_layout_render(pw);
3138 }
3139
3140 static void print_text_cb_name(GtkWidget *widget, gpointer data)
3141 {
3142 PrintWindow *pw = data;
3143 gint active;
3144
3145 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
3146 print_text_field_set(pw, TEXT_INFO_FILENAME, active);
3147 }
3148
3149 static void print_text_cb_date(GtkWidget *widget, gpointer data)
3150 {
3151 PrintWindow *pw = data;
3152 gint active;
3153
3154 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
3155 print_text_field_set(pw, TEXT_INFO_FILEDATE, active);
3156 }
3157
3158 static void print_text_cb_size(GtkWidget *widget, gpointer data)
3159 {
3160 PrintWindow *pw = data;
3161 gint active;
3162
3163 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
3164 print_text_field_set(pw, TEXT_INFO_FILESIZE, active);
3165 }
3166
3167 static void print_text_cb_dims(GtkWidget *widget, gpointer data)
3168 {
3169 PrintWindow *pw = data;
3170 gint active;
3171
3172 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
3173 print_text_field_set(pw, TEXT_INFO_DIMENSIONS, active);
3174 }
3175
3176 static void print_text_cb_points(GtkWidget *widget, gpointer data)
3177 {
3178 PrintWindow *pw = data;
3179
3180 pw->text_points = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
3181 print_window_layout_render(pw);
3182 }
3183
3184 static void print_text_menu(GtkWidget *box, PrintWindow *pw)
3185 {
3186 GtkWidget *group;
3187
3188 group = pref_group_new(box, FALSE, _("Show"), GTK_ORIENTATION_VERTICAL);
3189
3190 pref_checkbox_new(group, _("Name"), (pw->text_fields & TEXT_INFO_FILENAME),
3191 G_CALLBACK(print_text_cb_name), pw);
3192 pref_checkbox_new(group, _("Date"), (pw->text_fields & TEXT_INFO_FILEDATE),
3193 G_CALLBACK(print_text_cb_date), pw);
3194 pref_checkbox_new(group, _("Size"), (pw->text_fields & TEXT_INFO_FILESIZE),
3195 G_CALLBACK(print_text_cb_size), pw);
3196 pref_checkbox_new(group, _("Dimensions"), (pw->text_fields & TEXT_INFO_DIMENSIONS),
3197 G_CALLBACK(print_text_cb_dims), pw);
3198
3199 group = pref_group_new(box, FALSE, _("Font"), GTK_ORIENTATION_VERTICAL);
3200
3201 pref_spin_new(group, _("Size:"), _("points"),
3202 8.0, 100.0, 1.0, 0, pw->text_points,
3203 G_CALLBACK(print_text_cb_points), pw);
3204
3205 #if 0
3206 button = color_selection_new();
3207 gtk_box_pack_start(GTK_BOX(group), button, FALSE, FALSE, 0);
3208 gtk_widget_show(button);
3209 #endif
3210 }
3211
3212 /*
3213 *-----------------------------------------------------------------------------
3214 * print window
3215 *-----------------------------------------------------------------------------
3216 */
3217
3218 static void print_window_close(PrintWindow *pw)
3219 {
3220 print_window_layout_render_stop(pw);
3221
3222 generic_dialog_close(pw->dialog);
3223 pw->dialog = NULL;
3224
3225 print_job_close(pw, FALSE);
3226
3227 g_free(pw->source_path);
3228 path_list_free(pw->source_selection);
3229 path_list_free(pw->source_list);
3230
3231 g_free(pw->output_path);
3232 g_free(pw->output_custom);
3233
3234 g_free(pw);
3235 }
3236
3237 static void print_window_print_cb(GenericDialog *gd, gpointer data)
3238 {
3239 PrintWindow *pw = data;
3240
3241 switch (pw->output)
3242 {
3243 case PRINT_OUTPUT_RGB_FILE:
3244 case PRINT_OUTPUT_PS_FILE:
3245 g_free(pw->output_path);
3246 pw->output_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->path_entry)));
3247 break;
3248 case PRINT_OUTPUT_PS_CUSTOM:
3249 g_free(pw->output_custom);
3250 pw->output_custom = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->custom_entry)));
3251 break;
3252 case PRINT_OUTPUT_PS_LPR:
3253 default:
3254 break;
3255 }
3256
3257 print_window_print_start(pw);
3258 }
3259
3260 static void print_window_cancel_cb(GenericDialog *gd, gpointer data)
3261 {
3262 PrintWindow *pw = data;
3263
3264 print_window_close(pw);
3265 }
3266
3267 static gint print_pref_int(const gchar *key, gint fallback)
3268 {
3269 gint value;
3270
3271 if (pref_list_int_get(PRINT_PREF_GROUP, key, &value)) return value;
3272 return fallback;
3273 }
3274
3275 static gdouble print_pref_double(const gchar *key, gdouble fallback)
3276 {
3277 gdouble value;
3278
3279 if (pref_list_double_get(PRINT_PREF_GROUP, key, &value)) return value;
3280 return fallback;
3281 }
3282
3283 void print_window_new(const gchar *path, GList *selection, GList *list, GtkWidget *parent)
3284 {
3285 PrintWindow *pw;
3286 GdkGeometry geometry;
3287 GtkWidget *main_box;
3288 GtkWidget *vbox;
3289 GtkWidget *label;
3290 GtkWidget *combo;
3291 GtkWidget *box;
3292 GtkWidget *table;
3293
3294 pw = g_new0(PrintWindow, 1);
3295
3296 pw->source_path = g_strdup(path);
3297 pw->source_selection = selection;
3298 pw->source_list = list;
3299
3300 pw->source = PRINT_SOURCE_SELECTION;
3301 pw->layout = PRINT_LAYOUT_IMAGE;
3302
3303 pw->output = print_pref_int(PRINT_PREF_OUTPUT, PRINT_OUTPUT_PS_LPR);
3304 pw->output_format = print_pref_int(PRINT_PREF_FORMAT, PRINT_FILE_JPG_NORMAL);
3305
3306 pw->max_dpi = print_pref_double(PRINT_PREF_DPI, PRINT_PS_DPI_DEFAULT);
3307
3308 pw->paper_units = print_pref_int(PRINT_PREF_UNITS, paper_unit_default());
3309 pw->paper_size = print_pref_int(PRINT_PREF_SIZE, 1);
3310 if (pw->paper_size == 0 ||
3311 !print_paper_size_lookup(pw->paper_size, &pw->paper_width, &pw->paper_height))
3312 {
3313 pw->paper_width = print_pref_double(PRINT_PREF_CUSTOM_WIDTH, 360.0);
3314 pw->paper_height = print_pref_double(PRINT_PREF_CUSTOM_HEIGHT, 720.0);
3315 }
3316 pw->paper_orientation = print_pref_int(PRINT_PREF_ORIENTATION, PAPER_ORIENTATION_PORTRAIT);
3317
3318 pw->margin_left = print_pref_double(PRINT_PREF_MARGIN_LEFT, PRINT_MARGIN_DEFAULT);
3319 pw->margin_right = print_pref_double(PRINT_PREF_MARGIN_RIGHT, PRINT_MARGIN_DEFAULT);
3320 pw->margin_top = print_pref_double(PRINT_PREF_MARGIN_TOP, PRINT_MARGIN_DEFAULT);
3321 pw->margin_bottom = print_pref_double(PRINT_PREF_MARGIN_BOTTOM, PRINT_MARGIN_DEFAULT);
3322
3323 pw->proof_width = print_pref_double(PRINT_PREF_PROOF_WIDTH, PRINT_PROOF_DEFAULT_SIZE);
3324 pw->proof_height = print_pref_double(PRINT_PREF_PROOF_HEIGHT, PRINT_PROOF_DEFAULT_SIZE);
3325
3326 pw->text_fields = TEXT_INFO_FILENAME;
3327 pw->text_points = 10;
3328 pw->text_r = pw->text_g = pw->text_b = 0;
3329
3330 pw->save_settings = print_pref_int(PRINT_PREF_SAVE, TRUE);
3331
3332 pw->dialog = file_util_gen_dlg(_("Print - GQview"), "gqview", "print_dialog",
3333 parent, FALSE,
3334 print_window_cancel_cb, pw);
3335
3336 geometry.min_width = 32;
3337 geometry.min_height = 32;
3338 geometry.base_width = PRINT_DLG_WIDTH;
3339 geometry.base_height = PRINT_DLG_HEIGHT;
3340 gtk_window_set_geometry_hints(GTK_WINDOW(pw->dialog->dialog), NULL, &geometry,
3341 GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
3342
3343 pw->print_button = generic_dialog_add_button(pw->dialog, GTK_STOCK_PRINT, NULL, print_window_print_cb, TRUE);
3344
3345 main_box = pref_box_new(pw->dialog->vbox, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
3346
3347 pw->notebook = gtk_notebook_new();
3348 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pw->notebook), GTK_POS_TOP);
3349 gtk_box_pack_start(GTK_BOX(main_box), pw->notebook, FALSE, FALSE, 0);
3350
3351 /* layout tab */
3352
3353 vbox = gtk_vbox_new(FALSE, 0);
3354 gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
3355 gtk_widget_show(vbox);
3356 label = gtk_label_new(_("Layout"));
3357 gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
3358
3359 print_misc_menu(vbox, pw->source, _("Source"), "print_source",
3360 PRINT_SOURCE_COUNT, print_source_text,
3361 G_CALLBACK(print_source_select_cb), pw);
3362
3363 box = print_misc_menu(vbox, pw->layout, _("Layout"), "print_layout",
3364 PRINT_LAYOUT_COUNT, print_layout_text,
3365 G_CALLBACK(print_layout_select_cb), pw);
3366
3367 pref_spacer(box, PREF_PAD_GROUP);
3368
3369 table = pref_table_new(box, 2, 2, FALSE, FALSE);
3370
3371 pw->image_scale_spin = pref_table_spin(table, 0, 0, _("Image size:"), "%",
3372 5.0, 100.0, 1.0, 0, 100.0,
3373 G_CALLBACK(print_image_scale_cb), pw);
3374
3375 label = pref_table_label(table, 0, 1, _("Proof size:"), 1.0);
3376 pw->proof_group = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3377 pref_link_sensitivity(label, pw->proof_group);
3378
3379 pw->proof_width_spin = pref_spin_new(pw->proof_group, NULL, NULL,
3380 0.0, 50.0, 0.1, 3, 0.0,
3381 G_CALLBACK(print_proof_size_cb), pw);
3382 pw->proof_height_spin = pref_spin_new(pw->proof_group, "x", NULL,
3383 0.0, 50.0, 0.1, 3, 0.0,
3384 G_CALLBACK(print_proof_size_cb), pw);
3385
3386 /* text tab */
3387
3388 vbox = gtk_vbox_new(FALSE, 0);
3389 gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
3390 gtk_widget_show(vbox);
3391 label = gtk_label_new(_("Text"));
3392 gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
3393
3394 print_text_menu(vbox, pw);
3395
3396 /* paper tab */
3397
3398 vbox = gtk_vbox_new(FALSE, 0);
3399 gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
3400 gtk_widget_show(vbox);
3401 label = gtk_label_new(_("Paper"));
3402 gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
3403
3404 table = pref_table_new(vbox, 2, 4, FALSE, FALSE);
3405
3406 print_paper_menu(table, 0, 0, pw->paper_size, G_CALLBACK(print_paper_select_cb), pw);
3407
3408 label = pref_table_label(table, 0, 1, (_("Size:")), 1.0);
3409 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3410 pw->paper_width_spin = pref_spin_new(box, NULL, NULL,
3411 1.0, 10000.0, 1.0, 2, 66,
3412 G_CALLBACK(print_paper_size_cb), pw);
3413 pw->paper_height_spin = pref_spin_new(box, "x", NULL,
3414 1.0, 10000.0, 1.0, 2, 66,
3415 G_CALLBACK(print_paper_size_cb), pw);
3416 pref_link_sensitivity(label, pw->paper_width_spin);
3417
3418 pw->paper_units_menu = print_paper_units_menu(table, 0, 2, pw->paper_units,
3419 G_CALLBACK(print_paper_units_cb), pw);
3420
3421 print_paper_orientation_menu(table, 0, 3, pw->paper_orientation,
3422 G_CALLBACK(print_paper_orientation_cb), pw);
3423
3424 box = pref_group_new(vbox, FALSE, _("Margins"), GTK_ORIENTATION_VERTICAL);
3425 table = pref_table_new(box, 4, 2, FALSE, FALSE);
3426 pw->margin_left_spin = pref_table_spin(table, 0, 0, _("Left:"), NULL,
3427 0.0, 50.0, 0.1, 3, 0.0,
3428 G_CALLBACK(print_paper_margin_cb), pw);
3429 pw->margin_right_spin = pref_table_spin(table, 2, 0, _("Right:"), NULL,
3430 0.0, 50.0, 0.1, 3, 0.0,
3431 G_CALLBACK(print_paper_margin_cb), pw);
3432 pw->margin_top_spin = pref_table_spin(table, 0, 1, _("Top:"), NULL,
3433 0.0, 50.0, 0.1, 3, 0.0,
3434 G_CALLBACK(print_paper_margin_cb), pw);
3435 pw->margin_bottom_spin = pref_table_spin(table, 2, 1, _("Bottom:"), NULL,
3436 0.0, 50.0, 0.1, 3, 0.0,
3437 G_CALLBACK(print_paper_margin_cb), pw);
3438
3439 /* printer tab */
3440
3441 vbox = gtk_vbox_new(FALSE, 0);
3442 gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
3443 gtk_widget_show(vbox);
3444 label = gtk_label_new(_("Printer"));
3445 gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
3446
3447 table = pref_table_new(vbox, 2, 5, FALSE, FALSE);
3448 print_output_menu(table, 0, 0, pw->output, G_CALLBACK(print_output_cb), pw);
3449
3450 label = pref_table_label(table, 0, 1, _("Custom printer:"), 1.0);
3451 combo = history_combo_new(&pw->custom_entry, NULL, "print_custom", -1);
3452 print_custom_entry_set(pw, combo);
3453 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2,
3454 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
3455 gtk_widget_show(combo);
3456
3457 pref_link_sensitivity(label, combo);
3458
3459 label = pref_table_label(table, 0, 2, _("File:"), 1.0);
3460 combo = tab_completion_new_with_history(&pw->path_entry, NULL, "print_path", -1, NULL, pw);
3461 tab_completion_add_select_button(pw->path_entry, NULL, FALSE);
3462 gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3,
3463 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
3464 gtk_widget_show(combo);
3465
3466 pref_link_sensitivity(label, combo);
3467
3468 label = pref_table_label(table, 0, 3, _("File format:"), 1.0);
3469 pw->path_format_menu = print_output_format_menu(table, 1, 3, pw->output_format,
3470 G_CALLBACK(print_output_format_cb), pw);
3471 pref_link_sensitivity(label, pw->path_format_menu);
3472
3473 label = pref_table_label(table, 0, 4, _("DPI:"), 1.0);
3474 pw->max_dpi_menu = print_output_dpi_menu(table, 1, 4, pw->max_dpi,
3475 G_CALLBACK(print_output_dpi_cb), pw);
3476 pref_link_sensitivity(label, pw->max_dpi_menu);
3477
3478 print_output_set(pw, pw->output);
3479
3480 vbox = print_window_layout_setup(pw, main_box);
3481 pref_checkbox_new_int(vbox, _("Remember print settings"), pw->save_settings, &pw->save_settings);
3482
3483 print_window_layout_sync_layout(pw);
3484 print_window_layout_sync_paper(pw);
3485
3486 gtk_widget_show(pw->notebook);
3487 gtk_widget_show(pw->dialog->dialog);
3488 }
3489