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