summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore1
-rw-r--r--ChangeLog77
-rw-r--r--ChangeLog.pre-2-1077
-rw-r--r--Makefile.am3
-rw-r--r--configure.in56
-rw-r--r--docs/reference/ChangeLog20
-rw-r--r--docs/reference/gtk/Makefile.am6
-rw-r--r--docs/reference/gtk/gtk-docs.sgml22
-rw-r--r--docs/reference/gtk/gtk-sections.txt330
-rw-r--r--docs/reference/gtk/gtk.types9
-rw-r--r--docs/reference/gtk/images/pagesetupdialog.pngbin0 -> 19758 bytes
-rw-r--r--docs/reference/gtk/images/printdialog.pngbin0 -> 30969 bytes
-rw-r--r--docs/reference/gtk/tmpl/gtkpagesetup.sgml251
-rw-r--r--docs/reference/gtk/tmpl/gtkpagesetupunixdialog.sgml80
-rw-r--r--docs/reference/gtk/tmpl/gtkpapersize.sgml275
-rw-r--r--docs/reference/gtk/tmpl/gtkprintcontext.sgml175
-rw-r--r--docs/reference/gtk/tmpl/gtkprinter.sgml163
-rw-r--r--docs/reference/gtk/tmpl/gtkprintjob.sgml159
-rw-r--r--docs/reference/gtk/tmpl/gtkprintoperation.sgml321
-rw-r--r--docs/reference/gtk/tmpl/gtkprintsettings.sgml697
-rw-r--r--docs/reference/gtk/tmpl/gtkprintunixdialog.sgml86
-rw-r--r--docs/reference/gtk/visual_index.xml6
-rw-r--r--docs/tools/widgets.c41
-rw-r--r--gdk/directfb/Makefile.am9
-rw-r--r--gdk/gdk.symbols6
-rw-r--r--gdk/win32/gdkevents-win32.c25
-rw-r--r--gdk/win32/gdkwin32.h1
-rw-r--r--gtk+-unix-print-2.0.pc.in14
-rw-r--r--gtk/Makefile.am90
-rw-r--r--gtk/gen-paper-names.c238
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtk.symbols299
-rw-r--r--gtk/gtkenums.h40
-rw-r--r--gtk/gtkiconfactory.c3
-rw-r--r--gtk/gtkmarshalers.list2
-rw-r--r--gtk/gtkpagesetup.c288
-rw-r--r--gtk/gtkpagesetup.h85
-rw-r--r--gtk/gtkpagesetupunixdialog.c2016
-rw-r--r--gtk/gtkpagesetupunixdialog.h73
-rw-r--r--gtk/gtkpapersize.c551
-rw-r--r--gtk/gtkpapersize.h88
-rw-r--r--gtk/gtkprint-win32.c111
-rw-r--r--gtk/gtkprint-win32.h60
-rw-r--r--gtk/gtkprintbackend.c379
-rw-r--r--gtk/gtkprintbackend.h152
-rw-r--r--gtk/gtkprintcontext.c406
-rw-r--r--gtk/gtkprintcontext.h57
-rw-r--r--gtk/gtkprinter-private.h64
-rw-r--r--gtk/gtkprinter.c587
-rw-r--r--gtk/gtkprinter.h86
-rw-r--r--gtk/gtkprinteroption.c219
-rw-r--r--gtk/gtkprinteroption.h113
-rw-r--r--gtk/gtkprinteroptionset.c205
-rw-r--r--gtk/gtkprinteroptionset.h96
-rw-r--r--gtk/gtkprinteroptionwidget.c617
-rw-r--r--gtk/gtkprinteroptionwidget.h64
-rw-r--r--gtk/gtkprintjob.c472
-rw-r--r--gtk/gtkprintjob.h106
-rw-r--r--gtk/gtkprintoperation-private.h87
-rw-r--r--gtk/gtkprintoperation-unix.c243
-rw-r--r--gtk/gtkprintoperation-win32.c1598
-rw-r--r--gtk/gtkprintoperation.c1153
-rw-r--r--gtk/gtkprintoperation.h144
-rw-r--r--gtk/gtkprintsettings.c1230
-rw-r--r--gtk/gtkprintsettings.h196
-rw-r--r--gtk/gtkprintunixdialog.c2577
-rw-r--r--gtk/gtkprintunixdialog.h81
-rw-r--r--gtk/gtkstock.h3
-rw-r--r--gtk/paper_names.c192
-rw-r--r--gtk/paper_names_offsets.c712
-rw-r--r--gtk/stock-icons/24/gtk-orientation-landscape.pngbin0 -> 864 bytes
-rw-r--r--gtk/stock-icons/24/gtk-orientation-portrait.pngbin0 -> 835 bytes
-rw-r--r--gtk/stock-icons/24/gtk-orientation-reverse-landscape.pngbin0 -> 839 bytes
-rw-r--r--modules/Makefile.am7
-rw-r--r--modules/printbackends/Makefile.am7
-rw-r--r--modules/printbackends/cups/Makefile.am34
-rw-r--r--modules/printbackends/cups/gtkcupsutils.c922
-rw-r--r--modules/printbackends/cups/gtkcupsutils.h125
-rw-r--r--modules/printbackends/cups/gtkprintbackendcups.c2629
-rw-r--r--modules/printbackends/cups/gtkprintbackendcups.h42
-rw-r--r--modules/printbackends/cups/gtkprintercups.c125
-rw-r--r--modules/printbackends/cups/gtkprintercups.h70
-rw-r--r--modules/printbackends/lpr/Makefile.am29
-rw-r--r--modules/printbackends/lpr/gtkprintbackendlpr.c562
-rw-r--r--modules/printbackends/lpr/gtkprintbackendlpr.h43
-rw-r--r--modules/printbackends/pdf/Makefile.am29
-rw-r--r--modules/printbackends/pdf/gtkprintbackendpdf.c530
-rw-r--r--modules/printbackends/pdf/gtkprintbackendpdf.h43
-rw-r--r--tests/.cvsignore1
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/print-editor.c682
91 files changed, 24551 insertions, 26 deletions
diff --git a/.cvsignore b/.cvsignore
index d6f89153d..c7f3e710c 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -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
diff --git a/ChangeLog b/ChangeLog
index 44a141a62..ae97511c5 100644
--- 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)
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 44a141a62..ae97511c5 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -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)
diff --git a/Makefile.am b/Makefile.am
index b012a4754..094efcced 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/configure.in b/configure.in
index 5014d7c78..83b44fe75 100644
--- a/configure.in
+++ b/configure.in
@@ -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>], [
@@ -1500,6 +1536,21 @@ 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
diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog
index d6259339e..66e5ef428 100644
--- a/docs/reference/ChangeLog
+++ b/docs/reference/ChangeLog
@@ -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.
diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am
index 4ceaa7088..3dc2b9b7d 100644
--- a/docs/reference/gtk/Makefile.am
+++ b/docs/reference/gtk/Makefile.am
@@ -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 \
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml
index 794769b17..370a6dbaf 100644
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@ -84,6 +84,15 @@
<!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;
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 5b4defd22..48e832e89 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -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>
diff --git a/docs/reference/gtk/gtk.types b/docs/reference/gtk/gtk.types
index 9650289c7..89be3ba80 100644
--- a/docs/reference/gtk/gtk.types
+++ b/docs/reference/gtk/gtk.types
@@ -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
index 000000000..7f79a2c8b
--- /dev/null
+++ b/docs/reference/gtk/images/pagesetupdialog.png
Binary files differ
diff --git a/docs/reference/gtk/images/printdialog.png b/docs/reference/gtk/images/printdialog.png
new file mode 100644
index 000000000..7645b7023
--- /dev/null
+++ b/docs/reference/gtk/images/printdialog.png
Binary files differ
diff --git a/docs/reference/gtk/tmpl/gtkpagesetup.sgml b/docs/reference/gtk/tmpl/gtkpagesetup.sgml
new file mode 100644
index 000000000..1a15fb8d6
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkpagesetup.sgml
@@ -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
index 000000000..c98752ab1
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkpagesetupunixdialog.sgml
@@ -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
index 000000000..4298c4efc
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkpapersize.sgml
@@ -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
index 000000000..26a2651da
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprintcontext.sgml
@@ -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
index 000000000..36f0da697
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprinter.sgml
@@ -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
index 000000000..1d94ddc42
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprintjob.sgml
@@ -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
index 000000000..00e26dd40
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprintoperation.sgml
@@ -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
index 000000000..b9d9a4f99
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprintsettings.sgml
@@ -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
index 000000000..f27d5da92
--- /dev/null
+++ b/docs/reference/gtk/tmpl/gtkprintunixdialog.sgml
@@ -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:
+
+
diff --git a/docs/reference/gtk/visual_index.xml b/docs/reference/gtk/visual_index.xml
index ef3cc6b56..c6dc17eab 100644
--- a/docs/reference/gtk/visual_index.xml
+++ b/docs/reference/gtk/visual_index.xml
@@ -50,6 +50,12 @@
<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>
diff --git a/docs/tools/widgets.c b/docs/tools/widgets.c
index 4d822610b..2675632b6 100644
--- a/docs/tools/widgets.c
+++ b/docs/tools/widgets.c
@@ -1,3 +1,5 @@
+#include <gtk/gtkprintunixdialog.h>
+#include <gtk/gtkpagesetupunixdialog.h>
#include <gdk/gdkkeysyms.h>
#include <X11/Xatom.h>
#include <gdkx.h>
@@ -667,6 +669,43 @@ create_filesel (void)
}
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)
{
GtkWidget *widget, *menu;
@@ -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;
}
diff --git a/gdk/directfb/Makefile.am b/gdk/directfb/Makefile.am
index 7046e9a0c..97a2498da 100644
--- a/gdk/directfb/Makefile.am
+++ b/gdk/directfb/Makefile.am
@@ -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
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
index 908c549c6..84c1a7d96 100644
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@ -1111,6 +1111,12 @@ gdk_win32_drawable_get_handle
#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
gdk_win32_hdc_release
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index f241943cb..3683bc3a5 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -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)
{
diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h
index 37e6cbc76..1e79ce94c 100644
--- a/gdk/win32/gdkwin32.h
+++ b/gdk/win32/gdkwin32.h
@@ -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
index 000000000..b70351270
--- /dev/null
+++ b/gtk+-unix-print-2.0.pc.in
@@ -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
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 1a9f19a19..17cf8583a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -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
index 000000000..ef9aebfb3
--- /dev/null
+++ b/gtk/gen-paper-names.c
@@ -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;
+}
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 2575238e7..f4f927eda 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -132,6 +132,7 @@
#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>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 0ff5fa8ca..bdeff31b5 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -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
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index e87ec53e0..1c483de62 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -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__ */
diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
index cc8911de4..c64d3c0e4 100644
--- a/gtk/gtkiconfactory.c
+++ b/gtk/gtkiconfactory.c
@@ -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);
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 9d948c7c4..e081da60d 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -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
index 000000000..8406a28e8
--- /dev/null
+++ b/gtk/gtkpagesetup.c
@@ -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
index 000000000..db617a2c7
--- /dev/null
+++ b/gtk/gtkpagesetup.h
@@ -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
index 000000000..0815f17a4
--- /dev/null
+++ b/gtk/gtkpagesetupunixdialog.c
@@ -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
index 000000000..efd68413c
--- /dev/null
+++ b/gtk/gtkpagesetupunixdialog.h
@@ -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
index 000000000..7dfeb9019
--- /dev/null
+++ b/gtk/gtkpapersize.c
@@ -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
index 000000000..094d2aeee
--- /dev/null
+++ b/gtk/gtkpapersize.h
@@ -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
index 000000000..69b508a6e
--- /dev/null
+++ b/gtk/gtkprint-win32.c
@@ -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
index 000000000..643834937
--- /dev/null
+++ b/gtk/gtkprint-win32.h
@@ -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
index 000000000..32e6596d0
--- /dev/null
+++ b/gtk/gtkprintbackend.c
@@ -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
index 000000000..940ab49bc
--- /dev/null
+++ b/gtk/gtkprintbackend.h
@@ -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
index 000000000..8525ec8f2
--- /dev/null
+++ b/gtk/gtkprintcontext.c
@@ -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
index 000000000..30a66b9bf
--- /dev/null
+++ b/gtk/gtkprintcontext.h
@@ -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
index 000000000..49663c0da
--- /dev/null
+++ b/gtk/gtkprinter-private.h
@@ -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
index 000000000..db166a684
--- /dev/null
+++ b/gtk/gtkprinter.c
@@ -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
index 000000000..285605f1e
--- /dev/null
+++ b/gtk/gtkprinter.h
@@ -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
index 000000000..7aee3820a
--- /dev/null
+++ b/gtk/gtkprinteroption.c
@@ -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
index 000000000..bb3acfbb7
--- /dev/null
+++ b/gtk/gtkprinteroption.h
@@ -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
index 000000000..eb84a3448
--- /dev/null
+++ b/gtk/gtkprinteroptionset.c
@@ -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
index 000000000..226390928
--- /dev/null
+++ b/gtk/gtkprinteroptionset.h
@@ -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
index 000000000..71c294325
--- /dev/null
+++ b/gtk/gtkprinteroptionwidget.c
@@ -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
index 000000000..70ea1557c
--- /dev/null
+++ b/gtk/gtkprinteroptionwidget.h
@@ -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
index 000000000..3abffaa07
--- /dev/null
+++ b/gtk/gtkprintjob.c
@@ -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
index 000000000..a5116c999
--- /dev/null
+++ b/gtk/gtkprintjob.h
@@ -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
index 000000000..5109e9cce
--- /dev/null
+++ b/gtk/gtkprintoperation-private.h
@@ -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
index 000000000..936bc521a
--- /dev/null
+++ b/gtk/gtkprintoperation-unix.c
@@ -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
index 000000000..7f441abc7
--- /dev/null
+++ b/gtk/gtkprintoperation-win32.c
@@ -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
index 000000000..07f2e9203
--- /dev/null
+++ b/gtk/gtkprintoperation.c
@@ -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
index 000000000..f6a1f3df0
--- /dev/null
+++ b/gtk/gtkprintoperation.h
@@ -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
index 000000000..80c0c9913
--- /dev/null
+++ b/gtk/gtkprintsettings.c
@@ -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
index 000000000..3c5a74845
--- /dev/null
+++ b/gtk/gtkprintsettings.h
@@ -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
index 000000000..e7fc66089
--- /dev/null
+++ b/gtk/gtkprintunixdialog.c
@@ -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
index 000000000..26f1feebe
--- /dev/null
+++ b/gtk/gtkprintunixdialog.h
@@ -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__ */
diff --git a/gtk/gtkstock.h b/gtk/gtkstock.h
index 7babd59e9..b0359f50a 100644
--- a/gtk/gtkstock.h
+++ b/gtk/gtkstock.h
@@ -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
index 000000000..c2850d30d
--- /dev/null
+++ b/gtk/paper_names.c
@@ -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
index 000000000..de6ba27b9
--- /dev/null
+++ b/gtk/paper_names_offsets.c
@@ -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
index 000000000..b2aa37cec
--- /dev/null
+++ b/gtk/stock-icons/24/gtk-orientation-landscape.png
Binary files 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
index 000000000..ed1918480
--- /dev/null
+++ b/gtk/stock-icons/24/gtk-orientation-portrait.png
Binary files 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
index 000000000..6ada5b4ce
--- /dev/null
+++ b/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png
Binary files differ
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 10e4875ad..41dfbb447 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -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
index 000000000..91a7b5d01
--- /dev/null
+++ b/modules/printbackends/Makefile.am
@@ -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
index 000000000..017459825
--- /dev/null
+++ b/modules/printbackends/cups/Makefile.am
@@ -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
index 000000000..458e1c421
--- /dev/null
+++ b/modules/printbackends/cups/gtkcupsutils.c
@@ -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
index 000000000..f49cd2e9b
--- /dev/null
+++ b/modules/printbackends/cups/gtkcupsutils.h
@@ -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
index 000000000..79922a567
--- /dev/null
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -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
index 000000000..b1e136970
--- /dev/null
+++ b/modules/printbackends/cups/gtkprintbackendcups.h
@@ -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
index 000000000..c36b8077e
--- /dev/null
+++ b/modules/printbackends/cups/gtkprintercups.c
@@ -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
index 000000000..510050918
--- /dev/null
+++ b/modules/printbackends/cups/gtkprintercups.h
@@ -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
index 000000000..9cd83e81f
--- /dev/null
+++ b/modules/printbackends/lpr/Makefile.am
@@ -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
index 000000000..4560c92a2
--- /dev/null
+++ b/modules/printbackends/lpr/gtkprintbackendlpr.c
@@ -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
index 000000000..7a7f79a6f
--- /dev/null
+++ b/modules/printbackends/lpr/gtkprintbackendlpr.h
@@ -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
index 000000000..57be1fc31
--- /dev/null
+++ b/modules/printbackends/pdf/Makefile.am
@@ -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
index 000000000..e746f92d4
--- /dev/null
+++ b/modules/printbackends/pdf/gtkprintbackendpdf.c
@@ -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
index 000000000..f122ac92f
--- /dev/null
+++ b/modules/printbackends/pdf/gtkprintbackendpdf.h
@@ -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__ */
+
+
diff --git a/tests/.cvsignore b/tests/.cvsignore
index 53a6cc159..0c443fbd8 100644
--- a/tests/.cvsignore
+++ b/tests/.cvsignore
@@ -58,3 +58,4 @@ testtreesort
testtreeview
testxinerama
treestoretest
+print-editor
diff --git a/tests/Makefile.am b/tests/Makefile.am
index db204ce80..94a5980fa 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 000000000..7b78ac5a2
--- /dev/null
+++ b/tests/print-editor.c
@@ -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;
+}