diff --git a/meson_options.txt b/meson_options.txt index 5fd41258c3..9f608e9e35 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -41,6 +41,11 @@ option('media-gstreamer', # Print backends +option('print-cpdb', + type: 'feature', + value: 'disabled', + description : 'Build the cpdb print backend') + option('print-cups', type: 'feature', value: 'auto', diff --git a/modules/printbackends/gtkprintbackendcpdb.c b/modules/printbackends/gtkprintbackendcpdb.c new file mode 100644 index 0000000000..77498ccc72 --- /dev/null +++ b/modules/printbackends/gtkprintbackendcpdb.c @@ -0,0 +1,1692 @@ +/* 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"); + } +} diff --git a/modules/printbackends/gtkprintbackendcpdb.h b/modules/printbackends/gtkprintbackendcpdb.h new file mode 100644 index 0000000000..6324e76bff --- /dev/null +++ b/modules/printbackends/gtkprintbackendcpdb.h @@ -0,0 +1,43 @@ +/* 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 . + */ + + +#ifndef __GTK_PRINT_BACKEND_CPDB_H__ +#define __GTK_PRINT_BACKEND_CPDB_H__ + +#include +#include +#include "gtkprintbackendprivate.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_PRINT_BACKEND_CPDB (gtk_print_backend_cpdb_get_type ()) +#define GTK_PRINT_BACKEND_CPDB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_BACKEND_CPDB, GtkPrintBackendCpdb)) +#define GTK_IS_PRINT_BACKEND_CPDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_BACKEND_CPDB)) + +typedef struct _GtkPrintBackendCpdbClass GtkPrintBackendCpdbClass; +typedef struct _GtkPrintBackendCpdb GtkPrintBackendCpdb; + +GtkPrintBackend *gtk_print_backend_cpdb_new (void); +GType gtk_print_backend_cpdb_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GTK_PRINT_BACKEND_CPDB_H__ */ + diff --git a/modules/printbackends/gtkprintbackendcups.c b/modules/printbackends/gtkprintbackendcups.c index 878e073741..b88995b89d 100644 --- a/modules/printbackends/gtkprintbackendcups.c +++ b/modules/printbackends/gtkprintbackendcups.c @@ -55,6 +55,7 @@ #include "gtkcupsutils.h" #include "gtkcupssecretsutils.h" +#include "gtkprintbackendutils.h" #include #include "gtkprivate.h" @@ -6483,87 +6484,6 @@ foreach_option_get_settings (GtkPrinterOption *option, gtk_print_settings_set (settings, option->name, value); } -static gboolean -supports_am_pm (void) -{ - struct tm tmp_tm = { 0 }; - char time[8]; - int length; - - length = strftime (time, sizeof (time), "%p", &tmp_tm); - - return length != 0; -} - -/* Converts local time to UTC time. Local time has to be in one of these - * formats: HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm}, - * {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH. - * Returns a newly allocated string holding UTC time in HH:MM:SS format - * or NULL. - */ -static char * -localtime_to_utctime (const char *local_time) -{ - const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ", - " %H : %M : %S ", - " %I : %M %p ", " %p %I : %M ", - " %H : %M ", - " %I %p ", " %p %I "}; - const char *formats_1[] = {" %H : %M : %S ", " %H : %M "}; - const char *end = NULL; - struct tm *actual_local_time; - struct tm *actual_utc_time; - struct tm local_print_time; - struct tm utc_print_time; - struct tm diff_time; - char *utc_time = NULL; - int i, n; - - if (local_time == NULL || local_time[0] == '\0') - return NULL; - - n = supports_am_pm () ? G_N_ELEMENTS (formats_0) : G_N_ELEMENTS (formats_1); - - for (i = 0; i < n; i++) - { - local_print_time.tm_hour = 0; - local_print_time.tm_min = 0; - local_print_time.tm_sec = 0; - - if (supports_am_pm ()) - end = strptime (local_time, formats_0[i], &local_print_time); - else - end = strptime (local_time, formats_1[i], &local_print_time); - - if (end != NULL && end[0] == '\0') - break; - } - - if (end != NULL && end[0] == '\0') - { - time_t rawtime; - time (&rawtime); - - actual_utc_time = g_memdup2 (gmtime (&rawtime), sizeof (struct tm)); - actual_local_time = g_memdup2 (localtime (&rawtime), sizeof (struct tm)); - - diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour; - diff_time.tm_min = actual_utc_time->tm_min - actual_local_time->tm_min; - diff_time.tm_sec = actual_utc_time->tm_sec - actual_local_time->tm_sec; - - utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24; - utc_print_time.tm_min = ((local_print_time.tm_min + diff_time.tm_min) + 60) % 60; - utc_print_time.tm_sec = ((local_print_time.tm_sec + diff_time.tm_sec) + 60) % 60; - - utc_time = g_strdup_printf ("%02d:%02d:%02d", - utc_print_time.tm_hour, - utc_print_time.tm_min, - utc_print_time.tm_sec); - } - - return utc_time; -} - static void cups_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, diff --git a/modules/printbackends/gtkprintbackendutils.c b/modules/printbackends/gtkprintbackendutils.c new file mode 100644 index 0000000000..b1c8023468 --- /dev/null +++ b/modules/printbackends/gtkprintbackendutils.c @@ -0,0 +1,128 @@ +/* GTK - The GIMP Toolkit + * gtkprintbackendcups.h: Default implementation of GtkPrintBackend + * for the Common Unix Print System (CUPS) + * Copyright (C) 2006, 2007 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, see . + */ + + +#include +#include + +#include "gtkprintbackendutils.h" + +/* Converts local time to UTC time. Local time has to be in one of these + * formats: HH:MM:SS, HH:MM, HH:MM:SS {am, pm}, HH:MM {am, pm}, HH {am, pm}, + * {am, pm} HH:MM:SS, {am, pm} HH:MM, {am, pm} HH. + * Returns a newly allocated string holding UTC time in HH:MM:SS format + * or NULL. + */ +char * +localtime_to_utctime (const char *local_time) +{ + const char *formats_0[] = {" %I : %M : %S %p ", " %p %I : %M : %S ", + " %H : %M : %S ", + " %I : %M %p ", " %p %I : %M ", + " %H : %M ", + " %I %p ", " %p %I "}; + const char *formats_1[] = {" %H : %M : %S ", " %H : %M "}; + const char *end = NULL; + struct tm *actual_local_time; + struct tm *actual_utc_time; + struct tm local_print_time; + struct tm utc_print_time; + struct tm diff_time; + char *utc_time = NULL; + int i, n; + + if (local_time == NULL || local_time[0] == '\0') + return NULL; + + n = supports_am_pm () ? G_N_ELEMENTS (formats_0) : G_N_ELEMENTS (formats_1); + + for (i = 0; i < n; i++) + { + local_print_time.tm_hour = 0; + local_print_time.tm_min = 0; + local_print_time.tm_sec = 0; + + if (supports_am_pm ()) + end = strptime (local_time, formats_0[i], &local_print_time); + else + end = strptime (local_time, formats_1[i], &local_print_time); + + if (end != NULL && end[0] == '\0') + break; + } + + if (end != NULL && end[0] == '\0') + { + time_t rawtime; + time (&rawtime); + + actual_utc_time = g_memdup2 (gmtime (&rawtime), sizeof (struct tm)); + actual_local_time = g_memdup2 (localtime (&rawtime), sizeof (struct tm)); + + diff_time.tm_hour = actual_utc_time->tm_hour - actual_local_time->tm_hour; + diff_time.tm_min = actual_utc_time->tm_min - actual_local_time->tm_min; + diff_time.tm_sec = actual_utc_time->tm_sec - actual_local_time->tm_sec; + + utc_print_time.tm_hour = ((local_print_time.tm_hour + diff_time.tm_hour) + 24) % 24; + utc_print_time.tm_min = ((local_print_time.tm_min + diff_time.tm_min) + 60) % 60; + utc_print_time.tm_sec = ((local_print_time.tm_sec + diff_time.tm_sec) + 60) % 60; + + utc_time = g_strdup_printf ("%02d:%02d:%02d", + utc_print_time.tm_hour, + utc_print_time.tm_min, + utc_print_time.tm_sec); + } + + return utc_time; +} + +gboolean +supports_am_pm (void) +{ + struct tm tmp_tm = { 0 }; + char time[8]; + int length; + + length = strftime (time, sizeof (time), "%p", &tmp_tm); + + return length != 0; +} + +/* + * Generate a random string of "n" length + */ +char * +random_string (int n) +{ + const char charset[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + + char *str = g_new0 (char, n+1); + getrandom (str, n, 0); + for (int i=0; i. + */ + +#ifndef __GTK_PRINT_BACKEND_UTILS_H__ +#define __GTK_PRINT_BACKEND_UTILS_H__ + +char *random_string (int size); +char *localtime_to_utctime (const char *local_time); +gboolean supports_am_pm (void); + +#endif /* __GTK_PRINT_BACKEND_UTILS_H__ */ \ No newline at end of file diff --git a/modules/printbackends/gtkprintercpdb.c b/modules/printbackends/gtkprintercpdb.c new file mode 100644 index 0000000000..aaf13cbb17 --- /dev/null +++ b/modules/printbackends/gtkprintercpdb.c @@ -0,0 +1,137 @@ +/* GtkPrinterCpdb + * 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 + +enum { + PROP_0, + PROP_PRINTER_OBJ +}; + +static void gtk_printer_cpdb_init (GtkPrinterCpdb *printer); +static void gtk_printer_cpdb_class_init (GtkPrinterCpdbClass *class); + +static GType gtk_printer_cpdb_type = 0; + +static void gtk_printer_cpdb_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_printer_cpdb_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +void +gtk_printer_cpdb_register_type (GTypeModule *module) +{ + const GTypeInfo object_info = + { + sizeof (GtkPrinterCpdbClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gtk_printer_cpdb_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkPrinterCpdb), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_printer_cpdb_init, + }; + + gtk_printer_cpdb_type = g_type_module_register_type (module, + GTK_TYPE_PRINTER, + "GtkPrinterCpdb", + &object_info, 0); +} + +GType +gtk_printer_cpdb_get_type (void) +{ + return gtk_printer_cpdb_type; +} + +static void +gtk_printer_cpdb_class_init (GtkPrinterCpdbClass *klass) +{ + + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gtk_printer_cpdb_set_property; + object_class->get_property = gtk_printer_cpdb_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_PRINTER_OBJ, + g_param_spec_pointer ("printer-obj", + NULL, + NULL, + G_PARAM_READWRITE)); +} + +static void +gtk_printer_cpdb_init (GtkPrinterCpdb *self) +{ +} + +static void +gtk_printer_cpdb_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (object); + switch (prop_id) + { + case PROP_PRINTER_OBJ: + printer_cpdb->printer_obj = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_printer_cpdb_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkPrinterCpdb *printer_cpdb = GTK_PRINTER_CPDB (object); + switch (prop_id) + { + case PROP_PRINTER_OBJ: + g_value_set_pointer (value, printer_cpdb->printer_obj); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +cpdb_printer_obj_t * +gtk_printer_cpdb_get_printer_obj (GtkPrinterCpdb *cpdb_printer) +{ + return cpdb_printer->printer_obj; +} + +void +gtk_printer_cpdb_set_printer_obj (GtkPrinterCpdb *cpdb_printer, + cpdb_printer_obj_t *printer_obj) +{ + cpdb_printer->printer_obj = printer_obj; +} diff --git a/modules/printbackends/gtkprintercpdb.h b/modules/printbackends/gtkprintercpdb.h new file mode 100644 index 0000000000..bca0eebea1 --- /dev/null +++ b/modules/printbackends/gtkprintercpdb.h @@ -0,0 +1,46 @@ +/* GtkPrinterCpdb + * 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 . + */ + + +#ifndef __GTK_PRINTER_CPDB_H__ +#define __GTK_PRINTER_CPDB_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_PRINTER_CPDB (gtk_printer_cpdb_get_type ()) +G_DECLARE_FINAL_TYPE (GtkPrinterCpdb, gtk_printer_cpdb, GTK, PRINTER_CPDB, GtkPrinter) + +struct _GtkPrinterCpdb +{ + GtkPrinter parent_instance; + cpdb_printer_obj_t *printer_obj; +}; + +void gtk_printer_cpdb_register_type (GTypeModule *module); + +cpdb_printer_obj_t *gtk_printer_cpdb_get_printer_obj (GtkPrinterCpdb *cpdb_printer); + +void gtk_printer_cpdb_set_printer_obj (GtkPrinterCpdb *cpdb_printer, + cpdb_printer_obj_t *printer_obj); + +G_END_DECLS + +#endif /* __GTK_PRINTER_CPDB_H__ */ \ No newline at end of file diff --git a/modules/printbackends/meson.build b/modules/printbackends/meson.build index 6e0188f62c..de4effa520 100644 --- a/modules/printbackends/meson.build +++ b/modules/printbackends/meson.build @@ -10,8 +10,27 @@ printbackends_args = [ '-DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED', ] + common_cflags +cpdb_dep = dependency('cpdb-frontend', version : '>=1.0', required: get_option('print-cpdb')) cups_dep = dependency('cups', version : '>=2.0', required: get_option('print-cups')) -if cups_dep.found() + +# Use cpdb backend if present and enabled. +# If not, use cups if present. +# If not, use lpr. + +if get_option('print-cpdb').enabled() and cpdb_dep.found() + print_backends += 'cpdb' + shared_module('printbackend-cpdb', + sources: [ + 'gtkprintbackendcpdb.c', + 'gtkprintercpdb.c', + 'gtkprintbackendutils.c', + ], + c_args: printbackends_args, + dependencies: [libgtk_dep, cpdb_dep], + install_dir: printbackends_install_dir, + install: true, + ) +elif cups_dep.found() print_backends += 'cups' shared_module('printbackend-cups', sources: [ @@ -19,6 +38,7 @@ if cups_dep.found() 'gtkprintercups.c', 'gtkcupsutils.c', 'gtkcupssecretsutils.c', + 'gtkprintbackendutils.c', ], c_args: printbackends_args, dependencies: [libgtk_dep, cups_dep, colord_dep],