Fix #160: Replace print dialog by standard GTK dialog
authorColin Clark <colin.clark@cclark.uk>
Thu, 20 Sep 2018 18:29:39 +0000 (19:29 +0100)
committerColin Clark <colin.clark@cclark.uk>
Thu, 20 Sep 2018 18:29:39 +0000 (19:29 +0100)
https://github.com/BestImageViewer/geeqie/issues/160

Does not include proof print.

src/options.c
src/options.h
src/print.c
src/rcfile.c

index eec3b48..200b552 100644 (file)
@@ -194,6 +194,10 @@ ConfOptions *init_options(ConfOptions *options)
        options->read_metadata_in_idle = FALSE;
        options->star_rating.star = STAR_RATING_STAR;
        options->star_rating.rejected = STAR_RATING_REJECTED;
+
+       options->printer.font = g_strdup("Serif 10");
+       options->printer.text_fields = 1;
+
        return options;
 }
 
index 3b2d62b..f9e92dc 100644 (file)
@@ -301,6 +301,12 @@ struct _ConfOptions
                gunichar rejected;
        } star_rating;
 
+       /* Printer */
+       struct {
+               gchar *font;
+               gint text_fields;
+       } printer;
+
        gboolean read_metadata_in_idle;
 };
 
index fbc4759..4dc0919 100644 (file)
@@ -1,8 +1,7 @@
 /*
- * Copyright (C) 2004 John Ellis
- * Copyright (C) 2008 - 2016 The Geeqie Team
+ * Copyright (C) 2018 The Geeqie Team
  *
- * Author: John Ellis
+ * Author: Colin Clark
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "print.h"
 
 #include "filedata.h"
-#include "filefilter.h"
-#include "image.h"
 #include "image-load.h"
-#include "pixbuf_util.h"
-#include "thumb.h"
-#include "utilops.h"
-#include "ui_bookmark.h"
-#include "ui_menu.h"
 #include "ui_misc.h"
-#include "ui_utildlg.h"
 #include "ui_fileops.h"
-#include "ui_spinner.h"
-#include "ui_tabcomp.h"
 
-#include <locale.h>
-#include <signal.h>
-#include <glib/gprintf.h>
+#define PRINT_SETTINGS "print_settings" // filename save printer settings
+#define PAGE_SETUP "page_setup" // filename save page setup
 
-#define PRINT_LPR_COMMAND "lpr"
-#define PRINT_LPR_CUSTOM  "lpr -P %s"
-#define PRINT_LPR_QUERY   "lpstat -p"
-
-#define PRINT_DLG_WIDTH 600
-#define PRINT_DLG_HEIGHT 400
-
-#define PRINT_DLG_PREVIEW_WIDTH 270
-#define PRINT_DLG_PREVIEW_HEIGHT -1
-
-/* these are in point units */
-#define PRINT_MIN_WIDTH 100
-#define PRINT_MIN_HEIGHT 100
-#define PRINT_MAX_WIDTH 4000
-#define PRINT_MAX_HEIGHT 4000
-
-#define PRINT_MARGIN_DEFAULT 36
-
-#define PRINT_PROOF_MIN_SIZE 8
-#define PRINT_PROOF_MAX_SIZE 720
-#define PRINT_PROOF_DEFAULT_SIZE 144
-#define PRINT_PROOF_MARGIN 5
-
-/* default page size */
-#define PAGE_LAYOUT_WIDTH 850
-#define PAGE_LAYOUT_HEIGHT 1100
-
-/* preview uses 1 pixel = PRINT_PREVIEW_SCALE points */
-#define PRINT_PREVIEW_SCALE 4
-
-/* default dpi to use for printing ps image data */
-#define PRINT_PS_DPI_DEFAULT 300.0
-#define PRINT_PS_DPI_MIN 150.0
-/* method to use when scaling down image data */
-#define PRINT_PS_MAX_INTERP GDK_INTERP_BILINEAR
-/* color to use as mask when printing transparent images */
-#define PRINT_PS_MASK_R 255
-#define PRINT_PS_MASK_G 255
-#define PRINT_PS_MASK_B 255
-
-/* padding between objects */
-#define PRINT_TEXT_PADDING 3.0
-
-/* locale for postscript portability */
-#define POSTSCRIPT_LOCALE "C"
-
-
-/* group and keys for saving prefs */
-#define PRINT_PREF_GROUP       "print_settings"
-
-#define PRINT_PREF_SAVE                "save_settings"
-
-#define PRINT_PREF_OUTPUT      "output"
-#define PRINT_PREF_FORMAT      "format"
-#define PRINT_PREF_DPI         "dpi"
-#define PRINT_PREF_UNITS       "units"
-#define PRINT_PREF_SIZE                "size"
-#define PRINT_PREF_ORIENTATION "orientation"
-
-#define PRINT_PREF_CUSTOM_WIDTH                "custom_width"
-#define PRINT_PREF_CUSTOM_HEIGHT       "custom_height"
-#define PRINT_PREF_MARGIN_LEFT         "margin_left"
-#define PRINT_PREF_MARGIN_RIGHT                "margin_right"
-#define PRINT_PREF_MARGIN_TOP          "margin_top"
-#define PRINT_PREF_MARGIN_BOTTOM       "margin_bottom"
-#define PRINT_PREF_PROOF_WIDTH         "proof_width"
-#define PRINT_PREF_PROOF_HEIGHT                "proof_height"
-
-#define PRINT_PREF_PRINTERC    "custom_printer"
-
-#define PRINT_PREF_TEXT                        "text"
-#define PRINT_PREF_TEXTSIZE            "textsize"
-#define PRINT_PREF_TEXTCOLOR_R         "textcolor_r"
-#define PRINT_PREF_TEXTCOLOR_G         "textcolor_g"
-#define PRINT_PREF_TEXTCOLOR_B         "textcolor_b"
-
-#define PRINT_PREF_SOURCE              "source"
-#define PRINT_PREF_LAYOUT              "layout"
-
-#define PRINT_PREF_IMAGE_SCALE         "image_scale"
-
-typedef enum {
-       PRINT_SOURCE_IMAGE = 0,
-       PRINT_SOURCE_SELECTION,
-       PRINT_SOURCE_ALL,
-       PRINT_SOURCE_COUNT
-} PrintSource;
-
-const gchar *print_source_text[] = {
-       N_("Image"),
-       N_("Selection"),
-       N_("All"),
-       NULL
-};
-
-typedef enum {
-       PRINT_LAYOUT_IMAGE = 0,
-       PRINT_LAYOUT_PROOF,
-       PRINT_LAYOUT_COUNT
-} PrintLayout;
-
-const gchar *print_layout_text[] = {
-       N_("One image per page"),
-       N_("Proof sheet"),
-       NULL
-};
-
-typedef enum {
-       PRINT_OUTPUT_PS_LPR = 0,
-       PRINT_OUTPUT_PS_CUSTOM,
-       PRINT_OUTPUT_PS_FILE,
-       PRINT_OUTPUT_RGB_FILE,
-       PRINT_OUTPUT_COUNT
-} PrintOutput;
-
-const gchar *print_output_text[] = {
-       N_("Default printer"),
-       N_("Custom printer"),
-       N_("PostScript file"),
-       N_("Image file"),
-       NULL,
-       NULL
-};
-
-typedef enum {
-       PRINT_FILE_JPG_LOW = 0,
-       PRINT_FILE_JPG_NORMAL,
-       PRINT_FILE_JPG_HIGH,
-       PRINT_FILE_PNG,
-       PRINT_FILE_COUNT
-} PrintFileFormat;
-
-const gchar *print_file_format_text[] = {
-       N_("jpeg, low quality"),
-       N_("jpeg, normal quality"),
-       N_("jpeg, high quality"),
-       "png",
-       NULL
-};
-
-typedef enum {
-       RENDER_FORMAT_PREVIEW,
-       RENDER_FORMAT_RGB,
-       RENDER_FORMAT_PS
-} RenderFormat;
-
-typedef enum {
-       TEXT_INFO_FILENAME = 1 << 0,
-       TEXT_INFO_FILEDATE = 1 << 1,
-       TEXT_INFO_FILESIZE = 1 << 2,
-       TEXT_INFO_DIMENSIONS = 1 << 3,
-       TEXT_INFO_FILEPATH = 1 << 4
-} TextInfo;
-
-typedef enum {
-       PAPER_UNIT_POINTS = 0,
-       PAPER_UNIT_MM,
-       PAPER_UNIT_CM,
-       PAPER_UNIT_INCH,
-       PAPER_UNIT_PICAS,
-       PAPER_UNIT_COUNT
-} PaperUnits;
-
-typedef enum {
-       PAPER_ORIENTATION_PORTRAIT = 0,
-       PAPER_ORIENTATION_LANDSCAPE,
-       PAPER_ORIENTATION_COUNT
-} PaperOrientation;
-
-
-typedef struct _PrintWindow PrintWindow;
-struct _PrintWindow
-{
-       GenericDialog *dialog;
-
-       FileData *source_fd;
-       GList *source_selection;
-       GList *source_list;
-
-       PrintSource source;
-       PrintLayout layout;
-       PrintOutput output;
-
-       gchar *output_path;
-       gchar *output_custom;
-
-       PrintFileFormat output_format;
-
-       gdouble max_dpi;
-
-       GtkWidget *notebook;
-
-       GtkWidget *path_entry;
-       GtkWidget *custom_entry;
-       GtkWidget *path_format_menu;
-       GtkWidget *max_dpi_menu;
-
-       ImageWindow *layout_image;
-       gdouble layout_width;
-       gdouble layout_height;
-
-       guint layout_idle_id; /* event source id */
-
-       gdouble image_scale;
-
-       GtkWidget *image_scale_spin;
-
-       gdouble proof_width;
-       gdouble proof_height;
-       gint proof_columns;
-       gint proof_rows;
-       GList *proof_point;
-       gint proof_position;
-       gint proof_page;
-
-       GtkWidget *proof_group;
-       GtkWidget *proof_width_spin;
-       GtkWidget *proof_height_spin;
-
-       GtkWidget *paper_menu;
-       GtkWidget *paper_width_spin;
-       GtkWidget *paper_height_spin;
-       GtkWidget *paper_units_menu;
-       GtkWidget *paper_orientation_menu;
-
-       GtkWidget *margin_left_spin;
-       GtkWidget *margin_right_spin;
-       GtkWidget *margin_top_spin;
-       GtkWidget *margin_bottom_spin;
-
-       PaperUnits paper_units;
-       gint paper_size;
-       gdouble paper_width;
-       gdouble paper_height;
-       PaperOrientation paper_orientation;
-
-       gdouble margin_left;
-       gdouble margin_right;
-       gdouble margin_top;
-       gdouble margin_bottom;
-
-       GtkWidget *button_back;
-       GtkWidget *button_next;
-       GtkWidget *page_label;
-       GtkWidget *print_button;
-
-       gdouble single_scale;
-       gdouble single_x;
-       gdouble single_y;
-
-       GtkWidget *single_scale_spin;
-
-       TextInfo        text_fields;
-       gint            text_points;
-       guint8          text_r;
-       guint8          text_g;
-       guint8          text_b;
-
-       gint save_settings;
-
-       /* job printing */
-
-       GenericDialog   *job_dialog;
-       GtkWidget       *job_progress;
-       GtkWidget       *job_progress_label;
-
-       RenderFormat     job_format;
-       PrintOutput      job_output;
-
-       FILE            *job_file;
-       FILE            *job_pipe;
-       gchar           *job_path;
-
-       GdkPixbuf       *job_pixbuf;
-
-       gint             job_page;
-       ImageLoader     *job_loader;
-};
-
-
-static void print_job_throw_error(PrintWindow *pw, const gchar *message);
-static gint print_job_start(PrintWindow *pw, RenderFormat format, PrintOutput output);
-static void print_job_close(PrintWindow *pw, gint error);
-static void print_window_close(PrintWindow *pw);
-
-
-/* misc utils */
-
-static gboolean clip_region(gdouble x1, gdouble y1, gdouble w1, gdouble h1,
-                           gdouble x2, gdouble y2, gdouble w2, gdouble h2,
-                           gdouble *rx, gdouble *ry, gdouble *rw, gdouble *rh)
-{
-       if (x2 + w2 <= x1 || x2 >= x1 + w1 ||
-           y2 + h2 <= y1 || y2 >= y1 + h1)
-               {
-               return FALSE;
-               }
-
-       *rx = MAX(x1, x2);
-       *rw = MIN((x1 + w1), (x2 + w2)) - *rx;
-
-       *ry = MAX(y1, y2);
-       *rh = MIN((y1 + h1), (y2 + h2)) - *ry;
-
-       return TRUE;
-}
-
-static const gchar *print_output_name(PrintOutput output)
-{
-       if (output >= PRINT_OUTPUT_COUNT) return "";
-
-       return _(print_output_text[output]);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * data
- *-----------------------------------------------------------------------------
- */
-
-
-typedef struct _PaperSize PaperSize;
-struct _PaperSize {
-       gchar *description;
-       gint width;
-       gint height;
-       PaperOrientation orientation;
-};
-
-const gchar *print_paper_units[] = {
-       N_("points"),
-       N_("millimeters"),
-       N_("centimeters"),
-       N_("inches"),
-       N_("picas"),
-       NULL
-};
-
-const gchar *print_paper_orientation[] = {
-       N_("Portrait"),
-       N_("Landscape"),
-       NULL
-};
-
-PaperSize print_paper_sizes[] = {
-       { N_("Custom"),         360,    720,    PAPER_ORIENTATION_PORTRAIT },
-       { N_("Letter"),         612,    792,    PAPER_ORIENTATION_PORTRAIT },   /* in 8.5 x 11 */
-       { N_("Legal"),          612,    1008,   PAPER_ORIENTATION_PORTRAIT },   /* in 8.5 x 14 */
-       { N_("Executive"),      522,    756,    PAPER_ORIENTATION_PORTRAIT },   /* in 7.25x 10.5 */
-       { "A0",                 2384,   3370,   PAPER_ORIENTATION_PORTRAIT },   /* mm 841 x 1189 */
-       { "A1",                 1684,   2384,   PAPER_ORIENTATION_PORTRAIT },   /* mm 594 x 841 */
-       { "A2",                 1191,   1684,   PAPER_ORIENTATION_PORTRAIT },   /* mm 420 x 594 */
-       { "A3",                 842,    1191,   PAPER_ORIENTATION_PORTRAIT },   /* mm 297 x 420 */
-       { "A4",                 595,    842,    PAPER_ORIENTATION_PORTRAIT },   /* mm 210 x 297 */
-       { "A5",                 420,    595,    PAPER_ORIENTATION_PORTRAIT },   /* mm 148 x 210 */
-       { "A6",                 298,    420,    PAPER_ORIENTATION_PORTRAIT },   /* mm 105 x 148 */
-       { "B3",                 1001,   1417,   PAPER_ORIENTATION_PORTRAIT },   /* mm 353 x 500 */
-       { "B4",                 709,    1001,   PAPER_ORIENTATION_PORTRAIT },   /* mm 250 x 353 */
-       { "B5",                 499,    709,    PAPER_ORIENTATION_PORTRAIT },   /* mm 176 x 250 */
-       { "B6",                 354,    499,    PAPER_ORIENTATION_PORTRAIT },   /* mm 125 x 176 */
-       { N_("Envelope #10"),   297,    684,    PAPER_ORIENTATION_LANDSCAPE },  /* in 4.125 x 9.5 */
-       { N_("Envelope #9"),    279,    639,    PAPER_ORIENTATION_LANDSCAPE },  /* in 3.875 x 8.875 */
-       { N_("Envelope C4"),    649,    918,    PAPER_ORIENTATION_LANDSCAPE },  /* mm 229 x 324 */
-       { N_("Envelope C5"),    459,    649,    PAPER_ORIENTATION_LANDSCAPE },  /* mm 162 x 229 */
-       { N_("Envelope C6"),    323,    459,    PAPER_ORIENTATION_LANDSCAPE },  /* mm 114 x 162 */
-       { N_("Photo 6x4"),      432,    288,    PAPER_ORIENTATION_PORTRAIT },   /* in 6   x 4 */
-       { N_("Photo 8x10"),     576,    720,    PAPER_ORIENTATION_PORTRAIT },   /* in 8   x 10 */
-       { N_("Postcard"),       284,    419,    PAPER_ORIENTATION_LANDSCAPE },  /* mm 100 x 148 */
-       { N_("Tabloid"),        792,    1224,   PAPER_ORIENTATION_PORTRAIT },   /* in 11  x 17 */
-       { NULL, 0, 0, 0 }
-};
-
-
-static PaperSize *print_paper_size_nth(gint n)
-{
-       PaperSize *ps = NULL;
-       gint i = 0;
-
-       while (i <= n && print_paper_sizes[i].description)
-               {
-               ps = &print_paper_sizes[i];
-               i++;
-               }
-
-       return ps;
-}
-
-static gint print_paper_size_lookup(gint n, gdouble *width, gdouble *height)
-{
-       PaperSize *ps;
-       gdouble w, h;
-
-       ps = print_paper_size_nth(n);
-       if (!ps) return FALSE;
-
-       if (ps->orientation == PAPER_ORIENTATION_PORTRAIT)
-               {
-               w = ps->width;
-               h = ps->height;
-               }
-       else
-               {
-               h = ps->width;
-               w = ps->height;
-               }
-
-       if (width) *width = w;
-       if (height) *height = h;
-
-       return TRUE;
-}
-
-static gdouble print_paper_size_convert_units(gdouble value, PaperUnits src, PaperUnits dst)
-{
-       gdouble ret;
-
-       if (src == dst) return value;
-
-       switch (src)
-               {
-               case PAPER_UNIT_MM:
-                       ret = value / 25.4 * 72.0;
-                       break;
-               case PAPER_UNIT_CM:
-                       ret = value / 2.54 * 72.0;
-                       break;
-               case PAPER_UNIT_INCH:
-                       ret = value * 72.0;
-                       break;
-               case PAPER_UNIT_PICAS:
-                       ret = value * 12.0;
-                       break;
-               case PAPER_UNIT_POINTS:
-               default:
-                       ret = value;
-                       break;
-               }
-
-       switch (dst)
-               {
-               case PAPER_UNIT_MM:
-                       ret = ret / 72.0 * 25.4;
-                       break;
-               case PAPER_UNIT_CM:
-                       ret = ret / 72.0 * 2.54;
-                       break;
-               case PAPER_UNIT_INCH:
-                       ret = ret / 72.0;
-                       break;
-               case PAPER_UNIT_PICAS:
-                       ret = ret / 12.0;
-                       break;
-               case PAPER_UNIT_POINTS:
-               default:
-                       break;
-               }
-
-       return ret;
-}
-
-static PaperUnits paper_unit_default(void)
-{
-       const gchar *result;
-#if 0
-       /* this is not used because it is not even slightly portable */
-       #include <langinfo.h>
-
-       result = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
-       if (result[0] == '2') return PAPER_UNIT_INCH;
-#endif
-
-#ifdef LC_MEASUREMENT
-       result = setlocale(LC_MEASUREMENT, NULL);
-#else
-       result = setlocale(LC_ALL, NULL);
-#endif
-       if (result &&
-           (strstr(result, "_US") || strstr(result, "_PR")) )
-               {
-               return PAPER_UNIT_INCH;
-               }
-
-       return PAPER_UNIT_CM;
-}
-
-/*
- *-----------------------------------------------------------------------------
- * the layout window
- *-----------------------------------------------------------------------------
- */
-
-static gint print_layout_page_count(PrintWindow *pw);
-
-
-static gint print_preview_unit(gdouble points)
-{
-       return (gint)(points / PRINT_PREVIEW_SCALE);
-}
-
-static void print_proof_size(PrintWindow *pw, gdouble *width, gdouble *height)
-{
-       if (width) *width = pw->proof_width + PRINT_PROOF_MARGIN * 2;
-       if (height)
-               {
-               gdouble h;
-
-               h = pw->proof_height + PRINT_PROOF_MARGIN * 2;
-               if (pw->text_fields != 0) h += PRINT_TEXT_PADDING;
-               if (pw->text_fields & TEXT_INFO_FILENAME) h+= (gdouble)pw->text_points * 1.25;
-               if (pw->text_fields & TEXT_INFO_DIMENSIONS) h+= (gdouble)pw->text_points * 1.25;
-               if (pw->text_fields & TEXT_INFO_FILEDATE) h+= (gdouble)pw->text_points * 1.25;
-               if (pw->text_fields & TEXT_INFO_FILESIZE) h+= (gdouble)pw->text_points * 1.25;
-               *height = h;
-               }
-}
-
-static void print_window_layout_status(PrintWindow *pw)
-{
-       gint total;
-       gchar *buf;
-
-       total = print_layout_page_count(pw);
-       pw->proof_page = CLAMP(pw->proof_page, 0, total - 1);
-
-       buf = g_strdup_printf(_("page %d of %d"), pw->proof_page + 1, (total > 0) ? total : 1);
-       gtk_label_set_text(GTK_LABEL(pw->page_label), buf);
-       g_free(buf);
-
-       gtk_widget_set_sensitive(pw->page_label, (total > 0));
-
-       gtk_widget_set_sensitive(pw->button_back, (pw->proof_page > 0));
-       gtk_widget_set_sensitive(pw->button_next, (pw->proof_page < total - 1));
-
-       gtk_widget_set_sensitive(pw->print_button, total > 0);
-}
-
-static void print_window_layout_render_stop(PrintWindow *pw)
-{
-       if (pw->layout_idle_id)
-               {
-               g_source_remove(pw->layout_idle_id);
-               pw->layout_idle_id = 0;
-               }
-}
-
-static gboolean print_window_layout_render_idle(gpointer data)
-{
-       PrintWindow *pw = data;
-
-       print_job_close(pw, FALSE);
-       print_job_start(pw, RENDER_FORMAT_PREVIEW, 0);
-
-       pw->layout_idle_id = 0;
-       return FALSE;
-}
-
-static void print_window_layout_render(PrintWindow *pw)
-{
-       gdouble proof_w, proof_h;
-
-       print_proof_size(pw, &proof_w, &proof_h);
-       pw->proof_columns = (pw->layout_width - pw->margin_left - pw->margin_right) / proof_w;
-       pw->proof_rows = (pw->layout_height - pw->margin_top - pw->margin_bottom) / proof_h;
-
-       print_window_layout_status(pw);
-
-       if (!pw->layout_idle_id)
-               {
-               pw->layout_idle_id = g_idle_add(print_window_layout_render_idle, pw);
-               }
-}
-
-static void print_window_layout_size(PrintWindow *pw)
-{
-       GdkPixbuf *pixbuf;
-       gdouble width;
-       gdouble height;
-       gint sw, sh;
-
-       if (!pw->layout_image) return;
-
-       if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
-               {
-               width = pw->paper_height;
-               height = pw->paper_width;
-               }
-       else
-               {
-               width = pw->paper_width;
-               height = pw->paper_height;
-               }
-
-       pw->layout_width = width;
-       pw->layout_height = height;
-
-       sw = print_preview_unit(width);
-       sh = print_preview_unit(height);
-       pixbuf = image_get_pixbuf(pw->layout_image);
-       if (!pixbuf ||
-           gdk_pixbuf_get_width(pixbuf) != sw ||
-           gdk_pixbuf_get_height(pixbuf) != sh)
-               {
-               pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, sw, sh);
-               image_change_pixbuf(pw->layout_image, pixbuf, 0.0, FALSE);
-               g_object_unref(pixbuf);
-               }
-
-       print_window_layout_render(pw);
-       print_window_layout_status(pw);
-}
-
-static gint print_layout_page_count(PrintWindow *pw)
-{
-       gint images;
-       gint images_per_page;
-       gint pages;
-
-       if (pw->layout_width - pw->margin_left - pw->margin_right <= 0.0 ||
-           pw->layout_height - pw->margin_top - pw->margin_bottom <= 0.0)
-               {
-               return 0;
-               }
-
-       switch (pw->source)
-               {
-               case PRINT_SOURCE_ALL:
-                       images = g_list_length(pw->source_list);
-                       break;
-               case PRINT_SOURCE_SELECTION:
-                       images = g_list_length(pw->source_selection);
-                       break;
-               case PRINT_SOURCE_IMAGE:
-               default:
-                       images = (pw->source_fd) ? 1 : 0;
-                       break;
-               }
-
-       switch (pw->layout)
-               {
-               case PRINT_LAYOUT_PROOF:
-                       images_per_page = pw->proof_columns * pw->proof_rows;
-                       break;
-               case PRINT_LAYOUT_IMAGE:
-               default:
-                       images_per_page = 1;
-                       break;
-               }
-
-       if (images < 1 || images_per_page < 1) return 0;
-
-       pages = images / images_per_page;
-       if (pages * images_per_page < images) pages++;
-
-       return pages;
-}
-
-static void print_layout_page_step(PrintWindow *pw, gint step)
-{
-       gint max;
-       gint page;
-
-       max = print_layout_page_count(pw);
-       page = pw->proof_page + step;
-
-       if (page >= max) page = max - 1;
-       if (page < 0) page = 0;
-
-       if (page == pw->proof_page) return;
-
-       pw->proof_page = page;
-       print_window_layout_size(pw);
-}
-
-static void print_layout_page_back_cb(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-
-       print_layout_page_step(pw, -1);
-}
-
-static void print_layout_page_next_cb(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-
-       print_layout_page_step(pw, 1);
-}
-
-static void print_layout_zoom_in_cb(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       image_zoom_adjust(pw->layout_image, 0.25);
-}
-
-static void print_layout_zoom_out_cb(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       image_zoom_adjust(pw->layout_image, -0.25);
-}
-
-static void print_layout_zoom_original_cb(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gdouble zoom;
-
-       zoom = image_zoom_get(pw->layout_image);
-       image_zoom_set(pw->layout_image, (zoom == 1.0) ? 0.0 : 1.0);
-}
-
-static GtkWidget *print_window_layout_setup(PrintWindow *pw, GtkWidget *box)
-{
-       GtkWidget *vbox;
-       GtkWidget *hbox;
-       GtkWidget *group;
-       GtkWidget *button;
-
-       vbox = pref_box_new(box, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
-       group = pref_frame_new(vbox, TRUE, _("Preview"), GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
-
-       pw->layout_idle_id = 0;
-
-       pw->layout_image = image_new(FALSE);
-       gtk_widget_set_size_request(pw->layout_image->widget, PRINT_DLG_PREVIEW_WIDTH, PRINT_DLG_PREVIEW_HEIGHT);
-
-       gtk_box_pack_start(GTK_BOX(group), pw->layout_image->widget, TRUE, TRUE, 0);
-       gtk_widget_show(pw->layout_image->widget);
-
-       hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
-       pw->button_back = pref_button_new(hbox, GTK_STOCK_GO_BACK, NULL, TRUE,
-                                         G_CALLBACK(print_layout_page_back_cb), pw);
-       pw->button_next = pref_button_new(hbox, GTK_STOCK_GO_FORWARD, NULL, TRUE,
-                                         G_CALLBACK(print_layout_page_next_cb), pw);
-       pw->page_label = pref_label_new(hbox, "");
-
-       button = pref_button_new(NULL, GTK_STOCK_ZOOM_OUT, NULL, TRUE,
-                                G_CALLBACK(print_layout_zoom_out_cb), pw);
-       gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-       gtk_widget_show(button);
-       button = pref_button_new(NULL, GTK_STOCK_ZOOM_IN, NULL, TRUE,
-                                G_CALLBACK(print_layout_zoom_in_cb), pw);
-       gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-       gtk_widget_show(button);
-       button = pref_button_new(NULL, GTK_STOCK_ZOOM_100, NULL, TRUE,
-                                G_CALLBACK(print_layout_zoom_original_cb), pw);
-       gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-       gtk_widget_show(button);
-
-       print_window_layout_size(pw);
-
-       return vbox;
-}
-
-static void print_window_spin_set(GtkSpinButton *spin, gpointer block_data,
-                                 gdouble value, gdouble min, gdouble max,
-                                 gdouble step, gdouble page, gint digits)
-{
-       if (block_data) g_signal_handlers_block_matched(G_OBJECT(spin), G_SIGNAL_MATCH_DATA,
-                                                       0, 0, NULL, NULL, block_data);
-       gtk_spin_button_set_digits(spin, digits);
-       gtk_spin_button_set_increments(spin, step, page);
-       gtk_spin_button_set_range(spin, min, max);
-       gtk_spin_button_set_value(spin, value);
-
-       if (block_data) g_signal_handlers_unblock_matched(G_OBJECT(spin), G_SIGNAL_MATCH_DATA,
-                                                         0, 0, NULL, NULL, block_data);
-}
-
-static void print_window_layout_sync_layout(PrintWindow *pw)
-{
-       gtk_widget_set_sensitive(pw->image_scale_spin, (pw->layout == PRINT_LAYOUT_IMAGE));
-       gtk_widget_set_sensitive(pw->proof_group, (pw->layout == PRINT_LAYOUT_PROOF));
-}
-
-static void print_window_layout_sync_paper(PrintWindow *pw)
-{
-       gdouble width, height;
-       gint digits;
-       gdouble step;
-       gdouble page;
-
-       gtk_widget_set_sensitive(pw->paper_width_spin, (pw->paper_size == 0));
-       gtk_widget_set_sensitive(pw->paper_height_spin, (pw->paper_size == 0));
-
-       width = print_paper_size_convert_units((gdouble)pw->paper_width, PAPER_UNIT_POINTS, pw->paper_units);
-       height = print_paper_size_convert_units((gdouble)pw->paper_height, PAPER_UNIT_POINTS, pw->paper_units);
-
-       switch (pw->paper_units)
-               {
-               case PAPER_UNIT_MM:
-                       digits = 1;
-                       step = 1.0;
-                       page = 10.0;
-                       break;
-               case PAPER_UNIT_CM:
-                       digits = 2;
-                       step = 0.5;
-                       page = 1.0;
-                       break;
-               case PAPER_UNIT_INCH:
-                       digits = 3;
-                       step = 0.25;
-                       page = 1.0;
-                       break;
-               case PAPER_UNIT_PICAS:
-                       digits = 2;
-                       step = 1.0;
-                       page = 6.0;
-                       break;
-               case PAPER_UNIT_POINTS:
-               default:
-                       digits = 1;
-                       step = 1.0;
-                       page = 10.0;
-                       break;
-               }
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->paper_width_spin), pw, width,
-                             print_paper_size_convert_units(PRINT_MIN_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->paper_height_spin), pw, height,
-                             print_paper_size_convert_units(PRINT_MIN_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_left_spin), pw,
-                             print_paper_size_convert_units(pw->margin_left, PAPER_UNIT_POINTS, pw->paper_units),
-                             0.0,
-                             print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_right_spin), pw,
-                             print_paper_size_convert_units(pw->margin_right, PAPER_UNIT_POINTS, pw->paper_units),
-                             0.0,
-                             print_paper_size_convert_units(PRINT_MAX_WIDTH, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_top_spin), pw,
-                             print_paper_size_convert_units(pw->margin_top, PAPER_UNIT_POINTS, pw->paper_units),
-                             0.0,
-                             print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->margin_bottom_spin), pw,
-                             print_paper_size_convert_units(pw->margin_bottom, PAPER_UNIT_POINTS, pw->paper_units),
-                             0.0,
-                             print_paper_size_convert_units(PRINT_MAX_HEIGHT, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->proof_width_spin), pw,
-                             print_paper_size_convert_units(pw->proof_width, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_PROOF_MIN_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_PROOF_MAX_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-
-       print_window_spin_set(GTK_SPIN_BUTTON(pw->proof_height_spin), pw,
-                             print_paper_size_convert_units(pw->proof_height, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_PROOF_MIN_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
-                             print_paper_size_convert_units(PRINT_PROOF_MAX_SIZE, PAPER_UNIT_POINTS, pw->paper_units),
-                             step, page, digits);
-}
-
-static void print_window_layout_set_size(PrintWindow *pw, gdouble width, gdouble height)
-{
-       pw->paper_width = width;
-       pw->paper_height = height;
-
-       print_window_layout_sync_paper(pw);
-
-       print_window_layout_size(pw);
-}
-
-static void print_window_layout_set_orientation(PrintWindow *pw, PaperOrientation o)
-{
-       if (pw->paper_orientation == o) return;
-
-       pw->paper_orientation = o;
-
-       print_window_layout_size(pw);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * list printers
- *-----------------------------------------------------------------------------
- */
-
-static GList *print_window_list_printers(void)
-{
-       FILE *p;
-       GList *list = NULL;
-       gchar buffer[2048];
-
-       p = popen(PRINT_LPR_QUERY, "r");
-       if (!p) return NULL;
-
-       while (fgets(buffer, sizeof(buffer), p) != NULL)
-               {
-               gchar *ptr;
-               gchar *end;
-
-               ptr = buffer;
-               if (strncmp(ptr, "printer ", 8) != 0) continue;
-               if (strstr(ptr, "enabled") == NULL) continue;
-               ptr += 8;
-               end = ptr;
-               while (*end != '\0' && *end != '\n' && *end != ' ' && *end != '\t') end++;
-               *end = '\0';
-               list = g_list_append(list, g_strdup(ptr));
-               DEBUG_1("adding printer: %s", ptr);
-               }
-
-       pclose(p);
-
-       return list;
-}
-
-/*
- *-----------------------------------------------------------------------------
- * print ps
- *-----------------------------------------------------------------------------
- */
-
-typedef struct _PipeError PipeError;
-struct _PipeError {
-       struct sigaction old_action;
-       sig_atomic_t *error;
-};
-
-static sig_atomic_t pipe_handler_error = FALSE;
-static PipeError *pipe_handler_data = NULL;
-
-static void pipe_handler_sigpipe_cb(gint fd)
-{
-       pipe_handler_error = TRUE;
-}
-
-static PipeError *pipe_handler_new(void)
-{
-       struct sigaction new_action;
-       PipeError *pe;
-
-       if (pipe_handler_data)
-               {
-               log_printf("warning SIGPIPE handler already in use\n");
-               return NULL;
-               }
-
-       pe = g_new0(PipeError, 1);
-
-       pipe_handler_error = FALSE;
-       pe->error = &pipe_handler_error;
-
-       new_action.sa_handler = pipe_handler_sigpipe_cb;
-       sigemptyset(&new_action.sa_mask);
-       new_action.sa_flags = 0;
-
-       /* setup our signal handler */
-       sigaction(SIGPIPE, &new_action, &pe->old_action);
-
-       pipe_handler_data = pe;
-       return pe;
-}
-
-static void pipe_handler_free(PipeError *pe)
-{
-       if (!pe) return;
-       if (pe != pipe_handler_data) log_printf("warning SIGPIPE handler not closing same data\n");
-
-       /* restore the original signal handler */
-       sigaction(SIGPIPE, &pe->old_action, NULL);
-
-       pipe_handler_data = NULL;
-       g_free(pe);
-}
-
-static gboolean pipe_handler_check(PipeError *pe)
-{
-       if (!pe) return FALSE;
-       return !!(*pe->error);
-}
-
-static FILE *print_job_ps_fd(PrintWindow *pw)
-{
-       if (pw->job_file) return pw->job_file;
-       if (pw->job_pipe) return pw->job_pipe;
-       return NULL;
-}
-
-static gboolean print_job_ps_init(PrintWindow *pw)
-{
-       FILE *f;
-       PipeError *pe;
-       const gchar *cmd = NULL;
-       const gchar *path = NULL;
-       gchar *lc_pointer;
-       gboolean ret;
-
-       if (pw->job_file != NULL || pw->job_pipe != NULL) return FALSE;
-
-       switch (pw->job_output)
-               {
-               case PRINT_OUTPUT_PS_LPR:
-                       cmd = PRINT_LPR_COMMAND;
-                       break;
-               case PRINT_OUTPUT_PS_CUSTOM:
-                       cmd = pw->output_custom;
-                       break;
-               case PRINT_OUTPUT_PS_FILE:
-                       path = pw->output_path;
-                       break;
-               default:
-                       return FALSE;
-                       break;
-               }
-
-       if (cmd)
-               {
-               pw->job_pipe = popen(cmd, "w");
-
-               if (!pw->job_pipe)
-                       {
-                       gchar *buf;
-
-                       buf = g_strdup_printf(_("Unable to open pipe for writing.\n\"%s\""), cmd);
-                       print_job_throw_error(pw, buf);
-                       g_free(buf);
-
-                       return FALSE;
-                       }
-               }
-       else if (path)
-               {
-               gchar *pathl;
-
-               if (isfile(path))
-                       {
-                       gchar *buf;
-
-                       buf = g_strdup_printf(_("A file with name %s already exists."), path);
-                       print_job_throw_error(pw, buf);
-                       g_free(buf);
-
-                       return FALSE;
-                       }
-
-               pathl = path_from_utf8(path);
-               pw->job_file = fopen(pathl, "w");
-               g_free(pathl);
-
-               if (!pw->job_file)
-                       {
-                       gchar *buf;
-
-                       buf = g_strdup_printf(_("Failure writing to file %s"), path);
-                       print_job_throw_error(pw, buf);
-                       g_free(buf);
-
-                       return FALSE;
-                       }
-
-               g_free(pw->job_path);
-               pw->job_path = g_strdup(path);
-               }
-
-       f = print_job_ps_fd(pw);
-       if (!f) return FALSE;
-
-       lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
-       setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
-
-       pe = pipe_handler_new();
-
-       /* comments, etc. */
-       g_fprintf(f, "%%!PS-Adobe-3.0\n");
-       g_fprintf(f, "%%%%Creator: %s Version %s\n", GQ_APPNAME, VERSION);
-       g_fprintf(f, "%%%%CreationDate: \n");
-       g_fprintf(f, "%%%%LanguageLevel 2\n");
-       g_fprintf(f, "%%%%DocumentMedia: \n");
-       g_fprintf(f, "%%%%Orientation: %s\n",
-               (pw->paper_orientation == PAPER_ORIENTATION_PORTRAIT) ? "Portrait" : "Landscape");
-       g_fprintf(f, "%%%%BoundingBox: %f %f %f %f\n",
-               0.0, 0.0, pw->paper_width, pw->paper_height);
-       g_fprintf(f, "%%%%Pages: %d\n", print_layout_page_count(pw));
-       g_fprintf(f, "%%%%PageOrder: Ascend\n");
-       g_fprintf(f, "%%%%Title:\n");
-
-       /* setup page size, coordinates (do we really need this?) */
-       /* enabled for 1.0beta2  https://bugzilla.redhat.com/222639 */
-#if 1
-       g_fprintf(f, "<<\n");
-       g_fprintf(f, "/PageSize [%f %f]\n", pw->layout_width, pw->layout_height);
-       g_fprintf(f, "/ImagingBBox [%f %f %f %f]\n", /* l b r t */
-               pw->margin_left, pw->margin_bottom,
-               pw->layout_width - pw->margin_right, pw->layout_height - pw->margin_top);
-       g_fprintf(f, "/Orientation %d\n",
-               (pw->paper_orientation == PAPER_ORIENTATION_PORTRAIT) ? 0 : 1);
-       g_fprintf(f, ">> setpagedevice\n");
-#endif
-
-       ret = !pipe_handler_check(pe);
-       pipe_handler_free(pe);
-
-       if (lc_pointer)
-               {
-               setlocale(LC_NUMERIC, lc_pointer);
-               g_free(lc_pointer);
-               }
-
-       if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
-
-       return ret;
-}
-
-static gboolean print_job_ps_page_new(PrintWindow *pw, gint page)
-{
-       FILE *f;
-       PipeError *pe;
-       gchar *lc_pointer;
-       gboolean ret;
-
-       f= print_job_ps_fd(pw);
-       if (!f) return FALSE;
-
-       lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
-       setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
-
-       pe = pipe_handler_new();
-
-       g_fprintf(f, "%%%% page %d\n", page + 1);
-
-       if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
-               {
-               g_fprintf(f, "/pagelevel save def\n");
-               g_fprintf(f, "%d 0 translate 90 rotate\n", (gint)pw->layout_height);
-               }
-
-       ret = !pipe_handler_check(pe);
-       pipe_handler_free(pe);
-
-       if (lc_pointer)
-               {
-               setlocale(LC_NUMERIC, lc_pointer);
-               g_free(lc_pointer);
-               }
-
-       if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
-
-       return ret;
-}
-
-static gboolean print_job_ps_page_done(PrintWindow *pw)
-{
-       FILE *f;
-       PipeError *pe;
-       gchar *lc_pointer;
-       gboolean ret;
-
-       f = print_job_ps_fd(pw);
-       if (!f) return FALSE;
-
-       lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
-       setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
-
-       pe = pipe_handler_new();
-
-       if (pw->paper_orientation == PAPER_ORIENTATION_LANDSCAPE)
-               {
-               g_fprintf(f, "pagelevel restore\n");
-               }
-
-       g_fprintf(f, "showpage\n");
-
-       ret = !pipe_handler_check(pe);
-       pipe_handler_free(pe);
-
-       if (lc_pointer)
-               {
-               setlocale(LC_NUMERIC, lc_pointer);
-               g_free(lc_pointer);
-               }
-
-       if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
-
-       return ret;
-}
-
-static void print_job_ps_page_image_pixel(FILE *f, guchar *pix)
-{
-       static gchar hex_digits[] = "0123456789abcdef";
-       gchar text[8];
-       gint i;
-
-       for (i = 0; i < 3; i++)
-               {
-               text[i*2] = hex_digits[pix[i] >> 4];
-               text[i*2+1] = hex_digits[pix[i] & 0xf];
-               }
-       text[6] = '\0';
-
-       g_fprintf(f, "%s", text);
-}
-static gboolean print_job_ps_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
-                                       gdouble x, gdouble y, gdouble w, gdouble h,
-                                       gdouble offx, gdouble offy)
-{
-       FILE *f;
-       PipeError *pe;
-       gchar *lc_pointer;
-       gint sw, sh;
-       gint bps;
-       gint rowstride;
-       guchar *pix;
-       gint i, j;
-       gint c;
-       guchar *p;
-       guchar bps_buf[3];
-       gboolean ret;
-
-       if (!pixbuf) return TRUE;
-
-       f = print_job_ps_fd(pw);
-       if (!f) return FALSE;
-
-       sw = gdk_pixbuf_get_width(pixbuf);
-       sh = gdk_pixbuf_get_height(pixbuf);
-
-       if (pw->max_dpi >= PRINT_PS_DPI_MIN &&
-           sw / pw->max_dpi > w / 72.0)
-               {
-               pixbuf = gdk_pixbuf_scale_simple(pixbuf,
-                                               (gint)(w / 72.0 * pw->max_dpi),
-                                               (gint)(h / 72.0 * pw->max_dpi),
-                                               PRINT_PS_MAX_INTERP);
-               sw = gdk_pixbuf_get_width(pixbuf);
-               sh = gdk_pixbuf_get_height(pixbuf);
-               }
-       else
-               {
-               g_object_ref(G_OBJECT(pixbuf));
-               }
-
-       bps = (gdk_pixbuf_get_has_alpha(pixbuf)) ? 4 : 3;
-       rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-       pix = gdk_pixbuf_get_pixels(pixbuf);
-
-       lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
-       setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
-
-       pe = pipe_handler_new();
-
-       g_fprintf(f, "gsave\n");
-       g_fprintf(f, "[%f 0 0 %f %f %f] concat\n", w, h, x, pw->layout_height - h - y);
-       g_fprintf(f, "/buf %d string def\n", sw * 3);
-       g_fprintf(f, "%d %d %d\n", sw, sh, 8);
-       g_fprintf(f, "[%d 0 0 -%d 0 %d]\n", sw, sh, sh);
-       g_fprintf(f, "{ currentfile buf readhexstring pop }\n");
-       g_fprintf(f, "false %d colorimage\n", 3);
-
-       c = 0;
-       for (j = 0; j < sh; j++)
-               {
-               p = pix + j * rowstride;
-               for (i = 0; i < sw; i++)
-                       {
-                       if (bps == 3)
-                               {
-                               print_job_ps_page_image_pixel(f, p);
-                               }
-                       else
-                               {
-                               bps_buf[0] = (p[0] * p[3] + PRINT_PS_MASK_R * (256 - p[3])) >> 8;
-                               bps_buf[1] = (p[1] * p[3] + PRINT_PS_MASK_G * (256 - p[3])) >> 8;
-                               bps_buf[2] = (p[2] * p[3] + PRINT_PS_MASK_B * (256 - p[3])) >> 8;
-                               print_job_ps_page_image_pixel(f, bps_buf);
-                               }
-                       p+=bps;
-                       c++;
-                       if (c > 11)
-                               {
-                               g_fprintf(f, "\n");
-                               c = 0;
-                               }
-                       }
-               }
-       if (c > 0) g_fprintf(f, "\n");
-       g_fprintf(f, "grestore\n");
-
-       ret = !pipe_handler_check(pe);
-       pipe_handler_free(pe);
-
-       if (lc_pointer)
-               {
-               setlocale(LC_NUMERIC, lc_pointer);
-               g_free(lc_pointer);
-               }
-
-       g_object_unref(G_OBJECT(pixbuf));
-
-       if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
-
-       return ret;
-}
-
-static gdouble convert_pango_dpi(gdouble points);
-
-static gboolean print_job_ps_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
-                                      gdouble x, gdouble y, gdouble width,
-                                      guint8 r, guint8 g, guint8 b)
-{
-       PangoLayout *layout;
-       PangoFontDescription *desc;
-       GdkPixbuf *pixbuf;
-       gint lw, lh;
-       gboolean ret;
-       gdouble scale_to_max_dpi = (pw->max_dpi >= PRINT_PS_DPI_MIN) ? pw->max_dpi / 72.0 : 1200.0 / 72.0;
-
-       layout = gtk_widget_create_pango_layout(pw->dialog->dialog, NULL);
-
-       desc = pango_font_description_new();
-       pango_font_description_set_size(desc, convert_pango_dpi(point_size) * PANGO_SCALE * scale_to_max_dpi);
-       pango_layout_set_font_description(layout, desc);
-       pango_font_description_free(desc);
-
-       pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
-       pango_layout_set_text(layout, text, -1);
-
-       pango_layout_get_pixel_size(layout, &lw, &lh);
-       x = x - (gdouble)lw / 2.0 / scale_to_max_dpi;
-
-       pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, lw, lh);
-       gdk_pixbuf_fill(pixbuf, 0xffffffff);
-       pixbuf_draw_layout(pixbuf, layout, pw->dialog->dialog, 0, 0, r, g, b, 255);
-       g_object_unref(G_OBJECT(layout));
-
-       ret = print_job_ps_page_image(pw, pixbuf, x, y,
-                                      /* do not allow rescaling of the pixbuf due to rounding errors */
-                                     ((gdouble)lw + 0.01) / scale_to_max_dpi,
-                                     ((gdouble)lh + 0.01) / scale_to_max_dpi,
-                                     0, 0);
-
-       g_object_unref(G_OBJECT(pixbuf));
-
-       return ret;
-}
-
-static gboolean print_job_ps_end(PrintWindow *pw)
-{
-       FILE *f;
-       PipeError *pe;
-       gchar *lc_pointer;
-       gboolean ret;
-
-       f = print_job_ps_fd(pw);
-       if (!f) return FALSE;
-
-       lc_pointer = g_strdup(setlocale(LC_NUMERIC, NULL));
-       setlocale(LC_NUMERIC, POSTSCRIPT_LOCALE);
-
-       pe = pipe_handler_new();
-
-       g_fprintf(f, "%%%%EOF\n");
-
-       ret = !pipe_handler_check(pe);
-       pipe_handler_free(pe);
-
-       if (lc_pointer)
-               {
-               setlocale(LC_NUMERIC, lc_pointer);
-               g_free(lc_pointer);
-               }
-
-       if (!ret) print_job_throw_error(pw, _("SIGPIPE error writing to printer."));
-
-       return ret;
-}
-
-/*
- *-----------------------------------------------------------------------------
- * print rgb
- *-----------------------------------------------------------------------------
- */
-
-static gboolean print_job_rgb_page_new(PrintWindow *pw, gint page)
-{
-       gint total;
-
-       if (pw->job_pixbuf)
-               {
-               pixbuf_set_rect_fill(pw->job_pixbuf, 0, 0,
-                                    gdk_pixbuf_get_width(pw->job_pixbuf),
-                                    gdk_pixbuf_get_height(pw->job_pixbuf),
-                                    255, 255, 255, 255);
-               }
-
-       g_free(pw->job_path);
-       pw->job_path = NULL;
-
-       total = print_layout_page_count(pw);
-
-       if (!pw->output_path ||
-           page < 0 || page >= total) return FALSE;
-
-       if (total > 1)
-               {
-               const gchar *ext;
-               gchar *base;
-
-               ext = registered_extension_from_path(pw->output_path);
-
-               if (ext)
-                       {
-                       base = g_strndup(pw->output_path, ext - pw->output_path);
-                       }
-               else
-                       {
-                       base = g_strdup(pw->output_path);
-                       ext = "";
-                       }
-               pw->job_path = g_strdup_printf("%s_%03d%s", base, page + 1, ext);
-               g_free(base);
-               }
-       else
-               {
-               pw->job_path = g_strdup(pw->output_path);
-               }
-
-       if (isfile(pw->job_path))
-               {
-               gchar *buf;
-
-               buf = g_strdup_printf(_("A file with name %s already exists."), pw->job_path);
-               print_job_throw_error(pw, buf);
-               g_free(buf);
-
-               g_free(pw->job_path);
-               pw->job_path = NULL;
-               }
-
-       return (pw->job_path != NULL);
-}
-
-static gboolean print_job_rgb_page_done(PrintWindow *pw)
-{
-       gchar *pathl;
-       gboolean ret = FALSE;
-
-       if (!pw->job_pixbuf) return FALSE;
-
-       pathl = path_from_utf8(pw->job_path);
-
-       if (pw->output_format == PRINT_FILE_PNG)
-               {
-               ret = pixbuf_to_file_as_png(pw->job_pixbuf, pathl);
-               }
-       else
-               {
-               gint quality = 0;
-
-               switch (pw->output_format)
-                       {
-                       case PRINT_FILE_JPG_LOW:
-                               quality = 65;
-                               break;
-                       case PRINT_FILE_JPG_NORMAL:
-                               quality = 80;
-                               break;
-                       case PRINT_FILE_JPG_HIGH:
-                               quality = 95;
-                               break;
-                       default:
-                               break;
-                       }
-
-               if (quality > 0)
-                       {
-                       ret = pixbuf_to_file_as_jpg(pw->job_pixbuf, pathl, quality);
-                       }
-               }
-
-       g_free(pathl);
-
-       if (!ret)
-               {
-               gchar *buf;
-
-               buf = g_strdup_printf(_("Failure writing to file %s"), pw->job_path);
-               print_job_throw_error(pw, buf);
-               g_free(buf);
-               }
-
-       return ret;
-}
-
-static gboolean print_job_rgb_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
-                                        gdouble x, gdouble y, gdouble w, gdouble h,
-                                        gdouble offx, gdouble offy)
-{
-       gdouble sw, sh;
-       gdouble dw, dh;
-       gdouble rx, ry, rw, rh;
-
-       if (!pw->job_pixbuf) return FALSE;
-       if (!pixbuf) return TRUE;
-
-       sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
-       sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
-
-       dw = (gdouble)gdk_pixbuf_get_width(pw->job_pixbuf);
-       dh = (gdouble)gdk_pixbuf_get_height(pw->job_pixbuf);
-
-       if (clip_region(x, y, w, h,
-                       0.0, 0.0, dw, dh,
-                       &rx, &ry, &rw, &rh))
-               {
-               gdk_pixbuf_composite(pixbuf, pw->job_pixbuf, rx, ry, rw, rh,
-                                    x + offx, y + offy,
-                                    w / sw, h / sh,
-                                    (w / sw < 0.01 || h / sh < 0.01) ? GDK_INTERP_NEAREST : GDK_INTERP_BILINEAR, 255);
-               }
-
-       return TRUE;
-}
-
-static gdouble convert_pango_dpi(gdouble points)
-{
-       static gdouble dpi = 0.0;
-
-       if (dpi == 0.0)
-               {
-               GtkSettings *settings;
-               GObjectClass *klass;
-
-               settings = gtk_settings_get_default();
-               klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings));
-               if (g_object_class_find_property(klass, "gtk-xft-dpi"))
-                       {
-                       gint int_dpi;
-                       g_object_get(settings, "gtk-xft-dpi", &int_dpi, NULL);
-                       dpi = (gdouble)int_dpi / PANGO_SCALE;
-                       }
-
-               if (dpi < 25.0)
-                       {
-                       static gboolean warned = FALSE;
-                       gdouble fallback_dpi = 96.0;
-
-                       if (!warned)
-                               {
-                               if (dpi == 0.0)
-                                       {
-                                       log_printf("pango dpi unknown, assuming %.0f\n", fallback_dpi);
-                                       }
-                               else
-                                       {
-                                       log_printf("pango dpi reported as %.0f ignored, assuming %.0f\n", dpi, fallback_dpi);
-                                       }
-                               warned = TRUE;
-                               }
-
-                       dpi = fallback_dpi;
-                       }
-               }
-
-       if (dpi == 0) return points;
-       return points * 72.0 / dpi;
-}
-
-static gboolean print_job_rgb_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
-                                       gdouble x, gdouble y, gdouble width,
-                                       guint8 r, guint8 g, guint8 b)
-{
-       PangoLayout *layout;
-       PangoFontDescription *desc;
-       gint lw, lh;
-
-       if (!pw->job_pixbuf) return FALSE;
-
-       layout = gtk_widget_create_pango_layout(pw->dialog->dialog, NULL);
-
-       desc = pango_font_description_new();
-       pango_font_description_set_size(desc, convert_pango_dpi(point_size) * PANGO_SCALE);
-       pango_layout_set_font_description(layout, desc);
-       pango_font_description_free(desc);
-
-       pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
-       pango_layout_set_text(layout, text, -1);
-
-       pango_layout_get_pixel_size(layout, &lw, &lh);
-       x = x - (gdouble)lw / 2.0;
-
-       pixbuf_draw_layout(pw->job_pixbuf, layout, pw->dialog->dialog, x, y, r, g, b, 255);
-       g_object_unref(G_OBJECT(layout));
-
-       return TRUE;
-}
-
-static gboolean print_job_rgb_init(PrintWindow *pw)
-{
-       if (pw->job_pixbuf) g_object_unref(pw->job_pixbuf);
-       pw->job_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
-                                       (gint)pw->layout_width, (gint)pw->layout_height);
-
-       return print_job_rgb_page_new(pw, pw->job_page);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * print preview
- *-----------------------------------------------------------------------------
- */
-
-static gboolean print_job_preview_page_new(PrintWindow *pw, gint page)
-{
-       GdkPixbuf *pixbuf;
-       gint w, h;
-       gint l, r, t, b;
-
-       pixbuf = pw->job_pixbuf;
-       if (!pixbuf) return FALSE;
-
-       w = print_preview_unit(pw->layout_width);
-       h = print_preview_unit(pw->layout_height);
-       l = print_preview_unit(pw->margin_left);
-       r = print_preview_unit(pw->margin_right);
-       t = print_preview_unit(pw->margin_top);
-       b = print_preview_unit(pw->margin_bottom);
-
-       /* fill background */
-       pixbuf_set_rect_fill(pixbuf, 0, 0, w, h,
-                            255, 255, 255, 255);
-
-       /* draw cm or inch grid */
-       if (TRUE)
-               {
-               gdouble i;
-               gdouble grid;
-               PaperUnits units;
-
-               units = (pw->paper_units == PAPER_UNIT_MM ||
-                        pw->paper_units == PAPER_UNIT_CM) ? PAPER_UNIT_CM : PAPER_UNIT_INCH;
-
-               grid = print_paper_size_convert_units(1.0, units, PAPER_UNIT_POINTS);
-               for (i = grid ; i < pw->layout_width; i += grid)
-                       {
-                       pixbuf_draw_rect_fill(pixbuf, print_preview_unit(i), 0, 1, h, 0, 0, 0, 16);
-                       }
-               for (i = grid; i < pw->layout_height; i += grid)
-                       {
-                       pixbuf_draw_rect_fill(pixbuf, 0, print_preview_unit(i), w, 1, 0, 0, 0, 16);
-                       }
-               }
-
-       /* proof sheet grid */
-       if (pw->layout == PRINT_LAYOUT_PROOF)
-               {
-               gdouble i, j;
-               gdouble proof_w, proof_h;
-               gint uw, uh;
-
-               print_proof_size(pw, &proof_w, &proof_h);
-               uw = print_preview_unit(proof_w + PRINT_PREVIEW_SCALE - 0.1);
-               uh = print_preview_unit(proof_h + PRINT_PREVIEW_SCALE - 0.1);
-
-               for (i = 0; i < pw->proof_columns; i++)
-                   for (j = 0; j < pw->proof_rows; j++)
-                       {
-                       gint x, y;
-
-                       x = pw->margin_left + (pw->layout_width - pw->margin_left - pw->margin_right - (pw->proof_columns * proof_w)) / 2 + i * proof_w;
-                       y = pw->margin_top + j * proof_h;
-
-                       pixbuf_draw_rect(pixbuf, print_preview_unit(x), print_preview_unit(y), uw, uh,
-                                        255, 0, 0, 64, 1, 1, 1, 1);
-                       }
-               }
-
-       /* non-printable region (margins) */
-       pixbuf_draw_rect(pixbuf, 0, 0, w, h,
-                        0, 0, 0, 16,
-                        l, r, t, b);
-
-       /* margin lines */
-       pixbuf_draw_rect(pixbuf, l, 0, w - l - r, h,
-                        0, 0, 255, 128,
-                        1, 1, 0, 0);
-       pixbuf_draw_rect(pixbuf, 0, t, w, h - t - b,
-                        0, 0, 255, 128,
-                        0, 0, 1, 1);
-
-       /* border */
-       pixbuf_draw_rect(pixbuf, 0, 0, w, h,
-                        0, 0, 0, 255,
-                        1, 1, 1, 1);
-
-       image_area_changed(pw->layout_image, 0, 0, w, h);
-
-       return TRUE;
-}
-
-static gboolean print_job_preview_page_done(PrintWindow *pw)
-{
-       return TRUE;
-}
-
-static gboolean print_job_preview_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
-                                            gdouble x, gdouble y, gdouble w, gdouble h,
-                                            gdouble offx, gdouble offy)
-{
-       gdouble sw, sh;
-       gdouble dw, dh;
-       gdouble rx, ry, rw, rh;
-
-       if (!pw->job_pixbuf) return FALSE;
-       if (!pixbuf) return TRUE;
-
-       sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
-       sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
-
-       dw = (gdouble)gdk_pixbuf_get_width(pw->job_pixbuf);
-       dh = (gdouble)gdk_pixbuf_get_height(pw->job_pixbuf);
-
-       x = print_preview_unit(x);
-       y = print_preview_unit(y);
-       w = print_preview_unit(w);
-       h = print_preview_unit(h);
-       offx = print_preview_unit(offx);
-       offy = print_preview_unit(offy);
-
-       if (clip_region(x, y, w, h,
-                       0.0, 0.0, dw, dh,
-                       &rx, &ry, &rw, &rh))
-               {
-               gdk_pixbuf_composite(pixbuf, pw->job_pixbuf, rx, ry, rw, rh,
-                                    x + offx, y + offy,
-                                    w / sw, h / sh,
-                                    (w / sw < 0.01 || h / sh < 0.01) ? GDK_INTERP_NEAREST : GDK_INTERP_BILINEAR, 255);
-
-               image_area_changed(pw->layout_image, rx, ry, rw, rh);
-               }
-
-       return TRUE;
-}
-
-static gboolean print_job_preview_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
-                                           gdouble x, gdouble y, gdouble width,
-                                           guint8 r, guint8 g, guint8 b)
-{
-       PangoLayout *layout;
-       PangoFontDescription *desc;
-       gint lw, lh;
-       GdkPixbuf *pixbuf;
-
-       if (!pw->job_pixbuf) return FALSE;
-
-       layout = gtk_widget_create_pango_layout(pw->dialog->dialog, NULL);
-
-       desc = pango_font_description_new();
-       pango_font_description_set_size(desc, convert_pango_dpi(point_size) * PANGO_SCALE);
-       pango_layout_set_font_description(layout, desc);
-       pango_font_description_free(desc);
-
-       pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
-       pango_layout_set_text(layout, text, -1);
-
-       pango_layout_get_pixel_size(layout, &lw, &lh);
-       x = x - (gdouble)lw / 2.0;
-
-       pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, lw, lh);
-       pixbuf_set_rect_fill(pixbuf, 0, 0, lw, lh, 0, 0, 0, 0);
-       pixbuf_draw_layout(pixbuf, layout, pw->dialog->dialog, 0, 0, r, g, b, 255);
-       g_object_unref(G_OBJECT(layout));
-
-       print_job_preview_page_image(pw, pixbuf, x, y, (gdouble)lw, (gdouble)lh, 0, 0);
-       g_object_unref(pixbuf);
-
-       return TRUE;
-}
-
-static gboolean print_job_preview_init(PrintWindow *pw)
-{
-       if (pw->job_pixbuf) g_object_unref(pw->job_pixbuf);
-       pw->job_pixbuf = image_get_pixbuf(pw->layout_image);
-       g_object_ref(pw->job_pixbuf);
-
-       return print_job_preview_page_new(pw, pw->job_page);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * wrappers
- *-----------------------------------------------------------------------------
- */
-
-static gboolean print_job_page_new(PrintWindow *pw)
-{
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       return print_job_rgb_page_new(pw, pw->job_page);
-               case RENDER_FORMAT_PS:
-                       return print_job_ps_page_new(pw, pw->job_page);
-               case RENDER_FORMAT_PREVIEW:
-                       return print_job_preview_page_new(pw, pw->job_page);
-               }
-
-       return FALSE;
-}
-
-static gboolean print_job_page_done(PrintWindow *pw)
-{
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       return print_job_rgb_page_done(pw);
-               case RENDER_FORMAT_PS:
-                       return print_job_ps_page_done(pw);
-               case RENDER_FORMAT_PREVIEW:
-                       return print_job_preview_page_done(pw);
-               }
-
-       return FALSE;
-}
-
-static gboolean print_job_page_image(PrintWindow *pw, GdkPixbuf *pixbuf,
-                                    gdouble x, gdouble y, gdouble w, gdouble h,
-                                    gdouble offx, gdouble offy)
-{
-       gboolean success = FALSE;
-
-       if (w <= 0.0 || h <= 0.0) return TRUE;
-
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       success = print_job_rgb_page_image(pw, pixbuf, x, y, w, h, offx, offy);
-                       break;
-               case RENDER_FORMAT_PS:
-                       success = print_job_ps_page_image(pw, pixbuf, x, y, w, h, offx, offy);
-                       break;
-               case RENDER_FORMAT_PREVIEW:
-                       success = print_job_preview_page_image(pw, pixbuf, x, y, w, h, offx, offy);
-                       break;
-               }
-
-       return success;
-}
-
-static gboolean print_job_page_text(PrintWindow *pw, const gchar *text, gdouble point_size,
-                                   gdouble x, gdouble y, gdouble width,
-                                   guint8 r, guint8 g, guint8 b)
-{
-       gboolean success = TRUE;
-
-       if (!text) return TRUE;
-
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       success = print_job_rgb_page_text(pw, text, point_size, x, y, width, r, g, b);
-                       break;
-               case RENDER_FORMAT_PS:
-                       success = print_job_ps_page_text(pw, text, point_size, x, y, width, r, g, b);
-                       break;
-               case RENDER_FORMAT_PREVIEW:
-                       success = print_job_preview_page_text(pw, text, point_size, x, y, width, r, g, b);
-                       break;
-               }
-
-       return success;
-}
-
-/*
- *-----------------------------------------------------------------------------
- * print ?
- *-----------------------------------------------------------------------------
- */
-
-static gboolean print_job_render_image(PrintWindow *pw);
-static gboolean print_job_render_proof(PrintWindow *pw);
-
-
-static void print_job_status(PrintWindow *pw)
-{
-       gdouble value;
-       gint page;
-       gint total;
-       gchar *buf;
-
-       if (!pw->job_progress) return;
-
-       page = pw->job_page;
-       total = print_layout_page_count(pw);
-
-       if (pw->layout == PRINT_LAYOUT_PROOF && pw->proof_point)
-               {
-               GList *start;
-
-               start = g_list_first(pw->proof_point);
-               value = (gdouble)g_list_position(start, pw->proof_point) / g_list_length(start);
-               }
-       else
-               {
-               value = (total > 0) ? (gdouble)page / total : 0.0;
-               }
-
-       buf = g_strdup_printf(_("Page %d"), page + 1);
-       gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pw->job_progress), buf);
-       g_free(buf);
-
-       if (pw->job_path && pw->job_progress_label)
-               {
-               gtk_label_set_text(GTK_LABEL(pw->job_progress_label), pw->job_path);
-               }
-
-       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pw->job_progress), value);
-}
-
-static void print_job_throw_error(PrintWindow *pw, const gchar *message)
-{
-       GenericDialog *gd;
-       GtkWidget *parent = NULL;
-       GtkWidget *group;
-       GtkWidget *label;
-       gchar *buf;
-
-       if (gtk_widget_get_visible(pw->dialog->dialog)) parent = pw->dialog->dialog;
-
-       gd = generic_dialog_new(_("Printing error"), "print_warning",
-                               parent, TRUE, NULL, NULL);
-       generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, NULL, TRUE);
-
-       buf = g_strdup_printf(_("An error occurred printing to %s."), print_output_name(pw->output));
-       generic_dialog_add_message(gd, GTK_STOCK_DIALOG_ERROR, _("Printing error"), buf, TRUE);
-       g_free(buf);
-
-       group = pref_group_new(gd->vbox, FALSE, _("Details"), GTK_ORIENTATION_VERTICAL);
-       label = pref_label_new(group, message);
-       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
-       gtk_widget_show(gd->dialog);
-}
-
-static void print_job_done(PrintWindow *pw)
-{
-       print_job_close(pw, FALSE);
-}
-
-static gboolean print_job_text_image(PrintWindow *pw, const gchar *path,
-                                    gdouble x, gdouble y, gdouble width,
-                                    gint sw, gint sh, gint proof)
-{
-       GString *string;
-       gboolean space = FALSE;
-       gboolean newline = FALSE;
-       gboolean ret;
-
-       if (pw->text_fields == 0) return TRUE;
-
-       string = g_string_new("");
-       path = image_loader_get_fd(pw->job_loader)->path;
-
-       if (pw->text_fields & TEXT_INFO_FILENAME)
-               {
-               if (pw->text_fields & TEXT_INFO_FILEPATH)
-                       g_string_append(string, path);
-               else
-                       g_string_append(string, filename_from_path(path));
-               newline = TRUE;
-               }
-       else if (pw->text_fields & TEXT_INFO_FILEPATH)
-               {
-               gchar *dirname = g_path_get_dirname(path);
-
-               g_string_append_printf(string, "%s%s", dirname, G_DIR_SEPARATOR_S);
-               g_free(dirname);
-               newline = TRUE;
-               }
-       if (pw->text_fields & TEXT_INFO_DIMENSIONS)
-               {
-               if (newline) g_string_append(string, "\n");
-               g_string_append_printf(string, "%d x %d", (gint)sw, (gint)sh);
-               newline = proof;
-               space = !proof;
-               }
-       if (pw->text_fields & TEXT_INFO_FILEDATE)
-               {
-               if (newline)  g_string_append(string, "\n");
-               if (space) g_string_append(string, " - ");
-               g_string_append(string, text_from_time(filetime(image_loader_get_fd(pw->job_loader)->path)));
-               newline = proof;
-               space = !proof;
-               }
-       if (pw->text_fields & TEXT_INFO_FILESIZE)
-               {
-               gchar *size;
-
-               if (newline)  g_string_append(string, "\n");
-               if (space) g_string_append(string, " - ");
-               size = text_from_size_abrev(filesize(image_loader_get_fd(pw->job_loader)->path));
-               g_string_append(string, size);
-               g_free(size);
-               }
-
-       ret = print_job_page_text(pw, string->str, pw->text_points, x, y, width,
-                                 pw->text_r, pw->text_g, pw->text_b);
-
-       g_string_free(string, TRUE);
-
-       return ret;
-}
-
-static void print_job_render_image_loader_done(ImageLoader *il, gpointer data)
-{
-       PrintWindow *pw = data;
-       GdkPixbuf *pixbuf;
-       gboolean success = TRUE;
-
-       pixbuf = image_loader_get_pixbuf(il);
-       if (pixbuf)
-               {
-               gdouble sw, sh;
-               gdouble dw, dh;
-               gdouble x, y, w, h;
-               gdouble offx, offy;
-
-               sw = (gdouble)gdk_pixbuf_get_width(pixbuf);
-               sh = (gdouble)gdk_pixbuf_get_height(pixbuf);
-
-               dw = pw->layout_width - pw->margin_left - pw->margin_right;
-               dh = pw->layout_height - pw->margin_top - pw->margin_bottom;
-
-               if (dw / sw < dh / sh)
-                       {
-                       w = dw;
-                       h = dw / sw * sh;
-                       }
-               else
-                       {
-                       h = dh;
-                       w = dh / sh *sw;
-                       }
-
-               if (pw->image_scale >= 5.0)
-                       {
-                       w = w * pw->image_scale / 100.0;
-                       h = h * pw->image_scale / 100.0;
-                       }
-
-               x = pw->margin_left + (dw / 2) - (w / 2);
-               y = pw->margin_top + (dh / 2) - (h / 2);
-
-               offx = offy = 0;
-
-               if (x < 0)
-                       {
-                       w += x;
-                       offx = x;
-                       x = 0;
-                       }
-               if (x + w >= pw->layout_width) w = pw->layout_width - x;
-
-               if (y < 0)
-                       {
-                       h += y;
-                       offy = y;
-                       y = 0;
-                       }
-               if (y + h >= pw->layout_height) h = pw->layout_height - y;
-
-               success = (success &&
-                          print_job_page_image(pw, pixbuf, x, y, w, h, offx, offy));
-
-               x = x + w / 2;
-               y = y + h + PRINT_TEXT_PADDING;
-
-               success = (success &&
-                          print_job_text_image(pw, image_loader_get_fd(pw->job_loader)->path, x, y, dw, sw, sh, FALSE));
-               }
-
-       image_loader_free(pw->job_loader);
-       pw->job_loader = NULL;
-
-       if (pw->job_format == RENDER_FORMAT_PREVIEW)
-               {
-               print_job_done(pw);
-               return;
-               }
-
-       success = (success && print_job_page_done(pw));
-       if (!success)
-               {
-               print_job_close(pw, TRUE);
-               return;
-               }
-
-       pw->job_page++;
-       print_job_status(pw);
-
-       if (print_job_render_image(pw))
-               {
-               if (!print_job_page_new(pw)) print_job_close(pw, TRUE);
-               }
-       else
-               {
-               print_job_done(pw);
-               }
-}
-
-static gboolean print_job_render_image(PrintWindow *pw)
-{
-       FileData *fd = NULL;
-
-       switch (pw->source)
-               {
-               case PRINT_SOURCE_SELECTION:
-                       fd = g_list_nth_data(pw->source_selection, pw->job_page);
-                       break;
-               case PRINT_SOURCE_ALL:
-                       fd = g_list_nth_data(pw->source_list, pw->job_page);
-                       break;
-               case PRINT_SOURCE_IMAGE:
-               default:
-                       if (pw->job_page == 0) fd = pw->source_fd;
-                       break;
-               }
-
-       image_loader_free(pw->job_loader);
-       pw->job_loader = NULL;
-
-       if (!fd) return FALSE;
-
-       pw->job_loader = image_loader_new(fd);
-       g_signal_connect(G_OBJECT(pw->job_loader), "done", (GCallback)print_job_render_image_loader_done, pw);
-       if (!image_loader_start(pw->job_loader))
-               {
-               image_loader_free(pw->job_loader);
-               pw->job_loader= NULL;
-               }
-
-       return TRUE;
-}
-
-static void print_job_render_proof_loader_done(ImageLoader *il, gpointer data)
-{
-       PrintWindow *pw = data;
-       GdkPixbuf *pixbuf;
-       gdouble x, y;
-       gdouble w, h;
-       gdouble proof_w, proof_h;
-       gdouble icon_w, icon_h;
-       gboolean success = TRUE;
-
-       if (pw->proof_columns < 1 || pw->proof_rows < 1)
-               {
-               image_loader_free(pw->job_loader);
-               pw->job_loader = NULL;
-
-               print_job_done(pw);
-
-               return;
-               }
-
-       pixbuf = image_loader_get_pixbuf(il);
-
-       if (options->image.exif_proof_rotate_enable == TRUE) {
-               pixbuf = pixbuf_apply_orientation(pixbuf, il->fd->exif_orientation);
-       }
-
-       w = gdk_pixbuf_get_width(pixbuf);
-       h = gdk_pixbuf_get_height(pixbuf);
-
-       if (pw->proof_width / w < pw->proof_height / h)
-               {
-               icon_w = pw->proof_width;
-               icon_h = pw->proof_width / w * h;
-               }
-       else
-               {
-               icon_h = pw->proof_height;
-               icon_w = pw->proof_height / h * w;
-               }
-
-       y = pw->proof_position / pw->proof_columns;
-       x = pw->proof_position - (y * pw->proof_columns);
-
-       print_proof_size(pw, &proof_w, &proof_h);
-
-       x *= proof_w;
-       y *= proof_h;
-       x += pw->margin_left + (pw->layout_width - pw->margin_left - pw->margin_right - (pw->proof_columns * proof_w)) / 2 + (proof_w - icon_w) / 2;
-       y += pw->margin_top + PRINT_PROOF_MARGIN + (pw->proof_height - icon_h) / 2;
-
-       success = (success &&
-                  print_job_page_image(pw, pixbuf, x, y, icon_w, icon_h, 0, 0));
-
-       x = x + icon_w / 2;
-       y = y + icon_h + (pw->proof_height - icon_h) / 2 + PRINT_TEXT_PADDING;
-
-       success = (success &&
-                  print_job_text_image(pw, image_loader_get_fd(pw->job_loader)->path, x, y, icon_w + PRINT_PROOF_MARGIN * 2, w, h, TRUE));
-
-       if (!success)
-               {
-               print_job_close(pw, TRUE);
-               return;
-               }
-
-       if (pw->proof_point) pw->proof_point = pw->proof_point->next;
-
-       pw->proof_position++;
-       if (pw->proof_position >= pw->proof_columns * pw->proof_rows)
-               {
-               if (pw->job_format == RENDER_FORMAT_PREVIEW)
-                       {
-                       print_job_done(pw);
-                       return;
-                       }
-
-               if (!print_job_page_done(pw))
-                       {
-                       print_job_close(pw, TRUE);
-                       return;
-                       }
-
-               pw->proof_position = 0;
-               pw->job_page++;
-               if (print_job_render_proof(pw))
-                       {
-                       if (!print_job_page_new(pw))
-                               {
-                               print_job_close(pw, TRUE);
-                               return;
-                               }
-                       print_job_status(pw);
-                       }
-               else
-                       {
-                       print_job_done(pw);
-                       }
-               }
-       else
-               {
-               if (print_job_render_proof(pw))
-                       {
-                       print_job_status(pw);
-                       }
-               else
-                       {
-                       if (print_job_page_done(pw))
-                               {
-                               print_job_done(pw);
-                               }
-                       else
-                               {
-                               print_job_close(pw, TRUE);
-                               }
-                       }
-               }
-}
-
-static gboolean print_job_render_proof(PrintWindow *pw)
-{
-       FileData *fd = NULL;
-
-       if (pw->proof_columns < 1 || pw->proof_rows < 1) return FALSE;
-
-       if (!pw->proof_point && pw->proof_position == 0 && pw->source == PRINT_SOURCE_IMAGE)
-               {
-               fd = pw->source_fd;
-               }
-       else if (pw->proof_point &&
-                pw->proof_position < pw->proof_columns * pw->proof_rows)
-               {
-               fd = pw->proof_point->data;
-               }
-
-       if (!fd) return FALSE;
-
-       image_loader_free(pw->job_loader);
-       pw->job_loader = image_loader_new(fd);
-       g_signal_connect(G_OBJECT(pw->job_loader), "done", (GCallback)print_job_render_proof_loader_done, pw);
-       if (!image_loader_start(pw->job_loader))
-               {
-               image_loader_free(pw->job_loader);
-               pw->job_loader = NULL;
-               }
-
-       return TRUE;
-}
-
-static void print_job_render(PrintWindow *pw)
-{
-       gdouble proof_w, proof_h;
-       gboolean finished;
-
-       pw->proof_position = 0;
-
-       switch (pw->source)
-               {
-               case PRINT_SOURCE_SELECTION:
-                       pw->proof_point = pw->source_selection;
-                       break;
-               case PRINT_SOURCE_ALL:
-                       pw->proof_point = pw->source_list;
-                       break;
-               case PRINT_SOURCE_IMAGE:
-               default:
-                       pw->proof_point = NULL;
-                       break;
-               }
-
-       print_proof_size(pw, &proof_w, &proof_h);
-       pw->proof_columns = (pw->layout_width - pw->margin_left - pw->margin_right) / proof_w;
-       pw->proof_rows = (pw->layout_height - pw->margin_top - pw->margin_bottom) / proof_h;
-
-       if (pw->job_format == RENDER_FORMAT_PREVIEW)
-               {
-               gint total;
-
-               total = print_layout_page_count(pw);
-               if (pw->job_page < 0 || pw->job_page >= total)
-                       {
-                       print_job_done(pw);
-                       return;
-                       }
-
-               if (pw->proof_point && pw->job_page > 0)
-                       {
-                       pw->proof_point = g_list_nth(pw->proof_point, pw->job_page * pw->proof_columns * pw->proof_rows);
-                       }
-               }
-
-       if (!print_job_page_new(pw))
-               {
-               print_job_close(pw, TRUE);
-               return;
-               }
-
-       if (pw->layout == PRINT_LAYOUT_IMAGE)
-               {
-               finished = !print_job_render_image(pw);
-               }
-       else
-               {
-               finished = !print_job_render_proof(pw);
-               }
-
-       if (finished) print_job_done(pw);
-}
-
-static gboolean print_job_init(PrintWindow *pw)
-{
-       gboolean success = FALSE;
-
-       pw->job_page = 0;
-
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       success = print_job_rgb_init(pw);
-                       break;
-               case RENDER_FORMAT_PS:
-                       success = print_job_ps_init(pw);
-                       break;
-               case RENDER_FORMAT_PREVIEW:
-                       pw->job_page = pw->proof_page;
-                       success = print_job_preview_init(pw);
-                       break;
-               }
-
-       return success;
-}
-
-static gboolean print_job_finish(PrintWindow *pw)
-{
-       gboolean success = FALSE;
-
-       switch (pw->job_format)
-               {
-               case RENDER_FORMAT_RGB:
-                       success = TRUE;
-                       break;
-               case RENDER_FORMAT_PS:
-                       print_job_ps_end(pw);
-                       break;
-               case RENDER_FORMAT_PREVIEW:
-                       success = TRUE;
-                       break;
-               }
-
-       return success;
-}
-
-static void print_job_close_file(PrintWindow *pw)
-{
-       if (pw->job_file)
-               {
-               fclose(pw->job_file);
-               pw->job_file = NULL;
-               }
-
-       if (pw->job_pipe)
-               {
-               PipeError *pe;
-
-               pe = pipe_handler_new();
-               pclose(pw->job_pipe);
-               pipe_handler_free(pe);
-
-               pw->job_pipe = NULL;
-               }
-}
-
-static gboolean print_job_close_finish_cb(gpointer data)
-{
-       PrintWindow *pw = data;
-
-       print_window_close(pw);
-       return FALSE;
-}
-
-static void print_job_close(PrintWindow *pw, gint error)
-{
-       if (!error) print_job_finish(pw);
-
-       print_job_close_file(pw);
-       g_free(pw->job_path);
-       pw->job_path = NULL;
-
-       if (pw->job_dialog)
-               {
-               generic_dialog_close(pw->job_dialog);
-               pw->job_dialog = NULL;
-               pw->job_progress = NULL;
-               }
-
-       image_loader_free(pw->job_loader);
-       pw->job_loader = NULL;
-
-       if (pw->job_pixbuf)
-               {
-               g_object_unref(pw->job_pixbuf);
-               pw->job_pixbuf = NULL;
-               }
-
-       if (pw->dialog && !gtk_widget_get_visible(pw->dialog->dialog))
-               {
-               g_idle_add_full(G_PRIORITY_HIGH_IDLE, print_job_close_finish_cb, pw, NULL);
-               }
-}
-
-static void print_job_cancel_cb(GenericDialog *gd, gpointer data)
-{
-       PrintWindow *pw = data;
-
-       print_job_close(pw, FALSE);
-}
-
-static void print_pref_store(PrintWindow *pw)
-{
-
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_SAVE, pw->save_settings);
-
-       if (!pw->save_settings) return;
-
-       /* only store values that are actually used in this print job, hence the if()s */
-
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_OUTPUT, pw->output);
-
-       if (pw->output == PRINT_OUTPUT_RGB_FILE)
-               {
-               pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_FORMAT, pw->output_format);
-               }
-
-       if (pw->job_format == RENDER_FORMAT_PS)
-               {
-               pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_DPI, pw->max_dpi);
-               }
-
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_UNITS, pw->paper_units);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_SIZE, pw->paper_size);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_ORIENTATION, pw->paper_orientation);
-
-       if (pw->paper_size == 0)
-               {
-               pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_CUSTOM_WIDTH, pw->paper_width);
-               pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_CUSTOM_HEIGHT, pw->paper_height);
-               }
-
-       pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_LEFT, pw->margin_left);
-       pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_RIGHT, pw->margin_right);
-       pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_TOP, pw->margin_top);
-       pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_MARGIN_BOTTOM, pw->margin_bottom);
-
-       if (pw->layout == PRINT_LAYOUT_PROOF)
-               {
-               pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_PROOF_WIDTH, pw->proof_width);
-               pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_PROOF_HEIGHT, pw->proof_height);
-               }
-
-       if (pw->output == PRINT_OUTPUT_PS_CUSTOM)
-               {
-               pref_list_string_set(PRINT_PREF_GROUP, PRINT_PREF_PRINTERC, pw->output_custom);
-               }
-
-       if (pw->output == PRINT_OUTPUT_RGB_FILE ||
-           pw->output == PRINT_OUTPUT_PS_FILE)
-               {
-               tab_completion_append_to_history(pw->path_entry, pw->output_path);
-               }
-
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_TEXT, pw->text_fields);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_TEXTSIZE, pw->text_points);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_TEXTCOLOR_R, pw->text_r);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_TEXTCOLOR_G, pw->text_g);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_TEXTCOLOR_B, pw->text_b);
-
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_SOURCE, pw->source);
-       pref_list_int_set(PRINT_PREF_GROUP, PRINT_PREF_LAYOUT, pw->layout);
-
-       pref_list_double_set(PRINT_PREF_GROUP, PRINT_PREF_IMAGE_SCALE, pw->image_scale);
-}
-
-static gboolean print_job_start(PrintWindow *pw, RenderFormat format, PrintOutput output)
-{
-       GtkWidget *hbox;
-       GtkWidget *spinner;
-       gchar *msg;
-
-       if (pw->job_dialog) return FALSE;
-
-       pw->job_format = format;
-       pw->job_output = output;
-
-       if (!print_job_init(pw))
-               {
-               print_job_close(pw, TRUE);
-               return FALSE;
-               }
-
-       if (format == RENDER_FORMAT_PREVIEW)
-               {
-               print_job_render(pw);
-               return TRUE;
-               }
-
-       print_pref_store(pw);
-
-       gtk_widget_hide(pw->dialog->dialog);
-
-       pw->job_dialog = file_util_gen_dlg(_("Print"), "print_job_dialog",
-                                          (GtkWidget *)gtk_window_get_transient_for(GTK_WINDOW(pw->dialog->dialog)), FALSE,
-                                          print_job_cancel_cb, pw);
-
-       msg = g_strdup_printf(_("Printing %d pages to %s."), print_layout_page_count(pw), print_output_name(pw->output));
-       generic_dialog_add_message(pw->job_dialog, NULL, msg, NULL, TRUE);
-       g_free(msg);
-
-       if (pw->job_output == PRINT_OUTPUT_PS_FILE ||
-           pw->job_output == PRINT_OUTPUT_RGB_FILE)
-               {
-               hbox = pref_box_new(pw->job_dialog->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
-               pref_label_new(hbox, _("Filename:"));
-
-               pw->job_progress_label = pref_label_new(hbox, "");
-               }
-       else
-               {
-               pw->job_progress_label = NULL;
-               }
-
-       pref_spacer(pw->job_dialog->vbox, PREF_PAD_SPACE);
-
-       hbox = pref_box_new(pw->job_dialog->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
-
-       pw->job_progress = gtk_progress_bar_new();
-       gtk_box_pack_start(GTK_BOX(hbox), pw->job_progress, TRUE, TRUE, 0);
-       gtk_widget_show(pw->job_progress);
-
-       spinner = spinner_new(NULL, SPINNER_SPEED);
-       gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0);
-       gtk_widget_show(spinner);
-
-       gtk_widget_show(pw->job_dialog->dialog);
-
-       print_job_render(pw);
-       print_job_status(pw);
-
-       return TRUE;
-}
-
-static void print_window_print_start(PrintWindow *pw)
-{
-       RenderFormat format;
-
-       switch (pw->output)
-               {
-               case PRINT_OUTPUT_RGB_FILE:
-                       format = RENDER_FORMAT_RGB;
-                       break;
-               case PRINT_OUTPUT_PS_FILE:
-               case PRINT_OUTPUT_PS_CUSTOM:
-               case PRINT_OUTPUT_PS_LPR:
-               default:
-                       format = RENDER_FORMAT_PS;
-                       break;
-               }
-
-       print_job_start(pw, format, pw->output);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * combo box util
- *-----------------------------------------------------------------------------
- */
-
-static GtkWidget *print_combo_menu(const gchar *text[], gint count, gint preferred,
-                                  GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-       gint i;
-
-       combo = gtk_combo_box_text_new();
-
-       for (i = 0 ; i < count; i++)
-               {
-               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _(text[i]));
-               }
-
-       if (preferred >= 0 && preferred < count)
-               {
-               gtk_combo_box_set_active(GTK_COMBO_BOX(combo), preferred);
-               }
-
-       if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
-
-       return combo;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * paper selection
- *-----------------------------------------------------------------------------
- */
-
-static GtkWidget *print_paper_menu(GtkWidget *table, gint column, gint row,
-                                  PaperOrientation preferred, GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-       gint i;
-
-       pref_table_label(table, column, row, (_("Format:")), 1.0);
-
-       combo = gtk_combo_box_text_new();
-
-       i = 0;
-       while (print_paper_sizes[i].description)
-               {
-               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _(print_paper_sizes[i].description));
-               i++;
-               }
-
-       gtk_combo_box_set_active(GTK_COMBO_BOX(combo), preferred);
-       if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_paper_select_cb(GtkWidget *combo, gpointer data)
-{
-       PrintWindow *pw = data;
-       PaperSize *ps;
-       gint n;
-
-       n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-       ps = print_paper_size_nth(n);
-
-       if (!ps) return;
-
-       pw->paper_size = n;
-
-       if (pw->paper_size == 0)
-               {
-               print_window_layout_sync_paper(pw);
-               return;
-               }
-
-       if (ps->orientation == PAPER_ORIENTATION_PORTRAIT)
-               {
-               print_window_layout_set_size(pw, ps->width, ps->height);
-               }
-       else
-               {
-               print_window_layout_set_size(pw, ps->height, ps->width);
-               }
-}
-
-static void print_paper_size_cb(GtkWidget *spin, gpointer data)
-{
-       PrintWindow *pw = data;
-       gdouble value;
-
-       value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
-                                              pw->paper_units, PAPER_UNIT_POINTS);
-
-       if (spin == pw->paper_width_spin)
-               {
-               pw->paper_width = value;
-               }
-       else
-               {
-               pw->paper_height = value;
-               }
-
-       print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
-}
-
-static GtkWidget *print_paper_units_menu(GtkWidget *table, gint column, gint row,
-                                        PaperUnits units, GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-
-       pref_table_label(table, column, row, (_("Units:")), 1.0);
-
-       combo = print_combo_menu(print_paper_units, PAPER_UNIT_COUNT, units, func, data);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_paper_units_set(PrintWindow *pw, PaperUnits units)
-{
-       PaperUnits old_units;
-
-       if (units >= PAPER_UNIT_COUNT) return;
-
-       old_units = pw->paper_units;
-       pw->paper_units = units;
-       print_window_layout_sync_paper(pw);
-
-       if ((units == PAPER_UNIT_MM || units == PAPER_UNIT_CM) !=
-           (old_units == PAPER_UNIT_MM || old_units == PAPER_UNIT_CM))
-               {
-               print_window_layout_render(pw);
-               }
-}
-
-static void print_paper_units_cb(GtkWidget *combo, gpointer data)
-{
-       PrintWindow *pw = data;
-       PaperUnits units;
-
-       units = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-
-       print_paper_units_set(pw, units);
-}
-
-static GtkWidget *print_paper_orientation_menu(GtkWidget *table, gint column, gint row,
-                                              PaperOrientation preferred,
-                                              GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-
-       pref_table_label(table, column, row, (_("Orientation:")), 1.0);
-
-       combo = print_combo_menu(print_paper_orientation, PAPER_ORIENTATION_COUNT, preferred, func, data);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_paper_orientation_cb(GtkWidget *combo, gpointer data)
-{
-       PrintWindow *pw = data;
-       PaperOrientation o;
-
-       o = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-
-       print_window_layout_set_orientation(pw, o);
-}
-
-static void print_paper_margin_cb(GtkWidget *spin, gpointer data)
-{
-       PrintWindow *pw = data;
-       gdouble value;
-
-       value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
-                                              pw->paper_units, PAPER_UNIT_POINTS);
-
-       if (spin == pw->margin_left_spin)
-               {
-               pw->margin_left = CLAMP(value, 0.0, pw->paper_width);
-               }
-       else if (spin == pw->margin_right_spin)
-               {
-               pw->margin_right = CLAMP(value, 0.0, pw->paper_width);
-               }
-       else if (spin == pw->margin_top_spin)
-               {
-               pw->margin_top = CLAMP(value, 0.0, pw->paper_height);
-               }
-       else if (spin == pw->margin_bottom_spin)
-               {
-               pw->margin_bottom = CLAMP(value, 0.0, pw->paper_height);
-               }
-
-       print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
-}
-
-static GtkWidget *print_misc_menu(GtkWidget *parent_box, gint preferred,
-                                 const gchar *title, const gchar *key,
-                                 gint count, const gchar **text,
-                                 GCallback func, gpointer data)
-{
-       GtkWidget *box;
-       GtkWidget *button = NULL;
-       gint i;
-
-       box = pref_group_new(parent_box, FALSE, title, GTK_ORIENTATION_VERTICAL);
-
-       for (i = 0; i < count; i++)
-               {
-               button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(button), _(text[i]));
-               if (i == preferred)
-                       {
-                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
-                       }
-               g_object_set_data(G_OBJECT(button), key, GINT_TO_POINTER(i));
-               if (func) g_signal_connect(G_OBJECT(button), "clicked", func, data);
-               gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
-               gtk_widget_show(button);
-               }
+/* method to use when scaling down image data */
+#define PRINT_MAX_INTERP GDK_INTERP_HYPER
 
-       return box;
-}
+typedef enum {
+       TEXT_INFO_FILENAME = 1 << 0,
+       TEXT_INFO_FILEDATE = 1 << 1,
+       TEXT_INFO_FILESIZE = 1 << 2,
+       TEXT_INFO_DIMENSIONS = 1 << 3,
+       TEXT_INFO_FILEPATH = 1 << 4
+} TextInfo;
 
-static void print_source_select_cb(GtkWidget *widget, gpointer data)
+typedef struct _PrintWindow PrintWindow;
+struct _PrintWindow
 {
-       PrintWindow *pw = data;
+       GtkWidget *vbox;
+       GList *source_selection;
 
-       if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
+       TextInfo        text_fields;
+       gint             job_page;
+       ImageLoader     *job_loader;
 
-       pw->source = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "print_source"));
-       print_window_layout_size(pw);
-}
+       GList *print_pixbuf_queue;
+       gboolean job_render_finished;
+};
 
