X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=modules%2Fprintbackends%2Ffile%2Fgtkprintbackendfile.c;h=fdb36b6dbc75237c6ebf8d0d940493cd612ce0ef;hb=01a3345c06e4c9dea4454e30f6751bdae3dd9a4e;hp=b1a40dd0c24ad00734dc0934f414e072a0b25442;hpb=919cdba486e502c99386bf3dc8465a068f938345;p=~andy%2Fgtk diff --git a/modules/printbackends/file/gtkprintbackendfile.c b/modules/printbackends/file/gtkprintbackendfile.c index b1a40dd0c..fdb36b6db 100644 --- a/modules/printbackends/file/gtkprintbackendfile.c +++ b/modules/printbackends/file/gtkprintbackendfile.c @@ -1,5 +1,5 @@ /* GTK - The GIMP Toolkit - * gtkprintbackendpdf.c: Default implementation of GtkPrintBackend + * gtkprintbackendfile.c: Default implementation of GtkPrintBackend * for printing to a file * Copyright (C) 2003, Red Hat, Inc. * @@ -14,12 +14,10 @@ * 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. + * License along with this library. If not, see . */ -#include +#include "config.h" #include #include @@ -32,17 +30,15 @@ #include #include #include +#include #include -#include "gtkprintoperation.h" +#include "gtk/gtk.h" +#include "gtk/gtkprinter-private.h" -#include "gtkprintbackend.h" #include "gtkprintbackendfile.h" -#include "gtkprinter.h" -#include "gtkprinter-private.h" - typedef struct _GtkPrintBackendFileClass GtkPrintBackendFileClass; #define GTK_PRINT_BACKEND_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_FILE, GtkPrintBackendFileClass)) @@ -67,13 +63,15 @@ typedef enum { FORMAT_PDF, FORMAT_PS, + FORMAT_SVG, N_FORMATS } OutputFormat; static const gchar* formats[N_FORMATS] = { "pdf", - "ps" + "ps", + "svg" }; static GObjectClass *backend_parent_class; @@ -103,10 +101,13 @@ static cairo_surface_t * file_printer_create_cairo_surface (GtkPrinter gdouble height, GIOChannel *cache_io); +static GList * file_printer_list_papers (GtkPrinter *printer); +static GtkPageSetup * file_printer_get_default_page_size (GtkPrinter *printer); + static void gtk_print_backend_file_register_type (GTypeModule *module) { - static const GTypeInfo print_backend_file_info = + const GTypeInfo print_backend_file_info = { sizeof (GtkPrintBackendFileClass), NULL, /* base_init */ @@ -179,6 +180,8 @@ gtk_print_backend_file_class_init (GtkPrintBackendFileClass *class) backend_class->printer_get_options = file_printer_get_options; backend_class->printer_get_settings_from_options = file_printer_get_settings_from_options; backend_class->printer_prepare_for_print = file_printer_prepare_for_print; + backend_class->printer_list_papers = file_printer_list_papers; + backend_class->printer_get_default_page_size = file_printer_get_default_page_size; } /* return N_FORMATS if no explicit format in the settings */ @@ -191,7 +194,8 @@ format_from_settings (GtkPrintSettings *settings) if (settings == NULL) return N_FORMATS; - value = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT); + value = gtk_print_settings_get (settings, + GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT); if (value == NULL) return N_FORMATS; @@ -209,13 +213,13 @@ output_file_from_settings (GtkPrintSettings *settings, const gchar *default_format) { gchar *uri = NULL; - + if (settings) uri = g_strdup (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI)); if (uri == NULL) { - const gchar *extension; + const gchar *extension, *basename, *output_dir; gchar *name, *locale_name, *path; if (default_format) @@ -225,22 +229,57 @@ output_file_from_settings (GtkPrintSettings *settings, OutputFormat format; format = format_from_settings (settings); - extension = format == FORMAT_PS ? "ps" : "pdf"; + switch (format) + { + default: + case FORMAT_PDF: + extension = "pdf"; + break; + case FORMAT_PS: + extension = "ps"; + break; + case FORMAT_SVG: + extension = "svg"; + break; + } } - - /* default filename used for print-to-file */ - name = g_strdup_printf (_("output.%s"), extension); + + basename = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME); + if (basename == NULL) + basename = _("output"); + + name = g_strconcat (basename, ".", extension, NULL); + locale_name = g_filename_from_utf8 (name, -1, NULL, NULL, NULL); g_free (name); if (locale_name != NULL) - { - path = g_build_filename (g_get_current_dir (), locale_name, NULL); - g_free (locale_name); + { + output_dir = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_DIR); + if (output_dir == NULL) + { + const gchar *document_dir = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); + + if (document_dir == NULL) + { + gchar *current_dir = g_get_current_dir (); + path = g_build_filename (current_dir, locale_name, NULL); + g_free (current_dir); + } + else + path = g_build_filename (document_dir, locale_name, NULL); + + uri = g_filename_to_uri (path, NULL, NULL); + } + else + { + path = g_build_filename (output_dir, locale_name, NULL); + uri = g_filename_to_uri (path, NULL, NULL); + } - uri = g_filename_to_uri (path, NULL, NULL); - g_free (path); - } + g_free (path); + g_free (locale_name); + } } return uri; @@ -293,16 +332,31 @@ file_printer_create_cairo_surface (GtkPrinter *printer, { cairo_surface_t *surface; OutputFormat format; + const cairo_svg_version_t *versions; + int num_versions = 0; format = format_from_settings (settings); - if (format == FORMAT_PS) - surface = cairo_ps_surface_create_for_stream (_cairo_write, cache_io, width, height); - else - surface = cairo_pdf_surface_create_for_stream (_cairo_write, cache_io, width, height); + switch (format) + { + default: + case FORMAT_PDF: + surface = cairo_pdf_surface_create_for_stream (_cairo_write, cache_io, width, height); + break; + case FORMAT_PS: + surface = cairo_ps_surface_create_for_stream (_cairo_write, cache_io, width, height); + break; + case FORMAT_SVG: + surface = cairo_svg_surface_create_for_stream (_cairo_write, cache_io, width, height); + cairo_svg_get_versions (&versions, &num_versions); + if (num_versions > 0) + cairo_svg_surface_restrict_to_version (surface, versions[num_versions - 1]); + break; + } - /* TODO: DPI from settings object? */ - cairo_surface_set_fallback_resolution (surface, 300, 300); + cairo_surface_set_fallback_resolution (surface, + 2.0 * gtk_print_settings_get_printer_lpi (settings), + 2.0 * gtk_print_settings_get_printer_lpi (settings)); return surface; } @@ -311,20 +365,21 @@ typedef struct { GtkPrintBackend *backend; GtkPrintJobCompleteFunc callback; GtkPrintJob *job; - GIOChannel *target_io; + GFileOutputStream *target_io_stream; gpointer user_data; GDestroyNotify dnotify; } _PrintStreamData; +/* expects GDK lock to be held */ static void -file_print_cb (GtkPrintBackendFile *print_backend, - GError *error, - gpointer user_data) +file_print_cb_locked (GtkPrintBackendFile *print_backend, + GError *error, + gpointer user_data) { _PrintStreamData *ps = (_PrintStreamData *) user_data; - if (ps->target_io != NULL) - g_io_channel_unref (ps->target_io); + if (ps->target_io_stream != NULL) + g_output_stream_close (G_OUTPUT_STREAM (ps->target_io_stream), NULL, NULL); if (ps->callback) ps->callback (ps->job, ps->user_data, error); @@ -337,10 +392,22 @@ file_print_cb (GtkPrintBackendFile *print_backend, if (ps->job) g_object_unref (ps->job); - + g_free (ps); } +static void +file_print_cb (GtkPrintBackendFile *print_backend, + GError *error, + gpointer user_data) +{ + GDK_THREADS_ENTER (); + + file_print_cb_locked (print_backend, error, user_data); + + GDK_THREADS_LEAVE (); +} + static gboolean file_write (GIOChannel *source, GIOCondition con, @@ -354,7 +421,7 @@ file_write (GIOChannel *source, error = NULL; - read_status = + read_status = g_io_channel_read_chars (source, buf, _STREAM_MAX_CHUNK_SIZE, @@ -365,11 +432,12 @@ file_write (GIOChannel *source, { gsize bytes_written; - g_io_channel_write_chars (ps->target_io, - buf, - bytes_read, - &bytes_written, - &error); + g_output_stream_write_all (G_OUTPUT_STREAM (ps->target_io_stream), + buf, + bytes_read, + &bytes_written, + NULL, + &error); } if (error != NULL || read_status == G_IO_STATUS_EOF) @@ -402,12 +470,11 @@ gtk_print_backend_file_print_stream (GtkPrintBackend *print_backend, GDestroyNotify dnotify) { GError *internal_error = NULL; - GtkPrinter *printer; _PrintStreamData *ps; GtkPrintSettings *settings; - gchar *uri, *filename; + gchar *uri; + GFile *file = NULL; - printer = gtk_print_job_get_printer (job); settings = gtk_print_job_get_settings (job); ps = g_new0 (_PrintStreamData, 1); @@ -419,24 +486,21 @@ gtk_print_backend_file_print_stream (GtkPrintBackend *print_backend, internal_error = NULL; uri = output_file_from_settings (settings, NULL); - filename = g_filename_from_uri (uri, NULL, &internal_error); - g_free (uri); - if (filename == NULL) + if (uri == NULL) goto error; - ps->target_io = g_io_channel_new_file (filename, "w", &internal_error); + file = g_file_new_for_uri (uri); + ps->target_io_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &internal_error); - g_free (filename); - - if (internal_error == NULL) - g_io_channel_set_encoding (ps->target_io, NULL, &internal_error); + g_object_unref (file); + g_free (uri); error: if (internal_error != NULL) { - file_print_cb (GTK_PRINT_BACKEND_FILE (print_backend), - internal_error, ps); + file_print_cb_locked (GTK_PRINT_BACKEND_FILE (print_backend), + internal_error, ps); g_error_free (internal_error); return; @@ -457,10 +521,11 @@ gtk_print_backend_file_init (GtkPrintBackendFile *backend) "name", _("Print to File"), "backend", backend, "is-virtual", TRUE, + "accepts-pdf", TRUE, NULL); gtk_printer_set_has_details (printer, TRUE); - gtk_printer_set_icon_name (printer, "gtk-floppy"); + gtk_printer_set_icon_name (printer, "document-save"); gtk_printer_set_is_active (printer, TRUE); gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer); @@ -469,6 +534,106 @@ gtk_print_backend_file_init (GtkPrintBackendFile *backend) gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend)); } +typedef struct { + GtkPrinter *printer; + GtkPrinterOptionSet *set; +} _OutputFormatChangedData; + +static void +set_printer_format_from_option_set (GtkPrinter *printer, + GtkPrinterOptionSet *set) +{ + GtkPrinterOption *format_option; + const gchar *value; + gint i; + + format_option = gtk_printer_option_set_lookup (set, "output-file-format"); + if (format_option && format_option->value) + { + value = format_option->value; + if (value) + { + for (i = 0; i < N_FORMATS; ++i) + if (strcmp (value, formats[i]) == 0) + break; + + g_assert (i < N_FORMATS); + + switch (i) + { + case FORMAT_PDF: + gtk_printer_set_accepts_pdf (printer, TRUE); + gtk_printer_set_accepts_ps (printer, FALSE); + break; + case FORMAT_PS: + gtk_printer_set_accepts_pdf (printer, FALSE); + gtk_printer_set_accepts_ps (printer, TRUE); + break; + case FORMAT_SVG: + default: + gtk_printer_set_accepts_pdf (printer, FALSE); + gtk_printer_set_accepts_ps (printer, FALSE); + break; + } + } + } +} + +static void +file_printer_output_file_format_changed (GtkPrinterOption *format_option, + gpointer user_data) +{ + GtkPrinterOption *uri_option; + gchar *base = NULL; + _OutputFormatChangedData *data = (_OutputFormatChangedData *) user_data; + + if (! format_option->value) + return; + + uri_option = gtk_printer_option_set_lookup (data->set, + "gtk-main-page-custom-input"); + + if (uri_option && uri_option->value) + { + const gchar *uri = uri_option->value; + const gchar *dot = strrchr (uri, '.'); + + if (dot) + { + gint i; + + /* check if the file extension matches one of the known ones */ + for (i = 0; i < N_FORMATS; i++) + if (strcmp (dot + 1, formats[i]) == 0) + break; + + if (i < N_FORMATS && strcmp (formats[i], format_option->value)) + { + /* the file extension is known but doesn't match the + * selected one, strip it away + */ + base = g_strndup (uri, dot - uri); + } + } + else + { + /* there's no file extension */ + base = g_strdup (uri); + } + } + + if (base) + { + gchar *tmp = g_strdup_printf ("%s.%s", base, format_option->value); + + gtk_printer_option_set (uri_option, tmp); + g_free (tmp); + g_free (base); + } + + set_printer_format_from_option_set (data->printer, data->set); +} + static GtkPrinterOptionSet * file_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, @@ -477,14 +642,16 @@ file_printer_get_options (GtkPrinter *printer, { GtkPrinterOptionSet *set; GtkPrinterOption *option; - const gchar *n_up[] = { "1" }; - const gchar *format_names[N_FORMATS] = { N_("PDF"), N_("Postscript") }; + const gchar *n_up[] = {"1", "2", "4", "6", "9", "16" }; + const gchar *pages_per_sheet = NULL; + const gchar *format_names[N_FORMATS] = { N_("PDF"), N_("Postscript"), N_("SVG") }; const gchar *supported_formats[N_FORMATS]; gchar *display_format_names[N_FORMATS]; gint n_formats = 0; OutputFormat format; gchar *uri; gint current_format = 0; + _OutputFormatChangedData *format_changed_data; format = format_from_settings (settings); @@ -493,7 +660,12 @@ file_printer_get_options (GtkPrinter *printer, 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), (char **) n_up, (char **) n_up /* FIXME i18n (localised digits)! */); - gtk_printer_option_set (option, "1"); + if (settings) + pages_per_sheet = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_NUMBER_UP); + if (pages_per_sheet) + gtk_printer_option_set (option, pages_per_sheet); + else + gtk_printer_option_set (option, "1"); gtk_printer_option_set_add (set, option); g_object_unref (option); @@ -521,7 +693,20 @@ file_printer_get_options (GtkPrinter *printer, } else { - current_format = format == FORMAT_PS ? FORMAT_PS : FORMAT_PDF; + switch (format) + { + default: + case FORMAT_PDF: + current_format = FORMAT_PDF; + break; + case FORMAT_PS: + current_format = FORMAT_PS; + break; + case FORMAT_SVG: + current_format = FORMAT_SVG; + break; + } + for (n_formats = 0; n_formats < N_FORMATS; ++n_formats) { supported_formats[n_formats] = formats[n_formats]; @@ -533,7 +718,9 @@ file_printer_get_options (GtkPrinter *printer, option = gtk_printer_option_new ("gtk-main-page-custom-input", _("File"), GTK_PRINTER_OPTION_TYPE_FILESAVE); + gtk_printer_option_set_activates_default (option, TRUE); gtk_printer_option_set (option, uri); + g_free (uri); option->group = g_strdup ("GtkPrintDialogExtension"); gtk_printer_option_set_add (set, option); @@ -548,7 +735,15 @@ file_printer_get_options (GtkPrinter *printer, display_format_names); gtk_printer_option_set (option, supported_formats[current_format]); gtk_printer_option_set_add (set, option); - + + set_printer_format_from_option_set (printer, set); + format_changed_data = g_new (_OutputFormatChangedData, 1); + format_changed_data->printer = printer; + format_changed_data->set = set; + g_signal_connect_data (option, "changed", + G_CALLBACK (file_printer_output_file_format_changed), + format_changed_data, (GClosureNotify)g_free, 0); + g_object_unref (option); } @@ -568,7 +763,14 @@ file_printer_get_settings_from_options (GtkPrinter *printer, option = gtk_printer_option_set_lookup (options, "output-file-format"); if (option) gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, option->value); - + + option = gtk_printer_option_set_lookup (options, "gtk-n-up"); + if (option) + gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, option->value); + + option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout"); + if (option) + gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, option->value); } static void @@ -578,24 +780,64 @@ file_printer_prepare_for_print (GtkPrinter *printer, GtkPageSetup *page_setup) { gdouble scale; + GtkPrintPages pages; + GtkPageRange *ranges; + gint n_ranges; - 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_n_copies (settings); + pages = gtk_print_settings_get_print_pages (settings); + gtk_print_job_set_pages (print_job, pages); + + if (pages == GTK_PRINT_PAGES_RANGES) + ranges = gtk_print_settings_get_page_ranges (settings, &n_ranges); + else + { + ranges = NULL; + n_ranges = 0; + } + + gtk_print_job_set_page_ranges (print_job, ranges, n_ranges); + gtk_print_job_set_collate (print_job, gtk_print_settings_get_collate (settings)); + gtk_print_job_set_reverse (print_job, gtk_print_settings_get_reverse (settings)); + gtk_print_job_set_num_copies (print_job, gtk_print_settings_get_n_copies (settings)); + gtk_print_job_set_n_up (print_job, gtk_print_settings_get_number_up (settings)); + gtk_print_job_set_n_up_layout (print_job, gtk_print_settings_get_number_up_layout (settings)); scale = gtk_print_settings_get_scale (settings); if (scale != 100.0) - print_job->scale = scale/100.0; + gtk_print_job_set_scale (print_job, scale / 100.0); + + gtk_print_job_set_page_set (print_job, gtk_print_settings_get_page_set (settings)); + gtk_print_job_set_rotate (print_job, TRUE); +} + +static GList * +file_printer_list_papers (GtkPrinter *printer) +{ + GList *result = NULL; + GList *papers, *p; + GtkPageSetup *page_setup; + + papers = gtk_paper_size_get_paper_sizes (TRUE); + + for (p = papers; p; p = p->next) + { + GtkPaperSize *paper_size = p->data; + + page_setup = gtk_page_setup_new (); + gtk_page_setup_set_paper_size (page_setup, paper_size); + gtk_paper_size_free (paper_size); + result = g_list_prepend (result, page_setup); + } + + g_list_free (papers); + + return g_list_reverse (result); +} + +static GtkPageSetup * +file_printer_get_default_page_size (GtkPrinter *printer) +{ + GtkPageSetup *result = NULL; - print_job->page_set = gtk_print_settings_get_page_set (settings); - print_job->rotate_to_orientation = TRUE; + return result; }