1 /* GTK - The GIMP Toolkit
2 * gtkprintbackendcups.h: Default implementation of GtkPrintBackend
3 * for the Common Unix Print System (CUPS)
4 * Copyright (C) 2003, Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 #include <sys/types.h>
28 #include <cups/cups.h>
29 #include <cups/language.h>
30 #include <cups/http.h>
34 #include <cairo-pdf.h>
37 #include <glib/gi18n-lib.h>
40 #include <gtk/gtkprintoperation.h>
41 #include <gtk/gtkprintsettings.h>
42 #include <gtk/gtkprintbackend.h>
43 #include <gtk/gtkprinter.h>
45 #include "gtkprintbackendcups.h"
46 #include "gtkprintercups.h"
48 #include "gtkcupsutils.h"
51 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
53 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
54 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
55 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
57 #define _CUPS_MAX_ATTEMPTS 10
58 #define _CUPS_MAX_CHUNK_SIZE 8192
60 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
61 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
63 static GType print_backend_cups_type = 0;
65 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
66 GtkCupsResult *result,
77 } GtkPrintCupsDispatchState;
84 GtkCupsRequest *request;
86 GtkPrintBackendCups *backend;
88 } GtkPrintCupsDispatchWatch;
90 struct _GtkPrintBackendCupsClass
92 GtkPrintBackendClass parent_class;
95 struct _GtkPrintBackendCups
97 GtkPrintBackend parent_instance;
99 char *default_printer;
101 guint list_printers_poll;
102 guint list_printers_pending : 1;
103 guint got_default_printer : 1;
106 static GObjectClass *backend_parent_class;
108 static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class);
109 static void gtk_print_backend_cups_init (GtkPrintBackendCups *impl);
110 static void gtk_print_backend_cups_finalize (GObject *object);
111 static void gtk_print_backend_cups_dispose (GObject *object);
112 static void cups_get_printer_list (GtkPrintBackend *print_backend);
113 static void cups_request_execute (GtkPrintBackendCups *print_backend,
114 GtkCupsRequest *request,
115 GtkPrintCupsResponseCallbackFunc callback,
117 GDestroyNotify notify,
119 static void cups_printer_get_settings_from_options (GtkPrinter *printer,
120 GtkPrinterOptionSet *options,
121 GtkPrintSettings *settings);
122 static gboolean cups_printer_mark_conflicts (GtkPrinter *printer,
123 GtkPrinterOptionSet *options);
124 static GtkPrinterOptionSet *cups_printer_get_options (GtkPrinter *printer,
125 GtkPrintSettings *settings,
126 GtkPageSetup *page_setup);
127 static void cups_printer_prepare_for_print (GtkPrinter *printer,
128 GtkPrintJob *print_job,
129 GtkPrintSettings *settings,
130 GtkPageSetup *page_setup);
131 static GList * cups_printer_list_papers (GtkPrinter *printer);
132 static void cups_printer_request_details (GtkPrinter *printer);
133 static void cups_request_default_printer (GtkPrintBackendCups *print_backend);
134 static void cups_request_ppd (GtkPrinter *printer);
135 static void cups_printer_get_hard_margins (GtkPrinter *printer,
140 static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer);
141 static void set_option_from_settings (GtkPrinterOption *option,
142 GtkPrintSettings *setting);
143 static void cups_begin_polling_info (GtkPrintBackendCups *print_backend,
146 static gboolean cups_job_info_poll_timeout (gpointer user_data);
147 static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend,
150 GtkPrintJobCompleteFunc callback,
152 GDestroyNotify dnotify);
153 static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer,
160 gtk_print_backend_cups_register_type (GTypeModule *module)
162 static const GTypeInfo print_backend_cups_info =
164 sizeof (GtkPrintBackendCupsClass),
165 NULL, /* base_init */
166 NULL, /* base_finalize */
167 (GClassInitFunc) gtk_print_backend_cups_class_init,
168 NULL, /* class_finalize */
169 NULL, /* class_data */
170 sizeof (GtkPrintBackendCups),
172 (GInstanceInitFunc) gtk_print_backend_cups_init
175 print_backend_cups_type = g_type_module_register_type (module,
176 GTK_TYPE_PRINT_BACKEND,
177 "GtkPrintBackendCups",
178 &print_backend_cups_info, 0);
182 pb_module_init (GTypeModule *module)
184 gtk_print_backend_cups_register_type (module);
185 gtk_printer_cups_register_type (module);
189 pb_module_exit (void)
194 G_MODULE_EXPORT GtkPrintBackend *
195 pb_module_create (void)
197 return gtk_print_backend_cups_new ();
201 * GtkPrintBackendCups
204 gtk_print_backend_cups_get_type (void)
206 return print_backend_cups_type;
210 * gtk_print_backend_cups_new:
212 * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
213 * implements the #GtkPrintBackend interface with direct access to
214 * the filesystem using Unix/Linux API calls
216 * Return value: the new #GtkPrintBackendCups object
219 gtk_print_backend_cups_new (void)
221 return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
225 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
227 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
228 GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
230 backend_parent_class = g_type_class_peek_parent (class);
232 gobject_class->finalize = gtk_print_backend_cups_finalize;
233 gobject_class->dispose = gtk_print_backend_cups_dispose;
235 backend_class->request_printer_list = cups_get_printer_list;
236 backend_class->print_stream = gtk_print_backend_cups_print_stream;
237 backend_class->printer_request_details = cups_printer_request_details;
238 backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
239 backend_class->printer_get_options = cups_printer_get_options;
240 backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
241 backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
242 backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
243 backend_class->printer_list_papers = cups_printer_list_papers;
244 backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
245 backend_class->printer_get_capabilities = cups_printer_get_capabilities;
248 static cairo_status_t
249 _cairo_write_to_cups (void *cache_fd_as_pointer,
250 const unsigned char *data,
253 cairo_status_t result;
255 cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
257 result = CAIRO_STATUS_WRITE_ERROR;
259 /* write out the buffer */
260 if (write (cache_fd, data, length) != -1)
261 result = CAIRO_STATUS_SUCCESS;
267 static cairo_surface_t *
268 cups_printer_create_cairo_surface (GtkPrinter *printer,
273 cairo_surface_t *surface;
275 /* TODO: check if it is a ps or pdf printer */
277 surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
279 /* TODO: DPI from settings object? */
280 cairo_ps_surface_set_dpi (surface, 300, 300);
286 GtkPrintJobCompleteFunc callback;
289 GDestroyNotify dnotify;
290 } CupsPrintStreamData;
293 cups_free_print_stream_data (CupsPrintStreamData *data)
296 data->dnotify (data->user_data);
297 g_object_unref (data->job);
302 cups_print_cb (GtkPrintBackendCups *print_backend,
303 GtkCupsResult *result,
306 GError *error = NULL;
307 CupsPrintStreamData *ps = user_data;
309 if (gtk_cups_result_is_error (result))
310 error = g_error_new_literal (gtk_print_error_quark (),
311 GTK_PRINT_ERROR_INTERNAL_ERROR,
312 gtk_cups_result_get_error_string (result));
315 ps->callback (ps->job, ps->user_data, error);
320 ipp_attribute_t *attr; /* IPP job-id attribute */
321 ipp_t *response = gtk_cups_result_get_response (result);
323 if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
324 job_id = attr->values[0].integer;
326 if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
327 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
330 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
331 cups_begin_polling_info (print_backend, ps->job, job_id);
335 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
339 g_error_free (error);
344 add_cups_options (const char *key,
348 GtkCupsRequest *request = user_data;
350 if (!g_str_has_prefix (key, "cups-"))
353 if (strcmp (value, "gtk-ignore-value") == 0)
356 key = key + strlen("cups-");
358 gtk_cups_request_encode_option (request, key, value);
362 gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
365 GtkPrintJobCompleteFunc callback,
367 GDestroyNotify dnotify)
370 GtkPrinterCups *cups_printer;
371 CupsPrintStreamData *ps;
372 GtkCupsRequest *request;
373 GtkPrintSettings *settings;
376 cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
377 settings = gtk_print_job_get_settings (job);
381 request = gtk_cups_request_new (NULL,
386 cups_printer->device_uri);
388 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
389 NULL, cups_printer->printer_uri);
391 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
394 title = gtk_print_job_get_title (job);
396 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
399 gtk_print_settings_foreach (settings, add_cups_options, request);
401 ps = g_new0 (CupsPrintStreamData, 1);
402 ps->callback = callback;
403 ps->user_data = user_data;
404 ps->dnotify = dnotify;
405 ps->job = g_object_ref (job);
407 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
409 (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
411 (GDestroyNotify)cups_free_print_stream_data,
417 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
419 backend_cups->list_printers_poll = 0;
420 backend_cups->list_printers_pending = FALSE;
422 cups_request_default_printer (backend_cups);
426 gtk_print_backend_cups_finalize (GObject *object)
428 GtkPrintBackendCups *backend_cups;
430 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
432 g_free (backend_cups->default_printer);
433 backend_cups->default_printer = NULL;
435 backend_parent_class->finalize (object);
439 gtk_print_backend_cups_dispose (GObject *object)
441 GtkPrintBackendCups *backend_cups;
443 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
445 if (backend_cups->list_printers_poll > 0)
446 g_source_remove (backend_cups->list_printers_poll);
447 backend_cups->list_printers_poll = 0;
449 backend_parent_class->dispose (object);
454 cups_dispatch_watch_check (GSource *source)
456 GtkPrintCupsDispatchWatch *dispatch;
457 GtkCupsPollState poll_state;
460 dispatch = (GtkPrintCupsDispatchWatch *) source;
462 poll_state = gtk_cups_request_get_poll_state (dispatch->request);
464 if (dispatch->data_poll == NULL &&
465 dispatch->request->http != NULL)
467 dispatch->data_poll = g_new0 (GPollFD, 1);
468 dispatch->data_poll->fd = dispatch->request->http->fd;
470 g_source_add_poll (source, dispatch->data_poll);
473 if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
475 if (dispatch->data_poll->fd != dispatch->request->http->fd)
476 dispatch->data_poll->fd = dispatch->request->http->fd;
478 if (poll_state == GTK_CUPS_HTTP_READ)
479 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
480 else if (poll_state == GTK_CUPS_HTTP_WRITE)
481 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
483 dispatch->data_poll->events = 0;
486 if (poll_state != GTK_CUPS_HTTP_IDLE)
487 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
490 result = gtk_cups_request_read_write (dispatch->request);
491 if (result && dispatch->data_poll != NULL)
493 g_source_remove_poll (source, dispatch->data_poll);
494 g_free (dispatch->data_poll);
495 dispatch->data_poll = NULL;
502 cups_dispatch_watch_prepare (GSource *source,
505 GtkPrintCupsDispatchWatch *dispatch;
507 dispatch = (GtkPrintCupsDispatchWatch *) source;
511 return gtk_cups_request_read_write (dispatch->request);
515 cups_dispatch_watch_dispatch (GSource *source,
516 GSourceFunc callback,
519 GtkPrintCupsDispatchWatch *dispatch;
520 GtkPrintCupsResponseCallbackFunc ep_callback;
521 GtkCupsResult *result;
523 g_assert (callback != NULL);
525 ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
527 dispatch = (GtkPrintCupsDispatchWatch *) source;
529 result = gtk_cups_request_get_result (dispatch->request);
531 if (gtk_cups_result_is_error (result))
532 g_warning (gtk_cups_result_get_error_string (result));
534 ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
540 cups_dispatch_watch_finalize (GSource *source)
542 GtkPrintCupsDispatchWatch *dispatch;
544 dispatch = (GtkPrintCupsDispatchWatch *) source;
546 gtk_cups_request_free (dispatch->request);
548 if (dispatch->backend)
550 /* We need to unref this at idle time, because it might be the
551 * last reference to this module causing the code to be
552 * unloaded (including this particular function!)
553 * Update: Doing this at idle caused a deadlock taking the
554 * mainloop context lock while being in a GSource callout for
555 * multithreaded apps. So, for now we just disable unloading
556 * of print backends. See _gtk_print_backend_create for the
559 g_object_unref (dispatch->backend);
560 dispatch->backend = NULL;
563 if (dispatch->data_poll != NULL)
564 g_free (dispatch->data_poll);
567 static GSourceFuncs _cups_dispatch_watch_funcs = {
568 cups_dispatch_watch_prepare,
569 cups_dispatch_watch_check,
570 cups_dispatch_watch_dispatch,
571 cups_dispatch_watch_finalize
576 cups_request_execute (GtkPrintBackendCups *print_backend,
577 GtkCupsRequest *request,
578 GtkPrintCupsResponseCallbackFunc callback,
580 GDestroyNotify notify,
583 GtkPrintCupsDispatchWatch *dispatch;
585 dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
586 sizeof (GtkPrintCupsDispatchWatch));
588 dispatch->request = request;
589 dispatch->backend = g_object_ref (print_backend);
590 dispatch->data_poll = NULL;
592 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
594 g_source_attach ((GSource *) dispatch, NULL);
595 g_source_unref ((GSource *) dispatch);
599 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
600 GtkCupsResult *result,
603 ipp_attribute_t *attr;
606 GtkPrinterCups *cups_printer;
612 gboolean status_changed;
614 g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
616 printer_name = (gchar *)user_data;
617 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
623 cups_printer = GTK_PRINTER_CUPS (printer);
625 if (gtk_cups_result_is_error (result))
627 if (gtk_printer_is_new (printer))
629 gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
634 return; /* TODO: mark as inactive printer */
637 response = gtk_cups_result_get_response (result);
639 /* TODO: determine printer type and use correct icon */
640 gtk_printer_set_icon_name (printer, "printer");
646 for (attr = response->attrs; attr != NULL; attr = attr->next)
651 _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
652 _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
653 _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
654 _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
655 _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
658 status_changed = gtk_printer_set_job_count (printer, job_count);
660 status_changed |= gtk_printer_set_location (printer, loc);
661 status_changed |= gtk_printer_set_description (printer, desc);
662 status_changed |= gtk_printer_set_state_message (printer, state_msg);
665 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
666 "printer-status-changed", printer);
670 cups_request_printer_info (GtkPrintBackendCups *print_backend,
671 const gchar *printer_name)
674 GtkCupsRequest *request;
676 static const char * const pattrs[] = /* Attributes we're interested in */
680 "printer-state-message",
687 request = gtk_cups_request_new (NULL,
689 IPP_GET_PRINTER_ATTRIBUTES,
694 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
696 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
697 "printer-uri", NULL, printer_uri);
699 g_free (printer_uri);
701 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
702 "requested-attributes", G_N_ELEMENTS (pattrs),
705 cups_request_execute (print_backend,
707 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
708 g_strdup (printer_name),
709 (GDestroyNotify) g_free,
716 GtkPrintBackendCups *print_backend;
723 job_object_died (gpointer user_data,
724 GObject *where_the_object_was)
726 CupsJobPollData *data = user_data;
731 cups_job_poll_data_free (CupsJobPollData *data)
734 g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
740 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
741 GtkCupsResult *result,
744 CupsJobPollData *data = user_data;
745 ipp_attribute_t *attr;
750 if (data->job == NULL)
752 cups_job_poll_data_free (data);
758 response = gtk_cups_result_get_response (result);
761 for (attr = response->attrs; attr != NULL; attr = attr->next)
766 _CUPS_MAP_ATTR_INT (attr, state, "job-state");
772 case IPP_JOB_PENDING:
774 case IPP_JOB_STOPPED:
775 gtk_print_job_set_status (data->job,
776 GTK_PRINT_STATUS_PENDING);
778 case IPP_JOB_PROCESSING:
779 gtk_print_job_set_status (data->job,
780 GTK_PRINT_STATUS_PRINTING);
783 case IPP_JOB_CANCELLED:
784 case IPP_JOB_ABORTED:
785 gtk_print_job_set_status (data->job,
786 GTK_PRINT_STATUS_FINISHED_ABORTED);
790 case IPP_JOB_COMPLETED:
791 gtk_print_job_set_status (data->job,
792 GTK_PRINT_STATUS_FINISHED);
797 if (!done && data->job != NULL)
801 if (data->counter < 5)
803 else if (data->counter < 10)
808 g_timeout_add (timeout, cups_job_info_poll_timeout, data);
811 cups_job_poll_data_free (data);
815 cups_request_job_info (CupsJobPollData *data)
818 GtkCupsRequest *request;
823 request = gtk_cups_request_new (NULL,
825 IPP_GET_JOB_ATTRIBUTES,
830 printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
831 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
832 "job-uri", NULL, printer_uri);
833 g_free (printer_uri);
835 cups_request_execute (data->print_backend,
837 (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
844 cups_job_info_poll_timeout (gpointer user_data)
846 CupsJobPollData *data = user_data;
848 if (data->job == NULL)
849 cups_job_poll_data_free (data);
851 cups_request_job_info (data);
857 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
861 CupsJobPollData *data;
863 data = g_new0 (CupsJobPollData, 1);
865 data->print_backend = print_backend;
867 data->job_id = job_id;
870 g_object_weak_ref (G_OBJECT (job), job_object_died, data);
872 cups_request_job_info (data);
876 mark_printer_inactive (GtkPrinter *printer,
877 GtkPrintBackend *backend)
879 gtk_printer_set_is_active (printer, FALSE);
880 g_signal_emit_by_name (backend,
881 "printer-removed", printer);
885 find_printer (GtkPrinter *printer, const char *find_name)
887 const char *printer_name;
889 printer_name = gtk_printer_get_name (printer);
890 return g_ascii_strcasecmp (printer_name, find_name);
894 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
895 GtkCupsResult *result,
898 ipp_attribute_t *attr;
900 gboolean list_has_changed;
901 GList *removed_printer_checklist;
903 list_has_changed = FALSE;
905 g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
907 cups_backend->list_printers_pending = FALSE;
909 if (gtk_cups_result_is_error (result))
911 g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
915 /* gether the names of the printers in the current queue
916 so we may check to see if they were removed */
917 removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
919 response = gtk_cups_result_get_response (result);
922 for (attr = response->attrs; attr != NULL; attr = attr->next)
925 const gchar *printer_name;
926 const char *printer_uri;
927 const char *member_uris;
931 * Skip leading attributes until we hit a printer...
933 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
942 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
944 if (!strcmp(attr->name, "printer-name") &&
945 attr->value_tag == IPP_TAG_NAME)
946 printer_name = attr->values[0].string.text;
947 else if (!strcmp(attr->name, "printer-uri-supported") &&
948 attr->value_tag == IPP_TAG_URI)
949 printer_uri = attr->values[0].string.text;
950 else if (!strcmp(attr->name, "member-uris") &&
951 attr->value_tag == IPP_TAG_URI)
952 member_uris = attr->values[0].string.text;
957 if (printer_name == NULL ||
958 (printer_uri == NULL && member_uris == NULL))
966 /* remove name from checklist if it was found */
967 node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
968 removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
970 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
973 GtkPrinterCups *cups_printer;
974 char uri[HTTP_MAX_URI], /* Printer URI */
975 method[HTTP_MAX_URI], /* Method/scheme name */
976 username[HTTP_MAX_URI], /* Username:password */
977 hostname[HTTP_MAX_URI], /* Hostname */
978 resource[HTTP_MAX_URI]; /* Resource name */
979 int port; /* Port number */
981 list_has_changed = TRUE;
982 cups_printer = gtk_printer_cups_new (printer_name,
983 GTK_PRINT_BACKEND (cups_backend));
985 cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
989 cups_printer->printer_uri = g_strdup (member_uris);
992 cups_printer->printer_uri = g_strdup (printer_uri);
994 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
995 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
996 method, sizeof (method),
997 username, sizeof (username),
998 hostname, sizeof (hostname),
1000 resource, sizeof (resource));
1003 httpSeparate (cups_printer->printer_uri,
1011 gethostname(uri, sizeof(uri));
1012 if (strcasecmp(uri, hostname) == 0)
1013 strcpy(hostname, "localhost");
1015 cups_printer->hostname = g_strdup (hostname);
1016 cups_printer->port = port;
1018 printer = GTK_PRINTER (cups_printer);
1020 if (cups_backend->default_printer != NULL &&
1021 strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1022 gtk_printer_set_is_default (printer, TRUE);
1025 gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
1028 g_object_ref (printer);
1030 if (!gtk_printer_is_active (printer))
1032 gtk_printer_set_is_active (printer, TRUE);
1033 gtk_printer_set_is_new (printer, TRUE);
1034 list_has_changed = TRUE;
1037 if (gtk_printer_is_new (printer))
1039 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
1043 gtk_printer_set_is_new (printer, FALSE);
1046 cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1048 /* The ref is held by GtkPrintBackend, in add_printer() */
1049 g_object_unref (printer);
1056 /* look at the removed printers checklist and mark any printer
1057 as inactive if it is in the list, emitting a printer_removed signal */
1058 if (removed_printer_checklist != NULL)
1060 g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
1061 GTK_PRINT_BACKEND (cups_backend));
1062 g_list_free (removed_printer_checklist);
1063 list_has_changed = TRUE;
1066 if (list_has_changed)
1067 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
1069 gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
1073 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1076 GtkCupsRequest *request;
1077 static const char * const pattrs[] = /* Attributes we're interested in */
1080 "printer-uri-supported",
1084 if (cups_backend->list_printers_pending ||
1085 !cups_backend->got_default_printer)
1088 cups_backend->list_printers_pending = TRUE;
1092 request = gtk_cups_request_new (NULL,
1099 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1100 "requested-attributes", G_N_ELEMENTS (pattrs),
1103 cups_request_execute (cups_backend,
1105 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1115 cups_get_printer_list (GtkPrintBackend *backend)
1117 GtkPrintBackendCups *cups_backend;
1119 cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1120 if (cups_backend->list_printers_poll == 0)
1122 cups_request_printer_list (cups_backend);
1123 cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
1124 (GSourceFunc) cups_request_printer_list,
1130 GtkPrinterCups *printer;
1132 gchar *ppd_filename;
1136 get_ppd_data_free (GetPPDData *data)
1138 close (data->ppd_fd);
1139 unlink (data->ppd_filename);
1140 g_free (data->ppd_filename);
1141 g_object_unref (data->printer);
1146 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1147 GtkCupsResult *result,
1151 GtkPrinter *printer;
1153 printer = GTK_PRINTER (data->printer);
1154 GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1156 if (gtk_cups_result_is_error (result))
1158 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1162 response = gtk_cups_result_get_response (result);
1164 data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
1165 gtk_printer_set_has_details (printer, TRUE);
1166 g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
1170 cups_request_ppd (GtkPrinter *printer)
1173 GtkPrintBackend *print_backend;
1174 GtkPrinterCups *cups_printer;
1175 GtkCupsRequest *request;
1180 cups_printer = GTK_PRINTER_CUPS (printer);
1184 http = httpConnectEncrypt(cups_printer->hostname,
1188 data = g_new0 (GetPPDData, 1);
1190 data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
1191 &data->ppd_filename,
1196 g_warning ("%s", error->message);
1197 g_error_free (error);
1201 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1205 fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
1207 data->printer = g_object_ref (printer);
1209 resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
1210 request = gtk_cups_request_new (http,
1214 cups_printer->hostname,
1219 cups_printer->reading_ppd = TRUE;
1221 print_backend = gtk_printer_get_backend (printer);
1223 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1225 (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1227 (GDestroyNotify)get_ppd_data_free,
1233 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1234 GtkCupsResult *result,
1238 ipp_attribute_t *attr;
1240 response = gtk_cups_result_get_response (result);
1242 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
1243 print_backend->default_printer = g_strdup (attr->values[0].string.text);
1245 print_backend->got_default_printer = TRUE;
1247 /* Make sure to kick off get_printers if we are polling it, as we could
1248 have blocked this reading the default printer */
1249 if (print_backend->list_printers_poll != 0)
1250 cups_request_printer_list (print_backend);
1254 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1257 GtkCupsRequest *request;
1262 if ((str = getenv("LPDEST")) != NULL)
1264 print_backend->default_printer = g_strdup (str);
1265 print_backend->got_default_printer = TRUE;
1268 else if ((str = getenv("PRINTER")) != NULL &&
1269 strcmp(str, "lp") != 0)
1271 print_backend->default_printer = g_strdup (str);
1272 print_backend->got_default_printer = TRUE;
1276 request = gtk_cups_request_new (NULL,
1283 cups_request_execute (print_backend,
1285 (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1286 g_object_ref (print_backend),
1293 cups_printer_request_details (GtkPrinter *printer)
1295 GtkPrinterCups *cups_printer;
1297 cups_printer = GTK_PRINTER_CUPS (printer);
1298 if (!cups_printer->reading_ppd &&
1299 gtk_printer_cups_get_ppd (cups_printer) == NULL)
1300 cups_request_ppd (printer);
1304 ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
1306 const char *encoding = NULL;
1309 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1311 return g_strdup (text);
1313 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1315 encoding = "ISO-8859-1";
1317 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1319 encoding = "ISO-8859-2";
1321 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1323 encoding = "ISO-8859-5";
1325 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1327 encoding = "SHIFT-JIS";
1329 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1331 encoding = "MACINTOSH";
1333 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1335 encoding = "WINDOWS-1252";
1339 /* Fallback, try iso-8859-1... */
1340 encoding = "ISO-8859-1";
1343 res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1347 g_warning ("unable to convert PPD text");
1348 res = g_strdup ("???");
1354 /* TODO: Add more translations for common settings here */
1356 static const struct {
1357 const char *keyword;
1358 const char *translation;
1359 } cups_option_translations[] = {
1360 { "Duplex", N_("Two Sided") },
1361 { "MediaType", N_("Paper Type") },
1362 { "InputSlot", N_("Paper Source") },
1363 { "OutputBin", N_("Output Tray") },
1367 static const struct {
1368 const char *keyword;
1370 const char *translation;
1371 } cups_choice_translations[] = {
1372 { "Duplex", "None", N_("One Sided") },
1373 { "InputSlot", "Auto", N_("Auto Select") },
1374 { "InputSlot", "AutoSelect", N_("Auto Select") },
1375 { "InputSlot", "Default", N_("Printer Default") },
1376 { "InputSlot", "None", N_("Printer Default") },
1377 { "InputSlot", "PrinterDefault", N_("Printer Default") },
1378 { "InputSlot", "Unspecified", N_("Auto Select") },
1381 static const struct {
1382 const char *ppd_keyword;
1384 } option_names[] = {
1385 {"Duplex", "gtk-duplex" },
1386 {"MediaType", "gtk-paper-type"},
1387 {"InputSlot", "gtk-paper-source"},
1388 {"OutputBin", "gtk-output-tray"},
1391 /* keep sorted when changing */
1392 static const char *color_option_whitelist[] = {
1393 "BRColorEnhancement",
1399 "BlackSubstitution",
1407 "RPSBlackOverPrint",
1411 /* keep sorted when changing */
1412 static const char *color_group_whitelist[] = {
1419 "HPColorOptionsPanel",
1422 /* keep sorted when changing */
1423 static const char *image_quality_option_whitelist[] = {
1425 "BRHalfTonePattern",
1435 "HPGraphicsHalftone",
1450 /* keep sorted when changing */
1451 static const char *image_quality_group_whitelist[] = {
1458 /* keep sorted when changing */
1459 static const char * finishing_option_whitelist[] = {
1472 "StapleOrientation",
1478 /* keep sorted when changing */
1479 static const char *finishing_group_whitelist[] = {
1488 /* keep sorted when changing */
1489 static const char *cups_option_blacklist[] = {
1498 get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
1503 for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1505 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1506 return g_strdup (_(cups_option_translations[i].translation));
1509 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1511 /* Some ppd files have spaces in the text before the colon */
1518 get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
1521 ppd_option_t *option = choice->option;
1522 const char *keyword = option->keyword;
1524 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1526 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1527 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1528 return g_strdup (_(cups_choice_translations[i].translation));
1530 return ppd_text_to_utf8 (ppd_file, choice->text);
1534 group_has_option (ppd_group_t *group, ppd_option_t *option)
1541 if (group->num_options > 0 &&
1542 option >= group->options && option < group->options + group->num_options)
1545 for (i = 0; i < group->num_subgroups; i++)
1547 if (group_has_option (&group->subgroups[i],option))
1554 set_option_off (GtkPrinterOption *option)
1556 /* Any of these will do, _set only applies the value
1557 * if its allowed of the option */
1558 gtk_printer_option_set (option, "False");
1559 gtk_printer_option_set (option, "Off");
1560 gtk_printer_option_set (option, "None");
1564 value_is_off (const char *value)
1566 return (strcasecmp (value, "None") == 0 ||
1567 strcasecmp (value, "Off") == 0 ||
1568 strcasecmp (value, "False") == 0);
1572 available_choices (ppd_file_t *ppd,
1573 ppd_option_t *option,
1574 ppd_choice_t ***available,
1575 gboolean keep_if_only_one_option)
1577 ppd_option_t *other_option;
1580 ppd_const_t *constraint;
1581 const char *choice, *other_choice;
1582 ppd_option_t *option1, *option2;
1583 ppd_group_t *installed_options;
1585 gboolean all_default;
1591 conflicts = g_new0 (char, option->num_choices);
1593 installed_options = NULL;
1594 for (i = 0; i < ppd->num_groups; i++)
1596 if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
1598 installed_options = &ppd->groups[i];
1603 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1605 option1 = ppdFindOption (ppd, constraint->option1);
1606 if (option1 == NULL)
1609 option2 = ppdFindOption (ppd, constraint->option2);
1610 if (option2 == NULL)
1613 if (option == option1)
1615 choice = constraint->choice1;
1616 other_option = option2;
1617 other_choice = constraint->choice2;
1619 else if (option == option2)
1621 choice = constraint->choice2;
1622 other_option = option1;
1623 other_choice = constraint->choice1;
1628 /* We only care of conflicts with installed_options and
1630 if (!group_has_option (installed_options, other_option) &&
1631 (strcmp (other_option->keyword, "PageSize") != 0))
1634 if (*other_choice == 0)
1636 /* Conflict only if the installed option is not off */
1637 if (value_is_off (other_option->defchoice))
1640 /* Conflict if the installed option has the specified default */
1641 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1646 /* Conflict with all non-off choices */
1647 for (j = 0; j < option->num_choices; j++)
1649 if (!value_is_off (option->choices[j].choice))
1655 for (j = 0; j < option->num_choices; j++)
1657 if (strcasecmp (option->choices[j].choice, choice) == 0)
1665 for (j = 0; j < option->num_choices; j++)
1669 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1670 all_default = FALSE;
1673 if (all_default && !keep_if_only_one_option)
1676 if (num_conflicts == option->num_choices)
1680 /* Some ppds don't have a "use printer default" option for
1681 InputSlot. This means you always have to select a particular slot,
1682 and you can't auto-pick source based on the paper size. To support
1683 this we always add an auto option if there isn't one already. If
1684 the user chooses the generated option we don't send any InputSlot
1685 value when printing. The way we detect existing auto-cases is based
1686 on feedback from Michael Sweet of cups fame.
1689 if (strcmp (option->keyword, "InputSlot") == 0)
1691 gboolean found_auto = FALSE;
1692 for (j = 0; j < option->num_choices; j++)
1696 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1697 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1698 strcmp (option->choices[j].choice, "Default") == 0 ||
1699 strcmp (option->choices[j].choice, "None") == 0 ||
1700 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1701 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1702 option->choices[j].code == NULL ||
1703 option->choices[j].code[0] == 0)
1718 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1721 for (j = 0; j < option->num_choices; j++)
1724 (*available)[i++] = &option->choices[j];
1728 (*available)[i++] = NULL;
1731 return option->num_choices - num_conflicts + add_auto;
1734 static GtkPrinterOption *
1735 create_pickone_option (ppd_file_t *ppd_file,
1736 ppd_option_t *ppd_option,
1737 const char *gtk_name)
1739 GtkPrinterOption *option;
1740 ppd_choice_t **available;
1745 g_assert (ppd_option->ui == PPD_UI_PICKONE);
1749 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1752 label = get_option_text (ppd_file, ppd_option);
1753 option = gtk_printer_option_new (gtk_name, label,
1754 GTK_PRINTER_OPTION_TYPE_PICKONE);
1757 gtk_printer_option_allocate_choices (option, n_choices);
1758 for (i = 0; i < n_choices; i++)
1760 if (available[i] == NULL)
1762 /* This was auto-added */
1763 option->choices[i] = g_strdup ("gtk-ignore-value");
1764 option->choices_display[i] = g_strdup (_("Printer Default"));
1768 option->choices[i] = g_strdup (available[i]->choice);
1769 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1772 gtk_printer_option_set (option, ppd_option->defchoice);
1774 #ifdef PRINT_IGNORED_OPTIONS
1776 g_warning ("Ignoring pickone %s\n", ppd_option->text);
1783 static GtkPrinterOption *
1784 create_boolean_option (ppd_file_t *ppd_file,
1785 ppd_option_t *ppd_option,
1786 const char *gtk_name)
1788 GtkPrinterOption *option;
1789 ppd_choice_t **available;
1793 g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1797 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1800 label = get_option_text (ppd_file, ppd_option);
1801 option = gtk_printer_option_new (gtk_name, label,
1802 GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1805 gtk_printer_option_allocate_choices (option, 2);
1806 option->choices[0] = g_strdup ("True");
1807 option->choices_display[0] = g_strdup ("True");
1808 option->choices[1] = g_strdup ("True");
1809 option->choices_display[1] = g_strdup ("True");
1811 gtk_printer_option_set (option, ppd_option->defchoice);
1813 #ifdef PRINT_IGNORED_OPTIONS
1815 g_warning ("Ignoring boolean %s\n", ppd_option->text);
1823 get_option_name (const char *keyword)
1827 for (i = 0; i < G_N_ELEMENTS (option_names); i++)
1828 if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
1829 return g_strdup (option_names[i].name);
1831 return g_strdup_printf ("cups-%s", keyword);
1835 strptr_cmp (const void *a, const void *b)
1837 char **aa = (char **)a;
1838 char **bb = (char **)b;
1839 return strcmp (*aa, *bb);
1844 string_in_table (char *str, const char *table[], int table_len)
1846 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
1849 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
1852 handle_option (GtkPrinterOptionSet *set,
1853 ppd_file_t *ppd_file,
1854 ppd_option_t *ppd_option,
1855 ppd_group_t *toplevel_group,
1856 GtkPrintSettings *settings)
1858 GtkPrinterOption *option;
1861 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
1864 name = get_option_name (ppd_option->keyword);
1867 if (ppd_option->ui == PPD_UI_PICKONE)
1869 option = create_pickone_option (ppd_file, ppd_option, name);
1871 else if (ppd_option->ui == PPD_UI_BOOLEAN)
1873 option = create_boolean_option (ppd_file, ppd_option, name);
1876 g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
1881 if (STRING_IN_TABLE (toplevel_group->name,
1882 color_group_whitelist) ||
1883 STRING_IN_TABLE (ppd_option->keyword,
1884 color_option_whitelist))
1886 option->group = g_strdup ("ColorPage");
1888 else if (STRING_IN_TABLE (toplevel_group->name,
1889 image_quality_group_whitelist) ||
1890 STRING_IN_TABLE (ppd_option->keyword,
1891 image_quality_option_whitelist))
1893 option->group = g_strdup ("ImageQualityPage");
1895 else if (STRING_IN_TABLE (toplevel_group->name,
1896 finishing_group_whitelist) ||
1897 STRING_IN_TABLE (ppd_option->keyword,
1898 finishing_option_whitelist))
1900 option->group = g_strdup ("FinishingPage");
1904 option->group = g_strdup (toplevel_group->text);
1907 set_option_from_settings (option, settings);
1909 gtk_printer_option_set_add (set, option);
1916 handle_group (GtkPrinterOptionSet *set,
1917 ppd_file_t *ppd_file,
1919 ppd_group_t *toplevel_group,
1920 GtkPrintSettings *settings)
1924 /* Ignore installable options */
1925 if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
1928 for (i = 0; i < group->num_options; i++)
1929 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
1931 for (i = 0; i < group->num_subgroups; i++)
1932 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
1936 static GtkPrinterOptionSet *
1937 cups_printer_get_options (GtkPrinter *printer,
1938 GtkPrintSettings *settings,
1939 GtkPageSetup *page_setup)
1941 GtkPrinterOptionSet *set;
1942 GtkPrinterOption *option;
1943 ppd_file_t *ppd_file;
1945 char *print_at[] = { "now", "at", "on-hold" };
1946 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
1947 char *prio[] = {"100", "80", "50", "30" };
1948 char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
1949 char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
1950 char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
1953 set = gtk_printer_option_set_new ();
1955 /* Cups specific, non-ppd related settings */
1957 option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
1958 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
1960 gtk_printer_option_set (option, "1");
1961 set_option_from_settings (option, settings);
1962 gtk_printer_option_set_add (set, option);
1963 g_object_unref (option);
1965 for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
1966 prio_display[i] = _(prio_display[i]);
1968 option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
1969 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
1970 prio, prio_display);
1971 gtk_printer_option_set (option, "50");
1972 set_option_from_settings (option, settings);
1973 gtk_printer_option_set_add (set, option);
1974 g_object_unref (option);
1976 option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
1977 gtk_printer_option_set (option, "");
1978 set_option_from_settings (option, settings);
1979 gtk_printer_option_set_add (set, option);
1980 g_object_unref (option);
1982 for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
1983 cover_display[i] = _(cover_display[i]);
1985 option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
1986 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1987 cover, cover_display);
1988 gtk_printer_option_set (option, "none");
1989 set_option_from_settings (option, settings);
1990 gtk_printer_option_set_add (set, option);
1991 g_object_unref (option);
1993 option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
1994 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1995 cover, cover_display);
1996 gtk_printer_option_set (option, "none");
1997 set_option_from_settings (option, settings);
1998 gtk_printer_option_set_add (set, option);
1999 g_object_unref (option);
2001 option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
2002 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2003 print_at, print_at);
2004 gtk_printer_option_set (option, "now");
2005 set_option_from_settings (option, settings);
2006 gtk_printer_option_set_add (set, option);
2007 g_object_unref (option);
2009 option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2010 gtk_printer_option_set (option, "");
2011 set_option_from_settings (option, settings);
2012 gtk_printer_option_set_add (set, option);
2013 g_object_unref (option);
2015 /* Printer (ppd) specific settings */
2016 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2019 GtkPaperSize *paper_size;
2020 ppd_option_t *option;
2022 ppdMarkDefaults (ppd_file);
2024 paper_size = gtk_page_setup_get_paper_size (page_setup);
2026 option = ppdFindOption(ppd_file, "PageSize");
2027 strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
2030 for (i = 0; i < ppd_file->num_groups; i++)
2031 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2039 mark_option_from_set (GtkPrinterOptionSet *set,
2040 ppd_file_t *ppd_file,
2041 ppd_option_t *ppd_option)
2043 GtkPrinterOption *option;
2044 char *name = get_option_name (ppd_option->keyword);
2046 option = gtk_printer_option_set_lookup (set, name);
2049 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2056 mark_group_from_set (GtkPrinterOptionSet *set,
2057 ppd_file_t *ppd_file,
2062 for (i = 0; i < group->num_options; i++)
2063 mark_option_from_set (set, ppd_file, &group->options[i]);
2065 for (i = 0; i < group->num_subgroups; i++)
2066 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2070 set_conflicts_from_option (GtkPrinterOptionSet *set,
2071 ppd_file_t *ppd_file,
2072 ppd_option_t *ppd_option)
2074 GtkPrinterOption *option;
2076 if (ppd_option->conflicted)
2078 name = get_option_name (ppd_option->keyword);
2079 option = gtk_printer_option_set_lookup (set, name);
2082 gtk_printer_option_set_has_conflict (option, TRUE);
2084 g_warning ("conflict for option %s ignored", ppd_option->keyword);
2091 set_conflicts_from_group (GtkPrinterOptionSet *set,
2092 ppd_file_t *ppd_file,
2097 for (i = 0; i < group->num_options; i++)
2098 set_conflicts_from_option (set, ppd_file, &group->options[i]);
2100 for (i = 0; i < group->num_subgroups; i++)
2101 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2105 cups_printer_mark_conflicts (GtkPrinter *printer,
2106 GtkPrinterOptionSet *options)
2108 ppd_file_t *ppd_file;
2112 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2114 if (ppd_file == NULL)
2117 ppdMarkDefaults (ppd_file);
2119 for (i = 0; i < ppd_file->num_groups; i++)
2120 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2122 num_conflicts = ppdConflicts (ppd_file);
2124 if (num_conflicts > 0)
2126 for (i = 0; i < ppd_file->num_groups; i++)
2127 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2130 return num_conflicts > 0;
2134 GtkPrinter *printer;
2135 GtkPrinterOptionSet *options;
2136 GtkPrintSettings *settings;
2137 ppd_file_t *ppd_file;
2142 const char *standard;
2146 map_settings_to_option (GtkPrinterOption *option,
2147 const NameMapping table[],
2149 GtkPrintSettings *settings,
2150 const char *standard_name,
2151 const char *cups_name)
2155 const char *cups_value;
2156 const char *standard_value;
2158 /* If the cups-specific setting is set, always use that */
2160 name = g_strdup_printf ("cups-%s", cups_name);
2161 cups_value = gtk_print_settings_get (settings, name);
2164 if (cups_value != NULL) {
2165 gtk_printer_option_set (option, cups_value);
2169 /* Otherwise we try to convert from the general setting */
2170 standard_value = gtk_print_settings_get (settings, standard_name);
2171 if (standard_value == NULL)
2174 for (i = 0; i < n_elements; i++)
2176 if (table[i].cups == NULL && table[i].standard == NULL)
2178 gtk_printer_option_set (option, standard_value);
2181 else if (table[i].cups == NULL &&
2182 strcmp (table[i].standard, standard_value) == 0)
2184 set_option_off (option);
2187 else if (strcmp (table[i].standard, standard_value) == 0)
2189 gtk_printer_option_set (option, table[i].cups);
2196 map_option_to_settings (const char *value,
2197 const NameMapping table[],
2199 GtkPrintSettings *settings,
2200 const char *standard_name,
2201 const char *cups_name)
2206 for (i = 0; i < n_elements; i++)
2208 if (table[i].cups == NULL && table[i].standard == NULL)
2210 gtk_print_settings_set (settings,
2215 else if (table[i].cups == NULL && table[i].standard != NULL)
2217 if (value_is_off (value))
2219 gtk_print_settings_set (settings,
2225 else if (strcmp (table[i].cups, value) == 0)
2227 gtk_print_settings_set (settings,
2234 /* Always set the corresponding cups-specific setting */
2235 name = g_strdup_printf ("cups-%s", cups_name);
2236 gtk_print_settings_set (settings, name, value);
2241 static const NameMapping paper_source_map[] = {
2242 { "Lower", "lower"},
2243 { "Middle", "middle"},
2244 { "Upper", "upper"},
2246 { "Envelope", "envelope"},
2247 { "Cassette", "cassette"},
2248 { "LargeCapacity", "large-capacity"},
2249 { "AnySmallFormat", "small-format"},
2250 { "AnyLargeFormat", "large-format"},
2254 static const NameMapping output_tray_map[] = {
2255 { "Upper", "upper"},
2256 { "Lower", "lower"},
2261 static const NameMapping duplex_map[] = {
2262 { "DuplexTumble", "vertical" },
2263 { "DuplexNoTumble", "horizontal" },
2267 static const NameMapping output_mode_map[] = {
2268 { "Standard", "normal" },
2269 { "Normal", "normal" },
2270 { "Draft", "draft" },
2271 { "Fast", "draft" },
2274 static const NameMapping media_type_map[] = {
2275 { "Transparency", "transparency"},
2276 { "Standard", "stationery"},
2280 static const NameMapping all_map[] = {
2286 set_option_from_settings (GtkPrinterOption *option,
2287 GtkPrintSettings *settings)
2289 const char *cups_value;
2292 if (settings == NULL)
2295 if (strcmp (option->name, "gtk-paper-source") == 0)
2296 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2297 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2298 else if (strcmp (option->name, "gtk-output-tray") == 0)
2299 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2300 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2301 else if (strcmp (option->name, "gtk-duplex") == 0)
2302 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2303 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2304 else if (strcmp (option->name, "cups-OutputMode") == 0)
2305 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2306 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2307 else if (strcmp (option->name, "cups-Resolution") == 0)
2309 cups_value = gtk_print_settings_get (settings, option->name);
2311 gtk_printer_option_set (option, cups_value);
2314 int res = gtk_print_settings_get_resolution (settings);
2317 value = g_strdup_printf ("%ddpi", res);
2318 gtk_printer_option_set (option, value);
2323 else if (strcmp (option->name, "gtk-paper-type") == 0)
2324 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2325 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2326 else if (strcmp (option->name, "gtk-n-up") == 0)
2328 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2329 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2331 else if (strcmp (option->name, "gtk-billing-info") == 0)
2333 cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2335 gtk_printer_option_set (option, cups_value);
2337 else if (strcmp (option->name, "gtk-job-prio") == 0)
2339 cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2341 gtk_printer_option_set (option, cups_value);
2343 else if (strcmp (option->name, "gtk-cover-before") == 0)
2345 cups_value = gtk_print_settings_get (settings, "cover-before");
2347 gtk_printer_option_set (option, cups_value);
2349 else if (strcmp (option->name, "gtk-cover-after") == 0)
2351 cups_value = gtk_print_settings_get (settings, "cover-after");
2353 gtk_printer_option_set (option, cups_value);
2355 else if (strcmp (option->name, "gtk-print-time") == 0)
2357 cups_value = gtk_print_settings_get (settings, "print-at");
2359 gtk_printer_option_set (option, cups_value);
2361 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2363 cups_value = gtk_print_settings_get (settings, "print-at-time");
2365 gtk_printer_option_set (option, cups_value);
2367 else if (g_str_has_prefix (option->name, "cups-"))
2369 cups_value = gtk_print_settings_get (settings, option->name);
2371 gtk_printer_option_set (option, cups_value);
2376 foreach_option_get_settings (GtkPrinterOption *option,
2379 struct OptionData *data = user_data;
2380 GtkPrintSettings *settings = data->settings;
2383 value = option->value;
2385 if (strcmp (option->name, "gtk-paper-source") == 0)
2386 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2387 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2388 else if (strcmp (option->name, "gtk-output-tray") == 0)
2389 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2390 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2391 else if (strcmp (option->name, "gtk-duplex") == 0)
2392 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2393 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2394 else if (strcmp (option->name, "cups-OutputMode") == 0)
2395 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2396 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2397 else if (strcmp (option->name, "cups-Resolution") == 0)
2399 int res = atoi (value);
2400 /* TODO: What if resolution is on XXXxYYYdpi form? */
2402 gtk_print_settings_set_resolution (settings, res);
2403 gtk_print_settings_set (settings, option->name, value);
2405 else if (strcmp (option->name, "gtk-paper-type") == 0)
2406 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2407 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2408 else if (strcmp (option->name, "gtk-n-up") == 0)
2409 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2410 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2411 else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2412 gtk_print_settings_set (settings, "cups-job-billing", value);
2413 else if (strcmp (option->name, "gtk-job-prio") == 0)
2414 gtk_print_settings_set (settings, "cups-job-priority", value);
2415 else if (strcmp (option->name, "gtk-cover-before") == 0)
2416 gtk_print_settings_set (settings, "cover-before", value);
2417 else if (strcmp (option->name, "gtk-cover-after") == 0)
2418 gtk_print_settings_set (settings, "cover-after", value);
2419 else if (strcmp (option->name, "gtk-print-time") == 0)
2420 gtk_print_settings_set (settings, "print-at", value);
2421 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2422 gtk_print_settings_set (settings, "print-at-time", value);
2423 else if (g_str_has_prefix (option->name, "cups-"))
2424 gtk_print_settings_set (settings, option->name, value);
2428 cups_printer_get_settings_from_options (GtkPrinter *printer,
2429 GtkPrinterOptionSet *options,
2430 GtkPrintSettings *settings)
2432 struct OptionData data;
2433 const char *print_at, *print_at_time;
2435 data.printer = printer;
2436 data.options = options;
2437 data.settings = settings;
2438 data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2440 if (data.ppd_file != NULL)
2442 GtkPrinterOption *cover_before, *cover_after;
2444 gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2446 cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2447 cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2448 if (cover_before && cover_after)
2450 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2451 gtk_print_settings_set (settings, "cups-job-sheets", value);
2455 print_at = gtk_print_settings_get (settings, "print-at");
2456 print_at_time = gtk_print_settings_get (settings, "print-at-time");
2457 if (strcmp (print_at, "at") == 0)
2458 gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2459 else if (strcmp (print_at, "on-hold") == 0)
2460 gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2465 cups_printer_prepare_for_print (GtkPrinter *printer,
2466 GtkPrintJob *print_job,
2467 GtkPrintSettings *settings,
2468 GtkPageSetup *page_setup)
2470 GtkPageSet page_set;
2471 GtkPaperSize *paper_size;
2472 const char *ppd_paper_name;
2475 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2476 print_job->page_ranges = NULL;
2477 print_job->num_page_ranges = 0;
2479 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2480 print_job->page_ranges =
2481 gtk_print_settings_get_page_ranges (settings,
2482 &print_job->num_page_ranges);
2484 if (gtk_print_settings_get_collate (settings))
2485 gtk_print_settings_set (settings, "cups-Collate", "True");
2486 print_job->collate = FALSE;
2488 if (gtk_print_settings_get_reverse (settings))
2489 gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2490 print_job->reverse = FALSE;
2492 if (gtk_print_settings_get_n_copies (settings) > 1)
2493 gtk_print_settings_set_int (settings, "cups-copies",
2494 gtk_print_settings_get_n_copies (settings));
2495 print_job->num_copies = 1;
2497 scale = gtk_print_settings_get_scale (settings);
2498 print_job->scale = 1.0;
2500 print_job->scale = scale/100.0;
2502 page_set = gtk_print_settings_get_page_set (settings);
2503 if (page_set == GTK_PAGE_SET_EVEN)
2504 gtk_print_settings_set (settings, "cups-page-set", "even");
2505 else if (page_set == GTK_PAGE_SET_ODD)
2506 gtk_print_settings_set (settings, "cups-page-set", "odd");
2507 print_job->page_set = GTK_PAGE_SET_ALL;
2509 paper_size = gtk_page_setup_get_paper_size (page_setup);
2510 ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2511 if (ppd_paper_name != NULL)
2512 gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2515 char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2516 gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2517 gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2518 gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2519 g_free (custom_name);
2522 print_job->rotate_to_orientation = TRUE;
2526 cups_printer_list_papers (GtkPrinter *printer)
2528 ppd_file_t *ppd_file;
2531 GtkPageSetup *page_setup;
2532 GtkPaperSize *paper_size;
2533 ppd_option_t *option;
2534 ppd_choice_t *choice;
2538 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2539 if (ppd_file == NULL)
2544 for (i = 0; i < ppd_file->num_sizes; i++)
2546 size = &ppd_file->sizes[i];
2548 display_name = NULL;
2549 option = ppdFindOption(ppd_file, "PageSize");
2552 choice = ppdFindChoice(option, size->name);
2554 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2556 if (display_name == NULL)
2557 display_name = g_strdup (size->name);
2559 page_setup = gtk_page_setup_new ();
2560 paper_size = gtk_paper_size_new_from_ppd (size->name,
2564 gtk_page_setup_set_paper_size (page_setup, paper_size);
2565 gtk_paper_size_free (paper_size);
2567 gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2568 gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2569 gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2570 gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2572 g_free (display_name);
2574 l = g_list_prepend (l, page_setup);
2577 return g_list_reverse (l);
2581 cups_printer_get_hard_margins (GtkPrinter *printer,
2587 ppd_file_t *ppd_file;
2589 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2590 if (ppd_file == NULL)
2593 *left = ppd_file->custom_margins[0];
2594 *bottom = ppd_file->custom_margins[1];
2595 *right = ppd_file->custom_margins[2];
2596 *top = ppd_file->custom_margins[3];
2599 static GtkPrintCapabilities
2600 cups_printer_get_capabilities (GtkPrinter *printer)
2603 GTK_PRINT_CAPABILITY_COPIES |
2604 GTK_PRINT_CAPABILITY_COLLATE |
2605 GTK_PRINT_CAPABILITY_REVERSE;