-static void print_layout_select_cb(GtkWidget *widget, gpointer data)
+static gint print_layout_page_count(PrintWindow *pw)
 {
-       PrintWindow *pw = data;
+       gint images;
 
-       if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
+       images = g_list_length(pw->source_selection);
 
-       pw->layout = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "print_layout"));
+       if (images < 1 ) return 0;
 
-       print_window_layout_sync_layout(pw);
-       print_window_layout_size(pw);
+       return images;
 }
 
-static void print_image_scale_cb(GtkWidget *spin, gpointer data)
-{
-       PrintWindow *pw = data;
-
-       pw->image_scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
-
-       print_window_layout_set_size(pw, pw->paper_width, pw->paper_height);
-}
+static gboolean print_job_render_image(PrintWindow *pw);
 
-static void print_proof_size_cb(GtkWidget *spin, gpointer data)
+static void print_job_render_image_loader_done(ImageLoader *il, gpointer data)
 {
        PrintWindow *pw = data;
-       gdouble value;
-
-       value = print_paper_size_convert_units(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)),
-                                              pw->paper_units, PAPER_UNIT_POINTS);
-
-       if (spin == pw->proof_width_spin)
-               {
-               pw->proof_width = value;
-               }
-       else
-               {
-               pw->proof_height = value;
-               }
-
-       print_window_layout_render(pw);
-}
-
-static GtkWidget *print_output_menu(GtkWidget *table, gint column, gint row,
-                                   PrintOutput preferred, GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-
-       pref_table_label(table, column, row, (_("Destination:")), 1.0);
-
-       combo = print_combo_menu(print_output_text, PRINT_OUTPUT_COUNT, preferred, func, data);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_custom_entry_set(PrintWindow *pw, GtkWidget *combo)
-{
-       GtkListStore *store;
-       const gchar *text;
-       GList *list;
-       GList *work;
-
-       store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
-       gtk_list_store_clear(store);
-
-       list = print_window_list_printers();
-       work = list;
-       while (work)
-               {
-               gchar *name;
-               gchar *buf;
-
-               name = work->data;
-               work = work->next;
-
-               buf = g_strdup_printf(PRINT_LPR_CUSTOM, name);
-               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
-               g_free(buf);
-               }
-       string_list_free(list);
+       GdkPixbuf *pixbuf;
 
-       if (pref_list_string_get(PRINT_PREF_GROUP, PRINT_PREF_PRINTERC, &text))
-               {
-               gtk_entry_set_text(GTK_ENTRY(pw->custom_entry), text);
-               }
-       else
-               {
-               text = gtk_entry_get_text(GTK_ENTRY(pw->custom_entry));
-               if (!text || strlen(text) == 0)
-                       {
-                       gchar *buf;
+       pixbuf = image_loader_get_pixbuf(il);
 
-                       buf = g_strdup_printf(PRINT_LPR_CUSTOM, _("<printer name>"));
-                       gtk_entry_set_text(GTK_ENTRY(pw->custom_entry), buf);
-                       g_free(buf);
-                       }
-               }
-}
+       g_object_ref(pixbuf);
+       pw->print_pixbuf_queue = g_list_append(pw->print_pixbuf_queue, pixbuf);
 
-static void print_output_set(PrintWindow *pw, PrintOutput output)
-{
-       gboolean use_file = FALSE;
-       gboolean use_custom = FALSE;
-       gboolean use_format = FALSE;
+       image_loader_free(pw->job_loader);
+       pw->job_loader = NULL;
 
-       pw->output = output;
+       pw->job_page++;
 
-       switch (pw->output)
+       if (!print_job_render_image(pw))
                {
-               case PRINT_OUTPUT_RGB_FILE:
-                       use_file = TRUE;
-                       use_format = TRUE;
-                       break;
-               case PRINT_OUTPUT_PS_FILE:
-                       use_file = TRUE;
-                       break;
-               case PRINT_OUTPUT_PS_CUSTOM:
-                       use_custom = TRUE;
-                       break;
-               case PRINT_OUTPUT_PS_LPR:
-               default:
-                       break;
+               pw->job_render_finished = TRUE;
                }
-
-       gtk_widget_set_sensitive(gtk_widget_get_parent(pw->path_entry), use_file);
-       gtk_widget_set_sensitive(gtk_widget_get_parent(pw->custom_entry), use_custom);
-       gtk_widget_set_sensitive(pw->path_format_menu, use_format);
-       gtk_widget_set_sensitive(pw->max_dpi_menu, !use_format);
-}
-
-static void print_output_cb(GtkWidget *combo, gpointer data)
-{
-       PrintWindow *pw = data;
-       PrintOutput output;
-
-       output = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-
-       print_output_set(pw, output);
 }
 
-static GtkWidget *print_output_format_menu(GtkWidget * table, gint column, gint row,
-                                          PrintFileFormat preferred, GCallback func, gpointer data)
-{
-       GtkWidget *combo;
-
-       combo = print_combo_menu(print_file_format_text, PRINT_FILE_COUNT, preferred, func, data);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column, column + 1, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_output_format_cb(GtkWidget *combo, gpointer data)
+static gboolean print_job_render_image(PrintWindow *pw)
 {
-       PrintWindow *pw = data;
+       FileData *fd = NULL;
 
-       pw->output_format = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
-}
+       fd = g_list_nth_data(pw->source_selection, pw->job_page);
+       if (!fd) return FALSE;
 
-static GtkWidget *print_output_dpi_menu(GtkWidget * table, gint column, gint row,
-                                       gdouble dpi, GCallback func, gpointer data)
-{
-       static gint dpilist[] = { 150, 300, 600, 1200, 0, -1};
-       GtkWidget *combo;
-       GtkListStore *store;
-       GtkCellRenderer *renderer;
-       gint current = 1;
-       gint i;
+       image_loader_free(pw->job_loader);
+       pw->job_loader = NULL;
 
-       store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+       pw->job_loader = image_loader_new(fd);
+       g_signal_connect(G_OBJECT(pw->job_loader), "done",
+                                               (GCallback)print_job_render_image_loader_done, pw);
 
-       i = 0;
-       while (dpilist[i] != -1)
+       if (!image_loader_start(pw->job_loader))
                {
-               GtkTreeIter iter;
-               gchar *text;
-
-               if (dpilist[i] == 0)
-                       {
-                       text = g_strdup(_("Unlimited"));
-                       }
-               else
-                       {
-                       text = g_strdup_printf("%d", dpilist[i]);
-                       }
-
-               gtk_list_store_append(store, &iter);
-               gtk_list_store_set(store, &iter, 0, text, 1, dpilist[i], -1);
-               g_free(text);
-
-               if (dpi == (gdouble)dpilist[i]) current = i;
-
-               i++;
+               image_loader_free(pw->job_loader);
+               pw->job_loader= NULL;
                }
 
-       combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
-       g_object_unref(store);
-
-       gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
-       if (func) g_signal_connect(G_OBJECT(combo), "changed", func, data);
-
-       renderer = gtk_cell_renderer_text_new();
-       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
-       gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", 0, NULL);
-
-       gtk_table_attach(GTK_TABLE(table), combo, column, column + 1, row, row + 1,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
-
-       return combo;
-}
-
-static void print_output_dpi_cb(GtkWidget *combo, gpointer data)
-{
-       PrintWindow *pw = data;
-       GtkTreeModel *store;
-       GtkTreeIter iter;
-       gint n = -1;
-
-       store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
-       if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) return;
-       gtk_tree_model_get(store, &iter, 1, &n, -1);
-
-       pw->max_dpi = (gdouble)n;
+       return TRUE;
 }
 
 static void print_text_field_set(PrintWindow *pw, TextInfo field, gboolean active)
@@ -3143,8 +121,6 @@ static void print_text_field_set(PrintWindow *pw, TextInfo field, gboolean activ
                {
                pw->text_fields &= ~field;
                }
-
-       print_window_layout_render(pw);
 }
 
 static void print_text_cb_name(GtkWidget *widget, gpointer data)
@@ -3192,17 +168,39 @@ static void print_text_cb_dims(GtkWidget *widget, gpointer data)
        print_text_field_set(pw, TEXT_INFO_DIMENSIONS, active);
 }
 
-static void print_text_cb_points(GtkWidget *widget, gpointer data)
+static void print_set_font_cb(GtkWidget *widget, gpointer data)
 {
-       PrintWindow *pw = data;
+#if GTK_CHECK_VERSION(3,4,0)
+       GtkWidget *dialog;
+       char *font;
+       PangoFontDescription *font_desc;
+
+       dialog = gtk_font_chooser_dialog_new("Printer Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
+       gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->printer.font);
 
-       pw->text_points = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
-       print_window_layout_render(pw);
+       if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
+               {
+               font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
+               font = pango_font_description_to_string(font_desc);
+               g_free(options->printer.font);
+               options->printer.font = g_strdup(font);
+               g_free(font);
+               }
+
+       gtk_widget_destroy(dialog);
+#else
+       const char *font;
+
+       font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
+       options->printer.font = g_strdup(font);
+#endif
 }
 
 static void print_text_menu(GtkWidget *box, PrintWindow *pw)
 {
        GtkWidget *group;
+       GtkWidget *hbox;
+       GtkWidget *button;
 
        group = pref_group_new(box, FALSE, _("Show"), GTK_ORIENTATION_VERTICAL);
 
@@ -3219,290 +217,365 @@ static void print_text_menu(GtkWidget *box, PrintWindow *pw)
 
        group = pref_group_new(box, FALSE, _("Font"), GTK_ORIENTATION_VERTICAL);
 
-       pref_spin_new(group, _("Size:"), _("points"),
-                     8.0, 100.0, 1.0, 0, pw->text_points,
-                     G_CALLBACK(print_text_cb_points), pw);
-}
+       hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
 
-/*
- *-----------------------------------------------------------------------------
- * print window
- *-----------------------------------------------------------------------------
- */
+#if GTK_CHECK_VERSION(3,4,0)
+       button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
+                                G_CALLBACK(print_set_font_cb), pw);
+#else
+       button = gtk_font_button_new();
+       gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Printer Font");
+       gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->printer.font);
+       g_signal_connect(G_OBJECT(button), "font-set",
+                                G_CALLBACK(print_set_font_cb),NULL);
+#endif
+       gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+       gtk_widget_show(button);
+}
 
