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