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