diff options
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 @@ -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 Binary files differnew file mode 100644 index 000000000..7f79a2c8b --- /dev/null +++ b/docs/reference/gtk/images/pagesetupdialog.png diff --git a/docs/reference/gtk/images/printdialog.png b/docs/reference/gtk/images/printdialog.png Binary files differnew file mode 100644 index 000000000..7645b7023 --- /dev/null +++ b/docs/reference/gtk/images/printdialog.png 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; +} @@ -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, ¤t_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 Binary files differnew file mode 100644 index 000000000..b2aa37cec --- /dev/null +++ b/gtk/stock-icons/24/gtk-orientation-landscape.png diff --git a/gtk/stock-icons/24/gtk-orientation-portrait.png b/gtk/stock-icons/24/gtk-orientation-portrait.png Binary files differnew file mode 100644 index 000000000..ed1918480 --- /dev/null +++ b/gtk/stock-icons/24/gtk-orientation-portrait.png diff --git a/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png b/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png Binary files differnew file mode 100644 index 000000000..6ada5b4ce --- /dev/null +++ b/gtk/stock-icons/24/gtk-orientation-reverse-landscape.png 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; +} |