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