/* GTK - The GIMP Toolkit * gtkprintbackendcpdb.h: Default implementation of GtkPrintBackend * for the Common Print Dialog Backends (CPDB) * Copyright (C) 2022, 2023 TinyTrebuchet * * 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, see . */ #include #include #include #include "gtkprintbackendcpdb.h" #include "gtkprintbackendutils.h" #include #include #include #include #define GTK_PRINT_BACKEND_CPDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CPDB, GtkPrintBackendCpdbClass)) #define GTK_IS_PRINT_BACKEND_CPDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CPDB)) #define GTK_PRINT_BACKEND_CPDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CPDB, GtkPrintBackendCpdbClass)) /* * Multiplier for converting points to mm */ #define points_multiplier 2.83464567 #define _CPDB_MAX_CHUNK_SIZE 8192 static void gtk_print_backend_cpdb_finalize (GObject *object); static void cpdb_request_printer_list (GtkPrintBackend *backend); static void cpdb_printer_request_details (GtkPrinter *printer); static void cpdb_acquire_details_cb (cpdb_printer_obj_t *cpdb_printer_obj, int success, gpointer user_data); static GtkPrintCapabilities cpdb_printer_get_capabilities (GtkPrinter *printer); static GtkPrinterOptionSet *cpdb_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup, GtkPrintCapabilities capabilities); static GtkPageSetup *cpdb_get_gtk_page_setup (cpdb_printer_obj_t *printer_obj, const char *media); static GList *cpdb_printer_list_papers (GtkPrinter *printer); static GtkPageSetup *cpdb_printer_get_default_page_size (GtkPrinter *printer); static gboolean cpdb_printer_get_hard_margins (GtkPrinter *printer, double *top, double *bottom, double *left, double *right); static gboolean cpdb_printer_get_hard_margins_for_paper_size (GtkPrinter *printer, GtkPaperSize *paper_size, double *top, double *bottom, double *left, double *right); static void cpdb_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings); static void cpdb_printer_prepare_for_print (GtkPrinter *printer, GtkPrintJob *print_job, GtkPrintSettings *settings, GtkPageSetup *page_setup); static void cpdb_print_cb (GtkPrintBackendCpdb *cpdb_backend, GError *error, gpointer user_data); static gboolean cpdb_write (GIOChannel *source, GIOCondition con, gpointer user_data); static void cpdb_print_stream (GtkPrintBackend *backend, GtkPrintJob *job, GIOChannel *data_io, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify); static void gtk_printer_cpdb_configure_page_setup (GtkPrinter *printer, GtkPageSetup *page_setup, GtkPrintSettings *settings); static void gtk_printer_cpdb_configure_settings (const char *key, const char *value, gpointer user_data); static cairo_surface_t *cpdb_printer_create_cairo_surface (GtkPrinter *printer, GtkPrintSettings *settings, double width, double height, GIOChannel *cache_io); static void cpdb_fill_gtk_option (GtkPrinterOption *gtk_option, cpdb_option_t *cpdb_option, cpdb_printer_obj_t *printer_obj); static void printer_updates_callback (cpdb_frontend_obj_t *frontend_obj, cpdb_printer_obj_t *printer_obj, cpdb_printer_update_t change); static void add_option_to_settings (GtkPrinterOption *option, gpointer user_data); static void cpdb_printer_add_hash_table (gpointer key, gpointer value, gpointer user_data); static void cpdb_add_gtk_printer (GtkPrintBackend *backend, cpdb_printer_obj_t *printer_obj); static void cpdb_remove_gtk_printer (GtkPrintBackend *backend, cpdb_printer_obj_t *printer_obj); static void set_state_message (GtkPrinter *printer); static char *cpdb_option_translation (cpdb_printer_obj_t *printer_obj, const char *option_name); static char *cpdb_choice_translation (cpdb_printer_obj_t *printer_obj, const char *option_name, const char *choice_name); static void initialize (void); static gchar *get_gtk_group (cpdb_printer_obj_t *printer_obj, const char *group_name); /* * List of locales for text translation */ static const gchar* const* locales = NULL; /* * Mark the options which have already been displayed in other tabs, * and exclude them from the "Advanced" tab, while getting printer options */ static GHashTable *already_used_options = NULL; struct _GtkPrintBackendCpdbClass { GtkPrintBackendClass parent_class; }; struct _GtkPrintBackendCpdb { GtkPrintBackend parent_instance; cpdb_frontend_obj_t *frontend_obj; }; typedef struct { GtkPrintBackend *backend; GtkPrintJobCompleteFunc callback; GtkPrintJob *job; char *path; GIOStream *target_io_stream; gpointer user_data; GDestroyNotify dnotify; } _PrintStreamData; G_DEFINE_DYNAMIC_TYPE (GtkPrintBackendCpdb, gtk_print_backend_cpdb, GTK_TYPE_PRINT_BACKEND) /* * GtkPrintBackend object for currently opened print dialog */ static GtkPrintBackend *gtk_print_backend = NULL; G_MODULE_EXPORT void g_io_module_load (GIOModule *module) { g_type_module_use (G_TYPE_MODULE (module)); gtk_print_backend_cpdb_register_type (G_TYPE_MODULE (module)); gtk_printer_cpdb_register_type (G_TYPE_MODULE (module)); g_io_extension_point_implement (GTK_PRINT_BACKEND_EXTENSION_POINT_NAME, GTK_TYPE_PRINT_BACKEND_CPDB, "cpdb", 10); } G_MODULE_EXPORT void g_io_module_unload (GIOModule *module) { } G_MODULE_EXPORT char ** g_io_module_query (void) { char *eps[] = { (char *)GTK_PRINT_BACKEND_EXTENSION_POINT_NAME, NULL }; return g_strdupv (eps); } /* * GtkPrintBackendCpdb */ /* * gtk_print_backend_cpdb_new: * * Creates a new #GtkPrintBackendCpdb object. #GtkPrintBackendCpdb * implements the #GtkPrintBackend interface with direct access to * the filesystem using Unix/Linux API calls * * Returns: the new #GtkPrintBackendCpdb object */ GtkPrintBackend * gtk_print_backend_cpdb_new (void) { GTK_DEBUG (PRINTING, "CPDB Backend: Creating a new CPDB print backend object"); return g_object_new (GTK_TYPE_PRINT_BACKEND_CPDB, NULL); } static void gtk_print_backend_cpdb_class_init (GtkPrintBackendCpdbClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (klass); gobject_class->finalize = gtk_print_backend_cpdb_finalize; backend_class->request_printer_list = cpdb_request_printer_list; backend_class->printer_request_details = cpdb_printer_request_details; backend_class->printer_get_capabilities = cpdb_printer_get_capabilities; backend_class->printer_get_options = cpdb_printer_get_options; backend_class->printer_list_papers = cpdb_printer_list_papers; backend_class->printer_get_default_page_size = cpdb_printer_get_default_page_size; backend_class->printer_get_hard_margins = cpdb_printer_get_hard_margins; backend_class->printer_get_hard_margins_for_paper_size = cpdb_printer_get_hard_margins_for_paper_size; backend_class->printer_get_settings_from_options = cpdb_printer_get_settings_from_options; backend_class->printer_prepare_for_print = cpdb_printer_prepare_for_print; backend_class->printer_create_cairo_surface = cpdb_printer_create_cairo_surface; backend_class->print_stream = cpdb_print_stream; } static void gtk_print_backend_cpdb_class_finalize (GtkPrintBackendCpdbClass *class) { } static void gtk_print_backend_cpdb_init (GtkPrintBackendCpdb *backend_cpdb) { char *tmp, *instance_name; initialize (); /* * Initialize the FrontendObj with a random instance name to * prevent conflicts with print dialogs opened from other programs */ tmp = random_string (4); instance_name = g_strdup_printf ("Gtk_%s", tmp); GTK_DEBUG (PRINTING, "Creating frontendObj for CPDB backend: %s", instance_name); backend_cpdb->frontend_obj = cpdbGetNewFrontendObj (instance_name, (cpdb_printer_callback) printer_updates_callback); cpdbIgnoreLastSavedSettings (backend_cpdb->frontend_obj); gtk_print_backend = GTK_PRINT_BACKEND (backend_cpdb); g_free (tmp); g_free (instance_name); } static void gtk_print_backend_cpdb_finalize (GObject *object) { GtkPrintBackendCpdb *backend_cpdb; GObjectClass *backend_parent_class; GTK_DEBUG (PRINTING, "Finalizing CPDB backend object"); backend_cpdb = GTK_PRINT_BACKEND_CPDB (object); backend_parent_class = G_OBJECT_CLASS (gtk_print_backend_cpdb_parent_class); cpdbDeleteFrontendObj (backend_cpdb->frontend_obj); gtk_print_backend = NULL; backend_parent_class->finalize (object); } /* * This function is responsible for displaying the printer * list obtained from CPDB backend on the print dialog. */ static void cpdb_request_printer_list (GtkPrintBackend *backend) { GtkPrintBackendCpdb *backend_cpdb = GTK_PRINT_BACKEND_CPDB (backend); cpdbConnectToDBus (backend_cpdb->frontend_obj); g_hash_table_foreach (backend_cpdb->frontend_obj->printer, cpdb_printer_add_hash_table, backend); gtk_print_backend_set_list_done (backend); } /* * This function is responsible for making a printer acquire all * the details and supported options list, which need not be queried * until the user clicks on the printer in the printer list in the dialog. * The print dialog runs this function asynchronously and displays * "Getting printer attributes..." as the printer status meanwhile. * This function is needed as some printers (like temporary CUPS queue) * can take a couple of seconds to materialize and acquire all the details, * and it's important the dialog doesn't block during that time. */ static void cpdb_printer_request_details (GtkPrinter *printer) { GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); cpdbAcquireDetails (printer_obj, cpdb_acquire_details_cb, printer); } static void cpdb_acquire_details_cb (cpdb_printer_obj_t *printer_obj, int success, gpointer user_data) { GtkPrinter *printer = GTK_PRINTER (user_data); GtkPrintBackend *backend = gtk_printer_get_backend (printer); gboolean accepting_jobs, paused, status_changed; if (success == 0) { GTK_DEBUG (PRINTING, "Error acquiring printer details"); g_signal_emit_by_name (printer, "details-acquired", FALSE); return; } accepting_jobs = cpdbIsAcceptingJobs (printer_obj); paused = g_strcmp0 (cpdbGetState (printer_obj), "stopped") == 0; status_changed = paused ^ gtk_printer_is_paused (printer); gtk_printer_set_is_accepting_jobs (printer, accepting_jobs); gtk_printer_set_is_paused (printer, paused); set_state_message (printer); gtk_printer_set_has_details (printer, TRUE); g_signal_emit_by_name (printer, "details-acquired", TRUE); if (status_changed) g_signal_emit_by_name (backend, "printer-status-changed", printer); } /* * This function is responsible for specifying which features the * print dialog should offer for the given printer. */ static GtkPrintCapabilities cpdb_printer_get_capabilities (GtkPrinter *printer) { GtkPrintCapabilities capabilities = 0; cpdb_option_t *cpdb_option; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_PAGE_SET); if (cpdb_option != NULL && cpdb_option->num_supported >= 3) capabilities |= GTK_PRINT_CAPABILITY_PAGE_SET; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_COPIES); if (cpdb_option != NULL && g_strcmp0 (cpdb_option->supported_values[0], "1") != 0 && g_strcmp0 (cpdb_option->supported_values[0], "1-1") != 0) capabilities |= GTK_PRINT_CAPABILITY_COPIES; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_COLLATE); if (cpdb_option != NULL && cpdb_option->num_supported > 1) capabilities |= GTK_PRINT_CAPABILITY_COLLATE; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_PAGE_DELIVERY); if (cpdb_option != NULL && cpdb_option->num_supported > 1) capabilities |= GTK_PRINT_CAPABILITY_REVERSE; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_PRINT_SCALING); if (cpdb_option != NULL && cpdb_option->num_supported > 1) capabilities |= GTK_PRINT_CAPABILITY_SCALE; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_NUMBER_UP); if (cpdb_option != NULL && cpdb_option->num_supported > 1) capabilities |= GTK_PRINT_CAPABILITY_NUMBER_UP; cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_NUMBER_UP_LAYOUT); if (cpdb_option != NULL && cpdb_option->num_supported > 1) capabilities |= GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT; return capabilities; } /* * This function is responsible for getting all the options * that the printer supports and display them into the * GUI template of GTK+ print dialog box. * The backend should obtain whatever options it supports, * from either its print server or PPDs. */ static GtkPrinterOptionSet * cpdb_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup, GtkPrintCapabilities capabilities) { char *option_name; char *display_name; gpointer key, value; GHashTableIter iter; GtkPrinterCpdb *printer_cpdb; cpdb_printer_obj_t *printer_obj; cpdb_option_t *cpdb_option; GtkPrinterOption *gtk_option; GtkPrinterOptionSet *gtk_option_set; gtk_option_set = gtk_printer_option_set_new (); printer_cpdb = GTK_PRINTER_CPDB (printer); printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); /** Page-Setup **/ cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_NUMBER_UP); if ((capabilities & GTK_PRINT_CAPABILITY_NUMBER_UP) && cpdb_option != NULL) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-n-up", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_NUMBER_UP_LAYOUT); if ((capabilities & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) && cpdb_option != NULL) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-n-up-layout", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_SIDES); if (cpdb_option != NULL && cpdb_option->num_supported > 1) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-duplex", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_MEDIA_SOURCE); if (cpdb_option != NULL && cpdb_option->num_supported > 1) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-paper-source", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_MEDIA_TYPE); if (cpdb_option != NULL && cpdb_option->num_supported > 1) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-paper-type", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_OUTPUT_BIN); if (cpdb_option != NULL && cpdb_option->num_supported > 1) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-output-tray", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } /** Jobs **/ cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_JOB_PRIORITY); if (cpdb_option != NULL) { /* job-priority is represented as a number from 1-100 */ const char *prio[] = {"100", "80", "50", "30"}; const char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low")}; for (int i = 0; i < G_N_ELEMENTS(prio_display); i++) prio_display[i] = _(prio_display[i]); display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-job-prio", display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); gtk_printer_option_choices_from_array (gtk_option, G_N_ELEMENTS (prio), prio, prio_display); gtk_printer_option_set (gtk_option, "50"); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_JOB_SHEETS); if (cpdb_option != NULL && cpdb_option->num_supported > 1) { gtk_option = gtk_printer_option_new ("gtk-cover-before", C_("printer option", "Before"), GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); gtk_option = gtk_printer_option_new ("gtk-cover-after", C_("printer option", "After"), GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } cpdb_option = cpdbGetOption (printer_obj, CPDB_OPTION_BILLING_INFO); if (cpdb_option != NULL) { display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new ("gtk-billing-info", display_name, GTK_PRINTER_OPTION_TYPE_STRING); gtk_printer_option_set (gtk_option, ""); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } const char *print_at[] = {"now", "at", "on-hold"}; gtk_option = gtk_printer_option_new ("gtk-print-time", _("Print at"), GTK_PRINTER_OPTION_TYPE_PICKONE); gtk_printer_option_choices_from_array (gtk_option, G_N_ELEMENTS (print_at), print_at, print_at); gtk_printer_option_set (gtk_option, "now"); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); gtk_option = gtk_printer_option_new ("gtk-print-time-text", _("Print at time"), GTK_PRINTER_OPTION_TYPE_STRING); gtk_printer_option_set (gtk_option, ""); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); /** Other options **/ g_hash_table_iter_init (&iter, printer_obj->options->table); while (g_hash_table_iter_next (&iter, &key, &value)) { option_name = (char *) key; if (g_hash_table_contains (already_used_options, option_name)) continue; cpdb_option = (cpdb_option_t *) value; if (cpdb_option->num_supported <= 1) continue; display_name = cpdb_option_translation (printer_obj, cpdb_option->option_name); gtk_option = gtk_printer_option_new (cpdb_option->option_name, display_name, GTK_PRINTER_OPTION_TYPE_PICKONE); cpdb_fill_gtk_option (gtk_option, cpdb_option, printer_obj); gtk_option->group = get_gtk_group (printer_obj, cpdb_option->group_name); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } /* * Check if borderles printing is supported */ gboolean borderless = TRUE; const char *attrs[] = {CPDB_OPTION_MARGIN_TOP, CPDB_OPTION_MARGIN_BOTTOM, CPDB_OPTION_MARGIN_LEFT, CPDB_OPTION_MARGIN_RIGHT}; for (int i = 0; i < 4; i++) { cpdb_option = cpdbGetOption (printer_obj, (gchar *) attrs[i]); gboolean found = FALSE; if (cpdb_option != NULL) { for (int j = 0; j < cpdb_option->num_supported; j++) { if (g_strcmp0 (cpdb_option->supported_values[j], "0") == 0) { found = TRUE; break; } } } if (!found) { borderless = FALSE; break; } } if (borderless) { gtk_option = gtk_printer_option_new ("borderless", C_("print option", "Borderless"), GTK_PRINTER_OPTION_TYPE_BOOLEAN); gtk_option->group = get_gtk_group (printer_obj, CPDB_GROUP_MEDIA); gtk_printer_option_set_add (gtk_option_set, gtk_option); g_object_unref (gtk_option); } return gtk_option_set; } /* * Helper function to create GtkPageSetup from given "media" size */ static GtkPageSetup * cpdb_get_gtk_page_setup (cpdb_printer_obj_t *printer_obj, const char *media) { char *display_name; int width, height, num_margins, ok; cpdb_margin_t *margins; GtkPaperSize *paper_size; GtkPageSetup *page_setup; page_setup = gtk_page_setup_new (); display_name = cpdb_choice_translation (printer_obj, CPDB_OPTION_MEDIA, media); ok = cpdbGetMediaSize (printer_obj, media, &width, &height); if (ok == 1) { paper_size = gtk_paper_size_new_custom (media, display_name, width / 100.0, height / 100.0, GTK_UNIT_MM); gtk_page_setup_set_paper_size (page_setup, paper_size); gtk_paper_size_free (paper_size); } num_margins = cpdbGetMediaMargins (printer_obj, media, &margins); if (num_margins > 0) { gtk_page_setup_set_left_margin (page_setup, margins[0].left / 100.0, GTK_UNIT_MM); gtk_page_setup_set_right_margin (page_setup, margins[0].right / 100.0, GTK_UNIT_MM); gtk_page_setup_set_top_margin (page_setup, margins[0].top / 100.0, GTK_UNIT_MM); gtk_page_setup_set_bottom_margin (page_setup, margins[0].bottom / 100.0, GTK_UNIT_MM); } return page_setup; } /* * This function is responsible for listing all the page sizes supported by a printer */ static GList * cpdb_printer_list_papers (GtkPrinter *printer) { cpdb_option_t *media; GList *result = NULL; GtkPageSetup *page_setup; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); media = cpdbGetOption (printer_obj, CPDB_OPTION_MEDIA); if (media == NULL) return NULL; for (int i = 0; i < media->num_supported; i++) { if (g_str_has_prefix (media->supported_values[i], "custom_min") || g_str_has_prefix (media->supported_values[i], "custom_max")) continue; page_setup = cpdb_get_gtk_page_setup (printer_obj, media->supported_values[i]); result = g_list_prepend (result, page_setup); } result = g_list_reverse (result); return result; } /* * This function is responsible for getting the default page size for a printer */ static GtkPageSetup * cpdb_printer_get_default_page_size (GtkPrinter *printer) { char *default_media; GtkPageSetup *page_setup = NULL; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); default_media = cpdbGetDefault (printer_obj, CPDB_OPTION_MEDIA); if (default_media != NULL) { page_setup = cpdb_get_gtk_page_setup (printer_obj, default_media); } return page_setup; } /* * This function is responsible for getting the * default page size margins supported by a printer */ static gboolean cpdb_printer_get_hard_margins (GtkPrinter *printer, double *top, double *bottom, double *left, double *right) { char *left_margin, *right_margin, *top_margin, *bottom_margin; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); top_margin = cpdbGetDefault (printer_obj, CPDB_OPTION_MARGIN_TOP); left_margin = cpdbGetDefault (printer_obj, CPDB_OPTION_MARGIN_LEFT); right_margin = cpdbGetDefault (printer_obj, CPDB_OPTION_MARGIN_RIGHT); bottom_margin = cpdbGetDefault (printer_obj, CPDB_OPTION_MARGIN_BOTTOM); if (top_margin != NULL && left_margin != NULL && right_margin != NULL && bottom_margin != NULL) { *top = g_ascii_strtod (top_margin, NULL) * points_multiplier / 100.0; *left = g_ascii_strtod (left_margin, NULL) * points_multiplier / 100.0; *right = g_ascii_strtod (right_margin, NULL) * points_multiplier / 100.0; *bottom = g_ascii_strtod (bottom_margin, NULL) * points_multiplier / 100.0; return TRUE; } return FALSE; } /* * This function is responsible for getting the * default page size margins for give paper size */ static gboolean cpdb_printer_get_hard_margins_for_paper_size (GtkPrinter *printer, GtkPaperSize *paper_size, double *top, double *bottom, double *left, double *right) { int num_margins; const char *media; cpdb_margin_t *margins; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); media = gtk_paper_size_get_name (paper_size); if (media != NULL) { num_margins = cpdbGetMediaMargins (printer_obj, media, &margins); if (num_margins > 0) { *top = margins[0].top * points_multiplier / 100.0; *left = margins[0].left * points_multiplier / 100.0; *right = margins[0].right * points_multiplier / 100.0; *bottom = margins[0].bottom * points_multiplier / 100.0; return TRUE; } } return FALSE; } /* * @user_data: GtkPrintSettings */ static void add_option_to_settings (GtkPrinterOption *option, gpointer user_data) { GtkPrintSettings *settings = (GtkPrintSettings *) user_data; gtk_print_settings_set (settings, option->name, option->value); } /* * This method is invoked when the print button on the print dialog is pressed. * It's responsible for gathering all the settings from the print dialog that the * user may have selected before pressing the print button. */ static void cpdb_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings) { char *value; GtkPrinterOption *option, *cover_before, *cover_after; option = gtk_printer_option_set_lookup (options, "gtk-n-up"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_NUMBER_UP, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_NUMBER_UP_LAYOUT, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-duplex"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_SIDES, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-paper-source"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_MEDIA_SOURCE, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-paper-type"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_MEDIA_TYPE, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-output-tray"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_OUTPUT_BIN, option->value); } option = gtk_printer_option_set_lookup (options, "gtk-job-prio"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_JOB_PRIORITY, option->value); } 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 != NULL && cover_after != NULL) { value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value); gtk_print_settings_set (settings, CPDB_OPTION_JOB_SHEETS, value); g_free (value); } option = gtk_printer_option_set_lookup (options, "gtk-billing-info"); if (option != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_BILLING_INFO, option->value); } char *print_at = NULL; option = gtk_printer_option_set_lookup (options, "gtk-print-time"); if (option != NULL) print_at = g_strdup (option->value); char *print_at_time = NULL; option = gtk_printer_option_set_lookup (options, "gtk-print-time-text"); if (option != NULL) print_at_time = g_strdup (option->value); if (print_at != NULL && print_at_time != NULL) { if (g_strcmp0 (print_at, "at") == 0) { char *utc_time = NULL; utc_time = localtime_to_utctime (print_at_time); if (utc_time != NULL) { gtk_print_settings_set (settings, CPDB_OPTION_JOB_HOLD_UNTIL, utc_time); g_free (utc_time); } else gtk_print_settings_set (settings, CPDB_OPTION_JOB_HOLD_UNTIL, print_at_time); } else if (g_strcmp0 (print_at, "on-hold") == 0) gtk_print_settings_set (settings, CPDB_OPTION_JOB_HOLD_UNTIL, CPDB_JOB_HOLD_INDEFINITE); } if (print_at != NULL) g_free (print_at); if (print_at_time != NULL) g_free (print_at_time); gtk_printer_option_set_foreach (options, add_option_to_settings, settings); } static cairo_status_t _cairo_write (void *closure, const unsigned char *data, unsigned int length) { GIOChannel *io = (GIOChannel *)closure; gsize written; GError *error; error = NULL; GTK_DEBUG (PRINTING, "CPDB Backend: Writing %i byte chunk to temp file", length); while (length > 0) { g_io_channel_write_chars (io, (const char *)data, length, &written, &error); if (error != NULL) { GTK_DEBUG (PRINTING, "CPDB Backend: Error writing to temp file, %s", error->message); g_error_free (error); return CAIRO_STATUS_WRITE_ERROR; } GTK_DEBUG (PRINTING, "CPDB Backend: Wrote %" G_GSIZE_FORMAT " bytes to temp file\n", written); data += written; length -= written; } return CAIRO_STATUS_SUCCESS; } /* * called after prepare_for_print () */ static cairo_surface_t * cpdb_printer_create_cairo_surface (GtkPrinter *printer, GtkPrintSettings *settings, double width, double height, GIOChannel *cache_io) { cairo_surface_t *surface; surface = cairo_pdf_surface_create_for_stream (_cairo_write, cache_io, width, height); 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; } static void gtk_printer_cpdb_configure_settings (const char *key, const char *value, gpointer user_data) { const char *option_name, *option_value; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (user_data); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); option_name = key; option_value = value; if (g_str_has_prefix (option_name, "gtk") || g_strcmp0 (option_value, "") == 0) { return; } cpdbAddSettingToPrinter (printer_obj, option_name, option_value); } static void gtk_printer_cpdb_configure_page_setup (GtkPrinter *printer, GtkPageSetup *page_setup, GtkPrintSettings *settings) { char *value, *orientation, *default_orientation; const char *borderless; double width, height, left, top, right, bottom; GtkPageOrientation page_orientation; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM) * 100.0; height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM) * 100.0; left = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM) * 100.0; right = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM) * 100.0; top = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM) * 100.0; bottom = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM) * 100.0; borderless = gtk_print_settings_get (settings, "borderless"); if (g_ascii_strcasecmp (borderless, "True") == 0) left = right = top = bottom = 0; value = g_strdup_printf ("{media-size={x-dimension=%.0f y-dimension=%.0f} " "media-bottom-margin=%.0f " "media-left-margin=%.0f " "media-right-margin=%.0f " "media-top-margin=%.0f}", width, height, bottom, left, right, top); gtk_print_settings_set (settings, CPDB_OPTION_MEDIA_COL, value); g_free (value); page_orientation = gtk_page_setup_get_orientation (page_setup); default_orientation = cpdbGetDefault (printer_obj, CPDB_OPTION_ORIENTATION); switch (page_orientation) { case GTK_PAGE_ORIENTATION_PORTRAIT: orientation = g_strdup_printf (CPDB_ORIENTATION_PORTRAIT); break; case GTK_PAGE_ORIENTATION_LANDSCAPE: orientation = g_strdup_printf (CPDB_ORIENTATION_LANDSCAPE); break; case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: orientation = g_strdup_printf (CPDB_ORIENTATION_RLANDSCAPE); break; case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: orientation = g_strdup_printf (CPDB_ORIENTATION_RPORTRAIT); break; default: orientation = default_orientation; } gtk_print_settings_set (settings, CPDB_OPTION_ORIENTATION, orientation); g_free (orientation); } static void cpdb_printer_prepare_for_print (GtkPrinter *printer, GtkPrintJob *print_job, GtkPrintSettings *settings, GtkPageSetup *page_setup) { int n_ranges; double scale; GtkPrintPages pages; GtkPageRange *ranges; GtkPageSet page_set; GtkPrintCapabilities capabilities; capabilities = cpdb_printer_get_capabilities (printer); pages = gtk_print_settings_get_print_pages (settings); gtk_print_job_set_pages (print_job, pages); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_PRINT_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_settings_unset (settings, GTK_PRINT_SETTINGS_PAGE_RANGES); scale = gtk_print_settings_get_scale (settings); if (scale != 100.0) gtk_print_job_set_scale (print_job, scale / 100.0); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_SCALE); if (capabilities & GTK_PRINT_CAPABILITY_COLLATE) { if (gtk_print_settings_get_collate (settings)) gtk_print_settings_set (settings, CPDB_OPTION_COLLATE, CPDB_COLLATE_ENABLED); } gtk_print_job_set_collate (print_job, FALSE); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_COLLATE); if (capabilities & GTK_PRINT_CAPABILITY_REVERSE) { if (gtk_print_settings_get_reverse (settings)) gtk_print_settings_set (settings, CPDB_OPTION_PAGE_DELIVERY, CPDB_PAGE_DELIVERY_REVERSE); } gtk_print_job_set_reverse (print_job, FALSE); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_REVERSE); if (capabilities & GTK_PRINT_CAPABILITY_COPIES) { int copies = gtk_print_settings_get_n_copies (settings); if (copies > 1) { char *value = g_strdup_printf ("%d", copies); gtk_print_settings_set (settings, CPDB_OPTION_COPIES, value); g_free (value); } } gtk_print_job_set_num_copies (print_job, 1); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_N_COPIES); page_set = gtk_print_settings_get_page_set (settings); switch (page_set) { case GTK_PAGE_SET_EVEN : gtk_print_settings_set (settings, CPDB_OPTION_PAGE_SET, CPDB_PAGE_SET_EVEN); break; case GTK_PAGE_SET_ODD : gtk_print_settings_set (settings, CPDB_OPTION_PAGE_SET, CPDB_PAGE_SET_ODD); break; case GTK_PAGE_SET_ALL : default : gtk_print_settings_set (settings, CPDB_OPTION_PAGE_SET, CPDB_PAGE_SET_ALL); } gtk_print_job_set_page_set (print_job, GTK_PAGE_SET_ALL); gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_PAGE_SET); gtk_print_settings_unset (settings, "printer"); gtk_printer_cpdb_configure_page_setup (printer, page_setup, settings); gtk_print_settings_unset (settings, "borderless"); gtk_print_settings_foreach (settings, gtk_printer_cpdb_configure_settings, printer); } static void cpdb_print_cb (GtkPrintBackendCpdb *backend_cpdb, GError *error, gpointer user_data) {; GtkPrinterCpdb *printer_cpdb; cpdb_printer_obj_t *printer_obj; _PrintStreamData *ps = (_PrintStreamData *) user_data; if (ps->target_io_stream != NULL) g_io_stream_close (G_IO_STREAM (ps->target_io_stream), NULL, NULL); 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 ? GTK_PRINT_STATUS_FINISHED_ABORTED : GTK_PRINT_STATUS_FINISHED); if (!error) { printer_cpdb = GTK_PRINTER_CPDB (gtk_print_job_get_printer (ps->job)); printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); GTK_DEBUG (PRINTING, "CPDB Backend: Sending file to CPDB for printing - %s\n", ps->path); cpdbPrintFile (printer_obj, ps->path); g_free (ps->path); } if (ps->job) g_object_unref (ps->job); g_free (ps); } static gboolean cpdb_write (GIOChannel *source, GIOCondition con, gpointer user_data) { char buf[_CPDB_MAX_CHUNK_SIZE]; gsize bytes_read; GError *error; GIOStatus status; GOutputStream *out_stream; _PrintStreamData *ps = (_PrintStreamData *) user_data; error = NULL; status = g_io_channel_read_chars (source, buf, _CPDB_MAX_CHUNK_SIZE, &bytes_read, &error); if (status != G_IO_STATUS_ERROR) { gsize bytes_written; out_stream = g_io_stream_get_output_stream (ps->target_io_stream); g_output_stream_write_all (out_stream, buf, bytes_read, &bytes_written, NULL, &error); } if (error != NULL || status == G_IO_STATUS_EOF) { cpdb_print_cb (GTK_PRINT_BACKEND_CPDB (ps->backend), error, user_data); if (error != NULL) { GTK_DEBUG (PRINTING, "CPDB Backend: Error writing to file - %s\n", error->message); g_error_free (error); } return FALSE; } GTK_DEBUG (PRINTING, "CPDB Backend: Writing %" G_GSIZE_FORMAT " byte chunk to cpdb pipe\n", bytes_read); return TRUE; } static void cpdb_print_stream (GtkPrintBackend *backend, GtkPrintJob *job, GIOChannel *data_io, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify) { GError *error; GFile *file; _PrintStreamData *ps; GFileIOStream *iostream; ps = g_new0 (_PrintStreamData, 1); ps->callback = callback; ps->user_data = user_data; ps->dnotify = dnotify; ps->job = g_object_ref (job); ps->backend = backend; error = NULL; file = g_file_new_tmp (NULL, &iostream, &error); if (file == NULL) goto error; ps->path = g_file_get_path (file); ps->target_io_stream = G_IO_STREAM (iostream); g_object_unref (file); error: if (error != NULL) { GTK_DEBUG (PRINTING, "Error: %s\n", error->message); cpdb_print_cb (GTK_PRINT_BACKEND_CPDB (backend), error, ps); g_error_free (error); return; } g_io_add_watch (data_io, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, (GIOFunc) cpdb_write, ps); } /* * Reflect changes in printers to the GTK print dialog. */ static void printer_updates_callback (cpdb_frontend_obj_t *frontend_obj, cpdb_printer_obj_t *printer_obj, cpdb_printer_update_t change) { GtkPrinter *printer; if (gtk_print_backend == NULL) return; switch (change) { case CPDB_CHANGE_PRINTER_ADDED: cpdb_add_gtk_printer (gtk_print_backend, printer_obj); break; case CPDB_CHANGE_PRINTER_REMOVED: cpdb_remove_gtk_printer (gtk_print_backend, printer_obj); cpdbDeletePrinterObj (printer_obj); break; case CPDB_CHANGE_PRINTER_STATE_CHANGED: printer = gtk_print_backend_find_printer (gtk_print_backend, printer_obj->name); set_state_message (printer); g_signal_emit_by_name (gtk_print_backend, "printer-status-changed", printer); break; default: break; } } /* * @key: printer name * @value: cpdb_printer_obj_t * @user_data: GtkPrintBackend */ static void cpdb_printer_add_hash_table (gpointer key, gpointer value, gpointer user_data) { cpdb_add_gtk_printer (user_data, value); } /* * Adds given printer to given GtkPrintBackend */ static void cpdb_add_gtk_printer (GtkPrintBackend *backend, cpdb_printer_obj_t *printer_obj) { GtkPrinter *printer; GtkPrinterCpdb *printer_cpdb; cpdb_printer_obj_t *default_printer; GtkPrintBackendCpdb *backend_cpdb = GTK_PRINT_BACKEND_CPDB (backend); /* * Ignore printers from FILE backend, * since we are using "Print To File" GTK print backend. */ if (g_strcmp0 (printer_obj->backend_name, "FILE") == 0) return; printer_cpdb = g_object_new (GTK_TYPE_PRINTER_CPDB, "name", printer_obj->name, "backend", backend, NULL); gtk_printer_cpdb_set_printer_obj (printer_cpdb, printer_obj); printer = GTK_PRINTER (printer_cpdb); gtk_printer_set_icon_name (printer, "printer"); gtk_printer_set_location (printer, printer_obj->location); gtk_printer_set_description (printer, printer_obj->info); gtk_printer_set_accepts_pdf (printer, TRUE); gtk_printer_set_accepts_ps (printer, TRUE); gtk_printer_set_is_active (printer, TRUE); gtk_printer_set_has_details (printer, FALSE); default_printer = cpdbGetDefaultPrinter (backend_cpdb->frontend_obj); if (default_printer == printer_obj) gtk_printer_set_is_default (printer, TRUE); /* * If printer state is not available, wait till cpdbAcquireDetails () * is called when the printer is clicked on in the print dialog */ if (g_strcmp0 (printer_obj->state, "NA") == 0) { gtk_printer_set_is_accepting_jobs (printer, TRUE); gtk_printer_set_is_paused (printer, FALSE); gtk_printer_set_state_message (printer, ""); } else { gtk_printer_set_is_accepting_jobs (printer, cpdbIsAcceptingJobs (printer_obj)); gtk_printer_set_is_paused (printer, g_strcmp0 (cpdbGetState (printer_obj), CPDB_STATE_STOPPED) == 0); set_state_message (printer); } gtk_print_backend_add_printer (backend, printer); if (gtk_print_backend_printer_list_is_done (backend)) { g_signal_emit_by_name (backend, "printer-added", printer); g_signal_emit_by_name (backend, "printer-list-changed"); } g_object_unref (printer); } /* * Removes given printer from given GtkPrintBackend */ static void cpdb_remove_gtk_printer (GtkPrintBackend *backend, cpdb_printer_obj_t *printer_obj) { GtkPrinter *printer = gtk_print_backend_find_printer (backend, printer_obj->name); gtk_print_backend_remove_printer (backend, printer); g_signal_emit_by_name (backend, "printer-removed", printer); g_signal_emit_by_name (backend, "printer-list-changed"); } /* * Sets printer status */ static void set_state_message (GtkPrinter *printer) { gboolean stopped, accepting_jobs; GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (printer); cpdb_printer_obj_t *printer_obj = gtk_printer_cpdb_get_printer_obj (printer_cpdb); stopped = g_strcmp0 (cpdbGetState (printer_obj), CPDB_STATE_STOPPED) == 0; accepting_jobs = cpdbIsAcceptingJobs (printer_obj); if (stopped && !accepting_jobs) /* Translators: this is a printer status. */ gtk_printer_set_state_message (printer, _("Paused; Rejecting Jobs")); else if (stopped && accepting_jobs) /* Translators: this is a printer status. */ gtk_printer_set_state_message (printer, _("Paused")); else if (!accepting_jobs) /* Translators: this is a printer status. */ gtk_printer_set_state_message (printer, _("Rejecting Jobs")); else gtk_printer_set_state_message (printer, ""); } /* * Fills option choices & sets default in gtk_option from cpdb_option */ static void cpdb_fill_gtk_option (GtkPrinterOption *gtk_option, cpdb_option_t *cpdb_option, cpdb_printer_obj_t *printer_obj) { char *display_val; char **default_val; gtk_printer_option_allocate_choices (gtk_option, cpdb_option->num_supported); for (int i = 0; i < cpdb_option->num_supported; i++) { gtk_option->choices[i] = g_strdup (cpdb_option->supported_values[i]); display_val = cpdb_choice_translation (printer_obj, cpdb_option->option_name, cpdb_option->supported_values[i]); gtk_option->choices_display[i] = g_strdup (display_val); } if (g_strcmp0 (cpdb_option->default_value, "NA") != 0) { if (g_strcmp0 (cpdb_option->option_name, CPDB_OPTION_JOB_SHEETS) == 0) { default_val = g_strsplit (cpdb_option->default_value, ",", 2); if (g_strcmp0 (gtk_option->name, "gtk-cover-before") == 0) gtk_printer_option_set (gtk_option, default_val[0]); else if (g_strcmp0 (gtk_option->name, "gtk-cover-after") == 0) gtk_printer_option_set (gtk_option, default_val[1]); } else { gtk_printer_option_set (gtk_option, g_strdup (cpdb_option->default_value)); } } } /* * Wrapper for getting translation of an option name */ static char * cpdb_option_translation (cpdb_printer_obj_t *printer_obj, const char *option_name) { int i; char *translation = NULL; for (i = 0; locales[i] != NULL; i++) { translation = cpdbGetOptionTranslation (printer_obj, option_name, locales[i]); if (translation != NULL) break; } return translation; } /* * Wrapper for getting translation of a choice name */ static char * cpdb_choice_translation (cpdb_printer_obj_t *printer_obj, const char *option_name, const char *choice_name) { int i; char *translation = NULL; for (i = 0; locales[i] != NULL; i++) { translation = cpdbGetChoiceTranslation (printer_obj, option_name, choice_name, locales[i]); if (translation != NULL) break; } return translation; } /* * Wrapper for getting translation of a group name */ static char * cpdb_group_translation (cpdb_printer_obj_t *printer_obj, const char *group_name) { int i; char *translation = NULL; for (i = 0; locales[i] != NULL; i++) { translation = cpdbGetGroupTranslation (printer_obj, group_name, locales[i]); if (translation != NULL) break; } return translation; } /* * Convert CPDB groups explicitly supported by GTK print dialog */ static gchar * get_gtk_group (cpdb_printer_obj_t *printer_obj, const char *group_name) { if (g_strcmp0 (group_name, CPDB_GROUP_COLOR) == 0) return g_strdup ("ColorPage"); if (g_strcmp0 (group_name, CPDB_GROUP_QUALITY) == 0) return g_strdup ("ImageQualityPage"); if (g_strcmp0 (group_name, CPDB_GROUP_FINISHINGS) == 0) return g_strdup ("FinishingPage"); return cpdb_group_translation (printer_obj, group_name); } /* * Do initial setup */ static void initialize (void) { cpdbInit (); if (locales == NULL) locales = g_get_language_names (); if (already_used_options == NULL) { already_used_options = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_COPIES); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_PAGE_RANGES); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_ORIENTATION); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_PAGE_DELIVERY); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_COLLATE); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_NUMBER_UP); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_NUMBER_UP_LAYOUT); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_PAGE_SET); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MEDIA); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MARGIN_TOP); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MARGIN_BOTTOM); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MARGIN_LEFT); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MARGIN_RIGHT); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_SIDES); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MEDIA_SOURCE); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_MEDIA_TYPE); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_OUTPUT_BIN); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_JOB_PRIORITY); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_JOB_SHEETS); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_JOB_HOLD_UNTIL); g_hash_table_add (already_used_options, (gpointer) CPDB_OPTION_BILLING_INFO); g_hash_table_add (already_used_options, (gpointer) "borderless"); } }