-static void print_window_close(PrintWindow *pw)
+static gboolean paginate_cb(GtkPrintOperation *operation,
+                                                                       GtkPrintContext *context,
+                                                                       gpointer data)
 {
-       print_window_layout_render_stop(pw);
-
-       generic_dialog_close(pw->dialog);
-       pw->dialog = NULL;
+       PrintWindow *pw = data;
 
-       print_job_close(pw, FALSE);
+       if (pw->job_render_finished)
+               {
+               return TRUE;
+               }
+       else
+               {
+               return FALSE;
+               }
+}
 
-       file_data_unref(pw->source_fd);
-       filelist_free(pw->source_selection);
-       filelist_free(pw->source_list);
+/* Returns the "depth" of a layout, that is the distance from the
+ * top of the layout to the baseline of the first line in the
+ * layout. */
+int get_layout_depth(PangoLayout *layout)
+{
+  PangoLayoutLine *layout_line = pango_layout_get_line(layout,0);
+  PangoRectangle rect;
 
-       g_free(pw->output_path);
-       g_free(pw->output_custom);
+  pango_layout_line_get_extents(layout_line, NULL, &rect);
 
-       g_free(pw);
+  return PANGO_ASCENT(rect);
 }
 
-static void print_window_print_cb(GenericDialog *gd, gpointer data)
+static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context,
+                                                                       gint page_nr, gpointer data)
 {
+       FileData *fd;
        PrintWindow *pw = data;
+       cairo_t *cr;
+       gdouble width, height;
+       gdouble width_pixbuf_image, height_pixbuf_image;
+       gdouble width_offset;
+       gdouble height_offset;
+       GdkPixbuf *pixbuf;
+       GdkPixbuf *pixbuf_scaled;
+       PangoLayout *layout;
+       PangoFontDescription *desc;
+       GString *text = g_string_new(NULL);
+       PangoRectangle ink_rect, logical_rect;
+       gdouble depth;
+       gdouble text_padding;
+       gdouble x, y, w, h, scale;
+       gdouble pango_height;
+
+       pixbuf = g_list_nth_data(pw->print_pixbuf_queue, page_nr);
+       width_pixbuf_image = gdk_pixbuf_get_width(pixbuf);
+       height_pixbuf_image = gdk_pixbuf_get_height(pixbuf);
 
-       switch (pw->output)
+       fd = g_list_nth_data(pw->source_selection, page_nr);
+
+       if (pw->text_fields & TEXT_INFO_FILENAME)
+               {
+               text = g_string_append(text, g_strdup(fd->name));
+               text = g_string_append(text, "\n");
+               }
+       if (pw->text_fields & TEXT_INFO_FILEDATE)
+               {
+               text = g_string_append(text, g_strdup(text_from_time(fd->date)));
+               text = g_string_append(text, "\n");
+               }
+       if (pw->text_fields & TEXT_INFO_FILESIZE)
                {
-               case PRINT_OUTPUT_RGB_FILE:
-               case PRINT_OUTPUT_PS_FILE:
-                       g_free(pw->output_path);
-                       pw->output_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->path_entry)));
-                       break;
-               case PRINT_OUTPUT_PS_CUSTOM:
-                       g_free(pw->output_custom);
-                       pw->output_custom = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->custom_entry)));
-                       break;
-               case PRINT_OUTPUT_PS_LPR:
-               default:
-                       break;
+               text = g_string_append(text, g_strdup(text_from_size(fd->size)));
+               text = g_string_append(text, "\n");
+               }
+       if (pw->text_fields & TEXT_INFO_DIMENSIONS)
+               {
+               g_string_append_printf(text, "%d x %d", (gint)width_pixbuf_image,
+                                                                                       (gint)height_pixbuf_image);
+               text = g_string_append(text, "\n");
+               }
+       if (pw->text_fields & TEXT_INFO_FILEPATH)
+               {
+               text = g_string_append(text, g_strdup(fd->path));
+               text = g_string_append(text, "\n");
                }
 
