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