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