-       print_window_print_start(pw);
-}
+       cr = gtk_print_context_get_cairo_context(context);
+       width = gtk_print_context_get_width(context);
+       height = gtk_print_context_get_height(context);
 
-static void print_window_cancel_cb(GenericDialog *gd, gpointer data)
-{
-       PrintWindow *pw = data;
+       if (text->len > 0)
+               {
+               text = g_string_truncate(text, text->len - 1);
 
-       print_window_close(pw);
-}
+               layout = pango_cairo_create_layout(cr);
 
-static gint print_pref_int(const gchar *key, gint fallback)
-{
-       gint value;
+               pango_layout_set_text(layout, text->str, -1);
+               desc = pango_font_description_from_string(options->printer.font);
+               pango_layout_set_font_description(layout, desc);
 
-       if (pref_list_int_get(PRINT_PREF_GROUP, key, &value)) return value;
-       return fallback;
-}
+               pango_layout_get_extents(layout, &ink_rect, &logical_rect);
+               x = ((gdouble)logical_rect.width / PANGO_SCALE) ;
+               y = ((gdouble)logical_rect.height / PANGO_SCALE);
 
-static gdouble print_pref_double(const gchar *key, gdouble fallback)
-{
-       gdouble value;
+               pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+               pango_layout_set_text(layout, text->str, -1);
 
-       if (pref_list_double_get(PRINT_PREF_GROUP, key, &value)) return value;
-       return fallback;
-}
+               depth = (gdouble)get_layout_depth(layout);
+               text_padding = depth / 2 / PANGO_SCALE ;
 
-void print_window_new(FileData *fd, GList *selection, GList *list, GtkWidget *parent)
-{
-       PrintWindow *pw;
-       GdkGeometry geometry;
-       GtkWidget *main_box;
-       GtkWidget *vbox;
-       GtkWidget *label;
-       GtkWidget *combo;
-       GtkWidget *box;
-       GtkWidget *table;
+               pango_height = y + text_padding * 2;
 
-       pw = g_new0(PrintWindow, 1);
+               }
+       else
+               {
+               pango_height = 0;
+               depth = 0;
+               text_padding = 0;
+               x = 0;
+               y = 0;
+               }
 
-       pw->source_fd = file_data_ref(fd);
-       pw->source_selection = file_data_process_groups_in_selection(selection, FALSE, NULL);
-       pw->source_list = list;
+       if ((width / width_pixbuf_image) < ((height - pango_height) / height_pixbuf_image))
+               {
+               w = width;
+               scale = width / width_pixbuf_image;
+               h = height_pixbuf_image * scale;
+               height_offset = (height - (h + pango_height)) / 2;
+               width_offset = 0;
+               }
+       else
+               {
+               h = height - pango_height ;
+               scale = (height - pango_height) / height_pixbuf_image;
+               w = width_pixbuf_image * scale;
+               height_offset = 0;
+               width_offset = (width - (width_pixbuf_image * scale)) / 2;
+               }
 
-       pw->source = print_pref_int(PRINT_PREF_SOURCE, PRINT_SOURCE_SELECTION);
-       pw->layout = print_pref_int(PRINT_PREF_LAYOUT, PRINT_LAYOUT_IMAGE);
+       if (text->len > 0)
+               {
+               cairo_move_to(cr, (w / 2) - (x / 2) + width_offset, h + height_offset + text_padding);
+               pango_cairo_show_layout(cr, layout);
+               }
 
-       pw->image_scale = print_pref_double(PRINT_PREF_IMAGE_SCALE, 100.0);
+       pixbuf_scaled = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
+       gdk_pixbuf_scale(pixbuf, pixbuf_scaled, 0, 0, w, h, 0, 0,  scale, scale, PRINT_MAX_INTERP);
 
-       pw->output = print_pref_int(PRINT_PREF_OUTPUT, PRINT_OUTPUT_PS_LPR);
-       pw->output_format = print_pref_int(PRINT_PREF_FORMAT, PRINT_FILE_JPG_NORMAL);
+       cairo_rectangle(cr, width_offset, height_offset, w, h);
 
-       pw->max_dpi = print_pref_double(PRINT_PREF_DPI, PRINT_PS_DPI_DEFAULT);
+       gdk_cairo_set_source_pixbuf(cr, pixbuf_scaled, width_offset, height_offset);
+       cairo_fill(cr);
 
-       pw->paper_units = print_pref_int(PRINT_PREF_UNITS, paper_unit_default());
-       pw->paper_size = print_pref_int(PRINT_PREF_SIZE, 1);
-       if (pw->paper_size == 0 ||
-           !print_paper_size_lookup(pw->paper_size, &pw->paper_width, &pw->paper_height))
+       if (text->len > 0)
                {
-               pw->paper_width = print_pref_double(PRINT_PREF_CUSTOM_WIDTH, 360.0);
-               pw->paper_height = print_pref_double(PRINT_PREF_CUSTOM_HEIGHT, 720.0);
+               g_object_unref(layout);
+               g_string_free(text, TRUE);
+               pango_font_description_free(desc);
                }
-       pw->paper_orientation = print_pref_int(PRINT_PREF_ORIENTATION, PAPER_ORIENTATION_PORTRAIT);
 
-       pw->margin_left = print_pref_double(PRINT_PREF_MARGIN_LEFT, PRINT_MARGIN_DEFAULT);
-       pw->margin_right = print_pref_double(PRINT_PREF_MARGIN_RIGHT, PRINT_MARGIN_DEFAULT);
-       pw->margin_top = print_pref_double(PRINT_PREF_MARGIN_TOP, PRINT_MARGIN_DEFAULT);
-       pw->margin_bottom = print_pref_double(PRINT_PREF_MARGIN_BOTTOM, PRINT_MARGIN_DEFAULT);
+       g_object_unref(pixbuf_scaled);
 
-       pw->proof_width = print_pref_double(PRINT_PREF_PROOF_WIDTH, PRINT_PROOF_DEFAULT_SIZE);
-       pw->proof_height = print_pref_double(PRINT_PREF_PROOF_HEIGHT, PRINT_PROOF_DEFAULT_SIZE);
+       return;
+}
 
-       pw->text_fields = print_pref_int(PRINT_PREF_TEXT, TEXT_INFO_FILENAME);
-       pw->text_points = print_pref_int(PRINT_PREF_TEXTSIZE, 10);
-       pw->text_r = print_pref_int(PRINT_PREF_TEXTCOLOR_R, 0);
-       pw->text_g = print_pref_int(PRINT_PREF_TEXTCOLOR_G, 0);
-       pw->text_b = print_pref_int(PRINT_PREF_TEXTCOLOR_B, 0);
+static void begin_print(GtkPrintOperation *operation,
+                                               GtkPrintContext *context,
+                                               gpointer user_data)
+{
+       PrintWindow *pw = user_data;
+       gint page_count;
 
-       pw->save_settings = print_pref_int(PRINT_PREF_SAVE, TRUE);
+       page_count = print_layout_page_count(pw);
+       gtk_print_operation_set_n_pages (operation, page_count);
 
-       pw->dialog = file_util_gen_dlg(_("Print"), "print_dialog",
-                                      parent, FALSE,
-                                      print_window_cancel_cb, pw);
+       print_job_render_image(pw);
+}
 
-       geometry.min_width = DEFAULT_MINIMAL_WINDOW_SIZE;
-       geometry.min_height = DEFAULT_MINIMAL_WINDOW_SIZE;
-       geometry.base_width = PRINT_DLG_WIDTH;
-       geometry.base_height = PRINT_DLG_HEIGHT;
-       gtk_window_set_geometry_hints(GTK_WINDOW(pw->dialog->dialog), NULL, &geometry,
-                                     GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
 
-       pw->print_button = generic_dialog_add_button(pw->dialog, GTK_STOCK_PRINT, NULL, print_window_print_cb, TRUE);
+GObject *option_tab_cb(GtkPrintOperation *operation, gpointer user_data)
+{
+       PrintWindow *pw = user_data;
 
-       main_box = pref_box_new(pw->dialog->vbox, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
+       return G_OBJECT(pw->vbox);
+}
 
-       pw->notebook = gtk_notebook_new();
-       gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pw->notebook), GTK_POS_TOP);
-       gtk_box_pack_start(GTK_BOX(main_box), pw->notebook, FALSE, FALSE, 0);
+static void print_pref_store(PrintWindow *pw)
+{
+       options->printer.text_fields = pw->text_fields;
+}
 
-       /* layout tab */
+static void end_print_cb(GtkPrintOperation *operation,
+                                                               GtkPrintContext *context, gpointer data)
+{
+       PrintWindow *pw = data;
+       GList *work;
+       GdkPixbuf *pixbuf;
+       gchar *path;
+       GtkPrintSettings *print_settings;
+       GtkPageSetup *page_setup;
+       GError *error = NULL;
 
-       vbox = gtk_vbox_new(FALSE, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
-       gtk_widget_show(vbox);
-       label = gtk_label_new(_("Layout"));
-       gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
+       print_settings = gtk_print_operation_get_print_settings(operation);
+       path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
 
-       print_misc_menu(vbox, pw->source, _("Source"), "print_source",
-                       PRINT_SOURCE_COUNT, print_source_text,
-                       G_CALLBACK(print_source_select_cb), pw);
+       gtk_print_settings_to_file(print_settings, path, &error);
+       if (error)
+               {
+               log_printf("Error: Print settings save failed:\n%s", error->message);
+               g_error_free(error);
+               error = NULL;
+               }
+       g_free(path);
+       g_object_unref(print_settings);
 
-       box = print_misc_menu(vbox, pw->layout, _("Layout"), "print_layout",
-                             PRINT_LAYOUT_COUNT, print_layout_text,
-                             G_CALLBACK(print_layout_select_cb), pw);
+       page_setup = gtk_print_operation_get_default_page_setup(operation);
+       path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
 
-       pref_spacer(box, PREF_PAD_GROUP);
+       gtk_page_setup_to_file(page_setup, path, &error);
+       if (error)
+               {
+               log_printf("Error: Print page setup save failed:\n%s", error->message);
+               g_error_free(error);
+               error = NULL;
+               }
+       g_free(path);
+       g_object_unref(page_setup);
 
-       table = pref_table_new(box, 2, 2, FALSE, FALSE);
+       print_pref_store(pw);
 
-       pw->image_scale_spin = pref_table_spin(table, 0, 0, _("Image size:"), "%",
-                                              5.0, 100.0, 1.0, 0, pw->image_scale,
-                                              G_CALLBACK(print_image_scale_cb), pw);
+       work = pw->print_pixbuf_queue;
+       while (work)
+               {
+               pixbuf = work->data;
+               if (pixbuf)
+                       {
+                       g_object_unref(pixbuf);
+                       }
+               work = work->next;
+               }
+       g_list_free(pw->print_pixbuf_queue);
+       g_free(pw);
+}
 
-       label = pref_table_label(table, 0, 1, _("Proof size:"), 1.0);
-       pw->proof_group = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
-       pref_link_sensitivity(label, pw->proof_group);
+void print_window_new(FileData *fd, GList *selection, GList *list, GtkWidget *parent)
+{
+       PrintWindow *pw;
+       GtkWidget *vbox;
+       GtkPrintOperation *operation;
+       GtkPageSetup *page_setup;
+       gchar *uri;
+       const gchar *dir;
+       GError *error = NULL;
+       gchar *path;
+       GtkPrintSettings *settings;
 
-       pw->proof_width_spin = pref_spin_new(pw->proof_group, NULL, NULL,
-                                            0.0, 50.0, 0.1, 3, 0.0,
-                                            G_CALLBACK(print_proof_size_cb), pw);
-       pw->proof_height_spin = pref_spin_new(pw->proof_group, "x", NULL,
-                                             0.0, 50.0, 0.1, 3, 0.0,
-                                             G_CALLBACK(print_proof_size_cb), pw);
+       pw = g_new0(PrintWindow, 1);
 
-       /* text tab */
+       pw->source_selection = file_data_process_groups_in_selection(selection, FALSE, NULL);
+       pw->text_fields = options->printer.text_fields;
 
        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
        gtk_widget_show(vbox);
-       label = gtk_label_new(_("Text"));
-       gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
 
        print_text_menu(vbox, pw);
+       pw->vbox = vbox;
 
-       /* paper tab */
+       pw->print_pixbuf_queue = NULL;
+       pw->job_render_finished = FALSE;
+       pw->job_page = 0;
 
-       vbox = gtk_vbox_new(FALSE, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
-       gtk_widget_show(vbox);
-       label = gtk_label_new(_("Paper"));
-       gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
-
-       table = pref_table_new(vbox, 2, 4, FALSE, FALSE);
-
-       print_paper_menu(table, 0, 0, pw->paper_size, G_CALLBACK(print_paper_select_cb), pw);
-
-       label = pref_table_label(table, 0, 1, (_("Size:")), 1.0);
-       box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
-       pw->paper_width_spin = pref_spin_new(box, NULL, NULL,
-                                            1.0, 10000.0, 1.0, 2, 66,
-                                            G_CALLBACK(print_paper_size_cb), pw);
-       pw->paper_height_spin = pref_spin_new(box, "x", NULL,
-                                             1.0, 10000.0, 1.0, 2, 66,
-                                             G_CALLBACK(print_paper_size_cb), pw);
-       pref_link_sensitivity(label, pw->paper_width_spin);
-
-       pw->paper_units_menu = print_paper_units_menu(table, 0, 2, pw->paper_units,
-                                       G_CALLBACK(print_paper_units_cb), pw);
-
-       print_paper_orientation_menu(table, 0, 3, pw->paper_orientation,
-                                    G_CALLBACK(print_paper_orientation_cb), pw);
-
-       box = pref_group_new(vbox, FALSE, _("Margins"), GTK_ORIENTATION_VERTICAL);
-       table = pref_table_new(box, 4, 2, FALSE, FALSE);
-       pw->margin_left_spin = pref_table_spin(table, 0, 0, _("Left:"), NULL,
-                                       0.0, 50.0, 0.1, 3, 0.0,
-                                       G_CALLBACK(print_paper_margin_cb), pw);
-       pw->margin_right_spin = pref_table_spin(table, 2, 0, _("Right:"), NULL,
-                                       0.0, 50.0, 0.1, 3, 0.0,
-                                       G_CALLBACK(print_paper_margin_cb), pw);
-       pw->margin_top_spin = pref_table_spin(table, 0, 1, _("Top:"), NULL,
-                                       0.0, 50.0, 0.1, 3, 0.0,
-                                       G_CALLBACK(print_paper_margin_cb), pw);
-       pw->margin_bottom_spin = pref_table_spin(table, 2, 1, _("Bottom:"), NULL,
-                                       0.0, 50.0, 0.1, 3, 0.0,
-                                       G_CALLBACK(print_paper_margin_cb), pw);
-
-       /* printer tab */
+       operation = gtk_print_operation_new();
+       settings = gtk_print_settings_new();
 
-       vbox = gtk_vbox_new(FALSE, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
-       gtk_widget_show(vbox);
-       label = gtk_label_new(_("Printer"));
-       gtk_notebook_append_page(GTK_NOTEBOOK(pw->notebook), vbox, label);
+       gtk_print_operation_set_custom_tab_label(operation, "Options");
+       gtk_print_operation_set_use_full_page(operation, TRUE);
+       gtk_print_operation_set_unit(operation, GTK_UNIT_POINTS);
+       gtk_print_operation_set_embed_page_setup(operation, TRUE);
+       gtk_print_operation_set_allow_async (operation, TRUE);
+       dir = g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS);
+       if (dir == NULL)
+               {
+               dir = g_get_home_dir();
+               }
 
-       table = pref_table_new(vbox, 2, 5, FALSE, FALSE);
-       print_output_menu(table, 0, 0, pw->output, G_CALLBACK(print_output_cb), pw);
+       uri = g_build_filename("file:/", dir, "geeqie-file.pdf", NULL);
+       gtk_print_settings_set(settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
+       g_free(uri);
 
-       label = pref_table_label(table, 0, 1, _("Custom printer:"), 1.0);
-       combo = history_combo_new(&pw->custom_entry, NULL, "print_custom", -1);
-       print_custom_entry_set(pw, combo);
-       gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
+       path = g_build_filename(get_rc_dir(), PRINT_SETTINGS, NULL);
+       gtk_print_settings_load_file(settings, path, &error);
+       if (error)
+               {
+               log_printf("Error: Printer settings load failed:\n%s", error->message);
+               g_error_free(error);
+               error = NULL;
+               }
+       gtk_print_operation_set_print_settings(operation, settings);
+       g_free(path);
 
-       pref_link_sensitivity(label, combo);
+       page_setup = gtk_page_setup_new();
+       path = g_build_filename(get_rc_dir(), PAGE_SETUP, NULL);
+       gtk_page_setup_load_file(page_setup, path, &error);
+       if (error)
+               {
+               log_printf("Error: Print page setup load failed:\n%s", error->message);
+               g_error_free(error);
+               error = NULL;
+               }
+       gtk_print_operation_set_default_page_setup(operation, page_setup);
+       g_free(path);
 
-       label = pref_table_label(table, 0, 2, _("File:"), 1.0);
-       combo = tab_completion_new_with_history(&pw->path_entry, NULL, "print_path", -1, NULL, pw);
-       tab_completion_add_select_button(pw->path_entry, NULL, FALSE);
-       gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3,
-                        GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-       gtk_widget_show(combo);
+       g_signal_connect (G_OBJECT (operation), "begin-print",
+                                       G_CALLBACK (begin_print), pw);
+       g_signal_connect (G_OBJECT (operation), "draw-page",
+                                       G_CALLBACK (draw_page), pw);
+       g_signal_connect (G_OBJECT (operation), "end-print",
+                                       G_CALLBACK (end_print_cb), pw);
+       g_signal_connect (G_OBJECT (operation), "create-custom-widget",
+                                       G_CALLBACK (option_tab_cb), pw);
+       g_signal_connect (G_OBJECT (operation), "paginate",
+                                       G_CALLBACK (paginate_cb), pw);
 
-       pref_link_sensitivity(label, combo);
+       gtk_print_operation_set_n_pages(operation, print_layout_page_count(pw));
 
-       label = pref_table_label(table, 0, 3, _("File format:"), 1.0);
-       pw->path_format_menu = print_output_format_menu(table, 1, 3, pw->output_format,
-                                                       G_CALLBACK(print_output_format_cb), pw);
-       pref_link_sensitivity(label, pw->path_format_menu);
+       gtk_print_operation_run(operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                                                                               GTK_WINDOW (parent), &error);
 
-       label = pref_table_label(table, 0, 4, _("DPI:"), 1.0);
-       pw->max_dpi_menu = print_output_dpi_menu(table, 1, 4, pw->max_dpi,
-                                                G_CALLBACK(print_output_dpi_cb), pw);
-       pref_link_sensitivity(label, pw->max_dpi_menu);
+       if (error)
+               {
+               GtkWidget *dialog;
 
-       print_output_set(pw, pw->output);
+               dialog = gtk_message_dialog_new(GTK_WINDOW (parent),
+                                                               GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                               GTK_MESSAGE_ERROR,
+                                                               GTK_BUTTONS_CLOSE,
+                                                               "%s", error->message);
+               g_error_free (error);
 
-       vbox = print_window_layout_setup(pw, main_box);
-       pref_checkbox_new_int(vbox, _("Remember print settings"), pw->save_settings, &pw->save_settings);
+               g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
 
-       print_window_layout_sync_layout(pw);
-       print_window_layout_sync_paper(pw);
+               gtk_widget_show (dialog);
+               }
 
-       gtk_widget_show(pw->notebook);
-       gtk_widget_show(pw->dialog->dialog);
+       g_object_unref(page_setup);
+       g_object_unref(settings);
 }
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index c6314e8..3d2a500 100644 (file)
@@ -494,6 +494,10 @@ static void write_global_attributes(GString *outstr, gint indent)
        WRITE_NL(); WRITE_INT(*options, cp_mv_rn.auto_padding);
        WRITE_NL(); WRITE_CHAR(*options, cp_mv_rn.auto_end);
        WRITE_NL(); WRITE_INT(*options, cp_mv_rn.formatted_start);
+
+       /* printer */
+       WRITE_NL(); WRITE_CHAR(*options, printer.font);
+       WRITE_NL(); WRITE_INT(*options, printer.text_fields);
 }
 
 static void write_color_profile(GString *outstr, gint indent)
@@ -829,6 +833,10 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar **
                if (READ_CHAR(*options, cp_mv_rn.auto_end)) continue;
                if (READ_INT(*options, cp_mv_rn.formatted_start)) continue;
 
+               /* printer */
+               if (READ_CHAR(*options, printer.font)) continue;
+               if (READ_INT(*options, printer.text_fields)) continue;
+
                /* Dummy options */
                if (READ_DUMMY(*options, image.dither_quality, "deprecated since 2012-08-13")) continue;