📄 gtkprintbackendcups.c
字号:
/* 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <config.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <stdlib.h>#include <cups/cups.h>#include <cups/language.h>#include <cups/http.h>#include <cups/ipp.h>#include <errno.h>#include <cairo.h>#include <cairo-pdf.h>#include <cairo-ps.h>#include <glib/gi18n-lib.h>#include <gmodule.h>#include <gtk/gtkprintoperation.h>#include <gtk/gtkprintsettings.h>#include <gtk/gtkprintbackend.h>#include <gtk/gtkprinter.h>#include <gtk/gtkprinter-private.h>#include "gtkprintbackendcups.h"#include "gtkprintercups.h"#include "gtkcupsutils.h"#include "gtkdebug.h"typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;#define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))#define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))#define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))#define _CUPS_MAX_ATTEMPTS 10 #define _CUPS_MAX_CHUNK_SIZE 8192/* define this to see warnings about ignored ppd options */#undef PRINT_IGNORED_OPTIONS#define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}#define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}static GType print_backend_cups_type = 0;typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend, GtkCupsResult *result, gpointer user_data);typedef enum { DISPATCH_SETUP, DISPATCH_REQUEST, DISPATCH_SEND, DISPATCH_CHECK, DISPATCH_READ, DISPATCH_ERROR} GtkPrintCupsDispatchState;typedef struct { GSource source; http_t *http; GtkCupsRequest *request; GPollFD *data_poll; GtkPrintBackendCups *backend;} GtkPrintCupsDispatchWatch;struct _GtkPrintBackendCupsClass{ GtkPrintBackendClass parent_class;};struct _GtkPrintBackendCups{ GtkPrintBackend parent_instance; char *default_printer; guint list_printers_poll; guint list_printers_pending : 1; guint got_default_printer : 1;};static GObjectClass *backend_parent_class;static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class);static void gtk_print_backend_cups_init (GtkPrintBackendCups *impl);static void gtk_print_backend_cups_finalize (GObject *object);static void gtk_print_backend_cups_dispose (GObject *object);static void cups_get_printer_list (GtkPrintBackend *print_backend);static void cups_request_execute (GtkPrintBackendCups *print_backend, GtkCupsRequest *request, GtkPrintCupsResponseCallbackFunc callback, gpointer user_data, GDestroyNotify notify);static void cups_printer_get_settings_from_options (GtkPrinter *printer, GtkPrinterOptionSet *options, GtkPrintSettings *settings);static gboolean cups_printer_mark_conflicts (GtkPrinter *printer, GtkPrinterOptionSet *options);static GtkPrinterOptionSet *cups_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup, GtkPrintCapabilities capabilities);static void cups_printer_prepare_for_print (GtkPrinter *printer, GtkPrintJob *print_job, GtkPrintSettings *settings, GtkPageSetup *page_setup);static GList * cups_printer_list_papers (GtkPrinter *printer);static void cups_printer_request_details (GtkPrinter *printer);static void cups_request_default_printer (GtkPrintBackendCups *print_backend);static void cups_request_ppd (GtkPrinter *printer);static void cups_printer_get_hard_margins (GtkPrinter *printer, double *top, double *bottom, double *left, double *right);static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer);static void set_option_from_settings (GtkPrinterOption *option, GtkPrintSettings *setting);static void cups_begin_polling_info (GtkPrintBackendCups *print_backend, GtkPrintJob *job, int job_id);static gboolean cups_job_info_poll_timeout (gpointer user_data);static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend, GtkPrintJob *job, GIOChannel *data_io, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify);static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer, GtkPrintSettings *settings, gdouble width, gdouble height, GIOChannel *cache_io);static voidgtk_print_backend_cups_register_type (GTypeModule *module){ static const GTypeInfo print_backend_cups_info = { sizeof (GtkPrintBackendCupsClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) gtk_print_backend_cups_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GtkPrintBackendCups), 0, /* n_preallocs */ (GInstanceInitFunc) gtk_print_backend_cups_init }; print_backend_cups_type = g_type_module_register_type (module, GTK_TYPE_PRINT_BACKEND, "GtkPrintBackendCups", &print_backend_cups_info, 0);}G_MODULE_EXPORT void pb_module_init (GTypeModule *module){ GTK_NOTE (PRINTING, g_print ("CUPS Backend: Initializing the CUPS print backend module\n")); gtk_print_backend_cups_register_type (module); gtk_printer_cups_register_type (module);}G_MODULE_EXPORT void pb_module_exit (void){} G_MODULE_EXPORT GtkPrintBackend * pb_module_create (void){ return gtk_print_backend_cups_new ();}/* * GtkPrintBackendCups */GTypegtk_print_backend_cups_get_type (void){ return print_backend_cups_type;}/** * gtk_print_backend_cups_new: * * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups * implements the #GtkPrintBackend interface with direct access to * the filesystem using Unix/Linux API calls * * Return value: the new #GtkPrintBackendCups object */GtkPrintBackend *gtk_print_backend_cups_new (void){ GTK_NOTE (PRINTING, g_print ("CUPS Backend: Creating a new CUPS print backend object\n")); return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);}static voidgtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class){ GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class); backend_parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_print_backend_cups_finalize; gobject_class->dispose = gtk_print_backend_cups_dispose; backend_class->request_printer_list = cups_get_printer_list; backend_class->print_stream = gtk_print_backend_cups_print_stream; backend_class->printer_request_details = cups_printer_request_details; backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface; backend_class->printer_get_options = cups_printer_get_options; backend_class->printer_mark_conflicts = cups_printer_mark_conflicts; backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options; backend_class->printer_prepare_for_print = cups_printer_prepare_for_print; backend_class->printer_list_papers = cups_printer_list_papers; backend_class->printer_get_hard_margins = cups_printer_get_hard_margins; backend_class->printer_get_capabilities = cups_printer_get_capabilities;}static cairo_status_t_cairo_write_to_cups (void *closure, const unsigned char *data, unsigned int length){ GIOChannel *io = (GIOChannel *)closure; gsize written; GError *error; error = NULL; GTK_NOTE (PRINTING, g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length)); while (length > 0) { g_io_channel_write_chars (io, (gchar *)data, length, &written, &error); if (error != NULL) { GTK_NOTE (PRINTING, g_print ("CUPS Backend: Error writing to temp file, %s\n", error->message)); g_error_free (error); return CAIRO_STATUS_WRITE_ERROR; } GTK_NOTE (PRINTING, g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written)); data += written; length -= written; } return CAIRO_STATUS_SUCCESS;}static cairo_surface_t *cups_printer_create_cairo_surface (GtkPrinter *printer, GtkPrintSettings *settings, gdouble width, gdouble height, GIOChannel *cache_io){ cairo_surface_t *surface; /* TODO: check if it is a ps or pdf printer */ surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height); /* TODO: DPI from settings object? */ cairo_surface_set_fallback_resolution (surface, 300, 300); return surface;}typedef struct { GtkPrintJobCompleteFunc callback; GtkPrintJob *job; gpointer user_data; GDestroyNotify dnotify;} CupsPrintStreamData;static voidcups_free_print_stream_data (CupsPrintStreamData *data){ GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s\n", G_STRFUNC)); if (data->dnotify) data->dnotify (data->user_data); g_object_unref (data->job); g_free (data);}static voidcups_print_cb (GtkPrintBackendCups *print_backend, GtkCupsResult *result, gpointer user_data){ GError *error = NULL; CupsPrintStreamData *ps = user_data; GDK_THREADS_ENTER (); GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s\n", G_STRFUNC)); if (gtk_cups_result_is_error (result)) error = g_error_new_literal (gtk_print_error_quark (), GTK_PRINT_ERROR_INTERNAL_ERROR, gtk_cups_result_get_error_string (result)); if (ps->callback) ps->callback (ps->job, ps->user_data, error); if (error == NULL) { int job_id = 0; ipp_attribute_t *attr; /* IPP job-id attribute */ ipp_t *response = gtk_cups_result_get_response (result); if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL) job_id = attr->values[0].integer; if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0) gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED); else { gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING); cups_begin_polling_info (print_backend, ps->job, job_id); } } else gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED); if (error) g_error_free (error); GDK_THREADS_LEAVE (); }static voidadd_cups_options (const gchar *key, const gchar *value, gpointer user_data){ GtkCupsRequest *request = user_data; if (!g_str_has_prefix (key, "cups-")) return; if (strcmp (value, "gtk-ignore-value") == 0) return; key = key + strlen ("cups-"); gtk_cups_request_encode_option (request, key, value);}static voidgtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, GtkPrintJob *job, GIOChannel *data_io, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify){ GtkPrinterCups *cups_printer; CupsPrintStreamData *ps; GtkCupsRequest *request; GtkPrintSettings *settings; const gchar *title; GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s\n", G_STRFUNC)); cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job)); settings = gtk_print_job_get_settings (job); request = gtk_cups_request_new (NULL, GTK_CUPS_POST, IPP_PRINT_JOB, data_io, NULL, cups_printer->device_uri); gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, cups_printer->printer_uri); title = gtk_print_job_get_title (job); if (title) gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); gtk_print_settings_foreach (settings, add_cups_options, request); ps = g_new0 (CupsPrintStreamData, 1); ps->callback = callback; ps->user_data = user_data; ps->dnotify = dnotify; ps->job = g_object_ref (job); cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend), request, (GtkPrintCupsResponseCallbackFunc) cups_print_cb, ps, (GDestroyNotify)cups_free_print_stream_data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -