]> Pileus Git - ~andy/gtk/commitdiff
Merge the gtk-printing branch. For more detailed ChangeLog entries, see
authorAlexander Larsson <alexl@redhat.com>
Fri, 21 Apr 2006 15:09:32 +0000 (15:09 +0000)
committerAlexander Larsson <alexl@src.gnome.org>
Fri, 21 Apr 2006 15:09:32 +0000 (15:09 +0000)
2006-04-21  Alexander Larsson  <alexl@redhat.com>

        Merge the gtk-printing branch.
For more detailed ChangeLog entries, see the branch.

* .cvsignore:
* Makefile.am:
* configure.in:
* docs/tools/widgets.c:
* gtk+-unix-print-2.0.pc.in:
* gtk/Makefile.am:
* gtk/gen-paper-names.c:
* gtk/gtk.h:
* gtk/gtk.symbols:
* gtk/gtkenums.h:
* gtk/gtkiconfactory.c:
* gtk/gtkmarshalers.list:
* gtk/gtkpagesetup.[ch]:
* gtk/gtkpagesetupunixdialog.[ch]:
* gtk/gtkpapersize.[ch]:
* gtk/gtkprint-win32.[ch]:
* gtk/gtkprintbackend.[ch]:
* gtk/gtkprintcontext.[ch]:
* gtk/gtkprinter-private.h:
* gtk/gtkprinter.[ch]:
* gtk/gtkprinteroption.[ch]:
* gtk/gtkprinteroptionset.[ch]:
* gtk/gtkprinteroptionwidget.[ch]:
* gtk/gtkprintjob.[ch]:
* gtk/gtkprintoperation-private.h:
* gtk/gtkprintoperation-unix.c:
* gtk/gtkprintoperation-win32.c:
* gtk/gtkprintoperation.[ch]:
* gtk/gtkprintsettings.[ch]:
* gtk/gtkprintunixdialog.[ch]:
* gtk/paper_names.c:
* gtk/paper_names_offsets.c:
Platform independent printing API and implementations
for unix and windows.

* gtk/gtkstock.h:
* gtk/stock-icons/24/gtk-orientation-landscape.png:
* gtk/stock-icons/24/gtk-orientation-portrait.png:
* gtk/stock-icons/24/gtk-orientation-reverse-landscape.png:
Add stock icons for page orientation.

* modules/Makefile.am:
* modules/printbackends/Makefile.am:
* modules/printbackends/cups/Makefile.am:
* modules/printbackends/cups/gtkcupsutils.[ch]:
* modules/printbackends/cups/gtkprintbackendcups.[ch]:
* modules/printbackends/cups/gtkprintercups.[ch]:

Cups printing backend for unix.

* modules/printbackends/lpr/Makefile.am:
* modules/printbackends/lpr/gtkprintbackendlpr.[ch]:
lpr printing backend for unix.

* modules/printbackends/pdf/Makefile.am:
* modules/printbackends/pdf/gtkprintbackendpdf.[ch]:
print-to-pdf printing backend for unix.

* tests/.cvsignore:
* tests/Makefile.am:
* tests/print-editor.c:
Test application for printing.

* gdk/gdk.symbols:
* gdk/win32/gdkevents-win32.c:
* gdk/win32/gdkwin32.h:
Add gdk_win32_set_modal_dialog_libgtk_only so that we can pump the
mainloop while displaying a win32 common dialog.

* gdk/directfb/Makefile.am:
Whitespace cleanup.

91 files changed:
.cvsignore
ChangeLog
ChangeLog.pre-2-10
Makefile.am
configure.in
docs/reference/ChangeLog
docs/reference/gtk/Makefile.am
docs/reference/gtk/gtk-docs.sgml
docs/reference/gtk/gtk-sections.txt
docs/reference/gtk/gtk.types
docs/reference/gtk/images/pagesetupdialog.png [new file with mode: 0644]
docs/reference/gtk/images/printdialog.png [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkpagesetup.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkpagesetupunixdialog.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkpapersize.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprintcontext.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprinter.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprintjob.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprintoperation.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprintsettings.sgml [new file with mode: 0644]
docs/reference/gtk/tmpl/gtkprintunixdialog.sgml [new file with mode: 0644]
docs/reference/gtk/visual_index.xml
docs/tools/widgets.c
gdk/directfb/Makefile.am
gdk/gdk.symbols
gdk/win32/gdkevents-win32.c
gdk/win32/gdkwin32.h
gtk+-unix-print-2.0.pc.in [new file with mode: 0644]
gtk/Makefile.am
gtk/gen-paper-names.c [new file with mode: 0644]
gtk/gtk.h
gtk/gtk.symbols
gtk/gtkenums.h
gtk/gtkiconfactory.c
gtk/gtkmarshalers.list
gtk/gtkpagesetup.c [new file with mode: 0644]
gtk/gtkpagesetup.h [new file with mode: 0644]
gtk/gtkpagesetupunixdialog.c [new file with mode: 0644]
gtk/gtkpagesetupunixdialog.h [new file with mode: 0644]
gtk/gtkpapersize.c [new file with mode: 0644]
gtk/gtkpapersize.h [new file with mode: 0644]
gtk/gtkprint-win32.c [new file with mode: 0644]
gtk/gtkprint-win32.h [new file with mode: 0644]
gtk/gtkprintbackend.c [new file with mode: 0644]
gtk/gtkprintbackend.h [new file with mode: 0644]
gtk/gtkprintcontext.c [new file with mode: 0644]
gtk/gtkprintcontext.h [new file with mode: 0644]
gtk/gtkprinter-private.h [new file with mode: 0644]
gtk/gtkprinter.c [new file with mode: 0644]
gtk/gtkprinter.h [new file with mode: 0644]
gtk/gtkprinteroption.c [new file with mode: 0644]
gtk/gtkprinteroption.h [new file with mode: 0644]
gtk/gtkprinteroptionset.c [new file with mode: 0644]
gtk/gtkprinteroptionset.h [new file with mode: 0644]
gtk/gtkprinteroptionwidget.c [new file with mode: 0644]
gtk/gtkprinteroptionwidget.h [new file with mode: 0644]
gtk/gtkprintjob.c [new file with mode: 0644]
gtk/gtkprintjob.h [new file with mode: 0644]
gtk/gtkprintoperation-private.h [new file with mode: 0644]
gtk/gtkprintoperation-unix.c [new file with mode: 0644]
gtk/gtkprintoperation-win32.c [new file with mode: 0644]
gtk/gtkprintoperation.c [new file with mode: 0644]
gtk/gtkprintoperation.h [new file with mode: 0644]
gtk/gtkprintsettings.c [new file with mode: 0644]
gtk/gtkprintsettings.h [new file with mode: 0644]
gtk/gtkprintunixdialog.c [new file with mode: 0644]
gtk/gtkprintunixdialog.h [new file with mode: 0644]
gtk/gtkstock.h
gtk/paper_names.c [new file with mode: 0644]
gtk/paper_names_offsets.c [new file with mode: 0644]
gtk/stock-icons/24/gtk-orientation-landscape.png [new file with mode: 0644]
gtk/stock-icons/24/gtk-orientation-portrait.png [new file with mode: 0644]
gtk/stock-icons/24/gtk-orientation-reverse-landscape.png [new file with mode: 0644]
modules/Makefile.am
modules/printbackends/Makefile.am [new file with mode: 0644]
modules/printbackends/cups/Makefile.am [new file with mode: 0644]
modules/printbackends/cups/gtkcupsutils.c [new file with mode: 0644]
modules/printbackends/cups/gtkcupsutils.h [new file with mode: 0644]
modules/printbackends/cups/gtkprintbackendcups.c [new file with mode: 0644]
modules/printbackends/cups/gtkprintbackendcups.h [new file with mode: 0644]
modules/printbackends/cups/gtkprintercups.c [new file with mode: 0644]
modules/printbackends/cups/gtkprintercups.h [new file with mode: 0644]
modules/printbackends/lpr/Makefile.am [new file with mode: 0644]
modules/printbackends/lpr/gtkprintbackendlpr.c [new file with mode: 0644]
modules/printbackends/lpr/gtkprintbackendlpr.h [new file with mode: 0644]
modules/printbackends/pdf/Makefile.am [new file with mode: 0644]
modules/printbackends/pdf/gtkprintbackendpdf.c [new file with mode: 0644]
modules/printbackends/pdf/gtkprintbackendpdf.h [new file with mode: 0644]
tests/.cvsignore
tests/Makefile.am
tests/print-editor.c [new file with mode: 0644]

index d6f89153d2b3cf006270d39ed00514987dee38cc..c7f3e710c8691eecc6cb84e8b01d16d1d24985eb 100644 (file)
@@ -19,6 +19,7 @@ stamp-h.in
 gtk+.spec
 gtk+-2.0.pc
 gtk+-2.0-uninstalled.pc
+gtk+-unix-print-2.0.pc
 gtk+-linux-fb-2.0.pc
 gtk+-nanox-2.0.pc
 gtk+-x11-2.0.pc
index 44a141a62578bdffd0073cad09fcbb48f6f47248..ae97511c55ff826e9612964c55af514275829747 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,80 @@
+2006-04-21  Alexander Larsson  <alexl@redhat.com>
+
+        Merge the gtk-printing branch.
+       For more detailed ChangeLog entries, see the branch.
+       
+       * .cvsignore:
+       * Makefile.am:
+       * configure.in:
+       * docs/tools/widgets.c:
+       * gtk+-unix-print-2.0.pc.in:
+       * gtk/Makefile.am:
+       * gtk/gen-paper-names.c:
+       * gtk/gtk.h:
+       * gtk/gtk.symbols:
+       * gtk/gtkenums.h:
+       * gtk/gtkiconfactory.c:
+       * gtk/gtkmarshalers.list:
+       * gtk/gtkpagesetup.[ch]:
+       * gtk/gtkpagesetupunixdialog.[ch]:
+       * gtk/gtkpapersize.[ch]:
+       * gtk/gtkprint-win32.[ch]:
+       * gtk/gtkprintbackend.[ch]:
+       * gtk/gtkprintcontext.[ch]:
+       * gtk/gtkprinter-private.h:
+       * gtk/gtkprinter.[ch]:
+       * gtk/gtkprinteroption.[ch]:
+       * gtk/gtkprinteroptionset.[ch]:
+       * gtk/gtkprinteroptionwidget.[ch]:
+       * gtk/gtkprintjob.[ch]:
+       * gtk/gtkprintoperation-private.h:
+       * gtk/gtkprintoperation-unix.c:
+       * gtk/gtkprintoperation-win32.c:
+       * gtk/gtkprintoperation.[ch]:
+       * gtk/gtkprintsettings.[ch]:
+       * gtk/gtkprintunixdialog.[ch]:
+       * gtk/paper_names.c:
+       * gtk/paper_names_offsets.c:
+       Platform independent printing API and implementations
+       for unix and windows.
+
+       * gtk/gtkstock.h:
+       * gtk/stock-icons/24/gtk-orientation-landscape.png:
+       * gtk/stock-icons/24/gtk-orientation-portrait.png:
+       * gtk/stock-icons/24/gtk-orientation-reverse-landscape.png:
+       Add stock icons for page orientation.
+       
+       * modules/Makefile.am:
+       * modules/printbackends/Makefile.am:
+       * modules/printbackends/cups/Makefile.am:
+       * modules/printbackends/cups/gtkcupsutils.[ch]:
+       * modules/printbackends/cups/gtkprintbackendcups.[ch]:
+       * modules/printbackends/cups/gtkprintercups.[ch]:
+
+       Cups printing backend for unix.
+       
+       * modules/printbackends/lpr/Makefile.am:
+       * modules/printbackends/lpr/gtkprintbackendlpr.[ch]:
+       lpr printing backend for unix.
+       
+       * modules/printbackends/pdf/Makefile.am:
+       * modules/printbackends/pdf/gtkprintbackendpdf.[ch]:
+       print-to-pdf printing backend for unix.
+       
+       * tests/.cvsignore:
+       * tests/Makefile.am:
+       * tests/print-editor.c:
+       Test application for printing.
+
+       * gdk/gdk.symbols:
+       * gdk/win32/gdkevents-win32.c:
+       * gdk/win32/gdkwin32.h:
+       Add gdk_win32_set_modal_dialog_libgtk_only so that we can pump the
+       mainloop while displaying a win32 common dialog.
+
+       * gdk/directfb/Makefile.am:
+       Whitespace cleanup.
+       
 2006-04-20  Paolo Borelli  <pborelli@katamail.com>
 
        * gtk/gtkcombobox.c: plug small leak (#339132)
index 44a141a62578bdffd0073cad09fcbb48f6f47248..ae97511c55ff826e9612964c55af514275829747 100644 (file)
@@ -1,3 +1,80 @@
+2006-04-21  Alexander Larsson  <alexl@redhat.com>
+
+        Merge the gtk-printing branch.
+       For more detailed ChangeLog entries, see the branch.
+       
+       * .cvsignore:
+       * Makefile.am:
+       * configure.in:
+       * docs/tools/widgets.c:
+       * gtk+-unix-print-2.0.pc.in:
+       * gtk/Makefile.am:
+       * gtk/gen-paper-names.c:
+       * gtk/gtk.h:
+       * gtk/gtk.symbols:
+       * gtk/gtkenums.h:
+       * gtk/gtkiconfactory.c:
+       * gtk/gtkmarshalers.list:
+       * gtk/gtkpagesetup.[ch]:
+       * gtk/gtkpagesetupunixdialog.[ch]:
+       * gtk/gtkpapersize.[ch]:
+       * gtk/gtkprint-win32.[ch]:
+       * gtk/gtkprintbackend.[ch]:
+       * gtk/gtkprintcontext.[ch]:
+       * gtk/gtkprinter-private.h:
+       * gtk/gtkprinter.[ch]:
+       * gtk/gtkprinteroption.[ch]:
+       * gtk/gtkprinteroptionset.[ch]:
+       * gtk/gtkprinteroptionwidget.[ch]:
+       * gtk/gtkprintjob.[ch]:
+       * gtk/gtkprintoperation-private.h:
+       * gtk/gtkprintoperation-unix.c:
+       * gtk/gtkprintoperation-win32.c:
+       * gtk/gtkprintoperation.[ch]:
+       * gtk/gtkprintsettings.[ch]:
+       * gtk/gtkprintunixdialog.[ch]:
+       * gtk/paper_names.c:
+       * gtk/paper_names_offsets.c:
+       Platform independent printing API and implementations
+       for unix and windows.
+
+       * gtk/gtkstock.h:
+       * gtk/stock-icons/24/gtk-orientation-landscape.png:
+       * gtk/stock-icons/24/gtk-orientation-portrait.png:
+       * gtk/stock-icons/24/gtk-orientation-reverse-landscape.png:
+       Add stock icons for page orientation.
+       
+       * modules/Makefile.am:
+       * modules/printbackends/Makefile.am:
+       * modules/printbackends/cups/Makefile.am:
+       * modules/printbackends/cups/gtkcupsutils.[ch]:
+       * modules/printbackends/cups/gtkprintbackendcups.[ch]:
+       * modules/printbackends/cups/gtkprintercups.[ch]:
+
+       Cups printing backend for unix.
+       
+       * modules/printbackends/lpr/Makefile.am:
+       * modules/printbackends/lpr/gtkprintbackendlpr.[ch]:
+       lpr printing backend for unix.
+       
+       * modules/printbackends/pdf/Makefile.am:
+       * modules/printbackends/pdf/gtkprintbackendpdf.[ch]:
+       print-to-pdf printing backend for unix.
+       
+       * tests/.cvsignore:
+       * tests/Makefile.am:
+       * tests/print-editor.c:
+       Test application for printing.
+
+       * gdk/gdk.symbols:
+       * gdk/win32/gdkevents-win32.c:
+       * gdk/win32/gdkwin32.h:
+       Add gdk_win32_set_modal_dialog_libgtk_only so that we can pump the
+       mainloop while displaying a win32 common dialog.
+
+       * gdk/directfb/Makefile.am:
+       Whitespace cleanup.
+       
 2006-04-20  Paolo Borelli  <pborelli@katamail.com>
 
        * gtk/gtkcombobox.c: plug small leak (#339132)
index b012a4754ea79878a438cb46d4a1a36f502d9618..094efccedc07dcdba3af7e88e07b1c965de3a609 100644 (file)
@@ -132,9 +132,10 @@ gdk-$(GDKTARGET)-2.0-uninstalled.pc: gdk-2.0-uninstalled.pc
        cp gdk-2.0-uninstalled.pc gdk-$(GDKTARGET)-2.0-uninstalled.pc
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA= gdk-pixbuf-2.0.pc gdk-$(GDKTARGET)-2.0.pc gtk+-$(GDKTARGET)-2.0.pc
+pkgconfig_DATA= gdk-pixbuf-2.0.pc gdk-$(GDKTARGET)-2.0.pc gtk+-$(GDKTARGET)-2.0.pc gtk+-unix-print-2.0.pc
 
 DISTCLEANFILES =                               \
+       gtk+-unix-print-2.0.pc                  \
        gtk+-$(GDKTARGET)-2.0.pc                \
        gdk-$(GDKTARGET)-2.0.pc                 \
        gtk+-$(GDKTARGET)-2.0-uninstalled.pc    \
index 5014d7c7802d8d1a3add6cda458651f4152dae7c..83b44fe756c62b43a0bddbb1e789c77c15350987 100644 (file)
@@ -416,6 +416,42 @@ if test "$gtk_ok" = "yes"; then
            [Define if _NL_TIME_FIRST_WEEKDAY is available])
 fi
 
+# _NL_MEASUREMENT_MEASUREMENT is an enum and not a define
+AC_MSG_CHECKING([for _NL_MEASUREMENT_MEASUREMENT])
+AC_TRY_LINK([#include <langinfo.h>], [
+char c;
+c = *((unsigned char *)  nl_langinfo(_NL_MEASUREMENT_MEASUREMENT));
+], gtk_ok=yes, gtk_ok=no)
+AC_MSG_RESULT($gtk_ok)
+if test "$gtk_ok" = "yes"; then
+  AC_DEFINE([HAVE__NL_MEASUREMENT_MEASUREMENT], [1],
+           [Define if _NL_MEASUREMENT_MEASUREMENT is available])
+fi
+
+# _NL_PAPER_HEIGHT is an enum and not a define
+AC_MSG_CHECKING([for _NL_PAPER_HEIGHT])
+AC_TRY_LINK([#include <langinfo.h>], [
+char c;
+c = *((unsigned char *)  nl_langinfo(_NL_PAPER_HEIGHT));
+], gtk_ok=yes, gtk_ok=no)
+AC_MSG_RESULT($gtk_ok)
+if test "$gtk_ok" = "yes"; then
+  AC_DEFINE([HAVE__NL_PAPER_HEIGHT], [1],
+           [Define if _NL_PAPER_HEIGHT is available])
+fi
+
+# _NL_PAPER_WIDTH is an enum and not a define
+AC_MSG_CHECKING([for _NL_PAPER_WIDTH])
+AC_TRY_LINK([#include <langinfo.h>], [
+char c;
+c = *((unsigned char *)  nl_langinfo(_NL_PAPER_WIDTH));
+], gtk_ok=yes, gtk_ok=no)
+AC_MSG_RESULT($gtk_ok)
+if test "$gtk_ok" = "yes"; then
+  AC_DEFINE([HAVE__NL_PAPER_WIDTH], [1],
+           [Define if _NL_PAPER_WIDTH is available])
+fi
+       
 # sigsetjmp is a macro on some platforms, so AC_CHECK_FUNCS is not reliable
 AC_MSG_CHECKING(for sigsetjmp)
 AC_TRY_LINK([#include <setjmp.h>], [
@@ -1499,6 +1535,21 @@ AC_SUBST(GTK_DEP_CFLAGS)
 AC_SUBST(GTK_DEBUG_FLAGS)
 AC_SUBST(GTK_XIM_FLAGS)
 
+################################################################
+# Printing system checks
+################################################################
+
+AC_PATH_PROG(CUPS_CONFIG, cups-config, no)
+if test "x$CUPS_CONFIG" != "xno"; then
+  CUPS_CFLAGS=`cups-config --cflags | sed 's/-O[0-9]*//' | sed 's/-m[^\t]*//g'`
+  CUPS_LIBS=`cups-config --libs`
+
+  AC_SUBST(CUPS_CFLAGS)
+  AC_SUBST(CUPS_LIBS)
+fi
+AM_CONDITIONAL(HAVE_CUPS, test "x$CUPS_CONFIG" != "xno")
+
+       
 ################################################################
 # Strip -export-dynamic from the link lines of various libraries
 ################################################################
@@ -1638,6 +1689,7 @@ Makefile
 gdk-pixbuf-2.0.pc
 gdk-2.0.pc
 gtk+-2.0.pc
+gtk+-unix-print-2.0.pc
 gdk-pixbuf-2.0-uninstalled.pc
 gdk-2.0-uninstalled.pc
 gtk+-2.0-uninstalled.pc
@@ -1684,6 +1736,10 @@ modules/engines/pixbuf/Makefile
 modules/engines/ms-windows/Makefile
 modules/engines/ms-windows/Theme/Makefile
 modules/engines/ms-windows/Theme/gtk-2.0/Makefile
+modules/printbackends/Makefile
+modules/printbackends/cups/Makefile
+modules/printbackends/lpr/Makefile
+modules/printbackends/pdf/Makefile
 perf/Makefile
 contrib/Makefile
 contrib/gdk-pixbuf-xlib/Makefile
index d6259339ee73f6fdaa45826f3c16af0bca6d6879..66e5ef428fb72b973fdfbe460a511cd4d075a914 100644 (file)
@@ -1,3 +1,23 @@
+2006-04-21  Alexander Larsson  <alexl@redhat.com>
+
+       * gtk/Makefile.am:
+       * gtk/gtk-docs.sgml:
+       * gtk/gtk-sections.txt:
+       * gtk/gtk.types:
+       * gtk/images/pagesetupdialog.png:
+       * gtk/images/printdialog.png:
+       * gtk/tmpl/gtkpagesetup.sgml:
+       * gtk/tmpl/gtkpagesetupunixdialog.sgml:
+       * gtk/tmpl/gtkpapersize.sgml:
+       * gtk/tmpl/gtkprintcontext.sgml:
+       * gtk/tmpl/gtkprinter.sgml:
+       * gtk/tmpl/gtkprintjob.sgml:
+       * gtk/tmpl/gtkprintoperation.sgml:
+       * gtk/tmpl/gtkprintsettings.sgml:
+       * gtk/tmpl/gtkprintunixdialog.sgml:
+       * gtk/visual_index.xml:
+       Add docs for the printing support
+
 2006-04-17  Emmanuele Bassi  <ebassi@cvs.gnome.org>
 
        * gtk/tmp/gtkicontheme.sgml: Fix the code of the look up example.
index 4ceaa70889c41ae27e1c7b6d56723c74ba9bd762..3dc2b9b7dd2cc8ca76567a46ea637c3b8acf6143 100644 (file)
@@ -48,6 +48,10 @@ IGNORE_HFILES=                               \
        gtkmnemonichash.h               \
        gtkpathbar.h                    \
        gtkplugprivate.h                \
+       gtkprintbackend.h               \
+       gtkprinteroptionwidget.h        \
+       gtkprinter-private.h            \
+       gtkprintoperation-private.h     \
        gtkprivate.h                    \
        gtkrbtree.h                     \
        gtkrecentchooserdefault.h       \
@@ -277,6 +281,8 @@ HTML_IMAGES = \
        $(srcdir)/images/multiline-text.png                             \
        $(srcdir)/images/notebook.png                                   \
        $(srcdir)/images/panes.png                                      \
+       $(srcdir)/images/pagesetupdialog.png                            \
+       $(srcdir)/images/printdialog.png                                \
        $(srcdir)/images/progressbar.png                                \
        $(srcdir)/images/radio-group.png                                \
        $(srcdir)/images/recentchooserdialog.png                        \
index 794769b17e520f25f82dd10666a261228c20e48e..370a6dbaf859ee805d32e2913debf4a5ef484c22 100644 (file)
 <!ENTITY GtkPixmap SYSTEM "xml/gtkpixmap.xml">
 <!ENTITY GtkPlug SYSTEM "xml/gtkplug.xml">
 <!ENTITY GtkPreview SYSTEM "xml/gtkpreview.xml">
+<!ENTITY GtkPrintOperation SYSTEM "xml/gtkprintoperation.xml">
+<!ENTITY GtkPrintContext SYSTEM "xml/gtkprintcontext.xml">
+<!ENTITY GtkPrintSettings SYSTEM "xml/gtkprintsettings.xml">
+<!ENTITY GtkPageSetup SYSTEM "xml/gtkpagesetup.xml">
+<!ENTITY GtkPaperSize SYSTEM "xml/gtkpapersize.xml">
+<!ENTITY GtkPrinter SYSTEM "xml/gtkprinter.xml">
+<!ENTITY GtkPrintJob SYSTEM "xml/gtkprintjob.xml">
+<!ENTITY GtkPrintUnixDialog SYSTEM "xml/gtkprintunixdialog.xml">
+<!ENTITY GtkPageSetupUnixDialog SYSTEM "xml/gtkpagesetupunixdialog.xml">
 <!ENTITY GtkProgress SYSTEM "xml/gtkprogress.xml">
 <!ENTITY GtkProgressBar SYSTEM "xml/gtkprogressbar.xml">
 <!ENTITY GtkRadioAction SYSTEM "xml/gtkradioaction.xml">
@@ -513,6 +522,19 @@ that is, GUI components such as <link linkend="GtkButton">GtkButton</link> or
         &GtkScrolledWindow;
     </chapter>
 
+    <chapter id="Printing">
+      <title>Printing</title>
+      &GtkPrintOperation;
+      &GtkPrintContext;
+      &GtkPrintSettings;
+      &GtkPageSetup;
+      &GtkPaperSize;
+      &GtkPrintUnixDialog;
+      &GtkPrinter;
+      &GtkPrintJob; 
+      &GtkPageSetupUnixDialog;
+    </chapter>
+
     <chapter id="MiscObjects">
       <title>Miscellaneous</title>
         &GtkAdjustment;
index 5b4defd22faaa13ba932902ad13c2ca3c853665d..48e832e898ecd33077fdb8b34a07b9fbacc61034 100644 (file)
@@ -6057,3 +6057,333 @@ gtk_icon_factory_get_type
 gtk_icon_set_get_type
 gtk_icon_source_get_type
 </SECTION>
+
+
+<SECTION>
+<FILE>gtkprintoperation</FILE>
+<TITLE>High-level Printing API</TITLE>
+GtkPrintOperation
+GtkPrintStatus
+GtkPrintOperationResult
+GtkPrintError
+GTK_PRINT_ERROR
+gtk_print_error_quark
+gtk_print_operation_new
+gtk_print_operation_set_default_page_setup
+gtk_print_operation_get_default_page_setup
+gtk_print_operation_set_print_settings
+gtk_print_operation_get_print_settings
+gtk_print_operation_set_job_name
+gtk_print_operation_set_nr_of_pages
+gtk_print_operation_set_current_page
+gtk_print_operation_set_use_full_page
+gtk_print_operation_set_unit
+gtk_print_operation_set_show_dialog
+gtk_print_operation_set_pdf_target 
+gtk_print_operation_run
+gtk_print_operation_get_status
+gtk_print_operation_is_finished
+gtk_print_run_page_setup_dialog
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINT_OPERATION
+GTK_PRINT_OPERATION
+GTK_IS_PRINT_OPERATION
+
+<SUBSECTION Private>
+gtk_print_operation_get_type
+GtkPrintOperationPrivate
+</SECTION>
+
+
+<SECTION>
+<INCLUDE>gtk/gtkprintunixdialog.h</INCLUDE>
+<FILE>gtkprintunixdialog</FILE>
+<TITLE>GtkPrintUnixDialog</TITLE>
+GtkPrintUnixDialog
+gtk_print_unix_dialog_set_page_setup
+gtk_print_unix_dialog_get_page_setup
+gtk_print_unix_dialog_set_current_page
+gtk_print_unix_dialog_get_current_page
+gtk_print_unix_dialog_set_settings
+gtk_print_unix_dialog_get_settings
+gtk_print_unix_dialog_get_selected_printer
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINT_UNIX_DIALOG
+GTK_PRINT_UNIX_DIALOG
+GTK_PRINT_UNIX_DIALOG_CLASS
+GTK_IS_PRINT_UNIX_DIALOG
+GTK_IS_PRINT_UNIX_DIALOG_CLASS
+GTK_PRINT_UNIX_DIALOG_GET_CLASS
+
+<SUBSECTION Private>
+GtkPrintUnixDialogPrivate
+gtk_print_unix_dialog_get_type
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkprinter</FILE>
+<TITLE>GtkPrinter</TITLE>
+GtkPrinter
+GtkPrintBackend
+gtk_printer_new
+gtk_printer_get_backend
+gtk_printer_get_name
+gtk_printer_get_state_message
+gtk_printer_get_description
+gtk_printer_get_location
+gtk_printer_get_icon_name
+gtk_printer_get_job_count
+gtk_printer_is_active
+gtk_printer_is_virtual
+gtk_printer_is_default
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINTER
+GTK_PRINTER
+GTK_PRINTER_CLASS
+GTK_IS_PRINTER
+GTK_IS_PRINTER_CLASS
+GTK_PRINTER_GET_CLASS
+
+<SUBSECTION Private>
+GtkPrinterPrivate
+gtk_printer_get_type 
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkprintsettings</FILE>
+<TITLE>GtkPrintSettings</TITLE>
+GtkPrintSettings
+GtkPrintSettingsFunc
+gtk_print_settings_new
+gtk_print_settings_copy
+gtk_print_settings_has_key
+gtk_print_settings_get
+gtk_print_settings_set
+gtk_print_settings_unset
+gtk_print_settings_foreach
+gtk_print_settings_get_bool
+gtk_print_settings_set_bool
+gtk_print_settings_get_double
+gtk_print_settings_get_double_with_default
+gtk_print_settings_set_double
+gtk_print_settings_get_length
+gtk_print_settings_set_length
+gtk_print_settings_get_int
+gtk_print_settings_get_int_with_default
+gtk_print_settings_set_int
+gtk_print_settings_get_printer
+gtk_print_settings_set_printer
+GtkPageOrientation
+gtk_print_settings_get_orientation
+gtk_print_settings_set_orientation
+gtk_print_settings_get_paper_size
+gtk_print_settings_set_paper_size
+gtk_print_settings_get_paper_width
+gtk_print_settings_set_paper_width
+gtk_print_settings_get_paper_height
+gtk_print_settings_set_paper_height
+gtk_print_settings_get_use_color
+gtk_print_settings_set_use_color
+gtk_print_settings_get_collate
+gtk_print_settings_set_collate
+gtk_print_settings_get_reverse
+gtk_print_settings_set_reverse
+GtkPrintDuplex
+gtk_print_settings_get_duplex
+gtk_print_settings_set_duplex
+GtkPrintQuality
+gtk_print_settings_get_quality
+gtk_print_settings_set_quality
+gtk_print_settings_get_num_copies
+gtk_print_settings_set_num_copies
+gtk_print_settings_get_number_up
+gtk_print_settings_set_number_up
+gtk_print_settings_get_resolution
+gtk_print_settings_set_resolution
+gtk_print_settings_get_scale
+gtk_print_settings_set_scale
+gtk_print_settings_get_print_to_file
+gtk_print_settings_set_print_to_file
+GtkPrintPages
+gtk_print_settings_get_print_pages
+gtk_print_settings_set_print_pages
+GtkPageRange
+gtk_print_settings_get_page_ranges
+gtk_print_settings_set_page_ranges
+GtkPageSet
+gtk_print_settings_get_page_set
+gtk_print_settings_set_page_set
+gtk_print_settings_get_default_source
+gtk_print_settings_set_default_source
+gtk_print_settings_get_media_type
+gtk_print_settings_set_media_type
+gtk_print_settings_get_dither
+gtk_print_settings_set_dither
+gtk_print_settings_get_finishings
+gtk_print_settings_set_finishings
+gtk_print_settings_get_output_bin
+gtk_print_settings_set_output_bin
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINT_SETTINGS
+GTK_PRINT_SETTINGS
+GTK_IS_PRINT_SETTINGS
+
+<SUBSECTION Private>
+gtk_print_settings_get_type
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkpapersize</FILE>
+<TITLE>GtkPaperSize</TITLE>
+GtkPaperSize
+GtkUnit
+GTK_PAPER_NAME_A3
+GTK_PAPER_NAME_A4
+GTK_PAPER_NAME_A5
+GTK_PAPER_NAME_B5
+GTK_PAPER_NAME_LETTER
+GTK_PAPER_NAME_EXECUTIVE
+GTK_PAPER_NAME_LEGAL
+gtk_paper_size_new
+gtk_paper_size_new_from_ppd
+gtk_paper_size_new_custom
+gtk_paper_size_copy
+gtk_paper_size_free
+gtk_paper_size_is_equal
+gtk_paper_size_get_name
+gtk_paper_size_get_display_name
+gtk_paper_size_get_ppd_name
+gtk_paper_size_get_width
+gtk_paper_size_get_height
+gtk_paper_size_is_custom
+gtk_paper_size_set_size
+gtk_paper_size_get_default_top_margin
+gtk_paper_size_get_default_bottom_margin
+gtk_paper_size_get_default_left_margin
+gtk_paper_size_get_default_right_margin
+gtk_paper_size_get_default
+
+<SUBSECTION Standard>
+GTK_TYPE_PAPER_SIZE
+<SUBSECTION Private>
+gtk_paper_size_get_type
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkpagesetup</FILE>
+<TITLE>GtkPageSetup</TITLE>
+GtkPageSetup
+gtk_page_setup_new
+gtk_page_setup_copy
+gtk_page_setup_get_orientation
+gtk_page_setup_set_orientation
+gtk_page_setup_get_paper_size
+gtk_page_setup_set_paper_size
+gtk_page_setup_get_top_margin
+gtk_page_setup_set_top_margin
+gtk_page_setup_get_bottom_margin
+gtk_page_setup_set_bottom_margin
+gtk_page_setup_get_left_margin
+gtk_page_setup_set_left_margin
+gtk_page_setup_get_right_margin
+gtk_page_setup_set_right_margin
+gtk_page_setup_set_paper_size_and_default_margins
+gtk_page_setup_get_paper_width
+gtk_page_setup_get_paper_height
+gtk_page_setup_get_page_width
+gtk_page_setup_get_page_height
+
+<SUBSECTION Standard>
+GTK_TYPE_PAGE_SETUP
+GTK_PAGE_SETUP
+GTK_IS_PAGE_SETUP
+
+<SUBSECTION Private>
+gtk_page_setup_get_type
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkprintcontext</FILE>
+<TITLE>GtkPrintContext</TITLE>
+GtkPrintContext
+gtk_print_context_get_cairo
+gtk_print_context_get_page_setup
+gtk_print_context_get_width
+gtk_print_context_get_height
+gtk_print_context_get_dpi_x
+gtk_print_context_get_dpi_y
+gtk_print_context_get_fontmap
+gtk_print_context_create_context
+gtk_print_context_create_layout
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINT_CONTEXT
+GTK_PRINT_CONTEXT
+GTK_IS_PRINT_CONTEXT
+
+<SUBSECTION Private>
+gtk_print_context_get_type
+</SECTION>
+
+
+<SECTION>
+<FILE>gtkprintjob</FILE>
+<TITLE>GtkPrintJob</TITLE>
+GtkPrintJob
+GtkPrintJobCompleteFunc
+gtk_print_job_new
+gtk_print_job_get_settings
+gtk_print_job_get_printer
+gtk_print_job_get_title
+gtk_print_job_get_status
+gtk_print_job_set_source_file
+gtk_print_job_get_surface
+gtk_print_job_send
+
+<SUBSECTION Standard>
+GTK_TYPE_PRINT_JOB
+GTK_PRINT_JOB
+GTK_PRINT_JOB_CLASS
+GTK_IS_PRINT_JOB
+GTK_IS_PRINT_JOB_CLASS
+GTK_PRINT_JOB_GET_CLASS
+
+<SUBSECTION Private>
+GtkPrintJobPrivate
+gtk_print_job_get_type
+</SECTION>
+
+
+<SECTION>
+<INCLUDE>gtk/gtkpagesetupunixdialog.h</INCLUDE>
+<FILE>gtkpagesetupunixdialog</FILE>
+<TITLE>GtkPageSetupUnixDialog</TITLE>
+GtkPageSetupUnixDialog
+gtk_page_setup_unix_dialog_new
+gtk_page_setup_unix_dialog_set_page_setup
+gtk_page_setup_unix_dialog_get_page_setup
+gtk_page_setup_unix_dialog_set_print_settings
+gtk_page_setup_unix_dialog_get_print_settings
+
+<SUBSECTION Standard>
+GtkPageSetupUnixDialogClass
+GTK_TYPE_PAGE_SETUP_UNIX_DIALOG
+GTK_PAGE_SETUP_UNIX_DIALOG
+GTK_PAGE_SETUP_UNIX_DIALOG_CLASS
+GTK_IS_PAGE_SETUP_UNIX_DIALOG
+GTK_IS_PAGE_SETUP_UNIX_DIALOG_CLASS
+GTK_PAGE_SETUP_UNIX_DIALOG_GET_CLASS
+
+<SUBSECTION Private>
+GtkPageSetupUnixDialogPrivate
+gtk_page_setup_unix_dialog_get_type
+</SECTION>
index 9650289c71236393f3a39a333de7b45c18b75ca9..89be3ba80ee7e713e4c600c4b453c7d0a3395504 100644 (file)
@@ -96,10 +96,19 @@ gtk_notebook_get_type
 gtk_object_get_type
 gtk_old_editable_get_type
 gtk_option_menu_get_type
+gtk_page_setup_get_type
+gtk_page_setup_unix_dialog_get_type
 gtk_paned_get_type
+gtk_paper_size_get_type
 gtk_pixmap_get_type
 gtk_plug_get_type
 gtk_preview_get_type
+gtk_printer_get_type
+gtk_print_context_get_type
+gtk_print_job_get_type
+gtk_print_operation_get_type
+gtk_print_settings_get_type
+gtk_print_unix_dialog_get_type
 gtk_progress_bar_get_type
 gtk_progress_get_type
 gtk_radio_action_get_type
diff --git a/docs/reference/gtk/images/pagesetupdialog.png b/docs/reference/gtk/images/pagesetupdialog.png
new file mode 100644 (file)
index 0000000..7f79a2c
Binary files /dev/null and b/docs/reference/gtk/images/pagesetupdialog.png differ
diff --git a/docs/reference/gtk/images/printdialog.png b/docs/reference/gtk/images/printdialog.png
new file mode 100644 (file)
index 0000000..7645b70
Binary files /dev/null and b/docs/reference/gtk/images/printdialog.png differ
diff --git a/docs/reference/gtk/tmpl/gtkpagesetup.sgml b/docs/reference/gtk/tmpl/gtkpagesetup.sgml
new file mode 100644 (file)
index 0000000..1a15fb8
--- /dev/null
@@ -0,0 +1,251 @@
+<!-- ##### SECTION Title ##### -->
+GtkPageSetup
+
+<!-- ##### SECTION Short_Description ##### -->
+Stores page setup information
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A GtkPageSetup object stores the page size, orientation and margins. 
+The idea is that you can get one of these from the page setup dialog 
+and then pass it to the #GtkPrittntOperation when printing. 
+The benefit of splitting this out of the #GtkPrintSettings is that 
+these affect the actual layout of the page, and thus need to be set 
+long before user prints. 
+</para>
+<para id="print-margins">
+The margins specified in this object are the "print margins", i.e. the 
+parts of the page that the printer cannot print on. These are different
+from the layout margins that a word processor uses; they are typically
+used to determine the <emphasis>minimal</emphasis> size for the layout 
+margins.
+</para>
+<para>
+To obtain a #GtkPageSetup use gtk_page_setup_new()
+to get the defaults, or use gtk_print_run_page_setup_dialog() to show 
+the page setup dialog and receive the resulting page setup.
+</para>
+<example>
+<title>A page setup dialog</title>
+<programlisting>
+static GtkPrintSettings *settings = NULL;
+static GtkPageSetup *page_setup = NULL;
+
+static void
+do_page_setup (void)
+{
+  GtkPageSetup *new_page_setup;
+
+  if (settings == NULL)
+    settings = gtk_print_settings_new (<!-- -->);
+
+  new_page_setup = gtk_print_run_page_setup_dialog (GTK_WINDOW (main_window),
+                                                    page_setup, settings);
+
+  if (page_setup)
+    g_object_unref (page_setup);
+
+  page_setup = new_page_setup;
+}
+</programlisting>
+</example>
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPageSetup ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gtk_page_setup_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_copy ##### -->
+<para>
+
+</para>
+
+@other: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_orientation ##### -->
+<para>
+
+</para>
+
+@setup: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_orientation ##### -->
+<para>
+
+</para>
+
+@setup: 
+@orientation: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_paper_size ##### -->
+<para>
+
+</para>
+
+@setup: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_paper_size ##### -->
+<para>
+
+</para>
+
+@setup: 
+@size: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_top_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_top_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@margin: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_bottom_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_bottom_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@margin: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_left_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_left_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@margin: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_right_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_right_margin ##### -->
+<para>
+
+</para>
+
+@setup: 
+@margin: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_set_paper_size_and_default_margins ##### -->
+<para>
+
+</para>
+
+@setup: 
+@size: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_paper_width ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_paper_height ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_page_width ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_get_page_height ##### -->
+<para>
+
+</para>
+
+@setup: 
+@unit: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkpagesetupunixdialog.sgml b/docs/reference/gtk/tmpl/gtkpagesetupunixdialog.sgml
new file mode 100644 (file)
index 0000000..c98752a
--- /dev/null
@@ -0,0 +1,80 @@
+<!-- ##### SECTION Title ##### -->
+GtkPageSetupUnixDialog
+
+<!-- ##### SECTION Short_Description ##### -->
+A page setup dialog
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GtkPageSetupUnixDialog implements a page setup dialog for platforms
+which don't provide a native page setup dialog, like Unix. It can
+be used very much like any other GTK+ dialog, at the cost of
+the portability offered by the <link
+linkend="gtk-High-level-Printing-API">high-level printing API</link>
+</para>
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPageSetupUnixDialog ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gtk_page_setup_unix_dialog_new ##### -->
+<para>
+
+</para>
+
+@title: 
+@parent: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_unix_dialog_set_page_setup ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@page_setup: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_unix_dialog_get_page_setup ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_unix_dialog_set_print_settings ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@print_settings: 
+
+
+<!-- ##### FUNCTION gtk_page_setup_unix_dialog_get_print_settings ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkpapersize.sgml b/docs/reference/gtk/tmpl/gtkpapersize.sgml
new file mode 100644 (file)
index 0000000..4298c4e
--- /dev/null
@@ -0,0 +1,275 @@
+<!-- ##### SECTION Title ##### -->
+GtkPaperSize
+
+<!-- ##### SECTION Short_Description ##### -->
+Support for named paper sizes
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GtkPaperSize handles paper sizes. It uses the standard called 
+"PWG 5101.1-2002 PWG: Standard for Media Standardized Names" 
+<!-- FIXME link here -->
+to name the paper sizes (and to get the data for the page sizes).
+In addition to standard paper sizes, GtkPaperSize allows to
+construct custom paper sizes with arbitrary dimensions.
+</para>
+<para>
+The #GtkPaperSize object stores not only the dimensions (width
+and height) of a paper size and its name, it also provides
+default <link linkend="print-margins">print margins</link>.
+</para>
+
+<para>
+Printing support has been added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+#GtkPageSetup
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPaperSize ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ENUM GtkUnit ##### -->
+<para>
+
+</para>
+
+@GTK_UNIT_PIXEL: 
+@GTK_UNIT_POINTS: 
+@GTK_UNIT_INCH: 
+@GTK_UNIT_MM: 
+
+<!-- ##### MACRO GTK_PAPER_NAME_A3 ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_A4 ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_A5 ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_B5 ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_LETTER ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_EXECUTIVE ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO GTK_PAPER_NAME_LEGAL ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION gtk_paper_size_new ##### -->
+<para>
+
+</para>
+
+@name: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_new_from_ppd ##### -->
+<para>
+
+</para>
+
+@ppd_name: 
+@ppd_display_name: 
+@width: 
+@height: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_new_custom ##### -->
+<para>
+
+</para>
+
+@name: 
+@display_name: 
+@width: 
+@height: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_copy ##### -->
+<para>
+
+</para>
+
+@other: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_free ##### -->
+<para>
+
+</para>
+
+@size: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_is_equal ##### -->
+<para>
+
+</para>
+
+@size1: 
+@size2: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_name ##### -->
+<para>
+
+</para>
+
+@size: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_display_name ##### -->
+<para>
+
+</para>
+
+@size: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_ppd_name ##### -->
+<para>
+
+</para>
+
+@size: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_width ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_height ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_is_custom ##### -->
+<para>
+
+</para>
+
+@size: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_set_size ##### -->
+<para>
+
+</para>
+
+@size: 
+@width: 
+@height: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_default_top_margin ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_default_bottom_margin ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_default_left_margin ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_default_right_margin ##### -->
+<para>
+
+</para>
+
+@size: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_paper_size_get_default ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprintcontext.sgml b/docs/reference/gtk/tmpl/gtkprintcontext.sgml
new file mode 100644 (file)
index 0000000..26a2651
--- /dev/null
@@ -0,0 +1,175 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrintContext
+
+<!-- ##### SECTION Short_Description ##### -->
+Encapsulates context for drawing pages
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A GtkPrintContext encapsulates context information that is required when
+drawing pages for printing, such as the cairo context and important 
+parameters like page size and resolution. It also lets you easily
+create #PangoLayout and #PangoContext objects that match the font metrics 
+of the cairo surface.
+</para>
+<para>
+GtkPrintContext objects gets passed to the ::begin-print, ::end-print, 
+::request-page-setup and ::draw-page signals on the #GtkPrintOperation.
+</para>
+
+<example>
+<title>Using GtkPrintContext in a ::draw-page callback</title>
+<programlisting>
+static void
+draw_page (GtkPrintOperation *operation,
+          GtkPrintContext   *context,
+          int                page_nr)
+{
+  cairo_t *cr;
+  PangoLayout *layout;
+  PangoFontDescription *desc;
+  
+  cr = gtk_print_context_get_cairo (context);
+
+  /* Draw a red rectangle, as wide as the paper (inside the margins) */
+  cairo_set_source_rgb (cr, 1.0, 0, 0);
+  cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), 50);
+  
+  cairo_fill (cr);
+
+  /* Draw some lines */
+  cairo_move_to (cr, 20, 10);
+  cairo_line_to (cr, 40, 20);
+  cairo_arc (cr, 60, 60, 20, 0, M_PI);
+  cairo_line_to (cr, 80, 20);
+  
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_set_line_width (cr, 5);
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+  cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+  
+  cairo_stroke (cr);
+
+  /* Draw some text */ 
+  layout = gtk_print_context_create_layout (context);
+  pango_layout_set_text (layout, "Hello World! Printing is easy", -1);
+  desc = pango_font_description_from_string ("sans 28");
+  pango_layout_set_font_description (layout, desc);
+  pango_font_description_free (desc);
+
+  cairo_move_to (cr, 30, 20);
+  pango_cairo_layout_path (cr, layout);
+
+  /* Font Outline */
+  cairo_set_source_rgb (cr, 0.93, 1.0, 0.47);
+  cairo_set_line_width (cr, 0.5);
+  cairo_stroke_preserve (cr);
+
+  /* Font Fill */
+  cairo_set_source_rgb (cr, 0, 0.0, 1.0);
+  cairo_fill (cr);
+  
+  g_object_unref (layout);
+}
+</programlisting>
+</example>
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrintContext ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gtk_print_context_get_cairo ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_page_setup ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_width ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_height ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_dpi_x ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_dpi_y ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_get_fontmap ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_create_context ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_context_create_layout ##### -->
+<para>
+
+</para>
+
+@context: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprinter.sgml b/docs/reference/gtk/tmpl/gtkprinter.sgml
new file mode 100644 (file)
index 0000000..36f0da6
--- /dev/null
@@ -0,0 +1,163 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrinter
+
+<!-- ##### SECTION Short_Description ##### -->
+Represents a printer
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A #GtkPrinter object represents a printer. You only need to 
+deal directly with printers if you use the non-portable 
+#GtkPrintUnixDialog API. 
+</para>
+<para>
+A #GtkPrinter allows to get status information about the printer, 
+such as its description, its location, the number of queued jobs, 
+etc. Most importantly, a #GtkPrinter object can be used to create
+a #GtkPrintJob object, which lets you print to the printer.
+</para>
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrinter ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GtkPrinter::details-acquired ##### -->
+<para>
+
+</para>
+
+@printer: the object which received the signal.
+@arg1: 
+
+<!-- ##### ARG GtkPrinter:backend ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:icon-name ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:is-virtual ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:job-count ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:location ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:name ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrinter:state-message ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gtk_printer_new ##### -->
+<para>
+
+</para>
+
+@name: 
+@backend: 
+@virtual: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_backend ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_name ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_state_message ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_location ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_icon_name ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_get_job_count ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_is_active ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_printer_is_virtual ##### -->
+<para>
+
+</para>
+
+@printer: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprintjob.sgml b/docs/reference/gtk/tmpl/gtkprintjob.sgml
new file mode 100644 (file)
index 0000000..1d94ddc
--- /dev/null
@@ -0,0 +1,159 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrintJob
+
+<!-- ##### SECTION Short_Description ##### -->
+Represents a print job
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A #GtkPrintJob object represents a job that is sent to a
+printer. You only need to deal directly with print jobs if 
+you use the non-portable #GtkPrintUnixDialog API. 
+</para>
+<para>
+Use gtk_print_job_get_surface() to obtain the cairo surface
+onto which the pages must be drawn. Use gtk_print_job_send()
+to send the finished job to the printer. If you don't use cairo
+#GtkPrintJob also  supports printing of manually generated postscript,
+via gtk_print_job_set_source_file().
+<!-- FIXME more details needed here -->
+</para>
+<!-- FIXME examples ? -->
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrintJob ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GtkPrintJob::status-changed ##### -->
+<para>
+
+</para>
+
+@printjob: the object which received the signal.
+
+<!-- ##### ARG GtkPrintJob:page-setup ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrintJob:printer ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrintJob:settings ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GtkPrintJob:title ##### -->
+<para>
+
+</para>
+
+<!-- ##### USER_FUNCTION GtkPrintJobCompleteFunc ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@user_data: 
+@error: 
+
+
+<!-- ##### FUNCTION gtk_print_job_new ##### -->
+<para>
+
+</para>
+
+@title: 
+@printer: 
+@settings: 
+@page_setup: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_get_settings ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_get_printer ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_get_title ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_get_status ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_set_source_file ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@filename: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_get_surface ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_job_send ##### -->
+<para>
+
+</para>
+
+@print_job: 
+@callback: 
+@user_data: 
+@dnotify: 
+@error: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprintoperation.sgml b/docs/reference/gtk/tmpl/gtkprintoperation.sgml
new file mode 100644 (file)
index 0000000..00e26dd
--- /dev/null
@@ -0,0 +1,321 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrintOperation
+
+<!-- ##### SECTION Short_Description ##### -->
+High-level Printing API
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GtkPrintOperation is the high-level, portable printing API. It looks 
+a bit different than other GTK+ dialogs such as the #GtkFileChooser, 
+since some platforms don't expose enough infrastructure to implement
+a good print dialog. On such platforms, GtkPrintOperation uses the 
+native print dialog. On platforms which do not provide a native 
+print dialog, GTK+ uses its own, see #GtkPrintUnixDialog.
+</para>
+
+<para>
+The typical way to use the high-level printing API is to create a 
+#GtkPrintOperation object with gtk_print_operation_new() when the user 
+selects to print. Then you set some properties on it, e.g. the page size, 
+any #GtkPrintSettings from previous print operations, the number of pages, 
+the current page, etc. 
+</para>
+<para>
+Then you start the print operation by calling gtk_print_operation_run().
+It will then show a dialog, let the user select a printer and options. 
+When the user finished the dialog various signals will be emitted on the 
+#GtkPrintOperation, the main one being ::draw-page, which you are supposed 
+to catch and render the page on the provided #GtkPrintContext using Cairo.
+</para>
+
+<example>
+<title>The high-level printing API</title>
+<programlisting>
+static GtkPrintSettings *settings = NULL;
+
+static void
+do_print (void)
+{
+  GtkPrintOperation *print;
+  GtkPrintOperationResult res;
+
+  print = gtk_print_operation_new (<!-- -->);
+
+  if (settings != NULL) 
+    gtk_print_operation_set_print_settings (print, settings);
+
+  g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), NULL);
+  g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), NULL);
+
+  res = gtk_print_operation_run (print, GTK_WINDOW (main_window), NULL);
+
+  if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
+    {
+      if (settings != NULL)
+        g_object_unref (settings);
+      settings = g_object_ref (gtk_print_operation_get_print_settings (print));
+    }
+
+  g_object_unref (print);
+}
+
+</programlisting>
+</example>
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+#GtkPrintContext, #GtkPrintUnixDialog
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrintOperation ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GtkPrintOperation::begin-print ##### -->
+<para>
+
+</para>
+
+@printoperation: the object which received the signal.
+@arg1: 
+
+<!-- ##### SIGNAL GtkPrintOperation::draw-page ##### -->
+<para>
+
+</para>
+
+@printoperation: the object which received the signal.
+@arg1: 
+@arg2: 
+
+<!-- ##### SIGNAL GtkPrintOperation::end-print ##### -->
+<para>
+
+</para>
+
+@printoperation: the object which received the signal.
+@arg1: 
+
+<!-- ##### SIGNAL GtkPrintOperation::request-page-setup ##### -->
+<para>
+
+</para>
+
+@printoperation: the object which received the signal.
+@arg1: 
+@arg2: 
+@arg3: 
+
+<!-- ##### SIGNAL GtkPrintOperation::status-changed ##### -->
+<para>
+
+</para>
+
+@printoperation: the object which received the signal.
+
+<!-- ##### ENUM GtkPrintStatus ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_STATUS_INITIAL: 
+@GTK_PRINT_STATUS_PREPARING: 
+@GTK_PRINT_STATUS_GENERATING_DATA: 
+@GTK_PRINT_STATUS_SENDING_DATA: 
+@GTK_PRINT_STATUS_PENDING: 
+@GTK_PRINT_STATUS_PENDING_ISSUE: 
+@GTK_PRINT_STATUS_PRINTING: 
+@GTK_PRINT_STATUS_FINISHED: 
+@GTK_PRINT_STATUS_FINISHED_ABORTED: 
+
+<!-- ##### ENUM GtkPrintOperationResult ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_OPERATION_RESULT_ERROR: 
+@GTK_PRINT_OPERATION_RESULT_APPLY: 
+@GTK_PRINT_OPERATION_RESULT_CANCEL: 
+
+<!-- ##### ENUM GtkPrintError ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_ERROR_GENERAL: 
+@GTK_PRINT_ERROR_INTERNAL_ERROR: 
+@GTK_PRINT_ERROR_NOMEM: 
+
+<!-- ##### MACRO GTK_PRINT_ERROR ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION gtk_print_error_quark ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_default_page_setup ##### -->
+<para>
+
+</para>
+
+@op: 
+@default_page_setup: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_get_default_page_setup ##### -->
+<para>
+
+</para>
+
+@op: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_print_settings ##### -->
+<para>
+
+</para>
+
+@op: 
+@print_settings: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_get_print_settings ##### -->
+<para>
+
+</para>
+
+@op: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_job_name ##### -->
+<para>
+
+</para>
+
+@op: 
+@job_name: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_nr_of_pages ##### -->
+<para>
+
+</para>
+
+@op: 
+@n_pages: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_current_page ##### -->
+<para>
+
+</para>
+
+@op: 
+@current_page: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_use_full_page ##### -->
+<para>
+
+</para>
+
+@op: 
+@full_page: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_unit ##### -->
+<para>
+
+</para>
+
+@op: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_show_dialog ##### -->
+<para>
+
+</para>
+
+@op: 
+@show_dialog: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_set_pdf_target ##### -->
+<para>
+
+</para>
+
+@op: 
+@filename: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_run ##### -->
+<para>
+
+</para>
+
+@op: 
+@parent: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_get_status ##### -->
+<para>
+
+</para>
+
+@op: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_operation_is_finished ##### -->
+<para>
+
+</para>
+
+@op: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_run_page_setup_dialog ##### -->
+<para>
+
+</para>
+
+@parent: 
+@page_setup: 
+@settings: 
+@Returns: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprintsettings.sgml b/docs/reference/gtk/tmpl/gtkprintsettings.sgml
new file mode 100644 (file)
index 0000000..b9d9a4f
--- /dev/null
@@ -0,0 +1,697 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrintSettings
+
+<!-- ##### SECTION Short_Description ##### -->
+Stores print settings 
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+A GtkPrintSettings object represents the settings of a print dialog in 
+a system-independent way. The main use for this object is that once 
+you've printed you can get a settings object that represents the settings 
+the user chose, and the next time you print you can pass that object in so 
+that the user doesn't have to re-set all his settings. 
+</para>
+<para>
+Its also possible to enumerate the settings so that you can easily save 
+the settings for the next time your app runs, or even store them in a 
+document. The predefined keys try to use shared values as much as possible 
+so that moving such a document between systems still works.
+</para>
+
+<!-- TODO example of getting, storing and setting settings -->
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrintSettings ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### USER_FUNCTION GtkPrintSettingsFunc ##### -->
+<para>
+
+</para>
+
+@key: 
+@value: 
+@user_data: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_copy ##### -->
+<para>
+
+</para>
+
+@other: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_has_key ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@value: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_unset ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_foreach ##### -->
+<para>
+
+</para>
+
+@settings: 
+@func: 
+@user_data: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_bool ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_bool ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@value: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_double ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_double_with_default ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@def: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_double ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@value: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_length ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_length ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@value: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_int ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_int_with_default ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@def: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_int ##### -->
+<para>
+
+</para>
+
+@settings: 
+@key: 
+@value: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_printer ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_printer ##### -->
+<para>
+
+</para>
+
+@settings: 
+@printer: 
+
+
+<!-- ##### ENUM GtkPageOrientation ##### -->
+<para>
+
+</para>
+
+@GTK_PAGE_ORIENTATION_PORTRAIT: 
+@GTK_PAGE_ORIENTATION_LANDSCAPE: 
+@GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: 
+@GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_orientation ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_orientation ##### -->
+<para>
+
+</para>
+
+@settings: 
+@orientation: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_paper_size ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_paper_size ##### -->
+<para>
+
+</para>
+
+@settings: 
+@paper_size: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_paper_width ##### -->
+<para>
+
+</para>
+
+@settings: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_paper_width ##### -->
+<para>
+
+</para>
+
+@settings: 
+@width: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_paper_height ##### -->
+<para>
+
+</para>
+
+@settings: 
+@unit: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_paper_height ##### -->
+<para>
+
+</para>
+
+@settings: 
+@width: 
+@unit: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_use_color ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_use_color ##### -->
+<para>
+
+</para>
+
+@settings: 
+@use_color: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_collate ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_collate ##### -->
+<para>
+
+</para>
+
+@settings: 
+@collate: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_reverse ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_reverse ##### -->
+<para>
+
+</para>
+
+@settings: 
+@reverse: 
+
+
+<!-- ##### ENUM GtkPrintDuplex ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_DUPLEX_SIMPLEX: 
+@GTK_PRINT_DUPLEX_HORIZONTAL: 
+@GTK_PRINT_DUPLEX_VERTICAL: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_duplex ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_duplex ##### -->
+<para>
+
+</para>
+
+@settings: 
+@duplex: 
+
+
+<!-- ##### ENUM GtkPrintQuality ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_QUALITY_LOW: 
+@GTK_PRINT_QUALITY_NORMAL: 
+@GTK_PRINT_QUALITY_HIGH: 
+@GTK_PRINT_QUALITY_DRAFT: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_quality ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_quality ##### -->
+<para>
+
+</para>
+
+@settings: 
+@quality: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_num_copies ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_num_copies ##### -->
+<para>
+
+</para>
+
+@settings: 
+@num_copies: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_number_up ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_number_up ##### -->
+<para>
+
+</para>
+
+@settings: 
+@number_up: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_resolution ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_resolution ##### -->
+<para>
+
+</para>
+
+@settings: 
+@resolution: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_scale ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_scale ##### -->
+<para>
+
+</para>
+
+@settings: 
+@scale: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_print_to_file ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_print_to_file ##### -->
+<para>
+
+</para>
+
+@settings: 
+@print_to_file: 
+
+
+<!-- ##### ENUM GtkPrintPages ##### -->
+<para>
+
+</para>
+
+@GTK_PRINT_PAGES_ALL: 
+@GTK_PRINT_PAGES_CURRENT: 
+@GTK_PRINT_PAGES_RANGES: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_print_pages ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_print_pages ##### -->
+<para>
+
+</para>
+
+@settings: 
+@pages: 
+
+
+<!-- ##### STRUCT GtkPageRange ##### -->
+<para>
+
+</para>
+
+@start: 
+@end: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_page_ranges ##### -->
+<para>
+
+</para>
+
+@settings: 
+@num_ranges: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_page_ranges ##### -->
+<para>
+
+</para>
+
+@settings: 
+@page_ranges: 
+@num_ranges: 
+
+
+<!-- ##### ENUM GtkPageSet ##### -->
+<para>
+
+</para>
+
+@GTK_PAGE_SET_ALL: 
+@GTK_PAGE_SET_EVEN: 
+@GTK_PAGE_SET_ODD: 
+
+<!-- ##### FUNCTION gtk_print_settings_get_page_set ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_page_set ##### -->
+<para>
+
+</para>
+
+@settings: 
+@page_set: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_default_source ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_default_source ##### -->
+<para>
+
+</para>
+
+@settings: 
+@default_source: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_media_type ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_media_type ##### -->
+<para>
+
+</para>
+
+@settings: 
+@media_type: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_dither ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_dither ##### -->
+<para>
+
+</para>
+
+@settings: 
+@dither: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_finishings ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_finishings ##### -->
+<para>
+
+</para>
+
+@settings: 
+@finishings: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_get_output_bin ##### -->
+<para>
+
+</para>
+
+@settings: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_settings_set_output_bin ##### -->
+<para>
+
+</para>
+
+@settings: 
+@output_bin: 
+
+
diff --git a/docs/reference/gtk/tmpl/gtkprintunixdialog.sgml b/docs/reference/gtk/tmpl/gtkprintunixdialog.sgml
new file mode 100644 (file)
index 0000000..f27d5da
--- /dev/null
@@ -0,0 +1,86 @@
+<!-- ##### SECTION Title ##### -->
+GtkPrintUnixDialog
+
+<!-- ##### SECTION Short_Description ##### -->
+A print dialog 
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+GtkPrintUnixDialog implements a print dialog for platforms
+which don't provide a native print dialog, like Unix. It can 
+be used very much like any other GTK+ dialog, at the cost of 
+the portability offered by the <link 
+linkend="gtk-High-level-Printing-API">high-level printing API</link>
+</para>
+<para>
+In order to print something with #GtkPrintUnixDialog, you need
+to use gtk_print_unix_dialog_get_selected_printer() to obtain
+a #GtkPrinter object and use it to construct a #GtkPrintJob using
+gtk_print_job_new().
+</para>
+
+<!-- FIXME example here -->
+
+<para>
+Printing support was added in GTK+ 2.10.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+#GtkPageSetupUnixDialog, #GtkPrinter, #GtkPrintJob
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GtkPrintUnixDialog ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gtk_print_unix_dialog_set_page_setup ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@page_setup: 
+
+
+<!-- ##### FUNCTION gtk_print_unix_dialog_set_current_page ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@current_page: 
+
+
+<!-- ##### FUNCTION gtk_print_unix_dialog_set_settings ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@settings: 
+
+
+<!-- ##### FUNCTION gtk_print_unix_dialog_get_settings ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gtk_print_unix_dialog_get_selected_printer ##### -->
+<para>
+
+</para>
+
+@dialog: 
+@Returns: 
+
+
index ef3cc6b567b30587dfc9a89ba12fbb4d90ad0ada..c6dc17eab6dc0cf2a48000d677e03e055d376907 100644 (file)
   <link linkend="GtkPaned">
     <inlinegraphic fileref="panes.png" format="PNG"></inlinegraphic>
   </link> 
+  <link linkend="GtkPageSetupUnixDialog">
+    <inlinegraphic fileref="pagesetupdialog.png" format="PNG"></inlinegraphic>
+  </link> 
+  <link linkend="GtkPrintUnixDialog">
+    <inlinegraphic fileref="printdialog.png" format="PNG"></inlinegraphic>
+  </link> 
   <link linkend="GtkProgressBar">
     <inlinegraphic fileref="progressbar.png" format="PNG"></inlinegraphic>
   </link>
index 4d822610bfcecffd00b3663b60567690abd328aa..2675632b632045252ed801264dba3d5fc79b1183 100644 (file)
@@ -1,3 +1,5 @@
+#include <gtk/gtkprintunixdialog.h>
+#include <gtk/gtkpagesetupunixdialog.h>
 #include <gdk/gdkkeysyms.h>
 #include <X11/Xatom.h>
 #include <gdkx.h>
@@ -666,6 +668,43 @@ create_filesel (void)
   return info;
 }
 
+static WidgetInfo *
+create_print_dialog (void)
+{
+  WidgetInfo *info;
+  GtkWidget *widget;
+
+  widget = gtk_print_unix_dialog_new ("Print Dialog", NULL);   
+  gtk_widget_set_size_request (widget, 505, 350);
+  info = new_widget_info ("printdialog", widget, ASIS);
+  info->include_decorations = TRUE;
+
+  return info;
+}
+
+static WidgetInfo *
+create_page_setup_dialog (void)
+{
+  WidgetInfo *info;
+  GtkWidget *widget;
+  GtkPageSetup *page_setup;
+  GtkPrintSettings *settings;
+
+  page_setup = gtk_page_setup_new ();
+  settings = gtk_print_settings_new ();
+  widget = gtk_page_setup_unix_dialog_new ("Page Setup Dialog", NULL);   
+  gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (widget),
+                                            page_setup);
+  gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (widget),
+                                                settings);
+
+  info = new_widget_info ("pagesetupdialog", widget, ASIS);
+  gtk_widget_set_app_paintable (info->window, FALSE);
+  info->include_decorations = TRUE;
+
+  return info;
+}
+
 static WidgetInfo *
 create_toolbar (void)
 {
@@ -940,6 +979,8 @@ get_all_widgets (void)
   retval = g_list_prepend (retval, create_fontsel ());
   retval = g_list_prepend (retval, create_assistant ());
   retval = g_list_prepend (retval, create_recent_chooser_dialog ());
+  retval = g_list_prepend (retval, create_page_setup_dialog ());
+  retval = g_list_prepend (retval, create_print_dialog ());
 
   return retval;
 }
index 7046e9a0c2c359ccbf7bdd41a1df45f80803522a..97a2498dac634c8d2b1ee7bf6c48f825ed4d5688 100644 (file)
@@ -1,7 +1,6 @@
 ## Makefile.am for gtk+/gdk/gdk-directfb
 
 libgdkincludedir = $(includedir)/gtk-2.0/gdk
-libgdkgdk_directfbincludedir = $(includedir)/gtk-2.0/gdk/gdk-directfb
 
 INCLUDES =             \
        -DG_LOG_DOMAIN=\"Gdk-DirectFB\" \
@@ -23,8 +22,8 @@ libgdk_directfb_la_SOURCES =  \
        gdkcolor-directfb.c     \
        gdkcursor-directfb.c    \
        gdkdnd-directfb.c       \
-    gdkdisplay-directfb.c   \
-    gdkdisplay-directfb.h   \
+       gdkdisplay-directfb.c   \
+       gdkdisplay-directfb.h   \
        gdkdrawable-directfb.c  \
        gdkevents-directfb.c    \
        gdkfont-directfb.c      \
@@ -50,8 +49,8 @@ libgdk_directfb_la_SOURCES =  \
        x-cursors.xbm
 
 libgdkinclude_HEADERS =                \
-       gdkdirectfb.h \
+       gdkdirectfb.h           \
        gdkprivate-directfb.h
 
 
-EXTRA_DIST = AUTHORS README TODO ChangeLog
+EXTRA_DIST = AUTHORS README TODO 
index 908c549c686a14a5910aaf97955092e60f231f85..84c1a7d96301bc5d0f78daae62d2563444ed20d9 100644 (file)
@@ -1110,6 +1110,12 @@ gdk_win32_drawable_get_handle
 #endif
 #endif
 
+#if IN_HEADER(__GDK_WIN32_H__)
+#if IN_FILE(__GDK_EVENTS_WIN32_C__)
+gdk_win32_set_modal_dialog_libgtk_only
+#endif
+#endif
+
 #if IN_HEADER(__GDK_WIN32_H__)
 #if IN_FILE(__GDK_GC_WIN32_C__)
 gdk_win32_hdc_get
index f241943cb94cae2fab2a59192ce4aedc7bf0a378..3683bc3a575a1ec65074ed2747ca27a46b9da82e 100644 (file)
@@ -144,6 +144,9 @@ static gint current_root_x, current_root_y;
 static UINT msh_mousewheel;
 static UINT client_message;
 
+static UINT got_gdk_events_message;
+static HWND modal_win32_dialog = NULL;
+
 #ifdef HAVE_DIMM_H
 static IActiveIMMApp *active_imm_app = NULL;
 static IActiveIMMMessagePumpOwner *active_imm_msgpump_owner = NULL;
@@ -281,6 +284,9 @@ inner_window_procedure (HWND   hwnd,
       /* If gdk_event_translate() returns TRUE, we return ret_val from
        * the window procedure.
        */
+      if (modal_win32_dialog)
+       PostMessage (modal_win32_dialog, got_gdk_events_message,
+                    (WPARAM) 1, 0);
       return ret_val;
     }
   else
@@ -379,6 +385,7 @@ _gdk_events_init (void)
   msh_mousewheel = RegisterWindowMessage ("MSWHEEL_ROLLMSG");
 
   client_message = RegisterWindowMessage ("GDK_WIN32_CLIENT_MESSAGE");
+  got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
 
 #if 0
   /* Check if we have some input locale identifier loaded that uses a
@@ -463,7 +470,8 @@ gdk_events_pending (void)
 {
   MSG msg;
   return (_gdk_event_queue_find_first (_gdk_display) ||
-         PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
+         (modal_win32_dialog == NULL &&
+          PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)));
 }
 
 GdkEvent*
@@ -3516,6 +3524,9 @@ _gdk_events_queue (GdkDisplay *display)
 {
   MSG msg;
 
+  if (modal_win32_dialog != NULL)
+    return;
+  
   while (!_gdk_event_queue_find_first (display) &&
         PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
@@ -3536,7 +3547,8 @@ gdk_event_prepare (GSource *source,
   *timeout = -1;
 
   retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
-           PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
+           (modal_win32_dialog == NULL &&
+            PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)));
 
   GDK_THREADS_LEAVE ();
 
@@ -3553,7 +3565,8 @@ gdk_event_check (GSource *source)
 
   if (event_poll_fd.revents & G_IO_IN)
     retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
-             PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
+             (modal_win32_dialog == NULL &&
+              PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)));
   else
     retval = FALSE;
 
@@ -3587,6 +3600,12 @@ gdk_event_dispatch (GSource     *source,
   return TRUE;
 }
 
+void
+gdk_win32_set_modal_dialog_libgtk_only (HWND window)
+{
+  modal_win32_dialog = window;
+}
+
 static void
 check_for_too_much_data (GdkEvent *event)
 {
index 37e6cbc762076b150a11c51f9e12d9a681dc914d..1e79ce94cbd54ac79c0bd34f66268a0b801e2c17 100644 (file)
@@ -87,6 +87,7 @@ void          gdk_win32_selection_add_targets (GdkWindow  *owner,
 /* For internal GTK use only */
 GdkPixbuf *   gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon);
 HICON         gdk_win32_pixbuf_to_hicon_libgtk_only (GdkPixbuf *pixbuf);
+void          gdk_win32_set_modal_dialog_libgtk_only (HWND window);
 
 G_END_DECLS
 
diff --git a/gtk+-unix-print-2.0.pc.in b/gtk+-unix-print-2.0.pc.in
new file mode 100644 (file)
index 0000000..b703512
--- /dev/null
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+target=@gdktarget@
+
+gtk_binary_version=@GTK_BINARY_VERSION@
+gtk_host=@host@
+
+Name: GTK+
+Description: GIMP Tool Kit Unix print support
+Version: @VERSION@
+Requires: gtk+-${target}-2.0 @GTK_PACKAGES@
+Cflags: -I${includedir}/gtk-unix-print-2.0
index 1a9f19a1978febae889e2e834f443d25dd0b6899..17cf8583adde103381faa777aea32b6058e8b793 100644 (file)
@@ -6,7 +6,13 @@ if OS_UNIX
 SUBDIRS += xdgmime
 endif
 
-DIST_SUBDIRS=stock-icons theme-bits xdgmime
+DIST_SUBDIRS=theme-bits xdgmime
+
+if HAVE_CUPS
+GTK_PRINT_BACKENDS=pdf,cups
+else
+GTK_PRINT_BACKENDS=pdf,lpr
+endif
 
 INCLUDES =                                             \
        -DG_LOG_DOMAIN=\"Gtk\"                          \
@@ -18,6 +24,7 @@ INCLUDES =                                            \
        -DGTK_BINARY_VERSION=\"$(GTK_BINARY_VERSION)\"  \
        -DGTK_HOST=\"$(host)\"                          \
        -DGTK_COMPILATION                               \
+       -DGTK_PRINT_BACKENDS=\"$(GTK_PRINT_BACKENDS)\"  \
        -I$(top_builddir)/gtk                           \
        -I$(top_srcdir) -I../gdk                        \
        -I$(top_srcdir)/gdk                             \
@@ -26,6 +33,7 @@ INCLUDES =                                            \
        -DGDK_DISABLE_DEPRECATED                        \
        -DGTK_DISABLE_DEPRECATED                        \
        -DGTK_FILE_SYSTEM_ENABLE_UNSUPPORTED            \
+       -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED          \
        $(GTK_DEBUG_FLAGS)                              \
        $(GTK_DEP_CFLAGS)                               \
        $(gtk_clipboard_dnd_c_sources_CFLAGS)
@@ -215,10 +223,15 @@ gtk_public_h_sources =          \
        gtkobject.h             \
        gtkoldeditable.h        \
        gtkoptionmenu.h         \
+       gtkpagesetup.h          \
        gtkpaned.h              \
+       gtkpapersize.h          \
        gtkpixmap.h             \
        gtkplug.h               \
        gtkpreview.h            \
+       gtkprintcontext.h       \
+       gtkprintoperation.h     \
+       gtkprintsettings.h      \
        gtkprivate.h            \
        gtkprogress.h           \
        gtkprogressbar.h        \
@@ -295,6 +308,11 @@ gtk_public_h_sources =          \
        gtkwidget.h             \
        gtkwindow.h
 
+gtk_unix_print_public_h_sources =    \
+       gtkpagesetupunixdialog.h        \
+       gtkprinter.h                    \
+       gtkprintunixdialog.h
+
 # Installed header files without compatibility guarantees
 # that are not include in gtk/gtk.h
 gtk_semi_private_h_sources =    \
@@ -305,16 +323,17 @@ gtk_semi_private_h_sources =    \
 gtk_private_h_sources =                \
        gtkdndcursors.h         \
        gtkentryprivate.h       \
+       gtkfilechooserdefault.h \
        gtkfilechooserembed.h   \
        gtkfilechooserentry.h   \
-       gtkfilechooserdefault.h \
        gtkfilechooserprivate.h \
        gtkfilechooserutils.h   \
-       gtkfilesystemunix.h     \
        gtkfilesystemmodel.h    \
+       gtkfilesystemunix.h     \
        gtkiconcache.h          \
        gtkpathbar.h            \
        gtkplugprivate.h        \
+       gtkprintoperation-private.h\
        gtkrbtree.h             \
        gtkrecentchooserdefault.h \
        gtkrecentchooserprivate.h \
@@ -323,17 +342,17 @@ gtk_private_h_sources =           \
        gtksocketprivate.h      \
        gtktextbtree.h          \
        gtktextchildprivate.h   \
-       gtktextsegment.h        \
-       gtktexttypes.h          \
-       gtktextutil.h           \
        gtktextiterprivate.h    \
        gtktextmarkprivate.h    \
+       gtktextsegment.h        \
        gtktexttagprivate.h     \
+       gtktexttypes.h          \
+       gtktextutil.h           \
        gtkthemes.h             \
+       gtktoggleactionprivate.h\
        gtktreedatalist.h       \
        gtktreeprivate.h        \
-       gtkwindow-decorate.h    \
-       gtktoggleactionprivate.h
+       gtkwindow-decorate.h
 
 # GTK+ C sources to build the library from
 gtk_c_sources =                 \
@@ -388,10 +407,10 @@ gtk_c_sources =                 \
        gtkexpander.c           \
        gtkfilechooser.c        \
        gtkfilechooserbutton.c  \
+       gtkfilechooserdefault.c \
        gtkfilechooserdialog.c  \
        gtkfilechooserembed.c   \
        gtkfilechooserentry.c   \
-       gtkfilechooserdefault.c \
        gtkfilechooserutils.c   \
        gtkfilechooserwidget.c  \
        gtkfilefilter.c         \
@@ -414,8 +433,8 @@ gtk_c_sources =                 \
        gtkhseparator.c         \
        gtkhsv.c                \
        gtkhsv.h                \
-       gtkiconfactory.c        \
        gtkiconcache.c          \
+       gtkiconfactory.c        \
        gtkicontheme.c          \
        gtkiconview.c           \
        gtkimage.c              \
@@ -454,11 +473,16 @@ gtk_c_sources =                 \
        gtkobject.c             \
        gtkoldeditable.c        \
        gtkoptionmenu.c         \
+       gtkpagesetup.c          \
        gtkpaned.c              \
+       gtkpapersize.c          \
        gtkpathbar.c            \
        gtkpixmap.c             \
        gtkplug.c               \
        gtkpreview.c            \
+       gtkprintcontext.c       \
+       gtkprintoperation.c     \
+       gtkprintsettings.c      \
        gtkprogress.c           \
        gtkprogressbar.c        \
        gtkradioaction.c        \
@@ -480,11 +504,11 @@ gtk_c_sources =                 \
        gtkscale.c              \
        gtkscrollbar.c          \
        gtkscrolledwindow.c     \
-       gtksequence.c           \
        gtkselection.c          \
        gtkseparator.c          \
        gtkseparatormenuitem.c  \
        gtkseparatortoolitem.c  \
+       gtksequence.c           \
        gtksettings.c           \
        gtksignal.c             \
        gtksizegroup.c          \
@@ -554,13 +578,37 @@ gtk_c_sources =                 \
        $(gtk_clipboard_dnd_c_sources)
 
 if OS_UNIX
-gtk_private_h_sources += gtkfilesystemunix.h
-gtk_c_sources +=         gtkfilesystemunix.c
+gtk_private_h_sources += \
+       gtkfilesystemunix.h             \
+       gtkprintbackend.h               \
+       gtkprinter-private.h            \
+       gtkprinteroption.h              \
+       gtkprinteroptionset.h           \
+       gtkprinteroptionwidget.h        \
+       gtkprintjob.h
+
+gtk_c_sources += \
+       gtkfilesystemunix.c             \
+       gtkpagesetupunixdialog.c        \
+       gtkprinter.c                    \
+       gtkprinteroption.c              \
+       gtkprinteroptionset.c           \
+       gtkprinteroptionwidget.c        \
+       gtkprintjob.c                   \
+       gtkprintoperation-unix.c        \
+       gtkprintunixdialog.c            \
+        gtkprintbackend.c
 endif
 
 if OS_WIN32
-gtk_private_h_sources += gtkfilesystemwin32.h
-gtk_c_sources +=         gtkfilesystemwin32.c
+gtk_private_h_sources +=
+       gtkfilesystemwin32.h    \
+       gtkprint-win32.h
+
+gtk_c_sources += \
+       gtkfilesystemwin32.c            \
+       gtkprint-win32.c                \
+       gtkprintoperation-win32.c
 endif
 
 if USE_X11
@@ -622,6 +670,9 @@ stamp_files =                                       \
 # that don't serve as direct make target sources, i.e. they don't have
 # their own .lo rules and don't get publically installed
 gtk_extra_sources =                            \
+       paper_names.c                           \
+       paper_names_offsts.c                    \
+       gen-paper-names.c                       \
        gtk.symbols                             \
        gtkversion.h.in                         \
        gtkmarshalers.list                      \
@@ -634,6 +685,7 @@ MAINTAINERCLEANFILES = $(gtk_built_sources) $(stamp_files)
 EXTRA_HEADERS =
 EXTRA_DIST = $(gtk_private_h_sources) $(gtk_extra_sources)
 EXTRA_DIST += $(gtk_built_sources)
+EXTRA_DIST += $(STOCK_ICONS)
 
 #
 # rules to generate built sources
@@ -705,6 +757,9 @@ lib_LTLIBRARIES = $(gtktargetlib)
 gtkincludedir = $(includedir)/gtk-2.0/gtk
 gtkinclude_HEADERS = $(gtk_public_h_sources) $(gtk_semi_private_h_sources) $(gtk_built_public_sources) gtkversion.h
 
+gtkunixprintincludedir = $(includedir)/gtk-unix-print-2.0/gtk
+gtkunixprintinclude_HEADERS = $(gtk_unix_print_public_h_sources)
+
 libgtk_x11_2_0_la_SOURCES = $(gtk_c_sources)
 libgtk_linux_fb_2_0_la_SOURCES = $(gtk_c_sources)
 libgtk_win32_2_0_la_SOURCES = $(gtk_c_sources)
@@ -719,7 +774,7 @@ libgtk_directfb_2_0_la_LDFLAGS = $(libtool_opts)
 
 libgtk_x11_2_0_la_LIBADD = $(libadd)
 libgtk_linux_fb_2_0_la_LIBADD = $(libadd)
-libgtk_win32_2_0_la_LIBADD = $(libadd) -lole32 -lgdi32
+libgtk_win32_2_0_la_LIBADD = $(libadd) -lole32 -lgdi32 -lcomdlg32 -lwinspool
 libgtk_win32_2_0_la_DEPENDENCIES = $(gtk_def) $(gtk_win32_res)
 libgtk_quartz_2_0_la_LIBADD = $(libadd)
 libgtk_directfb_2_0_la_LIBADD = $(libadd)
@@ -933,6 +988,9 @@ STOCK_ICONS = \
        stock-icons/24/gtk-network.png                  \
        stock-icons/24/gtk-new.png                      \
        stock-icons/24/gtk-open.png                     \
+       stock-icons/24/gtk-orientation-reverse-landscape.png \
+       stock-icons/24/gtk-orientation-landscape.png    \
+       stock-icons/24/gtk-orientation-portrait.png     \
        stock-icons/24/gtk-paste.png                    \
        stock-icons/24/gtk-preferences.png              \
        stock-icons/24/gtk-print.png                    \
diff --git a/gtk/gen-paper-names.c b/gtk/gen-paper-names.c
new file mode 100644 (file)
index 0000000..ef9aebf
--- /dev/null
@@ -0,0 +1,238 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2006 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "paper_names.c"
+
+static const gint n_infos = G_N_ELEMENTS (standard_names);
+static const gint n_extra = G_N_ELEMENTS (extra_ppd_names);
+
+typedef struct {
+  const gchar *s;
+  gint         len;
+  gint         suffix;
+  gint         offset;
+} NameInfo;
+
+static NameInfo *names = NULL;
+static gint n_names = 0;
+
+static void
+add_name (const gchar *name)
+{
+  names[n_names].s = name;
+  names[n_names].len = strlen (name);
+  names[n_names].suffix = -1;
+  names[n_names].offset = 0;
+
+  n_names++;
+}
+
+static gint
+find_name (const gchar *name)
+{
+  gint i;
+
+  if (!name)
+    return -1;
+
+  for (i = 0; i < n_names; i++)
+    {
+      if (strcmp (names[i].s, name) == 0)
+       return names[i].offset;
+    }
+
+  fprintf (stderr, "BOO! %s not found\n", name);
+
+  return -2;
+}
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+static gboolean
+parse_media_size (const gchar *size,
+                 gdouble     *width_mm, 
+                 gdouble     *height_mm)
+{
+  const gchar *p;
+  gchar *e;
+  gdouble short_dim, long_dim;
+
+  p = size;
+  
+  short_dim = g_ascii_strtod (p, &e);
+
+  if (p == e || *e != 'x')
+    return FALSE;
+
+  p = e + 1; /* Skip x */
+
+  long_dim = g_ascii_strtod (p, &e);
+
+  if (p == e)
+    return TRUE;
+
+  p = e;
+
+  if (strcmp (p, "in") == 0)
+    {
+      short_dim = short_dim * MM_PER_INCH;
+      long_dim = long_dim * MM_PER_INCH;
+    }
+  else if (strcmp (p, "mm") != 0)
+    return FALSE;
+
+  if (width_mm)
+    *width_mm = short_dim;
+  if (height_mm)
+    *height_mm = long_dim;
+  
+  return TRUE;  
+}
+
+int 
+main (int argc, char *argv[])
+{
+  gint i, j, offset;
+  gdouble width, height;
+
+  names = (NameInfo *) malloc (sizeof (NameInfo) * (4 + n_infos + 2 * n_extra));
+  n_names = 0;
+
+  /* collect names */
+  for (i = 0; i < n_infos; i++)
+    {
+      add_name (standard_names[i].name);
+      add_name (standard_names[i].display_name);
+      if (standard_names[i].ppd_name)
+       add_name (standard_names[i].ppd_name);
+    }
+
+  for (i = 0; i < n_extra; i++)
+    {
+      add_name (extra_ppd_names[i].ppd_name);
+      add_name (extra_ppd_names[i].standard_name);
+    }
+
+  /* find suffixes and dupes */
+  for (i = 0; i < n_names; i++)
+    for (j = 0; j < n_names; j++)
+      {
+       if (i == j) continue;
+       
+       if (names[i].len < names[j].len ||
+           (names[i].len == names[j].len && j < i))
+         {
+           if (strcmp (names[i].s, names[j].s + names[j].len - names[i].len) == 0)
+             {
+               names[i].suffix = j;
+               break;
+             }
+         }
+      }
+  
+  /* calculate offsets for regular entries */
+  offset = 0;
+  for (i = 0; i < n_names; i++)
+    {
+      if (names[i].suffix == -1)
+       {
+         names[i].offset = offset;
+         offset += names[i].len + 1;
+       }
+    }
+  
+  /* calculate offsets for suffixes */
+  for (i = 0; i < n_names; i++)
+    {
+      if (names[i].suffix != -1)
+       {
+         j = names[i].suffix;
+         names[i].offset = names[j].offset + names[j].len - names[i].len;
+       }
+    }
+    
+  printf ("/* Generated by gen-paper-names */\n\n");
+
+  /* write N_ marked names */
+
+  printf ("#if 0\n");
+  for (i = 0; i < n_infos; i++)
+    printf ("N_(\"%s\")\n", standard_names[i].display_name);
+  printf ("#endif\n\n");
+
+  /* write strings */
+  printf ("const char paper_names[] =");
+  for (i = 0; i < n_names; i++)
+    {
+      if (names[i].suffix == -1)
+       printf ("\n  \"%s\\0\"", names[i].s);
+    }
+  printf (";\n\n");
+
+  /* dump PaperInfo array */
+  printf ("typedef struct {\n"
+         "  int name;\n"
+         "  float width;\n"
+          "  float height;\n"
+         "  int display_name;\n"
+         "  int ppd_name;\n"
+         "} PaperInfo;\n\n"
+          "const PaperInfo standard_names_offsets[] = {\n");
+
+  for (i = 0; i < n_infos; i++)
+    {
+      width = height = 0.0;
+      if (!parse_media_size (standard_names[i].size, &width, &height))
+       printf ("failed to parse size %s\n", standard_names[i].size);
+
+      printf ("  { %4d, %g, %g, %4d, %4d },\n", 
+             find_name (standard_names[i].name),
+             width, height,
+             find_name (standard_names[i].display_name),
+             find_name (standard_names[i].ppd_name));
+    }
+  
+  printf ("};\n\n");
+
+
+  /* dump extras */
+
+  printf ("const struct {\n"
+         "  int ppd_name;\n"
+         "  int standard_name;\n"
+         "} extra_ppd_names_offsets[] = {\n");
+
+  for (i = 0; i < n_extra; i++)
+    {
+      printf ("  { %4d, %4d },\n", 
+             find_name (extra_ppd_names[i].ppd_name),
+             find_name (extra_ppd_names[i].standard_name));
+    }
+  
+  printf ("};\n\n");
+
+  return 0;
+}
index 2575238e7a94ae927d5cd0bfdb13a30271bdd99a..f4f927eda15185f20ae22f2e6ac3f723a14323b6 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
 #include <gtk/gtkpixmap.h>
 #include <gtk/gtkplug.h>
 #include <gtk/gtkpreview.h>
+#include <gtk/gtkprintoperation.h>
 #include <gtk/gtkprogress.h>
 #include <gtk/gtkprogressbar.h>
 #include <gtk/gtkradioaction.h>
index 0ff5fa8ca996bffaf0fdab503bc04552cb6c6aeb..bdeff31b59e9abd98e450c050a5af4004b08ee0f 100644 (file)
@@ -2461,6 +2461,305 @@ gtk_preview_uninit
 #endif
 #endif
 
+#if IN_HEADER(__GTK_PAGE_SETUP_H__)
+#if IN_FILE(__GTK_PAGE_SETUP_C__)
+gtk_page_setup_get_type G_GNUC_CONST
+gtk_page_setup_new
+gtk_page_setup_copy
+gtk_page_setup_get_orientation
+gtk_page_setup_set_orientation
+gtk_page_setup_get_paper_size
+gtk_page_setup_set_paper_size
+gtk_page_setup_get_top_margin
+gtk_page_setup_set_top_margin
+gtk_page_setup_get_bottom_margin
+gtk_page_setup_set_bottom_margin
+gtk_page_setup_get_left_margin
+gtk_page_setup_set_left_margin
+gtk_page_setup_get_right_margin
+gtk_page_setup_set_right_margin
+gtk_page_setup_set_paper_size_and_default_margins
+gtk_page_setup_get_paper_width
+gtk_page_setup_get_paper_height
+gtk_page_setup_get_page_width
+gtk_page_setup_get_page_height
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PAGE_SETUP_UNIX_DIALOG_H__)
+#if IN_FILE(__GTK_PAGE_SETUP_UNIX_DIALOG_C__)
+#ifdef G_OS_UNIX
+gtk_page_setup_unix_dialog_get_type G_GNUC_CONST
+gtk_page_setup_unix_dialog_new
+gtk_page_setup_unix_dialog_set_page_setup
+gtk_page_setup_unix_dialog_get_page_setup
+gtk_page_setup_unix_dialog_set_print_settings
+gtk_page_setup_unix_dialog_get_print_settings
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PAPER_SIZE_H__)
+#if IN_FILE(__GTK_PAPER_SIZE_C__)
+gtk_paper_size_get_type G_GNUC_CONST
+gtk_paper_size_new
+gtk_paper_size_new_from_ppd
+gtk_paper_size_new_custom
+gtk_paper_size_copy
+gtk_paper_size_free
+gtk_paper_size_is_equal
+gtk_paper_size_get_name
+gtk_paper_size_get_display_name
+gtk_paper_size_get_ppd_name
+gtk_paper_size_get_width
+gtk_paper_size_get_height
+gtk_paper_size_is_custom
+gtk_paper_size_set_size
+gtk_paper_size_get_default_top_margin
+gtk_paper_size_get_default_bottom_margin
+gtk_paper_size_get_default_left_margin
+gtk_paper_size_get_default_right_margin
+gtk_paper_size_get_default
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_BACKEND_H__)
+#if IN_FILE(__GTK_PRINT_BACKEND_C__)
+#ifdef G_OS_UNIX
+gtk_print_backend_get_type G_GNUC_CONST
+gtk_print_backend_get_printer_list  
+gtk_print_backend_find_printer
+gtk_print_backend_print_stream
+gtk_print_backend_load_modules
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_CONTEXT_H__)
+#if IN_FILE(__GTK_PRINT_CONTEXT_C__)
+gtk_print_context_get_type G_GNUC_CONST
+gtk_print_context_get_cairo
+gtk_print_context_get_page_setup
+gtk_print_context_get_width
+gtk_print_context_get_height
+gtk_print_context_get_dpi_x
+gtk_print_context_get_dpi_y
+gtk_print_context_get_fontmap
+gtk_print_context_create_context
+gtk_print_context_create_layout
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINTER_H__)
+#if IN_FILE(__GTK_PRINTER_C__)
+#ifdef G_OS_UNIX
+gtk_printer_get_type G_GNUC_CONST
+gtk_printer_new
+gtk_printer_get_backend
+gtk_printer_get_name
+gtk_printer_get_state_message
+gtk_printer_get_location
+gtk_printer_get_icon_name
+gtk_printer_get_job_count
+gtk_printer_is_active
+gtk_printer_is_virtual
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINTER_OPTION_H__)
+#if IN_FILE(__GTK_PRINTER_OPTION_C__)
+#ifdef G_OS_UNIX
+gtk_printer_option_get_type
+gtk_printer_option_new
+gtk_printer_option_set
+gtk_printer_option_set_has_conflict
+gtk_printer_option_clear_has_conflict
+gtk_printer_option_set_boolean
+gtk_printer_option_allocate_choices
+gtk_printer_option_choices_from_array
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINTER_OPTION_SET_H__)
+#if IN_FILE(__GTK_PRINTER_OPTION_SET_C__)
+#ifdef G_OS_UNIX
+gtk_printer_option_set_get_type G_GNUC_CONST
+gtk_printer_option_set_new
+gtk_printer_option_set_add
+gtk_printer_option_set_remove
+gtk_printer_option_set_foreach
+gtk_printer_option_set_clear_conflicts
+gtk_printer_option_set_get_groups
+gtk_printer_option_set_foreach_in_group
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINTER_OPTION_WIDGET_H__)
+#if IN_FILE(__GTK_PRINTER_OPTION_WIDGET_C__)
+#ifdef G_OS_UNIX
+gtk_printer_option_widget_get_type G_GNUC_CONST
+gtk_printer_option_widget_new
+gtk_printer_option_widget_set_source
+gtk_printer_option_widget_has_external_label
+gtk_printer_option_widget_get_external_label
+gtk_printer_option_widget_get_value
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_JOB_H__)
+#if IN_FILE(__GTK_PRINT_JOB_C__)
+#ifdef G_OS_UNIX
+gtk_print_job_get_type G_GNUC_CONST
+gtk_print_job_new
+gtk_print_job_get_settings
+gtk_print_job_get_printer
+gtk_print_job_get_title
+gtk_print_job_get_status
+gtk_print_job_set_source_file
+gtk_print_job_get_surface
+gtk_print_job_send
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_OPERATION_H__)
+#if IN_FILE(__GTK_PRINT_OPERATION_C__)
+gtk_print_error_quark
+gtk_print_operation_get_type G_GNUC_CONST
+gtk_print_operation_new
+gtk_print_operation_set_default_page_setup
+gtk_print_operation_get_default_page_setup
+gtk_print_operation_set_print_settings
+gtk_print_operation_get_print_settings
+gtk_print_operation_set_job_name
+gtk_print_operation_set_nr_of_pages
+gtk_print_operation_set_current_page
+gtk_print_operation_set_use_full_page
+gtk_print_operation_set_unit
+gtk_print_operation_set_show_dialog
+gtk_print_operation_set_pdf_target
+gtk_print_operation_run
+gtk_print_operation_get_status
+gtk_print_operation_get_status_string
+gtk_print_operation_is_finished
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_OPERATION_H__)
+#if IN_FILE(__GTK_PRINT_OPERATION_UNIX_C__)
+#ifdef G_OS_UNIX
+gtk_print_run_page_setup_dialog
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_OPERATION_H__)
+#if IN_FILE(__GTK_PRINT_OPERATION_WIN32_C__)
+#ifdef G_OS_WIN32
+gtk_print_run_page_setup_dialog
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_SETTINGS_H__)
+#if IN_FILE(__GTK_PRINT_SETTINGS_C__)
+gtk_print_settings_get_type G_GNUC_CONST
+gtk_print_settings_new
+gtk_print_settings_copy
+gtk_print_settings_has_key
+gtk_print_settings_get
+gtk_print_settings_set
+gtk_print_settings_unset
+gtk_print_settings_foreach
+gtk_print_settings_get_bool
+gtk_print_settings_set_bool
+gtk_print_settings_get_double
+gtk_print_settings_get_double_with_default
+gtk_print_settings_set_double
+gtk_print_settings_get_length
+gtk_print_settings_set_length
+gtk_print_settings_get_int
+gtk_print_settings_get_int_with_default
+gtk_print_settings_get_printer
+gtk_print_settings_set_printer
+gtk_print_settings_get_orientation
+gtk_print_settings_set_orientation
+gtk_print_settings_get_paper_size
+gtk_print_settings_set_paper_size
+gtk_print_settings_get_paper_width
+gtk_print_settings_set_paper_width
+gtk_print_settings_get_paper_height
+gtk_print_settings_set_paper_height
+gtk_print_settings_get_use_color
+gtk_print_settings_set_use_color
+gtk_print_settings_get_collate
+gtk_print_settings_set_collate
+gtk_print_settings_get_reverse
+gtk_print_settings_set_reverse
+gtk_print_settings_get_duplex
+gtk_print_settings_set_duplex
+gtk_print_settings_get_quality
+gtk_print_settings_set_quality
+gtk_print_settings_get_num_copies
+gtk_print_settings_set_num_copies
+gtk_print_settings_get_number_up
+gtk_print_settings_set_number_up
+gtk_print_settings_get_resolution
+gtk_print_settings_set_resolution
+gtk_print_settings_get_scale
+gtk_print_settings_set_scale
+gtk_print_settings_get_print_to_file
+gtk_print_settings_set_print_to_file
+gtk_print_settings_get_print_pages
+gtk_print_settings_set_print_pages
+gtk_print_settings_get_page_ranges
+gtk_print_settings_set_page_ranges
+gtk_print_settings_get_page_set
+gtk_print_settings_set_page_set
+gtk_print_settings_get_default_source
+gtk_print_settings_set_default_source
+gtk_print_settings_get_media_type
+gtk_print_settings_set_media_type
+gtk_print_settings_get_dither
+gtk_print_settings_set_dither
+gtk_print_settings_get_finishings
+gtk_print_settings_set_finishings
+gtk_print_settings_get_output_bin
+gtk_print_settings_set_output_bin
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_UNIX_DIALOG_H__)
+#if IN_FILE(__GTK_PRINT_UNIX_DIALOG_C__)
+#ifdef G_OS_UNIX
+gtk_print_unix_dialog_get_type G_GNUC_CONST
+gtk_print_unix_dialog_new
+gtk_print_unix_dialog_set_page_setup
+gtk_print_unix_dialog_get_page_setup
+gtk_print_unix_dialog_set_current_page
+gtk_print_unix_dialog_get_current_page
+gtk_print_unix_dialog_set_settings
+gtk_print_unix_dialog_get_settings
+gtk_print_unix_dialog_get_selected_printer
+#endif
+#endif
+#endif
+
+#if IN_HEADER(__GTK_PRINT_WIN32_H__)
+#if IN_FILE(__GTK_PRINT_WIN32_C__)
+#ifdef G_OS_WIN32
+gtk_print_win32_devnames_free
+gtk_print_win32_devnames_from_win32
+gtk_print_win32_devnames_to_win32
+gtk_print_win32_devnames_from_printer_name
+#endif
+#endif
+#endif
+
 #if IN_HEADER(__GTK_PROGRESS_BAR_H__)
 #if IN_FILE(__GTK_PROGRESS_BAR_C__)
 gtk_progress_bar_get_fraction
index e87ec53e0f9b31fe67525f4cf715891923fe9b6c..1c483de62bb24bfa364f43a8b67b64f55ed4fb3a 100644 (file)
@@ -466,6 +466,46 @@ typedef enum
   GTK_PACK_DIRECTION_BTT
 } GtkPackDirection;
 
+typedef enum {
+  GTK_PRINT_PAGES_ALL,
+  GTK_PRINT_PAGES_CURRENT,
+  GTK_PRINT_PAGES_RANGES
+} GtkPrintPages;
+
+typedef enum {
+  GTK_PAGE_SET_ALL,
+  GTK_PAGE_SET_EVEN,
+  GTK_PAGE_SET_ODD
+} GtkPageSet;
+
+typedef enum {
+  GTK_PAGE_ORIENTATION_PORTRAIT,
+  GTK_PAGE_ORIENTATION_LANDSCAPE,
+  GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT,
+  GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE
+} GtkPageOrientation;
+
+typedef enum {
+  GTK_PRINT_QUALITY_LOW,
+  GTK_PRINT_QUALITY_NORMAL,
+  GTK_PRINT_QUALITY_HIGH,
+  GTK_PRINT_QUALITY_DRAFT
+} GtkPrintQuality;
+
+typedef enum {
+  GTK_PRINT_DUPLEX_SIMPLEX,
+  GTK_PRINT_DUPLEX_HORIZONTAL,
+  GTK_PRINT_DUPLEX_VERTICAL
+} GtkPrintDuplex;
+
+
+typedef enum {
+  GTK_UNIT_PIXEL,
+  GTK_UNIT_POINTS,
+  GTK_UNIT_INCH,
+  GTK_UNIT_MM
+} GtkUnit;
+
 G_END_DECLS
 
 #endif /* __GTK_ENUMS_H__ */
index cc8911de42538acce2a36fa7ebd5435b89c5094c..c64d3c0e4694f10a7ab2a78e3864e7832b2c8235 100644 (file)
@@ -450,6 +450,9 @@ get_default_icons (GtkIconFactory *factory)
   register_stock_icon (factory, GTK_STOCK_NETWORK);
   register_stock_icon (factory, GTK_STOCK_NEW);
   register_stock_icon (factory, GTK_STOCK_OPEN);
+  register_stock_icon (factory, GTK_STOCK_ORIENTATION_PORTRAIT);
+  register_stock_icon (factory, GTK_STOCK_ORIENTATION_LANDSCAPE);
+  register_stock_icon (factory, GTK_STOCK_ORIENTATION_REVERSE_LANDSCAPE);
   register_stock_icon (factory, GTK_STOCK_PASTE);
   register_stock_icon (factory, GTK_STOCK_PREFERENCES);
   register_stock_icon (factory, GTK_STOCK_PRINT);
index 9d948c7c49f23c803ab578554cb75c91071ecf9d..e081da60dc525e7d3cf7ccea2259e78335d91abc 100644 (file)
@@ -78,6 +78,8 @@ VOID:OBJECT
 VOID:OBJECT,BOOLEAN
 VOID:OBJECT,BOXED,BOXED
 VOID:OBJECT,BOXED,UINT,UINT
+VOID:OBJECT,INT
+VOID:OBJECT,INT,OBJECT
 VOID:OBJECT,INT,INT
 VOID:OBJECT,INT,INT,BOXED,UINT,UINT
 VOID:OBJECT,OBJECT
diff --git a/gtk/gtkpagesetup.c b/gtk/gtkpagesetup.c
new file mode 100644 (file)
index 0000000..8406a28
--- /dev/null
@@ -0,0 +1,288 @@
+/* GTK - The GIMP Toolkit
+ * gtkpagesetup.c: Page Setup
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gtkpagesetup.h"
+#include "gtkalias.h"
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+typedef struct _GtkPageSetupClass GtkPageSetupClass;
+
+#define GTK_IS_PAGE_SETUP_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PAGE_SETUP))
+#define GTK_PAGE_SETUP_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PAGE_SETUP, GtkPageSetupClass))
+#define GTK_PAGE_SETUP_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PAGE_SETUP, GtkPageSetupClass))
+
+struct _GtkPageSetup
+{
+  GObject parent_instance;
+
+  GtkPageOrientation orientation;
+  GtkPaperSize *paper_size;
+  /* These are stored in mm */
+  double top_margin, bottom_margin, left_margin, right_margin;
+};
+
+struct _GtkPageSetupClass
+{
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkPageSetup, gtk_page_setup, G_TYPE_OBJECT)
+
+static double
+to_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len * MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len * (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static double
+from_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len / MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len / (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static void
+gtk_page_setup_finalize (GObject *object)
+{
+  GtkPageSetup *setup = GTK_PAGE_SETUP (object);
+  
+  gtk_paper_size_free (setup->paper_size);
+  
+  G_OBJECT_CLASS (gtk_page_setup_parent_class)->finalize (object);
+}
+
+static void
+gtk_page_setup_init (GtkPageSetup *setup)
+{
+  setup->paper_size = gtk_paper_size_new (NULL);
+  setup->orientation = GTK_PAGE_ORIENTATION_PORTRAIT;
+  setup->top_margin = gtk_paper_size_get_default_top_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->bottom_margin = gtk_paper_size_get_default_bottom_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->left_margin = gtk_paper_size_get_default_left_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->right_margin = gtk_paper_size_get_default_right_margin (setup->paper_size, GTK_UNIT_MM);
+}
+
+static void
+gtk_page_setup_class_init (GtkPageSetupClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->finalize = gtk_page_setup_finalize;
+}
+  
+GtkPageSetup *
+gtk_page_setup_new (void)
+{
+  return g_object_new (GTK_TYPE_PAGE_SETUP, NULL);
+}
+
+GtkPageSetup *
+gtk_page_setup_copy (GtkPageSetup *other)
+{
+  GtkPageSetup *copy;
+
+  copy = gtk_page_setup_new ();
+  copy->orientation = other->orientation;
+  copy->paper_size = gtk_paper_size_copy (other->paper_size);
+  copy->top_margin = other->top_margin;
+  copy->bottom_margin = other->bottom_margin;
+  copy->left_margin = other->left_margin;
+  copy->right_margin = other->right_margin;
+
+  return copy;
+}
+
+GtkPageOrientation
+gtk_page_setup_get_orientation (GtkPageSetup *setup)
+{
+  return setup->orientation;
+}
+
+void
+gtk_page_setup_set_orientation (GtkPageSetup *setup,
+                               GtkPageOrientation orientation)
+{
+  setup->orientation = orientation;
+}
+
+GtkPaperSize *
+gtk_page_setup_get_paper_size (GtkPageSetup *setup)
+{
+  return setup->paper_size;
+}
+
+void
+gtk_page_setup_set_paper_size (GtkPageSetup *setup,
+                              GtkPaperSize *size)
+{
+  setup->paper_size = gtk_paper_size_copy (size);
+}
+
+void
+gtk_page_setup_set_paper_size_and_default_margins (GtkPageSetup *setup,
+                                                  GtkPaperSize *size)
+{
+  setup->paper_size = gtk_paper_size_copy (size);
+  setup->top_margin = gtk_paper_size_get_default_top_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->bottom_margin = gtk_paper_size_get_default_bottom_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->left_margin = gtk_paper_size_get_default_left_margin (setup->paper_size, GTK_UNIT_MM);
+  setup->right_margin = gtk_paper_size_get_default_right_margin (setup->paper_size, GTK_UNIT_MM);
+}
+
+double
+gtk_page_setup_get_top_margin (GtkPageSetup *setup,
+                              GtkUnit       unit)
+{
+  return from_mm (setup->top_margin, unit);
+}
+
+void
+gtk_page_setup_set_top_margin (GtkPageSetup *setup,
+                              double        margin,
+                              GtkUnit       unit)
+{
+  setup->top_margin = to_mm (margin, unit);
+}
+
+double
+gtk_page_setup_get_bottom_margin (GtkPageSetup *setup,
+                                 GtkUnit       unit)
+{
+  return from_mm (setup->bottom_margin, unit);
+}
+
+void
+gtk_page_setup_set_bottom_margin (GtkPageSetup *setup,
+                                 double        margin,
+                                 GtkUnit       unit)
+{
+  setup->bottom_margin = to_mm (margin, unit);
+}
+
+double
+gtk_page_setup_get_left_margin (GtkPageSetup    *setup,
+                               GtkUnit          unit)
+{
+  return from_mm (setup->left_margin, unit);
+}
+
+void
+gtk_page_setup_set_left_margin (GtkPageSetup    *setup,
+                               double           margin,
+                               GtkUnit          unit)
+{
+  setup->left_margin = to_mm (margin, unit);
+}
+
+double
+gtk_page_setup_get_right_margin (GtkPageSetup    *setup,
+                                GtkUnit          unit)
+{
+  return from_mm (setup->right_margin, unit);
+}
+
+void
+gtk_page_setup_set_right_margin (GtkPageSetup    *setup,
+                                double           margin,
+                                GtkUnit          unit)
+{
+  setup->right_margin = to_mm (margin, unit);
+}
+
+/* These take orientation, but not margins into consideration */
+double
+gtk_page_setup_get_paper_width (GtkPageSetup *setup,
+                               GtkUnit       unit)
+{
+  if (setup->orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
+      setup->orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+    return gtk_paper_size_get_width (setup->paper_size, unit);
+  else
+    return gtk_paper_size_get_height (setup->paper_size, unit);
+}
+
+double
+gtk_page_setup_get_paper_height (GtkPageSetup  *setup,
+                                GtkUnit        unit)
+{
+  if (setup->orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
+      setup->orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+    return gtk_paper_size_get_height (setup->paper_size, unit);
+  else
+    return gtk_paper_size_get_width (setup->paper_size, unit);
+}
+
+/* These take orientation, and margins into consideration */
+double
+gtk_page_setup_get_page_width (GtkPageSetup    *setup,
+                              GtkUnit          unit)
+{
+  double width;
+  
+  width = gtk_page_setup_get_paper_width (setup, GTK_UNIT_MM);
+  width -= setup->left_margin + setup->right_margin;
+  
+  return from_mm (width, unit);
+}
+
+double
+gtk_page_setup_get_page_height (GtkPageSetup    *setup,
+                               GtkUnit          unit)
+{
+  double height;
+  
+  height = gtk_page_setup_get_paper_height (setup, GTK_UNIT_MM);
+  height -= setup->top_margin + setup->bottom_margin;
+  
+  return from_mm (height, unit);
+}
+
+
+#define __GTK_PAGE_SETUP_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkpagesetup.h b/gtk/gtkpagesetup.h
new file mode 100644 (file)
index 0000000..db617a2
--- /dev/null
@@ -0,0 +1,85 @@
+/* GTK - The GIMP Toolkit
+ * gtkpagesetup.h: Page Setup
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PAGE_SETUP_H__
+#define __GTK_PAGE_SETUP_H__
+
+#include <glib-object.h>
+#include "gtkenums.h"
+#include "gtkpapersize.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPageSetup GtkPageSetup;
+
+#define GTK_TYPE_PAGE_SETUP    (gtk_page_setup_get_type ())
+#define GTK_PAGE_SETUP(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PAGE_SETUP, GtkPageSetup))
+#define GTK_IS_PAGE_SETUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PAGE_SETUP))
+
+GType              gtk_page_setup_get_type          (void) G_GNUC_CONST;
+GtkPageSetup *     gtk_page_setup_new               (void);
+GtkPageSetup *     gtk_page_setup_copy              (GtkPageSetup       *other);
+GtkPageOrientation gtk_page_setup_get_orientation   (GtkPageSetup       *setup);
+void               gtk_page_setup_set_orientation   (GtkPageSetup       *setup,
+                                                    GtkPageOrientation  orientation);
+GtkPaperSize *     gtk_page_setup_get_paper_size    (GtkPageSetup       *setup);
+void               gtk_page_setup_set_paper_size    (GtkPageSetup       *setup,
+                                                    GtkPaperSize       *size);
+double             gtk_page_setup_get_top_margin    (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+void               gtk_page_setup_set_top_margin    (GtkPageSetup       *setup,
+                                                    double              margin,
+                                                    GtkUnit             unit);
+double             gtk_page_setup_get_bottom_margin (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+void               gtk_page_setup_set_bottom_margin (GtkPageSetup       *setup,
+                                                    double              margin,
+                                                    GtkUnit             unit);
+double             gtk_page_setup_get_left_margin   (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+void               gtk_page_setup_set_left_margin   (GtkPageSetup       *setup,
+                                                    double              margin,
+                                                    GtkUnit             unit);
+double             gtk_page_setup_get_right_margin  (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+void               gtk_page_setup_set_right_margin  (GtkPageSetup       *setup,
+                                                    double              margin,
+                                                    GtkUnit             unit);
+
+void gtk_page_setup_set_paper_size_and_default_margins (GtkPageSetup *setup,
+                                                       GtkPaperSize *size);
+
+/* These take orientation, but not margins into consideration */
+double             gtk_page_setup_get_paper_width   (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+double             gtk_page_setup_get_paper_height  (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+
+
+/* These take orientation, and margins into consideration */
+double             gtk_page_setup_get_page_width    (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+double             gtk_page_setup_get_page_height   (GtkPageSetup       *setup,
+                                                    GtkUnit             unit);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PAGE_SETUP_H__ */
diff --git a/gtk/gtkpagesetupunixdialog.c b/gtk/gtkpagesetupunixdialog.c
new file mode 100644 (file)
index 0000000..0815f17
--- /dev/null
@@ -0,0 +1,2016 @@
+/* GtkPageSetupUnixDialog 
+ * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include "config.h"
+#include <string.h>
+#include <locale.h>
+#include <langinfo.h>
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkliststore.h"
+#include "gtkstock.h"
+#include "gtktreeviewcolumn.h"
+#include "gtktreeselection.h"
+#include "gtktreemodel.h"
+#include "gtkbutton.h"
+#include "gtkscrolledwindow.h"
+#include "gtkvbox.h"
+#include "gtkhbox.h"
+#include "gtkframe.h"
+#include "gtkeventbox.h"
+#include "gtkcombobox.h"
+#include "gtktogglebutton.h"
+#include "gtkradiobutton.h"
+#include "gtklabel.h"
+#include "gtktable.h"
+#include "gtktooltips.h"
+#include "gtkcelllayout.h"
+#include "gtkcellrenderertext.h"
+#include "gtkalignment.h"
+#include "gtkspinbutton.h"
+
+#include "gtkpagesetupunixdialog.h"
+#include "gtkprintbackend.h"
+#include "gtkprinter-private.h"
+#include "gtkpapersize.h"
+#include "gtkalias.h"
+
+#define CUSTOM_PAPER_FILENAME ".gtk-custom-papers"
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+
+struct GtkPageSetupUnixDialogPrivate
+{
+  GtkListStore *printer_list;
+  GtkListStore *page_setup_list;
+  GtkListStore *custom_paper_list;
+  
+  GList *print_backends;
+
+  GtkWidget *printer_combo;
+  GtkWidget *paper_size_combo;
+  GtkWidget *paper_size_label;
+  GtkWidget *paper_size_eventbox;
+  GtkTooltips *tooltips;
+
+  GtkWidget *portrait_radio;
+  GtkWidget *landscape_radio;
+  GtkWidget *reverse_landscape_radio;
+
+  guint request_details_tag;
+  
+  GtkPrintSettings *print_settings;
+
+  /* Save last setup so we can re-set it after selecting manage custom sizes */
+  GtkPageSetup *last_setup;
+
+  char *waiting_for_printer;
+};
+
+enum {
+  PRINTER_LIST_COL_NAME,
+  PRINTER_LIST_COL_PRINTER,
+  PRINTER_LIST_N_COLS
+};
+
+enum {
+  PAGE_SETUP_LIST_COL_PAGE_SETUP,
+  PAGE_SETUP_LIST_COL_IS_SEPARATOR,
+  PAGE_SETUP_LIST_N_COLS
+};
+
+G_DEFINE_TYPE (GtkPageSetupUnixDialog, gtk_page_setup_unix_dialog, GTK_TYPE_DIALOG);
+
+#define GTK_PAGE_SETUP_UNIX_DIALOG_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG, GtkPageSetupUnixDialogPrivate))
+
+static void gtk_page_setup_unix_dialog_finalize  (GObject                *object);
+static void populate_dialog                      (GtkPageSetupUnixDialog *dialog);
+static void fill_paper_sizes_from_printer        (GtkPageSetupUnixDialog *dialog,
+                                                 GtkPrinter             *printer);
+static void run_custom_paper_dialog              (GtkPageSetupUnixDialog *dialog);
+static void gtk_page_setup_unix_dialog_style_set (GtkWidget              *widget,
+                                                 GtkStyle               *previous_style);
+
+static const char * const common_paper_sizes[] = {
+  "na_letter",
+  "na_legal",
+  "iso_a4",
+  "iso_a5",
+  "roc_16k",
+  "iso_b5",
+  "jis_b5",
+  "na_number-10",
+  "iso_dl",
+  "jpn_chou3",
+  "na_ledger",
+  "iso_a3",
+};
+
+static double
+to_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len * MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len * (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static double
+from_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len / MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len / (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static GtkUnit
+get_default_user_units (void)
+{
+  /* Translate to the default units to use for presenting
+   * lengths to the user. Translate to default:inch if you
+   * want inches, otherwise translate to default:mm.
+   * Do *not* translate it to "predefinito:mm", if it
+   * it isn't default:mm or default:inch it will not work 
+   */
+  char *e = _("default:mm");
+  
+#ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
+  char *imperial = NULL;
+  
+  imperial = nl_langinfo(_NL_MEASUREMENT_MEASUREMENT);
+  if (imperial && imperial[0] == 2 )
+    return GTK_UNIT_INCH;  /* imperial */
+  if (imperial && imperial[0] == 1 )
+    return GTK_UNIT_MM;  /* metric */
+#endif
+  
+  if (strcmp (e, "default:inch")==0)
+    return GTK_UNIT_INCH;
+  else if (strcmp (e, "default:mm"))
+    g_warning ("Whoever translated default:mm did so wrongly.\n");
+  return GTK_UNIT_MM;
+}
+
+static char *
+custom_paper_get_filename (void)
+{
+  char *filename;
+
+  filename = g_build_filename (g_get_home_dir (), 
+                              CUSTOM_PAPER_FILENAME, NULL);
+  g_assert (filename != NULL);
+  return filename;
+}
+
+static gboolean
+scan_double (char **text, double *val, gboolean last)
+{
+  char *p, *e;
+
+  p = *text;
+  
+  *val = g_ascii_strtod (p, &e);
+  if (p == e)
+    return FALSE;
+
+  p = e;
+  if (!last)
+    {
+      while (g_ascii_isspace(*p))
+       p++;
+      if (*p++ != ',')
+       return FALSE;
+    }
+  *text = p;
+  return TRUE;
+}
+
+static void
+load_custom_papers (GtkListStore *store)
+{
+  char *filename;
+  gchar *contents;
+  
+  filename = custom_paper_get_filename ();
+
+  if (g_file_get_contents (filename, &contents, NULL, NULL))
+    {
+      gchar **lines = g_strsplit (contents, "\n", -1);
+      double w, h, top, bottom, left, right;
+      GtkPaperSize *paper_size;
+      GtkPageSetup *page_setup;
+      char *name, *p;
+      GtkTreeIter iter;
+      int i;
+
+      for (i = 0; lines[i]; i++)
+       {
+         name = lines[i];
+         p = strchr(lines[i], ':');
+         if (p == NULL)
+           continue;
+         *p++ = 0;
+
+         while (g_ascii_isspace(*p))
+           p++;
+         
+         if (!scan_double (&p, &w, FALSE))
+           continue;
+         if (!scan_double (&p, &h, FALSE))
+           continue;
+         if (!scan_double (&p, &top, FALSE))
+           continue;
+         if (!scan_double (&p, &bottom, FALSE))
+           continue;
+         if (!scan_double (&p, &left, FALSE))
+           continue;
+         if (!scan_double (&p, &right, TRUE))
+           continue;
+
+         page_setup = gtk_page_setup_new ();
+         paper_size = gtk_paper_size_new_custom (name, name, w, h, GTK_UNIT_MM);
+         gtk_page_setup_set_paper_size (page_setup, paper_size);
+         gtk_paper_size_free (paper_size);
+
+         gtk_page_setup_set_top_margin (page_setup, top, GTK_UNIT_MM);
+         gtk_page_setup_set_bottom_margin (page_setup, bottom, GTK_UNIT_MM);
+         gtk_page_setup_set_left_margin (page_setup, left, GTK_UNIT_MM);
+         gtk_page_setup_set_right_margin (page_setup, right, GTK_UNIT_MM);
+
+         gtk_list_store_append (store, &iter);
+         gtk_list_store_set (store, &iter,
+                             0, page_setup, 
+                             -1);
+
+         g_object_unref (page_setup);
+       }
+      
+      g_free (contents);
+      g_strfreev (lines);
+    }
+  g_free (filename);
+}
+
+static void
+save_custom_papers (GtkListStore *store)
+{
+  GtkTreeModel *model = GTK_TREE_MODEL (store);
+  GtkTreeIter iter;
+  GString *string;
+  char *filename;
+
+  string = g_string_new ("");
+  
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+       {
+         GtkPaperSize *paper_size;
+         GtkPageSetup *page_setup;
+         char buffer[G_ASCII_DTOSTR_BUF_SIZE];
+         
+         gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
+
+         paper_size = gtk_page_setup_get_paper_size (page_setup);
+         g_string_append_printf (string, "%s: ", gtk_paper_size_get_name (paper_size));
+         
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+                         gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+         g_string_append (string, ", ");
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+                         gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+         g_string_append (string, ", ");
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+                         gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+         g_string_append (string, ", ");
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE, 
+                         gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+         g_string_append (string, ", ");
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+                         gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+         g_string_append (string, ", ");
+         g_ascii_dtostr (buffer, G_ASCII_DTOSTR_BUF_SIZE,
+                         gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
+         g_string_append (string, buffer);
+
+         g_string_append (string, "\n");
+         
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+
+  filename = custom_paper_get_filename ();
+  g_file_set_contents (filename, string->str, -1, NULL);
+  g_free (filename);
+  
+  g_string_free (string, TRUE);
+}
+
+static void
+gtk_page_setup_unix_dialog_class_init (GtkPageSetupUnixDialogClass *class)
+{
+  GObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GObjectClass *) class;
+  widget_class = (GtkWidgetClass *) class;
+
+  object_class->finalize = gtk_page_setup_unix_dialog_finalize;
+
+  widget_class->style_set = gtk_page_setup_unix_dialog_style_set;
+
+  g_type_class_add_private (class, sizeof (GtkPageSetupUnixDialogPrivate));  
+}
+
+static void
+gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter iter;
+
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+  
+  dialog->priv = GTK_PAGE_SETUP_UNIX_DIALOG_GET_PRIVATE (dialog); 
+  dialog->priv->print_backends = NULL;
+
+  dialog->priv->printer_list = gtk_list_store_new (PRINTER_LIST_N_COLS,
+                                                  G_TYPE_STRING, 
+                                                  G_TYPE_OBJECT);
+
+  gtk_list_store_append (dialog->priv->printer_list, &iter);
+  gtk_list_store_set (dialog->priv->printer_list, &iter,
+                      PRINTER_LIST_COL_NAME, _("<b>Any Printer</b>\nFor portable documents"),
+                      PRINTER_LIST_COL_PRINTER, NULL,
+                      -1);
+  
+  dialog->priv->page_setup_list = gtk_list_store_new (PAGE_SETUP_LIST_N_COLS,
+                                                     G_TYPE_OBJECT,
+                                                     G_TYPE_BOOLEAN);
+
+  dialog->priv->custom_paper_list = gtk_list_store_new (1, G_TYPE_OBJECT);
+  load_custom_papers (dialog->priv->custom_paper_list);
+
+  populate_dialog (dialog);
+  
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
+                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                          GTK_STOCK_APPLY, GTK_RESPONSE_OK,
+                          NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+static void
+gtk_page_setup_unix_dialog_finalize (GObject *object)
+{
+  GtkPageSetupUnixDialog *dialog = GTK_PAGE_SETUP_UNIX_DIALOG (object);
+  
+  g_return_if_fail (object != NULL);
+
+  if (dialog->priv->request_details_tag)
+    {
+      g_source_remove (dialog->priv->request_details_tag);
+      dialog->priv->request_details_tag = 0;
+    }
+  
+  if (dialog->priv->printer_list)
+    {
+      g_object_unref (dialog->priv->printer_list);
+      dialog->priv->printer_list = NULL;
+    }
+
+  if (dialog->priv->page_setup_list)
+    {
+      g_object_unref (dialog->priv->page_setup_list);
+      dialog->priv->page_setup_list = NULL;
+    }
+
+  if (dialog->priv->print_settings)
+    {
+      g_object_unref (dialog->priv->print_settings);
+      dialog->priv->print_settings = NULL;
+    }
+
+  g_free (dialog->priv->waiting_for_printer);
+  dialog->priv->waiting_for_printer = NULL;
+  
+  if (G_OBJECT_CLASS (gtk_page_setup_unix_dialog_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_page_setup_unix_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtk_page_setup_unix_dialog_style_set (GtkWidget *widget,
+                                     GtkStyle  *previous_style)
+{
+  GtkDialog *dialog;
+
+  if (GTK_WIDGET_CLASS (gtk_page_setup_unix_dialog_parent_class)->style_set)
+    GTK_WIDGET_CLASS (gtk_page_setup_unix_dialog_parent_class)->style_set (widget, previous_style);
+
+  dialog = GTK_DIALOG (widget);
+
+  /* Override the style properties with HIG-compliant spacings.  Ugh.
+   * http://developer.gnome.org/projects/gup/hig/1.0/layout.html#layout-dialogs
+   * http://developer.gnome.org/projects/gup/hig/1.0/windows.html#alert-spacing
+   */
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 12);
+  gtk_box_set_spacing (GTK_BOX (dialog->vbox), 24);
+
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 0);
+  gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+}
+
+
+static void
+printer_added_cb (GtkPrintBackend *backend, 
+                 GtkPrinter *printer, 
+                 GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter iter;
+  char *str;
+  const char *location;;
+
+  if (gtk_printer_is_virtual (printer))
+    return;
+
+  location = gtk_printer_get_location (printer);
+  if (location == NULL)
+    location = "";
+  str = g_strdup_printf ("<b>%s</b>\n%s",
+                        gtk_printer_get_name (printer),
+                        location);
+  
+  gtk_list_store_append (dialog->priv->printer_list, &iter);
+  gtk_list_store_set (dialog->priv->printer_list, &iter,
+                      PRINTER_LIST_COL_NAME, str,
+                      PRINTER_LIST_COL_PRINTER, printer,
+                      -1);
+
+  g_object_set_data_full (G_OBJECT (printer), 
+                         "gtk-print-tree-iter", 
+                          gtk_tree_iter_copy (&iter),
+                          (GDestroyNotify) gtk_tree_iter_free);
+  
+  g_free (str);
+
+  if (dialog->priv->waiting_for_printer != NULL &&
+      strcmp (dialog->priv->waiting_for_printer,
+             gtk_printer_get_name (printer)) == 0)
+    {
+      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->printer_combo),
+                                    &iter);
+      dialog->priv->waiting_for_printer = NULL;
+    }
+}
+
+static void
+printer_removed_cb (GtkPrintBackend *backend, 
+                   GtkPrinter *printer, 
+                   GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter *iter;
+  iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
+  gtk_list_store_remove (GTK_LIST_STORE (dialog->priv->printer_list), iter);
+}
+
+
+static void
+printer_status_cb (GtkPrintBackend *backend, 
+                   GtkPrinter *printer, 
+                  GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter *iter;
+  char *str;
+  const char *location;;
+  
+  iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
+
+  location = gtk_printer_get_location (printer);
+  if (location == NULL)
+    location = "";
+  str = g_strdup_printf ("<b>%s</b>\n%s",
+                        gtk_printer_get_name (printer),
+                        location);
+  gtk_list_store_set (dialog->priv->printer_list, iter,
+                      PRINTER_LIST_COL_NAME, str,
+                      -1);
+}
+
+static void
+printer_list_initialize (GtkPageSetupUnixDialog *dialog,
+                        GtkPrintBackend *print_backend)
+{
+  GList *list, *node;
+  
+  g_return_if_fail (print_backend != NULL);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-added", 
+                          (GCallback) printer_added_cb, 
+                          G_OBJECT (dialog), 0);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-removed", 
+                          (GCallback) printer_removed_cb, 
+                          G_OBJECT (dialog), 0);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-status-changed", 
+                          (GCallback) printer_status_cb, 
+                          G_OBJECT (dialog), 0);
+
+  list = gtk_print_backend_get_printer_list (print_backend);
+
+  node = list;
+  while (node != NULL)
+    {
+      printer_added_cb (print_backend, node->data, dialog);
+      node = node->next;
+    }
+
+  g_list_free (list);
+  
+}
+
+static void
+load_print_backends (GtkPageSetupUnixDialog *dialog)
+{
+  GList *node;
+
+  if (g_module_supported ())
+    dialog->priv->print_backends = gtk_print_backend_load_modules ();
+
+  for (node = dialog->priv->print_backends; node != NULL; node = node->next)
+    printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
+}
+
+static gboolean
+paper_size_row_is_separator (GtkTreeModel *model,
+                            GtkTreeIter  *iter,
+                            gpointer      data)
+{
+  gboolean separator;
+
+  gtk_tree_model_get (model, iter, PAGE_SETUP_LIST_COL_IS_SEPARATOR, &separator, -1);
+  return separator;
+}
+
+static GtkPageSetup *
+get_current_page_setup (GtkPageSetupUnixDialog *dialog)
+{
+  GtkPageSetup *current_page_setup;
+  GtkComboBox *combo_box;
+  GtkTreeIter iter;
+
+  current_page_setup = NULL;
+  
+  combo_box = GTK_COMBO_BOX (dialog->priv->paper_size_combo);
+  if (gtk_combo_box_get_active_iter (combo_box, &iter))
+    gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->page_setup_list), &iter,
+                       PAGE_SETUP_LIST_COL_PAGE_SETUP, &current_page_setup, -1);
+
+  if (current_page_setup)
+    return current_page_setup;
+
+  /* No selected page size, return the default one.
+   * This is used to set the first page setup when the dialog is created
+   * as there is no selection on the first printer_changed.
+   */ 
+  return gtk_page_setup_new ();
+}
+
+static gboolean
+page_setup_is_equal (GtkPageSetup *a, GtkPageSetup *b)
+{
+  return
+    gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
+                            gtk_page_setup_get_paper_size (b)) &&
+    gtk_page_setup_get_top_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_top_margin (b, GTK_UNIT_MM) &&
+    gtk_page_setup_get_bottom_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (b, GTK_UNIT_MM) &&
+    gtk_page_setup_get_left_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_left_margin (b, GTK_UNIT_MM) &&
+    gtk_page_setup_get_right_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_right_margin (b, GTK_UNIT_MM);
+}
+
+static gboolean
+page_setup_is_same_size (GtkPageSetup *a, GtkPageSetup *b)
+{
+  return gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
+                                 gtk_page_setup_get_paper_size (b));
+}
+
+static gboolean
+set_paper_size (GtkPageSetupUnixDialog *dialog,
+               GtkPageSetup *page_setup,
+               gboolean size_only,
+               gboolean add_item)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkPageSetup *list_page_setup;
+
+  model = GTK_TREE_MODEL (dialog->priv->page_setup_list);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+       {
+         gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->page_setup_list), &iter,
+                             PAGE_SETUP_LIST_COL_PAGE_SETUP, &list_page_setup, -1);
+         if (list_page_setup == NULL)
+           continue;
+         
+         if ((size_only && page_setup_is_same_size (page_setup, list_page_setup)) ||
+             (!size_only && page_setup_is_equal (page_setup, list_page_setup)))
+           {
+             gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->paper_size_combo),
+                                            &iter);
+             g_object_unref (list_page_setup);
+             return TRUE;
+           }
+             
+         g_object_unref (list_page_setup);
+         
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+
+  if (add_item)
+    {
+      gtk_list_store_append (dialog->priv->page_setup_list, &iter);
+      gtk_list_store_set (dialog->priv->page_setup_list, &iter,
+                         PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
+                         -1);
+      gtk_list_store_append (dialog->priv->page_setup_list, &iter);
+      gtk_list_store_set (dialog->priv->page_setup_list, &iter,
+                         PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
+                         -1);
+      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->paper_size_combo),
+                                    &iter);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+fill_custom_paper_sizes (GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter iter, paper_iter;
+  GtkTreeModel *model;
+
+  model = GTK_TREE_MODEL (dialog->priv->custom_paper_list);
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      gtk_list_store_append (dialog->priv->page_setup_list, &paper_iter);
+      gtk_list_store_set (dialog->priv->page_setup_list, &paper_iter,
+                         PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
+                         -1);
+      do
+       {
+         GtkPageSetup *page_setup;
+         gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
+
+         gtk_list_store_append (dialog->priv->page_setup_list, &paper_iter);
+         gtk_list_store_set (dialog->priv->page_setup_list, &paper_iter,
+                             PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
+                             -1);
+
+         g_object_unref (page_setup);
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+  
+  gtk_list_store_append (dialog->priv->page_setup_list, &paper_iter);
+  gtk_list_store_set (dialog->priv->page_setup_list, &paper_iter,
+                      PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
+                      -1);
+  gtk_list_store_append (dialog->priv->page_setup_list, &paper_iter);
+  gtk_list_store_set (dialog->priv->page_setup_list, &paper_iter,
+                      PAGE_SETUP_LIST_COL_PAGE_SETUP, NULL,
+                      -1);
+}
+
+static void
+fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog,
+                              GtkPrinter *printer)
+{
+  GList *list, *l;
+  GtkPageSetup *current_page_setup, *page_setup;
+  GtkPaperSize *paper_size;
+  GtkTreeIter iter;
+  int i;
+
+  current_page_setup = get_current_page_setup (dialog);
+  
+  gtk_list_store_clear (dialog->priv->page_setup_list);
+
+  if (printer == NULL)
+    {
+      for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
+       {
+         page_setup = gtk_page_setup_new ();
+         paper_size = gtk_paper_size_new (common_paper_sizes[i]);
+         gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
+         gtk_paper_size_free (paper_size);
+         
+         gtk_list_store_append (dialog->priv->page_setup_list, &iter);
+         gtk_list_store_set (dialog->priv->page_setup_list, &iter,
+                             PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
+                             -1);
+         g_object_unref (page_setup);
+       }
+    }
+  else
+    {
+      list = _gtk_printer_list_papers (printer);
+      /* TODO: We should really sort this list so interesting size
+        are at the top */
+      for (l = list; l != NULL; l = l->next)
+       {
+         page_setup = l->data;
+         gtk_list_store_append (dialog->priv->page_setup_list, &iter);
+         gtk_list_store_set (dialog->priv->page_setup_list, &iter,
+                             PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
+                             -1);
+         g_object_unref (page_setup);
+       }
+      g_list_free (list);
+    }
+
+  fill_custom_paper_sizes (dialog);
+  
+  if (!set_paper_size (dialog, current_page_setup, FALSE, FALSE))
+    set_paper_size (dialog, current_page_setup, TRUE, TRUE);
+  
+  if (current_page_setup)
+    g_object_unref (current_page_setup);
+}
+
+static void
+printer_changed_finished_callback (GtkPrinter *printer,
+                                  gboolean success,
+                                  GtkPageSetupUnixDialog *dialog)
+{
+  dialog->priv->request_details_tag = 0;
+  
+  if (success)
+    fill_paper_sizes_from_printer (dialog, printer);
+
+}
+
+static void
+printer_changed_callback (GtkComboBox *combo_box,
+                         GtkPageSetupUnixDialog *dialog)
+{
+  GtkPrinter *printer;
+  GtkTreeIter iter;
+
+  /* If we're waiting for a specific printer but the user changed
+     to another printer, cancel that wait. */
+  if (dialog->priv->waiting_for_printer)
+    {
+      g_free (dialog->priv->waiting_for_printer);
+      dialog->priv->waiting_for_printer = NULL;
+    }
+  
+  if (dialog->priv->request_details_tag)
+    {
+      g_source_remove (dialog->priv->request_details_tag);
+      dialog->priv->request_details_tag = 0;
+    }
+  
+  if (gtk_combo_box_get_active_iter (combo_box, &iter))
+    {
+      gtk_tree_model_get (gtk_combo_box_get_model (combo_box), &iter,
+                         PRINTER_LIST_COL_PRINTER, &printer, -1);
+
+      if (printer == NULL || _gtk_printer_has_details (printer))
+       fill_paper_sizes_from_printer (dialog, printer);
+      else
+       {
+         dialog->priv->request_details_tag =
+           g_signal_connect (printer, "details-acquired",
+                             G_CALLBACK (printer_changed_finished_callback), dialog);
+         _gtk_printer_request_details (printer);
+
+       }
+
+      if (printer)
+       g_object_unref (printer);
+
+      if (dialog->priv->print_settings)
+       {
+         const char *name = NULL;
+
+         if (printer)
+           name = gtk_printer_get_name (printer);
+         
+         gtk_print_settings_set (dialog->priv->print_settings,
+                                 "format-for-printer", name);
+       }
+    }
+}
+
+/* We do this munging because we don't want to show zero digits
+   after the decimal point, and not to many such digits if they
+   are nonzero. I wish printf let you specify max precision for %f... */
+static char *
+double_to_string (double d, GtkUnit unit)
+{
+  char *val, *p;
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+  
+  /* Max two decimal digits for inch, max one for mm */
+  if (unit == GTK_UNIT_INCH)
+    val = g_strdup_printf ("%.2f", d);
+  else
+    val = g_strdup_printf ("%.1f", d);
+
+  if (strstr (val, decimal_point))
+    {
+      p = val + strlen (val) - 1;
+      while (*p == '0')
+        p--;
+      if (p - val + 1 >= decimal_point_len &&
+         strncmp (p - (decimal_point_len - 1), decimal_point, decimal_point_len) == 0)
+        p -= decimal_point_len;
+      p[1] = '\0';
+    }
+
+  return val;
+}
+
+static void
+paper_size_changed (GtkComboBox *combo_box, GtkPageSetupUnixDialog *dialog)
+{
+  GtkTreeIter iter;
+  GtkPageSetup *page_setup, *last_page_setup;
+  GtkUnit unit;
+  char *str, *w, *h;
+  char *top, *bottom, *left, *right;
+  GtkLabel *label;
+  const char *unit_str;
+
+  label = GTK_LABEL (dialog->priv->paper_size_label);
+   
+  if (gtk_combo_box_get_active_iter (combo_box, &iter))
+    {
+      gtk_tree_model_get (gtk_combo_box_get_model (combo_box),
+                         &iter, PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup, -1);
+
+      if (page_setup == NULL)
+       {
+         run_custom_paper_dialog (dialog);
+
+         /* Save current last_setup as it is changed by updating the list */
+         last_page_setup = NULL;
+         if (dialog->priv->last_setup)
+           last_page_setup = g_object_ref (dialog->priv->last_setup);
+
+         /* Update printer page list */
+         printer_changed_callback (GTK_COMBO_BOX (dialog->priv->printer_combo), dialog);
+
+         /* Change from "manage" menu item to last value */
+         if (last_page_setup == NULL)
+           last_page_setup = gtk_page_setup_new (); /* "good" default */
+         set_paper_size (dialog, last_page_setup, FALSE, TRUE);
+         g_object_unref (last_page_setup);
+         
+         return;
+       }
+
+      if (dialog->priv->last_setup)
+       g_object_unref (dialog->priv->last_setup);
+
+      dialog->priv->last_setup = g_object_ref (page_setup);
+      
+      unit = get_default_user_units ();
+
+      if (unit == GTK_UNIT_MM)
+       unit_str = _("mm");
+      else
+       unit_str = _("inch");
+       
+
+      w = double_to_string (gtk_page_setup_get_paper_width (page_setup, unit),
+                           unit);
+      h = double_to_string (gtk_page_setup_get_paper_height (page_setup, unit),
+                           unit);
+      str = g_strdup_printf ("%s x %s %s", w, h, unit_str);
+      g_free (w);
+      g_free (h);
+      
+      gtk_label_set_text (label, str);
+      g_free (str);
+
+      top = double_to_string (gtk_page_setup_get_top_margin (page_setup, unit), unit);
+      bottom = double_to_string (gtk_page_setup_get_bottom_margin (page_setup, unit), unit);
+      left = double_to_string (gtk_page_setup_get_left_margin (page_setup, unit), unit);
+      right = double_to_string (gtk_page_setup_get_right_margin (page_setup, unit), unit);
+
+      str = g_strdup_printf (_("Margins:\n"
+                              " Left: %s %s\n"
+                              " Right: %s %s\n"
+                              " Top: %s %s\n"
+                              " Bottom: %s %s"
+                              ),
+                            left, unit_str,
+                            right, unit_str,
+                            top, unit_str,
+                            bottom, unit_str);
+      g_free (top);
+      g_free (bottom);
+      g_free (left);
+      g_free (right);
+      
+      gtk_tooltips_set_tip (GTK_TOOLTIPS (dialog->priv->tooltips),
+                           dialog->priv->paper_size_eventbox, str, NULL);
+      g_free (str);
+      
+      g_object_unref (page_setup);
+    }
+  else
+    {
+      gtk_label_set_text (label, "");
+      gtk_tooltips_set_tip (GTK_TOOLTIPS (dialog->priv->tooltips),
+                           dialog->priv->paper_size_eventbox, NULL, NULL);
+      if (dialog->priv->last_setup)
+       g_object_unref (dialog->priv->last_setup);
+      dialog->priv->last_setup = NULL;
+    }
+}
+
+static void
+page_name_func (GtkCellLayout   *cell_layout,
+               GtkCellRenderer *cell,
+               GtkTreeModel    *tree_model,
+               GtkTreeIter     *iter,
+               gpointer         data)
+{
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+  
+  gtk_tree_model_get (tree_model, iter,
+                     PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup, -1);
+  if (page_setup)
+    {
+      paper_size = gtk_page_setup_get_paper_size (page_setup);
+      g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
+      g_object_unref (page_setup);
+    }
+  else
+    g_object_set (cell, "text",  _("Manage Custom Sizes..."), NULL);
+      
+}
+
+static void
+populate_dialog (GtkPageSetupUnixDialog *dialog)
+{
+  GtkPageSetupUnixDialogPrivate *priv;
+  GtkWidget *table, *label, *combo, *radio_button, *ebox, *image;
+  GtkCellRenderer *cell;
+  
+  g_return_if_fail (GTK_IS_PAGE_SETUP_UNIX_DIALOG (dialog));
+  
+  priv = dialog->priv;
+
+  table = gtk_table_new (4, 4, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 12);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+                     table, TRUE, TRUE, 6);
+  gtk_widget_show (table);
+
+  label = gtk_label_new_with_mnemonic (_("_Format for:"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,
+                   GTK_FILL, 0, 0, 0);
+  gtk_widget_show (label);
+
+  combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (dialog->priv->printer_list));
+  dialog->priv->printer_combo = combo;
+  
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
+                                  "markup", PRINTER_LIST_COL_NAME,
+                                  NULL);
+
+  gtk_table_attach (GTK_TABLE (table), combo,
+                   1, 4, 0, 1,
+                   GTK_FILL | GTK_EXPAND, 0, 0, 0);
+  gtk_widget_show (combo);
+
+  label = gtk_label_new_with_mnemonic (_("_Paper size:"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2,
+                   GTK_FILL, 0, 0, 0);
+  gtk_widget_show (label);
+
+  combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (dialog->priv->page_setup_list));
+  dialog->priv->paper_size_combo = combo;
+  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo), 
+                                       paper_size_row_is_separator, NULL, NULL);
+  
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
+                                     page_name_func, NULL, NULL);
+
+  gtk_table_attach (GTK_TABLE (table), combo,
+                   1, 4, 1, 2,
+                   GTK_FILL | GTK_EXPAND, 0, 0, 0);
+  gtk_widget_show (combo);
+
+  gtk_table_set_row_spacing (GTK_TABLE (table), 1, 0);
+
+  ebox = gtk_event_box_new ();
+  dialog->priv->paper_size_eventbox = ebox;
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
+  gtk_table_attach (GTK_TABLE (table), ebox,
+                   1, 4, 2, 3,
+                   GTK_FILL, 0, 0, 0);
+  gtk_widget_show (ebox);
+  
+  label = gtk_label_new_with_mnemonic ("");
+  dialog->priv->paper_size_label = label;
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_misc_set_padding (GTK_MISC (label), 12, 4);
+  gtk_container_add (GTK_CONTAINER (ebox), label);
+  gtk_widget_show (label);
+
+  label = gtk_label_new_with_mnemonic (_("_Orientation:"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 3, 4,
+                   GTK_FILL, 0, 0, 0);
+  gtk_widget_show (label);
+
+  radio_button = gtk_radio_button_new (NULL);
+  image = gtk_image_new_from_stock (GTK_STOCK_ORIENTATION_PORTRAIT,
+                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
+  gtk_widget_show (image);
+  gtk_container_add (GTK_CONTAINER (radio_button), image);
+  dialog->priv->portrait_radio = radio_button;
+  gtk_table_attach (GTK_TABLE (table), radio_button,
+                   1, 2, 3, 4,
+                   0, 0, 0, 0);
+  gtk_widget_show (radio_button);
+
+  radio_button = gtk_radio_button_new (gtk_radio_button_get_group (GTK_RADIO_BUTTON(radio_button)));
+  image = gtk_image_new_from_stock (GTK_STOCK_ORIENTATION_LANDSCAPE,
+                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
+  gtk_widget_show (image);
+  gtk_container_add (GTK_CONTAINER (radio_button), image);
+  dialog->priv->landscape_radio = radio_button;
+  gtk_table_attach (GTK_TABLE (table), radio_button,
+                   2, 3, 3, 4,
+                   0, 0, 0, 0);
+  gtk_widget_show (radio_button);
+
+  gtk_table_set_row_spacing (GTK_TABLE (table), 3, 0);
+  
+  radio_button = gtk_radio_button_new (gtk_radio_button_get_group (GTK_RADIO_BUTTON(radio_button)));
+  image = gtk_image_new_from_stock (GTK_STOCK_ORIENTATION_REVERSE_LANDSCAPE,
+                                   GTK_ICON_SIZE_LARGE_TOOLBAR);
+  gtk_widget_show (image);
+  gtk_container_add (GTK_CONTAINER (radio_button), image);
+  dialog->priv->reverse_landscape_radio = radio_button;
+  gtk_table_attach (GTK_TABLE (table), radio_button,
+                   3, 4, 3, 4,
+                   0, 0, 0, 0);
+  gtk_widget_show (radio_button);
+
+  dialog->priv->tooltips = gtk_tooltips_new ();
+
+  g_signal_connect (dialog->priv->paper_size_combo, "changed", G_CALLBACK (paper_size_changed), dialog);
+  g_signal_connect (dialog->priv->printer_combo, "changed", G_CALLBACK (printer_changed_callback), dialog);
+  gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->printer_combo), 0);
+
+  load_print_backends (dialog);
+}
+
+GtkWidget *
+gtk_page_setup_unix_dialog_new (const gchar *title,
+                               GtkWindow *parent)
+{
+  GtkWidget *result;
+
+  if (title == NULL)
+    title = _("Page Setup");
+  
+  result = g_object_new (GTK_TYPE_PAGE_SETUP_UNIX_DIALOG,
+                         "title", title,
+                         NULL);
+
+  if (parent)
+    gtk_window_set_transient_for (GTK_WINDOW (result), parent);
+
+  return result;
+}
+
+static GtkPageOrientation
+get_orientation (GtkPageSetupUnixDialog *dialog)
+{
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->portrait_radio)))
+    return GTK_PAGE_ORIENTATION_PORTRAIT;
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->landscape_radio)))
+    return GTK_PAGE_ORIENTATION_LANDSCAPE;
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_landscape_radio)))
+    return GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE;
+  return GTK_PAGE_ORIENTATION_PORTRAIT;
+}
+
+static void
+set_orientation (GtkPageSetupUnixDialog *dialog, GtkPageOrientation orientation)
+{
+  switch (orientation)
+    {
+    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+    case GTK_PAGE_ORIENTATION_PORTRAIT:
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->portrait_radio), TRUE);
+      break;
+    case GTK_PAGE_ORIENTATION_LANDSCAPE:
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->landscape_radio), TRUE);
+      break;
+    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_landscape_radio), TRUE);
+      break;
+    }
+}
+
+
+void
+gtk_page_setup_unix_dialog_set_page_setup (GtkPageSetupUnixDialog *dialog,
+                                          GtkPageSetup           *page_setup)
+{
+  if (page_setup)
+    {
+      set_paper_size (dialog, page_setup, FALSE, TRUE);
+      set_orientation (dialog, gtk_page_setup_get_orientation (page_setup));
+    }
+}
+
+GtkPageSetup *
+gtk_page_setup_unix_dialog_get_page_setup (GtkPageSetupUnixDialog *dialog)
+{
+  GtkPageSetup *page_setup;
+  
+  page_setup = get_current_page_setup (dialog);
+  if (page_setup == NULL)
+    page_setup = gtk_page_setup_new ();
+
+  gtk_page_setup_set_orientation (page_setup, get_orientation (dialog));
+
+  return page_setup;
+}
+
+static gboolean
+set_active_printer (GtkPageSetupUnixDialog *dialog,
+                   const char *printer_name)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkPrinter *printer;
+
+  model = GTK_TREE_MODEL (dialog->priv->printer_list);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+       {
+         gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->printer_list), &iter,
+                             PRINTER_LIST_COL_PRINTER, &printer, -1);
+         if (printer == NULL)
+           continue;
+         
+         if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
+           {
+             gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->printer_combo),
+                                            &iter);
+             g_object_unref (printer);
+             return TRUE;
+           }
+             
+         g_object_unref (printer);
+         
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+  
+  return FALSE;
+}
+
+void
+gtk_page_setup_unix_dialog_set_print_settings (GtkPageSetupUnixDialog *dialog,
+                                              GtkPrintSettings       *print_settings)
+{
+  const char *format_for_printer;
+
+  if (dialog->priv->print_settings)
+    g_object_unref (dialog->priv->print_settings);
+
+  dialog->priv->print_settings = print_settings;
+
+  if (print_settings)
+    {
+      g_object_ref (print_settings);
+
+      format_for_printer = gtk_print_settings_get (print_settings, "format-for-printer");
+
+      /* Set printer if in list, otherwise set when that printer
+        is added */
+      if (format_for_printer &&
+         !set_active_printer (dialog, format_for_printer))
+       dialog->priv->waiting_for_printer = g_strdup (format_for_printer); 
+    }
+}
+
+GtkPrintSettings *
+gtk_page_setup_unix_dialog_get_print_settings (GtkPageSetupUnixDialog *dialog)
+{
+  return dialog->priv->print_settings;
+}
+
+static GtkWidget *
+wrap_in_frame (const char *label, GtkWidget *child)
+{
+  GtkWidget *frame, *alignment, *label_widget;
+  char *bold_text;
+
+  label_widget = gtk_label_new ("");
+  gtk_widget_show (label_widget);
+  
+  bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
+  gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
+  g_free (bold_text);
+  
+  frame = gtk_frame_new ("");
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label_widget);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  
+  alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+                            12, 0, 12, 0);
+  gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+  gtk_container_add (GTK_CONTAINER (alignment), child);
+
+  gtk_widget_show (frame);
+  gtk_widget_show (alignment);
+  
+  return frame;
+}
+
+typedef struct {
+  GtkUnit display_unit;
+  GtkWidget *spin_button;
+} UnitWidget;
+
+typedef struct {
+  GtkPageSetupUnixDialog *dialog;
+  GtkWidget *treeview;
+  GtkTreeViewColumn *text_column;
+  gboolean non_user_change;
+  GtkWidget *printer_combo;
+  GtkWidget *width_widget;
+  GtkWidget *height_widget;
+  GtkWidget *top_widget;
+  GtkWidget *bottom_widget;
+  GtkWidget *left_widget;
+  GtkWidget *right_widget;
+  guint request_details_tag;
+} CustomPaperDialog;
+
+static void unit_widget_changed (CustomPaperDialog *data);
+
+static GtkWidget *
+new_unit_widget (CustomPaperDialog *dialog, GtkUnit unit)
+{
+  GtkWidget *hbox, *button, *label;
+  UnitWidget *data;
+
+  data = g_new0 (UnitWidget, 1);
+  data->display_unit = unit;
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+
+  button = gtk_spin_button_new_with_range (0.0, 9999.0, 1);
+  if (unit == GTK_UNIT_INCH)
+    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 2);
+  else
+    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 1);
+
+  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+  gtk_widget_show (button);
+
+  data->spin_button = button;
+
+  g_signal_connect_swapped (button, "value_changed",
+                           G_CALLBACK (unit_widget_changed), dialog);
+  
+  if (unit == GTK_UNIT_INCH)
+    label = gtk_label_new (_(" inch"));
+  else
+    label = gtk_label_new (_(" mm"));
+
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+
+  g_object_set_data_full (G_OBJECT (hbox), "unit-data", data, g_free);
+  
+  return hbox;
+}
+
+static double
+unit_widget_get (GtkWidget *unit_widget)
+{
+  UnitWidget *data = g_object_get_data (G_OBJECT (unit_widget), "unit-data");
+  return to_mm (gtk_spin_button_get_value (GTK_SPIN_BUTTON (data->spin_button)),
+               data->display_unit);
+}
+
+static void
+unit_widget_set (GtkWidget *unit_widget, double val)
+{
+  UnitWidget *data = g_object_get_data (G_OBJECT (unit_widget), "unit-data");
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->spin_button),
+                            from_mm (val, data->display_unit));
+
+}
+
+static void
+unit_widget_set_sensitive (GtkWidget *unit_widget, gboolean sensitive)
+{
+  UnitWidget *data = g_object_get_data (G_OBJECT (unit_widget), "unit-data");
+  gtk_widget_set_sensitive (data->spin_button, sensitive);
+}
+
+static void
+custom_paper_printer_data_func (GtkCellLayout   *cell_layout,
+                               GtkCellRenderer *cell,
+                               GtkTreeModel    *tree_model,
+                               GtkTreeIter     *iter,
+                               gpointer         data)
+{
+  GtkPrinter *printer;
+  gtk_tree_model_get (tree_model, iter,
+                     PRINTER_LIST_COL_PRINTER, &printer, -1);
+
+  if (printer)
+    g_object_set (cell, "text",  gtk_printer_get_name (printer), NULL);
+  else
+    g_object_set (cell, "text",  _("Margins from Printer..."), NULL);
+  
+  if (printer)
+    g_object_unref (printer);
+}
+
+static void
+update_combo_sensitivity_from_printers (CustomPaperDialog *data)
+{
+  GtkTreeIter iter;
+  gboolean sensitive;
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+
+  sensitive = FALSE;
+  model = GTK_TREE_MODEL (data->dialog->priv->printer_list);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->treeview));
+  if (gtk_tree_model_get_iter_first (model, &iter) &&
+      gtk_tree_model_iter_next (model, &iter) &&
+      gtk_tree_selection_get_selected (selection, NULL, &iter))
+    sensitive = TRUE;
+
+  g_print ("sensitive: %d\n", sensitive);
+  gtk_widget_set_sensitive (data->printer_combo, sensitive);
+}
+
+static void
+update_custom_widgets_from_list (CustomPaperDialog *data)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkPageSetup *page_setup;
+  
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->treeview));
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->treeview));
+
+  data->non_user_change = TRUE;
+  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+    {
+      gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
+      
+      unit_widget_set (data->width_widget,
+                      gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM));
+      unit_widget_set (data->height_widget, 
+                      gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM));
+      unit_widget_set (data->top_widget,
+                      gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
+      unit_widget_set (data->bottom_widget, 
+                      gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
+      unit_widget_set (data->left_widget,
+                      gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
+      unit_widget_set (data->right_widget,
+                      gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
+      
+      unit_widget_set_sensitive (data->width_widget, TRUE);
+      unit_widget_set_sensitive (data->height_widget, TRUE);
+      unit_widget_set_sensitive (data->top_widget, TRUE);
+      unit_widget_set_sensitive (data->bottom_widget, TRUE);
+      unit_widget_set_sensitive (data->left_widget, TRUE);
+      unit_widget_set_sensitive (data->right_widget, TRUE);
+    }
+  else
+    {
+      unit_widget_set_sensitive (data->width_widget, FALSE);
+      unit_widget_set_sensitive (data->height_widget, FALSE);
+      unit_widget_set_sensitive (data->top_widget, FALSE);
+      unit_widget_set_sensitive (data->bottom_widget, FALSE);
+      unit_widget_set_sensitive (data->left_widget, FALSE);
+      unit_widget_set_sensitive (data->right_widget, FALSE);
+    }
+
+  update_combo_sensitivity_from_printers (data);
+  data->non_user_change = FALSE;
+}
+
+static void
+selected_custom_paper_changed (GtkTreeSelection *selection,
+                              CustomPaperDialog *data)
+{
+  update_custom_widgets_from_list (data);
+}
+
+static void
+unit_widget_changed (CustomPaperDialog *data)
+{
+  double w, h, top, bottom, left, right;
+  GtkTreeSelection *selection;
+  GtkTreeIter iter;
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+
+  if (data->non_user_change)
+    return;
+  
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->treeview));
+
+  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+    {
+      gtk_tree_model_get (GTK_TREE_MODEL (data->dialog->priv->custom_paper_list), &iter, 0, &page_setup, -1);
+
+      w = unit_widget_get (data->width_widget);
+      h = unit_widget_get (data->height_widget);
+
+      paper_size = gtk_page_setup_get_paper_size (page_setup);
+      gtk_paper_size_set_size (paper_size, w, h, GTK_UNIT_MM);
+      
+      top = unit_widget_get (data->top_widget);
+      bottom = unit_widget_get (data->bottom_widget);
+      left = unit_widget_get (data->left_widget);
+      right = unit_widget_get (data->right_widget);
+
+      gtk_page_setup_set_top_margin (page_setup, top, GTK_UNIT_MM);
+      gtk_page_setup_set_bottom_margin (page_setup, bottom, GTK_UNIT_MM);
+      gtk_page_setup_set_left_margin (page_setup, left, GTK_UNIT_MM);
+      gtk_page_setup_set_right_margin (page_setup, right, GTK_UNIT_MM);
+      
+      g_object_unref (page_setup);
+    }
+}
+
+static gboolean
+custom_paper_name_used (CustomPaperDialog *data, const char *name)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+  
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->treeview));
+         
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+       {
+         gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
+         paper_size = gtk_page_setup_get_paper_size (page_setup);
+         if (strcmp (name,
+                     gtk_paper_size_get_name (paper_size)) == 0)
+           {
+             g_object_unref (page_setup);
+             return TRUE;
+           }
+         g_object_unref (page_setup);
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+  
+  return FALSE;
+}
+
+static void
+add_custom_paper (CustomPaperDialog *data)
+{
+  GtkListStore *store;
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+  GtkTreeSelection *selection;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  char *name;
+  int i;
+  
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->treeview));
+  store = data->dialog->priv->custom_paper_list;
+
+  i = 1;
+  name = NULL;
+  do
+    {
+      g_free (name);
+      name = g_strdup_printf (_("Custom Size %d"), i);
+      i++;
+    } while (custom_paper_name_used (data, name));
+
+  page_setup = gtk_page_setup_new ();
+  paper_size = gtk_paper_size_new_custom (name, name,
+                                         gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM),
+                                         gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM),
+                                         GTK_UNIT_MM);
+  gtk_page_setup_set_paper_size (page_setup, paper_size);
+  gtk_paper_size_free (paper_size);
+  
+  gtk_list_store_append (store, &iter);
+  gtk_list_store_set (store, &iter, 0, page_setup, -1);
+  g_object_unref (page_setup);
+
+  gtk_tree_selection_select_iter (selection, &iter);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+  gtk_widget_grab_focus (data->treeview);
+  gtk_tree_view_set_cursor (GTK_TREE_VIEW (data->treeview), path,
+                           data->text_column, TRUE);
+  gtk_tree_path_free (path);
+  
+}
+
+static void
+remove_custom_paper (CustomPaperDialog *data)
+{
+  GtkTreeSelection *selection;
+  GtkTreeIter iter;
+  GtkListStore *store;
+  
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->treeview));
+  store = data->dialog->priv->custom_paper_list;
+
+  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+    {
+      GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+      gtk_list_store_remove (store, &iter);
+      
+      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+       gtk_tree_selection_select_iter (selection, &iter);
+      else if (gtk_tree_path_prev (path) && gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
+       gtk_tree_selection_select_iter (selection, &iter);
+      
+      gtk_tree_path_free (path);
+    }
+}
+
+static void
+set_margins_from_printer (CustomPaperDialog *data,
+                         GtkPrinter *printer)
+{
+  double top, bottom, left, right;
+
+  top = bottom = left = right = 0;
+  _gtk_printer_get_hard_margins (printer, &top, &bottom, &left, &right);
+  
+  data->non_user_change = TRUE;
+  unit_widget_set (data->top_widget, to_mm (top, GTK_UNIT_POINTS));
+  unit_widget_set (data->bottom_widget, to_mm (bottom, GTK_UNIT_POINTS));
+  unit_widget_set (data->left_widget, to_mm (left, GTK_UNIT_POINTS));
+  unit_widget_set (data->right_widget, to_mm (right, GTK_UNIT_POINTS));
+  data->non_user_change = FALSE;
+
+  /* Only send one change */
+  unit_widget_changed (data);
+}
+
+static void
+get_margins_finished_callback (GtkPrinter *printer,
+                              gboolean success,
+                              CustomPaperDialog *data)
+{
+  data->request_details_tag = 0;
+  
+  if (success)
+    set_margins_from_printer (data, printer);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (data->printer_combo), 0);
+}
+
+static void
+margins_from_printer_changed (CustomPaperDialog *data)
+{
+  GtkTreeIter iter;
+  GtkComboBox *combo;
+  GtkPrinter *printer;
+
+  combo = GTK_COMBO_BOX (data->printer_combo);
+
+  if (data->request_details_tag)
+    {
+      g_source_remove (data->request_details_tag);
+      data->request_details_tag = 0;
+    }
+  
+  if (gtk_combo_box_get_active_iter  (combo, &iter))
+    {
+      gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+                         PRINTER_LIST_COL_PRINTER, &printer, -1);
+
+      if (printer)
+       {
+         if (_gtk_printer_has_details (printer))
+           {
+             set_margins_from_printer (data, printer);
+             gtk_combo_box_set_active (combo, 0);
+           }
+         else
+           {
+             data->request_details_tag =
+               g_signal_connect (printer, "details-acquired",
+                                 G_CALLBACK (get_margins_finished_callback), data);
+             _gtk_printer_request_details (printer);
+           }
+
+         g_object_unref (printer);
+       }
+    }
+}
+
+
+static void
+custom_paper_dialog_free (gpointer p)
+{
+  CustomPaperDialog *data = p;
+  if (data->request_details_tag)
+    {
+      g_source_remove (data->request_details_tag);
+      data->request_details_tag = 0;
+    }
+  
+  g_free (data);
+}
+
+static void
+custom_size_name_edited (GtkCellRenderer   *cell,
+                        gchar             *path_string,
+                        gchar             *new_text,
+                        CustomPaperDialog *data)
+{
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkListStore *store;
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+
+  store = data->dialog->priv->custom_paper_list;
+  path = gtk_tree_path_new_from_string (path_string);
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &page_setup, -1);
+  gtk_tree_path_free (path);
+
+  paper_size = gtk_paper_size_new_custom (new_text, new_text,
+                                         gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM),
+                                         gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM),
+                                         GTK_UNIT_MM);
+  gtk_page_setup_set_paper_size (page_setup, paper_size);
+  gtk_paper_size_free (paper_size);
+  
+  g_object_unref (page_setup);
+}
+
+static void
+custom_name_func (GtkTreeViewColumn *tree_column,
+                 GtkCellRenderer   *cell,
+                 GtkTreeModel      *tree_model,
+                 GtkTreeIter       *iter,
+                 gpointer           data)
+{
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+
+  gtk_tree_model_get (tree_model, iter, 0, &page_setup, -1);
+  if (page_setup)
+    {
+      paper_size = gtk_page_setup_get_paper_size (page_setup);
+      g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
+      g_object_unref (page_setup);
+    }
+}
+
+static void
+set_dialog_hig_spacing (GtkWidget *widget,
+                       GtkStyle *previous_style,
+                       GtkDialog *dialog)
+{
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 12);
+  gtk_box_set_spacing (GTK_BOX (dialog->vbox), 24);
+  gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 0);
+  gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
+}
+
+static void
+run_custom_paper_dialog (GtkPageSetupUnixDialog *dialog)
+{
+  GtkWidget *custom_dialog, *image, *table, *label, *widget, *frame, *combo;
+  GtkWidget *hbox, *vbox, *treeview, *scrolled, *button_box, *button;
+  GtkCellRenderer *cell;
+  GtkTreeViewColumn *column;
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  CustomPaperDialog *data;
+  GtkUnit user_units;
+  gulong printer_tag1, printer_tag2;
+  
+  custom_dialog = gtk_dialog_new_with_buttons (_("Manage Custom Sizes"),
+                                              GTK_WINDOW (dialog),
+                                              GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+                                              GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+                                              NULL);
+
+  g_signal_connect (custom_dialog, "style-set", G_CALLBACK (set_dialog_hig_spacing), custom_dialog);
+  
+  data = g_new0 (CustomPaperDialog, 1);
+  data->dialog = dialog;
+  g_object_set_data_full (G_OBJECT (custom_dialog), "custom-dialog", data, custom_paper_dialog_free);
+
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (custom_dialog)->vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+  gtk_widget_show (vbox);
+  
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
+                                      GTK_SHADOW_IN);
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
+  gtk_widget_show (scrolled);
+
+  treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (dialog->priv->custom_paper_list));
+  data->treeview = treeview;
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+  gtk_widget_set_size_request (treeview, 140, -1);
+  
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+  g_signal_connect (selection, "changed", G_CALLBACK (selected_custom_paper_changed), data);
+
+  cell = gtk_cell_renderer_text_new ();
+  g_object_set (cell, "editable", TRUE, NULL);
+  g_signal_connect (cell, "edited", 
+                   G_CALLBACK (custom_size_name_edited), data);
+  data->text_column = column =
+    gtk_tree_view_column_new_with_attributes ("paper", cell,
+                                             NULL);
+  gtk_tree_view_column_set_cell_data_func  (column, cell, custom_name_func, NULL, NULL);
+  
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  gtk_container_add (GTK_CONTAINER (scrolled), treeview);
+  gtk_widget_show (treeview);
+
+  button_box = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
+  gtk_widget_show (button_box);
+
+  button = gtk_button_new ();
+  image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (image);
+  gtk_container_add (GTK_CONTAINER (button), image);
+  gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  g_signal_connect_swapped (button, "clicked", G_CALLBACK (add_custom_paper), data);
+  
+  button = gtk_button_new ();
+  image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (image);
+  gtk_container_add (GTK_CONTAINER (button), image);
+  gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  g_signal_connect_swapped (button, "clicked", G_CALLBACK (remove_custom_paper), data);
+
+  user_units = get_default_user_units ();
+  
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+  gtk_widget_show (vbox);
+  
+  table = gtk_table_new (2, 2, FALSE);
+  
+  label = gtk_label_new (_("Width:"));
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1, 0, 0, 0, 0);
+  
+  widget = new_unit_widget (data, user_units);
+  data->width_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+  
+  label = gtk_label_new (_("Height:"));
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2, 0, 0, 0, 0);
+  
+  widget = new_unit_widget (data, user_units);
+  data->height_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 1, 2, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+
+  frame = wrap_in_frame (_("Paper Size"), table);
+  gtk_widget_show (table);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+  
+
+  table = gtk_table_new (3, 5, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 0);
+
+  widget = new_unit_widget (data, user_units);
+  data->top_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+
+  label = gtk_label_new (_("top"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   1, 2, 1, 2, 0, GTK_FILL|GTK_EXPAND, 0, 0);
+  gtk_misc_set_alignment (GTK_MISC (label),
+                         0.5, 0.0);
+  gtk_widget_show (label);
+  
+  widget = new_unit_widget (data, user_units);
+  data->bottom_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 2, 3, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+
+  label = gtk_label_new (_("bottom"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   1, 2, 3, 4, 0, GTK_FILL|GTK_EXPAND, 0, 0);
+  gtk_misc_set_alignment (GTK_MISC (label),
+                         0.5, 0.0);
+  gtk_widget_show (label);
+
+  widget = new_unit_widget (data, user_units);
+  data->left_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   0, 1, 1, 2, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+
+  label = gtk_label_new (_("left"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 2, 3, 0, GTK_FILL|GTK_EXPAND, 0, 0);
+  gtk_misc_set_alignment (GTK_MISC (label),
+                         0.5, 0.0);
+  gtk_widget_show (label);
+  
+  widget = new_unit_widget (data, user_units);
+  data->right_widget = widget;
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   2, 3, 1, 2, 0, 0, 0, 0);
+  gtk_widget_show (widget);
+
+  label = gtk_label_new (_("right"));
+  gtk_table_attach (GTK_TABLE (table), label,
+                   2, 3, 2, 3, 0, GTK_FILL|GTK_EXPAND, 0, 0);
+  gtk_misc_set_alignment (GTK_MISC (label),
+                         0.5, 0.0);
+  gtk_widget_show (label);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_table_attach (GTK_TABLE (table), hbox,
+                   0, 3, 4, 5, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+  gtk_widget_show (hbox);
+  gtk_table_set_row_spacing (GTK_TABLE (table), 3, 8);
+  
+  combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (dialog->priv->printer_list));
+  data->printer_combo = combo;
+
+  printer_tag1 =
+    g_signal_connect_swapped (dialog->priv->printer_list, "row_inserted",
+                             G_CALLBACK (update_combo_sensitivity_from_printers), data);
+  printer_tag2 =
+    g_signal_connect_swapped (dialog->priv->printer_list, "row_deleted",
+                             G_CALLBACK (update_combo_sensitivity_from_printers), data);
+  update_combo_sensitivity_from_printers (data);
+  
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
+  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
+                                     custom_paper_printer_data_func,
+                                     NULL, NULL);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+  gtk_widget_show (combo);
+
+  g_signal_connect_swapped (combo, "changed",
+                           G_CALLBACK (margins_from_printer_changed), data);
+  
+  frame = wrap_in_frame (_("Paper Margins"), table);
+  gtk_widget_show (table);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+
+  update_custom_widgets_from_list (data);
+
+  /* If no custom sizes, add one */
+  if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->custom_paper_list),
+                                     &iter))
+    {
+      /* Need to realize treeview so we can start the rename */
+      gtk_widget_realize (treeview);
+      add_custom_paper (data);
+    }
+  
+  gtk_dialog_run (GTK_DIALOG (custom_dialog));
+  gtk_widget_destroy (custom_dialog);
+
+  save_custom_papers (dialog->priv->custom_paper_list);
+
+  g_signal_handler_disconnect (dialog->priv->printer_list, printer_tag1);
+  g_signal_handler_disconnect (dialog->priv->printer_list, printer_tag2);
+  
+}
+
+
+#define __GTK_PAGE_SETUP_UNIX_DIALOG_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkpagesetupunixdialog.h b/gtk/gtkpagesetupunixdialog.h
new file mode 100644 (file)
index 0000000..efd6841
--- /dev/null
@@ -0,0 +1,73 @@
+/* GtkPageSetupUnixDialog 
+ * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PAGE_SETUP_UNIX_DIALOG_H__
+#define __GTK_PAGE_SETUP_UNIX_DIALOG_H__
+
+#include "gtkdialog.h"
+#include "gtkpagesetup.h"
+#include "gtkprintsettings.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PAGE_SETUP_UNIX_DIALOG                  (gtk_page_setup_unix_dialog_get_type ())
+#define GTK_PAGE_SETUP_UNIX_DIALOG(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG, GtkPageSetupUnixDialog))
+#define GTK_PAGE_SETUP_UNIX_DIALOG_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG, GtkPageSetupUnixDialogClass))
+#define GTK_IS_PAGE_SETUP_UNIX_DIALOG(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG))
+#define GTK_IS_PAGE_SETUP_UNIX_DIALOG_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG))
+#define GTK_PAGE_SETUP_UNIX_DIALOG_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG, GtkPageSetupUnixDialogClass))
+
+
+typedef struct _GtkPageSetupUnixDialog         GtkPageSetupUnixDialog;
+typedef struct _GtkPageSetupUnixDialogClass    GtkPageSetupUnixDialogClass;
+typedef struct GtkPageSetupUnixDialogPrivate   GtkPageSetupUnixDialogPrivate;
+
+struct _GtkPageSetupUnixDialog
+{
+  GtkDialog parent_instance;
+
+  GtkPageSetupUnixDialogPrivate *priv;
+};
+
+struct _GtkPageSetupUnixDialogClass
+{
+  GtkDialogClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType            gtk_page_setup_unix_dialog_get_type           (void) G_GNUC_CONST;
+GtkWidget *       gtk_page_setup_unix_dialog_new                (const gchar            *title,
+                                                                GtkWindow              *parent);
+void              gtk_page_setup_unix_dialog_set_page_setup     (GtkPageSetupUnixDialog *dialog,
+                                                                GtkPageSetup           *page_setup);
+GtkPageSetup *    gtk_page_setup_unix_dialog_get_page_setup     (GtkPageSetupUnixDialog *dialog);
+void              gtk_page_setup_unix_dialog_set_print_settings (GtkPageSetupUnixDialog *dialog,
+                                                                GtkPrintSettings       *print_settings);
+GtkPrintSettings *gtk_page_setup_unix_dialog_get_print_settings (GtkPageSetupUnixDialog *dialog);
+
+G_END_DECLS
+
+#endif /* __GTK_PAGE_SETUP_UNIX_DIALOG_H__ */
diff --git a/gtk/gtkpapersize.c b/gtk/gtkpapersize.c
new file mode 100644 (file)
index 0000000..7dfeb90
--- /dev/null
@@ -0,0 +1,551 @@
+/* GTK - The GIMP Toolkit
+ * gtkpapersize.c: Paper Size
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
+#include <langinfo.h>
+#endif
+
+#include "gtkpapersize.h"
+#include "gtkalias.h"
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+#include "paper_names_offsets.c"
+
+struct _GtkPaperSize
+{
+  const PaperInfo *info;
+
+  /* If these are not set we fall back to info */
+  char *name;
+  char *display_name;
+  char *ppd_name;
+  
+  double width, height; /* Stored in mm */
+  gboolean is_custom;
+};
+
+GType
+gtk_paper_size_get_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("GtkPaperSize",
+                                            (GBoxedCopyFunc)gtk_paper_size_copy,
+                                            (GBoxedFreeFunc)gtk_paper_size_free);
+  return our_type;
+}
+
+static PaperInfo *
+lookup_paper_info (const char *name)
+{
+  int lower = 0;
+  int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
+  int mid;
+  int cmp;
+
+  do 
+    {
+       mid = (lower + upper) / 2;
+       cmp = strcmp (name, paper_names + standard_names_offsets[mid].name);
+       if (cmp < 0)
+         upper = mid - 1;
+       else if (cmp > 0)
+         lower = mid + 1;
+       else
+        return &standard_names_offsets[mid];
+    }
+  while (lower <= upper);
+
+  return NULL;
+}
+
+static double
+to_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len * MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len * (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static double
+from_mm (double len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len / MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len / (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static gboolean
+parse_media_size (const char *size,
+                 double *width_mm, double *height_mm)
+{
+  const char *p;
+  char *e;
+  double short_dim, long_dim;
+
+  p = size;
+  
+  short_dim = g_ascii_strtod (p, &e);
+
+  if (p == e || *e != 'x')
+    return FALSE;
+
+  p = e + 1; /* Skip x */
+
+  long_dim = g_ascii_strtod (p, &e);
+
+  if (p == e)
+    return FALSE;
+
+  p = e;
+
+  if (strcmp (p, "in") == 0)
+    {
+      short_dim = short_dim * MM_PER_INCH;
+      long_dim = long_dim * MM_PER_INCH;
+    }
+  else if (strcmp (p, "mm") != 0)
+    return FALSE;
+
+  if (width_mm)
+    *width_mm = short_dim;
+  if (height_mm)
+    *height_mm = long_dim;
+  
+  return TRUE;  
+}
+
+static gboolean
+parse_full_media_size_name (const char *full_name,
+                           char **name,
+                           double *width_mm, double *height_mm)
+{
+  const char *p;
+  const char *end_of_name;
+  
+  /* From the spec:
+   media-size-self-describing-name =
+        ( class-in "_" size-name "_" short-dim "x" long-dim "in" ) |
+        ( class-mm "_" size-name "_" short-dim "x" long-dim "mm" )
+   class-in = "custom" | "na" | "asme" | "roc" | "oe"
+   class-mm = "custom" | "iso" | "jis" | "jpn" | "prc" | "om"
+   size-name = ( lowalpha | digit ) *( lowalpha | digit | "-" )
+   short-dim = dim
+   long-dim = dim
+   dim = integer-part [fraction-part] | "0" fraction-part
+   integer-part = non-zero-digit *digit
+   fraction-part = "." *digit non-zero-digit
+   lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+              "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+              "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+   non-zero-digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+   digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+ */
+
+  p = strchr (full_name, '_');
+  if (p == NULL)
+    return FALSE;
+
+  p++; /* Skip _ */
+  
+  p = strchr (p, '_');
+  if (p == NULL)
+    return FALSE;
+
+  end_of_name = p;
+
+  p++; /* Skip _ */
+
+  if (!parse_media_size (p, width_mm, height_mm))
+    return FALSE;
+
+  if (name)
+    *name = g_strndup (full_name, end_of_name - full_name);
+  
+  return TRUE;  
+}
+
+static GtkPaperSize *
+gtk_paper_size_new_from_info (const PaperInfo *info)
+{
+  GtkPaperSize *size;
+  
+  size = g_new0 (GtkPaperSize, 1);
+  size->info = info;
+  size->width = info->width;
+  size->height = info->height;
+  
+  return size;
+}
+
+GtkPaperSize *
+gtk_paper_size_new (const char *name)
+{
+  GtkPaperSize *size;
+  char *short_name;
+  double width, height;
+  PaperInfo *info;
+
+  if (name == NULL)
+    name = gtk_paper_size_get_default ();
+  
+  if (parse_full_media_size_name (name, &short_name, &width, &height))
+    {
+      size = g_new0 (GtkPaperSize, 1);
+
+      size->width = width;
+      size->height = height;
+      size->name = short_name;
+      size->display_name = g_strdup (short_name);
+    }
+  else
+    {
+      info = lookup_paper_info (name);
+      if (info != NULL)
+       size = gtk_paper_size_new_from_info (info);
+      else
+       {
+         g_warning ("Unknown paper size %s\n", name);
+         size = g_new0 (GtkPaperSize, 1);
+         size->name = g_strdup (name);
+         size->display_name = g_strdup (name);
+         /* Default to A4 size */
+         size->width = 210;
+         size->height = 297;
+       }
+    }
+  
+  return size;
+}
+
+GtkPaperSize *
+gtk_paper_size_new_from_ppd (const char *ppd_name,
+                            const char *ppd_display_name,
+                            double width,
+                            double height)
+{
+  char *name;
+  const char *lookup_ppd_name;
+  char *freeme;
+  GtkPaperSize *size;
+  int i;
+
+  lookup_ppd_name = ppd_name;
+  
+  freeme = NULL;
+  /* Strip out Traverse suffix in matching. */
+  if (g_str_has_suffix (ppd_name, ".Transverse"))
+    {
+      lookup_ppd_name = freeme =
+       g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
+    }
+  
+  for (i = 0; i < G_N_ELEMENTS(standard_names_offsets); i++)
+    {
+      if (standard_names_offsets[i].ppd_name != -1 &&
+         strcmp (paper_names + standard_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
+       {
+         size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
+         goto out;
+       }
+    }
+  
+  for (i = 0; i < G_N_ELEMENTS(extra_ppd_names_offsets); i++)
+    {
+      if (strcmp (paper_names + extra_ppd_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
+       {
+         size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
+         goto out;
+       }
+    }
+
+  name = g_strdup_printf ("ppd_%s", ppd_name);
+  size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
+  g_free (name);
+
+ out:
+
+  if (size->info == NULL ||
+      size->info->ppd_name == -1 ||
+      strcmp (paper_names + size->info->ppd_name, ppd_name) != 0)
+    size->ppd_name = g_strdup (ppd_name);
+  
+  g_free (freeme);
+  
+  return size;
+}
+
+
+GtkPaperSize *
+gtk_paper_size_new_custom (const char *name, 
+                          const char *display_name,
+                          double      width, 
+                          double      height, 
+                          GtkUnit     unit)
+{
+  GtkPaperSize *size;
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (unit != GTK_UNIT_PIXEL, NULL);
+
+  size = g_new0 (GtkPaperSize, 1);
+  
+  size->name = g_strdup (name);
+  size->display_name = g_strdup (display_name);
+  size->is_custom = TRUE;
+  
+  size->width = to_mm (width, unit);
+  size->height = to_mm (height, unit);
+  
+  return size;
+}
+
+GtkPaperSize *
+gtk_paper_size_copy (GtkPaperSize *other)
+{
+  GtkPaperSize *size;
+
+  size = g_new0 (GtkPaperSize, 1);
+
+  size->info = other->info;
+  if (other->name)
+    size->name = g_strdup (other->name);
+  if (other->display_name)
+    size->display_name = g_strdup (other->display_name);
+  if (other->ppd_name)
+    size->ppd_name = g_strdup (other->ppd_name);
+  
+  size->width = other->width;
+  size->height = other->height;
+  size->is_custom = other->is_custom;
+
+  return size;
+}
+
+void
+gtk_paper_size_free (GtkPaperSize *size)
+{
+  g_free (size->name);
+  g_free (size->display_name);
+  g_free (size->ppd_name);
+  g_free (size);
+}
+
+gboolean
+gtk_paper_size_is_equal (GtkPaperSize *size1,
+                        GtkPaperSize *size2)
+{
+  if (size1->info != NULL && size2->info != NULL)
+    return size1->info == size2->info;
+  
+  return strcmp (gtk_paper_size_get_name (size1),
+                gtk_paper_size_get_name (size2)) == 0;
+}
+G_CONST_RETURN char *
+gtk_paper_size_get_name (GtkPaperSize *size)
+{
+  if (size->name)
+    return size->name;
+  g_assert (size->info != NULL);
+  return paper_names + size->info->name;
+}
+
+G_CONST_RETURN char *
+gtk_paper_size_get_display_name (GtkPaperSize *size)
+{
+  if (size->display_name)
+    return size->display_name;
+  g_assert (size->info != NULL);
+  return gettext (paper_names + size->info->display_name);
+}
+
+G_CONST_RETURN char *
+gtk_paper_size_get_ppd_name (GtkPaperSize *size)
+{
+  if (size->ppd_name)
+    return size->ppd_name;
+  if (size->info)
+    return paper_names + size->info->ppd_name;
+  return NULL;
+}
+
+double
+gtk_paper_size_get_width (GtkPaperSize *size, GtkUnit unit)
+{
+  return from_mm (size->width, unit);
+}
+double
+gtk_paper_size_get_height (GtkPaperSize *size, GtkUnit unit)
+{
+  return from_mm (size->height, unit);
+}
+
+gboolean
+gtk_paper_size_is_custom (GtkPaperSize *size)
+{
+  return size->is_custom;
+}
+
+/* Only for custom sizes: */
+void
+gtk_paper_size_set_size (GtkPaperSize *size, double width, double height, GtkUnit unit)
+{
+  g_return_if_fail (size != NULL);
+  g_return_if_fail (size->is_custom);
+
+  size->width = to_mm (width, unit);
+  size->height = to_mm (height, unit);
+}
+
+#define NL_PAPER_GET(x)         \
+  ((union { char *string; unsigned int word; })nl_langinfo(x)).word
+
+G_CONST_RETURN char *
+gtk_paper_size_get_default (void)
+{
+  char *locale, *freeme = NULL;
+  const char *paper_size;
+
+#if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
+  {
+    int width = NL_PAPER_GET (_NL_PAPER_WIDTH);
+    int height = NL_PAPER_GET (_NL_PAPER_HEIGHT);
+    
+    if (width == 210 && height == 297)
+      return GTK_PAPER_NAME_A4;
+    
+    if (width == 216 && height == 279)
+      return GTK_PAPER_NAME_LETTER;
+  }
+#endif
+
+#ifdef G_OS_WIN32
+  freeme = locale = g_win32_getlocale ();
+#elif defined(LC_PAPER)
+  locale = setlocale(LC_PAPER, NULL);
+#else
+  locale = setlocale(LC_MESSAGES, NULL);
+#endif
+
+  if (!locale)
+    return GTK_PAPER_NAME_A4;
+
+  if (g_str_has_prefix (locale, "en_CA") ||
+      g_str_has_prefix (locale, "en_US") ||
+      g_str_has_prefix (locale, "es_PR") ||
+      g_str_has_prefix (locale, "es_US"))
+    paper_size = GTK_PAPER_NAME_LETTER;
+  else
+    paper_size = GTK_PAPER_NAME_A4;
+
+  g_free (freeme);
+  return paper_size;
+}
+
+/* These get the default margins used for the paper size. Its
+ * larger than most printers margins, so that it will be within
+ * the imageble area on any printer.
+ *
+ * I've taken the actual values used from the OSX page setup dialog.
+ * I'm not sure exactly where they got these values for, but might
+ * correspond to this (from ghostscript docs):
+ * 
+ * All DeskJets have 0.5 inches (1.27cm) of unprintable bottom margin,
+ * due to the mechanical arrangement used to grab the paper. Side margins
+ * are approximately 0.25 inches (0.64cm) for U.S. letter paper, and 0.15
+ * inches (0.38cm) for A4.
+ */
+
+double
+gtk_paper_size_get_default_top_margin (GtkPaperSize *size, GtkUnit unit)
+{
+  double margin;
+
+  margin = to_mm (0.25, GTK_UNIT_INCH);
+  return from_mm (margin, unit);
+}
+
+double
+gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size, GtkUnit unit)
+{
+  double margin;
+  const char *name;
+
+  margin = to_mm (0.25, GTK_UNIT_INCH);
+
+  name = gtk_paper_size_get_name (size);
+  if (strcmp (name, "na_letter") == 0 ||
+      strcmp (name, "na_legal") == 0 ||
+      strcmp (name, "iso_a4") == 0)
+    margin = to_mm (0.56, GTK_UNIT_INCH);
+  
+  return from_mm (margin, unit);
+}
+
+double
+gtk_paper_size_get_default_left_margin (GtkPaperSize *size, GtkUnit unit)
+{
+  double margin;
+
+  margin = to_mm (0.25, GTK_UNIT_INCH);
+  return from_mm (margin, unit);
+}
+
+double
+gtk_paper_size_get_default_right_margin (GtkPaperSize *size, GtkUnit unit)
+{
+  double margin;
+
+  margin = to_mm (0.25, GTK_UNIT_INCH);
+  return from_mm (margin, unit);
+}
+
+
+#define __GTK_PAPER_SIZE_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkpapersize.h b/gtk/gtkpapersize.h
new file mode 100644 (file)
index 0000000..094d2ae
--- /dev/null
@@ -0,0 +1,88 @@
+/* GTK - The GIMP Toolkit
+ * gtkpapersize.h: Paper Size
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PAPER_SIZE_H__
+#define __GTK_PAPER_SIZE_H__
+
+#include <glib-object.h>
+#include "gtkenums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPaperSize GtkPaperSize;
+
+#define GTK_TYPE_PAPER_SIZE    (gtk_paper_size_get_type ())
+
+/* Common names, from PWG 5101.1-2002 PWG: Standard for Media Standardized Names */
+#define GTK_PAPER_NAME_A3 "iso_a3"
+#define GTK_PAPER_NAME_A4 "iso_a4"
+#define GTK_PAPER_NAME_A5 "iso_a5"
+#define GTK_PAPER_NAME_B5 "iso_b5"
+#define GTK_PAPER_NAME_LETTER "na_letter"
+#define GTK_PAPER_NAME_EXECUTIVE "na_executive"
+#define GTK_PAPER_NAME_LEGAL "na_legal"
+
+GType gtk_paper_size_get_type (void) G_GNUC_CONST;
+
+GtkPaperSize *gtk_paper_size_new          (const char   *name);
+GtkPaperSize *gtk_paper_size_new_from_ppd (const char   *ppd_name,
+                                          const char   *ppd_display_name,
+                                          double        width,
+                                          double        height);
+GtkPaperSize *gtk_paper_size_new_custom   (const char   *name,
+                                          const char   *display_name,
+                                          double        width,
+                                          double        height,
+                                          GtkUnit       unit);
+GtkPaperSize *gtk_paper_size_copy         (GtkPaperSize *other);
+void          gtk_paper_size_free         (GtkPaperSize *size);
+gboolean      gtk_paper_size_is_equal     (GtkPaperSize *size1,
+                                          GtkPaperSize *size2);
+
+
+/* The width is always the shortest side, measure in mm */
+G_CONST_RETURN char *   gtk_paper_size_get_name         (GtkPaperSize *size);
+G_CONST_RETURN char *   gtk_paper_size_get_display_name (GtkPaperSize *size);
+G_CONST_RETURN char *   gtk_paper_size_get_ppd_name     (GtkPaperSize *size);
+
+double   gtk_paper_size_get_width        (GtkPaperSize *size, GtkUnit unit);
+double   gtk_paper_size_get_height       (GtkPaperSize *size, GtkUnit unit);
+gboolean gtk_paper_size_is_custom        (GtkPaperSize *size);
+
+/* Only for custom sizes: */
+void gtk_paper_size_set_size             (GtkPaperSize *size, 
+                                          double        width, 
+                                          double        height, 
+                                          GtkUnit       unit);
+
+double gtk_paper_size_get_default_top_margin    (GtkPaperSize *size,
+                                                GtkUnit       unit);
+double gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size,
+                                                GtkUnit       unit);
+double gtk_paper_size_get_default_left_margin   (GtkPaperSize *size,
+                                                GtkUnit       unit);
+double gtk_paper_size_get_default_right_margin  (GtkPaperSize *size,
+                                                GtkUnit       unit);
+
+G_CONST_RETURN char * gtk_paper_size_get_default (void);
+
+G_END_DECLS
+
+#endif /* __GTK_PAPER_SIZE_H__ */
diff --git a/gtk/gtkprint-win32.c b/gtk/gtkprint-win32.c
new file mode 100644 (file)
index 0000000..69b508a
--- /dev/null
@@ -0,0 +1,111 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation.c: Print Operation
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MSC_VER
+#define _WIN32_WINNT 0x0500
+#define WINVER _WIN32_WINNT
+#endif
+
+#include "config.h"
+#include "gtkprint-win32.h"
+#include "gtkalias.h"
+
+void
+gtk_print_win32_devnames_free (GtkPrintWin32Devnames *devnames)
+{
+  g_free (devnames->driver);
+  g_free (devnames->device);
+  g_free (devnames->output);
+  g_free (devnames);
+}
+
+GtkPrintWin32Devnames *
+gtk_print_win32_devnames_from_win32 (HGLOBAL global)
+{
+  LPDEVNAMES win = GlobalLock (global);
+  gunichar2 *data = (gunichar2 *)win;
+  GtkPrintWin32Devnames *devnames = g_new (GtkPrintWin32Devnames, 1);
+  
+  devnames->driver = g_utf16_to_utf8 (data + win->wDriverOffset, 
+                                     -1, NULL, NULL, NULL);
+  devnames->device = g_utf16_to_utf8 (data + win->wDeviceOffset, 
+                                     -1, NULL, NULL, NULL);
+  devnames->output = g_utf16_to_utf8 (data + win->wOutputOffset, 
+                                     -1, NULL, NULL, NULL);
+  devnames->flags = win->wDefault;
+  
+  GlobalUnlock (global);
+
+  return devnames;
+}
+
+HGLOBAL 
+gtk_print_win32_devnames_to_win32 (const GtkPrintWin32Devnames *devnames)
+{
+  HGLOBAL global;
+  LPDEVNAMES windevnames;
+  gunichar2 *data;
+  gunichar2 *driver, *device, *output;
+  glong driver_len, device_len, output_len;
+  int i;
+
+  driver = g_utf8_to_utf16 (devnames->driver, -1, NULL, &driver_len, NULL);
+  device = g_utf8_to_utf16 (devnames->device, -1, NULL, &device_len, NULL);
+  output = g_utf8_to_utf16 (devnames->output, -1, NULL, &output_len, NULL);
+
+  global = GlobalAlloc (GMEM_MOVEABLE, 
+                       sizeof (DEVNAMES) + 
+                       (driver_len + 1) * 2 + 
+                       (device_len + 1) * 2 +
+                       (output_len + 1) * 2);
+
+  windevnames = GlobalLock (global);
+  data = (gunichar2 *)windevnames;
+  i = sizeof(DEVNAMES) / sizeof (gunichar2);
+
+  windevnames->wDriverOffset = i;
+  memcpy (data + i, driver, (driver_len + 1) * sizeof (gunichar2));
+  i += driver_len + 1;
+  windevnames->wDeviceOffset = i;
+  memcpy (data + i, device, (device_len + 1) * sizeof (gunichar2));
+  i += device_len + 1;
+  windevnames->wOutputOffset = i;
+  memcpy (data + i, output, (output_len + 1) * sizeof (gunichar2));
+  i += output_len + 1;
+  windevnames->wDefault = devnames->flags;
+  GlobalUnlock (global);
+
+  g_free (driver);
+  g_free (device);
+  g_free (output);
+
+  return global;
+}
+
+HGLOBAL 
+gtk_print_win32_devnames_from_printer_name (const char *printer)
+{
+  const GtkPrintWin32Devnames devnames = { "", (char *)printer, "", 0 };
+  return gtk_print_win32_devnames_to_win32 (&devnames);
+}
+
+
+#define __GTK_PRINT_WIN32_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprint-win32.h b/gtk/gtkprint-win32.h
new file mode 100644 (file)
index 0000000..6438349
--- /dev/null
@@ -0,0 +1,60 @@
+/* GTK - The GIMP Toolkit
+ * gtkprint-win32.h: Win32 Print utils
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_WIN32_H__
+#define __GTK_PRINT_WIN32_H__
+
+#include "win32/gdkwin32.h"
+
+G_BEGIN_DECLS
+
+#ifndef START_PAGE_GENERAL
+#define START_PAGE_GENERAL 0xffffffff
+#endif
+
+#ifndef PD_RESULT_CANCEL
+#define PD_RESULT_CANCEL  0
+#define PD_RESULT_PRINT  1
+#define PD_RESULT_APPLY  2
+#endif
+
+#ifndef PD_NOCURRENTPAGE
+#define PD_NOCURRENTPAGE  0x00800000
+#endif
+
+#ifndef PD_CURRENTPAGE
+#define PD_CURRENTPAGE  0x00400000
+#endif
+
+typedef struct {
+  char *driver;
+  char *device;
+  char *output;
+  int flags;
+} GtkPrintWin32Devnames;
+
+void gtk_print_win32_devnames_free (GtkPrintWin32Devnames *devnames);
+GtkPrintWin32Devnames *gtk_print_win32_devnames_from_win32 (HGLOBAL global);
+HGLOBAL gtk_print_win32_devnames_to_win32 (const GtkPrintWin32Devnames *devnames);
+HGLOBAL gtk_print_win32_devnames_from_printer_name (const char *printer);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_WIN32_H__ */
diff --git a/gtk/gtkprintbackend.c b/gtk/gtkprintbackend.c
new file mode 100644 (file)
index 0000000..32e6596
--- /dev/null
@@ -0,0 +1,379 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackend.h: Abstract printer backend interfaces
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include <gmodule.h>
+
+#include "gtkintl.h"
+#include "gtkmodules.h"
+#include "gtkprivate.h"
+#include "gtkprintbackend.h"
+#include "gtkalias.h"
+
+static void gtk_print_backend_base_init (gpointer g_class);
+
+GQuark
+gtk_print_backend_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (quark == 0)
+    quark = g_quark_from_static_string ("gtk-print-backend-error-quark");
+  return quark;
+}
+
+/*****************************************
+ *     GtkPrintBackendModule modules     *
+ *****************************************/
+
+typedef struct _GtkPrintBackendModule GtkPrintBackendModule;
+typedef struct _GtkPrintBackendModuleClass GtkPrintBackendModuleClass;
+
+struct _GtkPrintBackendModule
+{
+  GTypeModule parent_instance;
+  
+  GModule *library;
+
+  void             (*init)     (GTypeModule    *module);
+  void             (*exit)     (void);
+  GtkPrintBackend* (*create)   (void);
+
+  gchar *path;
+};
+
+struct _GtkPrintBackendModuleClass
+{
+  GTypeModuleClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkPrintBackendModule, _gtk_print_backend_module, G_TYPE_TYPE_MODULE);
+#define GTK_TYPE_PRINT_BACKEND_MODULE      (_gtk_print_backend_module_get_type ())
+#define GTK_PRINT_BACKEND_MODULE(module)   (G_TYPE_CHECK_INSTANCE_CAST ((module), GTK_TYPE_PRINT_BACKEND_MODULE, GtkPrintBackendModule))
+
+static GSList *loaded_backends;
+
+static gboolean
+gtk_print_backend_module_load (GTypeModule *module)
+{
+  GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module); 
+  gpointer initp, exitp, createp;
+  pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+  if (!pb_module->library)
+    {
+      g_warning (g_module_error());
+      return FALSE;
+    }
+  
+  /* extract symbols from the lib */
+  if (!g_module_symbol (pb_module->library, "pb_module_init",
+                       &initp) ||
+      !g_module_symbol (pb_module->library, "pb_module_exit", 
+                       &exitp) ||
+      !g_module_symbol (pb_module->library, "pb_module_create", 
+                       &createp))
+    {
+      g_warning (g_module_error());
+      g_module_close (pb_module->library);
+      
+      return FALSE;
+    }
+
+  pb_module->init = initp;
+  pb_module->exit = exitp;
+  pb_module->create = createp;
+
+  /* call the filesystems's init function to let it */
+  /* setup anything it needs to set up. */
+  pb_module->init (module);
+
+  return TRUE;
+}
+
+static void
+gtk_print_backend_module_unload (GTypeModule *module)
+{
+  GtkPrintBackendModule *pb_module = GTK_PRINT_BACKEND_MODULE (module);
+  
+  pb_module->exit();
+
+  g_module_close (pb_module->library);
+  pb_module->library = NULL;
+
+  pb_module->init = NULL;
+  pb_module->exit = NULL;
+  pb_module->create = NULL;
+}
+
+/* This only will ever be called if an error occurs during
+ * initialization
+ */
+static void
+gtk_print_backend_module_finalize (GObject *object)
+{
+  GtkPrintBackendModule *module = GTK_PRINT_BACKEND_MODULE (object);
+
+  g_free (module->path);
+
+  G_OBJECT_CLASS (_gtk_print_backend_module_parent_class)->finalize (object);
+}
+
+static void
+_gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
+{
+  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  
+  module_class->load = gtk_print_backend_module_load;
+  module_class->unload = gtk_print_backend_module_unload;
+
+  gobject_class->finalize = gtk_print_backend_module_finalize;
+}
+
+static void
+_gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
+{
+}
+
+static GtkPrintBackend *
+_gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
+{
+  GtkPrintBackend *pb;
+  
+  if (g_type_module_use (G_TYPE_MODULE (pb_module)))
+    {
+      pb = pb_module->create ();
+      g_type_module_unuse (G_TYPE_MODULE (pb_module));
+      return pb;
+    }
+  return NULL;
+}
+
+GtkPrintBackend *
+_gtk_print_backend_create (const char *backend_name)
+{
+  GSList *l;
+  char *module_path;
+  char *full_name;
+  GtkPrintBackendModule *pb_module;
+  GtkPrintBackend *pb;
+
+  /* TODO: make module loading code work */
+  for (l = loaded_backends; l != NULL; l = l->next)
+    {
+      pb_module = l->data;
+      
+      if (strcmp (G_TYPE_MODULE (pb_module)->name, backend_name) == 0)
+       return _gtk_print_backend_module_create (pb_module);
+    }
+
+  pb = NULL;
+  if (g_module_supported ())
+    {
+      full_name = g_strconcat ("printbackend-", backend_name, NULL);
+      module_path = _gtk_find_module (full_name, "printbackends");
+      g_free (full_name);
+
+      if (module_path)
+       {
+         pb_module = g_object_new (GTK_TYPE_PRINT_BACKEND_MODULE, NULL);
+
+         g_type_module_set_name (G_TYPE_MODULE (pb_module), backend_name);
+         pb_module->path = g_strdup (module_path);
+
+         loaded_backends = g_slist_prepend (loaded_backends,
+                                            pb_module);
+
+         pb = _gtk_print_backend_module_create (pb_module);
+       }
+      
+      g_free (module_path);
+    }
+
+  return pb;
+
+  return NULL;
+}
+
+static void
+gtk_print_backend_initialize (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      gtk_settings_install_property (g_param_spec_string ("gtk-print-backends",
+                                                         P_("Default print backend"),
+                                                         P_("List of the GtkPrintBackend backends to use by default"),
+                                                         GTK_PRINT_BACKENDS,
+                                                         GTK_PARAM_READWRITE));
+
+      initialized = TRUE;
+    }
+}
+
+
+
+GList *
+gtk_print_backend_load_modules ()
+{
+  GList *result;
+  GtkPrintBackend *backend;
+  gchar *setting;
+  gchar **backends;
+  gint i;
+  GtkSettings *settings;
+
+  result = NULL;
+
+  gtk_print_backend_initialize ();
+  
+  settings = gtk_settings_get_default ();
+
+  g_object_get (settings, "gtk-print-backends", &setting, NULL);
+
+  backends = g_strsplit (setting, ",", -1);
+
+  for (i = 0; backends[i]; i++)
+    {
+      g_strchug (backends[i]);
+      g_strchomp (backends[i]);
+      backend = _gtk_print_backend_create (backends[i]);
+      
+      if (backend)
+        result = g_list_append (result, backend);
+    }
+
+  g_strfreev (backends);
+  g_free (setting);
+
+  return result;
+}
+
+/*****************************************
+ *             GtkPrintBackend           *
+ *****************************************/
+GType
+gtk_print_backend_get_type (void)
+{
+  static GType print_backend_type = 0;
+
+  if (!print_backend_type)
+    {
+      static const GTypeInfo print_backend_info =
+      {
+       sizeof (GtkPrintBackendIface),  /* class_size */
+       gtk_print_backend_base_init,    /* base_init */
+       NULL,                         /* base_finalize */
+      };
+
+      print_backend_type = g_type_register_static (G_TYPE_INTERFACE,
+                                                "GtkPrintBackend",
+                                                &print_backend_info, 0);
+
+      g_type_interface_add_prerequisite (print_backend_type, G_TYPE_OBJECT);
+    }
+
+  return print_backend_type;
+}
+
+static void
+gtk_print_backend_base_init (gpointer g_class)
+{
+  static gboolean initialized = FALSE;
+  
+  if (!initialized)
+    {
+      GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
+
+      g_signal_new ("printer-list-changed",
+                   iface_type,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (GtkPrintBackendIface, printer_list_changed),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__VOID,
+                   G_TYPE_NONE, 0);
+      g_signal_new ("printer-added",
+                   iface_type,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (GtkPrintBackendIface, printer_added),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__OBJECT,
+                   G_TYPE_NONE, 1, G_TYPE_OBJECT);
+      g_signal_new ("printer-removed",
+                   iface_type,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (GtkPrintBackendIface, printer_removed),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__OBJECT,
+                   G_TYPE_NONE, 1, G_TYPE_OBJECT);
+      g_signal_new ("printer-status-changed",
+                   iface_type,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (GtkPrintBackendIface, printer_status_changed),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__OBJECT,
+                   G_TYPE_NONE, 1, G_TYPE_OBJECT);
+
+      initialized = TRUE;
+    }
+}
+
+GList *
+gtk_print_backend_get_printer_list (GtkPrintBackend *print_backend)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), NULL);
+
+  return GTK_PRINT_BACKEND_GET_IFACE (print_backend)->get_printer_list (print_backend);
+
+}
+
+GtkPrinter *
+gtk_print_backend_find_printer (GtkPrintBackend *print_backend,
+                                const gchar *printer_name)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), NULL);
+
+  return GTK_PRINT_BACKEND_GET_IFACE (print_backend)->find_printer (print_backend, printer_name);
+
+}
+
+void
+gtk_print_backend_print_stream (GtkPrintBackend *print_backend,
+                                GtkPrintJob *job,
+                                gint data_fd,
+                                GtkPrintJobCompleteFunc callback,
+                                gpointer user_data,
+                               GDestroyNotify dnotify)
+{
+  g_return_if_fail (GTK_IS_PRINT_BACKEND (print_backend));
+
+  GTK_PRINT_BACKEND_GET_IFACE (print_backend)->print_stream (print_backend,
+                                                            job,
+                                                            data_fd,
+                                                            callback,
+                                                            user_data,
+                                                            dnotify);
+}
+
+#define __GTK_PRINT_BACKEND_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintbackend.h b/gtk/gtkprintbackend.h
new file mode 100644 (file)
index 0000000..940ab49
--- /dev/null
@@ -0,0 +1,152 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackend.h: Abstract printer backend interfaces
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_BACKEND_H__
+#define __GTK_PRINT_BACKEND_H__
+
+/* This is a "semi-private" header; it is meant only for
+ * alternate GtkPrintDialog backend modules; no stability guarantees 
+ * are made at this point
+ */
+#ifndef GTK_PRINT_BACKEND_ENABLE_UNSUPPORTED
+#error "GtkPrintBackend is not supported API for general use"
+#endif
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include "gtkprinter-private.h"
+#include "gtkprintsettings.h"
+#include "gtkprinteroption.h"
+#include "gtkprintjob.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPrintBackendIface  GtkPrintBackendIface;
+
+#define GTK_PRINT_BACKEND_ERROR (gtk_print_backend_error_quark ())
+
+typedef enum
+{
+  /* TODO: add specific errors */
+  GTK_PRINT_BACKEND_ERROR_GENERIC
+} GtkPrintBackendError;
+
+GQuark     gtk_print_backend_error_quark      (void);
+
+#define GTK_TYPE_PRINT_BACKEND             (gtk_print_backend_get_type ())
+#define GTK_PRINT_BACKEND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND, GtkPrintBackend))
+#define GTK_IS_PRINT_BACKEND(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND))
+#define GTK_PRINT_BACKEND_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendIface))
+
+struct _GtkPrintBackendIface
+{
+  GTypeInterface base_iface;
+
+  /* Global backend methods: */
+  GList      * (*get_printer_list) (GtkPrintBackend *printer_backend);
+
+  GtkPrinter * (*find_printer) (GtkPrintBackend *print_backend,
+                                const gchar *printer_name);
+  void         (*print_stream) (GtkPrintBackend *print_backend,
+                                GtkPrintJob *job,
+                               gint data_fd,
+                               GtkPrintJobCompleteFunc callback,
+                               gpointer user_data,
+                               GDestroyNotify dnotify);
+
+  /* Printer methods: */
+  void                  (*printer_request_details)           (GtkPrinter *printer);
+  cairo_surface_t *     (*printer_create_cairo_surface)      (GtkPrinter *printer,
+                                                             gdouble height,
+                                                             gdouble width,
+                                                             gint cache_fd);
+  GtkPrinterOptionSet * (*printer_get_options)               (GtkPrinter *printer,
+                                                             GtkPrintSettings *settings,
+                                                             GtkPageSetup *page_setup);
+  gboolean              (*printer_mark_conflicts)            (GtkPrinter *printer,
+                                                             GtkPrinterOptionSet *options);
+  void                  (*printer_get_settings_from_options) (GtkPrinter *printer,
+                                                             GtkPrinterOptionSet *options,
+                                                             GtkPrintSettings *settings);
+  void                  (*printer_prepare_for_print)         (GtkPrinter *printer,
+                                                             GtkPrintJob *print_job,
+                                                             GtkPrintSettings *settings,
+                                                             GtkPageSetup *page_setup);
+  GList  *              (*printer_list_papers)               (GtkPrinter *printer);
+  void                  (*printer_get_hard_margins)          (GtkPrinter *printer,
+                                                             double     *top,
+                                                             double     *bottom,
+                                                             double     *left,
+                                                             double     *right);
+
+  /* Signals 
+   */
+  void (*printer_list_changed)   (void);
+  void (*printer_added)          (GtkPrinter *printer);
+  void (*printer_removed)        (GtkPrinter *printer);
+  void (*printer_status_changed) (GtkPrinter *printer);
+};
+
+GType   gtk_print_backend_get_type       (void) G_GNUC_CONST;
+
+GList      *gtk_print_backend_get_printer_list (GtkPrintBackend         *print_backend);
+GtkPrinter *gtk_print_backend_find_printer     (GtkPrintBackend         *print_backend,
+                                               const gchar             *printer_name);
+void        gtk_print_backend_print_stream     (GtkPrintBackend         *print_backend,
+                                               GtkPrintJob             *job,
+                                               gint                     data_fd,
+                                               GtkPrintJobCompleteFunc  callback,
+                                               gpointer                 user_data,
+                                               GDestroyNotify           dnotify);
+GList *     gtk_print_backend_load_modules     (void);
+
+
+/* Backend-only functions for GtkPrinter */
+
+GtkPrinter *gtk_printer_new               (const char      *name,
+                                          GtkPrintBackend *backend,
+                                          gboolean         is_virtual);
+gboolean    gtk_printer_is_new            (GtkPrinter      *printer);
+void        gtk_printer_set_is_new        (GtkPrinter      *printer,
+                                          gboolean         val);
+void        gtk_printer_set_is_active     (GtkPrinter      *printer,
+                                          gboolean         val);
+void        gtk_printer_set_has_details   (GtkPrinter      *printer,
+                                          gboolean         val);
+void        gtk_printer_set_is_default    (GtkPrinter      *printer,
+                                          gboolean         val);
+void        gtk_printer_set_icon_name     (GtkPrinter      *printer,
+                                          const char      *icon);
+gboolean    gtk_printer_set_job_count     (GtkPrinter      *printer,
+                                          int              count);
+gboolean    gtk_printer_set_location      (GtkPrinter      *printer,
+                                          const char      *location);
+gboolean    gtk_printer_set_description   (GtkPrinter      *printer,
+                                          const char      *description);
+gboolean    gtk_printer_set_state_message (GtkPrinter      *printer,
+                                          const char      *message);
+void        gtk_printer_set_is_active     (GtkPrinter      *printer,
+                                          gboolean         active);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_BACKEND_H__ */
diff --git a/gtk/gtkprintcontext.c b/gtk/gtkprintcontext.c
new file mode 100644 (file)
index 0000000..8525ec8
--- /dev/null
@@ -0,0 +1,406 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintcontext.c: Print Context
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "gtkprintoperation-private.h"
+#include "gtkalias.h"
+
+typedef struct _GtkPrintContextClass GtkPrintContextClass;
+
+#define GTK_IS_PRINT_CONTEXT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_CONTEXT))
+#define GTK_PRINT_CONTEXT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
+#define GTK_PRINT_CONTEXT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+struct _GtkPrintContext
+{
+  GObject parent_instance;
+
+  GtkPrintOperation *op;
+  cairo_t *cr;
+  GtkPageSetup *page_setup;
+  PangoFontMap *fontmap;
+
+  gdouble pixels_per_unit_x;
+  gdouble pixels_per_unit_y;
+};
+
+struct _GtkPrintContextClass
+{
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
+
+static void
+gtk_print_context_finalize (GObject *object)
+{
+  GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
+
+  g_object_unref (context->fontmap);
+  if (context->page_setup)
+    g_object_unref (context->page_setup);
+
+  cairo_destroy (context->cr);
+
+  
+  G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
+}
+
+static void
+gtk_print_context_init (GtkPrintContext *context)
+{
+}
+
+static void
+gtk_print_context_class_init (GtkPrintContextClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->finalize = gtk_print_context_finalize;
+}
+
+
+GtkPrintContext *
+_gtk_print_context_new (GtkPrintOperation *op)
+{
+  GtkPrintContext *context;
+  
+  context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
+
+  context->op = op;
+  context->cr = cairo_create (op->priv->surface);
+
+  switch (op->priv->unit)
+    {
+    default:
+    case GTK_UNIT_PIXEL:
+      /* Do nothing, this is the cairo default unit */
+      context->pixels_per_unit_x = 1.0;
+      context->pixels_per_unit_y = 1.0;
+      break;
+    case GTK_UNIT_POINTS:
+      context->pixels_per_unit_x = op->priv->dpi_x / POINTS_PER_INCH;
+      context->pixels_per_unit_y = op->priv->dpi_y / POINTS_PER_INCH;
+      break;
+    case GTK_UNIT_INCH:
+      context->pixels_per_unit_x = op->priv->dpi_x;
+      context->pixels_per_unit_y = op->priv->dpi_y;
+      break;
+    case GTK_UNIT_MM:
+      context->pixels_per_unit_x = op->priv->dpi_x / MM_PER_INCH;
+      context->pixels_per_unit_y = op->priv->dpi_y / MM_PER_INCH;
+      break;
+    }
+  cairo_scale (context->cr,
+              context->pixels_per_unit_x,
+              context->pixels_per_unit_y);
+    
+  context->fontmap = pango_cairo_font_map_new ();
+  /* We use the unit-scaled resolution, as we still want fonts given in points to work */
+  pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (context->fontmap),
+                                      op->priv->dpi_y / context->pixels_per_unit_y);
+  
+  return context;
+}
+
+void
+_gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
+{
+  cairo_t *cr = context->cr;
+  cairo_matrix_t matrix;
+  GtkPaperSize *paper_size;
+  gdouble width, height;
+
+  paper_size = gtk_page_setup_get_paper_size (context->page_setup);
+
+  width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
+  width = width * context->op->priv->dpi_x / context->pixels_per_unit_x;
+  height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
+  height = height * context->op->priv->dpi_y / context->pixels_per_unit_y;
+  
+  switch (gtk_page_setup_get_orientation (context->page_setup))
+    {
+    default:
+    case GTK_PAGE_ORIENTATION_PORTRAIT:
+      break;
+    case GTK_PAGE_ORIENTATION_LANDSCAPE:
+      cairo_translate (cr, width, 0);
+      cairo_matrix_init (&matrix,
+                         0,  1,
+                        -1,  0,
+                         0,  0);
+      cairo_transform (cr, &matrix);
+      break;
+    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+      cairo_translate (cr, width, height);
+      cairo_matrix_init (&matrix,
+                        -1,  0,
+                         0, -1,
+                         0,  0);
+      cairo_transform (cr, &matrix);
+      break;
+    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+      cairo_translate (cr, 0, height);
+      cairo_matrix_init (&matrix,
+                        0, -1,
+                        1,  0,
+                        0,  0);
+      cairo_transform (cr, &matrix);
+      break;
+    }
+}
+
+void
+_gtk_print_context_translate_into_margin (GtkPrintContext *context)
+{
+  gdouble left, top;
+
+  g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
+
+  /* We do it this way to also handle GTK_UNIT_PIXELS */
+  
+  left = gtk_page_setup_get_left_margin (context->page_setup, GTK_UNIT_INCH);
+  top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
+
+  cairo_translate (context->cr,
+                  left * context->op->priv->dpi_x / context->pixels_per_unit_x,
+                  top * context->op->priv->dpi_y / context->pixels_per_unit_y);
+}
+
+void
+_gtk_print_context_set_page_setup (GtkPrintContext *context,
+                                  GtkPageSetup    *page_setup)
+{
+  g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
+  g_return_if_fail (page_setup == NULL ||
+                   GTK_IS_PAGE_SETUP (page_setup));
+  
+  g_object_ref (page_setup);
+
+  if (context->page_setup != NULL)
+    g_object_unref (context->page_setup);
+
+  context->page_setup = page_setup;
+}
+
+/**
+ * gtk_print_context_get_cairo:
+ * @context: a #GtkPrintContext
+ *
+ * Obtains the cairo context that is associated with the
+ * #GtkPrintContext.
+ *
+ * Return value: the cairo context of @context
+ *
+ * Since: 2.10
+ */
+cairo_t *
+gtk_print_context_get_cairo (GtkPrintContext *context)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
+
+  return context->cr;
+}
+
+/**
+ * gtk_print_context_get_page_setup:
+ * @context: a #GtkPrintContext
+ *
+ * Obtains the #GtkPageSetup that determines the page
+ * dimensions of the #GtkPrintContext.
+ *
+ * Return value: the page setup of @context
+ *
+ * Since: 2.10
+ */
+GtkPageSetup *
+gtk_print_context_get_page_setup (GtkPrintContext *context)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
+
+  return context->page_setup;
+}
+
+/**
+ * gtk_print_context_get_width:
+ * @context: a #GtkPrintContext
+ *
+ * Obtains the width of the #GtkPrintContext, in pixels.
+ *
+ * Return value: the width of @context
+ *
+ * Since: 2.10 
+ */
+gdouble
+gtk_print_context_get_width (GtkPrintContext *context)
+{
+  gdouble width;
+
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
+
+  if (context->op->priv->use_full_page)
+    width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
+  else
+    width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
+
+  /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
+  return width * context->op->priv->dpi_x / context->pixels_per_unit_x;
+}
+
+/**
+ * gtk_print_context_get_height:
+ * @context: a #GtkPrintContext
+ * 
+ * Obtains the width of the #GtkPrintContext, in pixels.
+ *
+ * Return value: the height of @context
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_context_get_height (GtkPrintContext *context)
+{
+  gdouble height;
+
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
+
+  if (context->op->priv->use_full_page)
+    height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
+  else
+    height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
+
+  /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
+  return height * context->op->priv->dpi_y / context->pixels_per_unit_y;
+}
+
+/**
+ * gtk_print_context_get_dpi_x:
+ * @context: a #GtkPrintContext
+ * 
+ * Obtains the horizontal resolution of the #GtkPrintContext,
+ * in dots per inch.
+ *
+ * Return value: the horizontal resolution of @context
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_context_get_dpi_x (GtkPrintContext *context)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
+
+  return context->op->priv->dpi_x;
+}
+
+/**
+ * gtk_print_context_get_dpi_y:
+ * @context: a #GtkPrintContext
+ * 
+ * Obtains the vertical resolution of the #GtkPrintContext,
+ * in dots per inch.
+ *
+ * Return value: the vertical resolution of @context
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_context_get_dpi_y (GtkPrintContext *context)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
+
+  return context->op->priv->dpi_y;
+}
+
+/**
+ * gtk_print_context_get_fontmap:
+ * @context: a #GtkPrintContext
+ *
+ * Returns a #PangoFontMap that is suitable for use 
+ * with the #GtkPrintContext.
+ *
+ * Return value: the font map of @context
+ *
+ * Since: 2.10
+ */
+PangoFontMap *
+gtk_print_context_get_fontmap (GtkPrintContext *context)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
+
+  return context->fontmap;
+}
+
+/**
+ * gtk_print_context_create_context:
+ * @context: a #GtkPrintContext 
+ *
+ * Creates a new #PangoContext that can be used with the
+ * #GtkPrintContext.
+ *
+ * Return value: a new Pango context for @context
+ * 
+ * Since: 2.10
+ */
+PangoContext *
+gtk_print_context_create_context (GtkPrintContext *context)
+{
+  PangoContext *pango_context;
+
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
+  
+  pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (context->fontmap));
+  
+  return pango_context;
+}
+
+/**
+ * gtk_print_context_create_layout:
+ * @context: a #GtkPrintContext
+ *
+ * Creates a new #PangoLayout that is suitable for use
+ * with the #GtkPrintContext.
+ * 
+ * Return value: a new Pango layout for @context
+ *
+ * Since: 2.10
+ */
+PangoLayout *
+gtk_print_context_create_layout (GtkPrintContext *context)
+{
+  PangoContext *pango_context;
+  PangoLayout *layout;
+
+  g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
+
+  pango_context = gtk_print_context_create_context (context);
+  layout = pango_layout_new (pango_context);
+
+  pango_cairo_update_context (context->cr, pango_context);
+  g_object_unref (pango_context);
+
+  return layout;
+}
+
+
+#define __GTK_PRINT_CONTEXT_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintcontext.h b/gtk/gtkprintcontext.h
new file mode 100644 (file)
index 0000000..30a66b9
--- /dev/null
@@ -0,0 +1,57 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintcontext.h: Print Context
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_CONTEXT_H__
+#define __GTK_PRINT_CONTEXT_H__
+
+#include <glib-object.h>
+#include <pango/pango-layout.h>
+#include "gtkenums.h"
+#include "gtkpagesetup.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPrintContext GtkPrintContext;
+
+#define GTK_TYPE_PRINT_CONTEXT    (gtk_print_context_get_type ())
+#define GTK_PRINT_CONTEXT(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContext))
+#define GTK_IS_PRINT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_CONTEXT))
+
+GType          gtk_print_context_get_type (void) G_GNUC_CONST;
+
+
+/* Rendering */
+cairo_t *     gtk_print_context_get_cairo      (GtkPrintContext *context);
+
+GtkPageSetup *gtk_print_context_get_page_setup (GtkPrintContext *context);
+gdouble       gtk_print_context_get_width      (GtkPrintContext *context);
+gdouble       gtk_print_context_get_height     (GtkPrintContext *context);
+gdouble       gtk_print_context_get_dpi_x      (GtkPrintContext *context);
+gdouble       gtk_print_context_get_dpi_y      (GtkPrintContext *context);
+
+/* Fonts */
+PangoFontMap *gtk_print_context_get_fontmap    (GtkPrintContext *context);
+PangoContext *gtk_print_context_create_context (GtkPrintContext *context);
+PangoLayout * gtk_print_context_create_layout  (GtkPrintContext *context);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_CONTEXT_H__ */
diff --git a/gtk/gtkprinter-private.h b/gtk/gtkprinter-private.h
new file mode 100644 (file)
index 0000000..49663c0
--- /dev/null
@@ -0,0 +1,64 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation.h: Print Operation
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINTER_PRIVATE_H__
+#define __GTK_PRINTER_PRIVATE_H__
+
+#include <glib.h>
+#include "gtkprinter.h"
+#include "gtkprintoperation.h"
+#include "gtkprinteroptionset.h"
+#include "gtkpagesetup.h"
+
+G_BEGIN_DECLS
+
+gboolean             _gtk_printer_has_details               (GtkPrinter          *printer);
+void                 _gtk_printer_request_details           (GtkPrinter          *printer);
+GtkPrinterOptionSet *_gtk_printer_get_options               (GtkPrinter          *printer,
+                                                            GtkPrintSettings *settings,
+                                                            GtkPageSetup        *page_setup);
+gboolean             _gtk_printer_mark_conflicts            (GtkPrinter          *printer,
+                                                            GtkPrinterOptionSet *options);
+void                 _gtk_printer_get_settings_from_options (GtkPrinter          *printer,
+                                                            GtkPrinterOptionSet *options,
+                                                            GtkPrintSettings    *settings);
+void                 _gtk_printer_prepare_for_print         (GtkPrinter          *printer,
+                                                            GtkPrintJob         *print_job,
+                                                            GtkPrintSettings    *settings,
+                                                            GtkPageSetup        *page_setup);
+cairo_surface_t *    _gtk_printer_create_cairo_surface      (GtkPrinter          *printer,
+                                                            gdouble              width,
+                                                            gdouble              height,
+                                                            gint                 cache_fd);
+GList  *             _gtk_printer_list_papers               (GtkPrinter          *printer);
+void                 _gtk_printer_get_hard_margins          (GtkPrinter          *printer,
+                                                            double              *top,
+                                                            double              *bottom,
+                                                            double              *left,
+                                                            double              *right);
+GHashTable *         _gtk_printer_get_custom_widgets        (GtkPrinter          *printer);
+
+
+/* GtkPrintJob private methods: */
+void gtk_print_job_set_status (GtkPrintJob   *job,
+                              GtkPrintStatus status);
+
+G_END_DECLS
+#endif /* __GTK_PRINT_OPERATION_PRIVATE_H__ */
diff --git a/gtk/gtkprinter.c b/gtk/gtkprinter.c
new file mode 100644 (file)
index 0000000..db166a6
--- /dev/null
@@ -0,0 +1,587 @@
+/* GtkPrinter
+ * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkprinter.h"
+#include "gtkprinter-private.h"
+#include "gtkprintbackend.h"
+#include "gtkprintjob.h"
+#include "gtkalias.h"
+
+#define GTK_PRINTER_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINTER, GtkPrinterPrivate))
+
+static void gtk_printer_finalize     (GObject *object);
+
+struct _GtkPrinterPrivate
+{
+  gchar *name;
+  gchar *location;
+  gchar *description;
+  gchar *icon_name;
+
+  guint is_active: 1;
+  guint is_new: 1;
+  guint is_virtual : 1;
+  guint is_default : 1;
+  guint has_details: 1;
+
+  gchar *state_message;  
+  gint job_count;
+
+  GtkPrintBackend *backend;
+};
+
+enum {
+  DETAILS_ACQUIRED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_NAME,
+  PROP_BACKEND,
+  PROP_IS_VIRTUAL,
+  PROP_STATE_MESSAGE,
+  PROP_LOCATION,
+  PROP_ICON_NAME,
+  PROP_JOB_COUNT
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gtk_printer_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec);
+static void gtk_printer_get_property (GObject      *object,
+                                     guint         prop_id,
+                                     GValue       *value,
+                                     GParamSpec   *pspec);
+
+G_DEFINE_TYPE (GtkPrinter, gtk_printer, G_TYPE_OBJECT);
+
+static int
+safe_strcmp (const char *a, const char *b)
+{
+  if (a == b)
+    return 0;
+  if (a == NULL)
+    return -1;
+  if (b == NULL)
+    return 1;
+  return strcmp (a, b);
+}
+
+static void
+gtk_printer_class_init (GtkPrinterClass *class)
+{
+  GObjectClass *object_class;
+  object_class = (GObjectClass *) class;
+
+  object_class->finalize = gtk_printer_finalize;
+
+  object_class->set_property = gtk_printer_set_property;
+  object_class->get_property = gtk_printer_get_property;
+
+  g_type_class_add_private (class, sizeof (GtkPrinterPrivate));
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_NAME,
+                                   g_param_spec_string ("name",
+                                                       P_("Name"),
+                                                       P_("Name of the printer"),
+                                                       NULL,
+                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_BACKEND,
+                                   g_param_spec_object ("backend",
+                                                       P_("Backend"),
+                                                       P_("Backend for the printer"),
+                                                       GTK_TYPE_PRINT_BACKEND,
+                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_IS_VIRTUAL,
+                                   g_param_spec_boolean ("is-virtual",
+                                                        P_("Is Virtual"),
+                                                        P_("False if this represents a real hardware printer"),
+                                                        FALSE,
+                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_STATE_MESSAGE,
+                                   g_param_spec_string ("state-message",
+                                                       P_("State Message"),
+                                                       P_("String giving the current state of the printer"),
+                                                       NULL,
+                                                       GTK_PARAM_READABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_LOCATION,
+                                   g_param_spec_string ("location",
+                                                       P_("Location"),
+                                                       P_("The location of the printer"),
+                                                       NULL,
+                                                       GTK_PARAM_READABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_ICON_NAME,
+                                   g_param_spec_string ("icon-name",
+                                                       P_("Icon Name"),
+                                                       P_("The icon name to use for the printer"),
+                                                       NULL,
+                                                       GTK_PARAM_READABLE));
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_JOB_COUNT,
+                                  g_param_spec_int ("job-count",
+                                                    P_("Job Count"),
+                                                    P_("Number of jobs queued in the printer"),
+                                                    0,
+                                                    G_MAXINT,
+                                                    0,
+                                                    GTK_PARAM_READABLE));
+
+
+  signals[DETAILS_ACQUIRED] =
+   g_signal_new ("details-acquired",
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrinterClass, details_acquired),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__BOOLEAN,
+                 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}
+
+static void
+gtk_printer_init (GtkPrinter *printer)
+{
+  printer->priv = GTK_PRINTER_GET_PRIVATE (printer); 
+
+  printer->priv->name = NULL;
+  printer->priv->location = NULL;
+  printer->priv->description = NULL;
+  printer->priv->icon_name = NULL;
+
+  printer->priv->is_active = TRUE;
+  printer->priv->is_new = TRUE;
+  printer->priv->has_details = FALSE;
+
+  printer->priv->state_message = NULL;  
+  printer->priv->job_count = 0;
+}
+
+static void
+gtk_printer_finalize (GObject *object)
+{
+  g_return_if_fail (object != NULL);
+
+  GtkPrinter *printer = GTK_PRINTER (object);
+
+  g_free (printer->priv->name);
+  g_free (printer->priv->location);
+  g_free (printer->priv->description);
+  g_free (printer->priv->state_message);
+  g_free (printer->priv->icon_name);
+
+  if (printer->priv->backend)
+    g_object_unref (printer->priv->backend);
+
+  if (G_OBJECT_CLASS (gtk_printer_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_printer_parent_class)->finalize (object);
+}
+
+static void
+gtk_printer_set_property (GObject         *object,
+                         guint            prop_id,
+                         const GValue    *value,
+                         GParamSpec      *pspec)
+{
+  GtkPrinter *printer = GTK_PRINTER (object);
+  
+  switch (prop_id)
+    {
+    case PROP_NAME:
+      printer->priv->name = g_value_dup_string (value);
+      break;
+    
+    case PROP_BACKEND:
+      printer->priv->backend = GTK_PRINT_BACKEND (g_value_dup_object (value));
+      break;
+
+    case PROP_IS_VIRTUAL:
+      printer->priv->is_virtual = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_printer_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  GtkPrinter *printer = GTK_PRINTER (object);
+
+  switch (prop_id)
+    {
+    case PROP_NAME:
+      if (printer->priv->name)
+       g_value_set_string (value, printer->priv->name);
+      else
+       g_value_set_string (value, "");
+      break;
+    case PROP_BACKEND:
+      g_value_set_object (value, printer->priv->backend);
+      break;
+    case PROP_STATE_MESSAGE:
+      if (printer->priv->state_message)
+       g_value_set_string (value, printer->priv->state_message);
+      else
+       g_value_set_string (value, "");
+      break;
+    case PROP_LOCATION:
+      if (printer->priv->location)
+       g_value_set_string (value, printer->priv->location);
+      else
+       g_value_set_string (value, "");
+      break;
+    case PROP_ICON_NAME:
+      if (printer->priv->icon_name)
+       g_value_set_string (value, printer->priv->icon_name);
+      else
+       g_value_set_string (value, "");
+      break;
+    case PROP_JOB_COUNT:
+      g_value_set_int (value, printer->priv->job_count);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+/**
+ * gtk_printer_new:
+ *
+ * Creates a new #GtkPrinter.
+ *
+ * Return value: a new #GtkPrinter
+ *
+ * Since: 2.8
+ **/
+GtkPrinter *
+gtk_printer_new (const char      *name,
+                GtkPrintBackend *backend,
+                gboolean         virtual)
+{
+  GObject *result;
+  
+  result = g_object_new (GTK_TYPE_PRINTER,
+                        "name", name,
+                        "backend", backend,
+                        "is-virtual", virtual,
+                         NULL);
+
+  return (GtkPrinter *) result;
+}
+
+GtkPrintBackend *
+gtk_printer_get_backend (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+  
+  return printer->priv->backend;
+}
+
+void
+gtk_printer_set_backend (GtkPrinter      *printer,
+                        GtkPrintBackend *backend)
+{
+  if (printer->priv->backend)
+    g_object_unref (printer->priv->backend);
+  
+  printer->priv->backend = g_object_ref (backend);
+}
+
+const gchar *
+gtk_printer_get_name (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+
+  return printer->priv->name;
+}
+
+const gchar *
+gtk_printer_get_description (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+  
+  return printer->priv->description;
+}
+
+gboolean
+gtk_printer_set_description (GtkPrinter *printer,
+                            const char *description)
+{
+  if (safe_strcmp (printer->priv->description, description) == 0)
+    return FALSE;
+
+  g_free (printer->priv->description);
+  printer->priv->description = g_strdup (description);
+  
+  return TRUE;
+}
+
+const gchar *
+gtk_printer_get_state_message (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+
+  return printer->priv->state_message;
+}
+
+gboolean
+gtk_printer_set_state_message (GtkPrinter *printer,
+                              const char *message)
+{
+  if (safe_strcmp (printer->priv->state_message, message) == 0)
+    return FALSE;
+
+  g_free (printer->priv->state_message);
+  printer->priv->state_message = g_strdup (message);
+  g_object_notify (G_OBJECT (printer), "state-message");
+
+  return TRUE;
+}
+
+const gchar *
+gtk_printer_get_location (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+
+  return printer->priv->location;
+}
+
+gboolean
+gtk_printer_set_location (GtkPrinter *printer,
+                         const char *location)
+{
+  if (safe_strcmp (printer->priv->location, location) == 0)
+    return FALSE;
+
+  g_free (printer->priv->location);
+  printer->priv->location = g_strdup (location);
+  g_object_notify (G_OBJECT (printer), "location");
+  
+  return TRUE;
+}
+
+const gchar * 
+gtk_printer_get_icon_name (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), NULL);
+
+  return printer->priv->icon_name;
+}
+
+void
+gtk_printer_set_icon_name (GtkPrinter *printer,
+                          const char *icon)
+{
+  g_free (printer->priv->icon_name);
+  printer->priv->icon_name = g_strdup (icon);
+  g_object_notify (G_OBJECT (printer), "icon-name");
+}
+
+gint 
+gtk_printer_get_job_count (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), 0);
+
+  return printer->priv->job_count;
+}
+
+gboolean
+gtk_printer_set_job_count (GtkPrinter *printer,
+                          int count)
+{
+  if (printer->priv->job_count == count)
+    return FALSE;
+
+  printer->priv->job_count = count;
+  
+  g_object_notify (G_OBJECT (printer), "job-count");
+  
+  return TRUE;
+}
+
+gboolean
+_gtk_printer_has_details (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), TRUE);
+  
+  return printer->priv->has_details;
+}
+
+void
+gtk_printer_set_has_details (GtkPrinter *printer,
+                            gboolean val)
+{
+  printer->priv->has_details = val;
+}
+
+gboolean
+gtk_printer_is_active (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), TRUE);
+  
+  return printer->priv->is_active;
+}
+
+void
+gtk_printer_set_is_active (GtkPrinter *printer,
+                          gboolean val)
+{
+  printer->priv->is_active = val;
+}
+
+
+gboolean
+gtk_printer_is_virtual (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), TRUE);
+  
+  return printer->priv->is_virtual;
+}
+
+gboolean
+gtk_printer_is_new (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), FALSE);
+  
+  return printer->priv->is_new;
+}
+
+void
+gtk_printer_set_is_new (GtkPrinter *printer,
+                       gboolean val)
+{
+  printer->priv->is_new = val;
+}
+
+
+gboolean
+gtk_printer_is_default (GtkPrinter *printer)
+{
+  g_return_val_if_fail (GTK_IS_PRINTER (printer), FALSE);
+  
+  return printer->priv->is_default;
+}
+
+void
+gtk_printer_set_is_default (GtkPrinter *printer,
+                           gboolean val)
+{
+  printer->priv->is_default = TRUE;
+}
+
+void
+_gtk_printer_request_details (GtkPrinter *printer)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+  return backend_iface->printer_request_details (printer);
+}
+
+GtkPrinterOptionSet *
+_gtk_printer_get_options (GtkPrinter *printer,
+                         GtkPrintSettings *settings,
+                         GtkPageSetup *page_setup)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+  return backend_iface->printer_get_options (printer, settings, page_setup);
+}
+
+gboolean
+_gtk_printer_mark_conflicts (GtkPrinter          *printer,
+                            GtkPrinterOptionSet *options)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+  return backend_iface->printer_mark_conflicts (printer, options);
+}
+  
+void
+_gtk_printer_get_settings_from_options (GtkPrinter          *printer,
+                                       GtkPrinterOptionSet *options,
+                                       GtkPrintSettings    *settings)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+  return backend_iface->printer_get_settings_from_options (printer, options, settings);
+}
+
+void
+_gtk_printer_prepare_for_print (GtkPrinter *printer,
+                               GtkPrintJob *print_job,
+                               GtkPrintSettings *settings,
+                               GtkPageSetup *page_setup)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+  return backend_iface->printer_prepare_for_print (printer, print_job, settings, page_setup);
+}
+
+cairo_surface_t *
+_gtk_printer_create_cairo_surface (GtkPrinter *printer,
+                                  gdouble width, 
+                                  gdouble height,
+                                  gint cache_fd)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+
+  return backend_iface->printer_create_cairo_surface (printer, width, height, cache_fd);
+}
+
+GList  *
+_gtk_printer_list_papers (GtkPrinter *printer)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+
+  return backend_iface->printer_list_papers (printer);
+}
+
+void
+_gtk_printer_get_hard_margins          (GtkPrinter          *printer,
+                                       double              *top,
+                                       double              *bottom,
+                                       double              *left,
+                                       double              *right)
+{
+  GtkPrintBackendIface *backend_iface = GTK_PRINT_BACKEND_GET_IFACE (printer->priv->backend);
+
+  backend_iface->printer_get_hard_margins (printer, top, bottom, left, right);
+}
+
+#define __GTK_PRINTER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprinter.h b/gtk/gtkprinter.h
new file mode 100644 (file)
index 0000000..285605f
--- /dev/null
@@ -0,0 +1,86 @@
+/* GtkPrinter 
+ * Copyright (C) 2006 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINTER_H__
+#define __GTK_PRINTER_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+#include <gtk/gtkprintsettings.h>
+#include <gtk/gtkpagesetup.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINTER                  (gtk_printer_get_type ())
+#define GTK_PRINTER(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINTER, GtkPrinter))
+#define GTK_PRINTER_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINTER, GtkPrinterClass))
+#define GTK_IS_PRINTER(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINTER))
+#define GTK_IS_PRINTER_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINTER))
+#define GTK_PRINTER_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINTER, GtkPrinterClass))
+
+typedef struct _GtkPrinter          GtkPrinter;
+typedef struct _GtkPrinterClass     GtkPrinterClass;
+typedef struct _GtkPrinterPrivate   GtkPrinterPrivate;
+typedef struct _GtkPrintBackend     GtkPrintBackend;
+typedef struct _GtkPrintJob         GtkPrintJob;
+
+struct _GtkPrintBackend;
+struct _GtkPrintJob;
+
+struct _GtkPrinter
+{
+  GObject parent_instance;
+
+  GtkPrinterPrivate *priv;
+};
+
+struct _GtkPrinterClass
+{
+  GObjectClass parent_class;
+
+  void (*details_acquired) (GtkPrinter *printer, gboolean success);
+  
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType                    gtk_printer_get_type          (void) G_GNUC_CONST;
+GtkPrinter              *gtk_printer_new               (const char      *name,
+                                                       GtkPrintBackend *backend,
+                                                       gboolean         virtual);
+GtkPrintBackend         *gtk_printer_get_backend       (GtkPrinter      *printer);
+const gchar             *gtk_printer_get_name          (GtkPrinter      *printer);
+const gchar             *gtk_printer_get_state_message (GtkPrinter      *printer);
+const gchar             *gtk_printer_get_description   (GtkPrinter      *printer);
+const gchar             *gtk_printer_get_location      (GtkPrinter      *printer);
+const gchar             *gtk_printer_get_icon_name     (GtkPrinter      *printer);
+gint                     gtk_printer_get_job_count     (GtkPrinter      *printer);
+gboolean                 gtk_printer_is_active         (GtkPrinter      *printer);
+gboolean                 gtk_printer_is_virtual        (GtkPrinter      *printer);
+gboolean                 gtk_printer_is_default        (GtkPrinter      *printer);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PRINTER_H__ */
diff --git a/gtk/gtkprinteroption.c b/gtk/gtkprinteroption.c
new file mode 100644 (file)
index 0000000..7aee382
--- /dev/null
@@ -0,0 +1,219 @@
+/* GTK - The GIMP Toolkit
+ * gtkprinteroption.c: Handling possible settings for a specific printer setting
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <gmodule.h>
+
+#include "gtkprinteroption.h"
+#include "gtkalias.h"
+
+/*****************************************
+ *            GtkPrinterOption           *
+ *****************************************/
+
+enum {
+  CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GtkPrinterOption, gtk_printer_option, G_TYPE_OBJECT)
+
+static void
+gtk_printer_option_finalize (GObject *object)
+{
+  GtkPrinterOption *option = GTK_PRINTER_OPTION (object);
+  int i;
+  
+  g_free (option->name);
+  g_free (option->display_text);
+  g_free (option->value);
+  for (i = 0; i < option->num_choices; i++)
+    {
+      g_free (option->choices[i]);
+      g_free (option->choices_display[i]);
+    }
+  g_free (option->choices);
+  g_free (option->choices_display);
+  g_free (option->group);
+  
+  G_OBJECT_CLASS (gtk_printer_option_parent_class)->finalize (object);
+}
+
+static void
+gtk_printer_option_init (GtkPrinterOption *option)
+{
+  option->value = g_strdup ("");
+}
+
+static void
+gtk_printer_option_class_init (GtkPrinterOptionClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->finalize = gtk_printer_option_finalize;
+
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrinterOptionClass, changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+GtkPrinterOption *
+gtk_printer_option_new (const char *name, const char *display_text,
+                              GtkPrinterOptionType type)
+{
+  GtkPrinterOption *option;
+
+  option = g_object_new (GTK_TYPE_PRINTER_OPTION, NULL);
+
+  option->name = g_strdup (name);
+  option->display_text = g_strdup (display_text);
+  option->type = type;
+  
+  return option;
+}
+
+static void
+emit_changed (GtkPrinterOption *option)
+{
+  g_signal_emit (option, signals[CHANGED], 0);
+}
+
+void
+gtk_printer_option_set (GtkPrinterOption *option,
+                       const char *value)
+{
+  if (value == NULL)
+    value = "";
+  
+  if (strcmp (option->value, value) == 0)
+    return;
+
+  if (option->type == GTK_PRINTER_OPTION_TYPE_PICKONE &&
+      value != NULL)
+    {
+      int i;
+      
+      for (i = 0; i < option->num_choices; i++)
+       {
+         if (g_ascii_strcasecmp (value, option->choices[i]) == 0)
+           {
+             value = option->choices[i];
+             break;
+           }
+       }
+
+      if (i == option->num_choices)
+       return; /* Not found in availible choices */
+    }
+  
+  g_free (option->value);
+  option->value = g_strdup (value);
+  
+  emit_changed (option);
+}
+
+void
+gtk_printer_option_set_boolean (GtkPrinterOption *option,
+                               gboolean value)
+{
+  gtk_printer_option_set (option, value ? "True" : "False");
+}
+
+void
+gtk_printer_option_set_has_conflict  (GtkPrinterOption *option,
+                                     gboolean  has_conflict)
+{
+  has_conflict = has_conflict != 0;
+  
+  if (option->has_conflict == has_conflict)
+    return;
+
+  option->has_conflict = has_conflict;
+  emit_changed (option);
+}
+
+void
+gtk_printer_option_clear_has_conflict (GtkPrinterOption     *option)
+{
+  gtk_printer_option_set_has_conflict  (option, FALSE);
+}
+
+void
+gtk_printer_option_allocate_choices (GtkPrinterOption     *option,
+                                    int num)
+{
+  g_free (option->choices);
+  g_free (option->choices_display);
+
+  option->num_choices = num;
+  if (num == 0)
+    {
+      option->choices = NULL;
+      option->choices_display = NULL;
+    }
+  else
+    {
+      option->choices = g_new0 (char *, num);
+      option->choices_display = g_new0 (char *, num);
+    }
+}
+
+void
+gtk_printer_option_choices_from_array (GtkPrinterOption   *option,
+                                      int                 num_choices,
+                                      char               *choices[],
+                                      char              *choices_display[])
+{
+  int i;
+  
+  gtk_printer_option_allocate_choices (option, num_choices);
+  for (i = 0; i < num_choices; i++)
+    {
+      option->choices[i] = g_strdup (choices[i]);
+      option->choices_display[i] = g_strdup (choices_display[i]);
+    }
+}
+
+gboolean
+gtk_printer_option_has_choice (GtkPrinterOption     *option,
+                              const char           *choice)
+{
+  int i;
+  
+  for (i = 0; i < option->num_choices; i++)
+    {
+      if (strcmp (option->choices[i], choice) == 0)
+       return TRUE;
+    }
+  
+  return FALSE;
+}
+
+
+#define __GTK_PRINTER_OPTION_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprinteroption.h b/gtk/gtkprinteroption.h
new file mode 100644 (file)
index 0000000..bb3acfb
--- /dev/null
@@ -0,0 +1,113 @@
+/* GTK - The GIMP Toolkit
+ * gtkprinteroption.h: printer option
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINTER_OPTION_H__
+#define __GTK_PRINTER_OPTION_H__
+
+/* This is a "semi-private" header; it is meant only for
+ * alternate GtkPrintDialog backend modules; no stability guarantees 
+ * are made at this point
+ */
+#ifndef GTK_PRINT_BACKEND_ENABLE_UNSUPPORTED
+#error "GtkPrintBackend is not supported API for general use"
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINTER_OPTION             (gtk_printer_option_get_type ())
+#define GTK_PRINTER_OPTION(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINTER_OPTION, GtkPrinterOption))
+#define GTK_IS_PRINTER_OPTION(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINTER_OPTION))
+
+typedef struct _GtkPrinterOption       GtkPrinterOption;
+typedef struct _GtkPrinterOptionClass  GtkPrinterOptionClass;
+
+#define GTK_PRINTER_OPTION_GROUP_IMAGE_QUALITY "ImageQuality"
+#define GTK_PRINTER_OPTION_GROUP_FINISHING "Finishing"
+
+typedef enum {
+  GTK_PRINTER_OPTION_TYPE_BOOLEAN,
+  GTK_PRINTER_OPTION_TYPE_PICKONE,
+  GTK_PRINTER_OPTION_TYPE_STRING,
+  GTK_PRINTER_OPTION_TYPE_FILESAVE
+} GtkPrinterOptionType;
+
+struct _GtkPrinterOption
+{
+  GObject parent_instance;
+
+  char *name;
+  char *display_text;
+  GtkPrinterOptionType type;
+
+  char *value;
+  
+  int num_choices;
+  char **choices;
+  char **choices_display;
+  
+  gboolean has_conflict;
+  char *group;
+};
+
+struct _GtkPrinterOptionClass
+{
+  GObjectClass parent_class;
+
+  void (*changed) (GtkPrinterOption *option);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType   gtk_printer_option_get_type       (void) G_GNUC_CONST;
+
+GtkPrinterOption *gtk_printer_option_new                (const char           *name,
+                                                        const char           *display_text,
+                                                        GtkPrinterOptionType  type);
+void              gtk_printer_option_set                (GtkPrinterOption     *option,
+                                                        const char           *value);
+void              gtk_printer_option_set_has_conflict   (GtkPrinterOption     *option,
+                                                        gboolean              has_conflict);
+void              gtk_printer_option_clear_has_conflict (GtkPrinterOption     *option);
+void              gtk_printer_option_set_boolean        (GtkPrinterOption     *option,
+                                                        gboolean              value);
+void              gtk_printer_option_allocate_choices   (GtkPrinterOption     *option,
+                                                        int                   num);
+void              gtk_printer_option_choices_from_array (GtkPrinterOption     *option,
+                                                        int                   num_choices,
+                                                        char                 *choices[],
+                                                        char                 *choices_display[]);
+gboolean          gtk_printer_option_has_choice         (GtkPrinterOption     *option,
+                                                        const char           *choice);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PRINTER_OPTION_H__ */
+
+
diff --git a/gtk/gtkprinteroptionset.c b/gtk/gtkprinteroptionset.c
new file mode 100644 (file)
index 0000000..eb84a34
--- /dev/null
@@ -0,0 +1,205 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackend.h: Abstract printer backend interfaces
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib.h>
+#include <gmodule.h>
+
+#include "gtkprinteroptionset.h"
+#include "gtkalias.h"
+
+/*****************************************
+ *         GtkPrinterOptionSet    *
+ *****************************************/
+
+enum {
+  CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* ugly side-effect of aliasing */
+#undef gtk_printer_option_set
+
+G_DEFINE_TYPE (GtkPrinterOptionSet, gtk_printer_option_set, G_TYPE_OBJECT)
+
+static void
+gtk_printer_option_set_finalize (GObject *object)
+{
+  GtkPrinterOptionSet *set = GTK_PRINTER_OPTION_SET (object);
+
+  g_hash_table_destroy (set->hash);
+  g_ptr_array_foreach (set->array, (GFunc)g_object_unref, NULL);
+  g_ptr_array_free (set->array, TRUE);
+  
+  G_OBJECT_CLASS (gtk_printer_option_set_parent_class)->finalize (object);
+}
+
+static void
+gtk_printer_option_set_init (GtkPrinterOptionSet *set)
+{
+  set->array = g_ptr_array_new ();
+  set->hash = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static void
+gtk_printer_option_set_class_init (GtkPrinterOptionSetClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->finalize = gtk_printer_option_set_finalize;
+
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrinterOptionSetClass, changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+
+static void
+emit_changed (GtkPrinterOptionSet *set)
+{
+  g_signal_emit (set, signals[CHANGED], 0);
+}
+
+GtkPrinterOptionSet *
+gtk_printer_option_set_new (void)
+{
+  return g_object_new (GTK_TYPE_PRINTER_OPTION_SET, NULL);
+}
+
+void
+gtk_printer_option_set_remove (GtkPrinterOptionSet *set,
+                              GtkPrinterOption    *option)
+{
+  int i;
+  
+  for (i = 0; i < set->array->len; i++)
+    {
+      if (g_ptr_array_index (set->array, i) == option)
+       {
+         g_ptr_array_remove_index (set->array, i);
+         g_hash_table_remove (set->hash, option->name);
+         g_signal_handlers_disconnect_by_func (option, emit_changed, set);
+
+         g_object_unref (option);
+         break;
+       }
+    }
+}
+
+void
+gtk_printer_option_set_add (GtkPrinterOptionSet *set,
+                           GtkPrinterOption    *option)
+{
+  g_object_ref (option);
+  
+  if (gtk_printer_option_set_lookup (set, option->name))
+    gtk_printer_option_set_remove (set, option);
+    
+  g_ptr_array_add (set->array, option);
+  g_hash_table_insert (set->hash, option->name, option);
+  g_signal_connect_object (option, "changed", G_CALLBACK (emit_changed), set, G_CONNECT_SWAPPED);
+}
+
+GtkPrinterOption *
+gtk_printer_option_set_lookup (GtkPrinterOptionSet *set,
+                              const char          *name)
+{
+  gpointer ptr;
+
+  ptr = g_hash_table_lookup (set->hash, name);
+
+  return GTK_PRINTER_OPTION (ptr);
+}
+
+void
+gtk_printer_option_set_clear_conflicts (GtkPrinterOptionSet *set)
+{
+  gtk_printer_option_set_foreach (set,
+                                 (GtkPrinterOptionSetFunc)gtk_printer_option_clear_has_conflict,
+                                 NULL);
+}
+
+static int
+safe_strcmp (const char *a, const char *b)
+{
+  if (a == NULL)
+    a = "";
+  if (b == NULL)
+    b = "";
+
+  return strcmp (a, b);
+}
+
+GList *
+gtk_printer_option_set_get_groups (GtkPrinterOptionSet *set)
+{
+  GtkPrinterOption *option;
+  GList *list = NULL;
+  int i;
+
+  for (i = 0; i < set->array->len; i++)
+    {
+      option = g_ptr_array_index (set->array, i);
+
+      if (g_list_find_custom (list, option->group, (GCompareFunc)safe_strcmp) == NULL)
+       list = g_list_prepend (list, g_strdup (option->group));
+    }
+
+  return g_list_reverse (list);
+}
+
+void
+gtk_printer_option_set_foreach_in_group (GtkPrinterOptionSet     *set,
+                                        const char              *group,
+                                        GtkPrinterOptionSetFunc  func,
+                                        gpointer                 user_data)
+{
+  GtkPrinterOption *option;
+  int i;
+
+  for (i = 0; i < set->array->len; i++)
+    {
+      option = g_ptr_array_index (set->array, i);
+
+      if (group == NULL ||
+         (option->group != NULL && strcmp (group, option->group) == 0))
+       func (option, user_data);
+    }
+}
+
+void
+gtk_printer_option_set_foreach (GtkPrinterOptionSet *set,
+                               GtkPrinterOptionSetFunc func,
+                               gpointer user_data)
+{
+  gtk_printer_option_set_foreach_in_group (set, NULL, func, user_data);
+}
+
+
+#define __GTK_PRINTER_OPTION_SET_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprinteroptionset.h b/gtk/gtkprinteroptionset.h
new file mode 100644 (file)
index 0000000..2263909
--- /dev/null
@@ -0,0 +1,96 @@
+
+/* GTK - The GIMP Toolkit
+ * gtkprinteroptionset.h: printer option set
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINTER_OPTION_SET_H__
+#define __GTK_PRINTER_OPTION_SET_H__
+
+/* This is a "semi-private" header; it is meant only for
+ * alternate GtkPrintDialog backend modules; no stability guarantees 
+ * are made at this point
+ */
+#ifndef GTK_PRINT_BACKEND_ENABLE_UNSUPPORTED
+#error "GtkPrintBackend is not supported API for general use"
+#endif
+
+#include <glib-object.h>
+#include "gtkprinteroption.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINTER_OPTION_SET             (gtk_printer_option_set_get_type ())
+#define GTK_PRINTER_OPTION_SET(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINTER_OPTION_SET, GtkPrinterOptionSet))
+#define GTK_IS_PRINTER_OPTION_SET(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINTER_OPTION_SET))
+
+typedef struct _GtkPrinterOptionSet       GtkPrinterOptionSet;
+typedef struct _GtkPrinterOptionSetClass  GtkPrinterOptionSetClass;
+
+struct _GtkPrinterOptionSet
+{
+  GObject parent_instance;
+
+  /*< private >*/
+  GPtrArray *array;
+  GHashTable *hash;
+};
+
+struct _GtkPrinterOptionSetClass
+{
+  GObjectClass parent_class;
+
+  void (*changed) (GtkPrinterOptionSet *option);
+
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+typedef void (*GtkPrinterOptionSetFunc) (GtkPrinterOption  *option,
+                                        gpointer           user_data);
+
+
+GType   gtk_printer_option_set_get_type       (void) G_GNUC_CONST;
+
+GtkPrinterOptionSet *gtk_printer_option_set_new              (void);
+void                 gtk_printer_option_set_add              (GtkPrinterOptionSet     *set,
+                                                             GtkPrinterOption        *option);
+void                 gtk_printer_option_set_remove           (GtkPrinterOptionSet     *set,
+                                                             GtkPrinterOption        *option);
+GtkPrinterOption *   gtk_printer_option_set_lookup           (GtkPrinterOptionSet     *set,
+                                                             const char              *name);
+void                 gtk_printer_option_set_foreach          (GtkPrinterOptionSet     *set,
+                                                             GtkPrinterOptionSetFunc  func,
+                                                             gpointer                 user_data);
+void                 gtk_printer_option_set_clear_conflicts  (GtkPrinterOptionSet     *set);
+GList *              gtk_printer_option_set_get_groups       (GtkPrinterOptionSet     *set);
+void                 gtk_printer_option_set_foreach_in_group (GtkPrinterOptionSet     *set,
+                                                             const char              *group,
+                                                             GtkPrinterOptionSetFunc  func,
+                                                             gpointer                 user_data);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINTER_OPTION_SET_H__ */
diff --git a/gtk/gtkprinteroptionwidget.c b/gtk/gtkprinteroptionwidget.c
new file mode 100644 (file)
index 0000000..71c2943
--- /dev/null
@@ -0,0 +1,617 @@
+/* GtkPrinterOptionWidget
+ * Copyright (C) 2006 Alexander Larsson  <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gtkintl.h"
+#include "gtkalignment.h"
+#include "gtkcheckbutton.h"
+#include "gtkcelllayout.h"
+#include "gtkcellrenderertext.h"
+#include "gtkcombobox.h"
+#include "gtkfilechooserbutton.h"
+#include "gtkimage.h"
+#include "gtklabel.h"
+#include "gtkliststore.h"
+#include "gtkstock.h"
+#include "gtktable.h"
+#include "gtktogglebutton.h"
+#include "gtkprivate.h"
+
+#include "gtkprinteroptionwidget.h"
+#include "gtkalias.h"
+
+#define GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetPrivate))
+
+static void gtk_printer_option_widget_finalize (GObject *object);
+
+static void deconstruct_widgets (GtkPrinterOptionWidget *widget);
+static void construct_widgets (GtkPrinterOptionWidget *widget);
+static void update_widgets (GtkPrinterOptionWidget *widget);
+
+struct GtkPrinterOptionWidgetPrivate
+{
+  GtkPrinterOption *source;
+  gulong source_changed_handler;
+  
+  GtkWidget *check;
+  GtkWidget *combo;
+  GtkWidget *entry;
+  GtkWidget *image;
+  GtkWidget *label;
+  GtkWidget *filechooser;
+};
+
+enum {
+  CHANGED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_SOURCE,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GtkPrinterOptionWidget, gtk_printer_option_widget, GTK_TYPE_HBOX);
+
+static void gtk_printer_option_widget_set_property (GObject      *object,
+                                                   guint         prop_id,
+                                                   const GValue *value,
+                                                   GParamSpec   *pspec);
+static void gtk_printer_option_widget_get_property (GObject      *object,
+                                                   guint         prop_id,
+                                                   GValue       *value,
+                                                   GParamSpec   *pspec);
+
+static void
+gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
+{
+  GObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GObjectClass *) class;
+  widget_class = (GtkWidgetClass *) class;
+
+  object_class->finalize = gtk_printer_option_widget_finalize;
+  object_class->set_property = gtk_printer_option_widget_set_property;
+  object_class->get_property = gtk_printer_option_widget_get_property;
+
+  g_type_class_add_private (class, sizeof (GtkPrinterOptionWidgetPrivate));  
+
+  signals[CHANGED] =
+    g_signal_new ("changed",
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrinterOptionWidgetClass, changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  g_object_class_install_property (object_class,
+                                   PROP_SOURCE,
+                                   g_param_spec_object ("source",
+                                                       P_("Source option"),
+                                                       P_("The PrinterOption backing this widget"),
+                                                       GTK_TYPE_PRINTER_OPTION,
+                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+}
+
+static void
+gtk_printer_option_widget_init (GtkPrinterOptionWidget *widget)
+{
+  widget->priv = GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE (widget); 
+}
+
+static void
+gtk_printer_option_widget_finalize (GObject *object)
+{
+  GtkPrinterOptionWidget *widget;
+  
+  widget = GTK_PRINTER_OPTION_WIDGET (object);
+
+  if (widget->priv->source)
+    {
+      g_object_unref (widget->priv->source);
+      widget->priv->source = NULL;
+    }
+  
+  if (G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize (object);
+}
+
+static void
+gtk_printer_option_widget_set_property (GObject         *object,
+                                       guint            prop_id,
+                                       const GValue    *value,
+                                       GParamSpec      *pspec)
+{
+  GtkPrinterOptionWidget *widget;
+  
+  widget = GTK_PRINTER_OPTION_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_SOURCE:
+      gtk_printer_option_widget_set_source (widget, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_printer_option_widget_get_property (GObject    *object,
+                                       guint       prop_id,
+                                       GValue     *value,
+                                       GParamSpec *pspec)
+{
+  GtkPrinterOptionWidget *widget;
+  
+  widget = GTK_PRINTER_OPTION_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_SOURCE:
+      g_value_set_object (value, widget->priv->source);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+emit_changed (GtkPrinterOptionWidget *widget)
+{
+  g_signal_emit (widget, signals[CHANGED], 0);
+}
+
+GtkWidget *
+gtk_printer_option_widget_new (GtkPrinterOption *source)
+{
+  return g_object_new (GTK_TYPE_PRINTER_OPTION_WIDGET, "source", source, NULL);
+}
+
+static void
+source_changed_cb (GtkPrinterOption *source,
+                  GtkPrinterOptionWidget  *widget)
+{
+  update_widgets (widget);
+  emit_changed (widget);
+}
+
+void
+gtk_printer_option_widget_set_source (GtkPrinterOptionWidget  *widget,
+                                     GtkPrinterOption *source)
+{
+  if (source)
+    g_object_ref (source);
+  
+  if (widget->priv->source)
+    {
+      g_signal_handler_disconnect (widget->priv->source,
+                                  widget->priv->source_changed_handler);
+      g_object_unref (widget->priv->source);
+    }
+
+  widget->priv->source = source;
+
+  if (source)
+    widget->priv->source_changed_handler =
+      g_signal_connect (source, "changed", G_CALLBACK (source_changed_cb), widget);
+
+  construct_widgets (widget);
+  update_widgets (widget);
+
+  g_object_notify (G_OBJECT (widget), "source");
+}
+
+static GtkWidget *
+combo_box_new (void)
+{
+  GtkWidget *combo_box;
+  GtkCellRenderer *cell;
+  GtkListStore *store;
+
+  store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+  combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+  g_object_unref (store);
+
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
+                                  "text", 0,
+                                  NULL);
+
+  return combo_box;
+}
+  
+static void
+combo_box_append (GtkWidget *combo,
+                 const char *display_text,
+                 const char *value)
+{
+  GtkTreeModel *model;
+  GtkListStore *store;
+  GtkTreeIter iter;
+  
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+  store = GTK_LIST_STORE (model);
+
+  gtk_list_store_append (store, &iter);
+  gtk_list_store_set (store, &iter,
+                     0, display_text,
+                     1, value,
+                     -1);
+}
+
+struct ComboSet {
+  GtkComboBox *combo;
+  const char *value;
+};
+
+static gboolean
+set_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+  struct ComboSet *set_data = data;
+  gboolean found;
+  char *value;
+  
+  gtk_tree_model_get (model, iter, 1, &value, -1);
+  found = (strcmp (value, set_data->value) == 0);
+  g_free (value);
+  
+  if (found)
+    gtk_combo_box_set_active_iter (set_data->combo, iter);
+
+  return found;
+}
+
+static void
+combo_box_set (GtkWidget *combo,
+              const char *value)
+{
+  GtkTreeModel *model;
+  GtkListStore *store;
+  struct ComboSet set_data;
+  
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+  store = GTK_LIST_STORE (model);
+
+  set_data.combo = GTK_COMBO_BOX (combo);
+  set_data.value = value;
+  gtk_tree_model_foreach (model, set_cb, &set_data);
+}
+
+static char *
+combo_box_get (GtkWidget *combo)
+{
+  GtkTreeModel *model;
+  char *val;
+  GtkTreeIter iter;
+  
+  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+
+  val = NULL;
+  if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
+    gtk_tree_model_get (model, &iter,
+                       1, &val,
+                       -1);
+  return val;
+}
+
+
+static void
+deconstruct_widgets (GtkPrinterOptionWidget *widget)
+{
+  if (widget->priv->check)
+    {
+      gtk_widget_destroy (widget->priv->check);
+      widget->priv->check = NULL;
+    }
+  
+  if (widget->priv->combo)
+    {
+      gtk_widget_destroy (widget->priv->combo);
+      widget->priv->combo = NULL;
+    }
+  
+  if (widget->priv->entry)
+    {
+      gtk_widget_destroy (widget->priv->entry);
+      widget->priv->entry = NULL;
+    }
+
+  /* make sure entry and combo are destroyed first */
+  /* as we use the two of them to create the filechooser */
+  if (widget->priv->filechooser)
+    {
+      gtk_widget_destroy (widget->priv->filechooser);
+      widget->priv->filechooser = NULL;
+    }
+
+  if (widget->priv->image)
+    {
+      gtk_widget_destroy (widget->priv->image);
+      widget->priv->image = NULL;
+    }
+
+  if (widget->priv->label)
+    {
+      gtk_widget_destroy (widget->priv->label);
+      widget->priv->label = NULL;
+    }
+}
+
+static void
+check_toggled_cb (GtkToggleButton *toggle_button,
+                 GtkPrinterOptionWidget *widget)
+{
+  g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
+  gtk_printer_option_set_boolean (widget->priv->source,
+                                 gtk_toggle_button_get_active (toggle_button));
+  g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
+  emit_changed (widget);
+}
+
+static void
+filesave_changed_cb (GtkWidget *w,
+                     GtkPrinterOptionWidget *widget)
+{
+  char *value;
+  char *directory;
+  const char *file;
+
+  /* combine the value of the chooser with the value of the entry */
+  g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);  
+  
+  /* TODO: how do we support nonlocal file systems? */
+  directory = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget->priv->combo));
+  file =  gtk_entry_get_text (GTK_ENTRY (widget->priv->entry));
+
+  value = g_build_filename (directory, file, NULL);
+
+  if (value)
+    gtk_printer_option_set (widget->priv->source, value);
+
+  g_free (directory);
+  g_free (value);
+
+  g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
+  emit_changed (widget);
+}
+
+static void
+combo_changed_cb (GtkWidget *combo,
+                 GtkPrinterOptionWidget *widget)
+{
+  char *value;
+  
+  g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
+  value = combo_box_get (combo);
+  if (value)
+    gtk_printer_option_set (widget->priv->source, value);
+  g_free (value);
+  g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
+  emit_changed (widget);
+}
+
+static void
+entry_changed_cb (GtkWidget *entry,
+                 GtkPrinterOptionWidget *widget)
+{
+  const char *value;
+  
+  g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
+  value = gtk_entry_get_text (GTK_ENTRY (entry));
+  if (value)
+    gtk_printer_option_set (widget->priv->source, value);
+  g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
+  emit_changed (widget);
+}
+
+
+static void
+construct_widgets (GtkPrinterOptionWidget *widget)
+{
+  GtkPrinterOption *source;
+  char *text;
+  int i;
+
+  source = widget->priv->source;
+  
+  deconstruct_widgets (widget);
+  
+  if (source == NULL)
+    {
+      widget->priv->combo = combo_box_new ();
+      combo_box_append (widget->priv->combo,_("Not available"), "None");
+      gtk_combo_box_set_active (GTK_COMBO_BOX (widget->priv->combo), 0);
+      gtk_widget_set_sensitive (widget->priv->combo, FALSE);
+      gtk_widget_show (widget->priv->combo);
+      gtk_box_pack_start (GTK_BOX (widget), widget->priv->combo, TRUE, TRUE, 0);
+    }
+  else switch (source->type)
+    {
+    case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
+      widget->priv->check = gtk_check_button_new_with_mnemonic (source->display_text);
+      g_signal_connect (widget->priv->check, "toggled", G_CALLBACK (check_toggled_cb), widget);
+      gtk_widget_show (widget->priv->check);
+      gtk_box_pack_start (GTK_BOX (widget), widget->priv->check, TRUE, TRUE, 0);
+      break;
+    case GTK_PRINTER_OPTION_TYPE_PICKONE:
+      widget->priv->combo = combo_box_new ();
+      for (i = 0; i < source->num_choices; i++)
+         combo_box_append (widget->priv->combo,
+                           source->choices_display[i],
+                           source->choices[i]);
+      gtk_widget_show (widget->priv->combo);
+      gtk_box_pack_start (GTK_BOX (widget), widget->priv->combo, TRUE, TRUE, 0);
+      g_signal_connect (widget->priv->combo, "changed", G_CALLBACK (combo_changed_cb), widget);
+
+      text = g_strdup_printf ("%s: ", source->display_text);
+      widget->priv->label = gtk_label_new_with_mnemonic (text);
+      g_free (text);
+      gtk_widget_show (widget->priv->label);
+      break;
+    case GTK_PRINTER_OPTION_TYPE_STRING:
+      widget->priv->entry = gtk_entry_new ();
+      gtk_widget_show (widget->priv->entry);
+      gtk_box_pack_start (GTK_BOX (widget), widget->priv->entry, TRUE, TRUE, 0);
+      g_signal_connect (widget->priv->entry, "changed", G_CALLBACK (entry_changed_cb), widget);
+
+      text = g_strdup_printf ("%s: ", source->display_text);
+      widget->priv->label = gtk_label_new_with_mnemonic (text);
+      g_free (text);
+      gtk_widget_show (widget->priv->label);
+
+      break;
+
+    case GTK_PRINTER_OPTION_TYPE_FILESAVE:
+      {
+        GtkWidget *label;
+        GtkWidget *align;
+        
+        widget->priv->filechooser = gtk_table_new (2, 2, FALSE);
+
+        /* TODO: make this a gtkfilechooserentry once we move to GTK */
+        widget->priv->entry = gtk_entry_new ();
+        widget->priv->combo = gtk_file_chooser_button_new ("Print to PDF", 
+                                                           GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+        
+        align = gtk_alignment_new (0, 0.5, 0, 0);
+        label = gtk_label_new ("Name:");
+        gtk_container_add (GTK_CONTAINER (align), label);
+
+        gtk_table_attach (GTK_TABLE (widget->priv->filechooser), align,
+                          0, 1, 0, 1, GTK_FILL, 0,
+                          0, 0);
+
+        gtk_table_attach (GTK_TABLE (widget->priv->filechooser), widget->priv->entry,
+                          1, 2, 0, 1, GTK_FILL, 0,
+                          0, 0);
+
+        align = gtk_alignment_new (0, 0.5, 0, 0);
+        label = gtk_label_new ("Save in folder:");
+        gtk_container_add (GTK_CONTAINER (align), label);
+
+        gtk_table_attach (GTK_TABLE (widget->priv->filechooser), align,
+                          0, 1, 1, 2, GTK_FILL, 0,
+                          0, 0);
+
+        gtk_table_attach (GTK_TABLE (widget->priv->filechooser), widget->priv->combo,
+                          1, 2, 1, 2, GTK_FILL, 0,
+                          0, 0);
+
+        gtk_widget_show_all (widget->priv->filechooser);
+        gtk_box_pack_start (GTK_BOX (widget), widget->priv->filechooser, TRUE, TRUE, 0);
+
+        g_signal_connect (widget->priv->entry, "changed", G_CALLBACK (filesave_changed_cb), widget);
+
+        g_signal_connect (widget->priv->combo, "current-folder-changed", G_CALLBACK (filesave_changed_cb), widget);
+      }
+      break;
+    default:
+      break;
+    }
+
+  widget->priv->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
+  gtk_box_pack_start (GTK_BOX (widget), widget->priv->image, FALSE, FALSE, 0);
+}
+
+static void
+update_widgets (GtkPrinterOptionWidget *widget)
+{
+  GtkPrinterOption *source;
+
+  source = widget->priv->source;
+  
+  if (source == NULL)
+    {
+      gtk_widget_hide (widget->priv->image);
+      return;
+    }
+
+  switch (source->type)
+    {
+    case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
+      if (strcmp (source->value, "True") == 0)
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->priv->check), TRUE);
+      else
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->priv->check), FALSE);
+      break;
+    case GTK_PRINTER_OPTION_TYPE_PICKONE:
+      combo_box_set (widget->priv->combo, source->value);
+      break;
+    case GTK_PRINTER_OPTION_TYPE_STRING:
+      gtk_entry_set_text (GTK_ENTRY (widget->priv->entry), source->value);
+      break;
+    case GTK_PRINTER_OPTION_TYPE_FILESAVE:
+      {
+       char *basename = g_path_get_basename (source->value);
+       char *dirname = g_path_get_dirname (source->value);
+       gtk_entry_set_text (GTK_ENTRY (widget->priv->entry), basename);
+       if (g_path_is_absolute (dirname))
+         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget->priv->combo),
+                                              dirname);
+       g_free (basename);
+       g_free (dirname);
+       break;
+      }
+    default:
+      break;
+    }
+
+  if (source->has_conflict)
+    gtk_widget_show (widget->priv->image);
+  else
+    gtk_widget_hide (widget->priv->image);
+}
+
+gboolean
+gtk_printer_option_widget_has_external_label (GtkPrinterOptionWidget  *widget)
+{
+  return widget->priv->label != NULL;
+}
+
+GtkWidget *
+gtk_printer_option_widget_get_external_label (GtkPrinterOptionWidget  *widget)
+{
+  return widget->priv->label;
+}
+
+const char *
+gtk_printer_option_widget_get_value (GtkPrinterOptionWidget  *widget)
+{
+  if (widget->priv->source)
+    return widget->priv->source->value;
+  
+  return "";
+}
+
+#define __GTK_PRINTER_OPTION_WIDGET_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprinteroptionwidget.h b/gtk/gtkprinteroptionwidget.h
new file mode 100644 (file)
index 0000000..70ea155
--- /dev/null
@@ -0,0 +1,64 @@
+/* GtkPrinterOptionWidget 
+ * Copyright (C) 2006 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINTER_OPTION_WIDGET_H__
+#define __GTK_PRINTER_OPTION_WIDGET_H__
+
+#include "gtkprinteroption.h"
+#include "gtkhbox.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINTER_OPTION_WIDGET                  (gtk_printer_option_widget_get_type ())
+#define GTK_PRINTER_OPTION_WIDGET(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidget))
+#define GTK_PRINTER_OPTION_WIDGET_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetClass))
+#define GTK_IS_PRINTER_OPTION_WIDGET(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINTER_OPTION_WIDGET))
+#define GTK_IS_PRINTER_OPTION_WIDGET_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINTER_OPTION_WIDGET))
+#define GTK_PRINTER_OPTION_WIDGET_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetClass))
+
+
+typedef struct _GtkPrinterOptionWidget         GtkPrinterOptionWidget;
+typedef struct _GtkPrinterOptionWidgetClass    GtkPrinterOptionWidgetClass;
+typedef struct GtkPrinterOptionWidgetPrivate   GtkPrinterOptionWidgetPrivate;
+
+struct _GtkPrinterOptionWidget
+{
+  GtkHBox parent_instance;
+
+  GtkPrinterOptionWidgetPrivate *priv;
+};
+
+struct _GtkPrinterOptionWidgetClass
+{
+  GtkHBoxClass parent_class;
+
+  void (*changed) (GtkPrinterOptionWidget *widget);
+};
+
+GType           gtk_printer_option_widget_get_type   (void) G_GNUC_CONST;
+
+GtkWidget * gtk_printer_option_widget_new                (GtkPrinterOption       *source);
+void        gtk_printer_option_widget_set_source         (GtkPrinterOptionWidget *setting,
+                                                         GtkPrinterOption       *source);
+gboolean    gtk_printer_option_widget_has_external_label (GtkPrinterOptionWidget *setting);
+GtkWidget * gtk_printer_option_widget_get_external_label (GtkPrinterOptionWidget *setting);
+const char *gtk_printer_option_widget_get_value          (GtkPrinterOptionWidget *setting);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINTER_OPTION_WIDGET_H__ */
diff --git a/gtk/gtkprintjob.c b/gtk/gtkprintjob.c
new file mode 100644 (file)
index 0000000..3abffaa
--- /dev/null
@@ -0,0 +1,472 @@
+/* GtkPrintJob
+ * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <glib/gstdio.h>
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkprintjob.h"
+#include "gtkprinter.h"
+#include "gtkprintbackend.h"
+#include "gtkalias.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+struct _GtkPrintJobPrivate
+{
+  gchar *title;
+
+  int spool_file_fd;
+  cairo_surface_t *surface;
+
+  GtkPrintStatus status;
+  GtkPrintBackend *backend;  
+  GtkPrinter *printer;
+  GtkPrintSettings *settings;
+  GtkPageSetup *page_setup;
+
+  gint printer_set : 1;
+  gint page_setup_set : 1;
+  gint settings_set  : 1;
+};
+
+
+#define GTK_PRINT_JOB_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_JOB, GtkPrintJobPrivate))
+
+static void     gtk_print_job_finalize     (GObject               *object);
+static void     gtk_print_job_set_property (GObject               *object,
+                                           guint                  prop_id,
+                                           const GValue          *value,
+                                           GParamSpec            *pspec);
+static void     gtk_print_job_get_property (GObject               *object,
+                                           guint                  prop_id,
+                                           GValue                *value,
+                                           GParamSpec            *pspec);
+static GObject* gtk_print_job_constructor  (GType                  type,
+                                           guint                  n_construct_properties,
+                                           GObjectConstructParam *construct_params);
+
+enum {
+  STATUS_CHANGED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  GTK_PRINT_JOB_PROP_TITLE,
+  GTK_PRINT_JOB_PROP_PRINTER,
+  GTK_PRINT_JOB_PROP_PAGE_SETUP,
+  GTK_PRINT_JOB_PROP_SETTINGS
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GtkPrintJob, gtk_print_job, G_TYPE_OBJECT);
+
+static void
+gtk_print_job_class_init (GtkPrintJobClass *class)
+{
+  GObjectClass *object_class;
+  object_class = (GObjectClass *) class;
+
+  object_class->finalize = gtk_print_job_finalize;
+  object_class->constructor = gtk_print_job_constructor;
+  object_class->set_property = gtk_print_job_set_property;
+  object_class->get_property = gtk_print_job_get_property;
+
+  g_type_class_add_private (class, sizeof (GtkPrintJobPrivate));
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   GTK_PRINT_JOB_PROP_TITLE,
+                                   g_param_spec_string ("title",
+                                                       P_("Title"),
+                                                       P_("Title of the print job"),
+                                                       NULL,
+                                                       GTK_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   GTK_PRINT_JOB_PROP_PRINTER,
+                                   g_param_spec_object ("printer",
+                                                       P_("Printer"),
+                                                       P_("Printer to print the job to"),
+                                                       GTK_TYPE_PRINTER,
+                                                       GTK_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   GTK_PRINT_JOB_PROP_SETTINGS,
+                                   g_param_spec_object ("settings",
+                                                       P_("Settings"),
+                                                       P_("Printer settings"),
+                                                       GTK_TYPE_PRINT_SETTINGS,
+                                                       GTK_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   GTK_PRINT_JOB_PROP_PAGE_SETUP,
+                                   g_param_spec_object ("page-setup",
+                                                       P_("Page Setup"),
+                                                       P_("Page Setup"),
+                                                       GTK_TYPE_PAGE_SETUP,
+                                                       GTK_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+
+  signals[STATUS_CHANGED] =
+   g_signal_new ("status-changed",
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintJobClass, status_changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+static void
+gtk_print_job_init (GtkPrintJob *print_job)
+{
+  print_job->priv = GTK_PRINT_JOB_GET_PRIVATE (print_job); 
+  print_job->priv->spool_file_fd = -1;
+
+  print_job->priv->title = g_strdup ("");
+  print_job->priv->surface = NULL;
+  print_job->priv->backend = NULL;
+  print_job->priv->printer = NULL;
+
+  print_job->priv->printer_set = FALSE;
+  print_job->priv->settings_set = FALSE;
+  print_job->priv->page_setup_set = FALSE;
+  print_job->priv->status = GTK_PRINT_STATUS_INITIAL;
+
+  print_job->print_pages = GTK_PRINT_PAGES_ALL;
+  print_job->page_ranges = NULL;
+  print_job->num_page_ranges = 0;
+  print_job->collate = FALSE;
+  print_job->reverse = FALSE;
+  print_job->num_copies = 1;
+  print_job->scale = 1.0;
+  print_job->page_set = GTK_PAGE_SET_ALL;
+  print_job->rotate_to_orientation = FALSE;
+}
+
+
+static GObject*
+gtk_print_job_constructor (GType                  type,
+                          guint                  n_construct_properties,
+                          GObjectConstructParam *construct_params)
+{
+  GtkPrintJob *job;
+  GObject *object;
+
+  object =
+    G_OBJECT_CLASS (gtk_print_job_parent_class)->constructor (type,
+                                                             n_construct_properties,
+                                                             construct_params);
+
+  job = GTK_PRINT_JOB (object);
+  
+  g_assert (job->priv->printer_set &&
+           job->priv->settings_set &&
+           job->priv->page_setup_set);
+  
+  _gtk_printer_prepare_for_print (job->priv->printer,
+                                 job,
+                                 job->priv->settings,
+                                 job->priv->page_setup);
+
+  return object;
+}
+
+
+static void
+gtk_print_job_finalize (GObject *object)
+{
+  GtkPrintJob *print_job;
+  
+  g_return_if_fail (object != NULL);
+
+  print_job = GTK_PRINT_JOB (object);
+
+  if (print_job->priv->spool_file_fd > 0)
+    {
+      close (print_job->priv->spool_file_fd);
+      print_job->priv->spool_file_fd = -1;
+    }
+  
+  if (print_job->priv->backend)
+    g_object_unref (G_OBJECT (print_job->priv->backend));
+
+  if (print_job->priv->printer)
+    g_object_unref (G_OBJECT (print_job->priv->printer));
+
+  if (print_job->priv->surface)
+    cairo_surface_destroy (print_job->priv->surface);
+
+  if (print_job->priv->settings)
+    g_object_unref (print_job->priv->settings);
+  
+  if (print_job->priv->page_setup)
+    g_object_unref (print_job->priv->page_setup);
+
+  g_free (print_job->page_ranges);
+  print_job->page_ranges = NULL;
+  
+  g_free (print_job->priv->title);
+  print_job->priv->title = NULL;
+  
+  if (G_OBJECT_CLASS (gtk_print_job_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_print_job_parent_class)->finalize (object);
+}
+
+/**
+ * gtk_print_job_new:
+ *
+ * Creates a new #GtkPrintJob.
+ *
+ * Return value: a new #GtkPrintJob
+ *
+ * Since: 2.8
+ **/
+GtkPrintJob *
+gtk_print_job_new (const gchar *title,
+                  GtkPrinter *printer,
+                  GtkPrintSettings *settings,
+                  GtkPageSetup *page_setup)
+{
+  GObject *result;
+  result = g_object_new (GTK_TYPE_PRINT_JOB,
+                         "title", title,
+                        "printer", printer,
+                        "settings", settings,
+                        "page-setup", page_setup,
+                        NULL);
+  return (GtkPrintJob *) result;
+}
+
+GtkPrintSettings *
+gtk_print_job_get_settings (GtkPrintJob *print_job)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (print_job), NULL);
+  
+  return print_job->priv->settings;
+}
+
+GtkPrinter *
+gtk_print_job_get_printer (GtkPrintJob *print_job)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (print_job), NULL);
+  
+  return print_job->priv->printer;
+}
+
+const char *
+gtk_print_job_get_title (GtkPrintJob *print_job)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (print_job), NULL);
+  
+  return print_job->priv->title;
+}
+
+GtkPrintStatus
+gtk_print_job_get_status (GtkPrintJob *print_job)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (print_job), GTK_PRINT_STATUS_FINISHED);
+  
+  return print_job->priv->status;
+}
+
+void
+gtk_print_job_set_status (GtkPrintJob   *job,
+                         GtkPrintStatus status)
+{
+  if (job->priv->status == status)
+    return;
+
+  job->priv->status = status;
+  g_signal_emit (job, signals[STATUS_CHANGED], 0);
+}
+
+gboolean
+gtk_print_job_set_source_file (GtkPrintJob *job,
+                              const char  *filename,
+                              GError     **error)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (job), FALSE);
+  
+  job->priv->spool_file_fd = g_open (filename, O_RDONLY|O_BINARY);
+  if (job->priv->spool_file_fd < 0)
+    {
+      gchar *display_filename = g_filename_display_name (filename);
+      int save_errno = errno;
+      
+      g_set_error (error,
+                   G_FILE_ERROR,
+                   g_file_error_from_errno (save_errno),
+                   _("Failed to open file '%s': %s"),
+                   display_filename, 
+                  g_strerror (save_errno));
+      
+      g_free (display_filename);
+
+      return FALSE;
+    }
+    return TRUE;
+}
+
+cairo_surface_t *
+gtk_print_job_get_surface (GtkPrintJob *job,
+                          GError **error)
+{
+  char *filename;
+  double width, height;
+  GtkPaperSize *paper_size;
+  
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (job), NULL);
+
+  if (job->priv->surface)
+    return job->priv->surface;
+  
+  job->priv->spool_file_fd = g_file_open_tmp ("gtkprint_XXXXXX", 
+                                             &filename, 
+                                             error);
+  if (job->priv->spool_file_fd == -1)
+    return NULL;
+
+  fchmod (job->priv->spool_file_fd, S_IRUSR | S_IWUSR);
+  unlink (filename);
+
+  paper_size = gtk_page_setup_get_paper_size (job->priv->page_setup);
+  width = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
+  height = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
+
+  job->priv->surface = _gtk_printer_create_cairo_surface (job->priv->printer,
+                                                         width, height,
+                                                         job->priv->spool_file_fd);
+  return job->priv->surface;
+}
+
+static void
+gtk_print_job_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                            GParamSpec   *pspec)
+
+{
+  GtkPrintJob *job = GTK_PRINT_JOB (object);
+  GtkPrintSettings *settings;
+
+  switch (prop_id)
+    {
+    case GTK_PRINT_JOB_PROP_TITLE:
+      job->priv->title = g_value_dup_string (value);
+      break;
+    
+    case GTK_PRINT_JOB_PROP_PRINTER:
+      job->priv->printer = GTK_PRINTER (g_value_dup_object (value));
+      job->priv->printer_set = TRUE;
+      job->priv->backend = g_object_ref (gtk_printer_get_backend (job->priv->printer));
+      break;
+
+    case GTK_PRINT_JOB_PROP_PAGE_SETUP:
+      job->priv->page_setup = GTK_PAGE_SETUP (g_value_dup_object (value));
+      job->priv->page_setup_set = TRUE;
+      break;
+      
+    case GTK_PRINT_JOB_PROP_SETTINGS:
+      /* We save a copy of the settings since we modify
+       * if when preparing the printer job. */
+      settings = GTK_PRINT_SETTINGS (g_value_get_object (value));
+      job->priv->settings = gtk_print_settings_copy (settings);
+      job->priv->settings_set = TRUE;
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_print_job_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  GtkPrintJob *job = GTK_PRINT_JOB (object);
+
+  switch (prop_id)
+    {
+    case GTK_PRINT_JOB_PROP_TITLE:
+      g_value_set_string (value, job->priv->title);
+      break;
+    case GTK_PRINT_JOB_PROP_PRINTER:
+      g_value_set_object (value, job->priv->printer);
+      break;
+    case GTK_PRINT_JOB_PROP_SETTINGS:
+      g_value_set_object (value, job->priv->settings);
+      break;
+    case GTK_PRINT_JOB_PROP_PAGE_SETUP:
+      g_value_set_object (value, job->priv->page_setup);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+gboolean
+gtk_print_job_send (GtkPrintJob *print_job,
+                    GtkPrintJobCompleteFunc callback,
+                    gpointer user_data,
+                   GDestroyNotify dnotify,
+                   GError **error)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_JOB (print_job), FALSE);
+  g_return_val_if_fail (print_job->priv->spool_file_fd > 0, FALSE);
+
+  gtk_print_job_set_status (print_job, GTK_PRINT_STATUS_SENDING_DATA);
+  lseek (print_job->priv->spool_file_fd, 0, SEEK_SET);
+  gtk_print_backend_print_stream (print_job->priv->backend,
+                                  print_job,
+                                 print_job->priv->spool_file_fd,
+                                  callback,
+                                  user_data,
+                                 dnotify);
+
+  return TRUE;
+}
+
+#define __GTK_PRINT_JOB_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintjob.h b/gtk/gtkprintjob.h
new file mode 100644 (file)
index 0000000..a5116c9
--- /dev/null
@@ -0,0 +1,106 @@
+/* GtkPrintJob 
+ * Copyright (C) 2006 Red Hat,Inc. 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINT_JOB_H__
+#define __GTK_PRINT_JOB_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include <gtk/gtkprinter.h>
+#include <gtk/gtkprintoperation.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_JOB                  (gtk_print_job_get_type ())
+#define GTK_PRINT_JOB(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_JOB, GtkPrintJob))
+#define GTK_PRINT_JOB_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_JOB, GtkPrintJobClass))
+#define GTK_IS_PRINT_JOB(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_JOB))
+#define GTK_IS_PRINT_JOB_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_JOB))
+#define GTK_PRINT_JOB_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_JOB, GtkPrintJobClass))
+
+
+typedef struct _GtkPrintJobClass     GtkPrintJobClass;
+typedef struct _GtkPrintJobPrivate   GtkPrintJobPrivate;
+
+typedef void (*GtkPrintJobCompleteFunc) (GtkPrintJob *print_job,
+                                         void *user_data, 
+                                         GError *error);
+
+struct _GtkPrinter;
+
+struct _GtkPrintJob
+{
+  GObject parent_instance;
+
+  GtkPrintJobPrivate *priv;
+
+  /* Settings the client has to implement:
+   * (These are read-only, set at initialization)
+   */
+  GtkPrintPages print_pages;
+  GtkPageRange *page_ranges;
+  int num_page_ranges;
+  GtkPageSet page_set;
+  int num_copies;
+  gboolean collate;
+  gboolean reverse;
+  double scale;
+  gboolean rotate_to_orientation;
+};
+
+struct _GtkPrintJobClass
+{
+  GObjectClass parent_class;
+
+  void (*status_changed) (GtkPrintJob *job);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType                    gtk_print_job_get_type     (void) G_GNUC_CONST;
+GtkPrintJob             *gtk_print_job_new          (const gchar              *title,
+                                                    GtkPrinter               *printer,
+                                                    GtkPrintSettings         *settings,
+                                                    GtkPageSetup             *page_setup);
+GtkPrintSettings        *gtk_print_job_get_settings (GtkPrintJob              *print_job);
+GtkPrinter              *gtk_print_job_get_printer  (GtkPrintJob              *print_job);
+const char              *gtk_print_job_get_title    (GtkPrintJob              *print_job);
+GtkPrintStatus           gtk_print_job_get_status   (GtkPrintJob              *print_job);
+
+gboolean                 gtk_print_job_set_source_file (GtkPrintJob              *print_job,
+                                                       const char               *filename,
+                                                       GError                  **error);
+cairo_surface_t         *gtk_print_job_get_surface     (GtkPrintJob              *print_job,
+                                                       GError                  **error);
+gboolean                 gtk_print_job_send            (GtkPrintJob              *print_job,
+                                                       GtkPrintJobCompleteFunc   callback,
+                                                       gpointer                  user_data,
+                                                       GDestroyNotify            dnotify,
+                                                       GError                  **error);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_JOB_H__ */
diff --git a/gtk/gtkprintoperation-private.h b/gtk/gtkprintoperation-private.h
new file mode 100644 (file)
index 0000000..5109e9c
--- /dev/null
@@ -0,0 +1,87 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation.h: Print Operation
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_OPERATION_PRIVATE_H__
+#define __GTK_PRINT_OPERATION_PRIVATE_H__
+
+#include "gtkprintoperation.h"
+
+G_BEGIN_DECLS
+
+struct _GtkPrintOperationPrivate
+{
+  GtkPrintStatus status;
+  char *status_string;
+  GtkPageSetup *default_page_setup;
+  GtkPrintSettings *print_settings;
+  char *job_name;
+  int nr_of_pages;
+  int current_page;
+  gboolean use_full_page;
+  GtkUnit unit;
+  gboolean show_dialog;
+  char *pdf_target;
+
+  /* Data for the print job: */
+  cairo_surface_t *surface;
+  double dpi_x, dpi_y;
+
+  GtkPrintPages print_pages;
+  GtkPageRange *page_ranges;
+  int num_page_ranges;
+  
+  int manual_num_copies;
+  gboolean manual_collation;
+  gboolean manual_reverse;
+  gboolean manual_orientation;
+  double manual_scale;
+  GtkPageSet manual_page_set;
+  void *platform_data;
+
+  void (*start_page) (GtkPrintOperation *operation,
+                     GtkPrintContext *print_context,
+                     GtkPageSetup *page_setup);
+  void (*end_page) (GtkPrintOperation *operation,
+                   GtkPrintContext *print_context);
+  void (*end_run) (GtkPrintOperation *operation);
+  GDestroyNotify free_platform_data;
+};
+
+GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *operation,
+                                                                         GtkWindow *parent,
+                                                                         gboolean *do_print,
+                                                                         GError **error);
+
+void _gtk_print_operation_set_status (GtkPrintOperation *op,
+                                     GtkPrintStatus status,
+                                     const char *string);
+
+/* GtkPrintContext private functions: */
+
+GtkPrintContext *_gtk_print_context_new                             (GtkPrintOperation *op);
+void             _gtk_print_context_set_page_setup                  (GtkPrintContext   *context,
+                                                                    GtkPageSetup      *page_setup);
+void             _gtk_print_context_translate_into_margin           (GtkPrintContext   *context);
+void             _gtk_print_context_rotate_according_to_orientation (GtkPrintContext   *context);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_OPERATION_PRIVATE_H__ */
diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c
new file mode 100644 (file)
index 0000000..936bc52
--- /dev/null
@@ -0,0 +1,243 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation-unix.c: Print Operation Details for Unix and Unix like platforms
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "gtkprintoperation-private.h"
+#include "gtkmarshal.h"
+#include "gtkmessagedialog.h"
+
+#include "gtkprintunixdialog.h"
+#include "gtkpagesetupunixdialog.h"
+#include "gtkprintbackend.h"
+#include "gtkprinter.h"
+#include "gtkprintjob.h"
+#include "gtkalias.h"
+
+typedef struct {
+  GtkPrintJob *job;         /* the job we are sending to the printer */
+  gulong job_status_changed_tag;
+  GtkWindow *parent;        /* parent window just in case we need to throw error dialogs */
+} GtkPrintOperationUnix;
+
+static void
+unix_start_page (GtkPrintOperation *op,
+                GtkPrintContext *print_context,
+                GtkPageSetup *page_setup)
+{
+
+}
+
+static void
+unix_end_page (GtkPrintOperation *op,
+              GtkPrintContext *print_context)
+{
+  cairo_t *cr;
+
+  cr = gtk_print_context_get_cairo (print_context);
+  cairo_show_page (cr);
+}
+
+static void
+op_unix_free (GtkPrintOperationUnix *op_unix)
+{
+  if (op_unix->job)
+    {
+      g_signal_handler_disconnect (op_unix->job,
+                                  op_unix->job_status_changed_tag);
+      g_object_unref (op_unix->job);
+    }
+
+  g_free (op_unix);
+}
+
+static void
+unix_finish_send  (GtkPrintJob *job,
+                   void *user_data, 
+                   GError *error)
+{
+  GtkPrintOperationUnix *op_unix;
+  GtkWindow *parent;
+
+  op_unix = (GtkPrintOperationUnix *) user_data;
+
+  parent = op_unix->parent;
+
+  if (error != NULL)
+    {
+      GtkWidget *edialog;
+      edialog = gtk_message_dialog_new (parent, 
+                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR,
+                                        GTK_BUTTONS_CLOSE,
+                                        "Error printing: %s",
+                                        error->message);
+
+      gtk_dialog_run (GTK_DIALOG (edialog));
+      gtk_widget_destroy (edialog);
+    }
+}
+
+static void
+unix_end_run (GtkPrintOperation *op)
+{
+  GtkPrintOperationUnix *op_unix = op->priv->platform_data;
+  /* TODO: Check for error */
+  gtk_print_job_send (op_unix->job,
+                      unix_finish_send, 
+                      op_unix, NULL,
+                     NULL);
+}
+
+static void
+job_status_changed_cb (GtkPrintJob *job, GtkPrintOperation *op)
+{
+  _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
+}
+
+GtkPrintOperationResult
+_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
+                                                 GtkWindow *parent,
+                                                 gboolean *do_print,
+                                                 GError **error)
+{
+  GtkWidget *pd;
+  GtkPrintOperationResult result;
+  GtkPageSetup *page_setup;
+  
+  result = GTK_PRINT_OPERATION_RESULT_CANCEL;
+
+  if (op->priv->default_page_setup)
+    page_setup = gtk_page_setup_copy (op->priv->default_page_setup);
+  else
+    page_setup = gtk_page_setup_new ();
+
+  pd = gtk_print_unix_dialog_new (NULL, parent);
+
+  if (op->priv->print_settings)
+    gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
+                                       op->priv->print_settings);
+
+  gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), page_setup);
+  
+  *do_print = FALSE; 
+  if (gtk_dialog_run (GTK_DIALOG (pd)) == GTK_RESPONSE_OK)
+    {
+      GtkPrintOperationUnix *op_unix;
+      GtkPrinter *printer;
+      GtkPrintSettings *settings;
+
+      result = GTK_PRINT_OPERATION_RESULT_APPLY;
+      
+      printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
+      if (printer == NULL)
+       goto out;
+      
+      *do_print = TRUE;
+
+      settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
+      gtk_print_operation_set_print_settings (op, settings);
+
+      op_unix = g_new0 (GtkPrintOperationUnix, 1);
+      op_unix->job = gtk_print_job_new (op->priv->job_name,
+                                       printer,
+                                       settings,
+                                       page_setup);
+      g_object_unref (settings);
+
+      op->priv->surface = gtk_print_job_get_surface (op_unix->job, error);
+      if (op->priv->surface == NULL)
+        {
+         *do_print = FALSE;
+         op_unix_free (op_unix);
+         result = GTK_PRINT_OPERATION_RESULT_ERROR;
+         goto out;
+       }
+
+      _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
+      op_unix->job_status_changed_tag =
+       g_signal_connect (op_unix->job, "status_changed",
+                         G_CALLBACK (job_status_changed_cb), op);
+      
+      op_unix->parent = parent;
+
+      op->priv->dpi_x = 72;
+      op->priv->dpi_y = 72;
+      op->priv->platform_data = op_unix;
+      op->priv->free_platform_data = (GDestroyNotify) op_unix_free;
+
+      op->priv->print_pages = op_unix->job->print_pages;
+      op->priv->page_ranges = op_unix->job->page_ranges;
+      op->priv->num_page_ranges = op_unix->job->num_page_ranges;
+  
+      op->priv->manual_num_copies = op_unix->job->num_copies;
+      op->priv->manual_collation = op_unix->job->collate;
+      op->priv->manual_reverse = op_unix->job->reverse;
+      op->priv->manual_page_set = op_unix->job->page_set;
+      op->priv->manual_scale = op_unix->job->scale;
+      op->priv->manual_orientation = op_unix->job->rotate_to_orientation;
+    } 
+
+  op->priv->start_page = unix_start_page;
+  op->priv->end_page = unix_end_page;
+  op->priv->end_run = unix_end_run;
+
+ out:
+  g_object_unref (page_setup); 
+  
+  gtk_widget_destroy (pd);
+
+  return result;
+}
+
+GtkPageSetup *
+gtk_print_run_page_setup_dialog (GtkWindow        *parent,
+                                GtkPageSetup     *page_setup,
+                                GtkPrintSettings *settings)
+{
+  GtkWidget *dialog;
+  GtkPageSetup *new_page_setup;
+  
+  dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
+  if (page_setup)
+    gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
+                                              page_setup);
+  gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
+                                                settings);
+  gtk_dialog_run (GTK_DIALOG (dialog));
+
+  new_page_setup = gtk_page_setup_unix_dialog_get_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+
+  return new_page_setup;
+}
+
+
+#define __GTK_PRINT_OPERATION_UNIX_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c
new file mode 100644 (file)
index 0000000..7f441ab
--- /dev/null
@@ -0,0 +1,1598 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation-win32.c: Print Operation Details for Win32
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MSC_VER
+#define _WIN32_WINNT 0x0500
+#define WINVER _WIN32_WINNT
+#endif
+
+#define COBJMACROS
+#include "config.h"
+#include <math.h>
+#include <stdlib.h>
+#include <cairo-win32.h>
+#include <glib.h>
+#include "gtkprintoperation-private.h"
+#include "gtkprint-win32.h"
+#include "gtkintl.h"
+#include "gtkinvisible.h"
+#include "gtkalias.h"
+
+#define MAX_PAGE_RANGES 20
+#define STATUS_POLLING_TIME 2000
+
+#ifndef JOB_STATUS_RESTART
+#define JOB_STATUS_RESTART 0x800
+#endif
+
+#ifndef JOB_STATUS_COMPLETE
+#define JOB_STATUS_COMPLETE 0x1000
+#endif
+
+typedef struct {
+  HDC hdc;
+  HGLOBAL devmode;
+  HGLOBAL devnames;
+  HANDLE printerHandle;
+  int job_id;
+  guint timeout_id;
+} GtkPrintOperationWin32;
+
+static void win32_poll_status (GtkPrintOperation *op);
+
+static const GUID myIID_IPrintDialogCallback  = {0x5852a2c3,0x6530,0x11d1,{0xb6,0xa3,0x0,0x0,0xf8,0x75,0x7b,0xf9}};
+
+#undef INTERFACE
+#define INTERFACE IPrintDialogCallback
+DECLARE_INTERFACE_ (IPrintDialogCallback, IUnknown)
+{
+    STDMETHOD (QueryInterface)(THIS_ REFIID,LPVOID*) PURE;
+    STDMETHOD_ (ULONG, AddRef)(THIS) PURE;
+    STDMETHOD_ (ULONG, Release)(THIS) PURE;
+    STDMETHOD (InitDone)(THIS) PURE;
+    STDMETHOD (SelectionChange)(THIS) PURE;
+    STDMETHOD (HandleMessage)(THIS_ HWND,UINT,WPARAM,LPARAM,LRESULT*) PURE;
+}; 
+
+static UINT got_gdk_events_message;
+
+UINT_PTR CALLBACK
+run_mainloop_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+  if (uiMsg == WM_INITDIALOG)
+    {
+      gdk_win32_set_modal_dialog_libgtk_only (hdlg);
+      while (gtk_events_pending ())
+       gtk_main_iteration ();
+    }
+  else if (uiMsg == got_gdk_events_message)
+    {
+      while (gtk_events_pending ())
+       gtk_main_iteration ();
+      return 1;
+    }
+  return 0;
+}
+
+static GtkPageOrientation
+orientation_from_win32 (short orientation)
+{
+  if (orientation == DMORIENT_LANDSCAPE)
+    return GTK_PAGE_ORIENTATION_LANDSCAPE;
+  return GTK_PAGE_ORIENTATION_PORTRAIT;
+}
+
+static short
+orientation_to_win32 (GtkPageOrientation orientation)
+{
+  if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE ||
+      orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
+    return DMORIENT_LANDSCAPE;
+  return DMORIENT_PORTRAIT;
+}
+
+static GtkPaperSize *
+paper_size_from_win32 (short size)
+{
+  const char *name;
+  
+  switch (size)
+    {
+    case DMPAPER_LETTER_TRANSVERSE:
+    case DMPAPER_LETTER:
+    case DMPAPER_LETTERSMALL:
+      name = "na_letter";
+      break;
+    case DMPAPER_TABLOID:
+    case DMPAPER_LEDGER:
+      name = "na_ledger";
+      break;
+    case DMPAPER_LEGAL:
+      name = "na_legal";
+      break;
+    case DMPAPER_STATEMENT:
+      name = "na_invoice";
+      break;
+    case DMPAPER_EXECUTIVE:
+      name = "na_executive";
+      break;
+    case DMPAPER_A3:
+    case DMPAPER_A3_TRANSVERSE:
+      name = "iso_a3";
+      break;
+    case DMPAPER_A4:
+    case DMPAPER_A4SMALL:
+    case DMPAPER_A4_TRANSVERSE:
+      name = "iso_a4";
+      break;
+    case DMPAPER_A5:
+    case DMPAPER_A5_TRANSVERSE:
+      name = "iso_a5";
+      break;
+    case DMPAPER_B4:
+      name = "jis_b4";
+      break;
+    case DMPAPER_B5:
+    case DMPAPER_B5_TRANSVERSE:
+      name = "jis_b5";
+      break;
+    case DMPAPER_QUARTO:
+      name = "na_quarto";
+      break;
+    case DMPAPER_10X14:
+      name = "na_10x14";
+      break;
+    case DMPAPER_11X17:
+      name = "na_ledger";
+      break;
+    case DMPAPER_NOTE:
+      name = "na_letter";
+      break;
+    case DMPAPER_ENV_9:
+      name = "na_number-9";
+      break;
+    case DMPAPER_ENV_10:
+      name = "na_number-10";
+      break;
+    case DMPAPER_ENV_11:
+      name = "na_number-11";
+      break;
+    case DMPAPER_ENV_12:
+      name = "na_number-12";
+      break;
+    case DMPAPER_ENV_14:
+      name = "na_number-14";
+      break;
+    case DMPAPER_CSHEET:
+      name = "na_c";
+      break;
+    case DMPAPER_DSHEET:
+      name = "na_d";
+      break;
+    case DMPAPER_ESHEET:
+      name = "na_e";
+      break;
+    case DMPAPER_ENV_DL:
+      name = "iso_dl";
+      break;
+    case DMPAPER_ENV_C5:
+      name = "iso_c5";
+      break;
+    case DMPAPER_ENV_C3:
+      name = "iso_c3";
+      break;
+    case DMPAPER_ENV_C4:
+      name = "iso_c4";
+      break;
+    case DMPAPER_ENV_C6:
+      name = "iso_c6";
+      break;
+    case DMPAPER_ENV_C65:
+      name = "iso_c6c5";
+      break;
+    case DMPAPER_ENV_B4:
+      name = "iso_b4";
+      break;
+    case DMPAPER_ENV_B5:
+      name = "iso_b5";
+      break;
+    case DMPAPER_ENV_B6:
+      name = "iso_b6";
+      break;
+    case DMPAPER_ENV_ITALY:
+      name = "om_italian";
+      break;
+    case DMPAPER_ENV_MONARCH:
+      name = "na_monarch";
+      break;
+    case DMPAPER_ENV_PERSONAL:
+      name = "na_personal";
+      break;
+    case DMPAPER_FANFOLD_US:
+      name = "na_fanfold-us";
+      break;
+    case DMPAPER_FANFOLD_STD_GERMAN:
+      name = "na_fanfold-eur";
+      break;
+    case DMPAPER_FANFOLD_LGL_GERMAN:
+      name = "na_foolscap";
+      break;
+    case DMPAPER_ISO_B4:
+      name = "iso_b4";
+      break;
+    case DMPAPER_JAPANESE_POSTCARD:
+      name = "jpn_hagaki";
+      break;
+    case DMPAPER_9X11:
+      name = "na_9x11";
+      break;
+    case DMPAPER_10X11:
+      name = "na_10x11";
+      break;
+    case DMPAPER_ENV_INVITE:
+      name = "om_invite";
+       break;
+    case DMPAPER_LETTER_EXTRA:
+    case DMPAPER_LETTER_EXTRA_TRANSVERSE:
+      name = "na_letter-extra";
+      break;
+    case DMPAPER_LEGAL_EXTRA:
+      name = "na_legal-extra";
+      break;
+    case DMPAPER_TABLOID_EXTRA:
+      name = "na_arch";
+      break;
+    case DMPAPER_A4_EXTRA:
+      name = "iso_a4-extra";
+      break;
+    case DMPAPER_B_PLUS:
+      name = "na_b-plus";
+      break;
+    case DMPAPER_LETTER_PLUS:
+      name = "na_letter-plus";
+      break;
+    case DMPAPER_A3_EXTRA:
+    case DMPAPER_A3_EXTRA_TRANSVERSE:
+      name = "iso_a3-extra";
+      break;
+    case DMPAPER_A5_EXTRA:
+      name = "iso_a5-extra";
+      break;
+    case DMPAPER_B5_EXTRA:
+      name = "iso_b5-extra";
+      break;
+    case DMPAPER_A2:
+      name = "iso_a2";
+      break;
+      
+    default:
+      name = NULL;
+      break;
+    }
+
+  if (name)
+    return gtk_paper_size_new (name);
+  else 
+    return NULL;
+}
+
+static short
+paper_size_to_win32 (GtkPaperSize *paper_size)
+{
+  const char *format;
+
+  if (gtk_paper_size_is_custom (paper_size))
+    return 0;
+  
+  format = gtk_paper_size_get_name (paper_size);
+
+  if (strcmp (format, "na_letter") == 0)
+    return DMPAPER_LETTER;
+  if (strcmp (format, "na_ledger") == 0)
+    return DMPAPER_LEDGER;
+  if (strcmp (format, "na_legal") == 0)
+    return DMPAPER_LEGAL;
+  if (strcmp (format, "na_invoice") == 0)
+    return DMPAPER_STATEMENT;
+  if (strcmp (format, "na_executive") == 0)
+    return DMPAPER_EXECUTIVE;
+  if (strcmp (format, "iso_a2") == 0)
+    return DMPAPER_A2;
+  if (strcmp (format, "iso_a3") == 0)
+    return DMPAPER_A3;
+  if (strcmp (format, "iso_a4") == 0)
+    return DMPAPER_A4;
+  if (strcmp (format, "iso_a5") == 0)
+    return DMPAPER_A5;
+  if (strcmp (format, "iso_b4") == 0)
+    return DMPAPER_B4;
+  if (strcmp (format, "iso_b5") == 0)
+    return DMPAPER_B5;
+  if (strcmp (format, "na_quarto") == 0)
+    return DMPAPER_QUARTO;
+  if (strcmp (format, "na_10x14") == 0)
+    return DMPAPER_10X14;
+  if (strcmp (format, "na_number-9") == 0)
+    return DMPAPER_ENV_9;
+  if (strcmp (format, "na_number-10") == 0)
+    return DMPAPER_ENV_10;
+  if (strcmp (format, "na_number-11") == 0)
+    return DMPAPER_ENV_11;
+  if (strcmp (format, "na_number-12") == 0)
+    return DMPAPER_ENV_12;
+  if (strcmp (format, "na_number-14") == 0)
+    return DMPAPER_ENV_14;
+  if (strcmp (format, "na_c") == 0)
+    return DMPAPER_CSHEET;
+  if (strcmp (format, "na_d") == 0)
+    return DMPAPER_DSHEET;
+  if (strcmp (format, "na_e") == 0)
+    return DMPAPER_ESHEET;
+  if (strcmp (format, "iso_dl") == 0)
+    return DMPAPER_ENV_DL;
+  if (strcmp (format, "iso_c3") == 0)
+    return DMPAPER_ENV_C3;
+  if (strcmp (format, "iso_c4") == 0)
+    return DMPAPER_ENV_C4;
+  if (strcmp (format, "iso_c5") == 0)
+    return DMPAPER_ENV_C5;
+  if (strcmp (format, "iso_c6") == 0)
+    return DMPAPER_ENV_C6;
+  if (strcmp (format, "iso_c5c6") == 0)
+    return DMPAPER_ENV_C65;
+  if (strcmp (format, "iso_b6") == 0)
+    return DMPAPER_ENV_B6;
+  if (strcmp (format, "om_italian") == 0)
+    return DMPAPER_ENV_ITALY;
+  if (strcmp (format, "na_monarch") == 0)
+    return DMPAPER_ENV_MONARCH;
+  if (strcmp (format, "na_personal") == 0)
+    return DMPAPER_ENV_PERSONAL;
+  if (strcmp (format, "na_fanfold-us") == 0)
+    return DMPAPER_FANFOLD_US;
+  if (strcmp (format, "na_fanfold-eur") == 0)
+    return DMPAPER_FANFOLD_STD_GERMAN;
+  if (strcmp (format, "na_foolscap") == 0)
+    return DMPAPER_FANFOLD_LGL_GERMAN;
+  if (strcmp (format, "jpn_hagaki") == 0)
+    return DMPAPER_JAPANESE_POSTCARD;
+  if (strcmp (format, "na_9x11") == 0)
+    return DMPAPER_9X11;
+  if (strcmp (format, "na_10x11") == 0)
+    return DMPAPER_10X11;
+  if (strcmp (format, "om_invite") == 0)
+    return DMPAPER_ENV_INVITE;
+  if (strcmp (format, "na_letter-extra") == 0)
+    return DMPAPER_LETTER_EXTRA;
+  if (strcmp (format, "na_legal-extra") == 0)
+    return DMPAPER_LEGAL_EXTRA;
+  if (strcmp (format, "na_arch") == 0)
+    return DMPAPER_TABLOID_EXTRA;
+  if (strcmp (format, "iso_a3-extra") == 0)
+    return DMPAPER_A3_EXTRA;
+  if (strcmp (format, "iso_a4-extra") == 0)
+    return DMPAPER_A4_EXTRA;
+  if (strcmp (format, "iso_a5-extra") == 0)
+    return DMPAPER_A5_EXTRA;
+  if (strcmp (format, "iso_b5-extra") == 0)
+    return DMPAPER_B5_EXTRA;
+  if (strcmp (format, "na_b-plus") == 0)
+    return DMPAPER_B_PLUS;
+  if (strcmp (format, "na_letter-plus") == 0)
+    return DMPAPER_LETTER_PLUS;
+
+  return 0;
+}
+
+void
+win32_start_page (GtkPrintOperation *op,
+                 GtkPrintContext *print_context,
+                 GtkPageSetup *page_setup)
+{
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+  LPDEVMODEW devmode;
+  GtkPaperSize *paper_size;
+
+  devmode = GlobalLock (op_win32->devmode);
+  
+  devmode->dmFields |= DM_ORIENTATION;
+  devmode->dmOrientation =
+    orientation_to_win32 (gtk_page_setup_get_orientation (page_setup));
+  
+  paper_size = gtk_page_setup_get_paper_size (page_setup);
+  devmode->dmFields |= DM_PAPERSIZE;
+  devmode->dmFields &= ~(DM_PAPERWIDTH | DM_PAPERLENGTH);
+  devmode->dmPaperSize = paper_size_to_win32 (paper_size);
+  if (devmode->dmPaperSize == 0)
+    {
+      devmode->dmPaperSize = DMPAPER_USER;
+      devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
+      devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) * 10.0;
+      devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) * 10.0;
+    }
+  
+  ResetDCW (op_win32->hdc, devmode);
+  
+  GlobalUnlock (op_win32->devmode);
+  
+  StartPage (op_win32->hdc);
+}
+
+static void
+win32_end_page (GtkPrintOperation *op,
+               GtkPrintContext *print_context)
+{
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+  EndPage (op_win32->hdc);
+}
+
+static gboolean
+win32_poll_status_timeout (GtkPrintOperation *op)
+{
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+  
+  op_win32->timeout_id = 0;
+  /* We need to ref this, as setting the status to finished
+     might unref the object */
+  g_object_ref (op);
+  win32_poll_status (op);
+
+  if (!gtk_print_operation_is_finished (op))
+    op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
+                                         (GSourceFunc)win32_poll_status_timeout,
+                                         op);
+  g_object_unref (op);
+  return FALSE;
+}
+
+
+static void
+win32_end_run (GtkPrintOperation *op)
+{
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+  LPDEVNAMES devnames;
+  HANDLE printerHandle = 0;
+  
+  EndDoc (op_win32->hdc);
+  devnames = GlobalLock (op_win32->devnames);
+  if (!OpenPrinterW (((gunichar2 *)devnames) + devnames->wDeviceOffset,
+                    &printerHandle, NULL))
+    printerHandle = 0;
+  GlobalUnlock (op_win32->devnames);
+  
+  GlobalFree(op_win32->devmode);
+  GlobalFree(op_win32->devnames);
+
+  cairo_surface_destroy (op->priv->surface);
+  op->priv->surface = NULL;
+
+  DeleteDC(op_win32->hdc);
+  
+  if (printerHandle != 0)
+    {
+      op_win32->printerHandle = printerHandle;
+      win32_poll_status (op);
+      op_win32->timeout_id = g_timeout_add (STATUS_POLLING_TIME,
+                                           (GSourceFunc)win32_poll_status_timeout,
+                                           op);
+    }
+  else
+    /* Dunno what happened, pretend its finished */
+    _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL);
+}
+
+static void
+win32_poll_status (GtkPrintOperation *op)
+{
+  GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
+  guchar *data;
+  DWORD needed;
+  JOB_INFO_1W *job_info;
+  GtkPrintStatus status;
+  char *status_str;
+  BOOL ret;
+
+  GetJobW (op_win32->printerHandle, op_win32->job_id,
+          1,(LPBYTE)NULL, 0, &needed);
+  data = g_malloc (needed);
+  ret = GetJobW (op_win32->printerHandle, op_win32->job_id,
+                1, (LPBYTE)data, needed, &needed);
+
+  status_str = NULL;
+  if (ret)
+    {
+      job_info = (JOB_INFO_1W *)data;
+      DWORD win32_status = job_info->Status;
+
+      if (job_info->pStatus)
+       status_str = g_utf16_to_utf8 (job_info->pStatus, 
+                                     -1, NULL, NULL, NULL);
+     
+      if (win32_status &
+         (JOB_STATUS_COMPLETE | JOB_STATUS_PRINTED))
+       status = GTK_PRINT_STATUS_FINISHED;
+      else if (win32_status &
+              (JOB_STATUS_OFFLINE |
+               JOB_STATUS_PAPEROUT |
+               JOB_STATUS_PAUSED |
+               JOB_STATUS_USER_INTERVENTION))
+       {
+         status = GTK_PRINT_STATUS_PENDING_ISSUE;
+         if (status_str == NULL)
+           {
+             if (win32_status & JOB_STATUS_OFFLINE)
+               status_str = g_strdup (_("Printer offline"));
+             else if (win32_status & JOB_STATUS_PAPEROUT)
+               status_str = g_strdup (_("Out of paper"));
+             else if (win32_status & JOB_STATUS_PAUSED)
+               status_str = g_strdup (_("Paused"));
+             else if (win32_status & JOB_STATUS_USER_INTERVENTION)
+               status_str = g_strdup (_("Need user intervention"));
+           }
+       }
+      else if (win32_status &
+              (JOB_STATUS_BLOCKED_DEVQ |
+               JOB_STATUS_DELETED |
+               JOB_STATUS_ERROR))
+       status = GTK_PRINT_STATUS_FINISHED_ABORTED;
+      else if (win32_status &
+              (JOB_STATUS_SPOOLING |
+               JOB_STATUS_DELETING))
+       status = GTK_PRINT_STATUS_PENDING;
+      else if (win32_status & JOB_STATUS_PRINTING)
+       status = GTK_PRINT_STATUS_PRINTING;
+      else
+       status = GTK_PRINT_STATUS_FINISHED;
+    }
+  else
+    status = GTK_PRINT_STATUS_FINISHED;
+
+  g_free (data);
+
+  _gtk_print_operation_set_status (op, status, status_str);
+  g_free (status_str);
+}
+
+static void
+op_win32_free (GtkPrintOperationWin32 *op_win32)
+{
+  if (op_win32->printerHandle)
+    ClosePrinter (op_win32->printerHandle);
+  if (op_win32->timeout_id != 0)
+    g_source_remove (op_win32->timeout_id);
+  g_free (op_win32);
+}
+
+static HWND
+get_parent_hwnd (GtkWidget *widget)
+{
+  gtk_widget_realize (widget);
+  return gdk_win32_drawable_get_handle (widget->window);
+}
+
+
+static void
+devnames_to_settings (GtkPrintSettings *settings,
+                     HANDLE hDevNames)
+{
+  GtkPrintWin32Devnames *devnames = gtk_print_win32_devnames_from_win32 (hDevNames);
+  gtk_print_settings_set_printer (settings, devnames->device);
+  gtk_print_win32_devnames_free (devnames);
+}
+
+static void
+devmode_to_settings (GtkPrintSettings *settings,
+                    HANDLE hDevMode)
+{
+  LPDEVMODEW devmode;
+
+  devmode = GlobalLock (hDevMode);
+  
+  gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION,
+                             devmode->dmDriverVersion);
+  if (devmode->dmDriverExtra != 0)
+    {
+      char *extra = g_base64_encode (((char *)devmode) + sizeof (DEVMODEW),
+                                    devmode->dmDriverExtra);
+      gtk_print_settings_set (settings,
+                             GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA,
+                             extra);
+      g_free (extra);
+    }
+  
+  if (devmode->dmFields & DM_ORIENTATION)
+    gtk_print_settings_set_orientation (settings,
+                                       orientation_from_win32 (devmode->dmOrientation));
+  
+  
+  if (devmode->dmFields & DM_PAPERSIZE &&
+      devmode->dmPaperSize != 0)
+    {
+      GtkPaperSize *paper_size = paper_size_from_win32 (devmode->dmPaperSize);
+      if (paper_size)
+       {
+         gtk_print_settings_set_paper_size (settings, paper_size);
+         gtk_paper_size_free (paper_size);
+       }
+      gtk_print_settings_set_int (settings, "win32-paper-size", (int)devmode->dmPaperSize);
+    }
+  else if ((devmode->dmFields & DM_PAPERSIZE &&
+           devmode->dmPaperSize == 0) ||
+          ((devmode->dmFields & DM_PAPERWIDTH) &&
+           (devmode->dmFields & DM_PAPERLENGTH)))
+    {
+      GtkPaperSize *paper_size;
+      char *form_name = NULL;
+      if (devmode->dmFields & DM_FORMNAME)
+       form_name = g_utf16_to_utf8 (devmode->dmFormName, 
+                                    -1, NULL, NULL, NULL);
+      if (form_name == NULL || form_name[0] == 0)
+       form_name = g_strdup (_("Custom size"));
+      paper_size = gtk_paper_size_new_custom (form_name,
+                                             form_name,
+                                             devmode->dmPaperWidth * 10.0,
+                                             devmode->dmPaperLength * 10.0,
+                                             GTK_UNIT_MM);
+      gtk_print_settings_set_paper_size (settings, paper_size);
+      gtk_paper_size_free (paper_size);
+    }
+  
+  if (devmode->dmFields & DM_SCALE)
+    gtk_print_settings_set_scale (settings,
+                                 devmode->dmScale / 100.0);
+  
+  if (devmode->dmFields & DM_COPIES)
+    gtk_print_settings_set_num_copies (settings,
+                                      devmode->dmCopies);
+  
+  if (devmode->dmFields & DM_DEFAULTSOURCE)
+    {
+      char *source;
+      switch (devmode->dmDefaultSource)
+       {
+       default:
+       case DMBIN_AUTO:
+         source = "auto";
+         break;
+       case DMBIN_CASSETTE:
+         source = "cassette";
+         break;
+       case DMBIN_ENVELOPE:
+         source = "envelope";
+         break;
+       case DMBIN_ENVMANUAL:
+         source = "envelope-manual";
+         break;
+       case DMBIN_LOWER:
+         source = "lower";
+         break;
+       case DMBIN_MANUAL:
+         source = "manual";
+         break;
+       case DMBIN_MIDDLE:
+         source = "middle";
+         break;
+       case DMBIN_ONLYONE:
+         source = "only-one";
+         break;
+       case DMBIN_FORMSOURCE:
+         source = "form-source";
+         break;
+       case DMBIN_LARGECAPACITY:
+         source = "large-capacity";
+         break;
+       case DMBIN_LARGEFMT:
+         source = "large-format";
+         break;
+       case DMBIN_TRACTOR:
+         source = "tractor";
+         break;
+       case DMBIN_SMALLFMT:
+         source = "small-format";
+         break;
+       }
+      gtk_print_settings_set_default_source (settings, source);
+      gtk_print_settings_set_int (settings, "win32-default-source", devmode->dmDefaultSource);
+    }
+  
+  if (devmode->dmFields & DM_PRINTQUALITY)
+    {
+      GtkPrintQuality quality;
+      switch (devmode->dmPrintQuality)
+       {
+       case DMRES_LOW:
+         quality = GTK_PRINT_QUALITY_LOW;
+         break;
+       case DMRES_MEDIUM:
+         quality = GTK_PRINT_QUALITY_NORMAL;
+         break;
+       default:
+       case DMRES_HIGH:
+         quality = GTK_PRINT_QUALITY_HIGH;
+         break;
+       case DMRES_DRAFT:
+         quality = GTK_PRINT_QUALITY_DRAFT;
+         break;
+       }
+      gtk_print_settings_set_quality (settings, quality);
+      gtk_print_settings_set_int (settings, "win32-print-quality", devmode->dmPrintQuality);
+    }
+  
+  if (devmode->dmFields & DM_COLOR)
+    gtk_print_settings_set_use_color (settings, devmode->dmFields == DMCOLOR_COLOR);
+  
+  if (devmode->dmFields & DM_DUPLEX)
+    {
+      GtkPrintDuplex duplex;
+      switch (devmode->dmDuplex)
+       {
+       default:
+       case DMDUP_SIMPLEX:
+         duplex = GTK_PRINT_DUPLEX_SIMPLEX;
+         break;
+       case DMDUP_HORIZONTAL:
+         duplex = GTK_PRINT_DUPLEX_HORIZONTAL;
+         break;
+       case DMDUP_VERTICAL:
+         duplex = GTK_PRINT_DUPLEX_VERTICAL;
+         break;
+       }
+      
+      gtk_print_settings_set_duplex (settings, duplex);
+    }
+  
+  if (devmode->dmFields & DM_COLLATE)
+    gtk_print_settings_set_collate (settings,
+                                   devmode->dmCollate == DMCOLLATE_TRUE);
+  
+  if (devmode->dmFields & DM_MEDIATYPE)
+    {
+      char *media_type;
+      switch (devmode->dmMediaType)
+       {
+       default:
+       case DMMEDIA_STANDARD:
+         media_type = "stationery";
+         break;
+       case DMMEDIA_TRANSPARENCY:
+         media_type = "transparency";
+         break;
+       case DMMEDIA_GLOSSY:
+         media_type = "photographic-glossy";
+         break;
+       }
+      gtk_print_settings_set_media_type (settings, media_type);
+      gtk_print_settings_set_int (settings, "win32-media-type", devmode->dmMediaType);
+    }
+  
+  if (devmode->dmFields & DM_DITHERTYPE)
+    {
+      char *dither;
+      switch (devmode->dmDitherType)
+       {
+       default:
+       case DMDITHER_FINE:
+         dither = "fine";
+         break;
+       case DMDITHER_NONE:
+         dither = "none";
+         break;
+       case DMDITHER_COARSE:
+         dither = "coarse";
+         break;
+       case DMDITHER_LINEART:
+         dither = "lineart";
+         break;
+       case DMDITHER_GRAYSCALE:
+         dither = "grayscale";
+         break;
+       case DMDITHER_ERRORDIFFUSION:
+         dither = "error-diffusion";
+         break;
+       }
+      gtk_print_settings_set_dither (settings, dither);
+      gtk_print_settings_set_int (settings, "win32-dither-type", devmode->dmDitherType);
+    }
+  
+  GlobalUnlock (hDevMode);
+}
+
+static void
+dialog_to_print_settings (GtkPrintOperation *op,
+                         LPPRINTDLGEXW printdlgex)
+{
+  int i;
+  GtkPrintSettings *settings;
+
+  settings = gtk_print_settings_new ();
+
+  gtk_print_settings_set_print_pages (settings,
+                                     GTK_PRINT_PAGES_ALL);
+  if (printdlgex->Flags & PD_CURRENTPAGE)
+    gtk_print_settings_set_print_pages (settings,
+                                       GTK_PRINT_PAGES_CURRENT);
+  else if (printdlgex->Flags & PD_PAGENUMS)
+    gtk_print_settings_set_print_pages (settings,
+                                       GTK_PRINT_PAGES_RANGES);
+
+  if (printdlgex->nPageRanges > 0)
+    {
+      GtkPageRange *ranges;
+      ranges = g_new (GtkPageRange, printdlgex->nPageRanges);
+
+      for (i = 0; i < printdlgex->nPageRanges; i++)
+       {
+         ranges[i].start = printdlgex->lpPageRanges[i].nFromPage - 1;
+         ranges[i].end = printdlgex->lpPageRanges[i].nToPage - 1;
+       }
+
+      gtk_print_settings_set_page_ranges (settings, ranges,
+                                         printdlgex->nPageRanges);
+      g_free (ranges);
+    }
+  
+  if (printdlgex->hDevNames != NULL)
+    devnames_to_settings (settings, printdlgex->hDevNames);
+
+  if (printdlgex->hDevMode != NULL)
+    devmode_to_settings (settings, printdlgex->hDevMode);
+  
+  gtk_print_operation_set_print_settings (op, settings);
+}
+
+static HANDLE
+devmode_from_settings (GtkPrintSettings *settings,
+                      GtkPageSetup *page_setup)
+{
+  HANDLE hDevMode;
+  LPDEVMODEW devmode;
+  char *extras;
+  GtkPaperSize *paper_size;
+  const char *extras_base64;
+  int extras_len;
+  const char *val;
+
+  extras = NULL;
+  extras_len = 0;
+  extras_base64 = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA);
+  if (extras_base64)
+    extras = g_base64_decode (extras_base64, &extras_len);
+  
+  hDevMode = GlobalAlloc (GMEM_MOVEABLE, 
+                         sizeof (DEVMODEW) + extras_len);
+
+  devmode = GlobalLock (hDevMode);
+
+  memset (devmode, 0, sizeof (DEVMODEW));
+  
+  devmode->dmSpecVersion = DM_SPECVERSION;
+  devmode->dmSize = sizeof (DEVMODEW);
+  
+  devmode->dmDriverExtra = 0;
+  if (extras && extras_len > 0)
+    {
+      devmode->dmDriverExtra = extras_len;
+      memcpy (((char *)devmode) + sizeof (DEVMODEW), extras, extras_len);
+      g_free (extras);
+    }
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION))
+    devmode->dmDriverVersion = gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION);
+  
+  if (page_setup ||
+      gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
+    {
+      GtkPageOrientation orientation = gtk_print_settings_get_orientation (settings);
+      if (page_setup)
+       orientation = gtk_page_setup_get_orientation (page_setup);
+      devmode->dmFields |= DM_ORIENTATION;
+      devmode->dmOrientation = orientation_to_win32 (orientation);
+    }
+
+  if (page_setup)
+    paper_size = gtk_paper_size_copy (gtk_page_setup_get_paper_size (page_setup));
+  else
+    {
+      int size;
+      if (gtk_print_settings_has_key (settings, "win32-paper-size") &&
+         (size = gtk_print_settings_get_int (settings, "win32-paper-size")) != 0)
+       {
+         devmode->dmFields |= DM_PAPERSIZE;
+         devmode->dmPaperSize = size;
+         paper_size = NULL;
+       }
+      else
+       paper_size = gtk_print_settings_get_paper_size (settings);
+    }
+  if (paper_size)
+    {
+      devmode->dmFields |= DM_PAPERSIZE;
+      devmode->dmPaperSize = paper_size_to_win32 (paper_size);
+      if (devmode->dmPaperSize == 0)
+       {
+         devmode->dmPaperSize = DMPAPER_USER;
+         devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
+         devmode->dmPaperWidth = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM) / 10.0;
+         devmode->dmPaperLength = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM) / 10.0;
+       }
+      gtk_paper_size_free (paper_size);
+    }
+
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_SCALE))
+    {
+      devmode->dmFields |= DM_SCALE;
+      devmode->dmScale = gtk_print_settings_get_scale (settings) * 100;
+    }
+  
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_NUM_COPIES))
+    {
+      devmode->dmFields |= DM_COPIES;
+      devmode->dmCopies = gtk_print_settings_get_num_copies (settings);
+    }
+
+  if (gtk_print_settings_has_key (settings, "win32-default-source"))
+    {
+      devmode->dmFields |= DM_DEFAULTSOURCE;
+      devmode->dmDefaultSource = gtk_print_settings_get_int (settings, "win32-default-source");
+    }
+  else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE))
+    {
+      devmode->dmFields |= DM_DEFAULTSOURCE;
+      devmode->dmDefaultSource = DMBIN_AUTO;
+
+      val = gtk_print_settings_get_default_source (settings);
+      if (strcmp (val, "auto") == 0)
+       devmode->dmDefaultSource = DMBIN_AUTO;
+      if (strcmp (val, "cassette") == 0)
+       devmode->dmDefaultSource = DMBIN_CASSETTE;
+      if (strcmp (val, "envelope") == 0)
+       devmode->dmDefaultSource = DMBIN_ENVELOPE;
+      if (strcmp (val, "envelope-manual") == 0)
+       devmode->dmDefaultSource = DMBIN_ENVMANUAL;
+      if (strcmp (val, "lower") == 0)
+       devmode->dmDefaultSource = DMBIN_LOWER;
+      if (strcmp (val, "manual") == 0)
+       devmode->dmDefaultSource = DMBIN_MANUAL;
+      if (strcmp (val, "middle") == 0)
+       devmode->dmDefaultSource = DMBIN_MIDDLE;
+      if (strcmp (val, "only-one") == 0)
+       devmode->dmDefaultSource = DMBIN_ONLYONE;
+      if (strcmp (val, "form-source") == 0)
+       devmode->dmDefaultSource = DMBIN_FORMSOURCE;
+      if (strcmp (val, "large-capacity") == 0)
+       devmode->dmDefaultSource = DMBIN_LARGECAPACITY;
+      if (strcmp (val, "large-format") == 0)
+       devmode->dmDefaultSource = DMBIN_LARGEFMT;
+      if (strcmp (val, "tractor") == 0)
+       devmode->dmDefaultSource = DMBIN_TRACTOR;
+      if (strcmp (val, "small-format") == 0)
+       devmode->dmDefaultSource = DMBIN_SMALLFMT;
+    }
+
+  if (gtk_print_settings_has_key (settings, "win32-print-quality"))
+    {
+      devmode->dmFields |= DM_PRINTQUALITY;
+      devmode->dmPrintQuality = gtk_print_settings_get_int (settings, "win32-print-quality");
+    }
+  else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_RESOLUTION))
+    {
+      devmode->dmFields |= DM_PRINTQUALITY;
+      devmode->dmPrintQuality = gtk_print_settings_get_resolution (settings);
+    } 
+  else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_QUALITY))
+    {
+      devmode->dmFields |= DM_PRINTQUALITY;
+      switch (gtk_print_settings_get_quality (settings))
+       {
+       case GTK_PRINT_QUALITY_LOW:
+         devmode->dmPrintQuality = DMRES_LOW;
+         break;
+       case GTK_PRINT_QUALITY_DRAFT:
+         devmode->dmPrintQuality = DMRES_DRAFT;
+         break;
+       default:
+       case GTK_PRINT_QUALITY_NORMAL:
+         devmode->dmPrintQuality = DMRES_MEDIUM;
+         break;
+       case GTK_PRINT_QUALITY_HIGH:
+         devmode->dmPrintQuality = DMRES_HIGH;
+         break;
+       }
+    }
+
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_USE_COLOR))
+    {
+      devmode->dmFields |= DM_COLOR;
+      if (gtk_print_settings_get_use_color (settings))
+       devmode->dmColor = DMCOLOR_COLOR;
+      else
+       devmode->dmColor = DMCOLOR_MONOCHROME;
+    }
+
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DUPLEX))
+    {
+      devmode->dmFields |= DM_DUPLEX;
+      switch (gtk_print_settings_get_duplex (settings))
+       {
+       default:
+       case GTK_PRINT_DUPLEX_SIMPLEX:
+         devmode->dmDuplex = DMDUP_SIMPLEX;
+         break;
+       case GTK_PRINT_DUPLEX_HORIZONTAL:
+         devmode->dmDuplex = DMDUP_HORIZONTAL;
+         break;
+       case GTK_PRINT_DUPLEX_VERTICAL:
+         devmode->dmDuplex = DMDUP_VERTICAL;
+         break;
+       }
+    }
+
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_COLLATE))
+    {
+      devmode->dmFields |= DM_COLLATE;
+      if (gtk_print_settings_get_collate (settings))
+       devmode->dmCollate = DMCOLLATE_TRUE;
+      else
+       devmode->dmCollate = DMCOLLATE_FALSE;
+    }
+
+  if (gtk_print_settings_has_key (settings, "win32-media-type"))
+    {
+      devmode->dmFields |= DM_MEDIATYPE;
+      devmode->dmMediaType = gtk_print_settings_get_int (settings, "win32-media-type");
+    }
+  else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE))
+    {
+      devmode->dmFields |= DM_MEDIATYPE;
+      devmode->dmMediaType = DMMEDIA_STANDARD;
+      
+      val = gtk_print_settings_get_media_type (settings);
+      if (strcmp (val, "transparency") == 0)
+       devmode->dmMediaType = DMMEDIA_TRANSPARENCY;
+      if (strcmp (val, "photographic-glossy") == 0)
+       devmode->dmMediaType = DMMEDIA_GLOSSY;
+    }
+  if (gtk_print_settings_has_key (settings, "win32-dither-type"))
+    {
+      devmode->dmFields |= DM_DITHERTYPE;
+      devmode->dmDitherType = gtk_print_settings_get_int (settings, "win32-dither-type");
+    }
+  else if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_DITHER))
+    {
+      devmode->dmFields |= DM_DITHERTYPE;
+      devmode->dmDitherType = DMDITHER_FINE;
+      
+      val = gtk_print_settings_get_dither (settings);
+      if (strcmp (val, "none") == 0)
+       devmode->dmDitherType = DMDITHER_NONE;
+      if (strcmp (val, "coarse") == 0)
+       devmode->dmDitherType = DMDITHER_COARSE;
+      if (strcmp (val, "fine") == 0)
+       devmode->dmDitherType = DMDITHER_FINE;
+      if (strcmp (val, "lineart") == 0)
+       devmode->dmDitherType = DMDITHER_LINEART;
+      if (strcmp (val, "grayscale") == 0)
+       devmode->dmDitherType = DMDITHER_GRAYSCALE;
+      if (strcmp (val, "error-diffusion") == 0)
+       devmode->dmDitherType = DMDITHER_ERRORDIFFUSION;
+    }
+  
+  GlobalUnlock (hDevMode);
+
+  return hDevMode;
+}
+
+static void
+dialog_from_print_settings (GtkPrintOperation *op,
+                           LPPRINTDLGEXW printdlgex)
+{
+  GtkPrintSettings *settings = op->priv->print_settings;
+  const char *printer;
+
+  if (settings == NULL)
+    return;
+
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PRINT_PAGES))
+    {
+      GtkPrintPages print_pages = gtk_print_settings_get_print_pages (settings);
+
+      switch (print_pages)
+       {
+       default:
+       case GTK_PRINT_PAGES_ALL:
+         printdlgex->Flags |= PD_ALLPAGES;
+         break;
+       case GTK_PRINT_PAGES_CURRENT:
+         printdlgex->Flags |= PD_CURRENTPAGE;
+         break;
+       case GTK_PRINT_PAGES_RANGES:
+         printdlgex->Flags |= PD_PAGENUMS;
+         break;
+       }
+    }
+  if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_PAGE_RANGES))
+    {
+      GtkPageRange *ranges;
+      int num_ranges, i;
+
+      ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
+
+      if (num_ranges > MAX_PAGE_RANGES)
+       num_ranges = MAX_PAGE_RANGES;
+
+      printdlgex->nPageRanges = num_ranges;
+      for (i = 0; i < num_ranges; i++)
+       {
+         printdlgex->lpPageRanges[i].nFromPage = ranges[i].start + 1;
+         printdlgex->lpPageRanges[i].nToPage = ranges[i].end + 1;
+       }
+    }
+  
+  printer = gtk_print_settings_get_printer (settings);
+  if (printer)
+    printdlgex->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
+  
+  printdlgex->hDevMode = devmode_from_settings (settings,
+                                               op->priv->default_page_setup);
+}
+
+typedef struct {
+  IPrintDialogCallback iPrintDialogCallback;
+  gboolean set_hwnd;
+  int ref_count;
+} PrintDialogCallback;
+
+
+static ULONG STDMETHODCALLTYPE
+iprintdialogcallback_addref (IPrintDialogCallback *This)
+{
+  PrintDialogCallback *callback = (PrintDialogCallback *)This;
+  return ++callback->ref_count;
+}
+
+static ULONG STDMETHODCALLTYPE
+iprintdialogcallback_release (IPrintDialogCallback *This)
+{
+  PrintDialogCallback *callback = (PrintDialogCallback *)This;
+  int ref_count = --callback->ref_count;
+
+  if (ref_count == 0)
+    g_free (This);
+
+  return ref_count;
+}
+
+static HRESULT STDMETHODCALLTYPE
+iprintdialogcallback_queryinterface (IPrintDialogCallback *This,
+                                    REFIID       riid,
+                                    LPVOID      *ppvObject)
+{
+   if (IsEqualIID (riid, &IID_IUnknown) ||
+       IsEqualIID (riid, &myIID_IPrintDialogCallback))
+     {
+       *ppvObject = This;
+       IUnknown_AddRef ((IUnknown *)This);
+       return NOERROR;
+     }
+   else
+     {
+       *ppvObject = NULL;
+       return E_NOINTERFACE;
+     }
+}
+
+static HRESULT STDMETHODCALLTYPE
+iprintdialogcallback_initdone (IPrintDialogCallback *This)
+{
+  return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE
+iprintdialogcallback_selectionchange (IPrintDialogCallback *This)
+{
+  return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE
+iprintdialogcallback_handlemessage (IPrintDialogCallback *This,
+                                   HWND hDlg,
+                                   UINT uMsg,
+                                   WPARAM wParam,
+                                   LPARAM lParam,
+                                   LRESULT *pResult)
+{
+  PrintDialogCallback *callback = (PrintDialogCallback *)This;
+
+  if (!callback->set_hwnd)
+    {
+      gdk_win32_set_modal_dialog_libgtk_only (hDlg);
+      callback->set_hwnd = TRUE;
+      while (gtk_events_pending ())
+       gtk_main_iteration ();
+    }
+  else if (uMsg == got_gdk_events_message)
+    {
+      while (gtk_events_pending ())
+       gtk_main_iteration ();
+      *pResult = TRUE;
+      return S_OK;
+    }
+  
+  *pResult = 0;
+  return S_FALSE;
+}
+
+static IPrintDialogCallbackVtbl ipdc_vtbl = {
+  iprintdialogcallback_queryinterface,
+  iprintdialogcallback_addref,
+  iprintdialogcallback_release,
+  iprintdialogcallback_initdone,
+  iprintdialogcallback_selectionchange,
+  iprintdialogcallback_handlemessage
+};
+
+static IPrintDialogCallback *
+print_callback_new  (void)
+{
+  PrintDialogCallback *callback;
+
+  callback = g_new0 (PrintDialogCallback, 1);
+  callback->iPrintDialogCallback.lpVtbl = &ipdc_vtbl;
+  callback->ref_count = 1;
+  callback->set_hwnd = FALSE;
+
+  return &callback->iPrintDialogCallback;
+}
+
+GtkPrintOperationResult
+_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
+                                                 GtkWindow *parent,
+                                                 gboolean *do_print,
+                                                 GError **error)
+{
+  HRESULT hResult;
+  LPPRINTDLGEXW printdlgex = NULL;
+  LPPRINTPAGERANGE page_ranges = NULL;
+  HWND parentHWnd;
+  GtkWidget *invisible = NULL;
+  GtkPrintOperationResult result;
+  GtkPrintOperationWin32 *op_win32;
+  IPrintDialogCallback *callback;
+  
+  *do_print = FALSE;
+
+  if (parent == NULL)
+    {
+      invisible = gtk_invisible_new ();
+      parentHWnd = get_parent_hwnd (invisible);
+    }
+  else 
+    parentHWnd = get_parent_hwnd (GTK_WIDGET (parent));
+
+  printdlgex = (LPPRINTDLGEXW)GlobalAlloc (GPTR, sizeof (PRINTDLGEXW));
+  if (!printdlgex)
+    {
+      result = GTK_PRINT_OPERATION_RESULT_ERROR;
+      g_set_error (error,
+                  GTK_PRINT_ERROR,
+                  GTK_PRINT_ERROR_NOMEM,
+                  _("Not enough free memory"));
+      goto out;
+    }      
+
+  printdlgex->lStructSize = sizeof(PRINTDLGEXW);
+  printdlgex->hwndOwner = parentHWnd;
+  printdlgex->hDevMode = NULL;
+  printdlgex->hDevNames = NULL;
+  printdlgex->hDC = NULL;
+  printdlgex->Flags = PD_RETURNDC | PD_NOSELECTION;
+  if (op->priv->current_page == -1)
+    printdlgex->Flags |= PD_NOCURRENTPAGE;
+  printdlgex->Flags2 = 0;
+  printdlgex->ExclusionFlags = 0;
+
+  page_ranges = (LPPRINTPAGERANGE) GlobalAlloc (GPTR, 
+                                               MAX_PAGE_RANGES * sizeof (PRINTPAGERANGE));
+  if (!page_ranges) 
+    {
+      result = GTK_PRINT_OPERATION_RESULT_ERROR;
+      g_set_error (error,
+                  GTK_PRINT_ERROR,
+                  GTK_PRINT_ERROR_NOMEM,
+                  _("Not enough free memory"));
+      goto out;
+    }
+
+  printdlgex->nPageRanges = 0;
+  printdlgex->nMaxPageRanges = MAX_PAGE_RANGES;
+  printdlgex->lpPageRanges = page_ranges;
+  printdlgex->nMinPage = 1;
+  if (op->priv->nr_of_pages != -1)
+    printdlgex->nMaxPage = op->priv->nr_of_pages;
+  else
+    printdlgex->nMaxPage = 10000;
+  printdlgex->nCopies = 1;
+  printdlgex->hInstance = 0;
+  printdlgex->lpPrintTemplateName = NULL;
+  printdlgex->lpCallback = NULL;
+  printdlgex->nPropertyPages = 0;
+  printdlgex->lphPropertyPages = NULL;
+  printdlgex->nStartPage = START_PAGE_GENERAL;
+  printdlgex->dwResultAction = 0;
+
+  dialog_from_print_settings (op, printdlgex);
+
+  callback = print_callback_new ();
+  printdlgex->lpCallback = (IUnknown *)callback;
+  got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
+  
+  hResult = PrintDlgExW(printdlgex);
+  IUnknown_Release ((IUnknown *)callback);
+  gdk_win32_set_modal_dialog_libgtk_only (NULL);
+
+  if (hResult != S_OK) 
+    {
+      result = GTK_PRINT_OPERATION_RESULT_ERROR;
+      if (hResult == E_OUTOFMEMORY)
+       g_set_error (error,
+                    GTK_PRINT_ERROR,
+                    GTK_PRINT_ERROR_NOMEM,
+                    _("Not enough free memory"));
+      else if (hResult == E_INVALIDARG)
+       g_set_error (error,
+                    GTK_PRINT_ERROR,
+                    GTK_PRINT_ERROR_INTERNAL_ERROR,
+                    _("Invalid argument to PrintDlgEx"));
+      else if (hResult == E_POINTER)
+       g_set_error (error,
+                    GTK_PRINT_ERROR,
+                    GTK_PRINT_ERROR_INTERNAL_ERROR,
+                    _("Invalid pointer to PrintDlgEx"));
+      else if (hResult == E_HANDLE)
+       g_set_error (error,
+                    GTK_PRINT_ERROR,
+                    GTK_PRINT_ERROR_INTERNAL_ERROR,
+                    _("Invalid handle to PrintDlgEx"));
+      else /* E_FAIL */
+       g_set_error (error,
+                    GTK_PRINT_ERROR,
+                    GTK_PRINT_ERROR_GENERAL,
+                    _("Unspecified error"));
+      goto out;
+    }
+
+  if (printdlgex->dwResultAction == PD_RESULT_PRINT ||
+      printdlgex->dwResultAction == PD_RESULT_APPLY)
+    {
+      result = GTK_PRINT_OPERATION_RESULT_APPLY;
+      dialog_to_print_settings (op, printdlgex);
+    }
+  else
+    result = GTK_PRINT_OPERATION_RESULT_CANCEL;
+  
+  if (printdlgex->dwResultAction == PD_RESULT_PRINT)
+    {
+      DOCINFOW docinfo;
+      int job_id;
+
+      *do_print = TRUE;
+
+      op->priv->surface = cairo_win32_surface_create (printdlgex->hDC);
+      op->priv->dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX);
+      op->priv->dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY);
+
+      memset( &docinfo, 0, sizeof (DOCINFOW));
+      docinfo.cbSize = sizeof (DOCINFOW); 
+      docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); 
+      docinfo.lpszOutput = (LPCWSTR) NULL; 
+      docinfo.lpszDatatype = (LPCWSTR) NULL; 
+      docinfo.fwType = 0; 
+
+      job_id = StartDocW(printdlgex->hDC, &docinfo); 
+      g_free ((void *)docinfo.lpszDocName);
+      if (job_id <= 0) 
+       { 
+         result = GTK_PRINT_OPERATION_RESULT_ERROR;
+         g_set_error (error,
+                      GTK_PRINT_ERROR,
+                      GTK_PRINT_ERROR_GENERAL,
+                    _("Error from StartDoc"));
+         *do_print = FALSE;
+         cairo_surface_destroy (op->priv->surface);
+         op->priv->surface = NULL;
+         goto out; 
+       } 
+      
+      op_win32 = g_new (GtkPrintOperationWin32, 1);
+      op->priv->platform_data = op_win32;
+      op->priv->free_platform_data = (GDestroyNotify) op_win32_free;
+      op_win32->hdc = printdlgex->hDC;
+      op_win32->devmode = printdlgex->hDevMode;
+      op_win32->devnames = printdlgex->hDevNames;
+      op_win32->job_id = job_id;
+      
+      op->priv->print_pages = gtk_print_settings_get_print_pages (op->priv->print_settings);
+      op->priv->num_page_ranges = 0;
+      if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
+       op->priv->page_ranges = gtk_print_settings_get_page_ranges (op->priv->print_settings,
+                                                                   &op->priv->num_page_ranges);
+      op->priv->manual_num_copies = printdlgex->nCopies;
+      op->priv->manual_collation = (printdlgex->Flags & PD_COLLATE) != 0;
+      op->priv->manual_reverse = FALSE;
+      op->priv->manual_orientation = FALSE;
+      op->priv->manual_scale = 1.0;
+      op->priv->manual_page_set = GTK_PAGE_SET_ALL;
+    }
+
+  op->priv->start_page = win32_start_page;
+  op->priv->end_page = win32_end_page;
+  op->priv->end_run = win32_end_run;
+  
+  out:
+  if (!*do_print && printdlgex && printdlgex->hDevMode != NULL) 
+    GlobalFree(printdlgex->hDevMode); 
+
+  if (!*do_print && printdlgex && printdlgex->hDevNames != NULL) 
+    GlobalFree(printdlgex->hDevNames); 
+
+  if (page_ranges)
+    GlobalFree (page_ranges);
+
+  if (printdlgex)
+    GlobalFree (printdlgex);
+
+  if (invisible)
+    gtk_widget_destroy (invisible);
+
+  return result;
+}
+
+GtkPageSetup *
+gtk_print_run_page_setup_dialog (GtkWindow        *parent,
+                                GtkPageSetup     *page_setup,
+                                GtkPrintSettings *settings)
+{
+  LPPAGESETUPDLGW pagesetupdlg = NULL;
+  BOOL res;
+  gboolean free_settings;
+  const char *printer;
+  GtkPaperSize *paper_size;
+  DWORD measure_system;
+  GtkUnit unit;
+  double scale;
+
+  pagesetupdlg = (LPPAGESETUPDLGW)GlobalAlloc (GPTR, sizeof (PAGESETUPDLGW));
+  if (!pagesetupdlg)
+    return NULL;
+
+  free_settings = FALSE;
+  if (settings == NULL)
+    {
+      settings = gtk_print_settings_new ();
+      free_settings = TRUE;
+    }
+  
+  memset (pagesetupdlg, 0, sizeof (PAGESETUPDLGW));
+
+  pagesetupdlg->lStructSize = sizeof(PAGESETUPDLGW);
+
+  if (parent != NULL)
+    pagesetupdlg->hwndOwner = get_parent_hwnd (GTK_WIDGET (parent));
+  else
+    pagesetupdlg->hwndOwner = NULL;
+
+  pagesetupdlg->Flags = PSD_DEFAULTMINMARGINS;
+  pagesetupdlg->hDevMode = devmode_from_settings (settings, page_setup);
+  pagesetupdlg->hDevNames = NULL;
+  printer = gtk_print_settings_get_printer (settings);
+  if (printer)
+    pagesetupdlg->hDevNames = gtk_print_win32_devnames_from_printer_name (printer);
+
+  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IMEASURE|LOCALE_RETURN_NUMBER,
+                (LPWSTR)&measure_system, sizeof (DWORD));
+
+  if (measure_system == 0)
+    {
+      pagesetupdlg->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
+      unit = GTK_UNIT_MM;
+      scale = 100;
+    }
+  else
+    {
+      pagesetupdlg->Flags |= PSD_INTHOUSANDTHSOFINCHES;
+      unit = GTK_UNIT_INCH;
+      scale = 1000;
+    }
+
+  /* This is the object we return, we allocate it here so that
+   * we can use the default page margins */
+  if (page_setup)
+    page_setup = gtk_page_setup_copy (page_setup);
+  else
+    page_setup = gtk_page_setup_new ();
+  
+  pagesetupdlg->Flags |= PSD_MARGINS;
+  pagesetupdlg->rtMargin.left =
+    floor (gtk_page_setup_get_left_margin (page_setup, unit) * scale + 0.5);
+  pagesetupdlg->rtMargin.right =
+    floor (gtk_page_setup_get_right_margin (page_setup, unit) * scale + 0.5);
+  pagesetupdlg->rtMargin.top = 
+    floor (gtk_page_setup_get_top_margin (page_setup, unit) * scale + 0.5);
+  pagesetupdlg->rtMargin.bottom =
+    floor (gtk_page_setup_get_bottom_margin (page_setup, unit) * scale + 0.5);
+
+  pagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK;
+  pagesetupdlg->lpfnPageSetupHook = run_mainloop_hook;
+  got_gdk_events_message = RegisterWindowMessage ("GDK_WIN32_GOT_EVENTS");
+  
+  res = PageSetupDlgW (pagesetupdlg);
+  gdk_win32_set_modal_dialog_libgtk_only (NULL);
+
+  if (res)
+    {  
+      if (pagesetupdlg->hDevNames != NULL)
+       devnames_to_settings (settings, pagesetupdlg->hDevNames);
+
+      if (pagesetupdlg->hDevMode != NULL)
+       devmode_to_settings (settings, pagesetupdlg->hDevMode);
+    }
+  
+  if (free_settings)
+    g_object_unref (settings);
+
+  if (res)
+    {
+      gtk_page_setup_set_orientation (page_setup, 
+                                     gtk_print_settings_get_orientation (settings));
+      paper_size = gtk_print_settings_get_paper_size (settings);
+      if (paper_size)
+       {
+         gtk_page_setup_set_paper_size (page_setup, paper_size);
+         gtk_paper_size_free (paper_size);
+       }
+
+      if (pagesetupdlg->Flags & PSD_INHUNDREDTHSOFMILLIMETERS)
+       {
+         unit = GTK_UNIT_MM;
+         scale = 100;
+       }
+      else
+       {
+         unit = GTK_UNIT_INCH;
+         scale = 1000;
+       }
+
+      gtk_page_setup_set_left_margin (page_setup,
+                                     pagesetupdlg->rtMargin.left / scale,
+                                     unit);
+      gtk_page_setup_set_right_margin (page_setup,
+                                      pagesetupdlg->rtMargin.right / scale,
+                                      unit);
+      gtk_page_setup_set_top_margin (page_setup,
+                                    pagesetupdlg->rtMargin.top / scale,
+                                    unit);
+      gtk_page_setup_set_bottom_margin (page_setup,
+                                       pagesetupdlg->rtMargin.bottom / scale,
+                                       unit);
+    }
+  
+  return page_setup;
+}
diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c
new file mode 100644 (file)
index 0000000..07f2e92
--- /dev/null
@@ -0,0 +1,1153 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation.c: Print Operation
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "string.h"
+#include "gtkprintoperation-private.h"
+#include "gtkmarshalers.h"
+#include <cairo-pdf.h>
+#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtkalias.h"
+
+#define GTK_PRINT_OPERATION_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_PRINT_OPERATION, GtkPrintOperationPrivate))
+
+enum {
+  BEGIN_PRINT,
+  REQUEST_PAGE_SETUP,
+  DRAW_PAGE,
+  END_PRINT,
+  STATUS_CHANGED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_DEFAULT_PAGE_SETUP,
+  PROP_PRINT_SETTINGS,
+  PROP_JOB_NAME,
+  PROP_NR_OF_PAGES,
+  PROP_CURRENT_PAGE,
+  PROP_USE_FULL_PAGE,
+  PROP_UNIT,
+  PROP_SHOW_DIALOG,
+  PROP_PDF_TARGET,
+  PROP_STATUS,
+  PROP_STATUS_STRING
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static int job_nr = 0;
+
+G_DEFINE_TYPE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT)
+
+/**
+ * gtk_print_error_quark:
+ *
+ * Registers an error quark for #GtkPrintOperation if necessary.
+ * 
+ * Return value: The error quark used for #GtkPrintOperation errors.
+ *
+ * Since: 2.10
+ **/
+GQuark     
+gtk_print_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (quark == 0)
+    quark = g_quark_from_static_string ("gtk-print-error-quark");
+  return quark;
+}
+     
+static void
+gtk_print_operation_finalize (GObject *object)
+{
+  GtkPrintOperation *print_operation = GTK_PRINT_OPERATION (object);
+
+  if (print_operation->priv->free_platform_data &&
+      print_operation->priv->platform_data)
+    {
+      print_operation->priv->free_platform_data (print_operation->priv->platform_data);
+      print_operation->priv->free_platform_data = NULL;
+    }
+
+  if (print_operation->priv->default_page_setup)
+    g_object_unref (print_operation->priv->default_page_setup);
+  
+  if (print_operation->priv->print_settings)
+    g_object_unref (print_operation->priv->print_settings);
+  
+  g_free (print_operation->priv->pdf_target);
+  g_free (print_operation->priv->job_name);
+
+  G_OBJECT_CLASS (gtk_print_operation_parent_class)->finalize (object);
+}
+
+static void
+gtk_print_operation_init (GtkPrintOperation *operation)
+{
+  const char *appname;
+
+  operation->priv = GTK_PRINT_OPERATION_GET_PRIVATE (operation);
+
+  operation->priv->status = GTK_PRINT_STATUS_INITIAL;
+  operation->priv->status_string = g_strdup ("");
+  operation->priv->default_page_setup = NULL;
+  operation->priv->print_settings = NULL;
+  operation->priv->nr_of_pages = -1;
+  operation->priv->current_page = -1;
+  operation->priv->use_full_page = FALSE;
+  operation->priv->show_dialog = TRUE;
+  operation->priv->pdf_target = NULL;
+
+  operation->priv->unit = GTK_UNIT_PIXEL;
+
+  appname = g_get_application_name ();
+  operation->priv->job_name = g_strdup_printf ("%s job #%d",
+                                              appname, ++job_nr);
+}
+
+static void
+gtk_print_operation_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GtkPrintOperation *op = GTK_PRINT_OPERATION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_DEFAULT_PAGE_SETUP:
+      gtk_print_operation_set_default_page_setup (op, g_value_get_object (value));
+      break;
+    case PROP_PRINT_SETTINGS:
+      gtk_print_operation_set_print_settings (op, g_value_get_object (value));
+      break;
+    case PROP_JOB_NAME:
+      gtk_print_operation_set_job_name (op, g_value_get_string (value));
+      break;
+    case PROP_NR_OF_PAGES:
+      gtk_print_operation_set_nr_of_pages (op, g_value_get_int (value));
+      break;
+    case PROP_CURRENT_PAGE:
+      gtk_print_operation_set_current_page (op, g_value_get_int (value));
+      break;
+    case PROP_USE_FULL_PAGE:
+      gtk_print_operation_set_use_full_page (op, g_value_get_boolean (value));
+      break;
+    case PROP_UNIT:
+      gtk_print_operation_set_unit (op, g_value_get_enum (value));
+      break;
+    case PROP_SHOW_DIALOG:
+      gtk_print_operation_set_show_dialog (op, g_value_get_boolean (value));
+      break;
+    case PROP_PDF_TARGET:
+      gtk_print_operation_set_pdf_target (op, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_print_operation_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GtkPrintOperation *op = GTK_PRINT_OPERATION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_DEFAULT_PAGE_SETUP:
+      g_value_set_object (value, op->priv->default_page_setup);
+      break;
+    case PROP_PRINT_SETTINGS:
+      g_value_set_object (value, op->priv->print_settings);
+      break;
+    case PROP_JOB_NAME:
+      g_value_set_string (value, op->priv->job_name);
+      break;
+    case PROP_NR_OF_PAGES:
+      g_value_set_int (value, op->priv->nr_of_pages);
+      break;
+    case PROP_CURRENT_PAGE:
+      g_value_set_int (value, op->priv->current_page);
+      break;      
+    case PROP_USE_FULL_PAGE:
+      g_value_set_boolean (value, op->priv->use_full_page);
+      break;
+    case PROP_UNIT:
+      g_value_set_enum (value, op->priv->unit);
+      break;
+    case PROP_SHOW_DIALOG:
+      g_value_set_boolean (value, op->priv->show_dialog);
+      break;
+    case PROP_PDF_TARGET:
+      g_value_set_string (value, op->priv->pdf_target);
+      break;
+    case PROP_STATUS:
+      g_value_set_enum (value, op->priv->status);
+      break;
+    case PROP_STATUS_STRING:
+      g_value_set_string (value, op->priv->status_string);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_print_operation_class_init (GtkPrintOperationClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->set_property = gtk_print_operation_set_property;
+  gobject_class->get_property = gtk_print_operation_get_property;
+  gobject_class->finalize = gtk_print_operation_finalize;
+  
+  g_type_class_add_private (gobject_class, sizeof (GtkPrintOperationPrivate));
+
+  /**
+   * GtkPrintOperation::begin-print:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   * @context: the #GtkPrintContext for the current operation
+   *
+   * Gets emitted after the user has finished changing print settings
+   * in the dialog, before the actual rendering starts. 
+   *
+   * A typical use for this signal is to use the parameters from the
+   * #GtkPrintContext and paginate the document accordingly, and then
+   * set the number of pages with gtk_print_operation_set_nr_of_pages().
+   *
+   * Since: 2.10
+   */
+  signals[BEGIN_PRINT] =
+    g_signal_new ("begin_print",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintOperationClass, begin_print),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, GTK_TYPE_PRINT_CONTEXT);
+
+  /**
+   * GtkPrintOperation::request-page-setup:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   * @context: the #GtkPrintContext for the current operation
+   * @page_nr: the number of the currently printed page
+   * @setup: the #GtkPageSetup 
+   * 
+   * Gets emitted once for every page that is printed, to give
+   * the application a chance to modify the page setup. Any changes 
+   * done to @setup will be in force only for printing this page.
+   *
+   * Since: 2.10
+   */
+  signals[REQUEST_PAGE_SETUP] =
+    g_signal_new ("request_page_setup",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintOperationClass, request_page_setup),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__OBJECT_INT_OBJECT,
+                 G_TYPE_NONE, 3,
+                 GTK_TYPE_PRINT_CONTEXT,
+                 G_TYPE_INT,
+                 GTK_TYPE_PAGE_SETUP);
+
+  /**
+   * GtkPrintOperation::draw-page:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   * @context: the #GtkPrintContext for the current operation
+   * @page_nr: the number of the currently printed page
+   *
+   * Gets emitted for every page that is printed. The signal handler
+   * must render the @page_nr's page onto the cairo context obtained
+   * from @context using gtk_print_context_get_cairo().
+   * 
+   * <informalexample><programlisting>
+   *  FIXME: need an example here
+   * </programlisting></informalexample>
+   *
+   * Since: 2.10
+   */
+  signals[DRAW_PAGE] =
+    g_signal_new ("draw_page",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintOperationClass, draw_page),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__OBJECT_INT,
+                 G_TYPE_NONE, 2,
+                 GTK_TYPE_PRINT_CONTEXT,
+                 G_TYPE_INT);
+
+  /**
+   * GtkPrintOperation::end-print:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   * @context: the #GtkPrintContext for the current operation
+   *
+   * Gets emitted after all pages have been rendered. 
+   * A handler for this signal can clean up any resources that have
+   * been allocated in the ::begin-print handler.
+   * 
+   * Since: 2.10
+   */
+  signals[END_PRINT] =
+    g_signal_new ("end_print",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintOperationClass, end_print),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, GTK_TYPE_PRINT_CONTEXT);
+
+  /**
+   * GtkPrintOperation::status-changed:
+   * @operation: the #GtkPrintOperation on which the signal was emitted
+   *
+   * Gets emitted at between the various phases of the print operation.
+   * See #GtkPrintStatus for the phases that are being discriminated.
+   * Use gtk_print_operation_get_status() to find out the current
+   * status.
+   *
+   * Since: 2.10
+   */
+  signals[STATUS_CHANGED] =
+   g_signal_new ("status-changed",
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintOperationClass, status_changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_DEFAULT_PAGE_SETUP,
+                                  g_param_spec_object ("default-page-setup",
+                                                       P_("Default Page Setup"),
+                                                       P_("The GtkPageSetup used by default"),
+                                                       GTK_TYPE_PAGE_SETUP,
+                                                       GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_PRINT_SETTINGS,
+                                  g_param_spec_object ("print-settings",
+                                                       P_("Print Settings"),
+                                                       P_("The GtkPrintSettings used for initializing the dialog"),
+                                                       GTK_TYPE_PRINT_SETTINGS,
+                                                       GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_JOB_NAME,
+                                  g_param_spec_string ("job-name",
+                                                       P_("Job Name"),
+                                                       P_("A string used for identifying the print job."),
+                                                       "",
+                                                       GTK_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_NR_OF_PAGES,
+                                  g_param_spec_int ("number-of-pages",
+                                                    P_("Number of Pages"),
+                                                    P_("The number of pages in the document."),
+                                                    -1,
+                                                    G_MAXINT,
+                                                    -1,
+                                                    GTK_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_CURRENT_PAGE,
+                                  g_param_spec_int ("current-page",
+                                                    P_("Current Page"),
+                                                    P_("The current page in the document."),
+                                                    -1,
+                                                    G_MAXINT,
+                                                    -1,
+                                                    GTK_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_USE_FULL_PAGE,
+                                  g_param_spec_boolean ("use-full-page",
+                                                        P_("Use full page"),
+                                                        P_(""),
+                                                        FALSE,
+                                                        GTK_PARAM_READWRITE));
+  
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_UNIT,
+                                  g_param_spec_enum ("unit",
+                                                     P_("Unit"),
+                                                     P_(""),
+                                                     GTK_TYPE_UNIT,
+                                                     GTK_UNIT_PIXEL,
+                                                     GTK_PARAM_READWRITE));
+  
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_SHOW_DIALOG,
+                                  g_param_spec_boolean ("show-dialog",
+                                                        P_("Show Dialog"),
+                                                        P_("%TRUE if gtk_print_operation_run() should show the print dialog."),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_JOB_NAME,
+                                  g_param_spec_string ("pdf-target",
+                                                       P_("PDF target filename"),
+                                                       P_(""),
+                                                       NULL,
+                                                       GTK_PARAM_READWRITE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_STATUS,
+                                  g_param_spec_enum ("status",
+                                                     P_("Status"),
+                                                     P_("The status of the print operation"),
+                                                     GTK_TYPE_PRINT_STATUS,
+                                                     GTK_PRINT_STATUS_INITIAL,
+                                                     GTK_PARAM_READABLE));
+  
+  g_object_class_install_property (gobject_class,
+                                  PROP_STATUS_STRING,
+                                  g_param_spec_string ("status-string",
+                                                       P_("Status String"),
+                                                       P_("A human-readable description of the status"),
+                                                       "",
+                                                       GTK_PARAM_READABLE));
+  
+
+}
+
+/**
+ * gtk_print_operation_new:
+ *
+ * Creates a new #GtkPrintOperation. 
+ *
+ * Returns: a new #GtkPrintOperation
+ *
+ * Since: 2.10
+ */
+GtkPrintOperation *
+gtk_print_operation_new (void)
+{
+  GtkPrintOperation *print_operation;
+
+  print_operation = g_object_new (GTK_TYPE_PRINT_OPERATION, NULL);
+  
+  return print_operation;
+}
+
+/**
+ * gtk_print_operation_set_default_page_setup:
+ * @op: a #GtkPrintOperation
+ * @default_page_setup: a #GtkPageSetup, or %NULL
+ * 
+ * Makes @default_page_setup the default page setup for @op.
+ *
+ * This page setup will be used by gtk_print_operation_run(),
+ * but it can be overridden on a per-page basis by connecting
+ * to the ::request-page-setup signal.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_print_operation_set_default_page_setup (GtkPrintOperation *op,
+                                           GtkPageSetup      *default_page_setup)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  g_return_if_fail (default_page_setup == NULL || 
+                    GTK_IS_PAGE_SETUP (default_page_setup));
+
+  if (default_page_setup != op->priv->default_page_setup)
+    {
+      if (default_page_setup)
+       g_object_ref (default_page_setup);
+      
+      if (op->priv->default_page_setup)
+       g_object_unref (op->priv->default_page_setup);
+      
+      op->priv->default_page_setup = default_page_setup;
+     
+      g_object_notify (G_OBJECT (op), "default-page-setup");
+    }
+}
+
+/**
+ * gtk_print_operation_get_default_page_setup:
+ * @op: a #GtkPrintOperation
+ *
+ * Returns the default page setup, see 
+ * gtk_print_operation_set_default_page_setup().
+ *
+ * Returns: the default page setup 
+ *
+ * Since: 2.10
+ */
+GtkPageSetup *
+gtk_print_operation_get_default_page_setup (GtkPrintOperation *op)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), NULL);
+
+  return op->priv->default_page_setup;
+}
+
+
+/**
+ * gtk_print_operation_set_print_settings:
+ * @op: a #GtkPrintOperation
+ * @print_settings: #GtkPrintSettings, or %NULL
+ * 
+ * Sets the print settings for @op. This is typically used to
+ * re-establish print settings from a previous print operation,
+ * see gtk_print_operation_run().
+ *
+ * Since: 2.10
+ **/
+void
+gtk_print_operation_set_print_settings (GtkPrintOperation *op,
+                                       GtkPrintSettings  *print_settings)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  g_return_if_fail (print_settings == NULL || 
+                    GTK_IS_PRINT_SETTINGS (print_settings));
+
+  if (print_settings != op->priv->print_settings)
+    {
+      if (print_settings)
+        g_object_ref (print_settings);
+
+      if (op->priv->print_settings)
+        g_object_unref (op->priv->print_settings);
+  
+      op->priv->print_settings = print_settings;
+
+      g_object_notify (G_OBJECT (op), "print-settings");
+    }
+}
+
+/**
+ * gtk_print_operation_get_print_settings:
+ * @op: a #GtkPrintOperation
+ * 
+ * Returns the current print settings. 
+ *
+ * Note that the return value is %NULL until either 
+ * gtk_print_operation_set_print_settings() or 
+ * gtk_print_operation_run() have been called.
+ * 
+ * Return value: the current print settings of @op.
+ * 
+ * Since: 2.10
+ **/
+GtkPrintSettings *
+gtk_print_operation_get_print_settings (GtkPrintOperation *op)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), NULL);
+
+  return op->priv->print_settings;
+}
+
+/**
+ * gtk_print_operation_set_job_name:
+ * @op: a #GtkPrintOperation
+ * @job_name: a string that identifies the print job
+ * 
+ * Sets the name of the print job. The name is used to identify 
+ * the job (e.g. in monitoring applications like eggcups). 
+ * 
+ * If you don't set a job name, GTK+ picks a default one by 
+ * numbering successive print jobs.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_print_operation_set_job_name (GtkPrintOperation *op,
+                                 const gchar       *job_name)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  g_return_if_fail (g_utf8_validate (job_name, -1, NULL));
+
+  g_free (op->priv->job_name);
+  op->priv->job_name = g_strdup (job_name);
+
+  g_object_notify (G_OBJECT (op), "job-name");
+}
+
+/**
+ * gtk_print_operation_set_nr_of_pages:
+ * @op: a #GtkPrintOperation
+ * @n_pages: the number of pages
+ * 
+ * Sets the number of pages in the document. 
+ *
+ * This <emphasis>must</emphasis> be set to a positive number
+ * before the print dialog is shown. It may be set in a
+ * ::begin-print signal hander.
+ *
+ * Note that the page numbers passed to the ::request-page-setup 
+ * and ::draw-page signals are 0-based, i.e. if the user chooses
+ * to print all pages, the last ::draw-page signal will be
+ * for page @n_pages - 1.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_print_operation_set_nr_of_pages (GtkPrintOperation *op,
+                                    gint               n_pages)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  g_return_if_fail (n_pages > 0);
+  g_return_if_fail (op->priv->current_page == -1 || 
+                   op->priv->current_page < n_pages);
+
+  if (op->priv->nr_of_pages != n_pages)
+    {
+      op->priv->nr_of_pages = n_pages;
+
+      g_object_notify (G_OBJECT (op), "number-of-pages");
+    }
+}
+
+/**
+ * gtk_print_operation_set_current_page:
+ * @op: a #GtkPrintOperation
+ * @current_page: the current page, 0-based
+ *
+ * Sets the current page.
+ * If this is called before gtk_print_operation_run(), 
+ * the user will be able to select to print only the current page.
+ *
+ * Note that this only makes sense for pre-paginated documents.
+ * 
+ * Since: 2.10
+ **/
+void
+gtk_print_operation_set_current_page (GtkPrintOperation *op,
+                                     gint               current_page)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  g_return_if_fail (current_page >= 0);
+  g_return_if_fail (op->priv->nr_of_pages == -1 || 
+                   current_page < op->priv->nr_of_pages);
+  if (op->priv->current_page != current_page)
+    {
+      op->priv->current_page = current_page;
+
+      g_object_notify (G_OBJECT (op), "current-page");
+    }
+}
+
+void
+gtk_print_operation_set_use_full_page (GtkPrintOperation *op,
+                                      gboolean           full_page)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+
+  full_page = full_page != FALSE;
+  
+  if (op->priv->use_full_page != full_page)
+    {
+      op->priv->use_full_page = full_page;
+   
+      g_object_notify (G_OBJECT (op), "use-full-page");
+    }
+}
+
+void
+gtk_print_operation_set_unit (GtkPrintOperation *op,
+                             GtkUnit            unit)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+
+  if (op->priv->unit != unit)
+    {
+      op->priv->unit = unit;
+
+      g_object_notify (G_OBJECT (op), "unit");
+    }
+}
+
+void
+_gtk_print_operation_set_status (GtkPrintOperation *op,
+                                GtkPrintStatus     status,
+                                const gchar       *string)
+{
+  const gchar *status_strs[] = {
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Initial state"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Preparing to print"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Generating data"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Sending data"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Waiting"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Blocking on issue"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Printing"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Finished"),
+    /* translators, strip the prefix up to and including the first | */
+    N_("print operation status|Finished with error")
+  };
+
+  if (status < 0 || status > GTK_PRINT_STATUS_FINISHED_ABORTED)
+    status = GTK_PRINT_STATUS_FINISHED_ABORTED;
+
+  if (string == NULL)
+    string = g_strip_context (status_strs[status],
+                             gettext (status_strs[status]));
+  
+  if (op->priv->status == status &&
+      strcmp (string, op->priv->status_string) == 0)
+    return;
+  
+  g_free (op->priv->status_string);
+  op->priv->status_string = g_strdup (string);
+  op->priv->status = status;
+
+  g_object_notify (G_OBJECT (op), "status");
+  g_object_notify (G_OBJECT (op), "status-string");
+
+  g_signal_emit (op, signals[STATUS_CHANGED], 0);
+}
+
+
+/**
+ * gtk_print_operation_get_status:
+ * @op: a #GtkPrintOperation
+ * 
+ * Returns the status of the print operation. 
+ * Also see gtk_print_operation_get_status_string().
+ * 
+ * Return value: the status of the print operation
+ *
+ * Since: 2.10
+ **/
+GtkPrintStatus
+gtk_print_operation_get_status (GtkPrintOperation *op)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), 
+                        GTK_PRINT_STATUS_FINISHED_ABORTED);
+
+  return op->priv->status;
+}
+
+/**
+ * gtk_print_operation_get_status_string:
+ * @op: a #GtkPrintOperation
+ * 
+ * Returns a string representation of the status of the 
+ * print operation. The string is translated and suitable
+ * for displaying the print status e.g. in a #GtkStatusbar.
+ *
+ * Use gtk_print_operation_get_status() to obtain a status
+ * value that is suitable for programmatic use. 
+ * 
+ * Return value: a string representation of the status
+ *    of the print operation
+ *
+ * Since: 2.10
+ **/
+G_CONST_RETURN gchar *
+gtk_print_operation_get_status_string (GtkPrintOperation *op)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), "");
+
+  return op->priv->status_string;
+}
+
+/**
+ * gtk_print_operation_is_finished:
+ * @op: a #GtkPrintOperation
+ * 
+ * A convenience function to find out if the print operation
+ * is finished, either successfully (%GTK_PRINT_STATUS_FINISHED)
+ * or unsuccessfully (%GTK_PRINT_STATUS_FINISHED_ABORTED).
+ * 
+ * Return value: %TRUE, if the print operation is finished.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_print_operation_is_finished (GtkPrintOperation *op)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), TRUE);
+
+  return
+    op->priv->status == GTK_PRINT_STATUS_FINISHED_ABORTED ||
+    op->priv->status == GTK_PRINT_STATUS_FINISHED;
+}
+
+
+/**
+ * gtk_print_operation_set_show_dialog:
+ * @op: a #GtkPrintOperation
+ * @show_dialog: %TRUE to show the print dialog
+ * 
+ * Sets whether calling gtk_print_operation_run() will present
+ * a print dialog to the user, or just print to the default printer.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_operation_set_show_dialog (GtkPrintOperation *op,
+                                    gboolean           show_dialog)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+  
+  show_dialog = show_dialog != FALSE;
+
+  if (op->priv->show_dialog != show_dialog)
+    {
+      op->priv->show_dialog = show_dialog;
+
+      g_object_notify (G_OBJECT (op), "show-dialog");
+    }
+}
+
+void
+gtk_print_operation_set_pdf_target (GtkPrintOperation *op,
+                                   const gchar *      filename)
+{
+  g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+
+  g_free (op->priv->pdf_target);
+  op->priv->pdf_target = g_strdup (filename);
+
+  g_object_notify (G_OBJECT (op), "pdf-target");
+}
+
+/* Creates the initial page setup used for printing unless the
+ * app overrides this on a per-page basis using request_page_setup.
+ *
+ * Data is taken from, in order, if existing:
+ *
+ * PrintSettings returned from the print dialog
+ *  (initial dialog values are set from default_page_setup
+ *   if unset in app specified print_settings)
+ * default_page_setup
+ * per-locale default setup
+ */
+static GtkPageSetup *
+create_page_setup (GtkPrintOperation *op)
+{
+  GtkPageSetup *page_setup;
+  GtkPrintSettings *settings;
+  
+  if (op->priv->default_page_setup)
+    page_setup = gtk_page_setup_copy (op->priv->default_page_setup);
+  else
+    page_setup = gtk_page_setup_new ();
+
+  settings = op->priv->print_settings;
+  if (settings)
+    {
+      GtkPaperSize *paper_size;
+      
+      if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION))
+       gtk_page_setup_set_orientation (page_setup,
+                                       gtk_print_settings_get_orientation (settings));
+
+
+      paper_size = gtk_print_settings_get_paper_size (settings);
+      if (paper_size)
+       {
+         gtk_page_setup_set_paper_size (page_setup, paper_size);
+         gtk_paper_size_free (paper_size);
+       }
+
+      /* TODO: Margins? */
+    }
+  
+  return page_setup;
+}
+
+static void 
+pdf_start_page (GtkPrintOperation *op,
+               GtkPrintContext   *print_context,
+               GtkPageSetup      *page_setup)
+{
+  /* TODO: Set up page size, not supported in cairo yet */
+}
+
+static void
+pdf_end_page (GtkPrintOperation *op,
+             GtkPrintContext   *print_context)
+{
+  cairo_t *cr;
+
+  cr = gtk_print_context_get_cairo (print_context);
+  cairo_show_page (cr);
+}
+
+static void
+pdf_end_run (GtkPrintOperation *op)
+{
+  cairo_surface_destroy (op->priv->surface);
+  op->priv->surface = NULL;
+}
+
+static GtkPrintOperationResult
+run_pdf (GtkPrintOperation  *op,
+        GtkWindow          *parent,
+        gboolean           *do_print,
+        GError            **error)
+{
+  GtkPageSetup *page_setup;
+  double width, height;
+  /* This will be overwritten later by the non-default size, but
+     we need to pass some size: */
+  
+  page_setup = create_page_setup (op);
+  width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
+  height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
+  g_object_unref (page_setup);
+  
+  op->priv->surface = cairo_pdf_surface_create (op->priv->pdf_target,
+                                               width, height);
+  /* TODO: DPI from settings object? */
+  cairo_pdf_surface_set_dpi (op->priv->surface, 300, 300);
+  
+  op->priv->dpi_x = 72;
+  op->priv->dpi_y = 72;
+
+  op->priv->manual_num_copies = 1;
+  op->priv->manual_collation = FALSE;
+  
+  *do_print = TRUE;
+  
+  op->priv->start_page = pdf_start_page;
+  op->priv->end_page = pdf_end_page;
+  op->priv->end_run = pdf_end_run;
+  
+  return GTK_PRINT_OPERATION_RESULT_APPLY; 
+}
+
+static GtkPrintOperationResult
+run_print_dialog (GtkPrintOperation  *op,
+                 GtkWindow          *parent,
+                 gboolean           *do_print,
+                 GError            **error)
+{
+  if (op->priv->pdf_target != NULL)
+    return run_pdf (op, parent, do_print, error);
+
+  /* This does:
+   * Open print dialog 
+   * set print settings on dialog
+   * run dialog, if show_dialog set
+   * extract print settings from dialog
+   * create cairo surface and data for print job
+   * return correct result val
+   */
+  return _gtk_print_operation_platform_backend_run_dialog (op, 
+                                                          parent,
+                                                          do_print,
+                                                          error);
+}
+
+/**
+ * gtk_print_operation_run:
+ * @op: a #GtkPrintOperation
+ * @parent: Transient parent of the dialog, or %NULL
+ * @error: Return location for errors, or %NULL
+ * 
+ * Runs the print operation, by first letting the user modify
+ * print settings in the print dialog, and then print the
+ * document.
+ *
+ * Note that this function does not return until the rendering
+ * of all pages is complete. You can connect to the ::status-changed
+ * signal on @op to obtain some information about the progress
+ * of the print operation.
+ * 
+ * <informalexample><programlisting>
+ *  FIXME: need an example here
+ * </programlisting></informalexample>
+ *
+ * Return value: the result of the print operation. A return value
+ *   of %GTK_PRINT_OPERATION_RESULT_APPLY indicates that the printing
+ *   was completed successfully. In this case, it is a good idea
+ *   to obtain the used print settings with 
+ *   gtk_print_operation_get_print_settings() and store them for
+ *   reuse with the next print operation.
+ *
+ * Since: 2.10
+ **/
+GtkPrintOperationResult
+gtk_print_operation_run (GtkPrintOperation  *op,
+                        GtkWindow          *parent,
+                        GError            **error)
+{
+  int page, range;
+  GtkPageSetup *initial_page_setup, *page_setup;
+  GtkPrintContext *print_context;
+  cairo_t *cr;
+  gboolean do_print;
+  int uncollated_copies, collated_copies;
+  int i, j;
+  GtkPageRange *ranges;
+  GtkPageRange one_range;
+  int num_ranges;
+  GtkPrintOperationResult result;
+  
+  g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), 
+                        GTK_PRINT_OPERATION_RESULT_ERROR);
+
+  result = run_print_dialog (op, parent, &do_print, error);
+  if (!do_print)
+    {
+      _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
+      return result;
+    }
+  
+  if (op->priv->manual_collation)
+    {
+      uncollated_copies = op->priv->manual_num_copies;
+      collated_copies = 1;
+    }
+  else
+    {
+      uncollated_copies = 1;
+      collated_copies = op->priv->manual_num_copies;
+    }
+
+  print_context = _gtk_print_context_new (op);
+
+  initial_page_setup = create_page_setup (op);
+  _gtk_print_context_set_page_setup (print_context, initial_page_setup);
+
+  _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_PREPARING, NULL);
+  g_signal_emit (op, signals[BEGIN_PRINT], 0, print_context);
+  
+  g_return_val_if_fail (op->priv->nr_of_pages > 0, GTK_PRINT_OPERATION_RESULT_ERROR);
+
+  if (op->priv->print_pages == GTK_PRINT_PAGES_RANGES)
+    {
+      ranges = op->priv->page_ranges;
+      num_ranges = op->priv->num_page_ranges;
+    }
+  else if (op->priv->print_pages == GTK_PRINT_PAGES_CURRENT &&
+          op->priv->current_page != -1)
+    {
+      ranges = &one_range;
+      num_ranges = 1;
+      ranges[0].start = op->priv->current_page;
+      ranges[0].end = op->priv->current_page;
+    }
+  else
+    {
+      ranges = &one_range;
+      num_ranges = 1;
+      ranges[0].start = 0;
+      ranges[0].end = op->priv->nr_of_pages - 1;
+    }
+  
+  _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_GENERATING_DATA, NULL);
+
+  for (i = 0; i < uncollated_copies; i++)
+    {
+      for (range = 0; range < num_ranges; range ++)
+       {
+         int start, end, inc;
+         int low = ranges[range].start;
+         int high = ranges[range].end;
+         
+         if (op->priv->manual_reverse)
+           {
+             start = high;
+             end = low - 1;
+             inc = -1;
+           }
+         else
+           {
+             start = low;
+             end = high + 1;
+             inc = 1;
+           }
+         for (page = start; page != end; page += inc)
+           {
+             if ((op->priv->manual_page_set == GTK_PAGE_SET_EVEN && page % 2 == 0) ||
+                 (op->priv->manual_page_set == GTK_PAGE_SET_ODD && page % 2 == 1))
+               continue;
+             
+             for (j = 0; j < collated_copies; j++)
+               {
+                 page_setup = gtk_page_setup_copy (initial_page_setup);
+                 g_signal_emit (op, signals[REQUEST_PAGE_SETUP], 0, print_context, page, page_setup);
+                 
+                 _gtk_print_context_set_page_setup (print_context, page_setup);
+                 op->priv->start_page (op, print_context, page_setup);
+                 
+                 cr = gtk_print_context_get_cairo (print_context);
+
+                 cairo_save (cr);
+                 if (op->priv->manual_scale != 100.0)
+                   cairo_scale (cr,
+                                op->priv->manual_scale,
+                                op->priv->manual_scale);
+                 
+                 if (op->priv->manual_orientation)
+                   _gtk_print_context_rotate_according_to_orientation (print_context);
+
+                 if (!op->priv->use_full_page)
+                   _gtk_print_context_translate_into_margin (print_context);
+         
+                 g_signal_emit (op, signals[DRAW_PAGE], 0, 
+                                print_context, page);
+                 
+                 op->priv->end_page (op, print_context);
+                 
+                 cairo_restore (cr);
+                 
+                 g_object_unref (page_setup);
+
+                 /* Iterate the mainloop so that we redraw windows */
+                 while (gtk_events_pending ())
+                   gtk_main_iteration ();
+               }
+           }
+       }
+    }
+  
+  g_signal_emit (op, signals[END_PRINT], 0, print_context);
+
+  g_object_unref (print_context);
+  g_object_unref (initial_page_setup);
+
+  cairo_surface_finish (op->priv->surface);
+  op->priv->end_run (op);
+
+  return GTK_PRINT_OPERATION_RESULT_APPLY;
+}
+
+
+#define __GTK_PRINT_OPERATION_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintoperation.h b/gtk/gtkprintoperation.h
new file mode 100644 (file)
index 0000000..f6a1f3d
--- /dev/null
@@ -0,0 +1,144 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperation.h: Print Operation
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_OPERATION_H__
+#define __GTK_PRINT_OPERATION_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+#include "gtkmain.h"
+#include "gtkenums.h"
+#include "gtkwindow.h"
+#include "gtkpagesetup.h"
+#include "gtkprintsettings.h"
+#include "gtkprintcontext.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_OPERATION               (gtk_print_operation_get_type ())
+#define GTK_PRINT_OPERATION(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_OPERATION, GtkPrintOperation))
+#define GTK_PRINT_OPERATION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_OPERATION, GtkPrintOperationClass))
+#define GTK_IS_PRINT_OPERATION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_OPERATION))
+#define GTK_IS_PRINT_OPERATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_OPERATION))
+#define GTK_PRINT_OPERATION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_OPERATION, GtkPrintOperationClass))
+
+typedef struct _GtkPrintOperationClass   GtkPrintOperationClass;
+typedef struct _GtkPrintOperationPrivate GtkPrintOperationPrivate;
+typedef struct _GtkPrintOperation        GtkPrintOperation;
+
+typedef enum {
+  GTK_PRINT_STATUS_INITIAL,
+  GTK_PRINT_STATUS_PREPARING,
+  GTK_PRINT_STATUS_GENERATING_DATA,
+  GTK_PRINT_STATUS_SENDING_DATA,
+  GTK_PRINT_STATUS_PENDING,
+  GTK_PRINT_STATUS_PENDING_ISSUE,
+  GTK_PRINT_STATUS_PRINTING,
+  GTK_PRINT_STATUS_FINISHED,
+  GTK_PRINT_STATUS_FINISHED_ABORTED
+} GtkPrintStatus;
+
+struct _GtkPrintOperation
+{
+  GObject parent_instance;
+  
+  GtkPrintOperationPrivate *priv;
+};
+
+struct _GtkPrintOperationClass
+{
+  GObjectClass parent_class;
+  
+  void (*begin_print)        (GtkPrintOperation *operation, 
+                              GtkPrintContext   *context);
+  void (*request_page_setup) (GtkPrintOperation *operation,
+                             GtkPrintContext   *context,
+                             gint               page_nr,
+                             GtkPageSetup      *setup);
+  void (*draw_page)          (GtkPrintOperation *operation,
+                             GtkPrintContext   *context,
+                             gint               page_nr);
+  void (*end_print)          (GtkPrintOperation *operation,
+                             GtkPrintContext   *context);
+  void (*status_changed)     (GtkPrintOperation *operation);
+  
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+typedef enum {
+  GTK_PRINT_OPERATION_RESULT_ERROR,
+  GTK_PRINT_OPERATION_RESULT_APPLY,
+  GTK_PRINT_OPERATION_RESULT_CANCEL
+} GtkPrintOperationResult;
+
+#define GTK_PRINT_ERROR gtk_print_error_quark ()
+
+typedef enum
+{
+  GTK_PRINT_ERROR_GENERAL,
+  GTK_PRINT_ERROR_INTERNAL_ERROR,
+  GTK_PRINT_ERROR_NOMEM
+} GtkPrintError;
+
+GQuark gtk_print_error_quark (void);
+
+GType                   gtk_print_operation_get_type               (void) G_GNUC_CONST;
+GtkPrintOperation *     gtk_print_operation_new                    (void);
+void                    gtk_print_operation_set_default_page_setup (GtkPrintOperation  *op,
+                                                                   GtkPageSetup       *default_page_setup);
+GtkPageSetup *          gtk_print_operation_get_default_page_setup (GtkPrintOperation  *op);
+void                    gtk_print_operation_set_print_settings     (GtkPrintOperation  *op,
+                                                                   GtkPrintSettings   *print_settings);
+GtkPrintSettings *      gtk_print_operation_get_print_settings     (GtkPrintOperation  *op);
+void                    gtk_print_operation_set_job_name           (GtkPrintOperation  *op,
+                                                                   const gchar        *job_name);
+void                    gtk_print_operation_set_nr_of_pages        (GtkPrintOperation  *op,
+                                                                   gint                n_pages);
+void                    gtk_print_operation_set_current_page       (GtkPrintOperation  *op,
+                                                                   gint                current_page);
+void                    gtk_print_operation_set_use_full_page      (GtkPrintOperation  *op,
+                                                                   gboolean            full_page);
+void                    gtk_print_operation_set_unit               (GtkPrintOperation  *op,
+                                                                   GtkUnit             unit);
+void                    gtk_print_operation_set_show_dialog        (GtkPrintOperation  *op,
+                                                                   gboolean            show_dialog);
+void                    gtk_print_operation_set_pdf_target         (GtkPrintOperation  *op,
+                                                                   const gchar        *filename);
+GtkPrintOperationResult gtk_print_operation_run                    (GtkPrintOperation  *op,
+                                                                   GtkWindow          *parent,
+                                                                   GError            **error);
+GtkPrintStatus          gtk_print_operation_get_status             (GtkPrintOperation  *op);
+G_CONST_RETURN gchar *  gtk_print_operation_get_status_string      (GtkPrintOperation  *op);
+gboolean                gtk_print_operation_is_finished            (GtkPrintOperation  *op);
+
+GtkPageSetup           *gtk_print_run_page_setup_dialog            (GtkWindow          *parent,
+                                                                   GtkPageSetup       *page_setup,
+                                                                   GtkPrintSettings   *settings);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_OPERATION_H__ */
diff --git a/gtk/gtkprintsettings.c b/gtk/gtkprintsettings.c
new file mode 100644 (file)
index 0000000..80c0c99
--- /dev/null
@@ -0,0 +1,1230 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintsettings.c: Print Settings
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gprintf.h>
+#include "gtkprintsettings.h"
+#include "gtkalias.h"
+
+#define MM_PER_INCH 25.4
+#define POINTS_PER_INCH 72
+
+typedef struct _GtkPrintSettingsClass GtkPrintSettingsClass;
+
+#define GTK_IS_PRINT_SETTINGS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_SETTINGS))
+#define GTK_PRINT_SETTINGS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_SETTINGS, GtkPrintSettingsClass))
+#define GTK_PRINT_SETTINGS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_SETTINGS, GtkPrintSettingsClass))
+
+struct _GtkPrintSettings
+{
+  GObject parent_instance;
+  
+  GHashTable *hash;
+};
+
+struct _GtkPrintSettingsClass
+{
+  GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkPrintSettings, gtk_print_settings, G_TYPE_OBJECT)
+
+static gdouble
+to_mm (gdouble len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len * MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len * (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static gdouble
+from_mm (gdouble len, GtkUnit unit)
+{
+  switch (unit)
+    {
+    case GTK_UNIT_MM:
+      return len;
+    case GTK_UNIT_INCH:
+      return len / MM_PER_INCH;
+    default:
+    case GTK_UNIT_PIXEL:
+      g_warning ("Unsupported unit");
+      /* Fall through */
+    case GTK_UNIT_POINTS:
+      return len / (MM_PER_INCH / POINTS_PER_INCH);
+      break;
+    }
+}
+
+static void
+gtk_print_settings_finalize (GObject *object)
+{
+  GtkPrintSettings *settings = GTK_PRINT_SETTINGS (object);
+
+  g_hash_table_destroy (settings->hash);
+
+  G_OBJECT_CLASS (gtk_print_settings_parent_class)->finalize (object);
+}
+
+static void
+gtk_print_settings_init (GtkPrintSettings *settings)
+{
+  settings->hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                         g_free, g_free);
+}
+
+static void
+gtk_print_settings_class_init (GtkPrintSettingsClass *class)
+{
+  GObjectClass *gobject_class = (GObjectClass *)class;
+
+  gobject_class->finalize = gtk_print_settings_finalize;
+}
+
+/**
+ * gtk_print_settings_new:
+ * 
+ * Creates a new #GtkPrintSettings object.
+ *  
+ * Return value: a new #GtkPrintSettings object
+ *
+ * Since: 2.10
+ */
+GtkPrintSettings *
+gtk_print_settings_new (void)
+{
+  return g_object_new (GTK_TYPE_PRINT_SETTINGS, NULL);
+}
+
+static void
+copy_hash_entry  (gpointer  key,
+                 gpointer  value,
+                 gpointer  user_data)
+{
+  GtkPrintSettings *settings = user_data;
+
+  g_hash_table_insert (settings->hash, 
+                      g_strdup (key), 
+                      g_strdup (value));
+}
+
+
+
+/**
+ * gtk_print_settings_copy:
+ * @other: a #GtkPrintSettings
+ * 
+ * Copies a #GtkPrintSettings object.
+ * 
+ * Return value: a newly allocated copy of @other
+ *
+ * Since: 2.10
+ */
+GtkPrintSettings *
+gtk_print_settings_copy (GtkPrintSettings *other)
+{
+  GtkPrintSettings *settings;
+
+  if (other == NULL)
+    return NULL;
+  
+  g_return_val_if_fail (GTK_IS_PRINT_SETTINGS (other), NULL);
+
+  settings = gtk_print_settings_new ();
+
+  g_hash_table_foreach (other->hash,
+                       copy_hash_entry,
+                       settings);
+
+  return settings;
+}
+
+/**
+ * gtk_print_settings_get:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Looks up the string value associated with @key.
+ * 
+ * Return value: the string value for @key
+ * 
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *        
+gtk_print_settings_get (GtkPrintSettings *settings,
+                       const gchar      *key)
+{
+  return g_hash_table_lookup (settings->hash, key);
+}
+
+/**
+ * gtk_print_settings_set:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @value: a string value, or %NULL
+ * 
+ * Associates @value with @key.
+ *
+ * Since: 2.10 
+ */
+void
+gtk_print_settings_set (GtkPrintSettings *settings,
+                       const gchar      *key,
+                       const gchar      *value)
+{
+  if (value == NULL)
+    gtk_print_settings_unset (settings, key);
+  else
+    g_hash_table_insert (settings->hash, 
+                        g_strdup (key), 
+                        g_strdup (value));
+}
+
+/**
+ * gtk_print_settings_unset:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Removes any value associated with @key. 
+ * This has the same effect as setting the value to %NULL.
+ *
+ * Since: 2.10 
+ */
+void
+gtk_print_settings_unset (GtkPrintSettings *settings,
+                         const gchar      *key)
+{
+  g_hash_table_remove (settings->hash, key);
+}
+
+/**
+ * gtk_print_settings_has_key:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Returns %TRUE, if a value is associated with @key.
+ * 
+ * Return value: %TRUE, if @key has a value
+ *
+ * Since: 2.10
+ */
+gboolean        
+gtk_print_settings_has_key (GtkPrintSettings *settings,
+                           const gchar      *key)
+{
+  return gtk_print_settings_get (settings, key) != NULL;
+}
+
+
+/**
+ * gtk_print_settings_get_bool:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Returns the boolean represented by the value
+ * that is associated with @key. 
+ *
+ * The string "true" represents %TRUE, any other 
+ * string %FALSE.
+ *
+ * Return value: %TRUE, if @key maps to a true value.
+ * 
+ * Since: 2.10
+ **/
+gboolean
+gtk_print_settings_get_bool (GtkPrintSettings *settings,
+                            const gchar      *key)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, key);
+  if (val != NULL && strcmp (val, "true") == 0)
+    return TRUE;
+  
+  return FALSE;
+}
+
+/**
+ * gtk_print_settings_get_bool_with_default:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @default_val: the default value
+ * 
+ * Returns the boolean represented by the value
+ * that is associated with @key, or @default_val
+ * if the value does not represent a boolean.
+ *
+ * The string "true" represents %TRUE, the string
+ * "false" represents %FALSE.
+ *
+ * Return value: the boolean value associated with @key
+ * 
+ * Since: 2.10
+ */
+static gboolean
+gtk_print_settings_get_bool_with_default (GtkPrintSettings *settings,
+                                         const gchar      *key,
+                                         gboolean          default_val)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, key);
+  if (val != NULL && strcmp (val, "true") == 0)
+    return TRUE;
+
+  if (val != NULL && strcmp (val, "false") == 0)
+    return FALSE;
+  
+  return default_val;
+}
+
+/**
+ * gtk_print_settings_set_bool:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @value: a boolean
+ * 
+ * Sets @key to a boolean value.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_bool (GtkPrintSettings *settings,
+                            const gchar      *key,
+                            gboolean          value)
+{
+  if (value)
+    gtk_print_settings_set (settings, key, "true");
+  else
+    gtk_print_settings_set (settings, key, "false");
+}
+
+/**
+ * gtk_print_settings_get_double_with_default:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @def: the default value
+ * 
+ * Returns the floating point number represented by 
+ * the value that is associated with @key, or @default_val
+ * if the value does not represent a floating point number.
+ *
+ * Floating point numbers are parsed with g_ascii_strtod().
+ *
+ * Return value: the floating point number associated with @key
+ * 
+ * Since: 2.10
+ */
+gdouble
+gtk_print_settings_get_double_with_default (GtkPrintSettings *settings,
+                                           const gchar      *key,
+                                           gdouble           def)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, key);
+  if (val == NULL)
+    return def;
+
+  return g_ascii_strtod (val, NULL);
+}
+
+/**
+ * gtk_print_settings_get_double:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Returns the double value associated with @key, or 0.
+ * 
+ * Return value: the double value of @key
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_settings_get_double (GtkPrintSettings *settings,
+                              const gchar      *key)
+{
+  return gtk_print_settings_get_double_with_default (settings, key, 0.0);
+}
+
+/**
+ * gtk_print_settings_set_double:
+ * @settings: a #GtkPrintSettings
+ * @key: a key 
+ * @value: a double value
+ * 
+ * Sets @key to a double value.
+ * 
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_double (GtkPrintSettings *settings,
+                              const gchar      *key,
+                              gdouble           value)
+{
+  gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+  
+  g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, value);
+  gtk_print_settings_set (settings, key, buf);
+}
+
+/**
+ * gtk_print_settings_get_length:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @unit: the unit of the return value
+ * 
+ * Returns the value associated with @key, interpreted
+ * as a length. The returned value is converted to @units.
+ * 
+ * Return value: the length value of @key, converted to @unit
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_settings_get_length (GtkPrintSettings *settings,
+                              const gchar      *key,
+                              GtkUnit           unit)
+{
+  gdouble length = gtk_print_settings_get_double (settings, key);
+  return from_mm (length, unit);
+}
+
+/**
+ * gtk_print_settings_set_length:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @length: a length
+ * @unit: the unit of @length
+ * 
+ * Associates a length in units of @unit with @key.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_length (GtkPrintSettings *settings,
+                              const gchar      *key,
+                              gdouble           length, 
+                              GtkUnit           unit)
+{
+  gtk_print_settings_set_double (settings, key,
+                                to_mm (length, unit));
+}
+
+/**
+ * gtk_print_settings_get_int_with_default:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @def: the default value
+ * 
+ * Returns the value of @key, interpreted as
+ * an integer, or the default value.
+ * 
+ * Return value: the integer value of @key
+ *
+ * Since: 2.10
+ */
+gint
+gtk_print_settings_get_int_with_default (GtkPrintSettings *settings,
+                                        const gchar      *key,
+                                        gint              def)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, key);
+  if (val == NULL)
+    return def;
+
+  return atoi (val);
+}
+
+/**
+ * gtk_print_settings_get_int:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * 
+ * Returns the integer value of @key, or 0.
+ * 
+ * Return value: the integer value of @key 
+ *
+ * Since: 2.10
+ */
+gint
+gtk_print_settings_get_int (GtkPrintSettings *settings,
+                           const gchar      *key)
+{
+  return gtk_print_settings_get_int_with_default (settings, key, 0);
+}
+
+/**
+ * gtk_print_settings_set_int:
+ * @settings: a #GtkPrintSettings
+ * @key: a key
+ * @value: an integer 
+ * 
+ * Sets @key to an integer value.
+ *
+ * Since: 2.10 
+ */
+void
+gtk_print_settings_set_int (GtkPrintSettings *settings,
+                           const gchar      *key,
+                           gint              value)
+{
+  gchar buf[128];
+  g_sprintf (buf, "%d", value);
+  gtk_print_settings_set (settings, key, buf);
+}
+
+/**
+ * gtk_print_settings_foreach:
+ * @settings: a #GtkPrintSettings
+ * @func: the function to call
+ * @user_data: user data for @func
+ * 
+ * Calls @func for each key-value pair of @settings.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_foreach (GtkPrintSettings    *settings,
+                           GtkPrintSettingsFunc func,
+                           gpointer             user_data)
+{
+  g_hash_table_foreach (settings->hash, (GHFunc)func, user_data);
+}
+
+/**
+ * gtk_print_settings_get_printer:
+ * @settings: a #GtkPrintSettings
+ * 
+ * Convenience function to obtain the value of 
+ * %GTK_PRINT_SETTINGS_PRINTER.
+ *
+ * Return value: the printer name
+ *
+ * Since: 2.10
+ */
+G_CONST_RETURN gchar *       
+gtk_print_settings_get_printer (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PRINTER);
+}
+
+
+/**
+ * gtk_print_settings_set_printer:
+ * @settings: a #GtkPrintSettings
+ * @printer: the printer name
+ * 
+ * Convenience function to set %GTK_PRINT_SETTINGS_PRINTER
+ * to @printer.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_printer (GtkPrintSettings *settings,
+                               const gchar      *printer)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PRINTER, printer);
+}
+
+/**
+ * gtk_print_settings_get_orientation:
+ * @settings: a #GtkPrintSettings
+ * 
+ * Get the value of %GTK_PRINT_SETTINGS_ORIENTATION, 
+ * converted to a #GtkPageOrientation.
+ * 
+ * Return value: the orientation
+ *
+ * Since: 2.10
+ */
+GtkPageOrientation
+gtk_print_settings_get_orientation (GtkPrintSettings *settings)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_ORIENTATION);
+
+  if (val == NULL || strcmp (val, "portrait") == 0)
+    return GTK_PAGE_ORIENTATION_PORTRAIT;
+
+  if (strcmp (val, "landscape") == 0)
+    return GTK_PAGE_ORIENTATION_LANDSCAPE;
+  
+  if (strcmp (val, "reverse_portrait") == 0)
+    return GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT;
+  
+  if (strcmp (val, "reverse_landscape") == 0)
+    return GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE;
+  
+  return GTK_PAGE_ORIENTATION_PORTRAIT;
+}
+
+/**
+ * gtk_print_settings_set_orientation:
+ * @settings: a #GtkPrintSettings
+ * @orientation: a page orientation
+ * 
+ * Sets the value of %GTK_PRINT_SETTINGS_ORIENTATION.
+ * 
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_orientation (GtkPrintSettings   *settings,
+                                   GtkPageOrientation  orientation)
+{
+  const gchar *val;
+
+  switch (orientation)
+    {
+    case GTK_PAGE_ORIENTATION_LANDSCAPE:
+      val = "landscape";
+      break;
+    default:
+    case GTK_PAGE_ORIENTATION_PORTRAIT:
+      val = "portrait";
+      break;
+    case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+      val = "reverse_landscape";
+      break;
+    case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+      val = "reverse_portrait";
+      break;
+    }
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_ORIENTATION, val);
+}
+
+/**
+ * gtk_print_settings_get_paper_size:
+ * @settings: a #GtkPrintSettings
+ * 
+ * Gets the value of %GTK_PRINT_SETTINGS_PAPER_FORMAT, 
+ * converted to a #GtkPaperSize.
+ * 
+ * Return value: the paper size
+ *
+ * Since: 2.10
+ */
+GtkPaperSize *     
+gtk_print_settings_get_paper_size (GtkPrintSettings *settings)
+{
+  const gchar *val;
+  const gchar *name;
+  gdouble w, h;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PAPER_FORMAT);
+  if (val == NULL)
+    return NULL;
+
+  if (g_str_has_prefix (val, "custom-")) 
+    {
+      name = val + strlen ("custom-");
+      w = gtk_print_settings_get_paper_width (settings, GTK_UNIT_MM);
+      h = gtk_print_settings_get_paper_height (settings, GTK_UNIT_MM);
+      return gtk_paper_size_new_custom (name, name, w, h, GTK_UNIT_MM);
+    }
+
+  return gtk_paper_size_new (val);
+}
+
+/**
+ * gtk_print_settings_set_paper_size:
+ * @settings: a #GtkPrintSettings
+ * @paper_size: a paper size
+ * 
+ * Sets the value of %GTK_PRINT_SETTINGS_PAPER_FORMAT,
+ * %GTK_PRINT_SETTINGS_PAPER_WIDTH and
+ * %GTK_PRINT_SETTINGS_PAPER_HEIGHT.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_paper_size (GtkPrintSettings *settings,
+                                  GtkPaperSize     *paper_size)
+{
+  gchar *custom_name;
+
+  if (paper_size == NULL) 
+    {
+      gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAPER_FORMAT, NULL);
+      gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAPER_WIDTH, NULL);
+      gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAPER_HEIGHT, NULL);
+    }
+  else if (gtk_paper_size_is_custom (paper_size)) 
+    {
+      custom_name = g_strdup_printf ("custom-%s", 
+                                    gtk_paper_size_get_name (paper_size));
+      gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAPER_FORMAT, custom_name);
+      g_free (custom_name);
+      gtk_print_settings_set_paper_width (settings, 
+                                         gtk_paper_size_get_width (paper_size, 
+                                                                   GTK_UNIT_MM),
+                                         GTK_UNIT_MM);
+      gtk_print_settings_set_paper_height (settings, 
+                                          gtk_paper_size_get_height (paper_size, 
+                                                                     GTK_UNIT_MM),
+                                          GTK_UNIT_MM);
+    } 
+  else
+    gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAPER_FORMAT, 
+                           gtk_paper_size_get_name (paper_size));
+}
+
+/**
+ * gtk_print_settings_get_paper_width:
+ * @settings: a #GtkPrintSettings
+ * @unit: the unit for the return value
+ * 
+ * Gets the value of %GTK_PRINT_SETTINGS_PAPER_WIDTH,
+ * converted to @unit. 
+ * 
+ * Return value: the paper width, in units of @unit
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_settings_get_paper_width (GtkPrintSettings *settings,
+                                   GtkUnit           unit)
+{
+  return gtk_print_settings_get_length (settings, GTK_PRINT_SETTINGS_PAPER_WIDTH, unit);
+}
+
+/**
+ * gtk_print_settings_set_paper_width:
+ * @settings: a #GtkPrintSettings
+ * @width: the paper width
+ * @unit: the units of @width
+ * 
+ * Sets the value of %GTK_PRINT_SETTINGS_PAPER_WIDTH.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_paper_width (GtkPrintSettings *settings,
+                                   gdouble           width, 
+                                   GtkUnit           unit)
+{
+  gtk_print_settings_set_length (settings, GTK_PRINT_SETTINGS_PAPER_WIDTH, width, unit);
+}
+
+/**
+ * gtk_print_settings_get_paper_height:
+ * @settings: a #GtkPrintSettings
+ * @unit: the unit for the return value
+ * 
+ * Gets the value of %GTK_PRINT_SETTINGS_PAPER_HEIGHT,
+ * converted to @unit. 
+ * 
+ * Return value: the paper height, in units of @unit
+ *
+ * Since: 2.10
+ */
+gdouble
+gtk_print_settings_get_paper_height (GtkPrintSettings *settings,
+                                    GtkUnit           unit)
+{
+  return gtk_print_settings_get_length (settings, 
+                                       GTK_PRINT_SETTINGS_PAPER_HEIGHT,
+                                       unit);
+}
+
+/**
+ * gtk_print_settings_set_paper_height:
+ * @settings: a #GtkPrintSettings
+ * @height: the paper height
+ * @unit: the units of @height
+ * 
+ * Sets the value of %GTK_PRINT_SETTINGS_PAPER_HEIGHT.
+ *
+ * Since: 2.10
+ */
+void
+gtk_print_settings_set_paper_height (GtkPrintSettings *settings,
+                                    gdouble           height, 
+                                    GtkUnit           unit)
+{
+  gtk_print_settings_set_length (settings, 
+                                GTK_PRINT_SETTINGS_PAPER_HEIGHT, 
+                                height, unit);
+}
+
+gboolean
+gtk_print_settings_get_use_color (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_bool_with_default (settings, 
+                                                  GTK_PRINT_SETTINGS_USE_COLOR,
+                                                  TRUE);
+}
+
+void
+gtk_print_settings_set_use_color (GtkPrintSettings *settings,
+                                 gboolean          use_color)
+{
+  gtk_print_settings_set_bool (settings,
+                              GTK_PRINT_SETTINGS_USE_COLOR, 
+                              use_color);
+}
+
+gboolean
+gtk_print_settings_get_collate (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_bool (settings, 
+                                     GTK_PRINT_SETTINGS_COLLATE);
+}
+
+void
+gtk_print_settings_set_collate (GtkPrintSettings *settings,
+                               gboolean          collate)
+{
+  gtk_print_settings_set_bool (settings,
+                              GTK_PRINT_SETTINGS_COLLATE, 
+                              collate);
+}
+
+gboolean
+gtk_print_settings_get_reverse (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_bool (settings, 
+                                     GTK_PRINT_SETTINGS_REVERSE);
+}
+
+void
+gtk_print_settings_set_reverse (GtkPrintSettings *settings,
+                                 gboolean        reverse)
+{
+  gtk_print_settings_set_bool (settings,
+                              GTK_PRINT_SETTINGS_REVERSE, 
+                              reverse);
+}
+
+GtkPrintDuplex
+gtk_print_settings_get_duplex (GtkPrintSettings *settings)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_DUPLEX);
+
+  if (val == NULL || (strcmp (val, "simplex") == 0))
+    return GTK_PRINT_DUPLEX_SIMPLEX;
+
+  if (strcmp (val, "horizontal") == 0)
+    return GTK_PRINT_DUPLEX_HORIZONTAL;
+  
+  if (strcmp (val, "vertical") == 0)
+    return GTK_PRINT_DUPLEX_HORIZONTAL;
+  
+  return GTK_PRINT_DUPLEX_SIMPLEX;
+}
+
+void
+gtk_print_settings_set_duplex (GtkPrintSettings *settings,
+                              GtkPrintDuplex    duplex)
+{
+  const gchar *str;
+
+  switch (duplex)
+    {
+    default:
+    case GTK_PRINT_DUPLEX_SIMPLEX:
+      str = "simplex";
+      break;
+    case GTK_PRINT_DUPLEX_HORIZONTAL:
+      str = "horizontal";
+      break;
+    case GTK_PRINT_DUPLEX_VERTICAL:
+      str = "vertical";
+      break;
+    }
+  
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_DUPLEX, str);
+}
+
+GtkPrintQuality
+gtk_print_settings_get_quality (GtkPrintSettings *settings)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_QUALITY);
+
+  if (val == NULL || (strcmp (val, "normal") == 0))
+    return GTK_PRINT_QUALITY_NORMAL;
+
+  if (strcmp (val, "high") == 0)
+    return GTK_PRINT_QUALITY_HIGH;
+  
+  if (strcmp (val, "low") == 0)
+    return GTK_PRINT_QUALITY_LOW;
+  
+  if (strcmp (val, "draft") == 0)
+    return GTK_PRINT_QUALITY_DRAFT;
+  
+  return GTK_PRINT_QUALITY_NORMAL;
+}
+
+void
+gtk_print_settings_set_quality (GtkPrintSettings *settings,
+                               GtkPrintQuality   quality)
+{
+  const gchar *str;
+
+  switch (quality)
+    {
+    default:
+    case GTK_PRINT_QUALITY_NORMAL:
+      str = "normal";
+      break;
+    case GTK_PRINT_QUALITY_HIGH:
+      str = "high";
+      break;
+    case GTK_PRINT_QUALITY_LOW:
+      str = "low";
+      break;
+    case GTK_PRINT_QUALITY_DRAFT:
+      str = "draft";
+      break;
+    }
+  
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_QUALITY, str);
+}
+
+GtkPageSet
+gtk_print_settings_get_page_set (GtkPrintSettings *settings)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PAGE_SET);
+
+  if (val == NULL || (strcmp (val, "all") == 0))
+    return GTK_PAGE_SET_ALL;
+
+  if (strcmp (val, "even") == 0)
+    return GTK_PAGE_SET_EVEN;
+  
+  if (strcmp (val, "odd") == 0)
+    return GTK_PAGE_SET_ODD;
+  
+  return GTK_PAGE_SET_ALL;
+}
+
+void
+gtk_print_settings_set_page_set (GtkPrintSettings *settings,
+                                GtkPageSet        page_set)
+{
+  const gchar *str;
+
+  switch (page_set)
+    {
+    default:
+    case GTK_PAGE_SET_ALL:
+      str = "all";
+      break;
+    case GTK_PAGE_SET_EVEN:
+      str = "even";
+      break;
+    case GTK_PAGE_SET_ODD:
+      str = "odd";
+      break;
+    }
+  
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAGE_SET, str);
+}
+
+gint
+gtk_print_settings_get_num_copies (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_NUM_COPIES, 1);
+}
+
+void
+gtk_print_settings_set_num_copies (GtkPrintSettings *settings,
+                                  gint              num_copies)
+{
+  gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_NUM_COPIES,
+                             num_copies);
+}
+
+gint
+gtk_print_settings_get_number_up (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_NUMBER_UP);
+}
+
+void
+gtk_print_settings_set_number_up (GtkPrintSettings *settings,
+                                 gint              number_up)
+{
+  gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_NUMBER_UP,
+                               number_up);
+}
+
+gint
+gtk_print_settings_get_resolution (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION);
+}
+
+void
+gtk_print_settings_set_resolution (GtkPrintSettings *settings,
+                                  gint              resolution)
+{
+  gtk_print_settings_set_int (settings, GTK_PRINT_SETTINGS_RESOLUTION,
+                             resolution);
+}
+
+gdouble
+gtk_print_settings_get_scale (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_double_with_default (settings,
+                                                    GTK_PRINT_SETTINGS_SCALE,
+                                                    100.0);
+}
+
+void
+gtk_print_settings_set_scale (GtkPrintSettings *settings,
+                             gdouble           scale)
+{
+  gtk_print_settings_set_double (settings, GTK_PRINT_SETTINGS_SCALE,
+                                scale);
+}
+
+gboolean
+gtk_print_settings_get_print_to_file (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get_bool (settings, 
+                                     GTK_PRINT_SETTINGS_PRINT_TO_FILE);
+}
+
+void
+gtk_print_settings_set_print_to_file (GtkPrintSettings *settings,
+                                     gboolean          print_to_file)
+{
+  gtk_print_settings_set_bool (settings,
+                              GTK_PRINT_SETTINGS_PRINT_TO_FILE, 
+                              print_to_file);
+}
+
+GtkPrintPages
+gtk_print_settings_get_print_pages (GtkPrintSettings *settings)
+{
+  const gchar *val;
+
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PRINT_PAGES);
+
+  if (val == NULL || (strcmp (val, "all") == 0))
+    return GTK_PRINT_PAGES_ALL;
+
+  if (strcmp (val, "current") == 0)
+    return GTK_PRINT_PAGES_CURRENT;
+  
+  if (strcmp (val, "ranges") == 0)
+    return GTK_PRINT_PAGES_RANGES;
+  
+  return GTK_PRINT_PAGES_ALL;
+}
+
+void
+gtk_print_settings_set_print_pages (GtkPrintSettings *settings,
+                                   GtkPrintPages     print_pages)
+{
+  const gchar *str;
+
+  switch (print_pages)
+    {
+    default:
+    case GTK_PRINT_PAGES_ALL:
+      str = "all";
+      break;
+    case GTK_PRINT_PAGES_CURRENT:
+      str = "current";
+      break;
+    case GTK_PRINT_PAGES_RANGES:
+      str = "ranges";
+      break;
+    }
+  
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PRINT_PAGES, str);
+}
+     
+
+
+GtkPageRange *
+gtk_print_settings_get_page_ranges (GtkPrintSettings *settings,
+                                   gint             *num_ranges)
+{
+  const gchar *val;
+  gchar **range_strs;
+  GtkPageRange *ranges;
+  gint i, n;
+  
+  val = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PAGE_RANGES);
+
+  if (val == NULL)
+    {
+      *num_ranges = 0;
+      return NULL;
+    }
+  
+  range_strs = g_strsplit (val, ",", 0);
+
+  for (i = 0; range_strs[i] != NULL; i++)
+    ;
+
+  n = i;
+
+  ranges = g_new0 (GtkPageRange, n);
+
+  for (i = 0; i < n; i++)
+    {
+      gint start, end;
+      gchar *str;
+
+      start = (gint)strtol (range_strs[i], &str, 10);
+      end = start;
+
+      if (*str == '-')
+       {
+         str++;
+         end = (gint)strtol (str, NULL, 10);
+         if (end < start)
+           end = start;
+       }
+
+      ranges[i].start = start;
+      ranges[i].end = end;
+    }
+
+  *num_ranges = n;
+  return ranges;
+}
+
+void
+gtk_print_settings_set_page_ranges  (GtkPrintSettings *settings,
+                                    GtkPageRange     *page_ranges,
+                                    gint              num_ranges)
+{
+  GString *s;
+  gint i;
+  
+  s = g_string_new ("");
+
+  for (i = 0; i < num_ranges; i++)
+    {
+      if (page_ranges[i].start == page_ranges[i].end)
+       g_string_append_printf (s, "%d", page_ranges[i].start);
+      else
+       g_string_append_printf (s, "%d-%d",
+                               page_ranges[i].start,
+                               page_ranges[i].end);
+      if (i < num_ranges - 1)
+       g_string_append (s, ",");
+    }
+
+  
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_PAGE_RANGES, 
+                         s->str);
+
+  g_string_free (s, TRUE);
+}
+
+G_CONST_RETURN gchar *
+gtk_print_settings_get_default_source (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE);
+}
+
+void
+gtk_print_settings_set_default_source (GtkPrintSettings *settings,
+                                      const gchar      *default_source)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, default_source);
+}
+     
+G_CONST_RETURN gchar *
+gtk_print_settings_get_media_type (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE);
+}
+
+/* The set of media types is defined in PWG 5101.1-2002 PWG */
+void
+gtk_print_settings_set_media_type (GtkPrintSettings *settings,
+                                  const gchar      *media_type)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, media_type);
+}
+
+
+G_CONST_RETURN gchar *
+gtk_print_settings_get_dither (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_DITHER);
+}
+
+void
+gtk_print_settings_set_dither (GtkPrintSettings *settings,
+                              const gchar      *dither)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_DITHER, dither);
+}
+     
+const gchar *
+gtk_print_settings_get_finishings (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_FINISHINGS);
+}
+
+void
+gtk_print_settings_set_finishings (GtkPrintSettings *settings,
+                                  const gchar      *finishings)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_FINISHINGS, finishings);
+}
+     
+G_CONST_RETURN gchar *
+gtk_print_settings_get_output_bin (GtkPrintSettings *settings)
+{
+  return gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_BIN);
+}
+
+void
+gtk_print_settings_set_output_bin (GtkPrintSettings *settings,
+                                  const gchar      *output_bin)
+{
+  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, output_bin);
+}
+   
+
+#define __GTK_PRINT_SETTINGS_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintsettings.h b/gtk/gtkprintsettings.h
new file mode 100644 (file)
index 0000000..3c5a748
--- /dev/null
@@ -0,0 +1,196 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintsettings.h: Print Settings
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINT_SETTINGS_H__
+#define __GTK_PRINT_SETTINGS_H__
+
+#include <glib-object.h>
+#include "gtkpapersize.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkPrintSettings GtkPrintSettings;
+
+#define GTK_TYPE_PRINT_SETTINGS    (gtk_print_settings_get_type ())
+#define GTK_PRINT_SETTINGS(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_SETTINGS, GtkPrintSettings))
+#define GTK_IS_PRINT_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_SETTINGS))
+
+typedef void  (*GtkPrintSettingsFunc)  (const gchar *key,
+                                       const gchar *value,
+                                       gpointer     user_data);
+
+typedef struct 
+{
+  gint start;
+  gint end;
+} GtkPageRange;
+
+GType             gtk_print_settings_get_type (void) G_GNUC_CONST;
+GtkPrintSettings *gtk_print_settings_new      (void);
+
+GtkPrintSettings *gtk_print_settings_copy                    (GtkPrintSettings     *other);
+gboolean          gtk_print_settings_has_key                 (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+G_CONST_RETURN gchar *gtk_print_settings_get                (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+void              gtk_print_settings_set                     (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             const gchar          *value);
+void              gtk_print_settings_unset                   (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+void              gtk_print_settings_foreach                 (GtkPrintSettings     *settings,
+                                                             GtkPrintSettingsFunc  func,
+                                                             gpointer              user_data);
+gboolean          gtk_print_settings_get_bool                (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+void              gtk_print_settings_set_bool                (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gboolean              value);
+gdouble           gtk_print_settings_get_double              (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+gdouble           gtk_print_settings_get_double_with_default (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gdouble               def);
+void              gtk_print_settings_set_double              (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gdouble               value);
+gdouble           gtk_print_settings_get_length              (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             GtkUnit               unit);
+void              gtk_print_settings_set_length              (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gdouble               value,
+                                                             GtkUnit               unit);
+gint              gtk_print_settings_get_int                 (GtkPrintSettings     *settings,
+                                                             const gchar          *key);
+gint              gtk_print_settings_get_int_with_default    (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gint                  def);
+void              gtk_print_settings_set_int                 (GtkPrintSettings     *settings,
+                                                             const gchar          *key,
+                                                             gint                  value);
+
+#define GTK_PRINT_SETTINGS_PRINTER        "printer"
+#define GTK_PRINT_SETTINGS_ORIENTATION    "orientation"
+#define GTK_PRINT_SETTINGS_PAPER_FORMAT   "paper-format"
+#define GTK_PRINT_SETTINGS_PAPER_WIDTH    "paper-width"
+#define GTK_PRINT_SETTINGS_PAPER_HEIGHT   "paper-height"
+#define GTK_PRINT_SETTINGS_NUM_COPIES     "num-copies"
+#define GTK_PRINT_SETTINGS_DEFAULT_SOURCE "default-source"
+#define GTK_PRINT_SETTINGS_QUALITY        "quality"
+#define GTK_PRINT_SETTINGS_RESOLUTION     "resolution"
+#define GTK_PRINT_SETTINGS_USE_COLOR      "use-color"
+#define GTK_PRINT_SETTINGS_DUPLEX         "duplex"
+#define GTK_PRINT_SETTINGS_COLLATE        "collate"
+#define GTK_PRINT_SETTINGS_REVERSE        "reverse"
+#define GTK_PRINT_SETTINGS_MEDIA_TYPE     "media-type"
+#define GTK_PRINT_SETTINGS_DITHER         "dither"
+#define GTK_PRINT_SETTINGS_SCALE          "scale"
+#define GTK_PRINT_SETTINGS_PRINT_PAGES    "print-pages"
+#define GTK_PRINT_SETTINGS_PAGE_RANGES    "page-ranges"
+#define GTK_PRINT_SETTINGS_PAGE_SET       "page-set"
+#define GTK_PRINT_SETTINGS_PRINT_TO_FILE  "print-to-file"
+#define GTK_PRINT_SETTINGS_FINISHINGS     "finishings"
+#define GTK_PRINT_SETTINGS_NUMBER_UP      "number-up"
+#define GTK_PRINT_SETTINGS_OUTPUT_BIN     "output-bin"
+
+#define GTK_PRINT_SETTINGS_WIN32_DRIVER_VERSION "win32-driver-version"
+#define GTK_PRINT_SETTINGS_WIN32_DRIVER_EXTRA   "win32-driver-extra"
+
+/* Helpers: */
+
+G_CONST_RETURN gchar *gtk_print_settings_get_printer     (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_printer        (GtkPrintSettings   *settings,
+                                                         const gchar        *printer);
+GtkPageOrientation gtk_print_settings_get_orientation    (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_orientation    (GtkPrintSettings   *settings,
+                                                         GtkPageOrientation  orientation);
+GtkPaperSize *     gtk_print_settings_get_paper_size     (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_paper_size     (GtkPrintSettings   *settings,
+                                                         GtkPaperSize       *paper_size);
+gdouble            gtk_print_settings_get_paper_width    (GtkPrintSettings   *settings,
+                                                         GtkUnit             unit);
+void               gtk_print_settings_set_paper_width    (GtkPrintSettings   *settings,
+                                                         gdouble             width,
+                                                         GtkUnit             unit);
+gdouble            gtk_print_settings_get_paper_height   (GtkPrintSettings   *settings,
+                                                         GtkUnit             unit);
+void               gtk_print_settings_set_paper_height   (GtkPrintSettings   *settings,
+                                                         gdouble             width,
+                                                         GtkUnit             unit);
+gboolean           gtk_print_settings_get_use_color      (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_use_color      (GtkPrintSettings   *settings,
+                                                         gboolean            use_color);
+gboolean           gtk_print_settings_get_collate        (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_collate        (GtkPrintSettings   *settings,
+                                                         gboolean            collate);
+gboolean           gtk_print_settings_get_reverse        (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_reverse        (GtkPrintSettings   *settings,
+                                                         gboolean            reverse);
+GtkPrintDuplex     gtk_print_settings_get_duplex         (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_duplex         (GtkPrintSettings   *settings,
+                                                         GtkPrintDuplex      duplex);
+GtkPrintQuality    gtk_print_settings_get_quality        (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_quality        (GtkPrintSettings   *settings,
+                                                         GtkPrintQuality     quality);
+gint               gtk_print_settings_get_num_copies     (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_num_copies     (GtkPrintSettings   *settings,
+                                                         gint                num_copies);
+gint               gtk_print_settings_get_number_up      (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_number_up      (GtkPrintSettings   *settings,
+                                                         gint                number_up);
+gint               gtk_print_settings_get_resolution     (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_resolution     (GtkPrintSettings   *settings,
+                                                         gint                resolution);
+gdouble            gtk_print_settings_get_scale          (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_scale          (GtkPrintSettings   *settings,
+                                                         gdouble             scale);
+gboolean           gtk_print_settings_get_print_to_file  (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_print_to_file  (GtkPrintSettings   *settings,
+                                                         gboolean            print_to_file);
+GtkPrintPages      gtk_print_settings_get_print_pages    (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_print_pages    (GtkPrintSettings   *settings,
+                                                         GtkPrintPages       pages);
+GtkPageRange *     gtk_print_settings_get_page_ranges    (GtkPrintSettings   *settings,
+                                                         gint               *num_ranges);
+void               gtk_print_settings_set_page_ranges    (GtkPrintSettings   *settings,
+                                                         GtkPageRange       *page_ranges,
+                                                         gint                num_ranges);
+GtkPageSet         gtk_print_settings_get_page_set       (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_page_set       (GtkPrintSettings   *settings,
+                                                         GtkPageSet          page_set);
+G_CONST_RETURN gchar *gtk_print_settings_get_default_source (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_default_source (GtkPrintSettings   *settings,
+                                                         const gchar        *default_source);
+G_CONST_RETURN gchar *gtk_print_settings_get_media_type  (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_media_type     (GtkPrintSettings   *settings,
+                                                         const gchar        *media_type);
+G_CONST_RETURN gchar *gtk_print_settings_get_dither      (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_dither         (GtkPrintSettings   *settings,
+                                                         const gchar        *dither);
+G_CONST_RETURN gchar *gtk_print_settings_get_finishings  (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_finishings     (GtkPrintSettings   *settings,
+                                                         const gchar        *finishings);
+G_CONST_RETURN gchar *gtk_print_settings_get_output_bin  (GtkPrintSettings   *settings);
+void               gtk_print_settings_set_output_bin     (GtkPrintSettings   *settings,
+                                                         const gchar        *output_bin);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_SETTINGS_H__ */
diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c
new file mode 100644 (file)
index 0000000..e7fc660
--- /dev/null
@@ -0,0 +1,2577 @@
+/* GtkPrintUnixDialog
+ * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
+ * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkspinbutton.h"
+#include "gtkcellrendererpixbuf.h"
+#include "gtkcellrenderertext.h"
+#include "gtkstock.h"
+#include "gtkimage.h"
+#include "gtktreeselection.h"
+#include "gtknotebook.h"
+#include "gtkscrolledwindow.h"
+#include "gtkcombobox.h"
+#include "gtktogglebutton.h"
+#include "gtkradiobutton.h"
+#include "gtkdrawingarea.h"
+#include "gtkvbox.h"
+#include "gtktable.h"
+#include "gtkframe.h"
+#include "gtkalignment.h"
+#include "gtklabel.h"
+
+#include "gtkprintbackend.h"
+#include "gtkprintunixdialog.h"
+#include "gtkprinteroptionwidget.h"
+#include "gtkalias.h"
+
+#define EXAMPLE_PAGE_AREA_SIZE 140
+
+#define GTK_PRINT_UNIX_DIALOG_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialogPrivate))
+
+static void gtk_print_unix_dialog_destroy      (GtkPrintUnixDialog *dialog);
+static void gtk_print_unix_dialog_finalize     (GObject            *object);
+static void gtk_print_unix_dialog_set_property (GObject            *object,
+                                               guint               prop_id,
+                                               const GValue       *value,
+                                               GParamSpec         *pspec);
+static void gtk_print_unix_dialog_get_property (GObject            *object,
+                                               guint               prop_id,
+                                               GValue             *value,
+                                               GParamSpec         *pspec);
+static void populate_dialog                    (GtkPrintUnixDialog *dialog);
+static void unschedule_idle_mark_conflicts     (GtkPrintUnixDialog *dialog);
+static void selected_printer_changed           (GtkTreeSelection   *selection,
+                                               GtkPrintUnixDialog *dialog);
+static void clear_per_printer_ui               (GtkPrintUnixDialog *dialog);
+
+enum {
+  PROP_0,
+  PROP_PAGE_SETUP,
+  PROP_CURRENT_PAGE,
+  PROP_PRINT_SETTINGS,
+  PROP_SELECTED_PRINTER
+};
+
+enum {
+  PRINTER_LIST_COL_ICON,
+  PRINTER_LIST_COL_NAME,
+  PRINTER_LIST_COL_STATE,
+  PRINTER_LIST_COL_JOBS,
+  PRINTER_LIST_COL_LOCATION,
+  PRINTER_LIST_COL_PRINTER_OBJ,
+  PRINTER_LIST_N_COLS
+};
+
+#define _EXTENTION_POINT_MAIN_PAGE_CUSTOM_INPUT "gtk-main-page-custom-input"
+
+struct GtkPrintUnixDialogPrivate
+{
+  GtkWidget *notebook;
+
+  GtkWidget *printer_treeview;
+  
+  GtkTreeModel *printer_list;
+  GtkTreeModelFilter *printer_list_filter;
+
+  GtkPageSetup *page_setup;
+
+  GtkWidget *all_pages_radio;
+  GtkWidget *current_page_radio;
+  GtkWidget *page_range_radio;
+  GtkWidget *page_range_entry;
+  
+  GtkWidget *copies_spin;
+  GtkWidget *collate_check;
+  GtkWidget *reverse_check;
+  GtkWidget *collate_image;
+  GtkWidget *page_layout_preview;
+  GtkWidget *scale_spin;
+  GtkWidget *page_set_combo;
+  GtkWidget *print_now_radio;
+  GtkWidget *print_at_radio;
+  GtkWidget *print_at_entry;
+  GtkWidget *print_hold_radio;
+  gboolean updating_print_at;
+  GtkPrinterOptionWidget *pages_per_sheet;
+  GtkPrinterOptionWidget *duplex;
+  GtkPrinterOptionWidget *paper_type;
+  GtkPrinterOptionWidget *paper_source;
+  GtkPrinterOptionWidget *output_tray;
+  GtkPrinterOptionWidget *job_prio;
+  GtkPrinterOptionWidget *billing_info;
+  GtkPrinterOptionWidget *cover_before;
+  GtkPrinterOptionWidget *cover_after;
+
+  GtkWidget *conflicts_widget;
+
+  GtkWidget *job_page;
+  GtkWidget *finishing_table;
+  GtkWidget *finishing_page;
+  GtkWidget *image_quality_table;
+  GtkWidget *image_quality_page;
+  GtkWidget *color_table;
+  GtkWidget *color_page;
+
+  GtkWidget *advanced_vbox;
+  GtkWidget *advanced_page;
+
+  GHashTable *extention_points;  
+
+  /* These are set initially on selected printer (either default printer, printer
+   * taken from set settings, or user-selected), but when any setting is changed
+   * by the user it is cleared */
+  GtkPrintSettings *initial_settings;
+  
+  /* This is the initial printer set by set_settings. We look for it in the
+   * added printers. We clear this whenever the user manually changes
+   * to another printer, when the user changes a setting or when we find
+   * this printer */
+  char *waiting_for_printer;
+  gboolean internal_printer_change;
+  
+  GList *print_backends;
+  
+  GtkPrinter *current_printer;
+  guint request_details_tag;
+  GtkPrinterOptionSet *options;
+  gulong options_changed_handler;
+  gulong mark_conflicts_id;
+
+  char *format_for_printer;
+  
+  gint current_page;
+};
+
+G_DEFINE_TYPE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG);
+
+/* XPM */
+static const char *collate_xpm[] = {
+"65 35 6 1",
+"      c None",
+".     c #000000",
+"+     c #020202",
+"@     c #FFFFFF",
+"#     c #010101",
+"$     c #070707",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..",
+"           ..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"..+++++++++##++++++$@@@@@@@@@..   ..+++++++++##++++++$@@@@@@@@@..",
+"..+++++++++##+++++#+@@@@@@@@@..   ..+++++++++##+++++#+@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@..@@@@..   ..@@@@@@@@@@@@@@@@++@@@..@@@@..",
+"..@@@@@@@@@@@@@@@@++@@.@@.@@@..   ..@@@@@@@@@@@@@@@@++@@.@@.@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@.@@@..   ..@@@@@@@@@@@@@@@@++@@@@@.@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@.@@@@@..   ..@@@@@@@@@@@@@@@@++@@@.@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@.@@@@@@..   ..@@@@@@@@@@@@@@@@++@@.@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@....@@@..   ..@@@@@@@@@@@@@@@@++@@....@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@.@@@@.............   ..@@@@@@@@@@@.@@@@.............",
+"..@@@@@@@@@@..@@@@.............   ..@@@@@@@@@@..@@@@.............",
+"..@@@@@@@@@@@.@@@@..              ..@@@@@@@@@@@.@@@@..           ",
+"..@@@@@@@@@@@.@@@@..              ..@@@@@@@@@@@.@@@@..           ",
+"..@@@@@@@@@@@.@@@@..              ..@@@@@@@@@@@.@@@@..           ",
+"..@@@@@@@@@@@.@@@@..              ..@@@@@@@@@@@.@@@@..           ",
+"..@@@@@@@@@@...@@@..              ..@@@@@@@@@@...@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"....................              ....................           ",
+"....................              ....................           "};
+
+/* XPM */
+static const char *nocollate_xpm[] = {
+"65 35 6 1",
+"      c None",
+".     c #000000",
+"+     c #FFFFFF",
+"@     c #020202",
+"#     c #010101",
+"$     c #070707",
+"           ....................              ....................",
+"           ....................              ....................",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"..@@@@@@@@@##@@@@@@$+++++++++..   ..@@@@@@@@@##@@@@@@$+++++++++..",
+"..@@@@@@@@@##@@@@@#@+++++++++..   ..@@@@@@@@@##@@@@@#@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@+++..++++..",
+"..++++++++++++++++@@+++..++++..   ..++++++++++++++++@@++.++.+++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@+++++.+++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@+++.+++++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@++.++++++..",
+"..++++++++++++++++@@+++...+++..   ..++++++++++++++++@@++....+++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..+++++++++++.++++.............   ..++++++++++..++++.............",
+"..++++++++++..++++.............   ..+++++++++.++.+++.............",
+"..+++++++++++.++++..              ..++++++++++++.+++..           ",
+"..+++++++++++.++++..              ..+++++++++++.++++..           ",
+"..+++++++++++.++++..              ..++++++++++.+++++..           ",
+"..+++++++++++.++++..              ..+++++++++.++++++..           ",
+"..++++++++++...+++..              ..+++++++++....+++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"....................              ....................           ",
+"....................              ....................           "};
+
+/* XPM */
+static const char *collate_reverse_xpm[] = {
+"65 35 6 1",
+"      c None",
+".     c #000000",
+"+     c #020202",
+"@     c #FFFFFF",
+"#     c #010101",
+"$     c #070707",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..",
+"           ..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"           ++@@@@@@@@@@@@@@@@..              ++@@@@@@@@@@@@@@@@..",
+"..+++++++++##++++++$@@@@@@@@@..   ..+++++++++##++++++$@@@@@@@@@..",
+"..+++++++++##+++++#+@@@@@@@@@..   ..+++++++++##+++++#+@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@..@@@@..   ..@@@@@@@@@@@@@@@@++@@@..@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@.@@@@..   ..@@@@@@@@@@@@@@@@++@@@@.@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@...@@@..   ..@@@@@@@@@@@@@@@@++@@@...@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@@@@@@@++@@@@@@@@@..   ..@@@@@@@@@@@@@@@@++@@@@@@@@@..",
+"..@@@@@@@@@@..@@@@.............   ..@@@@@@@@@@..@@@@.............",
+"..@@@@@@@@@.@@.@@@.............   ..@@@@@@@@@.@@.@@@.............",
+"..@@@@@@@@@@@@.@@@..              ..@@@@@@@@@@@@.@@@..           ",
+"..@@@@@@@@@@@.@@@@..              ..@@@@@@@@@@@.@@@@..           ",
+"..@@@@@@@@@@.@@@@@..              ..@@@@@@@@@@.@@@@@..           ",
+"..@@@@@@@@@.@@@@@@..              ..@@@@@@@@@.@@@@@@..           ",
+"..@@@@@@@@@....@@@..              ..@@@@@@@@@....@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"..@@@@@@@@@@@@@@@@..              ..@@@@@@@@@@@@@@@@..           ",
+"....................              ....................           ",
+"....................              ....................           "};
+
+/* XPM */
+static const char *nocollate_reverse_xpm[] = {
+"65 35 6 1",
+"      c None",
+".     c #000000",
+"+     c #FFFFFF",
+"@     c #020202",
+"#     c #010101",
+"$     c #070707",
+"           ....................              ....................",
+"           ....................              ....................",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           ..++++++++++++++++..              ..++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"           @@++++++++++++++++..              @@++++++++++++++++..",
+"..@@@@@@@@@##@@@@@@$+++++++++..   ..@@@@@@@@@##@@@@@@$+++++++++..",
+"..@@@@@@@@@##@@@@@#@+++++++++..   ..@@@@@@@@@##@@@@@#@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@+++..++++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@++.++.+++..   ..++++++++++++++++@@+++..++++..",
+"..++++++++++++++++@@+++++.+++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@++++.++++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@+++.+++++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@++.++++++..   ..++++++++++++++++@@++++.++++..",
+"..++++++++++++++++@@++....+++..   ..++++++++++++++++@@+++...+++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++++++++@@+++++++++..   ..++++++++++++++++@@+++++++++..",
+"..++++++++++..++++.............   ..+++++++++++.++++.............",
+"..+++++++++.++.+++.............   ..++++++++++..++++.............",
+"..++++++++++++.+++..              ..+++++++++++.++++..           ",
+"..+++++++++++.++++..              ..+++++++++++.++++..           ",
+"..++++++++++.+++++..              ..+++++++++++.++++..           ",
+"..+++++++++.++++++..              ..+++++++++++.++++..           ",
+"..+++++++++....+++..              ..++++++++++...+++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"..++++++++++++++++..              ..++++++++++++++++..           ",
+"....................              ....................           ",
+"....................              ....................           "};
+
+
+static gboolean
+is_default_printer (GtkPrintUnixDialog *dialog,
+                   GtkPrinter *printer)
+{
+  if (dialog->priv->format_for_printer)
+    return strcmp (dialog->priv->format_for_printer,
+                  gtk_printer_get_name (printer)) == 0;
+ else
+   return gtk_printer_is_default (printer);
+}
+
+static void
+gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
+{
+  GObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GObjectClass *) class;
+  widget_class = (GtkWidgetClass *) class;
+
+  object_class->finalize = gtk_print_unix_dialog_finalize;
+  object_class->set_property = gtk_print_unix_dialog_set_property;
+  object_class->get_property = gtk_print_unix_dialog_get_property;
+
+  g_object_class_install_property (object_class,
+                                  PROP_PAGE_SETUP,
+                                  g_param_spec_object ("page-setup",
+                                                       P_("Page Setup"),
+                                                       P_("The GtkPageSetup to use"),
+                                                       GTK_TYPE_PAGE_SETUP,
+                                                       GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                  PROP_CURRENT_PAGE,
+                                  g_param_spec_int ("current-page",
+                                                    P_("Current Page"),
+                                                    P_("The current page in the document"),
+                                                    -1,
+                                                    G_MAXINT,
+                                                    -1,
+                                                    GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                  PROP_PRINT_SETTINGS,
+                                  g_param_spec_object ("print-settings",
+                                                       P_("Print Settings"),
+                                                       P_("The GtkPrintSettings used for initializing the dialog"),
+                                                       GTK_TYPE_PRINT_SETTINGS,
+                                                       GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                  PROP_SELECTED_PRINTER,
+                                  g_param_spec_object ("selected-printer",
+                                                       P_("Selected Printer"),
+                                                       P_("The GtkPrinter which which is selected"),
+                                                       GTK_TYPE_PRINTER,
+                                                       GTK_PARAM_READABLE));
+  
+  g_type_class_add_private (class, sizeof (GtkPrintUnixDialogPrivate));  
+}
+
+static void
+gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
+{
+  dialog->priv = GTK_PRINT_UNIX_DIALOG_GET_PRIVATE (dialog); 
+  dialog->priv->print_backends = NULL;
+  dialog->priv->current_page = -1;
+
+  dialog->priv->extention_points = g_hash_table_new (g_str_hash,
+                                                     g_str_equal);
+
+  dialog->priv->page_setup = gtk_page_setup_new ();
+
+  populate_dialog (dialog);
+
+  g_signal_connect (dialog, 
+                    "destroy", 
+                   (GCallback) gtk_print_unix_dialog_destroy, 
+                   NULL);
+
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
+                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                         GTK_STOCK_PRINT, GTK_RESPONSE_OK,
+                          NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+}
+
+static void
+gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
+{
+  /* Make sure we don't destroy custom widgets owned by the backends */
+  clear_per_printer_ui (dialog);  
+}
+
+static void
+gtk_print_unix_dialog_finalize (GObject *object)
+{
+  GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
+  
+  g_return_if_fail (object != NULL);
+
+  unschedule_idle_mark_conflicts (dialog);
+
+  if (dialog->priv->request_details_tag)
+    {
+      g_source_remove (dialog->priv->request_details_tag);
+      dialog->priv->request_details_tag = 0;
+    }
+  
+  if (dialog->priv->current_printer)
+    {
+      g_object_unref (dialog->priv->current_printer);
+      dialog->priv->current_printer = NULL;
+    }
+
+  if (dialog->priv->printer_list)
+    {
+      g_object_unref (dialog->priv->printer_list);
+      dialog->priv->printer_list = NULL;
+    }
+  if (dialog->priv->printer_list_filter)
+    {
+      g_object_unref (dialog->priv->printer_list_filter);
+      dialog->priv->printer_list_filter = NULL;
+    }
+
+  if (dialog->priv->options)
+    {
+      g_object_unref (dialog->priv->options);
+      dialog->priv->options = NULL;
+    }
+  if (dialog->priv->extention_points)
+    {
+      g_hash_table_unref (dialog->priv->extention_points);
+      dialog->priv->extention_points = NULL;
+    }
+  if (dialog->priv->page_setup)
+    {
+      g_object_unref (dialog->priv->page_setup);
+      dialog->priv->page_setup = NULL;
+    }
+
+  if (dialog->priv->initial_settings)
+    {
+      g_object_unref (dialog->priv->initial_settings);
+      dialog->priv->initial_settings = NULL;
+    }
+
+  g_free (dialog->priv->waiting_for_printer);
+  dialog->priv->waiting_for_printer = NULL;
+  
+  g_free (dialog->priv->format_for_printer);
+  dialog->priv->format_for_printer = NULL;
+  
+  if (G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
+}
+
+static void
+printer_removed_cb (GtkPrintBackend    *backend, 
+                    GtkPrinter         *printer, 
+                   GtkPrintUnixDialog *dialog)
+{
+  GtkTreeIter *iter;
+  iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
+  gtk_list_store_remove (GTK_LIST_STORE (dialog->priv->printer_list), iter);
+}
+
+static void
+printer_status_cb (GtkPrintBackend    *backend, 
+                  GtkPrinter         *printer, 
+                  GtkPrintUnixDialog *dialog)
+{
+  GtkTreeIter *iter;
+  iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
+
+  gtk_list_store_set (GTK_LIST_STORE (dialog->priv->printer_list), iter,
+                      PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
+                      PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
+                      PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
+                      PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
+                      -1);
+
+}
+
+static void
+printer_added_cb (GtkPrintBackend    *backend, 
+                  GtkPrinter         *printer, 
+                 GtkPrintUnixDialog *dialog)
+{
+  GtkTreeIter iter, filter_iter;
+  GtkTreeSelection *selection;
+
+  gtk_list_store_append (GTK_LIST_STORE (dialog->priv->printer_list), &iter);
+  
+  g_object_set_data_full (G_OBJECT (printer), 
+                         "gtk-print-tree-iter", 
+                          gtk_tree_iter_copy (&iter),
+                          (GDestroyNotify) gtk_tree_iter_free);
+
+  gtk_list_store_set (GTK_LIST_STORE (dialog->priv->printer_list), &iter,
+                      PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
+                      PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
+                      PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
+                      PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
+                      PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
+                      PRINTER_LIST_COL_PRINTER_OBJ, printer,
+                      -1);
+
+  gtk_tree_model_filter_convert_child_iter_to_iter (dialog->priv->printer_list_filter,
+                                                   &filter_iter, &iter);
+  
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->printer_treeview));
+  
+  if (dialog->priv->waiting_for_printer != NULL &&
+      strcmp (gtk_printer_get_name (printer),
+             dialog->priv->waiting_for_printer) == 0)
+    {
+      dialog->priv->internal_printer_change = TRUE;
+      gtk_tree_selection_select_iter (selection, &filter_iter);
+      dialog->priv->internal_printer_change = FALSE;
+      g_free (dialog->priv->waiting_for_printer);
+      dialog->priv->waiting_for_printer = NULL;
+    }
+  else if (is_default_printer (dialog, printer) &&
+          gtk_tree_selection_count_selected_rows (selection) == 0)
+    {
+      dialog->priv->internal_printer_change = TRUE;
+      gtk_tree_selection_select_iter (selection, &filter_iter);
+      dialog->priv->internal_printer_change = FALSE;
+    }
+}
+
+static void
+printer_list_initialize (GtkPrintUnixDialog *dialog,
+                        GtkPrintBackend    *print_backend)
+{
+  GList *list;
+  GList *node;
+
+  g_return_if_fail (print_backend != NULL);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-added", 
+                          (GCallback) printer_added_cb, 
+                          G_OBJECT (dialog), 0);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-removed", 
+                          (GCallback) printer_removed_cb, 
+                          G_OBJECT (dialog), 0);
+
+  g_signal_connect_object (print_backend, 
+                          "printer-status-changed", 
+                          (GCallback) printer_status_cb, 
+                          G_OBJECT (dialog), 0);
+
+  list = gtk_print_backend_get_printer_list (print_backend);
+
+  node = list;
+  while (node != NULL)
+    {
+      printer_added_cb (print_backend, node->data, dialog);
+      node = node->next;
+    }
+
+  g_list_free (list);
+}
+
+static void
+load_print_backends (GtkPrintUnixDialog *dialog)
+{
+  GList *node;
+
+  if (g_module_supported ())
+    dialog->priv->print_backends = gtk_print_backend_load_modules ();
+
+  for (node = dialog->priv->print_backends; node != NULL; node = node->next)
+    printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
+}
+
+static void
+gtk_print_unix_dialog_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+
+{
+  GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_PAGE_SETUP:
+      gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
+      break;
+    case PROP_CURRENT_PAGE:
+      gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
+      break;
+    case PROP_PRINT_SETTINGS:
+      gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_print_unix_dialog_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_PAGE_SETUP:
+      g_value_set_object (value, dialog->priv->page_setup);
+      break;
+    case PROP_CURRENT_PAGE:
+      g_value_set_int (value, dialog->priv->current_page);
+      break;
+    case PROP_PRINT_SETTINGS:
+      g_value_set_object (value, gtk_print_unix_dialog_get_settings (dialog));
+      break;
+    case PROP_SELECTED_PRINTER:
+      g_value_set_object (value, dialog->priv->current_printer);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static gboolean
+is_printer_active (GtkTreeModel       *model,
+                   GtkTreeIter        *iter,
+                  GtkPrintUnixDialog *dialog)
+{
+  gboolean result;
+  GtkPrinter *printer;
+
+  gtk_tree_model_get (model,
+                     iter,
+                     PRINTER_LIST_COL_PRINTER_OBJ,
+                      &printer,
+                     -1);
+  
+  if (printer == NULL)
+    return FALSE;
+
+  result = gtk_printer_is_active (printer);
+
+  g_object_unref (printer);
+
+  return result;
+}
+
+static gint
+default_printer_list_sort_func (GtkTreeModel *model,
+                                GtkTreeIter  *a,
+                                GtkTreeIter  *b,
+                                gpointer      user_data)
+{
+  gchar *a_name;
+  gchar *b_name;
+  GtkPrinter *a_printer;
+  GtkPrinter *b_printer;
+  gint result;
+
+  gtk_tree_model_get (model, a, 
+                      PRINTER_LIST_COL_NAME, &a_name, 
+                     PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
+                     -1);
+  gtk_tree_model_get (model, b, 
+                      PRINTER_LIST_COL_NAME, &b_name,
+                     PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
+                     -1);
+
+  if (a_printer == NULL && b_printer == NULL)
+    result = 0;
+  else if (a_printer == NULL)
+   result = G_MAXINT;
+  else if (b_printer == NULL)
+   result = G_MININT;
+  else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
+    result = 0;
+  else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
+    result = G_MININT;
+  else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
+    result = G_MAXINT;
+  else if (a_name == NULL && b_name == NULL)
+    result = 0;
+  else if (a_name == NULL && b_name != NULL)
+    result = 1;
+  else if (a_name != NULL && b_name == NULL)
+    result = -1;
+  else
+    result = g_ascii_strcasecmp (a_name, b_name);
+
+  g_free (a_name);
+  g_free (b_name);
+  g_object_unref (a_printer);
+  g_object_unref (b_printer);
+
+  return result;
+}
+
+
+static void
+create_printer_list_model (GtkPrintUnixDialog *dialog)
+{
+  GtkListStore *model;
+  GtkTreeSortable *sort;
+
+  model = gtk_list_store_new (PRINTER_LIST_N_COLS,
+                              G_TYPE_STRING,
+                              G_TYPE_STRING, 
+                              G_TYPE_STRING, 
+                              G_TYPE_INT, 
+                              G_TYPE_STRING,
+                              G_TYPE_OBJECT);
+
+  dialog->priv->printer_list = (GtkTreeModel *)model;
+  dialog->priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
+                                                                                       NULL);
+
+  gtk_tree_model_filter_set_visible_func (dialog->priv->printer_list_filter,
+                                         (GtkTreeModelFilterVisibleFunc) is_printer_active,
+                                         dialog,
+                                         NULL);
+
+  sort = GTK_TREE_SORTABLE (model);
+  gtk_tree_sortable_set_default_sort_func (sort,
+                                          default_printer_list_sort_func,
+                                          NULL,
+                                          NULL);
+  gtk_tree_sortable_set_sort_column_id (sort,
+                                       GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+                                       GTK_SORT_ASCENDING);
+
+}
+
+
+static GtkWidget *
+wrap_in_frame (const gchar *label, 
+               GtkWidget   *child)
+{
+  GtkWidget *frame, *alignment, *label_widget;
+  char *bold_text;
+
+  label_widget = gtk_label_new ("");
+  gtk_widget_show (label_widget);
+  
+  bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
+  gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
+  g_free (bold_text);
+  
+  frame = gtk_frame_new ("");
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label_widget);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  
+  alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+                            12, 0, 12, 0);
+  gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+  gtk_container_add (GTK_CONTAINER (alignment), child);
+
+  gtk_widget_show (frame);
+  gtk_widget_show (alignment);
+  
+  return frame;
+}
+
+static gboolean
+setup_option (GtkPrintUnixDialog     *dialog,
+             const gchar            *option_name,
+             GtkPrinterOptionWidget *widget)
+{
+  GtkPrinterOption *option;
+
+  option = gtk_printer_option_set_lookup (dialog->priv->options, option_name);
+  gtk_printer_option_widget_set_source (widget, option);
+
+  return option != NULL;
+}
+
+static void
+add_option_to_extention_point (GtkPrinterOption *option,
+                              gpointer          user_data)
+{
+  GHashTable *extention_points = (GHashTable *) user_data;
+
+  GtkWidget *widget;
+  GtkBox *extention_hbox;
+
+  extention_hbox = (GtkBox *) g_hash_table_lookup (extention_points, option->name);
+
+  if (extention_hbox)
+    {
+
+      widget = gtk_printer_option_widget_new (option);
+      gtk_widget_show (widget);
+   
+      if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
+        {
+          GtkWidget *label;
+
+          label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
+          gtk_widget_show (label);
+          gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+          gtk_box_pack_start (extention_hbox, label, FALSE, FALSE, 6);
+          gtk_box_pack_start (extention_hbox, widget, FALSE, FALSE, 6);
+
+        }
+      else
+        gtk_box_pack_start (extention_hbox, widget, FALSE, FALSE, 6);
+    }
+  else
+    g_warning ("Extention point %s requested but not found.", option->name);
+}
+
+static void
+add_option_to_table (GtkPrinterOption *option,
+                    gpointer          user_data)
+{
+  GtkTable *table;
+  GtkWidget *label, *widget;
+  int row;
+
+  table = GTK_TABLE (user_data);
+  
+  if (g_str_has_prefix (option->name, "gtk-"))
+    return;
+  
+  widget = gtk_printer_option_widget_new (option);
+  gtk_widget_show (widget);
+
+  row = table->nrows;
+  gtk_table_resize (table, table->nrows + 1, table->ncols + 1);
+  
+  if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
+    {
+      label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
+      gtk_widget_show (label);
+
+      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+      
+      gtk_table_attach (table, label,
+                       0, 1, row - 1 , row,  GTK_FILL, 0, 0, 0);
+      
+      gtk_table_attach (table, widget,
+                       1, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
+    }
+  else
+    gtk_table_attach (table, widget,
+                     0, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
+}
+
+
+static void
+setup_page_table (GtkPrinterOptionSet *options,
+                 const gchar         *group,
+                 GtkWidget           *table,
+                 GtkWidget           *page)
+{
+  gtk_printer_option_set_foreach_in_group (options, group,
+                                          add_option_to_table,
+                                          table);
+  if (GTK_TABLE (table)->nrows == 1)
+    gtk_widget_hide (page);
+  else
+    gtk_widget_show (page);
+}
+
+static void
+update_print_at_option (GtkPrintUnixDialog *dialog)
+{
+  GtkPrinterOption *option;
+  
+  option = gtk_printer_option_set_lookup (dialog->priv->options, "gtk-print-time");
+
+  if (option == NULL)
+    return;
+  
+  if (dialog->priv->updating_print_at)
+    return;
+  
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->print_at_radio)))
+    gtk_printer_option_set (option, "at");
+  else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->print_hold_radio)))
+    gtk_printer_option_set (option, "on-hold");
+  else
+    gtk_printer_option_set (option, "now");
+  
+  option = gtk_printer_option_set_lookup (dialog->priv->options, "gtk-print-time-text");
+  if (option != NULL)
+    {
+      const char *text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->print_at_entry));
+      gtk_printer_option_set (option,text);
+    }
+}
+
+
+static gboolean
+setup_print_at (GtkPrintUnixDialog *dialog)
+{
+  GtkPrinterOption *option;
+  
+  option = gtk_printer_option_set_lookup (dialog->priv->options, "gtk-print-time");
+  if (option == NULL)
+    {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->print_now_radio),
+                                   TRUE);
+      gtk_widget_set_sensitive (dialog->priv->print_at_radio, FALSE);
+      gtk_widget_set_sensitive (dialog->priv->print_at_entry, FALSE);
+      gtk_widget_set_sensitive (dialog->priv->print_hold_radio, FALSE);
+      gtk_entry_set_text (GTK_ENTRY (dialog->priv->print_at_entry), "");
+      return FALSE;
+    }
+
+  dialog->priv->updating_print_at = TRUE;
+  
+  if (gtk_printer_option_has_choice (option, "at"))
+    {
+      gtk_widget_set_sensitive (dialog->priv->print_at_radio, TRUE);
+      gtk_widget_set_sensitive (dialog->priv->print_at_entry, TRUE);
+    }
+  else
+    {
+      gtk_widget_set_sensitive (dialog->priv->print_at_radio, FALSE);
+      gtk_widget_set_sensitive (dialog->priv->print_at_entry, FALSE);
+    }
+  
+  gtk_widget_set_sensitive (dialog->priv->print_hold_radio,
+                           gtk_printer_option_has_choice (option, "on-hold"));
+
+  update_print_at_option (dialog);
+
+  if (strcmp (option->value, "at") == 0)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->print_at_radio),
+                                 TRUE);
+  else if (strcmp (option->value, "on-hold") == 0)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->print_hold_radio),
+                                 TRUE);
+  else
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->print_now_radio),
+                                 TRUE);
+
+  option = gtk_printer_option_set_lookup (dialog->priv->options, "gtk-print-time-text");
+  if (option != NULL)
+    gtk_entry_set_text (GTK_ENTRY (dialog->priv->print_at_entry),
+                       option->value);
+  
+
+  dialog->priv->updating_print_at = FALSE;
+
+  return TRUE;
+}
+            
+static void
+update_dialog_from_settings (GtkPrintUnixDialog *dialog)
+{
+  GList *groups, *l;
+  char *group;
+  GtkWidget *table, *frame;
+  gboolean has_advanced, has_job;
+  if (dialog->priv->current_printer == NULL)
+    {
+       clear_per_printer_ui (dialog);
+       gtk_widget_hide (dialog->priv->job_page);
+       gtk_widget_hide (dialog->priv->advanced_page);
+       gtk_widget_hide (dialog->priv->image_quality_page);
+       gtk_widget_hide (dialog->priv->finishing_page);
+       gtk_widget_hide (dialog->priv->color_page);
+       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+
+       return;
+    }
+  setup_option (dialog, "gtk-n-up", dialog->priv->pages_per_sheet);
+  setup_option (dialog, "gtk-duplex", dialog->priv->duplex);
+  setup_option (dialog, "gtk-paper-type", dialog->priv->paper_type);
+  setup_option (dialog, "gtk-paper-source", dialog->priv->paper_source);
+  setup_option (dialog, "gtk-output-tray", dialog->priv->output_tray);
+
+  has_job = FALSE;
+  has_job |= setup_option (dialog, "gtk-job-prio", dialog->priv->job_prio);
+  has_job |= setup_option (dialog, "gtk-billing-info", dialog->priv->billing_info);
+  has_job |= setup_option (dialog, "gtk-cover-before", dialog->priv->cover_before);
+  has_job |= setup_option (dialog, "gtk-cover-after", dialog->priv->cover_after);
+  has_job |= setup_print_at (dialog);
+  
+  if (has_job)
+    gtk_widget_show (dialog->priv->job_page);
+  else
+    gtk_widget_hide (dialog->priv->job_page);
+
+  
+  setup_page_table (dialog->priv->options,
+                   "ImageQualityPage",
+                   dialog->priv->image_quality_table,
+                   dialog->priv->image_quality_page);
+  
+  setup_page_table (dialog->priv->options,
+                   "FinishingPage",
+                   dialog->priv->finishing_table,
+                   dialog->priv->finishing_page);
+
+  setup_page_table (dialog->priv->options,
+                   "ColorPage",
+                   dialog->priv->color_table,
+                   dialog->priv->color_page);
+
+  /* Put the rest of the groups in the advanced page */
+  groups = gtk_printer_option_set_get_groups (dialog->priv->options);
+
+  has_advanced = FALSE;
+  for (l = groups; l != NULL; l = l->next)
+    {
+      group = l->data;
+
+      if (group == NULL)
+       continue;
+      
+      if (strcmp (group, "ImageQualityPage") == 0 ||
+         strcmp (group, "ColorPage") == 0 ||
+         strcmp (group, "FinishingPage") == 0)
+       continue;
+
+      if (strcmp (group, "GtkPrintDialogExtention") == 0)
+        {
+          gtk_printer_option_set_foreach_in_group (dialog->priv->options,
+                                                  group,
+                                                  add_option_to_extention_point,
+                                                  dialog->priv->extention_points);
+          continue;
+        }
+
+      table = gtk_table_new (1, 2, FALSE);
+      gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+      gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+      
+      gtk_printer_option_set_foreach_in_group (dialog->priv->options,
+                                              group,
+                                              add_option_to_table,
+                                              table);
+      if (GTK_TABLE (table)->nrows == 1)
+       gtk_widget_destroy (table);
+      else
+       {
+         has_advanced = TRUE;
+         frame = wrap_in_frame (group, table);
+         gtk_widget_show (table);
+         gtk_widget_show (frame);
+         
+         gtk_box_pack_start (GTK_BOX (dialog->priv->advanced_vbox),
+                             frame, FALSE, FALSE, 0);
+       }
+    }
+
+  if (has_advanced)
+    gtk_widget_show (dialog->priv->advanced_page);
+  else
+    gtk_widget_hide (dialog->priv->advanced_page);
+
+  
+  g_list_foreach (groups, (GFunc) g_free, NULL);
+  g_list_free (groups);
+}
+
+static void
+mark_conflicts (GtkPrintUnixDialog *dialog)
+{
+  GtkPrinter *printer;
+  gboolean have_conflict;
+
+  have_conflict = FALSE;
+
+  printer = dialog->priv->current_printer;
+
+  if (printer)
+    {
+
+      g_signal_handler_block (dialog->priv->options,
+                             dialog->priv->options_changed_handler);
+      
+      gtk_printer_option_set_clear_conflicts (dialog->priv->options);
+      
+      have_conflict = _gtk_printer_mark_conflicts (printer,
+                                                  dialog->priv->options);
+      
+      g_signal_handler_unblock (dialog->priv->options,
+                               dialog->priv->options_changed_handler);
+    }
+
+  if (have_conflict)
+    gtk_widget_show (dialog->priv->conflicts_widget);
+  else
+    gtk_widget_hide (dialog->priv->conflicts_widget);
+}
+
+static gboolean
+mark_conflicts_callback (gpointer data)
+{
+  GtkPrintUnixDialog *dialog = data;
+
+  dialog->priv->mark_conflicts_id = 0;
+
+  mark_conflicts (dialog);
+
+  return FALSE;
+}
+
+static void
+unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
+{
+  if (dialog->priv->mark_conflicts_id != 0)
+    {
+      g_source_remove (dialog->priv->mark_conflicts_id);
+      dialog->priv->mark_conflicts_id = 0;
+    }
+}
+
+static void
+schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
+{
+  if (dialog->priv->mark_conflicts_id != 0)
+    return;
+
+  dialog->priv->mark_conflicts_id = g_idle_add (mark_conflicts_callback,
+                                               dialog);
+}
+
+static void
+options_changed_cb (GtkPrintUnixDialog *dialog)
+{
+  schedule_idle_mark_conflicts (dialog);
+
+  if (dialog->priv->initial_settings)
+    {
+      g_object_unref (dialog->priv->initial_settings);
+      dialog->priv->initial_settings = NULL;
+    }
+
+  g_free (dialog->priv->waiting_for_printer);
+  dialog->priv->waiting_for_printer = NULL;
+}
+
+static void
+remove_custom_widget (GtkWidget    *widget,
+                      GtkContainer *container)
+{
+  gtk_container_remove (container, widget);
+}
+
+static void
+extention_point_clear_children (const gchar  *key,
+                                GtkContainer *container,
+                                gpointer      data)
+{
+  gtk_container_foreach (container,
+                         (GtkCallback)remove_custom_widget,
+                         container);
+}
+
+static void
+clear_per_printer_ui (GtkPrintUnixDialog *dialog)
+{
+  gtk_container_foreach (GTK_CONTAINER (dialog->priv->finishing_table),
+                        (GtkCallback)gtk_widget_destroy,
+                        NULL);
+  gtk_table_resize (GTK_TABLE (dialog->priv->finishing_table), 1, 2);
+  gtk_container_foreach (GTK_CONTAINER (dialog->priv->image_quality_table),
+                        (GtkCallback)gtk_widget_destroy,
+                        NULL);
+  gtk_table_resize (GTK_TABLE (dialog->priv->image_quality_table), 1, 2);
+  gtk_container_foreach (GTK_CONTAINER (dialog->priv->color_table),
+                        (GtkCallback)gtk_widget_destroy,
+                        NULL);
+  gtk_table_resize (GTK_TABLE (dialog->priv->color_table), 1, 2);
+  gtk_container_foreach (GTK_CONTAINER (dialog->priv->advanced_vbox),
+                        (GtkCallback)gtk_widget_destroy,
+                        NULL);
+  g_hash_table_foreach (dialog->priv->extention_points, 
+                        (GHFunc) extention_point_clear_children, 
+                        NULL);
+}
+
+static void
+printer_details_acquired (GtkPrinter         *printer,
+                         gboolean            success,
+                         GtkPrintUnixDialog *dialog)
+{
+  dialog->priv->request_details_tag = 0;
+  
+  if (success)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->printer_treeview));
+      
+      selected_printer_changed (selection, dialog);
+    }
+}
+
+static void
+selected_printer_changed (GtkTreeSelection   *selection,
+                         GtkPrintUnixDialog *dialog)
+{
+  GtkPrinter *printer;
+  GtkTreeIter iter, filter_iter;
+
+  /* Whenever the user selects a printer we stop looking for
+     the printer specified in the initial settings */
+  if (dialog->priv->waiting_for_printer &&
+      !dialog->priv->internal_printer_change)
+    {
+      g_free (dialog->priv->waiting_for_printer);
+      dialog->priv->waiting_for_printer = NULL;
+    }
+  
+  if (dialog->priv->request_details_tag)
+    {
+      g_source_remove (dialog->priv->request_details_tag);
+      dialog->priv->request_details_tag = 0;
+    }
+  
+  printer = NULL;
+  if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
+    {
+      gtk_tree_model_filter_convert_iter_to_child_iter (dialog->priv->printer_list_filter,
+                                                       &iter,
+                                                       &filter_iter);
+
+      gtk_tree_model_get (dialog->priv->printer_list, &iter,
+                         PRINTER_LIST_COL_PRINTER_OBJ, &printer,
+                         -1);
+    }
+  
+  if (printer != NULL && !_gtk_printer_has_details (printer))
+    {
+      gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
+      dialog->priv->request_details_tag =
+       g_signal_connect (printer, "details-acquired",
+                         G_CALLBACK (printer_details_acquired), dialog);
+      _gtk_printer_request_details (printer);
+      return;
+    }
+  
+  if (printer == dialog->priv->current_printer)
+    {
+      if (printer)
+       g_object_unref (printer);
+      return;
+    }
+
+  if (dialog->priv->options)
+    {
+      g_object_unref (dialog->priv->options);
+      dialog->priv->options = NULL;  
+
+      clear_per_printer_ui (dialog);
+    }
+
+  if (dialog->priv->current_printer)
+    {
+      g_object_unref (dialog->priv->current_printer);
+    }
+
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
+  dialog->priv->current_printer = printer;
+
+  if (printer != NULL)
+    {
+      dialog->priv->options = _gtk_printer_get_options (printer, dialog->priv->initial_settings,
+                                                       dialog->priv->page_setup);
+  
+      dialog->priv->options_changed_handler = 
+        g_signal_connect_swapped (dialog->priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
+    }
+
+  update_dialog_from_settings (dialog);
+}
+
+static void
+update_collate_icon (GtkToggleButton    *toggle_button,
+                    GtkPrintUnixDialog *dialog)
+{
+  GdkPixbuf *pixbuf;
+  gboolean collate, reverse;
+  const char **xpm;
+
+  collate = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
+  reverse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
+
+  if (collate)
+    {
+      if (reverse)
+       xpm = collate_reverse_xpm;
+      else
+       xpm = collate_xpm;
+    }
+  else
+    {
+      if (reverse)
+       xpm = nocollate_reverse_xpm;
+      else
+       xpm = nocollate_xpm;
+    }
+  
+  pixbuf = gdk_pixbuf_new_from_xpm_data (xpm);
+  gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->priv->collate_image), pixbuf);
+  g_object_unref (pixbuf);
+}
+
+static void
+create_main_page (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *main_vbox, *label, *hbox;
+  GtkWidget *scrolled, *treeview, *frame, *table;
+  GtkWidget *entry, *spinbutton;
+  GtkWidget *radio, *check, *image;
+  GtkCellRenderer *renderer;
+  GtkTreeViewColumn *column;
+  GtkTreeSelection *selection;
+  GtkWidget *custom_input;
+  
+  priv = dialog->priv;
+
+  main_vbox = gtk_vbox_new (FALSE, 6);
+  gtk_widget_show (main_vbox);
+
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
+                                      GTK_SHADOW_IN);
+  gtk_widget_show (scrolled);
+  gtk_box_pack_start (GTK_BOX (main_vbox), scrolled, TRUE, TRUE, 0);
+
+  treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
+  priv->printer_treeview = treeview;
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
+  gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+  g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  column = gtk_tree_view_column_new_with_attributes ("",
+                                                    renderer,
+                                                    "icon-name",
+                                                    PRINTER_LIST_COL_ICON,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes (_("Printer"),
+                                                    renderer,
+                                                    "text",
+                                                    PRINTER_LIST_COL_NAME,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+  
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes (_("Location"),
+                                                    renderer,
+                                                    "text",
+                                                    PRINTER_LIST_COL_LOCATION,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  column = gtk_tree_view_column_new_with_attributes (_("Status"),
+                                                    renderer,
+                                                    "text",
+                                                    PRINTER_LIST_COL_STATE,
+                                                    NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+  
+  gtk_widget_show (treeview);
+  gtk_container_add (GTK_CONTAINER (scrolled), treeview);
+
+  custom_input = gtk_hbox_new (FALSE, 8);
+  gtk_widget_show (custom_input);
+  gtk_box_pack_start (GTK_BOX (main_vbox), custom_input, FALSE, FALSE, 0);
+  g_hash_table_insert (dialog->priv->extention_points, 
+                       _EXTENTION_POINT_MAIN_PAGE_CUSTOM_INPUT,
+                       custom_input);
+
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_widget_show (hbox);
+  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
+
+  table = gtk_table_new (3, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Print Pages"), table);
+  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
+  gtk_widget_show (table);
+
+  radio = gtk_radio_button_new_with_label (NULL, _("All"));
+  priv->all_pages_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+  radio = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
+                                          _("Current"));
+  if (dialog->priv->current_page == -1)
+    gtk_widget_set_sensitive (radio, FALSE);    
+  priv->current_page_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+  radio = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
+                                          _("Range: "));
+  priv->page_range_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+  entry = gtk_entry_new ();
+  priv->page_range_entry = entry;
+  gtk_widget_show (entry);
+  gtk_table_attach (GTK_TABLE (table), entry,
+                   1, 2, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+
+  table = gtk_table_new (3, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Copies"), table);
+  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Copies:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+  spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
+  priv->copies_spin = spinbutton;
+  gtk_widget_show (spinbutton);
+  gtk_table_attach (GTK_TABLE (table), spinbutton,
+                   1, 2, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  check = gtk_check_button_new_with_mnemonic (_("_Collate"));
+  priv->collate_check = check;
+  g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
+  gtk_widget_show (check);
+  gtk_table_attach (GTK_TABLE (table), check,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+  check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
+  g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
+  priv->reverse_check = check;
+  gtk_widget_show (check);
+  gtk_table_attach (GTK_TABLE (table), check,
+                   0, 1, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+
+  image = gtk_image_new ();
+  dialog->priv->collate_image = image;
+  gtk_widget_show (image);
+  gtk_table_attach (GTK_TABLE (table), image,
+                   1, 2, 1, 3, GTK_FILL, 0,
+                   0, 0);
+
+  update_collate_icon (NULL, dialog);
+  
+  label = gtk_label_new (_("General"));
+  gtk_widget_show (label);
+  
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                           main_vbox, label);
+  
+}
+
+static gboolean
+is_range_separator (gchar c)
+{
+  return (c == ',' || c == ';' || c == ':');
+}
+
+static GtkPageRange *
+dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
+                       gint               *n_ranges_out)
+{
+  int i, n_ranges;
+  const char *text, *p;
+  char *next;
+  GtkPageRange *ranges;
+  int start, end;
+  
+  text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->page_range_entry));
+
+  if (*text == 0)
+    {
+      *n_ranges_out = 0;
+      return NULL;
+    }
+  
+  n_ranges = 1;
+  p = text;
+  while (*p)
+    {
+      if (is_range_separator (*p))
+       n_ranges++;
+      p++;
+    }
+
+  ranges = g_new0 (GtkPageRange, n_ranges);
+  
+  i = 0;
+  p = text;
+  while (*p)
+    {
+      start = (int)strtol (p, &next, 10);
+      if (start < 1)
+       start = 1;
+      end = start;
+
+      if (next != p)
+       {
+         p = next;
+
+         if (*p == '-')
+           {
+             p++;
+             end = (int)strtol (p, NULL, 10);
+             if (end < start)
+               end = start;
+           }
+       }
+
+      ranges[i].start = start - 1;
+      ranges[i].end = end - 1;
+      i++;
+
+      /* Skip until end or separator */
+      while (*p && !is_range_separator (*p))
+       p++;
+
+      /* if not at end, skip separator */
+      if (*p)
+       p++;
+    }
+
+  *n_ranges_out = i;
+  
+  return ranges;
+}
+
+static void
+dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
+                       GtkPageRange       *ranges,
+                       gint                n_ranges)
+{
+  int i;
+  GString *s = g_string_new ("");
+
+  for (i = 0; i < n_ranges; i++)
+    {
+      g_string_append_printf (s, "%d", ranges[i].start + 1);
+      if (ranges[i].end > ranges[i].start)
+       g_string_append_printf (s, "-%d", ranges[i].end + 1);
+      
+      if (i != n_ranges - 1)
+       g_string_append (s, ",");
+    }
+
+  gtk_entry_set_text (GTK_ENTRY (dialog->priv->page_range_entry),
+                     s->str);
+  
+  g_string_free (s, TRUE);
+}
+
+
+static GtkPrintPages
+dialog_get_print_pages (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv = dialog->priv;
+  
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
+    return GTK_PRINT_PAGES_ALL;
+  else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
+    return GTK_PRINT_PAGES_CURRENT;
+  else
+    return GTK_PRINT_PAGES_RANGES;
+}
+
+static void
+dialog_set_print_pages (GtkPrintUnixDialog *dialog, GtkPrintPages pages)
+{
+  GtkPrintUnixDialogPrivate *priv = dialog->priv;
+
+  if (pages == GTK_PRINT_PAGES_RANGES)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
+  else if (pages == GTK_PRINT_PAGES_CURRENT)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
+  else
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
+}
+
+static gdouble
+dialog_get_scale (GtkPrintUnixDialog *dialog)
+{
+  return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
+}
+
+static void
+dialog_set_scale (GtkPrintUnixDialog *dialog, 
+                  gdouble             val)
+{
+  return gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin),
+                                   val);
+}
+
+static GtkPageSet
+dialog_get_page_set (GtkPrintUnixDialog *dialog)
+{
+  return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
+}
+
+static void
+dialog_set_page_set (GtkPrintUnixDialog *dialog, 
+                     GtkPageSet          val)
+{
+  gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
+                           (int)val);
+}
+
+static gint
+dialog_get_n_copies (GtkPrintUnixDialog *dialog)
+{
+  return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
+}
+
+static void
+dialog_set_n_copies (GtkPrintUnixDialog *dialog, 
+                     gint                n_copies)
+{
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
+                            n_copies);
+}
+
+static gboolean
+dialog_get_collate (GtkPrintUnixDialog *dialog)
+{
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
+}
+
+static void
+dialog_set_collate (GtkPrintUnixDialog *dialog, 
+                    gboolean            collate)
+{
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
+                               collate);
+}
+
+static gboolean
+dialog_get_reverse (GtkPrintUnixDialog *dialog)
+{
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
+}
+
+static void
+dialog_set_reverse (GtkPrintUnixDialog *dialog, 
+                    gboolean            reverse)
+{
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
+                               reverse);
+}
+
+static gint 
+dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
+{
+  const char *val;
+  int num;
+
+  val = gtk_printer_option_widget_get_value (dialog->priv->pages_per_sheet);
+
+  num = 1;
+  
+  if (val)
+    {
+      num = atoi(val);
+      if (num < 1)
+       num = 1;
+    }
+  
+  return num;
+}
+
+
+static gboolean
+draw_page_cb (GtkWidget                 *widget,
+             GdkEventExpose     *event,
+             GtkPrintUnixDialog *dialog)
+{
+  cairo_t *cr;
+  double ratio;
+  int w, h, tmp, shadow_offset;
+  int pages_x, pages_y, i, x, y, layout_w, layout_h;
+  double page_width, page_height;
+  GtkPageOrientation orientation;
+  gboolean landscape;
+  PangoLayout *layout;
+  PangoFontDescription *font;
+  char *text;
+  
+  orientation = gtk_page_setup_get_orientation (dialog->priv->page_setup);
+  landscape =
+    (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
+    (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
+  
+  cr = gdk_cairo_create (widget->window);
+  
+  ratio = 1.4142;
+
+  w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
+  h = w * ratio;
+
+  switch (dialog_get_pages_per_sheet (dialog))
+    {
+    default:
+    case 1:
+      pages_x = 1; pages_y = 1;
+      break;
+    case 2:
+      landscape = !landscape;
+      pages_x = 1; pages_y = 2;
+      break;
+    case 4:
+      pages_x = 2; pages_y = 2;
+      break;
+    case 6:
+      landscape = !landscape;
+      pages_x = 2; pages_y = 3;
+      break;
+    case 9:
+      pages_x = 3; pages_y = 3;
+      break;
+    case 16:
+      pages_x = 4; pages_y = 4;
+      break;
+    }
+
+  if (landscape)
+    {
+      tmp = w;
+      w = h;
+      h = tmp;
+
+      tmp = pages_x;
+      pages_x = pages_y;
+      pages_y = tmp;
+    }
+  
+  shadow_offset = 3;
+  
+  cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
+  cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
+  cairo_fill (cr);
+  
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  cairo_rectangle (cr, 1, 1, w, h);
+  cairo_fill (cr);
+  cairo_set_line_width (cr, 1.0);
+  cairo_rectangle (cr, 0.5, 0.5, w+1, h+1);
+  
+  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+  cairo_stroke (cr);
+
+  i = 1;
+
+  page_width = (double)w / pages_x;
+  page_height = (double)h / pages_y;
+
+  layout  = pango_cairo_create_layout (cr);
+
+  font = pango_font_description_new ();
+  pango_font_description_set_family (font, "sans");
+  pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
+  pango_layout_set_font_description (layout, font);
+  pango_font_description_free (font);
+
+  pango_layout_set_width (layout, page_width * PANGO_SCALE);
+  pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+  
+  for (y = 0; y < pages_y; y++)
+    {
+      for (x = 0; x < pages_x; x++)
+       {
+         text = g_strdup_printf ("%d", i++);
+         pango_layout_set_text (layout, text, -1);
+         g_free (text);
+         pango_layout_get_size (layout, &layout_w, &layout_h);
+         cairo_save (cr);
+         cairo_translate (cr,
+                          x * page_width,
+                          y * page_height + (page_height - layout_h / 1024.0) / 2
+                          );
+         
+         pango_cairo_show_layout (cr, layout);
+         cairo_restore (cr);
+       }
+    }
+    
+  return TRUE;
+}
+
+static void
+redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
+{
+  if (dialog->priv->page_layout_preview)
+    gtk_widget_queue_draw (dialog->priv->page_layout_preview);
+}
+
+static void
+create_page_setup_page (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *main_vbox, *label, *hbox, *hbox2;
+  GtkWidget *frame, *table, *widget;
+  GtkWidget *combo, *spinbutton, *draw;
+  
+  priv = dialog->priv;
+
+  main_vbox = gtk_vbox_new (FALSE, 8);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
+  gtk_widget_show (main_vbox);
+
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_widget_show (hbox);
+  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, TRUE, TRUE, 0);
+
+  table = gtk_table_new (5, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Layout"), table);
+  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Pages per sheet:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
+  priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Two-sided:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Only Print:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+
+  combo = gtk_combo_box_new_text ();
+  priv->page_set_combo = combo;
+  gtk_widget_show (combo);
+  gtk_table_attach (GTK_TABLE (table), combo,
+                   1, 2, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+  /* In enum order */
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All pages"));  
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Even pages"));  
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Odd pages"));  
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+
+  label = gtk_label_new (_("Scale:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 3, 4,  GTK_FILL, 0,
+                   0, 0);
+
+  hbox2 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox2);
+  gtk_table_attach (GTK_TABLE (table), hbox2,
+                   1, 2, 3, 4,  GTK_FILL, 0,
+                   0, 0);
+  
+  spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
+  priv->scale_spin = spinbutton;
+  gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
+  gtk_widget_show (spinbutton);
+  gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
+  label = gtk_label_new ("%");
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
+
+
+  table = gtk_table_new (4, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Paper"), table);
+  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Paper Type:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Paper Source:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Output Tray:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+
+  hbox2 = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox2);
+  gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 6);
+
+  draw = gtk_drawing_area_new ();
+  dialog->priv->page_layout_preview = draw;
+  gtk_widget_set_size_request (draw, 200, 200);
+  g_signal_connect (draw, "expose_event", G_CALLBACK (draw_page_cb), dialog);
+  gtk_widget_show (draw);
+
+  gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 6);
+  
+  label = gtk_label_new (_("Page Setup"));
+  gtk_widget_show (label);
+  
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                           main_vbox, label);
+  
+}
+
+static void
+create_job_page (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *main_table, *label;
+  GtkWidget *frame, *table, *radio;
+  GtkWidget *entry, *widget;
+  
+  priv = dialog->priv;
+
+  main_table = gtk_table_new (2, 2, FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (main_table), 6);
+
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Job Details"), table);
+  gtk_table_attach (GTK_TABLE (main_table), frame,
+                   0, 1, 0, 1,  0, 0,
+                   0, 0);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Priority:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Billing info:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Print Document"), table);
+  gtk_table_attach (GTK_TABLE (main_table), frame,
+                   0, 1, 1, 2,  0, 0,
+                   0, 0);
+  gtk_widget_show (table);
+
+  radio = gtk_radio_button_new_with_label (NULL, _("Now"));
+  priv->print_now_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+  radio = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
+                                          _("At:"));
+  priv->print_at_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+  radio = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
+                                          _("On Hold"));
+  priv->print_hold_radio = radio;
+  gtk_widget_show (radio);
+  gtk_table_attach (GTK_TABLE (table), radio,
+                   0, 1, 2, 3,  GTK_FILL, 0,
+                   0, 0);
+  entry = gtk_entry_new ();
+  priv->print_at_entry = entry;
+  gtk_widget_show (entry);
+  gtk_table_attach (GTK_TABLE (table), entry,
+                   1, 2, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  g_signal_connect_swapped (priv->print_now_radio, "toggled",
+                           G_CALLBACK (update_print_at_option), dialog);
+  g_signal_connect_swapped (priv->print_at_radio, "toggled",
+                           G_CALLBACK (update_print_at_option), dialog);
+  g_signal_connect_swapped (priv->print_at_entry, "changed",
+                           G_CALLBACK (update_print_at_option), dialog);
+  g_signal_connect_swapped (priv->print_hold_radio, "toggled",
+                           G_CALLBACK (update_print_at_option), dialog);
+
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  frame = wrap_in_frame (_("Add Cover Page"), table);
+  gtk_table_attach (GTK_TABLE (main_table), frame,
+                   1, 2, 0, 1,  0, 0,
+                   0, 0);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Before:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 0, 1,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("After:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  widget = gtk_printer_option_widget_new (NULL);
+  priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
+  gtk_widget_show (widget);
+  gtk_table_attach (GTK_TABLE (table), widget,
+                   1, 2, 1, 2,  GTK_FILL, 0,
+                   0, 0);
+
+  label = gtk_label_new (_("Job"));
+  gtk_widget_show (label);
+
+  priv->job_page = main_table;
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                           main_table, label);
+}
+
+static void 
+create_optional_page (GtkPrintUnixDialog  *dialog,
+                     const gchar         *text,
+                     GtkWidget          **table_out,
+                     GtkWidget          **page_out)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *table, *label, *scrolled;
+  
+  priv = dialog->priv;
+
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_NEVER,
+                                 GTK_POLICY_AUTOMATIC);
+  
+  table = gtk_table_new (1, 2, FALSE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+  gtk_container_set_border_width (GTK_CONTAINER (table), 6);
+  gtk_widget_show (table);
+
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                        table);
+  gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
+                               GTK_SHADOW_NONE);
+  
+  label = gtk_label_new (text);
+  gtk_widget_show (label);
+  
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                           scrolled, label);
+
+  *table_out = table;
+  *page_out = scrolled;
+}
+
+static void
+create_advanced_page (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *main_vbox, *label, *scrolled;
+  
+  priv = dialog->priv;
+
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  priv->advanced_page = scrolled;
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_NEVER,
+                                 GTK_POLICY_AUTOMATIC);
+
+  main_vbox = gtk_vbox_new (FALSE, 8);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
+  gtk_widget_show (main_vbox);
+
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                        main_vbox);
+  gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
+                               GTK_SHADOW_NONE);
+  
+  dialog->priv->advanced_vbox = main_vbox;
+  
+  label = gtk_label_new (_("Advanced"));
+  gtk_widget_show (label);
+  
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+                           scrolled, label);
+}
+
+
+static void
+populate_dialog (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintUnixDialogPrivate *priv;
+  GtkWidget *hbox, *conflict_hbox, *image, *label;
+  
+  g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
+  
+  priv = dialog->priv;
+  create_printer_list_model (dialog);
+
+  priv->notebook = gtk_notebook_new ();
+
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), 
+                      priv->notebook,
+                      TRUE, TRUE, 10);
+
+  create_main_page (dialog);
+  create_page_setup_page (dialog);
+  create_job_page (dialog);
+  create_optional_page (dialog, _("Image Quality"),
+                       &dialog->priv->image_quality_table,
+                       &dialog->priv->image_quality_page);
+  create_optional_page (dialog, _("Color"),
+                       &dialog->priv->color_table,
+                       &dialog->priv->color_page);
+  create_optional_page (dialog, _("Finishing"),
+                       &dialog->priv->finishing_table,
+                       &dialog->priv->finishing_page);
+  create_advanced_page (dialog);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox);
+  gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
+                    FALSE, TRUE, 0);
+  
+  conflict_hbox = gtk_hbox_new (FALSE, 0);
+  image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image);
+  gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
+  label = gtk_label_new (_("Some of the settings in the dialog conflict"));
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
+  dialog->priv->conflicts_widget = conflict_hbox;
+
+  gtk_box_pack_start (GTK_BOX (hbox), conflict_hbox,
+                     FALSE, FALSE, 0);
+
+  /* Reparent the action area into the hbox. This is so we can have the
+   * conflict warning on the same row, but not make the buttons the same
+   * width as the warning (which the buttonbox does).
+   */
+  g_object_ref (GTK_DIALOG (dialog)->action_area);
+  gtk_container_remove (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
+                       GTK_DIALOG (dialog)->action_area);
+  gtk_box_pack_end (GTK_BOX (hbox), GTK_DIALOG (dialog)->action_area,
+                   FALSE, FALSE, 0);
+  g_object_unref (GTK_DIALOG (dialog)->action_area);
+  
+  gtk_widget_show (dialog->priv->notebook);
+
+  load_print_backends (dialog);
+}
+
+/**
+ * gtk_print_unix_dialog_new:
+ * @title: Title of the dialog, or %NULL
+ * @parent: Transient parent of the dialog, or %NULL
+ *
+ * Creates a new #GtkPrintUnixDialog.
+ *
+ * Return value: a new #GtkPrintUnixDialog
+ *
+ * Since: 2.10
+ **/
+GtkWidget *
+gtk_print_unix_dialog_new (const gchar *title,
+                          GtkWindow   *parent)
+{
+  GtkWidget *result;
+  const gchar *_title = _("Print");
+
+  if (title)
+    _title = title;
+  
+  result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
+                         "title", _title,
+                        "has-separator", FALSE,
+                         NULL);
+
+  if (parent)
+    gtk_window_set_transient_for (GTK_WINDOW (result), parent);
+
+  return result;
+}
+
+GtkPrinter *
+gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
+
+  return dialog->priv->current_printer;
+}
+
+void
+gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
+                                     GtkPageSetup       *page_setup)
+{
+  g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
+  g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
+
+  if (dialog->priv->page_setup != page_setup)
+    {
+      g_object_unref (dialog->priv->page_setup);
+      dialog->priv->page_setup = g_object_ref (page_setup);
+
+      g_object_notify (G_OBJECT (dialog), "page-setup");
+    }
+}
+
+GtkPageSetup *
+gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
+
+  return dialog->priv->page_setup;
+}
+
+void
+gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
+                                       gint                current_page)
+{
+  g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
+
+  if (dialog->priv->current_page != current_page)
+    {
+      dialog->priv->current_page = current_page;
+
+      if (dialog->priv->current_page_radio)
+       gtk_widget_set_sensitive (dialog->priv->current_page_radio, current_page != -1);
+
+      g_object_notify (G_OBJECT (dialog), "current-page");
+    }
+}
+
+gint
+gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
+{
+  g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
+
+  return dialog->priv->current_page;
+}
+
+static gboolean
+set_active_printer (GtkPrintUnixDialog *dialog,
+                   const gchar        *printer_name)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter, filter_iter;
+  GtkTreeSelection *selection;
+  GtkPrinter *printer;
+
+  model = GTK_TREE_MODEL (dialog->priv->printer_list);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+       {
+         gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->printer_list), &iter,
+                             PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
+         if (printer == NULL)
+           continue;
+         
+         if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
+           {
+             gtk_tree_model_filter_convert_child_iter_to_iter (dialog->priv->printer_list_filter,
+                                                               &filter_iter, &iter);
+             
+             selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->printer_treeview));
+             dialog->priv->internal_printer_change = TRUE;
+             gtk_tree_selection_select_iter (selection, &filter_iter);
+             dialog->priv->internal_printer_change = FALSE;
+             g_free (dialog->priv->waiting_for_printer);
+             dialog->priv->waiting_for_printer = NULL;
+             
+             g_object_unref (printer);
+             return TRUE;
+           }
+             
+         g_object_unref (printer);
+         
+       } while (gtk_tree_model_iter_next (model, &iter));
+    }
+  
+  return FALSE;
+}
+
+void
+gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
+                                   GtkPrintSettings   *settings)
+{
+  const char *printer;
+  GtkPageRange *ranges;
+  int num_ranges;
+  
+  g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
+  g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
+
+  if (settings != NULL)
+    {
+      dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
+      dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
+      dialog_set_n_copies (dialog, gtk_print_settings_get_num_copies (settings));
+      dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
+      dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
+      dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
+      ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
+      if (ranges)
+       dialog_set_page_ranges (dialog, ranges, num_ranges);
+
+      dialog->priv->format_for_printer =
+       g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
+    }
+
+  if (dialog->priv->initial_settings)
+    g_object_unref (dialog->priv->initial_settings);
+
+  dialog->priv->initial_settings = settings;
+
+  g_free (dialog->priv->waiting_for_printer);
+  dialog->priv->waiting_for_printer = NULL;
+  
+  if (settings)
+    {
+      g_object_ref (settings);
+
+      printer = gtk_print_settings_get_printer (settings);
+      
+      if (printer && !set_active_printer (dialog, printer))
+       dialog->priv->waiting_for_printer = g_strdup (printer); 
+    }
+
+  g_object_notify (G_OBJECT (dialog), "print-settings");
+}
+
+GtkPrintSettings *
+gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
+{
+  GtkPrintSettings *settings;
+  GtkPrintPages print_pages;
+  GtkPageRange *ranges;
+  int n_ranges;
+
+  g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
+
+  settings = gtk_print_settings_new ();
+
+  if (dialog->priv->current_printer)
+    gtk_print_settings_set_printer (settings,
+                                   gtk_printer_get_name (dialog->priv->current_printer));
+  else
+    gtk_print_settings_set_printer (settings, "default");
+  
+  gtk_print_settings_set (settings, "format-for-printer",
+                         dialog->priv->format_for_printer);
+
+  
+  gtk_print_settings_set_collate (settings,
+                                 dialog_get_collate (dialog));
+  
+  gtk_print_settings_set_reverse (settings,
+                                 dialog_get_reverse (dialog));
+  
+  gtk_print_settings_set_num_copies (settings,
+                                    dialog_get_n_copies (dialog));
+
+  gtk_print_settings_set_scale (settings,
+                               dialog_get_scale (dialog));
+  
+  gtk_print_settings_set_page_set (settings,
+                                  dialog_get_page_set (dialog));
+  
+  print_pages = dialog_get_print_pages (dialog);
+  gtk_print_settings_set_print_pages (settings, print_pages);
+
+  ranges = dialog_get_page_ranges (dialog, &n_ranges);
+  if (ranges)
+    {
+      gtk_print_settings_set_page_ranges  (settings, ranges, n_ranges);
+      g_free (ranges);
+    }
+
+  /* TODO: print when. How to handle? */
+
+  if (dialog->priv->current_printer)
+    _gtk_printer_get_settings_from_options (dialog->priv->current_printer,
+                                           dialog->priv->options,
+                                           settings);
+  
+  return settings;
+}
+
+
+#define __GTK_PRINT_UNIX_DIALOG_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintunixdialog.h b/gtk/gtkprintunixdialog.h
new file mode 100644 (file)
index 0000000..26f1fee
--- /dev/null
@@ -0,0 +1,81 @@
+/* GtkPrintUnixDialog 
+ * Copyright (C) 2006 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINT_UNIX_DIALOG_H__
+#define __GTK_PRINT_UNIX_DIALOG_H__
+
+#include "gtkdialog.h"
+#include "gtkprinter.h"
+#include "gtkprintsettings.h"
+#include "gtkpagesetup.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_UNIX_DIALOG                  (gtk_print_unix_dialog_get_type ())
+#define GTK_PRINT_UNIX_DIALOG(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialog))
+#define GTK_PRINT_UNIX_DIALOG_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialogClass))
+#define GTK_IS_PRINT_UNIX_DIALOG(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_UNIX_DIALOG))
+#define GTK_IS_PRINT_UNIX_DIALOG_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_UNIX_DIALOG))
+#define GTK_PRINT_UNIX_DIALOG_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialogClass))
+
+
+typedef struct _GtkPrintUnixDialog         GtkPrintUnixDialog;
+typedef struct _GtkPrintUnixDialogClass    GtkPrintUnixDialogClass;
+typedef struct GtkPrintUnixDialogPrivate   GtkPrintUnixDialogPrivate;
+
+struct _GtkPrintUnixDialog
+{
+  GtkDialog parent_instance;
+
+  GtkPrintUnixDialogPrivate *priv;
+};
+
+struct _GtkPrintUnixDialogClass
+{
+  GtkDialogClass parent_class;
+
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+};
+
+GType           gtk_print_unix_dialog_get_type    (void) G_GNUC_CONST;
+GtkWidget *      gtk_print_unix_dialog_new         (const gchar *title,
+                                                    GtkWindow   *parent);
+
+void              gtk_print_unix_dialog_set_page_setup       (GtkPrintUnixDialog *dialog,
+                                                             GtkPageSetup       *page_setup);
+GtkPageSetup *    gtk_print_unix_dialog_get_page_setup       (GtkPrintUnixDialog *dialog);
+void              gtk_print_unix_dialog_set_current_page     (GtkPrintUnixDialog *dialog,
+                                                             gint                current_page);
+gint              gtk_print_unix_dialog_get_current_page     (GtkPrintUnixDialog *dialog);
+void              gtk_print_unix_dialog_set_settings         (GtkPrintUnixDialog *dialog,
+                                                             GtkPrintSettings   *settings);
+GtkPrintSettings *gtk_print_unix_dialog_get_settings         (GtkPrintUnixDialog *dialog);
+GtkPrinter *      gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog);
+
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_UNIX_DIALOG_H__ */
index 7babd59e978fb25f408662753ca364e350bd19aa..b0359f50aaa4c85ad4f2e2d66929c3b45505fc3a 100644 (file)
@@ -134,6 +134,9 @@ void          gtk_stock_set_translate_func (const gchar      *domain,
 #define GTK_STOCK_NO               "gtk-no"
 #define GTK_STOCK_OK               "gtk-ok"
 #define GTK_STOCK_OPEN             "gtk-open"
+#define GTK_STOCK_ORIENTATION_PORTRAIT "gtk-orientation-portrait"
+#define GTK_STOCK_ORIENTATION_LANDSCAPE "gtk-orientation-landscape"
+#define GTK_STOCK_ORIENTATION_REVERSE_LANDSCAPE "gtk-orientation-reverse-landscape"
 #define GTK_STOCK_PASTE            "gtk-paste"
 #define GTK_STOCK_PREFERENCES      "gtk-preferences"
 #define GTK_STOCK_PRINT            "gtk-print"
diff --git a/gtk/paper_names.c b/gtk/paper_names.c
new file mode 100644 (file)
index 0000000..c2850d3
--- /dev/null
@@ -0,0 +1,192 @@
+#define N_(s) s
+
+/* The paper size names are from:
+ * PWG 5101.1-2002 PWG: Standard for Media Standardized Names
+ *
+ * The PPD names come from the PPD specification.
+ */
+
+static const PaperInfo standard_names[] = {
+  /* sorted by name, remember to sort when changing */
+  {"asme_f", "28x40in", N_("asme_f")}, /* f           5    e1 */
+  {"iso_2a0", "1189x1682mm", N_("A0x2")},
+  {"iso_a0", "841x1189mm", N_("A0"), "A0"},
+  {"iso_a0x3", "1189x2523mm", N_("A0x3")},
+  {"iso_a1", "594x841mm", N_("A1"), "A1"},
+  {"iso_a10", "26x37mm", N_("A10"), "A10"},
+  {"iso_a1x3", "841x1783mm", N_("A1x3")},
+  {"iso_a1x4", "841x2378mm", N_("A1x4")}, 
+  {"iso_a2", "420x594mm", N_("A2"), "A2"},
+  {"iso_a2x3", "594x1261mm", N_("A2x3")},
+  {"iso_a2x4", "594x1682mm", N_("A2x4")},
+  {"iso_a2x5", "594x2102mm", N_("A2x5")},
+  {"iso_a3", "297x420mm", N_("A3"), "A3"},
+  {"iso_a3-extra", "322x445mm", N_("A3 Extra"), "A3Extra"},
+  {"iso_a3x3", "420x891mm", N_("A3x3")},
+  {"iso_a3x4", "420x1189mm", N_("A3x4")},
+  {"iso_a3x5", "420x1486mm", N_("A3x5")},
+  {"iso_a3x6", "420x1783mm", N_("A3x6")},
+  {"iso_a3x7", "420x2080mm", N_("A3x7")},
+  {"iso_a4", "210x297mm", N_("A4"), "A4"},
+  {"iso_a4-extra", "235.5x322.3mm", N_("A4 Extra"), "A4Extra"},
+  {"iso_a4-tab", "225x297mm", N_("A4 Tab")},
+  {"iso_a4x3", "297x630mm", N_("A4x3")},
+  {"iso_a4x4", "297x841mm", N_("A4x4")},
+  {"iso_a4x5", "297x1051mm", N_("A4x5")},
+  {"iso_a4x6", "297x1261mm", N_("A4x6")},
+  {"iso_a4x7", "297x1471mm", N_("A4x7")},
+  {"iso_a4x8", "297x1682mm", N_("A4x8")},
+  {"iso_a4x9", "297x1892mm", N_("A4x9")},
+  {"iso_a5", "148x210mm", N_("A5"), "A5"},
+  {"iso_a5-extra", "174x235mm", N_("A5 Extra"), "A5Extra"},
+  {"iso_a6", "105x148mm", N_("A6"), "A6"},
+  {"iso_a7", "74x105mm", N_("A7"), "A7"},
+  {"iso_a8", "52x74mm", N_("A8"), "A8"},
+  {"iso_a9", "37x52mm", N_("A9"), "A9"},
+  {"iso_b0", "1000x1414mm", N_("B0"), "ISOB0"},
+  {"iso_b1", "707x1000mm", N_("B1"), "ISOB1"},
+  {"iso_b10", "31x44mm", N_("B10"), "ISOB10"},
+  {"iso_b2", "500x707mm", N_("B2"), "ISOB2"},
+  {"iso_b3", "353x500mm", N_("B3"), "ISOB3"},
+  {"iso_b4", "250x353mm", N_("B4"), "ISOB4"},
+  {"iso_b5", "176x250mm", N_("B5"), "ISOB5"},
+  {"iso_b5-extra", "201x276mm", N_("B5 Extra"), "ISOB5Extra"},
+  {"iso_b6", "125x176mm", N_("B6"), "ISOB6"}, 
+  {"iso_b6c4", "125x324mm", N_("B6/C4")}, /* b6/c4 Envelope */
+  {"iso_b7", "88x125mm", N_("B7"), "ISOB7"},
+  {"iso_b8", "62x88mm", N_("B8"), "ISOB8"},
+  {"iso_b9", "44x62mm", N_("B9"), "ISOB9"},
+  {"iso_c0", "917x1297mm", N_("C0"), "EnvC0"},
+  {"iso_c1", "648x917mm", N_("C1"), "EnvC1"},
+  {"iso_c10", "28x40mm", N_("C10"), "EnvC10"},
+  {"iso_c2", "458x648mm", N_("C2"), "EnvC2"},
+  {"iso_c3", "324x458mm", N_("C3"), "EnvC3"},
+  {"iso_c4", "229x324mm", N_("C4"), "EnvC4"},
+  {"iso_c5", "162x229mm", N_("C5"), "EnvC5"},
+  {"iso_c6", "114x162mm", N_("C6"), "EnvC6"},
+  {"iso_c6c5", "114x229mm", N_("C6/C5"), "EnvC65"},
+  {"iso_c7", "81x114mm", N_("C7"), "EnvC7"},
+  {"iso_c7c6", "81x162mm", N_("C7/C6")}, /* c7/c6 Envelope */
+  {"iso_c8", "57x81mm", N_("C8"), "EnvC8"},
+  {"iso_c9", "40x57mm", N_("C9"), "EnvC9"},
+  {"iso_dl", "110x220mm", N_("DL Envelope"), "EnvDL"}, /* iso-designated 1, 2 designated-long, dl Envelope */
+  {"iso_ra0", "860x1220mm", N_("RA0")},
+  {"iso_ra1", "610x860mm", N_("RA1")},
+  {"iso_ra2", "430x610mm", N_("RA2")},
+  {"iso_sra0", "900x1280mm", N_("SRA0")},
+  {"iso_sra1", "640x900mm", N_("SRA1")},
+  {"iso_sra2", "450x640mm", N_("SRA2")},
+  {"jis_b0", "1030x1456mm", N_("JB0"), "B0"},
+  {"jis_b1", "728x1030mm", N_("JB1"), "B1"},
+  {"jis_b10", "32x45mm", N_("JB10"), "B10"},
+  {"jis_b2", "515x728mm", N_("JB2"), "B2"},
+  {"jis_b3", "364x515mm", N_("JB3"), "B3"},
+  {"jis_b4", "257x364mm", N_("JB4"), "B4"},
+  {"jis_b5", "182x257mm", N_("JB5"), "B5"},
+  {"jis_b6", "128x182mm", N_("JB6"), "B6"},
+  {"jis_b7", "91x128mm", N_("JB7"), "B7"},
+  {"jis_b8", "64x91mm", N_("JB8"), "B8"},
+  {"jis_b9", "45x64mm", N_("JB9"), "B9"},
+  {"jis_exec", "216x330mm", N_("jis exec")},
+  {"jpn_chou2", "111.1x146mm", N_("Choukei 2 Envelope")},
+  {"jpn_chou3", "120x235mm", N_("Choukei 3 Envelope"), "EnvChou3"},
+  {"jpn_chou4", "90x205mm", N_("Choukei 4 Envelope"), "EnvChou4"},
+  {"jpn_hagaki", "100x148mm", N_("hagaki (postcard)"), "Postcard"},
+  {"jpn_kahu", "240x322.1mm", N_("kahu Envelope")},
+  {"jpn_kaku2", "240x332mm", N_("kaku2 Envelope"), "EnvKaku2"},
+  {"jpn_oufuku", "148x200mm", N_("oufuku (reply postcard)"), "DoublePostcard"},
+  {"jpn_you4", "105x235mm", N_("you4 Envelope")},
+  {"na_10x11", "10x11in", N_("10x11"), "10x11"},
+  {"na_10x13", "10x13in", N_("10x13"), "10x13"},
+  {"na_10x14", "10x14in", N_("10x14"), "10x14"},
+  {"na_10x15", "10x15in", N_("10x15")},
+  {"na_10x15", "10x15in", N_("10x15")},
+  {"na_11x12", "11x12in", N_("11x12"), "12x11"}, 
+  {"na_11x15", "11x15in", N_("11x15"), "15x11"}, 
+  {"na_12x19", "12x19in", N_("12x19")},
+  {"na_5x7", "5x7in", N_("5x7")},
+  {"na_6x9", "6x9in", N_("6x9 Envelope")},
+  {"na_7x9", "7x9in", N_("7x9 Envelope"), "7x9"},
+  {"na_9x11", "9x11in", N_("9x11 Envelope"), "9x11"},
+  {"na_a2", "4.375x5.75in", N_("a2 Envelope")},
+  {"na_arch-a", "9x12in", N_("Arch A"), "ARCHA"},
+  {"na_arch-b", "12x18in", N_("Arch B"), "ARCHB"},
+  {"na_arch-c", "18x24in", N_("Arch C"), "ARCHC"},
+  {"na_arch-d", "24x36in", N_("Arch D"), "ARCHD"},
+  {"na_arch-e", "36x48in", N_("Arch E"), "ARCHE"},
+  {"na_b-plus", "12x19.17in", N_("b-plus")},
+  {"na_c", "17x22in", N_("c"), "AnsiC"},
+  {"na_c5", "6.5x9.5in", N_("c5 Envelope")},
+  {"na_d", "22x34in", N_("d"), "AnsiD"},
+  {"na_e", "34x44in", N_("e"), "AnsiE"},
+  {"na_edp", "11x14in", N_("edp")},
+  {"na_eur-edp", "12x14in", N_("European edp")},
+  {"na_executive", "7.25x10.5in", N_("Executive"), "Executive"},
+  {"na_f", "44x68in", N_("f")},
+  {"na_fanfold-eur", "8.5x12in", N_("FanFold European"), "FanFoldGerman"},
+  {"na_fanfold-us", "11x14.875in", N_("FanFold US"), "FanFoldUS"},
+  {"na_foolscap", "8.5x13in", N_("FanFold German Legal"), "FanFoldGermanLegal"}, /* foolscap, german-legal-fanfold */
+  {"na_govt-legal", "8x13in", N_("Government Legal")},
+  {"na_govt-letter", "8x10in", N_("Government Letter"), "8x10"},
+  {"na_index-3x5", "3x5in", N_("Index 3x5")},
+  {"na_index-4x6", "4x6in", N_("Index 4x6 (postcard)")},
+  {"na_index-4x6-ext", "6x8in", N_("Index 4x6 ext")},
+  {"na_index-5x8", "5x8in", N_("Index 5x8")},
+  {"na_invoice", "5.5x8.5in", N_("Invoice"), "Statement"}, /* invoice,  statement, mini, half-letter */
+  {"na_ledger", "11x17in", N_("Tabloid"), "Ledger"}, /* tabloid, engineering-b */
+  {"na_legal", "8.5x14in", N_("US Legal"), "Legal"},
+  {"na_legal-extra", "9.5x15in", N_("US Legal Extra"), "LegalExtra"},
+  {"na_letter", "8.5x11in", N_("US Letter"), "Letter"},
+  {"na_letter-extra", "9.5x12in", N_("US Letter Extra"), "LetterExtra"},
+  {"na_letter-plus", "8.5x12.69in", N_("US Letter Plus"), "LetterPlus"},
+  {"na_monarch", "3.875x7.5in", N_("Monarch Envelope"), "EnvMonarch"},
+  {"na_number-10", "4.125x9.5in", N_("#10 Envelope"), "Env10"}, /* na-number-10-envelope 1, 2 comm-10 Envelope */
+  {"na_number-11", "4.5x10.375in", N_("#11 Eenvelope"), "Env11"}, /* number-11 Envelope */
+  {"na_number-12", "4.75x11in", N_("#12 Envelope"), "Env12"}, /* number-12 Envelope */
+  {"na_number-14", "5x11.5in", N_("#14 Envelope"), "Env14"}, /* number-14 Envelope */
+  {"na_number-9", "3.875x8.875in", N_("#9 Envelope"), "Env9"},
+  {"na_personal", "3.625x6.5in", N_("Personal Envelope"), "EnvPersonal"},
+  {"na_quarto", "8.5x10.83in", N_("Quarto"), "Quarto"}, 
+  {"na_super-a", "8.94x14in", N_("Super A"), "SuperA"}, 
+  {"na_super-b", "13x19in", N_("Super B"), "SuperB"}, 
+  {"na_wide-format", "30x42in", N_("Wide Format")},
+  {"om_dai-pa-kai", "275x395mm", N_("Dai-pa-kai")},
+  {"om_folio", "210x330mm", N_("Folio"), "Folio"}, 
+  {"om_folio-sp", "215x315mm", N_("Folio sp")},
+  {"om_invite", "220x220mm", N_("Invite Envelope"), "EnvInvite"},
+  {"om_italian", "110x230mm", N_("Italian Envelope"), "EnvItalian"},
+  {"om_juuro-ku-kai", "198x275mm", N_("juuro-ku-kai")},
+  {"om_pa-kai", "267x389mm", N_("pa-kai")},
+  {"om_postfix", "114x229mm", N_("Postfix Envelope")},
+  {"om_small-photo", "100x150mm", N_("Small Photo")},
+  {"prc_1", "102x165mm", N_("prc1 Envelope"), "EnvPRC1"},
+  {"prc_10", "324x458mm", N_("prc10 Envelope"), "EnvPRC10"},
+  {"prc_16k", "146x215mm", N_("prc 16k"), "PRC16K"},
+  {"prc_2", "102x176mm", N_("prc2 Envelope"), "EnvPRC2"},
+  {"prc_3", "125x176mm", N_("prc3 Envelope"), "EnvPRC3"},
+  {"prc_32k", "97x151mm", N_("prc 32k"), "PRC32K"},
+  {"prc_4", "110x208mm", N_("prc4 Envelope"), "EnvPRC4"},
+  {"prc_5", "110x220mm", N_("prc5 Envelope"), "EnvPRC5"},
+  {"prc_6", "120x320mm", N_("prc6 Envelope"), "EnvPRC6"},
+  {"prc_7", "160x230mm", N_("prc7 Envelope"), "EnvPRC7"},
+  {"prc_8", "120x309mm", N_("prc8 Envelope"), "EnvPRC8"},
+  {"roc_16k", "7.75x10.75in", N_("ROC 16k")},
+  {"roc_8k", "10.75x15.5in", N_("ROC 8k")},
+};
+
+/* Some page sizes have multiple PPD names in use.
+ * The array above only contails the prefered one,
+ * and this array fills out with the duplicates.
+ */
+const struct {
+  const char *ppd_name;
+  const char *standard_name;
+} extra_ppd_names[] = {
+  /* sorted by ppd_name, remember to sort when changing */
+  { "C4", "iso_c4"},
+  { "C5", "iso_c5"},
+  { "C6", "iso_c6"},
+  { "Comm10", "na_number-10"},
+  { "DL", "iso_dl"},
+  { "Monarch", "na_monarch"},
+};
diff --git a/gtk/paper_names_offsets.c b/gtk/paper_names_offsets.c
new file mode 100644 (file)
index 0000000..de6ba27
--- /dev/null
@@ -0,0 +1,712 @@
+/* Generated by gen-paper-names */
+
+#if 0
+N_("asme_f")
+N_("A0x2")
+N_("A0")
+N_("A0x3")
+N_("A1")
+N_("A10")
+N_("A1x3")
+N_("A1x4")
+N_("A2")
+N_("A2x3")
+N_("A2x4")
+N_("A2x5")
+N_("A3")
+N_("A3 Extra")
+N_("A3x3")
+N_("A3x4")
+N_("A3x5")
+N_("A3x6")
+N_("A3x7")
+N_("A4")
+N_("A4 Extra")
+N_("A4 Tab")
+N_("A4x3")
+N_("A4x4")
+N_("A4x5")
+N_("A4x6")
+N_("A4x7")
+N_("A4x8")
+N_("A4x9")
+N_("A5")
+N_("A5 Extra")
+N_("A6")
+N_("A7")
+N_("A8")
+N_("A9")
+N_("B0")
+N_("B1")
+N_("B10")
+N_("B2")
+N_("B3")
+N_("B4")
+N_("B5")
+N_("B5 Extra")
+N_("B6")
+N_("B6/C4")
+N_("B7")
+N_("B8")
+N_("B9")
+N_("C0")
+N_("C1")
+N_("C10")
+N_("C2")
+N_("C3")
+N_("C4")
+N_("C5")
+N_("C6")
+N_("C6/C5")
+N_("C7")
+N_("C7/C6")
+N_("C8")
+N_("C9")
+N_("DL Envelope")
+N_("RA0")
+N_("RA1")
+N_("RA2")
+N_("SRA0")
+N_("SRA1")
+N_("SRA2")
+N_("JB0")
+N_("JB1")
+N_("JB10")
+N_("JB2")
+N_("JB3")
+N_("JB4")
+N_("JB5")
+N_("JB6")
+N_("JB7")
+N_("JB8")
+N_("JB9")
+N_("jis exec")
+N_("Choukei 2 Envelope")
+N_("Choukei 3 Envelope")
+N_("Choukei 4 Envelope")
+N_("hagaki (postcard)")
+N_("kahu Envelope")
+N_("kaku2 Envelope")
+N_("oufuku (reply postcard)")
+N_("you4 Envelope")
+N_("10x11")
+N_("10x13")
+N_("10x14")
+N_("10x15")
+N_("10x15")
+N_("11x12")
+N_("11x15")
+N_("12x19")
+N_("5x7")
+N_("6x9 Envelope")
+N_("7x9 Envelope")
+N_("9x11 Envelope")
+N_("a2 Envelope")
+N_("Arch A")
+N_("Arch B")
+N_("Arch C")
+N_("Arch D")
+N_("Arch E")
+N_("b-plus")
+N_("c")
+N_("c5 Envelope")
+N_("d")
+N_("e")
+N_("edp")
+N_("European edp")
+N_("Executive")
+N_("f")
+N_("FanFold European")
+N_("FanFold US")
+N_("FanFold German Legal")
+N_("Government Legal")
+N_("Government Letter")
+N_("Index 3x5")
+N_("Index 4x6 (postcard)")
+N_("Index 4x6 ext")
+N_("Index 5x8")
+N_("Invoice")
+N_("Tabloid")
+N_("US Legal")
+N_("US Legal Extra")
+N_("US Letter")
+N_("US Letter Extra")
+N_("US Letter Plus")
+N_("Monarch Envelope")
+N_("#10 Envelope")
+N_("#11 Eenvelope")
+N_("#12 Envelope")
+N_("#14 Envelope")
+N_("#9 Envelope")
+N_("Personal Envelope")
+N_("Quarto")
+N_("Super A")
+N_("Super B")
+N_("Wide Format")
+N_("Dai-pa-kai")
+N_("Folio")
+N_("Folio sp")
+N_("Invite Envelope")
+N_("Italian Envelope")
+N_("juuro-ku-kai")
+N_("pa-kai")
+N_("Postfix Envelope")
+N_("Small Photo")
+N_("prc1 Envelope")
+N_("prc10 Envelope")
+N_("prc 16k")
+N_("prc2 Envelope")
+N_("prc3 Envelope")
+N_("prc 32k")
+N_("prc4 Envelope")
+N_("prc5 Envelope")
+N_("prc6 Envelope")
+N_("prc7 Envelope")
+N_("prc8 Envelope")
+N_("ROC 16k")
+N_("ROC 8k")
+#endif
+
+const char paper_names[] =
+  "asme_f\0"
+  "iso_2a0\0"
+  "A0x2\0"
+  "iso_a0\0"
+  "iso_a0x3\0"
+  "A0x3\0"
+  "iso_a1\0"
+  "iso_a10\0"
+  "A10\0"
+  "iso_a1x3\0"
+  "A1x3\0"
+  "iso_a1x4\0"
+  "A1x4\0"
+  "iso_a2\0"
+  "iso_a2x3\0"
+  "A2x3\0"
+  "iso_a2x4\0"
+  "A2x4\0"
+  "iso_a2x5\0"
+  "A2x5\0"
+  "iso_a3\0"
+  "A3\0"
+  "iso_a3-extra\0"
+  "A3 Extra\0"
+  "A3Extra\0"
+  "iso_a3x3\0"
+  "A3x3\0"
+  "iso_a3x4\0"
+  "A3x4\0"
+  "iso_a3x5\0"
+  "A3x5\0"
+  "iso_a3x6\0"
+  "A3x6\0"
+  "iso_a3x7\0"
+  "A3x7\0"
+  "iso_a4\0"
+  "A4\0"
+  "iso_a4-extra\0"
+  "A4 Extra\0"
+  "A4Extra\0"
+  "iso_a4-tab\0"
+  "A4 Tab\0"
+  "iso_a4x3\0"
+  "A4x3\0"
+  "iso_a4x4\0"
+  "A4x4\0"
+  "iso_a4x5\0"
+  "A4x5\0"
+  "iso_a4x6\0"
+  "A4x6\0"
+  "iso_a4x7\0"
+  "A4x7\0"
+  "iso_a4x8\0"
+  "A4x8\0"
+  "iso_a4x9\0"
+  "A4x9\0"
+  "iso_a5\0"
+  "A5\0"
+  "iso_a5-extra\0"
+  "A5 Extra\0"
+  "A5Extra\0"
+  "iso_a6\0"
+  "A6\0"
+  "iso_a7\0"
+  "A7\0"
+  "iso_a8\0"
+  "A8\0"
+  "iso_a9\0"
+  "A9\0"
+  "iso_b0\0"
+  "ISOB0\0"
+  "iso_b1\0"
+  "ISOB1\0"
+  "iso_b10\0"
+  "ISOB10\0"
+  "iso_b2\0"
+  "ISOB2\0"
+  "iso_b3\0"
+  "ISOB3\0"
+  "iso_b4\0"
+  "ISOB4\0"
+  "iso_b5\0"
+  "ISOB5\0"
+  "iso_b5-extra\0"
+  "B5 Extra\0"
+  "ISOB5Extra\0"
+  "iso_b6\0"
+  "ISOB6\0"
+  "iso_b6c4\0"
+  "B6/C4\0"
+  "iso_b7\0"
+  "ISOB7\0"
+  "iso_b8\0"
+  "ISOB8\0"
+  "iso_b9\0"
+  "ISOB9\0"
+  "iso_c0\0"
+  "EnvC0\0"
+  "iso_c1\0"
+  "EnvC1\0"
+  "iso_c10\0"
+  "EnvC10\0"
+  "iso_c2\0"
+  "EnvC2\0"
+  "iso_c3\0"
+  "EnvC3\0"
+  "iso_c4\0"
+  "EnvC4\0"
+  "iso_c5\0"
+  "EnvC5\0"
+  "iso_c6\0"
+  "EnvC6\0"
+  "iso_c6c5\0"
+  "C6/C5\0"
+  "EnvC65\0"
+  "iso_c7\0"
+  "EnvC7\0"
+  "iso_c7c6\0"
+  "C7/C6\0"
+  "iso_c8\0"
+  "EnvC8\0"
+  "iso_c9\0"
+  "EnvC9\0"
+  "iso_dl\0"
+  "DL Envelope\0"
+  "EnvDL\0"
+  "iso_ra0\0"
+  "iso_ra1\0"
+  "iso_ra2\0"
+  "iso_sra0\0"
+  "SRA0\0"
+  "iso_sra1\0"
+  "SRA1\0"
+  "iso_sra2\0"
+  "SRA2\0"
+  "jis_b0\0"
+  "JB0\0"
+  "jis_b1\0"
+  "JB1\0"
+  "jis_b10\0"
+  "JB10\0"
+  "jis_b2\0"
+  "JB2\0"
+  "jis_b3\0"
+  "JB3\0"
+  "jis_b4\0"
+  "JB4\0"
+  "jis_b5\0"
+  "JB5\0"
+  "jis_b6\0"
+  "JB6\0"
+  "jis_b7\0"
+  "JB7\0"
+  "jis_b8\0"
+  "JB8\0"
+  "jis_b9\0"
+  "JB9\0"
+  "jis_exec\0"
+  "jis exec\0"
+  "jpn_chou2\0"
+  "Choukei 2 Envelope\0"
+  "jpn_chou3\0"
+  "Choukei 3 Envelope\0"
+  "EnvChou3\0"
+  "jpn_chou4\0"
+  "Choukei 4 Envelope\0"
+  "EnvChou4\0"
+  "jpn_hagaki\0"
+  "hagaki (postcard)\0"
+  "jpn_kahu\0"
+  "kahu Envelope\0"
+  "jpn_kaku2\0"
+  "kaku2 Envelope\0"
+  "EnvKaku2\0"
+  "jpn_oufuku\0"
+  "oufuku (reply postcard)\0"
+  "DoublePostcard\0"
+  "jpn_you4\0"
+  "you4 Envelope\0"
+  "na_10x11\0"
+  "na_10x13\0"
+  "na_10x14\0"
+  "na_10x15\0"
+  "na_11x12\0"
+  "12x11\0"
+  "na_11x15\0"
+  "15x11\0"
+  "na_12x19\0"
+  "na_5x7\0"
+  "na_6x9\0"
+  "6x9 Envelope\0"
+  "na_7x9\0"
+  "7x9 Envelope\0"
+  "na_9x11\0"
+  "9x11 Envelope\0"
+  "na_a2\0"
+  "a2 Envelope\0"
+  "na_arch-a\0"
+  "Arch A\0"
+  "ARCHA\0"
+  "na_arch-b\0"
+  "Arch B\0"
+  "ARCHB\0"
+  "na_arch-c\0"
+  "Arch C\0"
+  "ARCHC\0"
+  "na_arch-d\0"
+  "Arch D\0"
+  "ARCHD\0"
+  "na_arch-e\0"
+  "Arch E\0"
+  "ARCHE\0"
+  "na_b-plus\0"
+  "na_c\0"
+  "AnsiC\0"
+  "na_c5\0"
+  "na_d\0"
+  "AnsiD\0"
+  "na_e\0"
+  "AnsiE\0"
+  "na_edp\0"
+  "na_eur-edp\0"
+  "European edp\0"
+  "na_executive\0"
+  "Executive\0"
+  "na_f\0"
+  "na_fanfold-eur\0"
+  "FanFold European\0"
+  "FanFoldGerman\0"
+  "na_fanfold-us\0"
+  "FanFold US\0"
+  "FanFoldUS\0"
+  "na_foolscap\0"
+  "FanFold German Legal\0"
+  "FanFoldGermanLegal\0"
+  "na_govt-legal\0"
+  "Government Legal\0"
+  "na_govt-letter\0"
+  "Government Letter\0"
+  "8x10\0"
+  "na_index-3x5\0"
+  "Index 3x5\0"
+  "na_index-4x6\0"
+  "Index 4x6 (postcard)\0"
+  "na_index-4x6-ext\0"
+  "Index 4x6 ext\0"
+  "na_index-5x8\0"
+  "Index 5x8\0"
+  "na_invoice\0"
+  "Invoice\0"
+  "Statement\0"
+  "na_ledger\0"
+  "Tabloid\0"
+  "Ledger\0"
+  "na_legal\0"
+  "US Legal\0"
+  "na_legal-extra\0"
+  "US Legal Extra\0"
+  "LegalExtra\0"
+  "na_letter\0"
+  "US Letter\0"
+  "na_letter-extra\0"
+  "US Letter Extra\0"
+  "LetterExtra\0"
+  "na_letter-plus\0"
+  "US Letter Plus\0"
+  "LetterPlus\0"
+  "na_monarch\0"
+  "Monarch Envelope\0"
+  "EnvMonarch\0"
+  "na_number-10\0"
+  "#10 Envelope\0"
+  "Env10\0"
+  "na_number-11\0"
+  "#11 Eenvelope\0"
+  "Env11\0"
+  "na_number-12\0"
+  "#12 Envelope\0"
+  "Env12\0"
+  "na_number-14\0"
+  "#14 Envelope\0"
+  "Env14\0"
+  "na_number-9\0"
+  "#9 Envelope\0"
+  "Env9\0"
+  "na_personal\0"
+  "Personal Envelope\0"
+  "EnvPersonal\0"
+  "na_quarto\0"
+  "Quarto\0"
+  "na_super-a\0"
+  "Super A\0"
+  "SuperA\0"
+  "na_super-b\0"
+  "Super B\0"
+  "SuperB\0"
+  "na_wide-format\0"
+  "Wide Format\0"
+  "om_dai-pa-kai\0"
+  "Dai-pa-kai\0"
+  "om_folio\0"
+  "Folio\0"
+  "om_folio-sp\0"
+  "Folio sp\0"
+  "om_invite\0"
+  "Invite Envelope\0"
+  "EnvInvite\0"
+  "om_italian\0"
+  "Italian Envelope\0"
+  "EnvItalian\0"
+  "om_juuro-ku-kai\0"
+  "om_pa-kai\0"
+  "om_postfix\0"
+  "Postfix Envelope\0"
+  "om_small-photo\0"
+  "Small Photo\0"
+  "prc_1\0"
+  "prc1 Envelope\0"
+  "EnvPRC1\0"
+  "prc_10\0"
+  "prc10 Envelope\0"
+  "EnvPRC10\0"
+  "prc_16k\0"
+  "prc 16k\0"
+  "PRC16K\0"
+  "prc_2\0"
+  "prc2 Envelope\0"
+  "EnvPRC2\0"
+  "prc_3\0"
+  "prc3 Envelope\0"
+  "EnvPRC3\0"
+  "prc_32k\0"
+  "prc 32k\0"
+  "PRC32K\0"
+  "prc_4\0"
+  "prc4 Envelope\0"
+  "EnvPRC4\0"
+  "prc_5\0"
+  "prc5 Envelope\0"
+  "EnvPRC5\0"
+  "prc_6\0"
+  "prc6 Envelope\0"
+  "EnvPRC6\0"
+  "prc_7\0"
+  "prc7 Envelope\0"
+  "EnvPRC7\0"
+  "prc_8\0"
+  "prc8 Envelope\0"
+  "EnvPRC8\0"
+  "roc_16k\0"
+  "ROC 16k\0"
+  "roc_8k\0"
+  "ROC 8k\0"
+  "Comm10\0";
+
+typedef struct {
+  int name;
+  float width;
+  float height;
+  int display_name;
+  int ppd_name;
+} PaperInfo;
+
+const PaperInfo standard_names_offsets[] = {
+  {    0, 711.2, 1016,    0,   -1 },
+  {    7, 1189, 1682,   15,   -1 },
+  {   20, 841, 1189,    1,    1 },
+  {   27, 1189, 2523,   36,   -1 },
+  {   41, 594, 841,    1,    1 },
+  {   48, 26, 37,   56,   56 },
+  {   60, 841, 1783,   69,   -1 },
+  {   74, 841, 2378,   83,   -1 },
+  {   88, 420, 594,    1,    1 },
+  {   95, 594, 1261,  104,   -1 },
+  {  109, 594, 1682,  118,   -1 },
+  {  123, 594, 2102,  132,   -1 },
+  {  137, 297, 420,  144,  144 },
+  {  147, 322, 445,  160,  169 },
+  {  177, 420, 891,  186,   -1 },
+  {  191, 420, 1189,  200,   -1 },
+  {  205, 420, 1486,  214,   -1 },
+  {  219, 420, 1783,  228,   -1 },
+  {  233, 420, 2080,  242,   -1 },
+  {  247, 210, 297,  254,  254 },
+  {  257, 235.5, 322.3,  270,  279 },
+  {  287, 225, 297,  298,   -1 },
+  {  305, 297, 630,  314,   -1 },
+  {  319, 297, 841,  328,   -1 },
+  {  333, 297, 1051,  342,   -1 },
+  {  347, 297, 1261,  356,   -1 },
+  {  361, 297, 1471,  370,   -1 },
+  {  375, 297, 1682,  384,   -1 },
+  {  389, 297, 1892,  398,   -1 },
+  {  403, 148, 210,  410,  410 },
+  {  413, 174, 235,  426,  435 },
+  {  443, 105, 148,  450,  450 },
+  {  453, 74, 105,  460,  460 },
+  {  463, 52, 74,  470,  470 },
+  {  473, 37, 52,  480,  480 },
+  {  483, 1000, 1414,  493,  490 },
+  {  496, 707, 1000,  506,  503 },
+  {  509, 31, 44,  520,  517 },
+  {  524, 500, 707,  534,  531 },
+  {  537, 353, 500,  547,  544 },
+  {  550, 250, 353,  560,  557 },
+  {  563, 176, 250,  573,  570 },
+  {  576, 201, 276,  589,  598 },
+  {  609, 125, 176,  619,  616 },
+  {  622, 125, 324,  631,   -1 },
+  {  637, 88, 125,  647,  644 },
+  {  650, 62, 88,  660,  657 },
+  {  663, 44, 62,  673,  670 },
+  {  676, 917, 1297,  686,  683 },
+  {  689, 648, 917,  699,  696 },
+  {  702, 28, 40,  713,  710 },
+  {  717, 458, 648,  727,  724 },
+  {  730, 324, 458,  740,  737 },
+  {  743, 229, 324,  634,  750 },
+  {  756, 162, 229,  766,  763 },
+  {  769, 114, 162,  779,  776 },
+  {  782, 114, 229,  791,  797 },
+  {  804, 81, 114,  814,  811 },
+  {  817, 81, 162,  826,   -1 },
+  {  832, 57, 81,  842,  839 },
+  {  845, 40, 57,  855,  852 },
+  {  858, 110, 220,  865,  877 },
+  {  883, 860, 1220,  917,   -1 },
+  {  891, 610, 860,  931,   -1 },
+  {  899, 430, 610,  945,   -1 },
+  {  907, 900, 1280,  916,   -1 },
+  {  921, 640, 900,  930,   -1 },
+  {  935, 450, 640,  944,   -1 },
+  {  949, 1030, 1456,  956,  493 },
+  {  960, 728, 1030,  967,  506 },
+  {  971, 32, 45,  979,  520 },
+  {  984, 515, 728,  991,  534 },
+  {  995, 364, 515, 1002,  547 },
+  { 1006, 257, 364, 1013,  560 },
+  { 1017, 182, 257, 1024,  573 },
+  { 1028, 128, 182, 1035,  619 },
+  { 1039, 91, 128, 1046,  647 },
+  { 1050, 64, 91, 1057,  660 },
+  { 1061, 45, 64, 1068,  673 },
+  { 1072, 216, 330, 1081,   -1 },
+  { 1090, 111.1, 146, 1100,   -1 },
+  { 1119, 120, 235, 1129, 1148 },
+  { 1157, 90, 205, 1167, 1186 },
+  { 1195, 100, 148, 1206, 1322 },
+  { 1224, 240, 322.1, 1233,   -1 },
+  { 1247, 240, 332, 1257, 1272 },
+  { 1281, 148, 200, 1292, 1316 },
+  { 1331, 105, 235, 1340,   -1 },
+  { 1354, 254, 279.4, 1357, 1357 },
+  { 1363, 254, 330.2, 1366, 1366 },
+  { 1372, 254, 355.6, 1375, 1375 },
+  { 1381, 254, 381, 1384,   -1 },
+  { 1381, 254, 381, 1384,   -1 },
+  { 1390, 279.4, 304.8, 1393, 1399 },
+  { 1405, 279.4, 381, 1408, 1414 },
+  { 1420, 304.8, 482.6, 1423,   -1 },
+  { 1429, 127, 177.8, 1432,   -1 },
+  { 1436, 152.4, 228.6, 1443,   -1 },
+  { 1456, 177.8, 228.6, 1463, 1459 },
+  { 1476, 228.6, 279.4, 1484, 1479 },
+  { 1498, 111.125, 146.05, 1504,   -1 },
+  { 1516, 228.6, 304.8, 1526, 1533 },
+  { 1539, 304.8, 457.2, 1549, 1556 },
+  { 1562, 457.2, 609.6, 1572, 1579 },
+  { 1585, 609.6, 914.4, 1595, 1602 },
+  { 1608, 914.4, 1219.2, 1618, 1625 },
+  { 1631, 304.8, 486.918, 1634,   -1 },
+  { 1641, 431.8, 558.8, 1079, 1646 },
+  { 1652, 165.1, 241.3, 3019,   -1 },
+  { 1658, 558.8, 863.6, 1329, 1663 },
+  { 1669, 863.6, 1117.6,  875, 1674 },
+  { 1680, 279.4, 355.6, 1683,   -1 },
+  { 1687, 304.8, 355.6, 1698,   -1 },
+  { 1711, 184.15, 266.7, 1724, 1724 },
+  { 1734, 1117.6, 1727.2,    5,   -1 },
+  { 1739, 215.9, 304.8, 1754, 1771 },
+  { 1785, 279.4, 377.825, 1799, 1810 },
+  { 1820, 215.9, 330.2, 1832, 1853 },
+  { 1872, 203.2, 330.2, 1886,   -1 },
+  { 1903, 203.2, 254, 1918, 1936 },
+  { 1941, 76.2, 127, 1954,   -1 },
+  { 1964, 101.6, 152.4, 1977,   -1 },
+  { 1998, 152.4, 203.2, 2015,   -1 },
+  { 2029, 127, 203.2, 2042,   -1 },
+  { 2052, 139.7, 215.9, 2063, 2071 },
+  { 2081, 279.4, 431.8, 2091, 2099 },
+  { 2106, 215.9, 355.6, 2115, 1847 },
+  { 2124, 241.3, 381, 2139, 2154 },
+  { 2165, 215.9, 279.4, 2175, 1929 },
+  { 2185, 241.3, 304.8, 2201, 2217 },
+  { 2229, 215.9, 322.326, 2244, 2259 },
+  { 2270, 98.425, 190.5, 2281, 2298 },
+  { 2309, 104.775, 241.3, 2322, 2335 },
+  { 2341, 114.3, 263.525, 2354, 2368 },
+  { 2374, 120.65, 279.4, 2387, 2400 },
+  { 2406, 127, 292.1, 2419, 2432 },
+  { 2438, 98.425, 225.425, 2450, 2462 },
+  { 2467, 92.075, 165.1, 2479, 2497 },
+  { 2509, 215.9, 275.082, 2519, 2519 },
+  { 2526, 227.076, 355.6, 2537, 2545 },
+  { 2552, 330.2, 482.6, 2563, 2571 },
+  { 2578, 762, 1066.8, 2593,   -1 },
+  { 2605, 275, 395, 2619,   -1 },
+  { 2630, 210, 330, 2639, 2639 },
+  { 2645, 215, 315, 2657,   -1 },
+  { 2666, 220, 220, 2676, 2692 },
+  { 2702, 110, 230, 2713, 2730 },
+  { 2741, 198, 275, 2744,   -1 },
+  { 2757, 267, 389, 2612,   -1 },
+  { 2767, 114, 229, 2778,   -1 },
+  { 2795, 100, 150, 2810,   -1 },
+  { 2822, 102, 165, 2828, 2842 },
+  { 2850, 324, 458, 2857, 2872 },
+  { 2881, 146, 215, 2889, 2897 },
+  { 2904, 102, 176, 2910, 2924 },
+  { 2932, 125, 176, 2938, 2952 },
+  { 2960, 97, 151, 2968, 2976 },
+  { 2983, 110, 208, 2989, 3003 },
+  { 3011, 110, 220, 3017, 3031 },
+  { 3039, 120, 320, 3045, 3059 },
+  { 3067, 160, 230, 3073, 3087 },
+  { 3095, 120, 309, 3101, 3115 },
+  { 3123, 196.85, 273.05, 3131,   -1 },
+  { 3139, 273.05, 393.7, 3146,   -1 },
+};
+
+const struct {
+  int ppd_name;
+  int standard_name;
+} extra_ppd_names_offsets[] = {
+  {  634,  743 },
+  {  766,  756 },
+  {  779,  769 },
+  { 3153, 2309 },
+  {  880,  858 },
+  { 2301, 2270 },
+};
+
diff --git a/gtk/stock-icons/24/gtk-orientation-landscape.png b/gtk/stock-icons/24/gtk-orientation-landscape.png
new file mode 100644 (file)
index 0000000..b2aa37c
Binary files /dev/null and b/gtk/stock-icons/24/gtk-orientation-landscape.png differ
diff --git a/gtk/stock-icons/24/gtk-orientation-portrait.png b/gtk/stock-icons/24/gtk-orientation-portrait.png
new file mode 100644 (file)
index 0000000..ed19184
Binary files /dev/null and b/gtk/stock-icons/24/gtk-orientation-portrait.png differ
diff --git a/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png b/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png
new file mode 100644 (file)
index 0000000..6ada5b4
Binary files /dev/null and b/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png differ
index 10e4875ad89014ded3e65328608a059acb2d97b9..41dfbb4470969601e6eaf56d332d0def9467ada0 100644 (file)
@@ -1 +1,6 @@
-SUBDIRS=input engines
+if OS_UNIX
+PRINTBACKENDS_SUBDIR=printbackends
+endif
+
+SUBDIRS=input engines $(PRINTBACKENDS_SUBDIR)
+DIST_SUBDIRS=input engines printbackends
diff --git a/modules/printbackends/Makefile.am b/modules/printbackends/Makefile.am
new file mode 100644 (file)
index 0000000..91a7b5d
--- /dev/null
@@ -0,0 +1,7 @@
+if HAVE_CUPS
+CUPS_SUBDIR=cups
+endif
+
+SUBDIRS=$(CUPS_SUBDIR) lpr pdf
+
+DIST_SUBDIRS=cups pdf lpr
diff --git a/modules/printbackends/cups/Makefile.am b/modules/printbackends/cups/Makefile.am
new file mode 100644 (file)
index 0000000..0174598
--- /dev/null
@@ -0,0 +1,34 @@
+if OS_WIN32
+no_undefined = -no-undefined
+endif
+
+INCLUDES = \
+       -I$(top_srcdir)                                 \
+       -I$(top_srcdir)/gtk                             \
+       -I$(top_builddir)/gtk                           \
+       -I$(top_srcdir)/gdk                             \
+       -I$(top_builddir)/gdk                           \
+       $(CUPS_CFLAGS)                                  \
+       -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED          \
+       $(GTK_DEP_CFLAGS)
+
+LDADDS = \
+       $(GTK_DEP_LIBS)                                 \
+       $(top_builddir)/gtk/$(gtktargetlib)             
+
+backenddir = $(libdir)/gtk-2.0/$(GTK_BINARY_VERSION)/printbackends
+
+backend_LTLIBRARIES = libprintbackend-cups.la
+
+libprintbackend_cups_la_SOURCES =      \
+       gtkprintbackendcups.c           \
+       gtkprintercups.c                \
+       gtkcupsutils.c
+
+noinst_HEADERS =                       \
+       gtkprintbackendcups.h           \
+       gtkprintercups.h                \
+       gtkcupsutils.h
+
+libprintbackend_cups_la_LDFLAGS =  -avoid-version -module $(no_undefined)
+libprintbackend_cups_la_LIBADD = $(LDADDS) $(CUPS_LIBS)
diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c
new file mode 100644 (file)
index 0000000..458e1c4
--- /dev/null
@@ -0,0 +1,922 @@
+/* GTK - The GIMP Toolkit
+ * gtkcupsutils.h: Statemachine implementation of POST and GET 
+ * cup calls which can be used to create a non-blocking cups API
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkcupsutils.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <time.h>
+
+typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);
+
+static void _connect            (GtkCupsRequest *request);
+static void _post_send          (GtkCupsRequest *request);
+static void _post_write_request (GtkCupsRequest *request);
+static void _post_write_data    (GtkCupsRequest *request);
+static void _post_check         (GtkCupsRequest *request);
+static void _post_read_response (GtkCupsRequest *request);
+
+static void _get_send           (GtkCupsRequest *request);
+static void _get_check          (GtkCupsRequest *request);
+static void _get_read_data      (GtkCupsRequest *request);
+
+struct _GtkCupsResult
+{
+  gchar *error_msg;
+  ipp_t *ipp_response;
+
+  guint is_error : 1;
+  guint is_ipp_response : 1;
+};
+
+
+#define _GTK_CUPS_MAX_ATTEMPTS 10 
+#define _GTK_CUPS_MAX_CHUNK_SIZE 8192
+
+GtkCupsRequestStateFunc post_states[] = {_connect,
+                                         _post_send,
+                                         _post_write_request,
+                                         _post_write_data,
+                                         _post_check,
+                                         _post_read_response};
+
+GtkCupsRequestStateFunc get_states[] = {_connect,
+                                        _get_send,
+                                        _get_check,
+                                        _get_read_data};
+
+static void
+gtk_cups_result_set_error (GtkCupsResult *result, 
+                           const char *error_msg,
+                          ...)
+{
+  va_list args;
+
+  result->is_ipp_response = FALSE;
+
+  result->is_error = TRUE;
+
+  va_start (args, error_msg);
+  result->error_msg = g_strdup_vprintf (error_msg, args);
+  va_end (args);
+}
+
+GtkCupsRequest *
+gtk_cups_request_new (http_t *connection,
+                      GtkCupsRequestType req_type, 
+                      gint operation_id,
+                      gint data_fd,
+                      const char *server,
+                      const char *resource)
+{
+  GtkCupsRequest *request;
+  cups_lang_t *language;
+  
+  request = g_new0 (GtkCupsRequest, 1);
+  request->result = g_new0 (GtkCupsResult, 1);
+
+  request->result->error_msg = NULL;
+  request->result->ipp_response = NULL;
+
+  request->result->is_error = FALSE;
+  request->result->is_ipp_response = FALSE;
+
+  request->type = req_type;
+  request->state = GTK_CUPS_REQUEST_START;
+
+   if (server)
+    request->server = g_strdup (server);
+  else
+    request->server = g_strdup (cupsServer());
+
+
+  if (resource)
+    request->resource = g_strdup (resource);
+  else
+    request->resource = g_strdup ("/");
+  if (connection != NULL)
+    {
+      request->http = connection;
+      request->own_http = FALSE;
+    }
+  else
+    {
+      request->http = NULL;
+      request->http = httpConnectEncrypt (request->server, ippPort(), cupsEncryption());
+
+      if (request->http)
+        httpBlocking (request->http, 0);
+        
+      request->own_http = TRUE;
+    }
+
+  request->last_status = HTTP_CONTINUE;
+
+  request->attempts = 0;
+  request->data_fd = data_fd;
+
+  request->ipp_request = ippNew();
+  request->ipp_request->request.op.operation_id = operation_id;
+  request->ipp_request->request.op.request_id = 1;
+
+  language = cupsLangDefault ();
+
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                                   "attributes-charset", 
+                                   NULL, "utf-8");
+       
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                                   "attributes-natural-language", 
+                                   NULL, language->language);
+
+  cupsLangFree (language);
+
+  return request;
+}
+
+static void
+gtk_cups_result_free (GtkCupsResult *result)
+{
+  g_free (result->error_msg);
+
+  if (result->ipp_response)
+    ippDelete (result->ipp_response);
+
+  g_free (result);
+}
+
+void
+gtk_cups_request_free (GtkCupsRequest *request)
+{
+  if (request->own_http)
+    if (request->http)
+      httpClose (request->http);
+  
+  if (request->ipp_request)
+    ippDelete (request->ipp_request);
+
+  g_free (request->server);
+  g_free (request->resource);
+
+  gtk_cups_result_free (request->result);
+
+  g_free (request);
+}
+
+gboolean 
+gtk_cups_request_read_write (GtkCupsRequest *request)
+{
+  if (request->type == GTK_CUPS_POST)
+    post_states[request->state](request);
+  else if (request->type == GTK_CUPS_GET)
+    get_states[request->state](request);
+
+  if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && 
+      request->state != GTK_CUPS_REQUEST_DONE)
+    {
+      gtk_cups_result_set_error (request->result, "Too many failed attempts");
+      request->state = GTK_CUPS_REQUEST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+    }
+    
+  if (request->state == GTK_CUPS_REQUEST_DONE)
+    {
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+GtkCupsPollState 
+gtk_cups_request_get_poll_state (GtkCupsRequest *request)
+{
+  return request->poll_state;
+}
+
+
+
+GtkCupsResult *
+gtk_cups_request_get_result (GtkCupsRequest *request)
+{
+  return request->result;
+}
+
+void            
+gtk_cups_request_ipp_add_string (GtkCupsRequest *request,
+                                 ipp_tag_t group,
+                                 ipp_tag_t tag,
+                                 const char *name,
+                                 const char *charset,
+                                 const char *value)
+{
+  ippAddString (request->ipp_request,
+                group,
+                tag,
+                name,
+                charset,
+                value);
+}
+
+typedef struct
+{
+  const char   *name;
+  ipp_tag_t    value_tag;
+} ipp_option_t;
+
+static const ipp_option_t ipp_options[] =
+                       {
+                         { "blackplot",                IPP_TAG_BOOLEAN },
+                         { "brightness",               IPP_TAG_INTEGER },
+                         { "columns",                  IPP_TAG_INTEGER },
+                         { "copies",                   IPP_TAG_INTEGER },
+                         { "finishings",               IPP_TAG_ENUM },
+                         { "fitplot",                  IPP_TAG_BOOLEAN },
+                         { "gamma",                    IPP_TAG_INTEGER },
+                         { "hue",                      IPP_TAG_INTEGER },
+                         { "job-k-limit",              IPP_TAG_INTEGER },
+                         { "job-page-limit",           IPP_TAG_INTEGER },
+                         { "job-priority",             IPP_TAG_INTEGER },
+                         { "job-quota-period",         IPP_TAG_INTEGER },
+                         { "landscape",                IPP_TAG_BOOLEAN },
+                         { "media",                    IPP_TAG_KEYWORD },
+                         { "mirror",                   IPP_TAG_BOOLEAN },
+                         { "natural-scaling",          IPP_TAG_INTEGER },
+                         { "number-up",                IPP_TAG_INTEGER },
+                         { "orientation-requested",    IPP_TAG_ENUM },
+                         { "page-bottom",              IPP_TAG_INTEGER },
+                         { "page-left",                IPP_TAG_INTEGER },
+                         { "page-ranges",              IPP_TAG_RANGE },
+                         { "page-right",               IPP_TAG_INTEGER },
+                         { "page-top",                 IPP_TAG_INTEGER },
+                         { "penwidth",                 IPP_TAG_INTEGER },
+                         { "ppi",                      IPP_TAG_INTEGER },
+                         { "prettyprint",              IPP_TAG_BOOLEAN },
+                         { "printer-resolution",       IPP_TAG_RESOLUTION },
+                         { "print-quality",            IPP_TAG_ENUM },
+                         { "saturation",               IPP_TAG_INTEGER },
+                         { "scaling",                  IPP_TAG_INTEGER },
+                         { "sides",                    IPP_TAG_KEYWORD },
+                         { "wrap",                     IPP_TAG_BOOLEAN }
+                       };
+
+
+static ipp_tag_t
+_find_option_tag (const gchar *option)
+{
+  int lower_bound, upper_bound, num_options;
+  int current_option;
+  ipp_tag_t result;
+
+  result = IPP_TAG_ZERO;
+
+  lower_bound = 0;
+  upper_bound = num_options = (int)(sizeof(ipp_options) / sizeof(ipp_options[0])) - 1;
+  
+  while (1)
+    {
+      int match;
+      current_option = (int) (((upper_bound - lower_bound) / 2) + lower_bound);
+
+      match = strcasecmp(option, ipp_options[current_option].name);
+      if (match == 0)
+        {
+         result = ipp_options[current_option].value_tag;
+         return result;
+       }
+      else if (match < 0)
+        {
+          upper_bound = current_option - 1;
+       }
+      else
+        {
+          lower_bound = current_option + 1;
+       }
+
+      if (upper_bound == lower_bound && upper_bound == current_option)
+        return result;
+
+      if (upper_bound < 0)
+        return result;
+
+      if (lower_bound > num_options)
+        return result;
+
+      if (upper_bound < lower_bound)
+        return result;
+    }
+}
+
+void
+gtk_cups_request_encode_option (GtkCupsRequest *request,
+                                const gchar *option,
+                               const gchar *value)
+{
+  ipp_tag_t option_tag;
+
+  g_assert (option != NULL);
+  g_assert (value != NULL);
+
+  option_tag = _find_option_tag (option);
+
+  if (option_tag == IPP_TAG_ZERO)
+    {
+      option_tag = IPP_TAG_NAME;
+      if (strcasecmp (value, "true") == 0 ||
+          strcasecmp (value, "false") == 0)
+        {
+          option_tag = IPP_TAG_BOOLEAN;
+        }
+    }
+        
+  switch (option_tag)
+    {
+      case IPP_TAG_INTEGER:
+      case IPP_TAG_ENUM:
+        ippAddInteger (request->ipp_request,
+                       IPP_TAG_OPERATION,
+                       option_tag,
+                       option,
+                       strtol (value, NULL, 0));
+        break;
+
+      case IPP_TAG_BOOLEAN:
+        {
+          char b;
+          b = 0;
+          if (!strcasecmp(value, "true") ||
+             !strcasecmp(value, "on") ||
+             !strcasecmp(value, "yes")) 
+           b = 1;
+         
+          ippAddBoolean(request->ipp_request,
+                        IPP_TAG_OPERATION,
+                        option,
+                        b);
+        
+          break;
+        }
+        
+      case IPP_TAG_RANGE:
+        {
+          char *s;
+          int lower;
+          int upper;
+          
+          if (*value == '-')
+           {
+             lower = 1;
+             s = (char *)value;
+           }
+         else
+           lower = strtol(value, &s, 0);
+
+         if (*s == '-')
+           {
+             if (s[1])
+               upper = strtol(s + 1, NULL, 0);
+             else
+               upper = 2147483647;
+            }
+         else
+           upper = lower;
+         
+          ippAddRange (request->ipp_request,
+                       IPP_TAG_OPERATION,
+                       option,
+                       lower,
+                       upper);
+
+          break;
+        }
+
+      case IPP_TAG_RESOLUTION:
+        {
+          char *s;
+          int xres;
+          int yres;
+          ipp_res_t units;
+          
+          xres = strtol(value, &s, 0);
+
+         if (*s == 'x')
+           yres = strtol(s + 1, &s, 0);
+         else
+           yres = xres;
+
+         if (strcasecmp(s, "dpc") == 0)
+            units = IPP_RES_PER_CM;
+          else
+            units = IPP_RES_PER_INCH;
+          
+          ippAddResolution (request->ipp_request,
+                            IPP_TAG_OPERATION,
+                            option,
+                            units,
+                            xres,
+                            yres);
+
+          break;
+        }
+
+      default:
+        ippAddString (request->ipp_request,
+                      IPP_TAG_OPERATION,
+                      option_tag,
+                      option,
+                      NULL,
+                      value);
+
+        break;
+    }
+}
+                               
+
+static void
+_connect (GtkCupsRequest *request)
+{
+  request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+  if (request->http == NULL)
+    {
+      request->http = httpConnectEncrypt (request->server, ippPort(), cupsEncryption());
+
+      if (request->http == NULL)
+        request->attempts++;
+
+      if (request->http)
+        httpBlocking (request->http, 0);
+        
+      request->own_http = TRUE;
+    }
+  else
+    {
+      request->attempts = 0;
+      request->state++;
+
+      /* we always write to the socket after we get
+         the connection */
+      request->poll_state = GTK_CUPS_HTTP_WRITE;
+    }
+}
+
+static void 
+_post_send (GtkCupsRequest *request)
+{
+  gchar length[255];
+  struct stat data_info;
+
+  request->poll_state = GTK_CUPS_HTTP_WRITE;
+
+  if (request->data_fd != 0)
+    {
+      fstat (request->data_fd, &data_info);
+      sprintf (length, "%lu", (unsigned long)ippLength(request->ipp_request) + data_info.st_size);
+    }
+  else
+    {
+      sprintf (length, "%lu", (unsigned long)ippLength(request->ipp_request));
+    }
+       
+  httpClearFields(request->http);
+  httpSetField(request->http, HTTP_FIELD_CONTENT_LENGTH, length);
+  httpSetField(request->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
+  httpSetField(request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
+
+  if (httpPost(request->http, request->resource))
+    {
+      if (httpReconnect(request->http))
+        {
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+          gtk_cups_result_set_error (request->result, "Failed Post");
+        }
+
+      request->attempts++;
+      return;    
+    }
+        
+    request->attempts = 0;
+
+    request->state = GTK_CUPS_POST_WRITE_REQUEST;
+    request->ipp_request->state = IPP_IDLE;
+}
+
+static void 
+_post_write_request (GtkCupsRequest *request)
+{
+  ipp_state_t ipp_status;
+
+  request->poll_state = GTK_CUPS_HTTP_WRITE;
+  
+  ipp_status = ippWrite(request->http, request->ipp_request);
+
+  if (ipp_status == IPP_ERROR)
+    {
+      request->state = GTK_CUPS_POST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      gtk_cups_result_set_error (request->result, "%s",ippErrorString (cupsLastError ()));
+      return;
+    }
+
+  if (ipp_status == IPP_DATA)
+    {
+      if (request->data_fd != 0)
+        request->state = GTK_CUPS_POST_WRITE_DATA;
+      else
+        {
+          request->state = GTK_CUPS_POST_CHECK;
+          request->poll_state = GTK_CUPS_HTTP_READ;
+       }
+    }
+}
+
+static void 
+_post_write_data (GtkCupsRequest *request)
+{
+  ssize_t bytes;
+  char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
+  http_status_t http_status;
+
+  request->poll_state = GTK_CUPS_HTTP_WRITE;
+  
+  if (httpCheck (request->http))
+    http_status = httpUpdate(request->http);
+  else
+    http_status = request->last_status;
+
+  request->last_status = http_status;
+
+
+  if (http_status == HTTP_CONTINUE || http_status == HTTP_OK)
+    {
+      /* send data */
+      bytes = read(request->data_fd, buffer, _GTK_CUPS_MAX_CHUNK_SIZE);
+
+      if (bytes == 0)
+        {
+          request->state = GTK_CUPS_POST_CHECK;
+         request->poll_state = GTK_CUPS_HTTP_READ;
+
+          request->attempts = 0;
+          return;
+        }
+      else if (bytes == -1)
+        {
+          request->state = GTK_CUPS_POST_DONE;
+         request->poll_state = GTK_CUPS_HTTP_IDLE;
+     
+          gtk_cups_result_set_error (request->result, "Error reading from cache file: %s", strerror (errno));
+          return;
+       }
+       
+      if (httpWrite(request->http, buffer, (int)bytes) < bytes)
+        {
+          request->state = GTK_CUPS_POST_DONE;
+         request->poll_state = GTK_CUPS_HTTP_IDLE;
+     
+          gtk_cups_result_set_error (request->result, "Error writting to socket in Post %s", strerror (httpError (request->http)));
+          return;
+        }
+    }
+   else
+    {
+      request->attempts++;
+    }
+}
+
+static void 
+_post_check (GtkCupsRequest *request)
+{
+  http_status_t http_status;
+
+  http_status = request->last_status;
+
+  request->poll_state = GTK_CUPS_HTTP_READ;
+
+  if (http_status == HTTP_CONTINUE)
+    {
+      goto again; 
+    }
+  else if (http_status == HTTP_UNAUTHORIZED)
+    {
+      /* TODO: callout for auth */
+      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization");
+      request->state = GTK_CUPS_POST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      
+      gtk_cups_result_set_error (request->result, "Can't prompt for authorization");
+      return;
+    }
+  else if (http_status == HTTP_ERROR)
+    {
+#ifdef G_OS_WIN32
+      if (request->http->error != WSAENETDOWN && 
+          request->http->error != WSAENETUNREACH)
+#else
+      if (request->http->error != ENETDOWN && 
+          request->http->error != ENETUNREACH)
+#endif /* G_OS_WIN32 */
+        {
+          request->attempts++;
+          goto again;
+        }
+      else
+        {
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+     
+          gtk_cups_result_set_error (request->result, "Unknown HTTP error");
+          return;
+        }
+    }
+/* TODO: detect ssl in configure.ac */
+#if HAVE_SSL
+  else if (http_status == HTTP_UPGRADE_REQUIRED)
+    {
+      /* Flush any error message... */
+      httpFlush (request->http);
+
+      /* Reconnect... */
+      httpReconnect (request->http);
+
+      /* Upgrade with encryption... */
+      httpEncryption(request->http, HTTP_ENCRYPT_REQUIRED);
+      request->attempts++;
+      goto again;
+    }
+#endif 
+  else if (http_status != HTTP_OK)
+    {
+      int http_errno;
+
+      http_errno = httpError (request->http);
+
+      if (http_errno == EPIPE)
+        request->state = GTK_CUPS_POST_CONNECT;
+      else
+        {
+          request->state = GTK_CUPS_POST_DONE;
+          gtk_cups_result_set_error (request->result, "HTTP Error in POST %s", strerror (http_errno));
+         request->poll_state = GTK_CUPS_HTTP_IDLE;
+          httpFlush(request->http); 
+          return;
+        }
+
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+       
+      httpFlush(request->http); 
+      
+      request->last_status = HTTP_CONTINUE;
+      httpClose (request->http);
+      request->http = NULL;
+      return;  
+    }
+  else
+    {
+      request->state = GTK_CUPS_POST_READ_RESPONSE;
+      return;
+    }
+
+ again:
+  http_status = HTTP_CONTINUE;
+
+  if (httpCheck (request->http))
+    http_status = httpUpdate (request->http);
+
+  request->last_status = http_status;
+}
+
+static void 
+_post_read_response (GtkCupsRequest *request)
+{
+  ipp_state_t ipp_status;
+
+  request->poll_state = GTK_CUPS_HTTP_READ;
+
+  if (request->result->ipp_response == NULL)
+    request->result->ipp_response = ippNew();
+
+  ipp_status = ippRead (request->http, 
+                        request->result->ipp_response);
+
+  if (ipp_status == IPP_ERROR)
+    {
+      gtk_cups_result_set_error (request->result, "%s", ippErrorString (cupsLastError()));
+      
+      ippDelete (request->result->ipp_response);
+      request->result->ipp_response = NULL;
+
+      request->state = GTK_CUPS_POST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+    }
+  else if (ipp_status == IPP_DATA)
+    {
+      request->state = GTK_CUPS_POST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+    }
+}
+
+static void 
+_get_send (GtkCupsRequest *request)
+{
+  request->poll_state = GTK_CUPS_HTTP_WRITE;
+
+  if (request->data_fd == 0)
+    {
+      gtk_cups_result_set_error (request->result, "Get requires an open file descriptor");
+      request->state = GTK_CUPS_GET_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+      return;
+    }
+
+  httpClearFields(request->http);
+  httpSetField(request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
+
+  if (httpGet(request->http, request->resource))
+    {
+      if (httpReconnect(request->http))
+        {
+          request->state = GTK_CUPS_GET_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+         
+          gtk_cups_result_set_error (request->result, "Failed Get");
+        }
+
+      request->attempts++;
+      return;    
+    }
+        
+  request->attempts = 0;
+
+  request->state = GTK_CUPS_GET_CHECK;
+  request->poll_state = GTK_CUPS_HTTP_READ;
+  
+  request->ipp_request->state = IPP_IDLE;
+}
+
+static void 
+_get_check (GtkCupsRequest *request)
+{
+  http_status_t http_status;
+
+  http_status = request->last_status;
+
+  request->poll_state = GTK_CUPS_HTTP_READ;
+
+  if (http_status == HTTP_CONTINUE)
+    {
+      goto again; 
+    }
+  else if (http_status == HTTP_UNAUTHORIZED)
+    {
+      /* TODO: callout for auth */
+      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization in a non blocking manner");
+      request->state = GTK_CUPS_GET_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      gtk_cups_result_set_error (request->result, "Can't prompt for authorization");
+      return;
+    }
+/* TODO: detect ssl in configure.ac */
+#if HAVE_SSL
+  else if (http_status == HTTP_UPGRADE_REQUIRED)
+    {
+      /* Flush any error message... */
+      httpFlush (request->http);
+
+      /* Reconnect... */
+      httpReconnect (request->http);
+
+      /* Upgrade with encryption... */
+      httpEncryption(request->http, HTTP_ENCRYPT_REQUIRED);
+      request->attempts++;
+      goto again;
+    }
+#endif 
+  else if (http_status != HTTP_OK)
+    {
+      int http_errno;
+
+      http_errno = httpError (request->http);
+
+      if (http_errno == EPIPE)
+        request->state = GTK_CUPS_GET_CONNECT;
+      else
+        {
+          request->state = GTK_CUPS_GET_DONE;
+          gtk_cups_result_set_error (request->result, "HTTP Error in GET %s", strerror (http_errno));
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          httpFlush(request->http);
+
+          return;
+        }
+
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      httpFlush (request->http);
+      httpClose (request->http);
+      request->last_status = HTTP_CONTINUE;
+      request->http = NULL;
+      return;
+
+    }
+  else
+    {
+      request->state = GTK_CUPS_GET_READ_DATA;
+      return;
+    }
+
+ again:
+  http_status = HTTP_CONTINUE;
+
+  if (httpCheck (request->http))
+    http_status = httpUpdate (request->http);
+
+  request->last_status = http_status;
+
+}
+
+static void 
+_get_read_data (GtkCupsRequest *request)
+{
+  char buffer[_GTK_CUPS_MAX_CHUNK_SIZE];
+  int bytes;
+  request->poll_state = GTK_CUPS_HTTP_READ;
+  bytes = httpRead(request->http, buffer, sizeof(buffer));
+
+  if (bytes == 0)
+    {
+      request->state = GTK_CUPS_GET_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+      return;
+    }
+    
+  if (write (request->data_fd, buffer, bytes) == -1)
+    {
+      char *error_msg;
+
+      request->state = GTK_CUPS_POST_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+    
+      error_msg = strerror (errno);
+      gtk_cups_result_set_error (request->result, error_msg ? error_msg:""); 
+    }
+}
+
+gboolean
+gtk_cups_request_is_done (GtkCupsRequest *request)
+{
+  return (request->state == GTK_CUPS_REQUEST_DONE);
+}
+
+gboolean
+gtk_cups_result_is_error (GtkCupsResult *result)
+{
+  return result->is_error;
+}
+
+ipp_t *
+gtk_cups_result_get_response (GtkCupsResult *result)
+{
+  return result->ipp_response;
+}
+
+const char *
+gtk_cups_result_get_error_string (GtkCupsResult *result)
+{
+  return result->error_msg; 
+}
+
diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h
new file mode 100644 (file)
index 0000000..f49cd2e
--- /dev/null
@@ -0,0 +1,125 @@
+/* gtkcupsutils.h 
+ * Copyright (C) 2006 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_CUPS_UTILS_H__
+#define __GTK_CUPS_UTILS_H__
+
+#include <glib.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/http.h>
+#include <cups/ipp.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCupsRequest  GtkCupsRequest;
+typedef struct _GtkCupsResult   GtkCupsResult;
+
+typedef enum
+{
+  GTK_CUPS_POST,
+  GTK_CUPS_GET
+} GtkCupsRequestType;
+
+
+/** 
+ * Direction we should be polling the http socket on.
+ * We are either reading or writting at each state.
+ * This makes it easy for mainloops to connect to poll.
+ */
+typedef enum
+{
+  GTK_CUPS_HTTP_IDLE,
+  GTK_CUPS_HTTP_READ,
+  GTK_CUPS_HTTP_WRITE
+} GtkCupsPollState;
+
+
+struct _GtkCupsRequest 
+{
+  GtkCupsRequestType type;
+
+  http_t *http;
+  http_status_t last_status;
+  ipp_t *ipp_request;
+
+  gchar *server;
+  gchar *resource;
+  gint data_fd;
+  gint attempts;
+
+  GtkCupsResult *result;
+
+  gint state;
+  GtkCupsPollState poll_state;
+
+  gint own_http : 1; 
+};
+
+#define GTK_CUPS_REQUEST_START 0
+#define GTK_CUPS_REQUEST_DONE 500
+
+/* POST states */
+enum 
+{
+  GTK_CUPS_POST_CONNECT = GTK_CUPS_REQUEST_START,
+  GTK_CUPS_POST_SEND,
+  GTK_CUPS_POST_WRITE_REQUEST,
+  GTK_CUPS_POST_WRITE_DATA,
+  GTK_CUPS_POST_CHECK,
+  GTK_CUPS_POST_READ_RESPONSE,
+  GTK_CUPS_POST_DONE = GTK_CUPS_REQUEST_DONE
+};
+
+/* GET states */
+enum
+{
+  GTK_CUPS_GET_CONNECT = GTK_CUPS_REQUEST_START,
+  GTK_CUPS_GET_SEND,
+  GTK_CUPS_GET_CHECK,
+  GTK_CUPS_GET_READ_DATA,
+  GTK_CUPS_GET_DONE = GTK_CUPS_REQUEST_DONE
+};
+
+GtkCupsRequest * gtk_cups_request_new             (http_t             *connection,
+                                                  GtkCupsRequestType  req_type,
+                                                  gint                operation_id,
+                                                  gint                data_fd,
+                                                  const char         *server,
+                                                  const char         *resource);
+void             gtk_cups_request_ipp_add_string  (GtkCupsRequest     *request,
+                                                  ipp_tag_t           group,
+                                                  ipp_tag_t           tag,
+                                                  const char         *name,
+                                                  const char         *charset,
+                                                  const char         *value);
+gboolean         gtk_cups_request_read_write      (GtkCupsRequest     *request);
+GtkCupsPollState gtk_cups_request_get_poll_state  (GtkCupsRequest     *request);
+void             gtk_cups_request_free            (GtkCupsRequest     *request);
+GtkCupsResult  * gtk_cups_request_get_result      (GtkCupsRequest     *request);
+gboolean         gtk_cups_request_is_done         (GtkCupsRequest     *request);
+void             gtk_cups_request_encode_option   (GtkCupsRequest     *request,
+                                                  const gchar        *option,
+                                                  const gchar        *value);
+gboolean         gtk_cups_result_is_error         (GtkCupsResult      *result);
+ipp_t          * gtk_cups_result_get_response     (GtkCupsResult      *result);
+const char     * gtk_cups_result_get_error_string (GtkCupsResult      *result);
+
+G_END_DECLS
+#endif 
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c
new file mode 100644 (file)
index 0000000..79922a5
--- /dev/null
@@ -0,0 +1,2629 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendcups.h: Default implementation of GtkPrintBackend 
+ * for the Common Unix Print System (CUPS)
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include <config.h>
+#include <cups/cups.h>
+#include <cups/language.h>
+#include <cups/http.h>
+#include <cups/ipp.h>
+#include <errno.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+#include <cairo-ps.h>
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gtk/gtkprintoperation.h>
+#include <gtk/gtkprintsettings.h>
+#include <gtk/gtkprintbackend.h>
+#include <gtk/gtkprinter.h>
+
+#include "gtkprintbackendcups.h"
+#include "gtkprintercups.h"
+
+#include "gtkcupsutils.h"
+
+
+typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
+
+#define GTK_PRINT_BACKEND_CUPS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
+#define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
+#define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
+
+#define _CUPS_MAX_ATTEMPTS 10 
+#define _CUPS_MAX_CHUNK_SIZE 8192
+
+#define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
+#define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = g_strdup (attr->values[0].string.text);}
+
+static GType print_backend_cups_type = 0;
+
+typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
+                                                   GtkCupsResult *result, 
+                                                   gpointer user_data);
+
+typedef enum 
+{
+  DISPATCH_SETUP,
+  DISPATCH_REQUEST,
+  DISPATCH_SEND,
+  DISPATCH_CHECK,
+  DISPATCH_READ,
+  DISPATCH_ERROR
+} GtkPrintCupsDispatchState;
+
+typedef struct 
+{
+  GSource source;
+
+  http_t *http;
+  GtkCupsRequest *request;
+  GPollFD *data_poll;
+  GtkPrintBackendCups *backend;
+
+} GtkPrintCupsDispatchWatch;
+
+struct _GtkPrintBackendCupsClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GtkPrintBackendCups
+{
+  GObject parent_instance;
+
+  GHashTable *printers;
+
+  char *default_printer;
+  
+  guint list_printers_poll;
+  guint list_printers_pending : 1;
+  guint got_default_printer : 1;
+};
+
+static GObjectClass *backend_parent_class;
+
+static void                 gtk_print_backend_cups_class_init      (GtkPrintBackendCupsClass          *class);
+static void                 gtk_print_backend_cups_iface_init      (GtkPrintBackendIface              *iface);
+static void                 gtk_print_backend_cups_init            (GtkPrintBackendCups               *impl);
+static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
+static GList *              cups_get_printer_list              (GtkPrintBackend                    *print_backend);
+static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
+                                                                   GtkCupsRequest                    *request,
+                                                                   GtkPrintCupsResponseCallbackFunc   callback,
+                                                                   gpointer                           user_data,
+                                                                   GDestroyNotify                     notify,
+                                                                   GError                           **err);
+static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
+                                                                   GtkPrinterOptionSet               *options,
+                                                                   GtkPrintSettings                  *settings);
+static gboolean             cups_printer_mark_conflicts            (GtkPrinter                        *printer,
+                                                                   GtkPrinterOptionSet               *options);
+static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
+                                                                   GtkPrintSettings                  *settings,
+                                                                   GtkPageSetup                      *page_setup);
+static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
+                                                                   GtkPrintJob                       *print_job,
+                                                                   GtkPrintSettings                  *settings,
+                                                                   GtkPageSetup                      *page_setup);
+static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
+static void                 cups_printer_request_details           (GtkPrinter                        *printer);
+static void                 cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
+static void                 cups_request_ppd                       (GtkPrinter                        *printer);
+static void                 cups_printer_get_hard_margins          (GtkPrinter                        *printer,
+                                                                   double                            *top,
+                                                                   double                            *bottom,
+                                                                   double                            *left,
+                                                                   double                            *right);
+static void                 set_option_from_settings               (GtkPrinterOption                  *option,
+                                                                   GtkPrintSettings                  *setting);
+static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
+                                                                   GtkPrintJob                       *job,
+                                                                   int                                job_id);
+static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
+
+static void
+gtk_print_backend_cups_register_type (GTypeModule *module)
+{
+  if (!print_backend_cups_type)
+    {
+      static const GTypeInfo print_backend_cups_info =
+      {
+       sizeof (GtkPrintBackendCupsClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) gtk_print_backend_cups_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (GtkPrintBackendCups),
+       0,              /* n_preallocs */
+       (GInstanceInitFunc) gtk_print_backend_cups_init
+      };
+
+      static const GInterfaceInfo print_backend_info =
+      {
+       (GInterfaceInitFunc) gtk_print_backend_cups_iface_init, /* interface_init */
+       NULL,                                                 /* interface_finalize */
+       NULL                                                  /* interface_data */
+      };
+
+      print_backend_cups_type = g_type_module_register_type (module,
+                                                             G_TYPE_OBJECT,
+                                                            "GtkPrintBackendCups",
+                                                            &print_backend_cups_info, 0);
+      g_type_module_add_interface (module,
+                                   print_backend_cups_type,
+                                  GTK_TYPE_PRINT_BACKEND,
+                                  &print_backend_info);
+    }
+}
+
+G_MODULE_EXPORT void 
+pb_module_init (GTypeModule *module)
+{
+  gtk_print_backend_cups_register_type (module);
+  gtk_printer_cups_register_type (module);
+}
+
+G_MODULE_EXPORT void 
+pb_module_exit (void)
+{
+
+}
+  
+G_MODULE_EXPORT GtkPrintBackend * 
+pb_module_create (void)
+{
+  return gtk_print_backend_cups_new ();
+}
+
+/*
+ * GtkPrintBackendCups
+ */
+GType
+gtk_print_backend_cups_get_type (void)
+{
+  return print_backend_cups_type;
+}
+
+/**
+ * gtk_print_backend_cups_new:
+ *
+ * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
+ * implements the #GtkPrintBackend interface with direct access to
+ * the filesystem using Unix/Linux API calls
+ *
+ * Return value: the new #GtkPrintBackendCups object
+ **/
+GtkPrintBackend *
+gtk_print_backend_cups_new (void)
+{
+  return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
+}
+
+static void
+gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  backend_parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->finalize = gtk_print_backend_cups_finalize;
+}
+
+static cairo_status_t
+_cairo_write_to_cups (void *cache_fd_as_pointer,
+                      const unsigned char *data,
+                      unsigned int         length)
+{
+  cairo_status_t result;
+  gint cache_fd;
+  cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
+
+  result = CAIRO_STATUS_WRITE_ERROR;
+  
+  /* write out the buffer */
+  if (write (cache_fd, data, length) != -1)
+      result = CAIRO_STATUS_SUCCESS;
+   
+  return result;
+}
+
+
+static cairo_surface_t *
+cups_printer_create_cairo_surface (GtkPrinter *printer,
+                                  gdouble width, 
+                                  gdouble height,
+                                  gint cache_fd)
+{
+  cairo_surface_t *surface; 
+  /* TODO: check if it is a ps or pdf printer */
+  
+  surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
+
+  /* TODO: DPI from settings object? */
+  cairo_ps_surface_set_dpi (surface, 300, 300);
+
+  return surface;
+}
+
+static GtkPrinter *
+gtk_print_backend_cups_find_printer (GtkPrintBackend *print_backend,
+                                     const gchar *printer_name)
+{
+  GtkPrintBackendCups *cups_print_backend;
+
+  cups_print_backend = GTK_PRINT_BACKEND_CUPS (print_backend);
+  
+  return (GtkPrinter *) g_hash_table_lookup (cups_print_backend->printers, 
+                                                  printer_name);  
+}
+
+typedef struct {
+  GtkPrintJobCompleteFunc callback;
+  GtkPrintJob *job;
+  gpointer user_data;
+  GDestroyNotify dnotify;
+} CupsPrintStreamData;
+
+static void
+cups_free_print_stream_data (CupsPrintStreamData *data)
+{
+  if (data->dnotify)
+    data->dnotify (data->user_data);
+  g_object_unref (data->job);
+  g_free (data);
+}
+
+static void
+cups_print_cb (GtkPrintBackendCups *print_backend,
+               GtkCupsResult *result,
+               gpointer user_data)
+{
+  GError *error = NULL;
+  CupsPrintStreamData *ps = user_data;
+
+  if (gtk_cups_result_is_error (result))
+    error = g_error_new_literal (gtk_print_error_quark (),
+                                 GTK_PRINT_ERROR_INTERNAL_ERROR,
+                                 gtk_cups_result_get_error_string (result));
+
+  if (ps->callback)
+    ps->callback (ps->job, ps->user_data, error);
+
+  if (error == NULL)
+    {
+      int job_id = 0;
+      ipp_attribute_t *attr;           /* IPP job-id attribute */
+      ipp_t *response = gtk_cups_result_get_response (result);
+
+      if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
+       job_id = attr->values[0].integer;
+
+
+        if (job_id == 0)
+         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
+       else
+         {
+           gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
+           cups_begin_polling_info (print_backend, ps->job, job_id);
+         }
+    }
+  else
+    gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
+
+  
+  if (error)
+    g_error_free (error);
+  
+}
+
+static void
+add_cups_options (const char *key,
+                 const char *value,
+                 gpointer  user_data)
+{
+  GtkCupsRequest *request = user_data;
+
+  if (!g_str_has_prefix (key, "cups-"))
+    return;
+
+  if (strcmp (value, "gtk-ignore-value") == 0)
+    return;
+  
+  key = key + strlen("cups-");
+
+  gtk_cups_request_encode_option (request, key, value);
+}
+
+static void
+gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
+                                     GtkPrintJob *job,
+                                    gint data_fd,
+                                    GtkPrintJobCompleteFunc callback,
+                                    gpointer user_data,
+                                    GDestroyNotify dnotify)
+{
+  GError *error;
+  GtkPrinterCups *cups_printer;
+  CupsPrintStreamData *ps;
+  GtkCupsRequest *request;
+  GtkPrintSettings *settings;
+  const gchar *title;
+
+  cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
+  settings = gtk_print_job_get_settings (job);
+
+  error = NULL;
+
+  request = gtk_cups_request_new (NULL,
+                                  GTK_CUPS_POST,
+                                  IPP_PRINT_JOB,
+                                 data_fd,
+                                 NULL,
+                                 cups_printer->device_uri);
+
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+                                   NULL, cups_printer->printer_uri);
+
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+                                   NULL, cupsUser());
+
+  title = gtk_print_job_get_title (job);
+  if (title)
+    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+                                     title);
+
+  gtk_print_settings_foreach (settings, add_cups_options, request);
+  
+  ps = g_new0 (CupsPrintStreamData, 1);
+  ps->callback = callback;
+  ps->user_data = user_data;
+  ps->dnotify = dnotify;
+  ps->job = g_object_ref (job);
+
+  cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
+                        ps,
+                        (GDestroyNotify)cups_free_print_stream_data,
+                        &error);
+}
+
+
+static void
+gtk_print_backend_cups_iface_init (GtkPrintBackendIface *iface)
+{
+  iface->get_printer_list = cups_get_printer_list; 
+  iface->find_printer = gtk_print_backend_cups_find_printer;
+  iface->print_stream = gtk_print_backend_cups_print_stream;
+  iface->printer_request_details = cups_printer_request_details;
+  iface->printer_create_cairo_surface = cups_printer_create_cairo_surface;
+  iface->printer_get_options = cups_printer_get_options;
+  iface->printer_mark_conflicts = cups_printer_mark_conflicts;
+  iface->printer_get_settings_from_options = cups_printer_get_settings_from_options;
+  iface->printer_prepare_for_print = cups_printer_prepare_for_print;
+  iface->printer_list_papers = cups_printer_list_papers;
+  iface->printer_get_hard_margins = cups_printer_get_hard_margins;
+}
+
+static void
+gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
+{
+  backend_cups->list_printers_poll = 0;  
+  backend_cups->list_printers_pending = FALSE;
+  backend_cups->printers = g_hash_table_new_full (g_str_hash, 
+                                                  g_str_equal, 
+                                                 (GDestroyNotify) g_free,
+                                                 (GDestroyNotify) g_object_unref);
+
+  cups_request_default_printer (backend_cups);
+}
+
+static void
+gtk_print_backend_cups_finalize (GObject *object)
+{
+  GtkPrintBackendCups *backend_cups;
+
+  backend_cups = GTK_PRINT_BACKEND_CUPS (object);
+
+  if (backend_cups->list_printers_poll > 0)
+    g_source_remove (backend_cups->list_printers_poll);
+
+  if (backend_cups->printers)
+    g_hash_table_unref (backend_cups->printers);
+
+  g_free (backend_cups->default_printer);
+  backend_cups->default_printer = NULL;
+  
+  backend_parent_class->finalize (object);
+}
+
+static gboolean
+cups_dispatch_watch_check (GSource *source)
+{
+  GtkPrintCupsDispatchWatch *dispatch;
+  GtkCupsPollState poll_state;
+  gboolean result;
+
+  dispatch = (GtkPrintCupsDispatchWatch *) source;
+
+  poll_state = gtk_cups_request_get_poll_state (dispatch->request);
+  
+  if (dispatch->data_poll == NULL && 
+      dispatch->request->http != NULL)
+    {
+      dispatch->data_poll = g_new0 (GPollFD, 1);
+      dispatch->data_poll->fd = dispatch->request->http->fd;
+
+      g_source_add_poll (source, dispatch->data_poll);
+    }
+            
+  if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
+    {
+      if (dispatch->data_poll->fd != dispatch->request->http->fd)
+        dispatch->data_poll->fd = dispatch->request->http->fd;
+
+      if (poll_state == GTK_CUPS_HTTP_READ)
+        dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
+      else if (poll_state == GTK_CUPS_HTTP_WRITE)
+        dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
+      else
+        dispatch->data_poll->events = 0;
+    }
+    
+  if (poll_state != GTK_CUPS_HTTP_IDLE)  
+    if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
+       return FALSE;
+  
+  result = gtk_cups_request_read_write (dispatch->request);
+  if (result && dispatch->data_poll != NULL)
+    {
+      g_source_remove_poll (source, dispatch->data_poll);
+      g_free (dispatch->data_poll);
+      dispatch->data_poll = NULL;
+    }
+  
+  return result;
+}
+
+static gboolean
+cups_dispatch_watch_prepare (GSource *source,
+                              gint *timeout_)
+{
+  GtkPrintCupsDispatchWatch *dispatch;
+
+  dispatch = (GtkPrintCupsDispatchWatch *) source;
+
+  *timeout_ = -1;
+  
+  return gtk_cups_request_read_write (dispatch->request);
+}
+
+static gboolean
+cups_dispatch_watch_dispatch (GSource *source,
+                               GSourceFunc callback,
+                               gpointer user_data)
+{
+  GtkPrintCupsDispatchWatch *dispatch;
+  GtkPrintCupsResponseCallbackFunc ep_callback;  
+  GtkCupsResult *result;
+  
+  g_assert (callback != NULL);
+
+  ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
+  
+  dispatch = (GtkPrintCupsDispatchWatch *) source;
+
+  result = gtk_cups_request_get_result (dispatch->request);
+
+  if (gtk_cups_result_is_error (result))
+    g_warning (gtk_cups_result_get_error_string (result));
+
+  ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
+
+  g_source_unref (source); 
+  return FALSE;
+}
+
+static void
+cups_dispatch_watch_finalize (GSource *source)
+{
+  GtkPrintCupsDispatchWatch *dispatch;
+
+  dispatch = (GtkPrintCupsDispatchWatch *) source;
+
+  gtk_cups_request_free (dispatch->request);
+
+  if (dispatch->backend)
+    {
+      g_object_unref (dispatch->backend);
+      dispatch->backend = NULL;
+    }
+
+  if (dispatch->data_poll != NULL)
+    g_free (dispatch->data_poll);
+}
+
+static GSourceFuncs _cups_dispatch_watch_funcs = {
+  cups_dispatch_watch_prepare,
+  cups_dispatch_watch_check,
+  cups_dispatch_watch_dispatch,
+  cups_dispatch_watch_finalize
+};
+
+
+static void
+cups_request_execute (GtkPrintBackendCups *print_backend,
+                      GtkCupsRequest *request,
+                      GtkPrintCupsResponseCallbackFunc callback,
+                      gpointer user_data,
+                      GDestroyNotify notify,
+                      GError **err)
+{
+  GtkPrintCupsDispatchWatch *dispatch;
+  
+  dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, 
+                                                         sizeof (GtkPrintCupsDispatchWatch));
+
+  dispatch->request = request;
+  dispatch->backend = g_object_ref (print_backend);
+  dispatch->data_poll = NULL;
+
+  g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
+
+  g_source_attach ((GSource *) dispatch, NULL);
+}
+
+static void
+cups_request_printer_info_cb (GtkPrintBackendCups *print_backend,
+                              GtkCupsResult *result,
+                              gpointer user_data)
+{
+  ipp_attribute_t *attr;
+  ipp_t *response;
+  gchar *printer_name;
+  GtkPrinterCups *cups_printer;
+  GtkPrinter *printer;
+  gchar *printer_uri;
+  gchar *member_printer_uri;
+  gchar *loc;
+  gchar *desc;
+  gchar *state_msg;
+  int job_count;
+
+  char uri[HTTP_MAX_URI],      /* Printer URI */
+       method[HTTP_MAX_URI],   /* Method/scheme name */
+       username[HTTP_MAX_URI], /* Username:password */
+       hostname[HTTP_MAX_URI], /* Hostname */
+       resource[HTTP_MAX_URI]; /* Resource name */
+  int  port;                   /* Port number */
+  gboolean status_changed;  
+
+  g_assert (GTK_IS_PRINT_BACKEND_CUPS (print_backend));
+
+  printer_uri = NULL;
+  member_printer_uri = NULL;
+
+  printer_name = (gchar *)user_data;
+  cups_printer = (GtkPrinterCups *) g_hash_table_lookup (print_backend->printers, printer_name);
+
+  if (!cups_printer)
+    return;
+
+  printer = GTK_PRINTER (cups_printer);
+  
+  if (gtk_cups_result_is_error (result))
+    {
+      if (gtk_printer_is_new (printer))
+       {
+         g_hash_table_remove (print_backend->printers,
+                              printer_name);
+         return;
+       }
+      else
+       return; /* TODO: mark as inactive printer */
+    }
+
+  response = gtk_cups_result_get_response (result);
+
+  /* TODO: determine printer type and use correct icon */
+  gtk_printer_set_icon_name (printer, "printer");
+  
+  cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
+
+  state_msg = "";
+  loc = "";
+  desc = "";
+  job_count = 0;
+  for (attr = response->attrs; attr != NULL; attr = attr->next) 
+    {
+      if (!attr->name)
+        continue;
+
+      _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
+      _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
+      _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
+      _CUPS_MAP_ATTR_STR (attr, printer_uri, "printer-uri-supported");
+      _CUPS_MAP_ATTR_STR (attr, member_printer_uri, "member-uris");
+      _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
+      _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
+    }
+
+  /* if we got a member_printer_uri then this printer is part of a class
+     so use member_printer_uri, else user printer_uri */
+
+  if (cups_printer->printer_uri)
+    g_free (cups_printer->printer_uri);
+
+  if (member_printer_uri)
+    {
+      g_free (printer_uri);
+      cups_printer->printer_uri = member_printer_uri;
+    }
+  else
+    cups_printer->printer_uri = printer_uri;
+
+  status_changed = gtk_printer_set_job_count (printer, job_count);
+  
+  status_changed |= gtk_printer_set_location (printer, loc);
+  status_changed |= gtk_printer_set_description (printer, desc);
+  status_changed |= gtk_printer_set_state_message (printer, state_msg);
+
+#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
+  httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, 
+                   method, sizeof (method), 
+                   username, sizeof (username),
+                   hostname, sizeof (hostname),
+                  &port, 
+                   resource, sizeof (resource));
+
+#else
+  httpSeparate (cups_printer->printer_uri, 
+                method, 
+                username, 
+                hostname,
+               &port, 
+                resource);
+#endif
+
+  gethostname(uri, sizeof(uri));
+
+  if (strcasecmp(uri, hostname) == 0)
+    strcpy(hostname, "localhost");
+
+  if (cups_printer->hostname)
+    g_free (cups_printer->hostname);
+
+  cups_printer->hostname = g_strdup (hostname);
+  cups_printer->port = port;
+
+  if (status_changed)
+    g_signal_emit_by_name (GTK_PRINT_BACKEND (print_backend), "printer-status-changed", printer); 
+}
+
+static void
+cups_request_printer_info (GtkPrintBackendCups *print_backend,
+                           const gchar *printer_name)
+{
+  GError *error;
+  GtkCupsRequest *request;
+  gchar *printer_uri;
+
+  error = NULL;
+
+  request = gtk_cups_request_new (NULL,
+                                  GTK_CUPS_POST,
+                                  IPP_GET_PRINTER_ATTRIBUTES,
+                                 0,
+                                 NULL,
+                                 NULL);
+
+  printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
+                                  printer_name);
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                                   "printer-uri", NULL, printer_uri);
+
+  g_free (printer_uri);
+
+  cups_request_execute (print_backend,
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
+                        g_strdup (printer_name),
+                        (GDestroyNotify) g_free,
+                        &error);
+}
+
+
+typedef struct {
+  GtkPrintBackendCups *print_backend;
+  GtkPrintJob *job;
+  int job_id;
+  int counter;
+} CupsJobPollData;
+
+static void
+job_object_died        (gpointer user_data,
+                GObject  *where_the_object_was)
+{
+  CupsJobPollData *data = user_data;
+  data->job = NULL;
+}
+
+static void
+cups_job_poll_data_free (CupsJobPollData *data)
+{
+  if (data->job)
+    g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
+    
+  g_free (data);
+}
+
+static void
+cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
+                         GtkCupsResult *result,
+                         gpointer user_data)
+{
+  CupsJobPollData *data = user_data;
+  ipp_attribute_t *attr;
+  ipp_t *response;
+  int state;
+  gboolean done;
+
+  if (data->job == NULL)
+    {
+      cups_job_poll_data_free (data);
+      return;
+    }
+
+  data->counter++;
+  
+  response = gtk_cups_result_get_response (result);
+
+  state = 0;
+  for (attr = response->attrs; attr != NULL; attr = attr->next) 
+    {
+      if (!attr->name)
+        continue;
+      
+      _CUPS_MAP_ATTR_INT (attr, state, "job-state");
+    }
+  
+  done = FALSE;
+  switch (state)
+    {
+    case IPP_JOB_PENDING:
+    case IPP_JOB_HELD:
+    case IPP_JOB_STOPPED:
+      gtk_print_job_set_status (data->job,
+                               GTK_PRINT_STATUS_PENDING);
+      break;
+    case IPP_JOB_PROCESSING:
+      gtk_print_job_set_status (data->job,
+                               GTK_PRINT_STATUS_PRINTING);
+      break;
+    default:
+    case IPP_JOB_CANCELLED:
+    case IPP_JOB_ABORTED:
+      gtk_print_job_set_status (data->job,
+                               GTK_PRINT_STATUS_FINISHED_ABORTED);
+      done = TRUE;
+      break;
+    case 0:
+    case IPP_JOB_COMPLETED:
+      gtk_print_job_set_status (data->job,
+                               GTK_PRINT_STATUS_FINISHED);
+      done = TRUE;
+      break;
+    }
+
+  if (!done && data->job != NULL)
+    {
+      guint32 timeout;
+
+      if (data->counter < 5)
+       timeout = 100;
+      else if (data->counter < 10)
+       timeout = 500;
+      else
+       timeout = 1000;
+      
+      g_timeout_add (timeout, cups_job_info_poll_timeout, data);
+    }
+  else
+    cups_job_poll_data_free (data);    
+}
+
+static void
+cups_request_job_info (CupsJobPollData *data)
+{
+  GError *error;
+  GtkCupsRequest *request;
+  gchar *printer_uri;
+
+  
+  error = NULL;
+  request = gtk_cups_request_new (NULL,
+                                  GTK_CUPS_POST,
+                                  IPP_GET_JOB_ATTRIBUTES,
+                                 0,
+                                 NULL,
+                                 NULL);
+
+  printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                                   "job-uri", NULL, printer_uri);
+  g_free (printer_uri);
+
+  cups_request_execute (data->print_backend,
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
+                        data,
+                        NULL,
+                        &error);
+}
+
+static gboolean
+cups_job_info_poll_timeout (gpointer user_data)
+{
+  CupsJobPollData *data = user_data;
+  
+  if (data->job == NULL)
+    cups_job_poll_data_free (data);
+  else
+    cups_request_job_info (data);
+  
+  return FALSE;
+}
+
+static void
+cups_begin_polling_info (GtkPrintBackendCups *print_backend,
+                        GtkPrintJob *job,
+                        int job_id)
+{
+  CupsJobPollData *data;
+
+  data = g_new0 (CupsJobPollData, 1);
+
+  data->print_backend = print_backend;
+  data->job = job;
+  data->job_id = job_id;
+  data->counter = 0;
+
+  g_object_weak_ref (G_OBJECT (job), job_object_died, data);
+
+  cups_request_job_info (data);
+}
+
+static gint
+printer_cmp (GtkPrinter *a, GtkPrinter *b)
+{
+  const char *name_a, *name_b;
+  g_assert (GTK_IS_PRINTER (a) && GTK_IS_PRINTER (b));
+
+  name_a = gtk_printer_get_name (a);
+  name_b = gtk_printer_get_name (b);
+  if (name_a == NULL  && name_b == NULL)
+    return 0;
+  else if (name_a == NULL)
+    return G_MAXINT;
+  else if (name_b == NULL)
+    return G_MININT;
+  else
+    return g_ascii_strcasecmp (name_a, name_b);
+}
+
+static void
+printer_hash_to_sorted_active_list (const gchar *key,
+                                    gpointer value,
+                                    GList **out_list)
+{
+  GtkPrinter *printer;
+
+  printer = GTK_PRINTER (value);
+
+  if (gtk_printer_get_name (printer) == NULL)
+    return;
+
+  if (!gtk_printer_is_active (printer))
+    return;
+
+  *out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) printer_cmp);
+}
+
+static void
+printer_hash_to_sorted_active_name_list (const gchar *key,
+                                         gpointer value,
+                                         GList **out_list)
+{
+  GtkPrinter *printer;
+
+  printer = GTK_PRINTER (value);
+
+
+  if (gtk_printer_get_name (printer) == NULL)
+    return;
+
+  if (!gtk_printer_is_active (printer))
+    return;
+
+  if (gtk_printer_is_active (printer))
+    *out_list = g_list_insert_sorted (*out_list,
+                                     (char *)gtk_printer_get_name (printer),
+                                     g_str_equal);
+}
+
+static void
+mark_printer_inactive (const gchar *printer_name, 
+                       GtkPrintBackendCups *cups_backend)
+{
+  GtkPrinter *printer;
+  GHashTable *printer_hash;
+
+  printer_hash = cups_backend->printers;
+
+  printer = (GtkPrinter *) g_hash_table_lookup (printer_hash, 
+                                                printer_name);
+
+  if (printer == NULL)
+    return;
+
+  gtk_printer_set_is_active (printer, FALSE);
+
+  g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-removed", printer);
+}
+
+static void
+cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
+                              GtkCupsResult *result,
+                              gpointer user_data)
+{
+  ipp_attribute_t *attr;
+  ipp_t *response;
+  gboolean list_has_changed;
+  GList *removed_printer_checklist;
+
+  list_has_changed = FALSE;
+
+  g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
+
+  cups_backend->list_printers_pending = FALSE;
+
+  if (gtk_cups_result_is_error (result))
+    {
+      g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
+      return;
+    }
+
+  /* gether the names of the printers in the current queue
+     so we may check to see if they were removed */
+  removed_printer_checklist = NULL;
+  if (cups_backend->printers != NULL)
+    g_hash_table_foreach (cups_backend->printers,
+                          (GHFunc) printer_hash_to_sorted_active_name_list,
+                          &removed_printer_checklist);
+
+  response = gtk_cups_result_get_response (result);
+
+  attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME);
+
+  while (attr) 
+    {
+      GtkPrinterCups *cups_printer;
+      GtkPrinter *printer;
+      const gchar *printer_name;
+      GList *node;
+
+      printer_name = attr->values[0].string.text;
+      /* remove name from checklist if it was found */
+      node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) g_ascii_strcasecmp);
+      removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
+      cups_printer = (GtkPrinterCups *) g_hash_table_lookup (cups_backend->printers, 
+                                                             printer_name);
+      printer = cups_printer ? GTK_PRINTER (cups_printer) : NULL;
+
+      if (!cups_printer)
+        {
+          list_has_changed = TRUE;
+         cups_printer = gtk_printer_cups_new (attr->values[0].string.text,
+                                              GTK_PRINT_BACKEND (cups_backend));
+         printer = GTK_PRINTER (cups_printer);
+
+         if (cups_backend->default_printer != NULL &&
+             strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
+           gtk_printer_set_is_default (printer, TRUE);
+
+          g_hash_table_insert (cups_backend->printers,
+                               g_strdup (gtk_printer_get_name (printer)), 
+                               cups_printer);
+        }
+    
+      if (!gtk_printer_is_active (printer))
+        {
+         gtk_printer_set_is_active (printer, TRUE);
+         gtk_printer_set_is_new (printer, TRUE);
+          list_has_changed = TRUE;
+        }
+
+      if (gtk_printer_is_new (printer))
+        {
+           g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), 
+                                  "printer-added",
+                                  printer);
+
+         gtk_printer_set_is_new (printer, FALSE);
+        }
+
+      cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
+      
+      attr = ippFindNextAttribute (response, 
+                                   "printer-name",
+                                   IPP_TAG_NAME);
+    }
+
+    /* look at the removed printers checklist and mark any printer
+       as inactive if it is in the list, emitting a printer_removed signal */
+
+    if (removed_printer_checklist != NULL)
+      {
+        g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, cups_backend);
+        g_list_free (removed_printer_checklist);
+        list_has_changed = TRUE;
+      }
+
+    if (list_has_changed)
+       g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
+
+}
+
+static gboolean
+cups_request_printer_list (GtkPrintBackendCups *cups_backend)
+{
+  GError *error;
+  GtkCupsRequest *request;
+
+  if (cups_backend->list_printers_pending ||
+      !cups_backend->got_default_printer)
+    return TRUE;
+
+  cups_backend->list_printers_pending = TRUE;
+
+  error = NULL;
+
+  request = gtk_cups_request_new (NULL,
+                                  GTK_CUPS_POST,
+                                  CUPS_GET_PRINTERS,
+                                 0,
+                                 NULL,
+                                 NULL);
+
+  cups_request_execute (cups_backend,
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
+                       request,
+                       NULL,
+                        &error);
+
+
+  return TRUE;
+}
+
+static GList * 
+cups_get_printer_list (GtkPrintBackend *print_backend)
+{
+  GtkPrintBackendCups *cups_backend;
+  GList *result;
+
+  cups_backend = GTK_PRINT_BACKEND_CUPS (print_backend);
+
+  result = NULL;
+  if (cups_backend->printers != NULL)
+    g_hash_table_foreach (cups_backend->printers,
+                          (GHFunc) printer_hash_to_sorted_active_list,
+                          &result);
+
+  if (cups_backend->list_printers_poll == 0)
+    {
+      cups_request_printer_list (cups_backend);
+      cups_backend->list_printers_poll = g_timeout_add (3000,
+                                                        (GSourceFunc) cups_request_printer_list,
+                                                        print_backend);
+    }
+  return result;
+}
+
+typedef struct {
+  GtkPrinterCups *printer;
+  gint ppd_fd;
+  gchar *ppd_filename;
+} GetPPDData;
+
+static void
+get_ppd_data_free (GetPPDData *data)
+{
+  close (data->ppd_fd);
+  unlink (data->ppd_filename);
+  g_free (data->ppd_filename);
+  g_object_unref (data->printer);
+  g_free (data);
+}
+
+static void
+cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
+                     GtkCupsResult *result,
+                     GetPPDData *data)
+{
+  ipp_t *response;
+  GtkPrinter *printer;
+
+  printer = GTK_PRINTER (data->printer);
+  GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
+
+  if (gtk_cups_result_is_error (result))
+    {
+      g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+      return;
+    }
+
+  response = gtk_cups_result_get_response (result);
+
+  data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
+  gtk_printer_set_has_details (printer, TRUE);
+  g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
+}
+
+static void
+cups_request_ppd (GtkPrinter      *printer)
+{
+  GError *error;
+  GtkPrintBackend *print_backend;
+  GtkPrinterCups *cups_printer;
+  GtkCupsRequest *request;
+  gchar *resource;
+  http_t *http;
+  GetPPDData *data;
+  
+  cups_printer = GTK_PRINTER_CUPS (printer);
+
+  error = NULL;
+
+  http = httpConnectEncrypt(cups_printer->hostname, 
+                            cups_printer->port,
+                            cupsEncryption());
+
+  data = g_new0 (GetPPDData, 1);
+
+  data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
+                                  &data->ppd_filename, 
+                                  &error);
+
+  if (error != NULL)
+    {
+      g_warning ("%s", error->message);
+      g_error_free (error);
+      httpClose (http);
+      g_free (data);
+
+      g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+      return;
+    }
+    
+  fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
+
+  data->printer = g_object_ref (printer);
+
+  resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
+  request = gtk_cups_request_new (http,
+                                  GTK_CUPS_GET,
+                                 0,
+                                  data->ppd_fd,
+                                 cups_printer->hostname,
+                                 resource);
+
+  g_free (resource);
+  cups_printer->reading_ppd = TRUE;
+
+  print_backend = gtk_printer_get_backend (printer);
+  cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
+                        data,
+                        (GDestroyNotify)get_ppd_data_free,
+                        &error);
+}
+
+
+static void
+cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
+                                GtkCupsResult *result,
+                                gpointer user_data)
+{
+  ipp_t *response;
+  ipp_attribute_t *attr;
+
+  response = gtk_cups_result_get_response (result);
+  
+  if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
+    print_backend->default_printer = g_strdup (attr->values[0].string.text);
+
+  print_backend->got_default_printer = TRUE;
+
+  /* Make sure to kick off get_printers if we are polling it, as we could
+     have blocked this reading the default printer */
+  if (print_backend->list_printers_poll != 0)
+    cups_request_printer_list (print_backend);
+}
+
+static void
+cups_request_default_printer (GtkPrintBackendCups *print_backend)
+{
+  GError *error;
+  GtkCupsRequest *request;
+  const char *str;
+
+  error = NULL;
+
+  if ((str = getenv("LPDEST")) != NULL)
+    {
+      print_backend->default_printer = g_strdup (str);
+      print_backend->got_default_printer = TRUE;
+      return;
+    }
+  else if ((str = getenv("PRINTER")) != NULL &&
+          strcmp(str, "lp") != 0)
+    {
+      print_backend->default_printer = g_strdup (str);
+      print_backend->got_default_printer = TRUE;
+      return;
+    }
+  
+  request = gtk_cups_request_new (NULL,
+                                  GTK_CUPS_POST,
+                                  CUPS_GET_DEFAULT,
+                                 0,
+                                 NULL,
+                                 NULL);
+  
+  cups_request_execute (print_backend,
+                        request,
+                        (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
+                       g_object_ref (print_backend),
+                       g_object_unref,
+                        &error);
+}
+
+
+static void
+cups_printer_request_details (GtkPrinter *printer)
+{
+  GtkPrinterCups *cups_printer;
+
+  cups_printer = GTK_PRINTER_CUPS (printer);
+  if (!cups_printer->reading_ppd && 
+      gtk_printer_cups_get_ppd (cups_printer) == NULL)
+    cups_request_ppd (printer); 
+}
+
+static char *
+ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
+{
+  const char *encoding = NULL;
+  char *res;
+  
+  if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
+    {
+      return g_strdup (text);
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
+    {
+      encoding = "ISO-8859-1";
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
+    {
+      encoding = "ISO-8859-2";
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
+    {
+      encoding = "ISO-8859-5";
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
+    {
+      encoding = "SHIFT-JIS";
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
+    {
+      encoding = "MACINTOSH";
+    }
+  else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
+    {
+      encoding = "WINDOWS-1252";
+    }
+  else 
+    {
+      /* Fallback, try iso-8859-1... */
+      encoding = "ISO-8859-1";
+    }
+
+  res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
+
+  if (res == NULL)
+    {
+      g_warning ("unable to convert PPD text");
+      res = g_strdup ("???");
+    }
+  
+  return res;
+}
+
+/* TODO: Add more translations for common settings here */
+
+static const struct {
+  const char *keyword;
+  const char *translation;
+} cups_option_translations[] = {
+  { "Duplex", N_("Two Sided") },
+};
+
+
+static const struct {
+  const char *keyword;
+  const char *choice;
+  const char *translation;
+} cups_choice_translations[] = {
+  { "Duplex", "None", N_("One Sided") },
+  { "InputSlot", "Auto", N_("Auto Select") },
+  { "InputSlot", "AutoSelect", N_("Auto Select") },
+  { "InputSlot", "Default", N_("Printer Default") },
+  { "InputSlot", "None", N_("Printer Default") },
+  { "InputSlot", "PrinterDefault", N_("Printer Default") },
+  { "InputSlot", "Unspecified", N_("Auto Select") },
+};
+
+static const struct {
+  const char *ppd_keyword;
+  const char *name;
+} option_names[] = {
+  {"Duplex", "gtk-duplex" },
+  {"MediaType", "gtk-paper-type"},
+  {"InputSlot", "gtk-paper-source"},
+  {"OutputBin", "gtk-output-tray"},
+};
+
+/* keep sorted when changing */
+static const char *color_option_whitelist[] = {
+  "BRColorEnhancement",
+  "BRColorMatching",
+  "BRColorMatching",
+  "BRColorMode",
+  "BRGammaValue",
+  "BRImprovedGray",
+  "BlackSubstitution",
+  "ColorModel",
+  "HPCMYKInks",
+  "HPCSGraphics",
+  "HPCSImages",
+  "HPCSText",
+  "HPColorSmart",
+  "RPSBlackMode",
+  "RPSBlackOverPrint",
+  "Rcmyksimulation",
+};
+
+/* keep sorted when changing */
+static const char *color_group_whitelist[] = {
+  "ColorPage",
+  "FPColorWise1",
+  "FPColorWise2",
+  "FPColorWise3",
+  "FPColorWise4",
+  "FPColorWise5",
+  "HPColorOptionsPanel",
+};
+  
+/* keep sorted when changing */
+static const char *image_quality_option_whitelist[] = {
+  "BRDocument",
+  "BRHalfTonePattern",
+  "BRNormalPrt",
+  "BRPrintQuality",
+  "BitsPerPixel",
+  "Darkness",
+  "Dithering",
+  "EconoMode",
+  "Economode",
+  "HPEconoMode",
+  "HPEdgeControl",
+  "HPGraphicsHalftone",
+  "HPHalftone",
+  "HPLJDensity",
+  "HPPhotoHalftone",
+  "OutputMode",
+  "REt",
+  "RPSBitsPerPixel",
+  "RPSDitherType",
+  "Resolution",
+  "ScreenLock",
+  "Smoothing",
+  "TonerSaveMode",
+  "UCRGCRForImage",
+};
+
+/* keep sorted when changing */
+static const char *image_quality_group_whitelist[] = {
+  "FPImageQuality1",
+  "FPImageQuality2",
+  "FPImageQuality3",
+  "ImageQualityPage",
+};
+
+/* keep sorted when changing */
+static const char * finishing_option_whitelist[] = {
+  "BindColor",
+  "BindEdge",
+  "BindType",
+  "BindWhen",
+  "Booklet",
+  "FoldType",
+  "FoldWhen",
+  "HPStaplerOptions",
+  "Jog",
+  "Slipsheet",
+  "Sorter",
+  "StapleLocation",
+  "StapleOrientation",
+  "StapleWhen",
+  "StapleX",
+  "StapleY",
+};
+
+/* keep sorted when changing */
+static const char *finishing_group_whitelist[] = {
+  "FPFinishing1",
+  "FPFinishing2",
+  "FPFinishing3",
+  "FPFinishing4",
+  "FinishingPage",
+  "HPFinishingPanel",
+};
+
+/* keep sorted when changing */
+static const char *cups_option_blacklist[] = {
+  "Collate",
+  "Copies", 
+  "OutputOrder",
+  "PageRegion",
+  "PageSize",
+};
+
+static char *
+get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
+{
+  int i;
+  char *utf8;
+  
+  for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
+    {
+      if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
+       return g_strdup (_(cups_option_translations[i].translation));
+    }
+
+  utf8 = ppd_text_to_utf8 (ppd_file, option->text);
+
+  /* Some ppd files have spaces in the text before the colon */
+  g_strchomp (utf8);
+  
+  return utf8;
+}
+
+static char *
+get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
+{
+  int i;
+  ppd_option_t *option = choice->option;
+  const char *keyword = option->keyword;
+  
+  for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
+    {
+      if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
+         strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
+       return g_strdup (_(cups_choice_translations[i].translation));
+    }
+  return ppd_text_to_utf8 (ppd_file, choice->text);
+}
+
+static gboolean
+group_has_option (ppd_group_t *group, ppd_option_t *option)
+{
+  int i;
+
+  if (group == NULL)
+    return FALSE;
+  
+  if (group->num_options > 0 &&
+      option >= group->options && option < group->options + group->num_options)
+    return TRUE;
+  
+  for (i = 0; i < group->num_subgroups; i++)
+    {
+      if (group_has_option (&group->subgroups[i],option))
+       return TRUE;
+    }
+  return FALSE;
+}
+
+static void
+set_option_off (GtkPrinterOption *option)
+{
+  /* Any of these will do, _set only applies the value
+   * if its allowed of the option */
+  gtk_printer_option_set (option, "False");
+  gtk_printer_option_set (option, "Off");
+  gtk_printer_option_set (option, "None");
+}
+
+static gboolean
+value_is_off (const char *value)
+{
+  return  (strcasecmp (value, "None") == 0 ||
+          strcasecmp (value, "Off") == 0 ||
+          strcasecmp (value, "False") == 0);
+}
+
+static int
+available_choices (ppd_file_t *ppd,
+                  ppd_option_t *option,
+                  ppd_choice_t ***available,
+                  gboolean keep_if_only_one_option)
+{
+  ppd_option_t *other_option;
+  int i, j;
+  char *conflicts;
+  ppd_const_t *constraint;
+  const char *choice, *other_choice;
+  ppd_option_t *option1, *option2;
+  ppd_group_t *installed_options;
+  int num_conflicts;
+  gboolean all_default;
+  int add_auto;
+
+  if (available)
+    *available = NULL;
+
+  conflicts = g_new0 (char, option->num_choices);
+
+  installed_options = NULL;
+  for (i = 0; i < ppd->num_groups; i++)
+    {
+      if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
+       {
+         installed_options = &ppd->groups[i];
+         break;
+       }
+    }
+
+  for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
+    {
+      option1 = ppdFindOption (ppd, constraint->option1);
+      if (option1 == NULL)
+       continue;
+
+      option2 = ppdFindOption (ppd, constraint->option2);
+      if (option2 == NULL)
+       continue;
+
+      if (option == option1)
+       {
+         choice = constraint->choice1;
+         other_option = option2;
+         other_choice = constraint->choice2;
+       }
+      else if (option == option2)
+       {
+         choice = constraint->choice2;
+         other_option = option1;
+         other_choice = constraint->choice1;
+       }
+      else
+       continue;
+
+      /* We only care of conflicts with installed_options and
+         PageSize */
+      if (!group_has_option (installed_options, other_option) &&
+         (strcmp (other_option->keyword, "PageSize") != 0))
+       continue;
+
+      if (*other_choice == 0)
+       {
+         /* Conflict only if the installed option is not off */
+         if (value_is_off (other_option->defchoice))
+           continue;
+       }
+      /* Conflict if the installed option has the specified default */
+      else if (strcasecmp (other_choice, other_option->defchoice) != 0)
+       continue;
+
+      if (*choice == 0)
+       {
+         /* Conflict with all non-off choices */
+         for (j = 0; j < option->num_choices; j++)
+           {
+             if (!value_is_off (option->choices[j].choice))
+               conflicts[j] = 1;
+           }
+       }
+      else
+       {
+         for (j = 0; j < option->num_choices; j++)
+           {
+             if (strcasecmp (option->choices[j].choice, choice) == 0)
+               conflicts[j] = 1;
+           }
+       }
+    }
+
+  num_conflicts = 0;
+  all_default = TRUE;
+  for (j = 0; j < option->num_choices; j++)
+    {
+      if (conflicts[j])
+       num_conflicts++;
+      else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
+       all_default = FALSE;
+    }
+
+  if (all_default && !keep_if_only_one_option)
+    return 0;
+  
+  if (num_conflicts == option->num_choices)
+    return 0;
+
+
+  /* Some ppds don't have a "use printer default" option for
+     InputSlot. This means you always have to select a particular slot,
+     and you can't auto-pick source based on the paper size. To support
+     this we always add an auto option if there isn't one already. If
+     the user chooses the generated option we don't send any InputSlot
+     value when printing. The way we detect existing auto-cases is based
+     on feedback from Michael Sweet of cups fame.
+  */
+  add_auto = 0;
+  if (strcmp (option->keyword, "InputSlot") == 0)
+    {
+      gboolean found_auto = FALSE;
+      for (j = 0; j < option->num_choices; j++)
+       {
+         if (!conflicts[j])
+           {
+             if (strcmp (option->choices[j].choice, "Auto") == 0 ||
+                 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
+                 strcmp (option->choices[j].choice, "Default") == 0 ||
+                 strcmp (option->choices[j].choice, "None") == 0 ||
+                 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
+                 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
+                 option->choices[j].code == NULL ||
+                 option->choices[j].code[0] == 0)
+               {
+                 found_auto = TRUE;
+                 break;
+               }
+           }
+       }
+
+      if (!found_auto)
+       add_auto = 1;
+    }
+  
+  if (available)
+    {
+      
+      *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
+
+      i = 0;
+      for (j = 0; j < option->num_choices; j++)
+       {
+         if (!conflicts[j])
+           (*available)[i++] = &option->choices[j];
+       }
+
+      if (add_auto) 
+       (*available)[i++] = NULL;
+    }
+  
+  return option->num_choices - num_conflicts + add_auto;
+}
+
+static GtkPrinterOption *
+create_pickone_option (ppd_file_t *ppd_file,
+                      ppd_option_t *ppd_option,
+                      const char *gtk_name)
+{
+  GtkPrinterOption *option;
+  ppd_choice_t **available;
+  char *label;
+  int n_choices;
+  int i;
+
+  g_assert (ppd_option->ui == PPD_UI_PICKONE);
+  
+  option = NULL;
+
+  n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
+  if (n_choices > 0)
+    {
+      label = get_option_text (ppd_file, ppd_option);
+      option = gtk_printer_option_new (gtk_name, label,
+                                      GTK_PRINTER_OPTION_TYPE_PICKONE);
+      g_free (label);
+      
+      gtk_printer_option_allocate_choices (option, n_choices);
+      for (i = 0; i < n_choices; i++)
+       {
+         if (available[i] == NULL)
+           {
+             /* This was auto-added */
+             option->choices[i] = g_strdup ("gtk-ignore-value");
+             option->choices_display[i] = g_strdup (_("Printer Default"));
+           }
+         else
+           {
+             option->choices[i] = g_strdup (available[i]->choice);
+             option->choices_display[i] = get_choice_text (ppd_file, available[i]);
+           }
+       }
+      gtk_printer_option_set (option, ppd_option->defchoice);
+    }
+#ifdef PRINT_IGNORED_OPTIONS
+  else
+    g_warning ("Ignoring pickone %s\n", ppd_option->text);
+#endif
+  g_free (available);
+
+  return option;
+}
+
+static GtkPrinterOption *
+create_boolean_option (ppd_file_t *ppd_file,
+                      ppd_option_t *ppd_option,
+                      const char *gtk_name)
+{
+  GtkPrinterOption *option;
+  ppd_choice_t **available;
+  char *label;
+  int n_choices;
+
+  g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
+  
+  option = NULL;
+
+  n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
+  if (n_choices == 2)
+    {
+      label = get_option_text (ppd_file, ppd_option);
+      option = gtk_printer_option_new (gtk_name, label,
+                                              GTK_PRINTER_OPTION_TYPE_BOOLEAN);
+      g_free (label);
+      
+      gtk_printer_option_allocate_choices (option, 2);
+      option->choices[0] = g_strdup ("True");
+      option->choices_display[0] = g_strdup ("True");
+      option->choices[1] = g_strdup ("True");
+      option->choices_display[1] = g_strdup ("True");
+      
+      gtk_printer_option_set (option, ppd_option->defchoice);
+    }
+#ifdef PRINT_IGNORED_OPTIONS
+  else
+    g_warning ("Ignoring boolean %s\n", ppd_option->text);
+#endif
+  g_free (available);
+
+  return option;
+}
+
+static char *
+get_option_name (const char *keyword)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (option_names); i++)
+    if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
+      return g_strdup (option_names[i].name);
+
+  return g_strdup_printf ("cups-%s", keyword);
+}
+
+static int
+strptr_cmp (const void *a, const void *b)
+{
+  char **aa = (char **)a;
+  char **bb = (char **)b;
+  return strcmp (*aa, *bb);
+}
+
+
+static gboolean
+string_in_table (char *str, const char *table[], int table_len)
+{
+  return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
+}
+
+#define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
+
+static void
+handle_option (GtkPrinterOptionSet *set,
+              ppd_file_t *ppd_file,
+              ppd_option_t *ppd_option,
+              ppd_group_t *toplevel_group,
+              GtkPrintSettings *settings)
+{
+  GtkPrinterOption *option;
+  char *name;
+
+  if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
+    return;
+  
+  name = get_option_name (ppd_option->keyword);
+
+  option = NULL;
+  if (ppd_option->ui == PPD_UI_PICKONE)
+    {
+      option = create_pickone_option (ppd_file, ppd_option, name);
+    }
+  else if (ppd_option->ui == PPD_UI_BOOLEAN)
+    {
+      option = create_boolean_option (ppd_file, ppd_option, name);
+    }
+  else
+    g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
+  
+  
+  if (option)
+    {
+      if (STRING_IN_TABLE (toplevel_group->name,
+                          color_group_whitelist) ||
+         STRING_IN_TABLE (ppd_option->keyword,
+                          color_option_whitelist))
+       {
+         option->group = g_strdup ("ColorPage");
+       }
+      else if (STRING_IN_TABLE (toplevel_group->name,
+                               image_quality_group_whitelist) ||
+              STRING_IN_TABLE (ppd_option->keyword,
+                               image_quality_option_whitelist))
+       {
+         option->group = g_strdup ("ImageQualityPage");
+       }
+      else if (STRING_IN_TABLE (toplevel_group->name,
+                               finishing_group_whitelist) ||
+              STRING_IN_TABLE (ppd_option->keyword,
+                               finishing_option_whitelist))
+       {
+         option->group = g_strdup ("FinishingPage");
+       }
+      else
+       {
+         option->group = g_strdup (toplevel_group->text);
+       }
+
+      set_option_from_settings (option, settings);
+      
+      gtk_printer_option_set_add (set, option);
+    }
+  
+  g_free (name);
+}
+
+static void
+handle_group (GtkPrinterOptionSet *set,
+             ppd_file_t *ppd_file,
+             ppd_group_t *group,
+             ppd_group_t *toplevel_group,
+             GtkPrintSettings *settings)
+{
+  int i;
+
+  /* Ignore installable options */
+  if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
+    return;
+  
+  for (i = 0; i < group->num_options; i++)
+    handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
+
+  for (i = 0; i < group->num_subgroups; i++)
+    handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
+
+}
+
+static GtkPrinterOptionSet *
+cups_printer_get_options (GtkPrinter *printer,
+                         GtkPrintSettings                  *settings,
+                         GtkPageSetup                      *page_setup)
+{
+  GtkPrinterOptionSet *set;
+  GtkPrinterOption *option;
+  ppd_file_t *ppd_file;
+  int i;
+  char *print_at[] = { "now", "at", "on-hold" };
+  char *n_up[] = {"1", "2", "4", "6", "9", "16" };
+  char *prio[] = {"100", "80", "50", "30" };
+  char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
+  char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
+  char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
+
+
+  set = gtk_printer_option_set_new ();
+
+  /* Cups specific, non-ppd related settings */
+
+  option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
+                                        n_up, n_up);
+  gtk_printer_option_set (option, "1");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
+    prio_display[i] = _(prio_display[i]);
+  
+  option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
+                                        prio, prio_display);
+  gtk_printer_option_set (option, "50");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
+  gtk_printer_option_set (option, "");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
+    cover_display[i] = _(cover_display[i]);
+  
+  option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
+                                        cover, cover_display);
+  gtk_printer_option_set (option, "none");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
+                                        cover, cover_display);
+  gtk_printer_option_set (option, "none");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
+                                        print_at, print_at);
+  gtk_printer_option_set (option, "now");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+  
+  option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
+  gtk_printer_option_set (option, "");
+  set_option_from_settings (option, settings);
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+  
+  /* Printer (ppd) specific settings */
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+  if (ppd_file)
+    {
+      GtkPaperSize *paper_size;
+      ppd_option_t *option;
+      
+      ppdMarkDefaults (ppd_file);
+
+      paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+      option = ppdFindOption(ppd_file, "PageSize");
+      strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
+              PPD_MAX_NAME);
+
+      for (i = 0; i < ppd_file->num_groups; i++)
+        handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
+    }
+
+  return set;
+}
+
+
+static void
+mark_option_from_set (GtkPrinterOptionSet *set,
+                     ppd_file_t *ppd_file,
+                     ppd_option_t *ppd_option)
+{
+  GtkPrinterOption *option;
+  char *name = get_option_name (ppd_option->keyword);
+
+  option = gtk_printer_option_set_lookup (set, name);
+
+  if (option)
+    ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
+  
+  g_free (name);
+}
+
+
+static void
+mark_group_from_set (GtkPrinterOptionSet *set,
+                    ppd_file_t *ppd_file,
+                    ppd_group_t *group)
+{
+  int i;
+
+  for (i = 0; i < group->num_options; i++)
+    mark_option_from_set (set, ppd_file, &group->options[i]);
+
+  for (i = 0; i < group->num_subgroups; i++)
+    mark_group_from_set (set, ppd_file, &group->subgroups[i]);
+}
+
+static void
+set_conflicts_from_option (GtkPrinterOptionSet *set,
+                          ppd_file_t *ppd_file,
+                          ppd_option_t *ppd_option)
+{
+  GtkPrinterOption *option;
+  char *name;
+  if (ppd_option->conflicted)
+    {
+      name = get_option_name (ppd_option->keyword);
+      option = gtk_printer_option_set_lookup (set, name);
+
+      if (option)
+       gtk_printer_option_set_has_conflict (option, TRUE);
+      else
+       g_warning ("conflict for option %s ignored", ppd_option->keyword);
+      
+      g_free (name);
+    }
+}
+
+static void
+set_conflicts_from_group (GtkPrinterOptionSet *set,
+                         ppd_file_t *ppd_file,
+                         ppd_group_t *group)
+{
+  int i;
+
+  for (i = 0; i < group->num_options; i++)
+    set_conflicts_from_option (set, ppd_file, &group->options[i]);
+
+  for (i = 0; i < group->num_subgroups; i++)
+    set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
+}
+
+static gboolean
+cups_printer_mark_conflicts  (GtkPrinter          *printer,
+                             GtkPrinterOptionSet *options)
+{
+  ppd_file_t *ppd_file;
+  int num_conflicts;
+  int i;
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+
+  if (ppd_file == NULL)
+    return FALSE;
+
+  ppdMarkDefaults (ppd_file);
+
+  for (i = 0; i < ppd_file->num_groups; i++)
+    mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
+
+  num_conflicts = ppdConflicts (ppd_file);
+
+  if (num_conflicts > 0)
+    {
+      for (i = 0; i < ppd_file->num_groups; i++)
+       set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
+    }
+  return num_conflicts > 0;
+}
+
+struct OptionData {
+  GtkPrinter *printer;
+  GtkPrinterOptionSet *options;
+  GtkPrintSettings *settings;
+  ppd_file_t *ppd_file;
+};
+
+typedef struct {
+  const char *cups;
+  const char *standard;
+} NameMapping;
+
+static void
+map_settings_to_option (GtkPrinterOption *option,
+                       const NameMapping table[],
+                       int n_elements,
+                       GtkPrintSettings *settings,
+                       const char *standard_name,
+                       const char *cups_name)
+{
+  int i;
+  char *name;
+  const char *cups_value;
+  const char *standard_value;
+
+  /* If the cups-specific setting is set, always use that */
+
+  name = g_strdup_printf ("cups-%s", cups_name);
+  cups_value = gtk_print_settings_get (settings, name);
+  g_free (name);
+  
+  if (cups_value != NULL) {
+    gtk_printer_option_set (option, cups_value);
+    return;
+  }
+
+  /* Otherwise we try to convert from the general setting */
+  standard_value = gtk_print_settings_get (settings, standard_name);
+  if (standard_value == NULL)
+    return;
+
+  for (i = 0; i < n_elements; i++)
+    {
+      if (table[i].cups == NULL && table[i].standard == NULL)
+       {
+         gtk_printer_option_set (option, standard_value);
+         break;
+       }
+      else if (table[i].cups == NULL &&
+              strcmp (table[i].standard, standard_value) == 0)
+       {
+         set_option_off (option);
+         break;
+       }
+      else if (strcmp (table[i].standard, standard_value) == 0)
+       {
+         gtk_printer_option_set (option, table[i].cups);
+         break;
+       }
+    }
+}
+
+static void
+map_option_to_settings (const char *value,
+                       const NameMapping table[],
+                       int n_elements,
+                       GtkPrintSettings *settings,
+                       const char *standard_name,
+                       const char *cups_name)
+{
+  int i;
+  char *name;
+
+  for (i = 0; i < n_elements; i++)
+    {
+      if (table[i].cups == NULL && table[i].standard == NULL)
+       {
+         gtk_print_settings_set (settings,
+                                 standard_name,
+                                 value);
+         break;
+       }
+      else if (table[i].cups == NULL && table[i].standard != NULL)
+       {
+         if (value_is_off (value))
+           {
+             gtk_print_settings_set (settings,
+                                     standard_name,
+                                     table[i].standard);
+             break;
+           }
+       }
+      else if (strcmp (table[i].cups, value) == 0)
+       {
+         gtk_print_settings_set (settings,
+                                 standard_name,
+                                 table[i].standard);
+         break;
+       }
+    }
+
+  /* Always set the corresponding cups-specific setting */
+  name = g_strdup_printf ("cups-%s", cups_name);
+  gtk_print_settings_set (settings, name, value);
+  g_free (name);
+}
+
+
+static const NameMapping paper_source_map[] = {
+  { "Lower", "lower"},
+  { "Middle", "middle"},
+  { "Upper", "upper"},
+  { "Rear", "rear"},
+  { "Envelope", "envelope"},
+  { "Cassette", "cassette"},
+  { "LargeCapacity", "large-capacity"},
+  { "AnySmallFormat", "small-format"},
+  { "AnyLargeFormat", "large-format"},
+  { NULL, NULL}
+};
+
+static const NameMapping output_tray_map[] = {
+  { "Upper", "upper"},
+  { "Lower", "lower"},
+  { "Rear", "rear"},
+  { NULL, NULL}
+};
+
+static const NameMapping duplex_map[] = {
+  { "DuplexTumble", "vertical" },
+  { "DuplexNoTumble", "horizontal" },
+  { NULL, "simplex" }
+};
+
+static const NameMapping output_mode_map[] = {
+  { "Standard", "normal" },
+  { "Normal", "normal" },
+  { "Draft", "draft" },
+  { "Fast", "draft" },
+};
+
+static const NameMapping media_type_map[] = {
+  { "Transparency", "transparency"},
+  { "Standard", "stationery"},
+  { NULL, NULL}
+};
+
+static const NameMapping all_map[] = {
+  { NULL, NULL}
+};
+
+
+static void
+set_option_from_settings (GtkPrinterOption *option,
+                         GtkPrintSettings *settings)
+{
+  const char *cups_value;
+  char *value;
+  
+  if (settings == NULL)
+    return;
+
+  if (strcmp (option->name, "gtk-paper-source") == 0)
+    map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
+                            settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
+  else if (strcmp (option->name, "gtk-output-tray") == 0)
+    map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
+                           settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
+  else if (strcmp (option->name, "gtk-duplex") == 0)
+    map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
+                           settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
+  else if (strcmp (option->name, "cups-OutputMode") == 0)
+    map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
+                           settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
+  else if (strcmp (option->name, "cups-Resolution") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, option->name);
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+      else
+       {
+         int res = gtk_print_settings_get_resolution (settings);
+         if (res != 0)
+           {
+             value = g_strdup_printf ("%ddpi", res);
+             gtk_printer_option_set (option, value);
+             g_free (value);
+           }
+       }
+    }
+  else if (strcmp (option->name, "gtk-paper-type") == 0)
+    map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
+                           settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
+  else if (strcmp (option->name, "gtk-n-up") == 0)
+    {
+      map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
+                             settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
+    }
+  else if (strcmp (option->name, "gtk-billing-info") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "cups-job-billing");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (strcmp (option->name, "gtk-job-prio") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "cups-job-priority");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (strcmp (option->name, "gtk-cover-before") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "cover-before");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (strcmp (option->name, "gtk-cover-after") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "cover-after");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (strcmp (option->name, "gtk-print-time") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "print-at");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (strcmp (option->name, "gtk-print-time-text") == 0)
+    {
+      cups_value = gtk_print_settings_get (settings, "print-at-time");
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+  else if (g_str_has_prefix (option->name, "cups-"))
+    {
+      cups_value = gtk_print_settings_get (settings, option->name);
+      if (cups_value)
+       gtk_printer_option_set (option, cups_value);
+    } 
+}
+
+static void
+foreach_option_get_settings (GtkPrinterOption  *option,
+                            gpointer          user_data)
+{
+  struct OptionData *data = user_data;
+  GtkPrintSettings *settings = data->settings;
+  const char *value;
+
+  value = option->value;
+
+  if (strcmp (option->name, "gtk-paper-source") == 0)
+    map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
+                           settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
+  else if (strcmp (option->name, "gtk-output-tray") == 0)
+    map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
+                           settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
+  else if (strcmp (option->name, "gtk-duplex") == 0)
+    map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
+                           settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
+  else if (strcmp (option->name, "cups-OutputMode") == 0)
+    map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
+                           settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
+  else if (strcmp (option->name, "cups-Resolution") == 0)
+    {
+      int res = atoi (value);
+      /* TODO: What if resolution is on XXXxYYYdpi form? */
+      if (res != 0)
+       gtk_print_settings_set_resolution (settings, res);
+      gtk_print_settings_set (settings, option->name, value);
+    }
+  else if (strcmp (option->name, "gtk-paper-type") == 0)
+    map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
+                           settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
+  else if (strcmp (option->name, "gtk-n-up") == 0)
+    map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
+                           settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
+  else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
+    gtk_print_settings_set (settings, "cups-job-billing", value);
+  else if (strcmp (option->name, "gtk-job-prio") == 0)
+    gtk_print_settings_set (settings, "cups-job-priority", value);
+  else if (strcmp (option->name, "gtk-cover-before") == 0)
+    gtk_print_settings_set (settings, "cover-before", value);
+  else if (strcmp (option->name, "gtk-cover-after") == 0)
+    gtk_print_settings_set (settings, "cover-after", value);
+  else if (strcmp (option->name, "gtk-print-time") == 0)
+    gtk_print_settings_set (settings, "print-at", value);
+  else if (strcmp (option->name, "gtk-print-time-text") == 0)
+    gtk_print_settings_set (settings, "print-at-time", value);
+  else if (g_str_has_prefix (option->name, "cups-"))
+    gtk_print_settings_set (settings, option->name, value);
+}
+
+static void
+cups_printer_get_settings_from_options (GtkPrinter *printer,
+                                       GtkPrinterOptionSet *options,
+                                       GtkPrintSettings *settings)
+{
+  struct OptionData data;
+  const char *print_at, *print_at_time;
+
+  data.printer = printer;
+  data.options = options;
+  data.settings = settings;
+  data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+  if (data.ppd_file != NULL)
+    {
+      GtkPrinterOption *cover_before, *cover_after;
+      
+      gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
+
+      cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
+      cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
+      if (cover_before && cover_after)
+       {
+         char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
+         gtk_print_settings_set (settings, "cups-job-sheets", value);
+         g_free (value);
+       }
+
+      print_at = gtk_print_settings_get (settings, "print-at");
+      print_at_time = gtk_print_settings_get (settings, "print-at-time");
+      if (strcmp (print_at, "at") == 0)
+       gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
+      else if (strcmp (print_at, "on-hold") == 0)
+       gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
+    }
+}
+
+static void
+cups_printer_prepare_for_print (GtkPrinter *printer,
+                               GtkPrintJob *print_job,
+                               GtkPrintSettings *settings,
+                               GtkPageSetup *page_setup)
+{
+  GtkPageSet page_set;
+  GtkPaperSize *paper_size;
+  const char *ppd_paper_name;
+  double scale;
+
+  print_job->print_pages = gtk_print_settings_get_print_pages (settings);
+  print_job->page_ranges = NULL;
+  print_job->num_page_ranges = 0;
+  
+  if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
+    print_job->page_ranges =
+      gtk_print_settings_get_page_ranges (settings,
+                                         &print_job->num_page_ranges);
+  
+  if (gtk_print_settings_get_collate (settings))
+    gtk_print_settings_set (settings, "cups-Collate", "True");
+  print_job->collate = FALSE;
+
+  if (gtk_print_settings_get_reverse (settings))
+    gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
+  print_job->reverse = FALSE;
+
+  if (gtk_print_settings_get_num_copies (settings) > 1)
+    gtk_print_settings_set_int (settings, "cups-copies",
+                               gtk_print_settings_get_num_copies (settings));
+  print_job->num_copies = 1;
+
+  scale = gtk_print_settings_get_scale (settings);
+  print_job->scale = 1.0;
+  if (scale != 100.0)
+    print_job->scale = scale/100.0;
+
+  page_set = gtk_print_settings_get_page_set (settings);
+  if (page_set == GTK_PAGE_SET_EVEN)
+    gtk_print_settings_set (settings, "cups-page-set", "even");
+  else if (page_set == GTK_PAGE_SET_ODD)
+    gtk_print_settings_set (settings, "cups-page-set", "odd");
+  print_job->page_set = GTK_PAGE_SET_ALL;
+
+  paper_size = gtk_page_setup_get_paper_size (page_setup);
+  ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
+  if (ppd_paper_name != NULL)
+    gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
+  else
+    {
+      char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
+                                          gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
+                                          gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
+      gtk_print_settings_set (settings, "cups-PageSize", custom_name);
+      g_free (custom_name);
+    }
+
+  print_job->rotate_to_orientation = TRUE;
+}
+
+static GList *
+cups_printer_list_papers (GtkPrinter *printer)
+{
+  ppd_file_t *ppd_file;
+  ppd_size_t *size;
+  char *display_name;
+  GtkPageSetup *page_setup;
+  GtkPaperSize *paper_size;
+  ppd_option_t *option;
+  ppd_choice_t *choice;
+  GList *l;
+  int i;
+
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+  if (ppd_file == NULL)
+    return NULL;
+
+  l = NULL;
+  
+  for (i = 0; i < ppd_file->num_sizes; i++)
+    {
+      size = &ppd_file->sizes[i];
+
+      display_name = NULL;
+      option = ppdFindOption(ppd_file, "PageSize");
+      if (option)
+       {
+         choice = ppdFindChoice(option, size->name);
+         if (choice)
+           display_name = ppd_text_to_utf8 (ppd_file, choice->text);
+       }
+      if (display_name == NULL)
+       display_name = g_strdup (size->name);
+
+      page_setup = gtk_page_setup_new ();
+      paper_size = gtk_paper_size_new_from_ppd (size->name,
+                                               display_name,
+                                               size->width,
+                                               size->length);
+      gtk_page_setup_set_paper_size (page_setup, paper_size);
+      gtk_paper_size_free (paper_size);
+
+      gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
+      gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
+      gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
+      gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
+       
+      g_free (display_name);
+
+      l = g_list_prepend (l, page_setup);
+    }
+
+  return g_list_reverse (l);
+}
+
+static void
+cups_printer_get_hard_margins (GtkPrinter *printer,
+                              double     *top,
+                              double     *bottom,
+                              double     *left,
+                              double     *right)
+{
+  ppd_file_t *ppd_file;
+
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+  if (ppd_file == NULL)
+    return;
+
+  *left = ppd_file->custom_margins[0];
+  *bottom = ppd_file->custom_margins[1];
+  *right = ppd_file->custom_margins[2];
+  *top = ppd_file->custom_margins[3];
+}
diff --git a/modules/printbackends/cups/gtkprintbackendcups.h b/modules/printbackends/cups/gtkprintbackendcups.h
new file mode 100644 (file)
index 0000000..b1e1369
--- /dev/null
@@ -0,0 +1,42 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendcups.h: Default implementation of GtkPrintBackend for the Common Unix Print System (CUPS)
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_BACKEND_CUPS_H__
+#define __GTK_PRINT_BACKEND_CUPS_H__
+
+#include <glib-object.h>
+#include "gtkprintbackend.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_BACKEND_CUPS             (gtk_print_backend_cups_get_type ())
+#define GTK_PRINT_BACKEND_CUPS(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCups))
+#define GTK_IS_PRINT_BACKEND_CUPS(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_CUPS))
+
+typedef struct _GtkPrintBackendCups      GtkPrintBackendCups;
+
+GtkPrintBackend *gtk_print_backend_cups_new      (void);
+GType          gtk_print_backend_cups_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_BACKEND_CUPS_H__ */
+
+
diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c
new file mode 100644 (file)
index 0000000..c36b807
--- /dev/null
@@ -0,0 +1,125 @@
+/* GtkPrinterCupsCups
+ * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "gtkprintercups.h"
+
+static void gtk_printer_cups_init       (GtkPrinterCups      *printer);
+static void gtk_printer_cups_class_init (GtkPrinterCupsClass *class);
+static void gtk_printer_cups_finalize   (GObject             *object);
+
+static GtkPrinterClass *gtk_printer_cups_parent_class;
+static GType gtk_printer_cups_type = 0;
+
+void 
+gtk_printer_cups_register_type (GTypeModule *module)
+{
+  static const GTypeInfo object_info =
+  {
+    sizeof (GtkPrinterCupsClass),
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) gtk_printer_cups_class_init,
+    NULL,           /* class_finalize */
+    NULL,           /* class_data */
+    sizeof (GtkPrinterCups),
+    0,              /* n_preallocs */
+    (GInstanceInitFunc) gtk_printer_cups_init,
+  };
+
+ gtk_printer_cups_type = g_type_module_register_type (module,
+                                                      GTK_TYPE_PRINTER,
+                                                      "GtkPrinterCups",
+                                                      &object_info, 0);
+}
+
+GType
+gtk_printer_cups_get_type (void)
+{
+  return gtk_printer_cups_type;
+}
+
+static void
+gtk_printer_cups_class_init (GtkPrinterCupsClass *class)
+{
+  GObjectClass *object_class = (GObjectClass *) class;
+       
+  gtk_printer_cups_parent_class = g_type_class_peek_parent (class);
+
+  object_class->finalize = gtk_printer_cups_finalize;
+}
+
+static void
+gtk_printer_cups_init (GtkPrinterCups *printer)
+{
+  printer->device_uri = NULL;
+  printer->printer_uri = NULL;
+  printer->state = 0;
+  printer->hostname = NULL;
+  printer->port = 0;
+  printer->ppd_file = NULL;
+}
+
+static void
+gtk_printer_cups_finalize (GObject *object)
+{
+  g_return_if_fail (object != NULL);
+
+  GtkPrinterCups *printer = GTK_PRINTER_CUPS (object);
+
+  g_free (printer->device_uri);
+  g_free (printer->printer_uri);
+  g_free (printer->hostname);
+
+  if (printer->ppd_file)
+    ppdClose (printer->ppd_file);
+
+  if (G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize)
+    G_OBJECT_CLASS (gtk_printer_cups_parent_class)->finalize (object);
+}
+
+/**
+ * gtk_printer_cups_new:
+ *
+ * Creates a new #GtkPrinterCups.
+ *
+ * Return value: a new #GtkPrinterCups
+ *
+ * Since: 2.10
+ **/
+GtkPrinterCups *
+gtk_printer_cups_new (const char      *name,
+                     GtkPrintBackend *backend)
+{
+  GObject *result;
+  
+  result = g_object_new (GTK_TYPE_PRINTER_CUPS,
+                        "name", name,
+                        "backend", backend,
+                        "is-virtual", FALSE,
+                         NULL);
+
+  return (GtkPrinterCups *) result;
+}
+
+ppd_file_t *
+gtk_printer_cups_get_ppd (GtkPrinterCups *printer)
+{
+  return printer->ppd_file;
+}
diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h
new file mode 100644 (file)
index 0000000..5100509
--- /dev/null
@@ -0,0 +1,70 @@
+/* GtkPrinterCups
+ * Copyright (C) 2006 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_PRINTER_CUPS_H__
+#define __GTK_PRINTER_CUPS_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <cups/cups.h>
+#include <cups/ppd.h>
+
+#include "gtkprinter.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINTER_CUPS                  (gtk_printer_cups_get_type ())
+#define GTK_PRINTER_CUPS(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINTER_CUPS, GtkPrinterCups))
+#define GTK_PRINTER_CUPS_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINTER_CUPS, GtkPrinterCupsClass))
+#define GTK_IS_PRINTER_CUPS(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINTER_CUPS))
+#define GTK_IS_PRINTER_CUPS_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINTER_CUPS))
+#define GTK_PRINTER_CUPS_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINTER_CUPS, GtkPrinterCupsClass))
+
+typedef struct _GtkPrinterCups         GtkPrinterCups;
+typedef struct _GtkPrinterCupsClass     GtkPrinterCupsClass;
+typedef struct _GtkPrinterCupsPrivate   GtkPrinterCupsPrivate;
+
+struct _GtkPrinterCups
+{
+  GtkPrinter parent_instance;
+
+  gchar *device_uri;
+  gchar *printer_uri;
+  gchar *hostname;
+  gint port;
+
+  ipp_pstate_t state;
+  gboolean reading_ppd;
+  ppd_file_t *ppd_file;
+};
+
+struct _GtkPrinterCupsClass
+{
+  GtkPrinterClass parent_class;
+
+};
+
+GType                    gtk_printer_cups_get_type      (void) G_GNUC_CONST;
+void                     gtk_printer_cups_register_type (GTypeModule     *module);
+GtkPrinterCups          *gtk_printer_cups_new           (const char      *name,
+                                                        GtkPrintBackend *backend);
+ppd_file_t *             gtk_printer_cups_get_ppd       (GtkPrinterCups  *printer);
+
+G_END_DECLS
+
+#endif /* __GTK_PRINTER_CUPS_H__ */
diff --git a/modules/printbackends/lpr/Makefile.am b/modules/printbackends/lpr/Makefile.am
new file mode 100644 (file)
index 0000000..9cd83e8
--- /dev/null
@@ -0,0 +1,29 @@
+if OS_WIN32
+no_undefined = -no-undefined
+endif
+
+INCLUDES = \
+       -I$(top_srcdir)                                 \
+       -I$(top_srcdir)/gtk                             \
+       -I$(top_builddir)/gtk                           \
+       -I$(top_srcdir)/gdk                             \
+       -I$(top_builddir)/gdk                           \
+       -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED          \
+       $(GTK_DEP_CFLAGS)
+
+LDADDS = \
+       $(GTK_DEP_LIBS)                                 \
+       $(top_builddir)/gtk/$(gtktargetlib)             
+
+backenddir = $(libdir)/gtk-2.0/$(GTK_BINARY_VERSION)/printbackends
+
+backend_LTLIBRARIES = libprintbackend-lpr.la
+
+libprintbackend_lpr_la_SOURCES =       \
+       gtkprintbackendlpr.c
+
+noinst_HEADERS =                       \
+       gtkprintbackendlpr.h
+
+libprintbackend_lpr_la_LDFLAGS =  -avoid-version -module $(no_undefined)
+libprintbackend_lpr_la_LIBADD = $(LDADDS)
diff --git a/modules/printbackends/lpr/gtkprintbackendlpr.c b/modules/printbackends/lpr/gtkprintbackendlpr.c
new file mode 100644 (file)
index 0000000..4560c92
--- /dev/null
@@ -0,0 +1,562 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendlpr.c: Default implementation of GtkPrintBackend 
+ * for printing to lpr 
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include <errno.h>
+#include <cairo.h>
+#include <cairo-ps.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "gtkprintoperation.h"
+
+#include "gtkprintbackendlpr.h"
+
+#include "gtkprinter.h"
+
+typedef struct _GtkPrintBackendLprClass GtkPrintBackendLprClass;
+
+#define GTK_PRINT_BACKEND_LPR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
+#define GTK_IS_PRINT_BACKEND_LPR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_LPR))
+#define GTK_PRINT_BACKEND_LPR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
+
+#define _LPR_MAX_CHUNK_SIZE 8192
+
+static GType print_backend_lpr_type = 0;
+
+struct _GtkPrintBackendLprClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GtkPrintBackendLpr
+{
+  GObject parent_instance;
+
+  GtkPrinter *printer;
+
+  GHashTable *printers;
+};
+
+static GObjectClass *backend_parent_class;
+
+static void                 gtk_print_backend_lpr_class_init      (GtkPrintBackendLprClass *class);
+static void                 gtk_print_backend_lpr_iface_init      (GtkPrintBackendIface    *iface);
+static void                 gtk_print_backend_lpr_init            (GtkPrintBackendLpr      *impl);
+static void                 gtk_print_backend_lpr_finalize        (GObject                 *object);
+static GList *              lpr_request_printer_list              (GtkPrintBackend         *print_backend);
+static void                 lpr_printer_get_settings_from_options (GtkPrinter              *printer,
+                                                                  GtkPrinterOptionSet     *options,
+                                                                  GtkPrintSettings        *settings);
+static gboolean             lpr_printer_mark_conflicts            (GtkPrinter              *printer,
+                                                                  GtkPrinterOptionSet     *options);
+static GtkPrinterOptionSet *lpr_printer_get_options               (GtkPrinter              *printer,
+                                                                  GtkPrintSettings        *settings,
+                                                                  GtkPageSetup            *page_setup);
+static void                 lpr_printer_prepare_for_print         (GtkPrinter              *printer,
+                                                                  GtkPrintJob             *print_job,
+                                                                  GtkPrintSettings        *settings,
+                                                                  GtkPageSetup            *page_setup);
+static void                 lpr_printer_get_hard_margins          (GtkPrinter              *printer,
+                                                                  double                  *top,
+                                                                  double                  *bottom,
+                                                                  double                  *left,
+                                                                  double                  *right);
+static void                 lpr_printer_request_details           (GtkPrinter              *printer);
+static GList *              lpr_printer_list_papers               (GtkPrinter              *printer);
+
+static void
+gtk_print_backend_lpr_register_type (GTypeModule *module)
+{
+  if (!print_backend_lpr_type)
+    {
+      static const GTypeInfo print_backend_lpr_info =
+      {
+       sizeof (GtkPrintBackendLprClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) gtk_print_backend_lpr_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (GtkPrintBackendLpr),
+       0,              /* n_preallocs */
+       (GInstanceInitFunc) gtk_print_backend_lpr_init,
+      };
+
+      static const GInterfaceInfo print_backend_info =
+      {
+       (GInterfaceInitFunc) gtk_print_backend_lpr_iface_init, /* interface_init */
+       NULL,                                                 /* interface_finalize */
+       NULL                                                  /* interface_data */
+      };
+
+      print_backend_lpr_type = g_type_module_register_type (module,
+                                                             G_TYPE_OBJECT,
+                                                            "GtkPrintBackendLpr",
+                                                            &print_backend_lpr_info, 0);
+      g_type_module_add_interface (module,
+                                   print_backend_lpr_type,
+                                  GTK_TYPE_PRINT_BACKEND,
+                                  &print_backend_info);
+    }
+
+
+}
+
+G_MODULE_EXPORT void 
+pb_module_init (GTypeModule *module)
+{
+  gtk_print_backend_lpr_register_type (module);
+}
+
+G_MODULE_EXPORT void 
+pb_module_exit (void)
+{
+
+}
+  
+G_MODULE_EXPORT GtkPrintBackend * 
+pb_module_create (void)
+{
+  return gtk_print_backend_lpr_new ();
+}
+
+/*
+ * GtkPrintBackendLpr
+ */
+GType
+gtk_print_backend_lpr_get_type (void)
+{
+  return print_backend_lpr_type;
+}
+
+/**
+ * gtk_print_backend_lpr_new:
+ *
+ * Creates a new #GtkPrintBackendLpr object. #GtkPrintBackendLpr
+ * implements the #GtkPrintBackend interface with direct access to
+ * the filesystem using Unix/Linux API calls
+ *
+ * Return value: the new #GtkPrintBackendLpr object
+ **/
+GtkPrintBackend *
+gtk_print_backend_lpr_new (void)
+{
+  return g_object_new (GTK_TYPE_PRINT_BACKEND_LPR, NULL);
+}
+
+static void
+gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  backend_parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->finalize = gtk_print_backend_lpr_finalize;
+}
+
+static cairo_status_t
+_cairo_write (void *cache_fd_as_pointer,
+              const unsigned char *data,
+              unsigned int         length)
+{
+  cairo_status_t result;
+  gint cache_fd;
+  cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
+  
+  result = CAIRO_STATUS_WRITE_ERROR;
+  
+  /* write out the buffer */
+  if (write (cache_fd, data, length) != -1)
+      result = CAIRO_STATUS_SUCCESS;
+   
+  return result;
+}
+
+
+static cairo_surface_t *
+lpr_printer_create_cairo_surface (GtkPrinter *printer,
+                                  gdouble width, 
+                                  gdouble height,
+                                  gint cache_fd)
+{
+  cairo_surface_t *surface;
+  
+  surface = cairo_ps_surface_create_for_stream  (_cairo_write, GINT_TO_POINTER (cache_fd), width, height);
+
+  /* TODO: DPI from settings object? */
+  cairo_ps_surface_set_dpi (surface, 300, 300);
+
+  return surface;
+}
+
+static GtkPrinter *
+gtk_print_backend_lpr_find_printer (GtkPrintBackend *print_backend,
+                                     const gchar *printer_name)
+{
+  GtkPrintBackendLpr *lpr_print_backend;
+  GtkPrinter *printer;
+
+  lpr_print_backend = GTK_PRINT_BACKEND_LPR (print_backend);
+  
+  printer = NULL;
+  if (strcmp (gtk_printer_get_name (lpr_print_backend->printer), printer_name) == 0)
+    printer = lpr_print_backend->printer;
+
+  return printer; 
+}
+
+typedef struct {
+  GtkPrintBackend *backend;
+  GtkPrintJobCompleteFunc callback;
+  GtkPrintJob *job;
+  gpointer user_data;
+  GDestroyNotify dnotify;
+
+  gint in;
+  gint out;
+  gint err;
+
+} _PrintStreamData;
+
+static void
+lpr_print_cb (GtkPrintBackendLpr *print_backend,
+              GError *error,
+              gpointer user_data)
+{
+  _PrintStreamData *ps = (_PrintStreamData *) user_data;
+
+  if (ps->in > 0)
+    close (ps->in);
+
+  if (ps->out > 0)
+    close (ps->out);
+
+  if (ps->err > 0)
+    close (ps->err);
+
+  if (ps->callback)
+    ps->callback (ps->job, ps->user_data, error);
+
+  if (ps->dnotify)
+    ps->dnotify (ps->user_data);
+
+  gtk_print_job_set_status (ps->job,
+                           (error != NULL)?GTK_PRINT_STATUS_FINISHED_ABORTED:GTK_PRINT_STATUS_FINISHED);
+
+  if (ps->job)
+    g_object_unref (ps->job);
+  
+  g_free (ps);
+}
+
+static gboolean
+lpr_write (GIOChannel *source,
+           GIOCondition con,
+           gpointer user_data)
+{
+  gchar buf[_LPR_MAX_CHUNK_SIZE];
+  gsize bytes_read;
+  GError *error;
+  _PrintStreamData *ps = (_PrintStreamData *) user_data;
+  gint source_fd;
+
+  error = NULL;
+
+  source_fd = g_io_channel_unix_get_fd (source);
+
+  bytes_read = read (source_fd,
+                     buf,
+                     _LPR_MAX_CHUNK_SIZE);
+
+  if (bytes_read > 0)
+    {
+      if (write (ps->in, buf, bytes_read) == -1)
+        {
+          error = g_error_new (GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_INTERNAL_ERROR, 
+                           g_strerror (errno));
+        }
+    }
+  else if (bytes_read == -1)
+    {
+      error = g_error_new (GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_INTERNAL_ERROR, 
+                           g_strerror (errno));
+    }
+
+  if (bytes_read == 0 || error != NULL)
+    {
+      lpr_print_cb (GTK_PRINT_BACKEND_LPR (ps->backend), error, user_data);
+
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+#define LPR_COMMAND "lpr"
+
+static void
+gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend,
+                                   GtkPrintJob *job,
+                                   gint data_fd,
+                                   GtkPrintJobCompleteFunc callback,
+                                   gpointer user_data,
+                                   GDestroyNotify dnotify)
+{
+  GError *error;
+  GtkPrinter *printer;
+  _PrintStreamData *ps;
+  GtkPrintSettings *settings;
+  GIOChannel *send_channel;
+  gint argc;  
+  gchar **argv;
+  const char *cmd_line;
+
+  printer = gtk_print_job_get_printer (job);
+  settings = gtk_print_job_get_settings (job);
+
+  error = NULL;
+
+  cmd_line = gtk_print_settings_get (settings, "lpr-commandline");
+  if (cmd_line == NULL)
+    cmd_line = LPR_COMMAND;
+  
+  ps = g_new0 (_PrintStreamData, 1);
+  ps->callback = callback;
+  ps->user_data = user_data;
+  ps->dnotify = dnotify;
+  ps->job = g_object_ref (job);
+  ps->in = 0;
+  ps->out = 0;
+  ps->err = 0;
+
+ /* spawn lpr with pipes and pipe ps file to lpr */
+  if (!g_shell_parse_argv (cmd_line,
+                           &argc,
+                           &argv,
+                           &error))
+    {
+      lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend),
+                    error, ps);
+      return;
+    }
+
+  if (!g_spawn_async_with_pipes (NULL,
+                                 argv,
+                                 NULL,
+                                 G_SPAWN_SEARCH_PATH,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &ps->in,
+                                 &ps->out,
+                                 &ps->err,
+                                 &error))
+    {
+       lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend),
+                    error, ps);
+
+      goto out;
+
+    }
+
+  send_channel = g_io_channel_unix_new (data_fd);
+  g_io_add_watch (send_channel, 
+                  G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
+                  (GIOFunc) lpr_write,
+                  ps);
+
+ out:
+  g_strfreev (argv);
+}
+
+
+static void
+gtk_print_backend_lpr_iface_init (GtkPrintBackendIface *iface)
+{
+  iface->get_printer_list = lpr_request_printer_list;
+  iface->find_printer = gtk_print_backend_lpr_find_printer;
+  iface->print_stream = gtk_print_backend_lpr_print_stream;
+  iface->printer_request_details = lpr_printer_request_details;
+  iface->printer_create_cairo_surface = lpr_printer_create_cairo_surface;
+  iface->printer_get_options = lpr_printer_get_options;
+  iface->printer_mark_conflicts = lpr_printer_mark_conflicts;
+  iface->printer_get_settings_from_options = lpr_printer_get_settings_from_options;
+  iface->printer_prepare_for_print = lpr_printer_prepare_for_print;
+  iface->printer_list_papers = lpr_printer_list_papers;
+  iface->printer_get_hard_margins = lpr_printer_get_hard_margins;
+}
+
+static GList *
+lpr_request_printer_list (GtkPrintBackend *backend)
+{
+  GList *l;
+  GtkPrintBackendLpr *lpr_backend;
+
+  l = NULL;
+
+  lpr_backend = GTK_PRINT_BACKEND_LPR (backend);
+  
+  if (lpr_backend->printer)
+    l = g_list_append (l, lpr_backend->printer);
+
+  return l; 
+}
+
+static void
+gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend_lpr)
+{
+  GtkPrinter *printer;
+
+  printer = gtk_printer_new (_("Print to LPR"),
+                            GTK_PRINT_BACKEND (backend_lpr),
+                            TRUE); 
+  gtk_printer_set_has_details (printer, TRUE);
+  gtk_printer_set_icon_name (printer, "printer");
+  gtk_printer_set_is_active (printer, TRUE);
+  
+  backend_lpr->printer = printer;
+}
+
+static void
+gtk_print_backend_lpr_finalize (GObject *object)
+{
+  GtkPrintBackendLpr *backend_lpr;
+
+  backend_lpr = GTK_PRINT_BACKEND_LPR (object);
+
+  g_object_unref (backend_lpr->printer);
+
+  backend_parent_class->finalize (object);
+}
+
+static void
+lpr_printer_request_details (GtkPrinter *printer)
+{
+}
+
+static GtkPrinterOptionSet *
+lpr_printer_get_options (GtkPrinter *printer,
+                        GtkPrintSettings *settings,
+                        GtkPageSetup *page_setup)
+{
+  GtkPrinterOptionSet *set;
+  GtkPrinterOption *option;
+  const char *command;
+  char *n_up[] = {"1", "2", "4", "6", "9", "16" };
+
+  set = gtk_printer_option_set_new ();
+
+  option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
+                                        n_up, n_up);
+  gtk_printer_option_set (option, "1");
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  option = gtk_printer_option_new ("gtk-main-page-custom-input", _("Command Line"), GTK_PRINTER_OPTION_TYPE_STRING);
+  option->group = g_strdup ("GtkPrintDialogExtention");
+  if (settings != NULL &&
+      (command = gtk_print_settings_get (settings, "lpr-commandline"))!= NULL)
+    gtk_printer_option_set (option, command);
+  else
+    gtk_printer_option_set (option, LPR_COMMAND);
+  gtk_printer_option_set_add (set, option);
+    
+  return set;
+}
+
+
+static gboolean
+lpr_printer_mark_conflicts  (GtkPrinter          *printer,
+                            GtkPrinterOptionSet *options)
+{
+  return FALSE;
+}
+
+static void
+lpr_printer_get_settings_from_options (GtkPrinter *printer,
+                                      GtkPrinterOptionSet *options,
+                                      GtkPrintSettings *settings)
+{
+  GtkPrinterOption *option;
+
+  option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
+  gtk_print_settings_set (settings, "lpr-commandline", option->value);
+}
+
+static void
+lpr_printer_prepare_for_print (GtkPrinter *printer,
+                              GtkPrintJob *print_job,
+                              GtkPrintSettings *settings,
+                              GtkPageSetup *page_setup)
+{
+  double scale;
+
+  print_job->print_pages = gtk_print_settings_get_print_pages (settings);
+  print_job->page_ranges = NULL;
+  print_job->num_page_ranges = 0;
+  
+  if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
+    print_job->page_ranges =
+      gtk_print_settings_get_page_ranges (settings,
+                                         &print_job->num_page_ranges);
+  
+  print_job->collate = gtk_print_settings_get_collate (settings);
+  print_job->reverse = gtk_print_settings_get_reverse (settings);
+  print_job->num_copies = gtk_print_settings_get_num_copies (settings);
+
+  scale = gtk_print_settings_get_scale (settings);
+  if (scale != 100.0)
+    print_job->scale = scale/100.0;
+
+  print_job->page_set = gtk_print_settings_get_page_set (settings);
+  print_job->rotate_to_orientation = TRUE;
+}
+
+static void
+lpr_printer_get_hard_margins (GtkPrinter *printer,
+                              double *top,
+                              double *bottom,
+                              double *left,
+                              double *right)
+{
+  *top = 0;
+  *bottom = 0;
+  *left = 0;
+  *right = 0;
+}
+
+static GList *
+lpr_printer_list_papers (GtkPrinter *printer)
+{
+  return NULL;
+}
diff --git a/modules/printbackends/lpr/gtkprintbackendlpr.h b/modules/printbackends/lpr/gtkprintbackendlpr.h
new file mode 100644 (file)
index 0000000..7a7f79a
--- /dev/null
@@ -0,0 +1,43 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendlpr.h: Default implementation of GtkPrintBackend 
+ * for printing to lpr 
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_BACKEND_LPR_H__
+#define __GTK_PRINT_BACKEND_LPR_H__
+
+#include <glib-object.h>
+#include "gtkprintbackend.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_BACKEND_LPR            (gtk_print_backend_lpr_get_type ())
+#define GTK_PRINT_BACKEND_LPR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLpr))
+#define GTK_IS_PRINT_BACKEND_LPR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_LPR))
+
+typedef struct _GtkPrintBackendLpr      GtkPrintBackendLpr;
+
+GtkPrintBackend *gtk_print_backend_lpr_new      (void);
+GType          gtk_print_backend_lpr_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_BACKEND_LPR_H__ */
+
+
diff --git a/modules/printbackends/pdf/Makefile.am b/modules/printbackends/pdf/Makefile.am
new file mode 100644 (file)
index 0000000..57be1fc
--- /dev/null
@@ -0,0 +1,29 @@
+if OS_WIN32
+no_undefined = -no-undefined
+endif
+
+INCLUDES = \
+       -I$(top_srcdir)                                 \
+       -I$(top_srcdir)/gtk                             \
+       -I$(top_builddir)/gtk                           \
+       -I$(top_srcdir)/gdk                             \
+       -I$(top_builddir)/gdk                           \
+       -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED          \
+       $(GTK_DEP_CFLAGS)
+
+LDADDS = \
+       $(GTK_DEP_LIBS)                                 \
+       $(top_builddir)/gtk/$(gtktargetlib)             
+
+backenddir = $(libdir)/gtk-2.0/$(GTK_BINARY_VERSION)/printbackends
+
+backend_LTLIBRARIES = libprintbackend-pdf.la
+
+libprintbackend_pdf_la_SOURCES =       \
+       gtkprintbackendpdf.c
+
+noinst_HEADERS =                       \
+       gtkprintbackendpdf.h
+
+libprintbackend_pdf_la_LDFLAGS =  -avoid-version -module $(no_undefined)
+libprintbackend_pdf_la_LIBADD = $(LDADDS)
diff --git a/modules/printbackends/pdf/gtkprintbackendpdf.c b/modules/printbackends/pdf/gtkprintbackendpdf.c
new file mode 100644 (file)
index 0000000..e746f92
--- /dev/null
@@ -0,0 +1,530 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendpdf.c: Default implementation of GtkPrintBackend 
+ * for printing to PDF files
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include <errno.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "gtkprintoperation.h"
+
+#include "gtkprintbackend.h"
+#include "gtkprintbackendpdf.h"
+
+#include "gtkprinter.h"
+
+typedef struct _GtkPrintBackendPdfClass GtkPrintBackendPdfClass;
+
+#define GTK_PRINT_BACKEND_PDF_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_PDF, GtkPrintBackendPdfClass))
+#define GTK_IS_PRINT_BACKEND_PDF_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_PDF))
+#define GTK_PRINT_BACKEND_PDF_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_PDF, GtkPrintBackendPdfClass))
+
+#define _PDF_MAX_CHUNK_SIZE 8192
+
+static GType print_backend_pdf_type = 0;
+
+struct _GtkPrintBackendPdfClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GtkPrintBackendPdf
+{
+  GObject parent_instance;
+
+  GtkPrinter *printer;
+
+  GHashTable *printers;
+};
+
+static GObjectClass *backend_parent_class;
+
+static void                 gtk_print_backend_pdf_class_init      (GtkPrintBackendPdfClass *class);
+static void                 gtk_print_backend_pdf_iface_init      (GtkPrintBackendIface    *iface);
+static void                 gtk_print_backend_pdf_init            (GtkPrintBackendPdf      *impl);
+static void                 gtk_print_backend_pdf_finalize        (GObject                 *object);
+static GList *              pdf_request_printer_list              (GtkPrintBackend         *print_backend);
+static void                 pdf_printer_get_settings_from_options (GtkPrinter              *printer,
+                                                                  GtkPrinterOptionSet     *options,
+                                                                  GtkPrintSettings        *settings);
+static gboolean             pdf_printer_mark_conflicts            (GtkPrinter              *printer,
+                                                                  GtkPrinterOptionSet     *options);
+static GtkPrinterOptionSet *pdf_printer_get_options               (GtkPrinter              *printer,
+                                                                  GtkPrintSettings        *settings,
+                                                                  GtkPageSetup            *page_setup);
+static void                 pdf_printer_prepare_for_print         (GtkPrinter              *printer,
+                                                                  GtkPrintJob             *print_job,
+                                                                  GtkPrintSettings        *settings,
+                                                                  GtkPageSetup            *page_setup);
+static void                 pdf_printer_get_hard_margins          (GtkPrinter              *printer,
+                                                                  double                  *top,
+                                                                  double                  *bottom,
+                                                                  double                  *left,
+                                                                  double                  *right);
+static void                 pdf_printer_request_details           (GtkPrinter              *printer);
+static GList *              pdf_printer_list_papers               (GtkPrinter              *printer);
+
+static void
+gtk_print_backend_pdf_register_type (GTypeModule *module)
+{
+  if (!print_backend_pdf_type)
+    {
+      static const GTypeInfo print_backend_pdf_info =
+      {
+       sizeof (GtkPrintBackendPdfClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) gtk_print_backend_pdf_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (GtkPrintBackendPdf),
+       0,              /* n_preallocs */
+       (GInstanceInitFunc) gtk_print_backend_pdf_init,
+      };
+
+      static const GInterfaceInfo print_backend_info =
+      {
+       (GInterfaceInitFunc) gtk_print_backend_pdf_iface_init, /* interface_init */
+       NULL,                                                 /* interface_finalize */
+       NULL                                                  /* interface_data */
+      };
+
+      print_backend_pdf_type = g_type_module_register_type (module,
+                                                             G_TYPE_OBJECT,
+                                                            "GtkPrintBackendPdf",
+                                                            &print_backend_pdf_info, 0);
+      g_type_module_add_interface (module,
+                                   print_backend_pdf_type,
+                                  GTK_TYPE_PRINT_BACKEND,
+                                  &print_backend_info);
+    }
+
+
+}
+
+G_MODULE_EXPORT void 
+pb_module_init (GTypeModule *module)
+{
+  gtk_print_backend_pdf_register_type (module);
+}
+
+G_MODULE_EXPORT void 
+pb_module_exit (void)
+{
+
+}
+  
+G_MODULE_EXPORT GtkPrintBackend * 
+pb_module_create (void)
+{
+  return gtk_print_backend_pdf_new ();
+}
+
+/*
+ * GtkPrintBackendPdf
+ */
+GType
+gtk_print_backend_pdf_get_type (void)
+{
+  return print_backend_pdf_type;
+}
+
+/**
+ * gtk_print_backend_pdf_new:
+ *
+ * Creates a new #GtkPrintBackendPdf object. #GtkPrintBackendPdf
+ * implements the #GtkPrintBackend interface with direct access to
+ * the filesystem using Unix/Linux API calls
+ *
+ * Return value: the new #GtkPrintBackendPdf object
+ **/
+GtkPrintBackend *
+gtk_print_backend_pdf_new (void)
+{
+  return g_object_new (GTK_TYPE_PRINT_BACKEND_PDF, NULL);
+}
+
+static void
+gtk_print_backend_pdf_class_init (GtkPrintBackendPdfClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  backend_parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->finalize = gtk_print_backend_pdf_finalize;
+}
+
+static cairo_status_t
+_cairo_write (void *cache_fd_as_pointer,
+              const unsigned char *data,
+              unsigned int         length)
+{
+  cairo_status_t result;
+  gint cache_fd;
+  cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
+  
+  result = CAIRO_STATUS_WRITE_ERROR;
+  
+  /* write out the buffer */
+  if (write (cache_fd, data, length) != -1)
+      result = CAIRO_STATUS_SUCCESS;
+   
+  return result;
+}
+
+
+static cairo_surface_t *
+pdf_printer_create_cairo_surface (GtkPrinter *printer,
+                                  gdouble width, 
+                                  gdouble height,
+                                  gint cache_fd)
+{
+  cairo_surface_t *surface;
+  
+  surface = cairo_pdf_surface_create_for_stream  (_cairo_write, GINT_TO_POINTER (cache_fd), width, height);
+
+  /* TODO: DPI from settings object? */
+  cairo_pdf_surface_set_dpi (surface, 300, 300);
+
+  return surface;
+}
+
+static GtkPrinter *
+gtk_print_backend_pdf_find_printer (GtkPrintBackend *print_backend,
+                                     const gchar *printer_name)
+{
+  GtkPrintBackendPdf *pdf_print_backend;
+  GtkPrinter *printer;
+
+  pdf_print_backend = GTK_PRINT_BACKEND_PDF (print_backend);
+  
+  printer = NULL;
+  if (strcmp (gtk_printer_get_name (pdf_print_backend->printer), printer_name) == 0)
+    printer = pdf_print_backend->printer;
+
+  return printer; 
+}
+
+typedef struct {
+  GtkPrintBackend *backend;
+  GtkPrintJobCompleteFunc callback;
+  GtkPrintJob *job;
+  gint target_fd;
+  gpointer user_data;
+  GDestroyNotify dnotify;
+} _PrintStreamData;
+
+static void
+pdf_print_cb (GtkPrintBackendPdf *print_backend,
+              GError *error,
+              gpointer user_data)
+{
+  _PrintStreamData *ps = (_PrintStreamData *) user_data;
+
+  if (ps->target_fd > 0)
+    close (ps->target_fd);
+
+  if (ps->callback)
+    ps->callback (ps->job, ps->user_data, error);
+
+  if (ps->dnotify)
+    ps->dnotify (ps->user_data);
+
+  gtk_print_job_set_status (ps->job,
+                           (error != NULL)?GTK_PRINT_STATUS_FINISHED_ABORTED:GTK_PRINT_STATUS_FINISHED);
+
+  if (ps->job)
+    g_object_unref (ps->job);
+  g_free (ps);
+}
+
+static gboolean
+pdf_write (GIOChannel *source,
+           GIOCondition con,
+           gpointer user_data)
+{
+  gchar buf[_PDF_MAX_CHUNK_SIZE];
+  gsize bytes_read;
+  GError *error;
+  _PrintStreamData *ps = (_PrintStreamData *) user_data;
+  gint source_fd;
+
+  error = NULL;
+
+  source_fd = g_io_channel_unix_get_fd (source);
+
+  bytes_read = read (source_fd,
+                     buf,
+                     _PDF_MAX_CHUNK_SIZE);
+
+   
+
+  if (bytes_read > 0)
+    {
+      if (write (ps->target_fd, buf, bytes_read) == -1)
+        {
+          error = g_error_new (GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_INTERNAL_ERROR, 
+                           g_strerror (errno));
+        }
+    }
+  else if (bytes_read == -1)
+    {
+      error = g_error_new (GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_INTERNAL_ERROR, 
+                           g_strerror (errno));
+    }
+
+  if (bytes_read == 0 || error != NULL)
+    {
+      pdf_print_cb (GTK_PRINT_BACKEND_PDF (ps->backend), error, user_data);
+
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+gtk_print_backend_pdf_print_stream (GtkPrintBackend *print_backend,
+                                   GtkPrintJob *job,
+                                   gint data_fd,
+                                   GtkPrintJobCompleteFunc callback,
+                                   gpointer user_data,
+                                   GDestroyNotify dnotify)
+{
+  GError *error;
+  GtkPrinter *printer;
+  _PrintStreamData *ps;
+  GtkPrintSettings *settings;
+  GIOChannel *save_channel;  
+  const char *filename;
+
+  printer = gtk_print_job_get_printer (job);
+  settings = gtk_print_job_get_settings (job);
+
+  error = NULL;
+
+  filename = gtk_print_settings_get (settings, "pdf-filename");
+  if (filename == NULL)
+    filename = "output.pdf";
+  
+  ps = g_new0 (_PrintStreamData, 1);
+  ps->callback = callback;
+  ps->user_data = user_data;
+  ps->job = g_object_ref (job);
+
+  ps->target_fd = creat (filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+  ps->backend = print_backend;
+
+  if (ps->target_fd == -1)
+    {
+      error = g_error_new (GTK_PRINT_ERROR,
+                           GTK_PRINT_ERROR_INTERNAL_ERROR, 
+                           g_strerror (errno));
+
+      pdf_print_cb (GTK_PRINT_BACKEND_PDF (print_backend),
+                    error,
+                    ps);
+
+      return;
+    }
+  
+  save_channel = g_io_channel_unix_new (data_fd);
+
+  g_io_add_watch (save_channel, 
+                  G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
+                  (GIOFunc) pdf_write,
+                  ps);
+}
+
+
+static void
+gtk_print_backend_pdf_iface_init (GtkPrintBackendIface *iface)
+{
+  iface->get_printer_list = pdf_request_printer_list;
+  iface->find_printer = gtk_print_backend_pdf_find_printer;
+  iface->print_stream = gtk_print_backend_pdf_print_stream;
+  iface->printer_request_details = pdf_printer_request_details;
+  iface->printer_create_cairo_surface = pdf_printer_create_cairo_surface;
+  iface->printer_get_options = pdf_printer_get_options;
+  iface->printer_mark_conflicts = pdf_printer_mark_conflicts;
+  iface->printer_get_settings_from_options = pdf_printer_get_settings_from_options;
+  iface->printer_prepare_for_print = pdf_printer_prepare_for_print;
+  iface->printer_list_papers = pdf_printer_list_papers;
+  iface->printer_get_hard_margins = pdf_printer_get_hard_margins;
+}
+
+static GList *
+pdf_request_printer_list (GtkPrintBackend *backend)
+{
+  GList *l;
+  GtkPrintBackendPdf *pdf_backend;
+
+  l = NULL;
+
+  pdf_backend = GTK_PRINT_BACKEND_PDF (backend);
+  
+  if (pdf_backend->printer)
+    l = g_list_append (l, pdf_backend->printer);
+
+  return l; 
+}
+
+static void
+gtk_print_backend_pdf_init (GtkPrintBackendPdf *backend_pdf)
+{
+  GtkPrinter *printer;
+  
+  backend_pdf->printer = gtk_printer_new (_("Print to PDF"),
+                                         GTK_PRINT_BACKEND (backend_pdf),
+                                         TRUE); 
+
+  printer = backend_pdf->printer;
+  gtk_printer_set_has_details (printer, TRUE);
+  gtk_printer_set_icon_name (printer, "floppy");
+  gtk_printer_set_is_active (printer, TRUE);
+}
+
+static void
+gtk_print_backend_pdf_finalize (GObject *object)
+{
+  GtkPrintBackendPdf *backend_pdf;
+
+  backend_pdf = GTK_PRINT_BACKEND_PDF (object);
+
+  g_object_unref (backend_pdf->printer);
+
+  backend_parent_class->finalize (object);
+}
+
+static void
+pdf_printer_request_details (GtkPrinter *printer)
+{
+}
+
+static GtkPrinterOptionSet *
+pdf_printer_get_options (GtkPrinter *printer,
+                        GtkPrintSettings *settings,
+                        GtkPageSetup *page_setup)
+{
+  GtkPrinterOptionSet *set;
+  GtkPrinterOption *option;
+  const char *filename;
+  char *n_up[] = {"1" };
+
+  set = gtk_printer_option_set_new ();
+
+  option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
+  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
+                                        n_up, n_up);
+  gtk_printer_option_set (option, "1");
+  gtk_printer_option_set_add (set, option);
+  g_object_unref (option);
+
+  option = gtk_printer_option_new ("gtk-main-page-custom-input", _("File"), GTK_PRINTER_OPTION_TYPE_FILESAVE);
+  gtk_printer_option_set (option, "output.pdf");
+  option->group = g_strdup ("GtkPrintDialogExtention");
+  gtk_printer_option_set_add (set, option);
+
+  if (settings != NULL &&
+      (filename = gtk_print_settings_get (settings, "pdf-filename"))!= NULL)
+    gtk_printer_option_set (option, filename);
+
+  return set;
+}
+
+
+static gboolean
+pdf_printer_mark_conflicts  (GtkPrinter          *printer,
+                            GtkPrinterOptionSet *options)
+{
+  return FALSE;
+}
+
+static void
+pdf_printer_get_settings_from_options (GtkPrinter *printer,
+                                      GtkPrinterOptionSet *options,
+                                      GtkPrintSettings *settings)
+{
+  GtkPrinterOption *option;
+
+  option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
+  gtk_print_settings_set (settings, "pdf-filename", option->value);
+}
+
+static void
+pdf_printer_prepare_for_print (GtkPrinter *printer,
+                              GtkPrintJob *print_job,
+                              GtkPrintSettings *settings,
+                              GtkPageSetup *page_setup)
+{
+  double scale;
+
+  print_job->print_pages = gtk_print_settings_get_print_pages (settings);
+  print_job->page_ranges = NULL;
+  print_job->num_page_ranges = 0;
+  
+  if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
+    print_job->page_ranges =
+      gtk_print_settings_get_page_ranges (settings,
+                                         &print_job->num_page_ranges);
+  
+  print_job->collate = gtk_print_settings_get_collate (settings);
+  print_job->reverse = gtk_print_settings_get_reverse (settings);
+  print_job->num_copies = gtk_print_settings_get_num_copies (settings);
+
+  scale = gtk_print_settings_get_scale (settings);
+  if (scale != 100.0)
+    print_job->scale = scale/100.0;
+
+  print_job->page_set = gtk_print_settings_get_page_set (settings);
+  print_job->rotate_to_orientation = TRUE;
+}
+
+static void
+pdf_printer_get_hard_margins (GtkPrinter *printer,
+                              double *top,
+                              double *bottom,
+                              double *left,
+                              double *right)
+{
+  *top = 0;
+  *bottom = 0;
+  *left = 0;
+  *right = 0;
+}
+
+static GList *
+pdf_printer_list_papers (GtkPrinter *printer)
+{
+  return NULL;
+}
diff --git a/modules/printbackends/pdf/gtkprintbackendpdf.h b/modules/printbackends/pdf/gtkprintbackendpdf.h
new file mode 100644 (file)
index 0000000..f122ac9
--- /dev/null
@@ -0,0 +1,43 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintbackendpdf.h: Default implementation of GtkPrintBackend 
+ * for printing to a PDF 
+ * Copyright (C) 2003, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_BACKEND_PDF_H__
+#define __GTK_PRINT_BACKEND_PDF_H__
+
+#include <glib-object.h>
+#include "gtkprintbackend.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_BACKEND_PDF            (gtk_print_backend_pdf_get_type ())
+#define GTK_PRINT_BACKEND_PDF(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_PDF, GtkPrintBackendPdf))
+#define GTK_IS_PRINT_BACKEND_PDF(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_PDF))
+
+typedef struct _GtkPrintBackendPdf      GtkPrintBackendPdf;
+
+GtkPrintBackend *gtk_print_backend_pdf_new      (void);
+GType          gtk_print_backend_pdf_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GTK_PRINT_BACKEND_PDF_H__ */
+
+
index 53a6cc1591c702cfaf0b544ca3068f4234320d88..0c443fbd8c110f98e80b1c0795aa221afeae7ae7 100644 (file)
@@ -58,3 +58,4 @@ testtreesort
 testtreeview
 testxinerama
 treestoretest
+print-editor
index db204ce804b4382b2af3fd3a879845046ec0d122..94a5980fa2f016cea3bb17a024c2ffa311ac86f9 100644 (file)
@@ -30,6 +30,7 @@ noinst_PROGRAMS =                     \
        autotestfilechooser             \
        floatingtest                    \
        simple                          \
+       print-editor                    \
        testaccel                       \
        testassistant                   \
        testcairo                       \
@@ -82,6 +83,7 @@ noinst_PROGRAMS =                     \
 autotestfilechooser_DEPENDENCIES = $(TEST_DEPS)
 simple_DEPENDENCIES = $(TEST_DEPS)
 floatingtest_DEPENDENCIES = $(TEST_DEPS)
+print_editor_DEPENDENCIES = $(TEST_DEPS)
 testicontheme_DEPENDENCIES = $(TEST_DEPS)
 testiconview_DEPENDENCIES = $(TEST_DEPS)
 testaccel_DEPENDENCIES = $(TEST_DEPS)
@@ -128,6 +130,7 @@ testactions_DEPENDENCIES = $(TEST_DEPS)
 autotestfilechooser_LDADD = $(LDADDS)
 simple_LDADD = $(LDADDS)
 floatingtest_LDADD = $(LDADDS)
+print_editor_LDADD = $(LDADDS)
 testaccel_LDADD = $(LDADDS)
 testassistant_LDADD = $(LDADDS)
 testcairo_LDADD = $(LDADDS)
diff --git a/tests/print-editor.c b/tests/print-editor.c
new file mode 100644 (file)
index 0000000..7b78ac5
--- /dev/null
@@ -0,0 +1,682 @@
+#include <pango/pangocairo.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkprintoperation.h>
+
+static GtkWidget *main_window;
+static char *filename = NULL;
+static GtkPageSetup *page_setup = NULL;
+static GtkPrintSettings *settings = NULL;
+static gboolean file_changed = FALSE;
+static GtkTextBuffer *buffer;
+static GtkWidget *statusbar;
+static GList *active_prints = NULL;
+
+static void
+update_title (void)
+{
+  char *basename;
+  char *title;
+  
+  if (filename == NULL)
+    basename = g_strdup ("Untitled");
+  else
+    basename = g_path_get_basename (filename);
+
+  title = g_strdup_printf ("Simple Editor with printing - %s", basename);
+  g_free (basename);
+  
+  gtk_window_set_title (GTK_WINDOW (main_window), title);
+  g_free (title);
+}
+
+static void
+update_statusbar (void)
+{
+  gchar *msg;
+  gint row, col;
+  GtkTextIter iter;
+  const char *print_str;
+
+  gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 0);
+  
+  gtk_text_buffer_get_iter_at_mark (buffer,
+                                    &iter,
+                                    gtk_text_buffer_get_insert (buffer));
+
+  row = gtk_text_iter_get_line (&iter);
+  col = gtk_text_iter_get_line_offset (&iter);
+
+  print_str = "";
+  if (active_prints)
+    {
+      GtkPrintOperation *op = active_prints->data;
+      print_str = gtk_print_operation_get_status_string (op);
+    }
+  
+  msg = g_strdup_printf ("%d, %d%s %s",
+                         row, col,
+                        file_changed?" - Modified":"",
+                        print_str);
+
+  gtk_statusbar_push (GTK_STATUSBAR (statusbar), 0, msg);
+
+  g_free (msg);
+}
+
+static void
+update_ui (void)
+{
+  update_title ();
+  update_statusbar ();
+}
+
+static char *
+get_text (void)
+{
+  GtkTextIter start, end;
+
+  gtk_text_buffer_get_start_iter (buffer, &start);
+  gtk_text_buffer_get_end_iter (buffer, &end);
+  return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+}
+
+static void
+set_text (const char *text, gsize len)
+{
+  gtk_text_buffer_set_text (buffer, text, len);
+  file_changed = FALSE;
+  update_ui ();
+}
+
+static void
+do_new (GtkAction *action)
+{
+  g_free (filename);
+  filename = NULL;
+  set_text ("", 0);
+}
+
+static void
+load_file (const char *open_filename)
+{
+  GtkWidget *error_dialog;
+  char *contents;
+  GError *error;
+  gsize len;
+  
+  error_dialog = NULL;
+  error = NULL;
+  if (g_file_get_contents (open_filename, &contents, &len, &error))
+    {
+      if (g_utf8_validate (contents, len, NULL))
+       {
+         filename = g_strdup (open_filename);
+         set_text (contents, len);
+         g_free (contents);
+       }
+      else
+       {
+         error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
+                                                GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_CLOSE,
+                                                "Error loading file %s:\n%s",
+                                                open_filename,
+                                                "Not valid utf8");
+       }
+    }
+  else
+    {
+      error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
+                                            GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_MESSAGE_ERROR,
+                                            GTK_BUTTONS_CLOSE,
+                                            "Error loading file %s:\n%s",
+                                            open_filename,
+                                            error->message);
+      
+      g_error_free (error);
+    }
+  if (error_dialog)
+    {
+      g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+      gtk_widget_show (error_dialog);
+    }
+}
+
+static void
+do_open (GtkAction *action)
+{
+  GtkWidget *dialog;
+  gint response;
+  char *open_filename;
+  
+  dialog = gtk_file_chooser_dialog_new ("Select file",
+                                       GTK_WINDOW (main_window),
+                                       GTK_FILE_CHOOSER_ACTION_OPEN,
+                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                       GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+                                       NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if (response == GTK_RESPONSE_OK)
+    {
+      open_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+      load_file (open_filename);
+      g_free (open_filename);
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+static void
+save_file (const char *save_filename)
+{
+  char *text = get_text ();
+  GtkWidget *error_dialog;
+  GError *error;
+
+  error = NULL;
+  if (g_file_set_contents (save_filename,
+                          text, -1, &error))
+    {
+      if (save_filename != filename)
+       {
+         g_free (filename);
+         filename = g_strdup (save_filename);
+       }
+      file_changed = FALSE;
+      update_ui ();
+    }
+  else
+    {
+      error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
+                                            GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_MESSAGE_ERROR,
+                                            GTK_BUTTONS_CLOSE,
+                                            "Error saving to file %s:\n%s",
+                                            filename,
+                                            error->message);
+      
+      g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+      gtk_widget_show (error_dialog);
+      
+      g_error_free (error);
+    }
+}
+
+static void
+do_save_as (GtkAction *action)
+{
+  GtkWidget *dialog;
+  gint response;
+  char *save_filename;
+  
+  dialog = gtk_file_chooser_dialog_new ("Select file",
+                                       GTK_WINDOW (main_window),
+                                       GTK_FILE_CHOOSER_ACTION_SAVE,
+                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                       GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+                                       NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if (response == GTK_RESPONSE_OK)
+    {
+      save_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+      save_file (save_filename);
+      g_free (save_filename);
+    }
+  
+  gtk_widget_destroy (dialog);
+}
+
+static void
+do_save (GtkAction *action)
+{
+  if (filename == NULL)
+    do_save_as (action);
+  else
+    save_file (filename);
+}
+
+typedef struct {
+  char *text;
+  PangoLayout *layout;
+  GList *page_breaks;
+} PrintData;
+
+static void
+begin_print (GtkPrintOperation *operation,
+            GtkPrintContext *context,
+            PrintData *print_data)
+{
+  PangoFontDescription *desc;
+  PangoLayoutLine *layout_line;
+  double width, height;
+  double page_height;
+  GList *page_breaks;
+  int num_lines;
+  int line;
+
+  width = gtk_print_context_get_width (context);
+  height = gtk_print_context_get_height (context);
+
+  print_data->layout = gtk_print_context_create_layout (context);
+
+  desc = pango_font_description_from_string ("Sans 12");
+  pango_layout_set_font_description (print_data->layout, desc);
+  pango_font_description_free (desc);
+
+  pango_layout_set_width (print_data->layout, width * PANGO_SCALE);
+  
+  pango_layout_set_text (print_data->layout, print_data->text, -1);
+
+  num_lines = pango_layout_get_line_count (print_data->layout);
+
+  page_breaks = NULL;
+  page_height = 0;
+
+  for (line = 0; line < num_lines; line++)
+    {
+      PangoRectangle ink_rect, logical_rect;
+      double line_height;
+      
+      layout_line = pango_layout_get_line (print_data->layout, line);
+      pango_layout_line_get_extents (layout_line, &ink_rect, &logical_rect);
+
+      line_height = logical_rect.height / 1024.0;
+
+      if (page_height + line_height > height)
+       {
+         page_breaks = g_list_prepend (page_breaks, GINT_TO_POINTER (line));
+         page_height = 0;
+       }
+
+      page_height += line_height;
+    }
+
+  page_breaks = g_list_reverse (page_breaks);
+  gtk_print_operation_set_nr_of_pages (operation, g_list_length (page_breaks) + 1);
+  
+  print_data->page_breaks = page_breaks;
+  
+}
+
+static void
+draw_page (GtkPrintOperation *operation,
+          GtkPrintContext *context,
+          int page_nr,
+          PrintData *print_data)
+{
+  cairo_t *cr;
+  GList *pagebreak;
+  int start, end, i;
+  PangoLayoutIter *iter;
+  double start_pos;
+  if (page_nr == 0)
+    start = 0;
+  else
+    {
+      pagebreak = g_list_nth (print_data->page_breaks, page_nr - 1);
+      start = GPOINTER_TO_INT (pagebreak->data);
+    }
+
+  pagebreak = g_list_nth (print_data->page_breaks, page_nr);
+  if (pagebreak == NULL)
+    end = pango_layout_get_line_count (print_data->layout);
+  else
+    end = GPOINTER_TO_INT (pagebreak->data);
+    
+  cr = gtk_print_context_get_cairo (context);
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  
+  i = 0;
+  start_pos = 0;
+  iter = pango_layout_get_iter (print_data->layout);
+  do
+    {
+      PangoRectangle   logical_rect;
+      PangoLayoutLine *line;
+      int              baseline;
+
+      if (i >= start)
+       {
+         line = pango_layout_iter_get_line (iter);
+
+         pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+         baseline = pango_layout_iter_get_baseline (iter);
+         
+         if (i == start)
+           start_pos = logical_rect.y / 1024.0;
+         
+         cairo_move_to (cr, logical_rect.x / 1024.0, baseline / 1024.0 - start_pos);
+         
+         pango_cairo_show_layout_line  (cr, line);
+       }
+      i++;
+    }
+  while (i < end &&
+        pango_layout_iter_next_line (iter));
+}
+
+static void
+do_page_setup (GtkAction *action)
+{
+  GtkPageSetup *new_page_setup;
+
+  if (settings == NULL)
+    settings = gtk_print_settings_new ();
+  
+  new_page_setup = gtk_print_run_page_setup_dialog (GTK_WINDOW (main_window),
+                                                   page_setup, settings);
+
+  if (page_setup)
+    g_object_unref (page_setup);
+  
+  page_setup = new_page_setup;
+}
+
+static void
+status_changed_cb (GtkPrintOperation *op,
+                  gpointer user_data)
+{
+  if (gtk_print_operation_is_finished (op))
+    {
+      active_prints = g_list_remove (active_prints, op);
+      g_object_unref (op);
+    }
+  update_statusbar ();
+}
+
+static void
+do_print (GtkAction *action)
+{
+  GtkWidget *error_dialog;
+  GtkPrintOperation *print;
+  PrintData print_data;
+  GtkPrintOperationResult res;
+  GError *error;
+
+  print_data.text = get_text ();
+
+  print = gtk_print_operation_new ();
+
+  
+  if (settings != NULL)
+    gtk_print_operation_set_print_settings (print, settings);
+
+  if (page_setup != NULL)
+    gtk_print_operation_set_default_page_setup (print, page_setup);
+  
+  g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), &print_data);
+  g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), &print_data);
+
+  error = NULL;
+  res = gtk_print_operation_run (print, GTK_WINDOW (main_window), &error);
+
+  if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
+    {
+      error_dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
+                                            GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_MESSAGE_ERROR,
+                                            GTK_BUTTONS_CLOSE,
+                                            "Error printing file:\n%s",
+                                            error->message);
+      g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+      gtk_widget_show (error_dialog);
+      g_error_free (error);
+    }
+  else if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
+    {
+      if (settings != NULL)
+       g_object_unref (settings);
+      settings = g_object_ref (gtk_print_operation_get_print_settings (print));
+    }
+
+  if (!gtk_print_operation_is_finished (print))
+    {
+      g_object_ref (print);
+      active_prints = g_list_append (active_prints, print);
+      update_statusbar ();
+      
+      /* This ref is unref:ed when we get the final state change */
+      g_signal_connect (print, "status_changed",
+                       G_CALLBACK (status_changed_cb), NULL);
+    }
+  
+  g_object_unref (print);
+}
+
+static void
+do_about (GtkAction *action)
+{
+  const gchar *authors[] = {
+    "Alexander Larsson",
+    NULL
+  };
+  gtk_show_about_dialog (GTK_WINDOW (main_window),
+                        "name", "print test editor",
+                        "version", "0.1",
+                        "copyright", "(C) Red Hat, Inc",
+                        "comments", "Program to demonstrate GTK+ printing.",
+                        "authors", authors,
+                        NULL);
+}
+
+static void
+do_quit (GtkAction *action)
+{
+  gtk_main_quit ();
+}
+
+static GtkActionEntry entries[] = {
+  { "FileMenu", NULL, "_File" },               /* name, stock id, label */
+  { "HelpMenu", NULL, "_Help" },               /* name, stock id, label */
+  { "New", GTK_STOCK_NEW,                      /* name, stock id */
+    "_New", "<control>N",                      /* label, accelerator */
+    "Create a new file",                       /* tooltip */ 
+    G_CALLBACK (do_new) },      
+  { "Open", GTK_STOCK_OPEN,                    /* name, stock id */
+    "_Open","<control>O",                      /* label, accelerator */     
+    "Open a file",                             /* tooltip */
+    G_CALLBACK (do_open) }, 
+  { "Save", GTK_STOCK_SAVE,                    /* name, stock id */
+    "_Save","<control>S",                      /* label, accelerator */     
+    "Save current file",                       /* tooltip */
+    G_CALLBACK (do_save) },
+  { "SaveAs", GTK_STOCK_SAVE,                  /* name, stock id */
+    "Save _As...", NULL,                       /* label, accelerator */     
+    "Save to a file",                          /* tooltip */
+    G_CALLBACK (do_save_as) },
+  { "Quit", GTK_STOCK_QUIT,                    /* name, stock id */
+    "_Quit", "<control>Q",                     /* label, accelerator */     
+    "Quit",                                    /* tooltip */
+    G_CALLBACK (do_quit) },
+  { "About", NULL,                             /* name, stock id */
+    "_About", "<control>A",                    /* label, accelerator */     
+    "About",                                   /* tooltip */  
+    G_CALLBACK (do_about) },
+  { "PageSetup", NULL,                         /* name, stock id */
+    "Page _Setup", NULL,                       /* label, accelerator */     
+    "Set up the page",                         /* tooltip */
+    G_CALLBACK (do_page_setup) },
+  { "Print", GTK_STOCK_PRINT,                  /* name, stock id */
+     NULL, NULL,                               /* label, accelerator */     
+    "Print the document",                      /* tooltip */
+    G_CALLBACK (do_print) },
+};
+static guint n_entries = G_N_ELEMENTS (entries);
+
+static const gchar *ui_info = 
+"<ui>"
+"  <menubar name='MenuBar'>"
+"    <menu action='FileMenu'>"
+"      <menuitem action='New'/>"
+"      <menuitem action='Open'/>"
+"      <menuitem action='Save'/>"
+"      <menuitem action='SaveAs'/>"
+"      <menuitem action='PageSetup'/>"
+"      <menuitem action='Print'/>"
+"      <separator/>"
+"      <menuitem action='Quit'/>"
+"    </menu>"
+"    <menu action='HelpMenu'>"
+"      <menuitem action='About'/>"
+"    </menu>"
+"  </menubar>"
+"</ui>";
+
+static void
+buffer_changed_callback (GtkTextBuffer *buffer)
+{
+  file_changed = TRUE;
+  update_statusbar ();
+}
+
+static void
+mark_set_callback (GtkTextBuffer     *buffer,
+                   const GtkTextIter *new_location,
+                   GtkTextMark       *mark,
+                   gpointer           data)
+{
+  update_statusbar ();
+}
+
+static void
+update_resize_grip (GtkWidget           *widget,
+                   GdkEventWindowState *event,
+                   GtkStatusbar        *statusbar)
+{
+  if (event->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED | 
+                            GDK_WINDOW_STATE_FULLSCREEN))
+    {
+      gboolean maximized;
+
+      maximized = event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED | 
+                                            GDK_WINDOW_STATE_FULLSCREEN);
+      gtk_statusbar_set_has_resize_grip (statusbar, !maximized);
+    }
+}
+
+static void
+create_window (void)
+{
+  GtkWidget *bar;
+  GtkWidget *table;
+  GtkWidget *contents;
+  GtkUIManager *ui;
+  GtkWidget *sw;
+  GtkActionGroup *actions;
+  GError *error;
+  
+  main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+  gtk_window_set_default_size (GTK_WINDOW (main_window),
+                              400, 600);
+  
+  g_signal_connect (main_window, "delete-event",
+                   G_CALLBACK (gtk_main_quit), NULL);
+  
+  actions = gtk_action_group_new ("Actions");
+  gtk_action_group_add_actions (actions, entries, n_entries, NULL);
+  
+  ui = gtk_ui_manager_new ();
+  gtk_ui_manager_insert_action_group (ui, actions, 0);
+  gtk_window_add_accel_group (GTK_WINDOW (main_window), 
+                             gtk_ui_manager_get_accel_group (ui));
+  gtk_container_set_border_width (GTK_CONTAINER (main_window), 0);
+
+  error = NULL;
+  if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
+    {
+      g_message ("building menus failed: %s", error->message);
+      g_error_free (error);
+    }
+
+  table = gtk_table_new (1, 3, FALSE);
+  gtk_container_add (GTK_CONTAINER (main_window), table);
+
+  bar = gtk_ui_manager_get_widget (ui, "/MenuBar");
+  gtk_widget_show (bar);
+  gtk_table_attach (GTK_TABLE (table),
+                   bar, 
+                   /* X direction */          /* Y direction */
+                   0, 1,                      0, 1,
+                   GTK_EXPAND | GTK_FILL,     0,
+                   0,                         0);
+
+  /* Create document  */
+  sw = gtk_scrolled_window_new (NULL, NULL);
+
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+                                      GTK_SHADOW_IN);
+  
+  gtk_table_attach (GTK_TABLE (table),
+                   sw,
+                   /* X direction */       /* Y direction */
+                   0, 1,                   1, 2,
+                   GTK_EXPAND | GTK_FILL,  GTK_EXPAND | GTK_FILL,
+                   0,                      0);
+  
+  contents = gtk_text_view_new ();
+  gtk_widget_grab_focus (contents);
+      
+  gtk_container_add (GTK_CONTAINER (sw),
+                    contents);
+  
+  /* Create statusbar */
+  
+  statusbar = gtk_statusbar_new ();
+  gtk_table_attach (GTK_TABLE (table),
+                   statusbar,
+                   /* X direction */       /* Y direction */
+                   0, 1,                   2, 3,
+                   GTK_EXPAND | GTK_FILL,  0,
+                   0,                      0);
+
+  /* Show text widget info in the statusbar */
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
+  
+  g_signal_connect_object (buffer,
+                          "changed",
+                          G_CALLBACK (buffer_changed_callback),
+                          NULL,
+                          0);
+  
+  g_signal_connect_object (buffer,
+                          "mark_set", /* cursor moved */
+                          G_CALLBACK (mark_set_callback),
+                          NULL,
+                          0);
+  
+  g_signal_connect_object (main_window, 
+                          "window_state_event", 
+                          G_CALLBACK (update_resize_grip),
+                          statusbar,
+                          0);
+  
+  update_ui ();
+  
+  gtk_widget_show_all (main_window);
+}
+
+int
+main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  create_window ();
+
+  if (argc == 2)
+    load_file (argv[1]);
+  
+  gtk_main ();
+  return 0;
+}