mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 22:41:43 +00:00
ade1aaa8be
The job priority strings need context to disambiguate them from similar short strings elsewhere.
1698 lines
61 KiB
C
1698 lines
61 KiB
C
/* GTK - The GIMP Toolkit
|
|
* gtkprintbackendcpdb.h: Default implementation of GtkPrintBackend
|
|
* for the Common Print Dialog Backends (CPDB)
|
|
* Copyright (C) 2022, 2023 TinyTrebuchet <tinytrebuchet@protonmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include <config.h>
|
|
#include <cpdb/frontend.h>
|
|
|
|
#include <gtk/gtkprivate.h>
|
|
#include "gtkprintbackendcpdb.h"
|
|
#include "gtkprintbackendutils.h"
|
|
|
|
#include <cairo.h>
|
|
#include <cairo-pdf.h>
|
|
|
|
#include <glib/gi18n-lib.h>
|
|
#include <gtkprintercpdb.h>
|
|
|
|
#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[] = {
|
|
NC_("Print job priority", "Urgent"),
|
|
NC_("Print job priority", "High"),
|
|
NC_("Print job priority", "Medium"),
|
|
NC_("Print job priority", "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");
|
|
}
|
|
}
|