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 void set_option_from_settings (GtkPrinterOption *option,
141 GtkPrintSettings *setting);
142 static void cups_begin_polling_info (GtkPrintBackendCups *print_backend,
145 static gboolean cups_job_info_poll_timeout (gpointer user_data);
146 static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend,
149 GtkPrintJobCompleteFunc callback,
151 GDestroyNotify dnotify);
152 static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer,
159 gtk_print_backend_cups_register_type (GTypeModule *module)
161 static const GTypeInfo print_backend_cups_info =
163 sizeof (GtkPrintBackendCupsClass),
164 NULL, /* base_init */
165 NULL, /* base_finalize */
166 (GClassInitFunc) gtk_print_backend_cups_class_init,
167 NULL, /* class_finalize */
168 NULL, /* class_data */
169 sizeof (GtkPrintBackendCups),
171 (GInstanceInitFunc) gtk_print_backend_cups_init
174 print_backend_cups_type = g_type_module_register_type (module,
175 GTK_TYPE_PRINT_BACKEND,
176 "GtkPrintBackendCups",
177 &print_backend_cups_info, 0);
181 pb_module_init (GTypeModule *module)
183 gtk_print_backend_cups_register_type (module);
184 gtk_printer_cups_register_type (module);
188 pb_module_exit (void)
193 G_MODULE_EXPORT GtkPrintBackend *
194 pb_module_create (void)
196 return gtk_print_backend_cups_new ();
200 * GtkPrintBackendCups
203 gtk_print_backend_cups_get_type (void)
205 return print_backend_cups_type;
209 * gtk_print_backend_cups_new:
211 * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
212 * implements the #GtkPrintBackend interface with direct access to
213 * the filesystem using Unix/Linux API calls
215 * Return value: the new #GtkPrintBackendCups object
218 gtk_print_backend_cups_new (void)
220 return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
224 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
226 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
227 GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
229 backend_parent_class = g_type_class_peek_parent (class);
231 gobject_class->finalize = gtk_print_backend_cups_finalize;
232 gobject_class->dispose = gtk_print_backend_cups_dispose;
234 backend_class->request_printer_list = cups_get_printer_list;
235 backend_class->print_stream = gtk_print_backend_cups_print_stream;
236 backend_class->printer_request_details = cups_printer_request_details;
237 backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
238 backend_class->printer_get_options = cups_printer_get_options;
239 backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
240 backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
241 backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
242 backend_class->printer_list_papers = cups_printer_list_papers;
243 backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
246 static cairo_status_t
247 _cairo_write_to_cups (void *cache_fd_as_pointer,
248 const unsigned char *data,
251 cairo_status_t result;
253 cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
255 result = CAIRO_STATUS_WRITE_ERROR;
257 /* write out the buffer */
258 if (write (cache_fd, data, length) != -1)
259 result = CAIRO_STATUS_SUCCESS;
265 static cairo_surface_t *
266 cups_printer_create_cairo_surface (GtkPrinter *printer,
271 cairo_surface_t *surface;
273 /* TODO: check if it is a ps or pdf printer */
275 surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
277 /* TODO: DPI from settings object? */
278 cairo_ps_surface_set_dpi (surface, 300, 300);
284 GtkPrintJobCompleteFunc callback;
287 GDestroyNotify dnotify;
288 } CupsPrintStreamData;
291 cups_free_print_stream_data (CupsPrintStreamData *data)
294 data->dnotify (data->user_data);
295 g_object_unref (data->job);
300 cups_print_cb (GtkPrintBackendCups *print_backend,
301 GtkCupsResult *result,
304 GError *error = NULL;
305 CupsPrintStreamData *ps = user_data;
307 if (gtk_cups_result_is_error (result))
308 error = g_error_new_literal (gtk_print_error_quark (),
309 GTK_PRINT_ERROR_INTERNAL_ERROR,
310 gtk_cups_result_get_error_string (result));
313 ps->callback (ps->job, ps->user_data, error);
318 ipp_attribute_t *attr; /* IPP job-id attribute */
319 ipp_t *response = gtk_cups_result_get_response (result);
321 if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
322 job_id = attr->values[0].integer;
324 if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
325 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
328 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
329 cups_begin_polling_info (print_backend, ps->job, job_id);
333 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
337 g_error_free (error);
342 add_cups_options (const char *key,
346 GtkCupsRequest *request = user_data;
348 if (!g_str_has_prefix (key, "cups-"))
351 if (strcmp (value, "gtk-ignore-value") == 0)
354 key = key + strlen("cups-");
356 gtk_cups_request_encode_option (request, key, value);
360 gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
363 GtkPrintJobCompleteFunc callback,
365 GDestroyNotify dnotify)
368 GtkPrinterCups *cups_printer;
369 CupsPrintStreamData *ps;
370 GtkCupsRequest *request;
371 GtkPrintSettings *settings;
374 cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
375 settings = gtk_print_job_get_settings (job);
379 request = gtk_cups_request_new (NULL,
384 cups_printer->device_uri);
386 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
387 NULL, cups_printer->printer_uri);
389 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
392 title = gtk_print_job_get_title (job);
394 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
397 gtk_print_settings_foreach (settings, add_cups_options, request);
399 ps = g_new0 (CupsPrintStreamData, 1);
400 ps->callback = callback;
401 ps->user_data = user_data;
402 ps->dnotify = dnotify;
403 ps->job = g_object_ref (job);
405 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
407 (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
409 (GDestroyNotify)cups_free_print_stream_data,
415 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
417 backend_cups->list_printers_poll = 0;
418 backend_cups->list_printers_pending = FALSE;
420 cups_request_default_printer (backend_cups);
424 gtk_print_backend_cups_finalize (GObject *object)
426 GtkPrintBackendCups *backend_cups;
428 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
430 g_free (backend_cups->default_printer);
431 backend_cups->default_printer = NULL;
433 backend_parent_class->finalize (object);
437 gtk_print_backend_cups_dispose (GObject *object)
439 GtkPrintBackendCups *backend_cups;
441 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
443 if (backend_cups->list_printers_poll > 0)
444 g_source_remove (backend_cups->list_printers_poll);
445 backend_cups->list_printers_poll = 0;
447 backend_parent_class->dispose (object);
452 cups_dispatch_watch_check (GSource *source)
454 GtkPrintCupsDispatchWatch *dispatch;
455 GtkCupsPollState poll_state;
458 dispatch = (GtkPrintCupsDispatchWatch *) source;
460 poll_state = gtk_cups_request_get_poll_state (dispatch->request);
462 if (dispatch->data_poll == NULL &&
463 dispatch->request->http != NULL)
465 dispatch->data_poll = g_new0 (GPollFD, 1);
466 dispatch->data_poll->fd = dispatch->request->http->fd;
468 g_source_add_poll (source, dispatch->data_poll);
471 if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
473 if (dispatch->data_poll->fd != dispatch->request->http->fd)
474 dispatch->data_poll->fd = dispatch->request->http->fd;
476 if (poll_state == GTK_CUPS_HTTP_READ)
477 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
478 else if (poll_state == GTK_CUPS_HTTP_WRITE)
479 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
481 dispatch->data_poll->events = 0;
484 if (poll_state != GTK_CUPS_HTTP_IDLE)
485 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
488 result = gtk_cups_request_read_write (dispatch->request);
489 if (result && dispatch->data_poll != NULL)
491 g_source_remove_poll (source, dispatch->data_poll);
492 g_free (dispatch->data_poll);
493 dispatch->data_poll = NULL;
500 cups_dispatch_watch_prepare (GSource *source,
503 GtkPrintCupsDispatchWatch *dispatch;
505 dispatch = (GtkPrintCupsDispatchWatch *) source;
509 return gtk_cups_request_read_write (dispatch->request);
513 cups_dispatch_watch_dispatch (GSource *source,
514 GSourceFunc callback,
517 GtkPrintCupsDispatchWatch *dispatch;
518 GtkPrintCupsResponseCallbackFunc ep_callback;
519 GtkCupsResult *result;
521 g_assert (callback != NULL);
523 ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
525 dispatch = (GtkPrintCupsDispatchWatch *) source;
527 result = gtk_cups_request_get_result (dispatch->request);
529 if (gtk_cups_result_is_error (result))
530 g_warning (gtk_cups_result_get_error_string (result));
532 ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
538 cups_dispatch_watch_finalize (GSource *source)
540 GtkPrintCupsDispatchWatch *dispatch;
542 dispatch = (GtkPrintCupsDispatchWatch *) source;
544 gtk_cups_request_free (dispatch->request);
546 if (dispatch->backend)
548 /* We need to unref this at idle time, because it might be the
549 * last reference to this module causing the code to be
550 * unloaded (including this particular function!)
551 * Update: Doing this at idle caused a deadlock taking the
552 * mainloop context lock while being in a GSource callout for
553 * multithreaded apps. So, for now we just disable unloading
554 * of print backends. See _gtk_print_backend_create for the
557 g_object_unref (dispatch->backend);
558 dispatch->backend = NULL;
561 if (dispatch->data_poll != NULL)
562 g_free (dispatch->data_poll);
565 static GSourceFuncs _cups_dispatch_watch_funcs = {
566 cups_dispatch_watch_prepare,
567 cups_dispatch_watch_check,
568 cups_dispatch_watch_dispatch,
569 cups_dispatch_watch_finalize
574 cups_request_execute (GtkPrintBackendCups *print_backend,
575 GtkCupsRequest *request,
576 GtkPrintCupsResponseCallbackFunc callback,
578 GDestroyNotify notify,
581 GtkPrintCupsDispatchWatch *dispatch;
583 dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
584 sizeof (GtkPrintCupsDispatchWatch));
586 dispatch->request = request;
587 dispatch->backend = g_object_ref (print_backend);
588 dispatch->data_poll = NULL;
590 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
592 g_source_attach ((GSource *) dispatch, NULL);
593 g_source_unref ((GSource *) dispatch);
597 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
598 GtkCupsResult *result,
601 ipp_attribute_t *attr;
604 GtkPrinterCups *cups_printer;
610 gboolean status_changed;
612 g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
614 printer_name = (gchar *)user_data;
615 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
621 cups_printer = GTK_PRINTER_CUPS (printer);
623 if (gtk_cups_result_is_error (result))
625 if (gtk_printer_is_new (printer))
627 gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
632 return; /* TODO: mark as inactive printer */
635 response = gtk_cups_result_get_response (result);
637 /* TODO: determine printer type and use correct icon */
638 gtk_printer_set_icon_name (printer, "printer");
644 for (attr = response->attrs; attr != NULL; attr = attr->next)
649 _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
650 _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
651 _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
652 _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
653 _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
656 status_changed = gtk_printer_set_job_count (printer, job_count);
658 status_changed |= gtk_printer_set_location (printer, loc);
659 status_changed |= gtk_printer_set_description (printer, desc);
660 status_changed |= gtk_printer_set_state_message (printer, state_msg);
663 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
664 "printer-status-changed", printer);
668 cups_request_printer_info (GtkPrintBackendCups *print_backend,
669 const gchar *printer_name)
672 GtkCupsRequest *request;
674 static const char * const pattrs[] = /* Attributes we're interested in */
678 "printer-state-message",
685 request = gtk_cups_request_new (NULL,
687 IPP_GET_PRINTER_ATTRIBUTES,
692 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
694 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
695 "printer-uri", NULL, printer_uri);
697 g_free (printer_uri);
699 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
700 "requested-attributes", G_N_ELEMENTS (pattrs),
703 cups_request_execute (print_backend,
705 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
706 g_strdup (printer_name),
707 (GDestroyNotify) g_free,
714 GtkPrintBackendCups *print_backend;
721 job_object_died (gpointer user_data,
722 GObject *where_the_object_was)
724 CupsJobPollData *data = user_data;
729 cups_job_poll_data_free (CupsJobPollData *data)
732 g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
738 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
739 GtkCupsResult *result,
742 CupsJobPollData *data = user_data;
743 ipp_attribute_t *attr;
748 if (data->job == NULL)
750 cups_job_poll_data_free (data);
756 response = gtk_cups_result_get_response (result);
759 for (attr = response->attrs; attr != NULL; attr = attr->next)
764 _CUPS_MAP_ATTR_INT (attr, state, "job-state");
770 case IPP_JOB_PENDING:
772 case IPP_JOB_STOPPED:
773 gtk_print_job_set_status (data->job,
774 GTK_PRINT_STATUS_PENDING);
776 case IPP_JOB_PROCESSING:
777 gtk_print_job_set_status (data->job,
778 GTK_PRINT_STATUS_PRINTING);
781 case IPP_JOB_CANCELLED:
782 case IPP_JOB_ABORTED:
783 gtk_print_job_set_status (data->job,
784 GTK_PRINT_STATUS_FINISHED_ABORTED);
788 case IPP_JOB_COMPLETED:
789 gtk_print_job_set_status (data->job,
790 GTK_PRINT_STATUS_FINISHED);
795 if (!done && data->job != NULL)
799 if (data->counter < 5)
801 else if (data->counter < 10)
806 g_timeout_add (timeout, cups_job_info_poll_timeout, data);
809 cups_job_poll_data_free (data);
813 cups_request_job_info (CupsJobPollData *data)
816 GtkCupsRequest *request;
821 request = gtk_cups_request_new (NULL,
823 IPP_GET_JOB_ATTRIBUTES,
828 printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
829 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
830 "job-uri", NULL, printer_uri);
831 g_free (printer_uri);
833 cups_request_execute (data->print_backend,
835 (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
842 cups_job_info_poll_timeout (gpointer user_data)
844 CupsJobPollData *data = user_data;
846 if (data->job == NULL)
847 cups_job_poll_data_free (data);
849 cups_request_job_info (data);
855 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
859 CupsJobPollData *data;
861 data = g_new0 (CupsJobPollData, 1);
863 data->print_backend = print_backend;
865 data->job_id = job_id;
868 g_object_weak_ref (G_OBJECT (job), job_object_died, data);
870 cups_request_job_info (data);
874 mark_printer_inactive (GtkPrinter *printer,
875 GtkPrintBackend *backend)
877 gtk_printer_set_is_active (printer, FALSE);
878 g_signal_emit_by_name (backend,
879 "printer-removed", printer);
883 find_printer (GtkPrinter *printer, const char *find_name)
885 const char *printer_name;
887 printer_name = gtk_printer_get_name (printer);
888 return g_ascii_strcasecmp (printer_name, find_name);
892 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
893 GtkCupsResult *result,
896 ipp_attribute_t *attr;
898 gboolean list_has_changed;
899 GList *removed_printer_checklist;
901 list_has_changed = FALSE;
903 g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
905 cups_backend->list_printers_pending = FALSE;
907 if (gtk_cups_result_is_error (result))
909 g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
913 /* gether the names of the printers in the current queue
914 so we may check to see if they were removed */
915 removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
917 response = gtk_cups_result_get_response (result);
920 for (attr = response->attrs; attr != NULL; attr = attr->next)
923 const gchar *printer_name;
924 const char *printer_uri;
925 const char *member_uris;
929 * Skip leading attributes until we hit a printer...
931 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
940 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
942 if (!strcmp(attr->name, "printer-name") &&
943 attr->value_tag == IPP_TAG_NAME)
944 printer_name = attr->values[0].string.text;
945 else if (!strcmp(attr->name, "printer-uri-supported") &&
946 attr->value_tag == IPP_TAG_URI)
947 printer_uri = attr->values[0].string.text;
948 else if (!strcmp(attr->name, "member-uris") &&
949 attr->value_tag == IPP_TAG_URI)
950 member_uris = attr->values[0].string.text;
955 if (printer_name == NULL ||
956 (printer_uri == NULL && member_uris == NULL))
964 /* remove name from checklist if it was found */
965 node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
966 removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
968 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
971 GtkPrinterCups *cups_printer;
972 char uri[HTTP_MAX_URI], /* Printer URI */
973 method[HTTP_MAX_URI], /* Method/scheme name */
974 username[HTTP_MAX_URI], /* Username:password */
975 hostname[HTTP_MAX_URI], /* Hostname */
976 resource[HTTP_MAX_URI]; /* Resource name */
977 int port; /* Port number */
979 list_has_changed = TRUE;
980 cups_printer = gtk_printer_cups_new (printer_name,
981 GTK_PRINT_BACKEND (cups_backend));
983 cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
987 cups_printer->printer_uri = g_strdup (member_uris);
990 cups_printer->printer_uri = g_strdup (printer_uri);
992 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
993 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
994 method, sizeof (method),
995 username, sizeof (username),
996 hostname, sizeof (hostname),
998 resource, sizeof (resource));
1001 httpSeparate (cups_printer->printer_uri,
1009 gethostname(uri, sizeof(uri));
1010 if (strcasecmp(uri, hostname) == 0)
1011 strcpy(hostname, "localhost");
1013 cups_printer->hostname = g_strdup (hostname);
1014 cups_printer->port = port;
1016 printer = GTK_PRINTER (cups_printer);
1018 if (cups_backend->default_printer != NULL &&
1019 strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1020 gtk_printer_set_is_default (printer, TRUE);
1023 gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
1026 g_object_ref (printer);
1028 if (!gtk_printer_is_active (printer))
1030 gtk_printer_set_is_active (printer, TRUE);
1031 gtk_printer_set_is_new (printer, TRUE);
1032 list_has_changed = TRUE;
1035 if (gtk_printer_is_new (printer))
1037 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
1041 gtk_printer_set_is_new (printer, FALSE);
1044 cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1046 /* The ref is held by GtkPrintBackend, in add_printer() */
1047 g_object_unref (printer);
1054 /* look at the removed printers checklist and mark any printer
1055 as inactive if it is in the list, emitting a printer_removed signal */
1056 if (removed_printer_checklist != NULL)
1058 g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
1059 GTK_PRINT_BACKEND (cups_backend));
1060 g_list_free (removed_printer_checklist);
1061 list_has_changed = TRUE;
1064 if (list_has_changed)
1065 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
1067 gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
1071 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1074 GtkCupsRequest *request;
1075 static const char * const pattrs[] = /* Attributes we're interested in */
1078 "printer-uri-supported",
1082 if (cups_backend->list_printers_pending ||
1083 !cups_backend->got_default_printer)
1086 cups_backend->list_printers_pending = TRUE;
1090 request = gtk_cups_request_new (NULL,
1097 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1098 "requested-attributes", G_N_ELEMENTS (pattrs),
1101 cups_request_execute (cups_backend,
1103 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1113 cups_get_printer_list (GtkPrintBackend *backend)
1115 GtkPrintBackendCups *cups_backend;
1117 cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1118 if (cups_backend->list_printers_poll == 0)
1120 cups_request_printer_list (cups_backend);
1121 cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
1122 (GSourceFunc) cups_request_printer_list,
1128 GtkPrinterCups *printer;
1130 gchar *ppd_filename;
1134 get_ppd_data_free (GetPPDData *data)
1136 close (data->ppd_fd);
1137 unlink (data->ppd_filename);
1138 g_free (data->ppd_filename);
1139 g_object_unref (data->printer);
1144 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1145 GtkCupsResult *result,
1149 GtkPrinter *printer;
1151 printer = GTK_PRINTER (data->printer);
1152 GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1154 if (gtk_cups_result_is_error (result))
1156 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1160 response = gtk_cups_result_get_response (result);
1162 data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
1163 gtk_printer_set_has_details (printer, TRUE);
1164 g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
1168 cups_request_ppd (GtkPrinter *printer)
1171 GtkPrintBackend *print_backend;
1172 GtkPrinterCups *cups_printer;
1173 GtkCupsRequest *request;
1178 cups_printer = GTK_PRINTER_CUPS (printer);
1182 http = httpConnectEncrypt(cups_printer->hostname,
1186 data = g_new0 (GetPPDData, 1);
1188 data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
1189 &data->ppd_filename,
1194 g_warning ("%s", error->message);
1195 g_error_free (error);
1199 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1203 fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
1205 data->printer = g_object_ref (printer);
1207 resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
1208 request = gtk_cups_request_new (http,
1212 cups_printer->hostname,
1217 cups_printer->reading_ppd = TRUE;
1219 print_backend = gtk_printer_get_backend (printer);
1221 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1223 (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1225 (GDestroyNotify)get_ppd_data_free,
1231 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1232 GtkCupsResult *result,
1236 ipp_attribute_t *attr;
1238 response = gtk_cups_result_get_response (result);
1240 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
1241 print_backend->default_printer = g_strdup (attr->values[0].string.text);
1243 print_backend->got_default_printer = TRUE;
1245 /* Make sure to kick off get_printers if we are polling it, as we could
1246 have blocked this reading the default printer */
1247 if (print_backend->list_printers_poll != 0)
1248 cups_request_printer_list (print_backend);
1252 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1255 GtkCupsRequest *request;
1260 if ((str = getenv("LPDEST")) != NULL)
1262 print_backend->default_printer = g_strdup (str);
1263 print_backend->got_default_printer = TRUE;
1266 else if ((str = getenv("PRINTER")) != NULL &&
1267 strcmp(str, "lp") != 0)
1269 print_backend->default_printer = g_strdup (str);
1270 print_backend->got_default_printer = TRUE;
1274 request = gtk_cups_request_new (NULL,
1281 cups_request_execute (print_backend,
1283 (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1284 g_object_ref (print_backend),
1291 cups_printer_request_details (GtkPrinter *printer)
1293 GtkPrinterCups *cups_printer;
1295 cups_printer = GTK_PRINTER_CUPS (printer);
1296 if (!cups_printer->reading_ppd &&
1297 gtk_printer_cups_get_ppd (cups_printer) == NULL)
1298 cups_request_ppd (printer);
1302 ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
1304 const char *encoding = NULL;
1307 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1309 return g_strdup (text);
1311 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1313 encoding = "ISO-8859-1";
1315 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1317 encoding = "ISO-8859-2";
1319 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1321 encoding = "ISO-8859-5";
1323 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1325 encoding = "SHIFT-JIS";
1327 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1329 encoding = "MACINTOSH";
1331 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1333 encoding = "WINDOWS-1252";
1337 /* Fallback, try iso-8859-1... */
1338 encoding = "ISO-8859-1";
1341 res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1345 g_warning ("unable to convert PPD text");
1346 res = g_strdup ("???");
1352 /* TODO: Add more translations for common settings here */
1354 static const struct {
1355 const char *keyword;
1356 const char *translation;
1357 } cups_option_translations[] = {
1358 { "Duplex", N_("Two Sided") },
1359 { "MediaType", N_("Paper Type") },
1360 { "InputSlot", N_("Paper Source") },
1361 { "OutputBin", N_("Output Tray") },
1365 static const struct {
1366 const char *keyword;
1368 const char *translation;
1369 } cups_choice_translations[] = {
1370 { "Duplex", "None", N_("One Sided") },
1371 { "InputSlot", "Auto", N_("Auto Select") },
1372 { "InputSlot", "AutoSelect", N_("Auto Select") },
1373 { "InputSlot", "Default", N_("Printer Default") },
1374 { "InputSlot", "None", N_("Printer Default") },
1375 { "InputSlot", "PrinterDefault", N_("Printer Default") },
1376 { "InputSlot", "Unspecified", N_("Auto Select") },
1379 static const struct {
1380 const char *ppd_keyword;
1382 } option_names[] = {
1383 {"Duplex", "gtk-duplex" },
1384 {"MediaType", "gtk-paper-type"},
1385 {"InputSlot", "gtk-paper-source"},
1386 {"OutputBin", "gtk-output-tray"},
1389 /* keep sorted when changing */
1390 static const char *color_option_whitelist[] = {
1391 "BRColorEnhancement",
1397 "BlackSubstitution",
1405 "RPSBlackOverPrint",
1409 /* keep sorted when changing */
1410 static const char *color_group_whitelist[] = {
1417 "HPColorOptionsPanel",
1420 /* keep sorted when changing */
1421 static const char *image_quality_option_whitelist[] = {
1423 "BRHalfTonePattern",
1433 "HPGraphicsHalftone",
1448 /* keep sorted when changing */
1449 static const char *image_quality_group_whitelist[] = {
1456 /* keep sorted when changing */
1457 static const char * finishing_option_whitelist[] = {
1470 "StapleOrientation",
1476 /* keep sorted when changing */
1477 static const char *finishing_group_whitelist[] = {
1486 /* keep sorted when changing */
1487 static const char *cups_option_blacklist[] = {
1496 get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
1501 for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1503 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1504 return g_strdup (_(cups_option_translations[i].translation));
1507 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1509 /* Some ppd files have spaces in the text before the colon */
1516 get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
1519 ppd_option_t *option = choice->option;
1520 const char *keyword = option->keyword;
1522 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1524 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1525 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1526 return g_strdup (_(cups_choice_translations[i].translation));
1528 return ppd_text_to_utf8 (ppd_file, choice->text);
1532 group_has_option (ppd_group_t *group, ppd_option_t *option)
1539 if (group->num_options > 0 &&
1540 option >= group->options && option < group->options + group->num_options)
1543 for (i = 0; i < group->num_subgroups; i++)
1545 if (group_has_option (&group->subgroups[i],option))
1552 set_option_off (GtkPrinterOption *option)
1554 /* Any of these will do, _set only applies the value
1555 * if its allowed of the option */
1556 gtk_printer_option_set (option, "False");
1557 gtk_printer_option_set (option, "Off");
1558 gtk_printer_option_set (option, "None");
1562 value_is_off (const char *value)
1564 return (strcasecmp (value, "None") == 0 ||
1565 strcasecmp (value, "Off") == 0 ||
1566 strcasecmp (value, "False") == 0);
1570 available_choices (ppd_file_t *ppd,
1571 ppd_option_t *option,
1572 ppd_choice_t ***available,
1573 gboolean keep_if_only_one_option)
1575 ppd_option_t *other_option;
1578 ppd_const_t *constraint;
1579 const char *choice, *other_choice;
1580 ppd_option_t *option1, *option2;
1581 ppd_group_t *installed_options;
1583 gboolean all_default;
1589 conflicts = g_new0 (char, option->num_choices);
1591 installed_options = NULL;
1592 for (i = 0; i < ppd->num_groups; i++)
1594 if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
1596 installed_options = &ppd->groups[i];
1601 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1603 option1 = ppdFindOption (ppd, constraint->option1);
1604 if (option1 == NULL)
1607 option2 = ppdFindOption (ppd, constraint->option2);
1608 if (option2 == NULL)
1611 if (option == option1)
1613 choice = constraint->choice1;
1614 other_option = option2;
1615 other_choice = constraint->choice2;
1617 else if (option == option2)
1619 choice = constraint->choice2;
1620 other_option = option1;
1621 other_choice = constraint->choice1;
1626 /* We only care of conflicts with installed_options and
1628 if (!group_has_option (installed_options, other_option) &&
1629 (strcmp (other_option->keyword, "PageSize") != 0))
1632 if (*other_choice == 0)
1634 /* Conflict only if the installed option is not off */
1635 if (value_is_off (other_option->defchoice))
1638 /* Conflict if the installed option has the specified default */
1639 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1644 /* Conflict with all non-off choices */
1645 for (j = 0; j < option->num_choices; j++)
1647 if (!value_is_off (option->choices[j].choice))
1653 for (j = 0; j < option->num_choices; j++)
1655 if (strcasecmp (option->choices[j].choice, choice) == 0)
1663 for (j = 0; j < option->num_choices; j++)
1667 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1668 all_default = FALSE;
1671 if (all_default && !keep_if_only_one_option)
1674 if (num_conflicts == option->num_choices)
1678 /* Some ppds don't have a "use printer default" option for
1679 InputSlot. This means you always have to select a particular slot,
1680 and you can't auto-pick source based on the paper size. To support
1681 this we always add an auto option if there isn't one already. If
1682 the user chooses the generated option we don't send any InputSlot
1683 value when printing. The way we detect existing auto-cases is based
1684 on feedback from Michael Sweet of cups fame.
1687 if (strcmp (option->keyword, "InputSlot") == 0)
1689 gboolean found_auto = FALSE;
1690 for (j = 0; j < option->num_choices; j++)
1694 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1695 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1696 strcmp (option->choices[j].choice, "Default") == 0 ||
1697 strcmp (option->choices[j].choice, "None") == 0 ||
1698 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1699 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1700 option->choices[j].code == NULL ||
1701 option->choices[j].code[0] == 0)
1716 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1719 for (j = 0; j < option->num_choices; j++)
1722 (*available)[i++] = &option->choices[j];
1726 (*available)[i++] = NULL;
1729 return option->num_choices - num_conflicts + add_auto;
1732 static GtkPrinterOption *
1733 create_pickone_option (ppd_file_t *ppd_file,
1734 ppd_option_t *ppd_option,
1735 const char *gtk_name)
1737 GtkPrinterOption *option;
1738 ppd_choice_t **available;
1743 g_assert (ppd_option->ui == PPD_UI_PICKONE);
1747 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1750 label = get_option_text (ppd_file, ppd_option);
1751 option = gtk_printer_option_new (gtk_name, label,
1752 GTK_PRINTER_OPTION_TYPE_PICKONE);
1755 gtk_printer_option_allocate_choices (option, n_choices);
1756 for (i = 0; i < n_choices; i++)
1758 if (available[i] == NULL)
1760 /* This was auto-added */
1761 option->choices[i] = g_strdup ("gtk-ignore-value");
1762 option->choices_display[i] = g_strdup (_("Printer Default"));
1766 option->choices[i] = g_strdup (available[i]->choice);
1767 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1770 gtk_printer_option_set (option, ppd_option->defchoice);
1772 #ifdef PRINT_IGNORED_OPTIONS
1774 g_warning ("Ignoring pickone %s\n", ppd_option->text);
1781 static GtkPrinterOption *
1782 create_boolean_option (ppd_file_t *ppd_file,
1783 ppd_option_t *ppd_option,
1784 const char *gtk_name)
1786 GtkPrinterOption *option;
1787 ppd_choice_t **available;
1791 g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1795 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1798 label = get_option_text (ppd_file, ppd_option);
1799 option = gtk_printer_option_new (gtk_name, label,
1800 GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1803 gtk_printer_option_allocate_choices (option, 2);
1804 option->choices[0] = g_strdup ("True");
1805 option->choices_display[0] = g_strdup ("True");
1806 option->choices[1] = g_strdup ("True");
1807 option->choices_display[1] = g_strdup ("True");
1809 gtk_printer_option_set (option, ppd_option->defchoice);
1811 #ifdef PRINT_IGNORED_OPTIONS
1813 g_warning ("Ignoring boolean %s\n", ppd_option->text);
1821 get_option_name (const char *keyword)
1825 for (i = 0; i < G_N_ELEMENTS (option_names); i++)
1826 if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
1827 return g_strdup (option_names[i].name);
1829 return g_strdup_printf ("cups-%s", keyword);
1833 strptr_cmp (const void *a, const void *b)
1835 char **aa = (char **)a;
1836 char **bb = (char **)b;
1837 return strcmp (*aa, *bb);
1842 string_in_table (char *str, const char *table[], int table_len)
1844 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
1847 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
1850 handle_option (GtkPrinterOptionSet *set,
1851 ppd_file_t *ppd_file,
1852 ppd_option_t *ppd_option,
1853 ppd_group_t *toplevel_group,
1854 GtkPrintSettings *settings)
1856 GtkPrinterOption *option;
1859 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
1862 name = get_option_name (ppd_option->keyword);
1865 if (ppd_option->ui == PPD_UI_PICKONE)
1867 option = create_pickone_option (ppd_file, ppd_option, name);
1869 else if (ppd_option->ui == PPD_UI_BOOLEAN)
1871 option = create_boolean_option (ppd_file, ppd_option, name);
1874 g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
1879 if (STRING_IN_TABLE (toplevel_group->name,
1880 color_group_whitelist) ||
1881 STRING_IN_TABLE (ppd_option->keyword,
1882 color_option_whitelist))
1884 option->group = g_strdup ("ColorPage");
1886 else if (STRING_IN_TABLE (toplevel_group->name,
1887 image_quality_group_whitelist) ||
1888 STRING_IN_TABLE (ppd_option->keyword,
1889 image_quality_option_whitelist))
1891 option->group = g_strdup ("ImageQualityPage");
1893 else if (STRING_IN_TABLE (toplevel_group->name,
1894 finishing_group_whitelist) ||
1895 STRING_IN_TABLE (ppd_option->keyword,
1896 finishing_option_whitelist))
1898 option->group = g_strdup ("FinishingPage");
1902 option->group = g_strdup (toplevel_group->text);
1905 set_option_from_settings (option, settings);
1907 gtk_printer_option_set_add (set, option);
1914 handle_group (GtkPrinterOptionSet *set,
1915 ppd_file_t *ppd_file,
1917 ppd_group_t *toplevel_group,
1918 GtkPrintSettings *settings)
1922 /* Ignore installable options */
1923 if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
1926 for (i = 0; i < group->num_options; i++)
1927 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
1929 for (i = 0; i < group->num_subgroups; i++)
1930 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
1934 static GtkPrinterOptionSet *
1935 cups_printer_get_options (GtkPrinter *printer,
1936 GtkPrintSettings *settings,
1937 GtkPageSetup *page_setup)
1939 GtkPrinterOptionSet *set;
1940 GtkPrinterOption *option;
1941 ppd_file_t *ppd_file;
1943 char *print_at[] = { "now", "at", "on-hold" };
1944 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
1945 char *prio[] = {"100", "80", "50", "30" };
1946 char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
1947 char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
1948 char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
1951 set = gtk_printer_option_set_new ();
1953 /* Cups specific, non-ppd related settings */
1955 option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
1956 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
1958 gtk_printer_option_set (option, "1");
1959 set_option_from_settings (option, settings);
1960 gtk_printer_option_set_add (set, option);
1961 g_object_unref (option);
1963 for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
1964 prio_display[i] = _(prio_display[i]);
1966 option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
1967 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
1968 prio, prio_display);
1969 gtk_printer_option_set (option, "50");
1970 set_option_from_settings (option, settings);
1971 gtk_printer_option_set_add (set, option);
1972 g_object_unref (option);
1974 option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
1975 gtk_printer_option_set (option, "");
1976 set_option_from_settings (option, settings);
1977 gtk_printer_option_set_add (set, option);
1978 g_object_unref (option);
1980 for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
1981 cover_display[i] = _(cover_display[i]);
1983 option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
1984 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1985 cover, cover_display);
1986 gtk_printer_option_set (option, "none");
1987 set_option_from_settings (option, settings);
1988 gtk_printer_option_set_add (set, option);
1989 g_object_unref (option);
1991 option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
1992 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1993 cover, cover_display);
1994 gtk_printer_option_set (option, "none");
1995 set_option_from_settings (option, settings);
1996 gtk_printer_option_set_add (set, option);
1997 g_object_unref (option);
1999 option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
2000 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2001 print_at, print_at);
2002 gtk_printer_option_set (option, "now");
2003 set_option_from_settings (option, settings);
2004 gtk_printer_option_set_add (set, option);
2005 g_object_unref (option);
2007 option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2008 gtk_printer_option_set (option, "");
2009 set_option_from_settings (option, settings);
2010 gtk_printer_option_set_add (set, option);
2011 g_object_unref (option);
2013 /* Printer (ppd) specific settings */
2014 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2017 GtkPaperSize *paper_size;
2018 ppd_option_t *option;
2020 ppdMarkDefaults (ppd_file);
2022 paper_size = gtk_page_setup_get_paper_size (page_setup);
2024 option = ppdFindOption(ppd_file, "PageSize");
2025 strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
2028 for (i = 0; i < ppd_file->num_groups; i++)
2029 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2037 mark_option_from_set (GtkPrinterOptionSet *set,
2038 ppd_file_t *ppd_file,
2039 ppd_option_t *ppd_option)
2041 GtkPrinterOption *option;
2042 char *name = get_option_name (ppd_option->keyword);
2044 option = gtk_printer_option_set_lookup (set, name);
2047 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2054 mark_group_from_set (GtkPrinterOptionSet *set,
2055 ppd_file_t *ppd_file,
2060 for (i = 0; i < group->num_options; i++)
2061 mark_option_from_set (set, ppd_file, &group->options[i]);
2063 for (i = 0; i < group->num_subgroups; i++)
2064 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2068 set_conflicts_from_option (GtkPrinterOptionSet *set,
2069 ppd_file_t *ppd_file,
2070 ppd_option_t *ppd_option)
2072 GtkPrinterOption *option;
2074 if (ppd_option->conflicted)
2076 name = get_option_name (ppd_option->keyword);
2077 option = gtk_printer_option_set_lookup (set, name);
2080 gtk_printer_option_set_has_conflict (option, TRUE);
2082 g_warning ("conflict for option %s ignored", ppd_option->keyword);
2089 set_conflicts_from_group (GtkPrinterOptionSet *set,
2090 ppd_file_t *ppd_file,
2095 for (i = 0; i < group->num_options; i++)
2096 set_conflicts_from_option (set, ppd_file, &group->options[i]);
2098 for (i = 0; i < group->num_subgroups; i++)
2099 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2103 cups_printer_mark_conflicts (GtkPrinter *printer,
2104 GtkPrinterOptionSet *options)
2106 ppd_file_t *ppd_file;
2110 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2112 if (ppd_file == NULL)
2115 ppdMarkDefaults (ppd_file);
2117 for (i = 0; i < ppd_file->num_groups; i++)
2118 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2120 num_conflicts = ppdConflicts (ppd_file);
2122 if (num_conflicts > 0)
2124 for (i = 0; i < ppd_file->num_groups; i++)
2125 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2128 return num_conflicts > 0;
2132 GtkPrinter *printer;
2133 GtkPrinterOptionSet *options;
2134 GtkPrintSettings *settings;
2135 ppd_file_t *ppd_file;
2140 const char *standard;
2144 map_settings_to_option (GtkPrinterOption *option,
2145 const NameMapping table[],
2147 GtkPrintSettings *settings,
2148 const char *standard_name,
2149 const char *cups_name)
2153 const char *cups_value;
2154 const char *standard_value;
2156 /* If the cups-specific setting is set, always use that */
2158 name = g_strdup_printf ("cups-%s", cups_name);
2159 cups_value = gtk_print_settings_get (settings, name);
2162 if (cups_value != NULL) {
2163 gtk_printer_option_set (option, cups_value);
2167 /* Otherwise we try to convert from the general setting */
2168 standard_value = gtk_print_settings_get (settings, standard_name);
2169 if (standard_value == NULL)
2172 for (i = 0; i < n_elements; i++)
2174 if (table[i].cups == NULL && table[i].standard == NULL)
2176 gtk_printer_option_set (option, standard_value);
2179 else if (table[i].cups == NULL &&
2180 strcmp (table[i].standard, standard_value) == 0)
2182 set_option_off (option);
2185 else if (strcmp (table[i].standard, standard_value) == 0)
2187 gtk_printer_option_set (option, table[i].cups);
2194 map_option_to_settings (const char *value,
2195 const NameMapping table[],
2197 GtkPrintSettings *settings,
2198 const char *standard_name,
2199 const char *cups_name)
2204 for (i = 0; i < n_elements; i++)
2206 if (table[i].cups == NULL && table[i].standard == NULL)
2208 gtk_print_settings_set (settings,
2213 else if (table[i].cups == NULL && table[i].standard != NULL)
2215 if (value_is_off (value))
2217 gtk_print_settings_set (settings,
2223 else if (strcmp (table[i].cups, value) == 0)
2225 gtk_print_settings_set (settings,
2232 /* Always set the corresponding cups-specific setting */
2233 name = g_strdup_printf ("cups-%s", cups_name);
2234 gtk_print_settings_set (settings, name, value);
2239 static const NameMapping paper_source_map[] = {
2240 { "Lower", "lower"},
2241 { "Middle", "middle"},
2242 { "Upper", "upper"},
2244 { "Envelope", "envelope"},
2245 { "Cassette", "cassette"},
2246 { "LargeCapacity", "large-capacity"},
2247 { "AnySmallFormat", "small-format"},
2248 { "AnyLargeFormat", "large-format"},
2252 static const NameMapping output_tray_map[] = {
2253 { "Upper", "upper"},
2254 { "Lower", "lower"},
2259 static const NameMapping duplex_map[] = {
2260 { "DuplexTumble", "vertical" },
2261 { "DuplexNoTumble", "horizontal" },
2265 static const NameMapping output_mode_map[] = {
2266 { "Standard", "normal" },
2267 { "Normal", "normal" },
2268 { "Draft", "draft" },
2269 { "Fast", "draft" },
2272 static const NameMapping media_type_map[] = {
2273 { "Transparency", "transparency"},
2274 { "Standard", "stationery"},
2278 static const NameMapping all_map[] = {
2284 set_option_from_settings (GtkPrinterOption *option,
2285 GtkPrintSettings *settings)
2287 const char *cups_value;
2290 if (settings == NULL)
2293 if (strcmp (option->name, "gtk-paper-source") == 0)
2294 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2295 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2296 else if (strcmp (option->name, "gtk-output-tray") == 0)
2297 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2298 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2299 else if (strcmp (option->name, "gtk-duplex") == 0)
2300 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2301 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2302 else if (strcmp (option->name, "cups-OutputMode") == 0)
2303 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2304 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2305 else if (strcmp (option->name, "cups-Resolution") == 0)
2307 cups_value = gtk_print_settings_get (settings, option->name);
2309 gtk_printer_option_set (option, cups_value);
2312 int res = gtk_print_settings_get_resolution (settings);
2315 value = g_strdup_printf ("%ddpi", res);
2316 gtk_printer_option_set (option, value);
2321 else if (strcmp (option->name, "gtk-paper-type") == 0)
2322 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2323 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2324 else if (strcmp (option->name, "gtk-n-up") == 0)
2326 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2327 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2329 else if (strcmp (option->name, "gtk-billing-info") == 0)
2331 cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2333 gtk_printer_option_set (option, cups_value);
2335 else if (strcmp (option->name, "gtk-job-prio") == 0)
2337 cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2339 gtk_printer_option_set (option, cups_value);
2341 else if (strcmp (option->name, "gtk-cover-before") == 0)
2343 cups_value = gtk_print_settings_get (settings, "cover-before");
2345 gtk_printer_option_set (option, cups_value);
2347 else if (strcmp (option->name, "gtk-cover-after") == 0)
2349 cups_value = gtk_print_settings_get (settings, "cover-after");
2351 gtk_printer_option_set (option, cups_value);
2353 else if (strcmp (option->name, "gtk-print-time") == 0)
2355 cups_value = gtk_print_settings_get (settings, "print-at");
2357 gtk_printer_option_set (option, cups_value);
2359 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2361 cups_value = gtk_print_settings_get (settings, "print-at-time");
2363 gtk_printer_option_set (option, cups_value);
2365 else if (g_str_has_prefix (option->name, "cups-"))
2367 cups_value = gtk_print_settings_get (settings, option->name);
2369 gtk_printer_option_set (option, cups_value);
2374 foreach_option_get_settings (GtkPrinterOption *option,
2377 struct OptionData *data = user_data;
2378 GtkPrintSettings *settings = data->settings;
2381 value = option->value;
2383 if (strcmp (option->name, "gtk-paper-source") == 0)
2384 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2385 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2386 else if (strcmp (option->name, "gtk-output-tray") == 0)
2387 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2388 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2389 else if (strcmp (option->name, "gtk-duplex") == 0)
2390 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2391 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2392 else if (strcmp (option->name, "cups-OutputMode") == 0)
2393 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2394 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2395 else if (strcmp (option->name, "cups-Resolution") == 0)
2397 int res = atoi (value);
2398 /* TODO: What if resolution is on XXXxYYYdpi form? */
2400 gtk_print_settings_set_resolution (settings, res);
2401 gtk_print_settings_set (settings, option->name, value);
2403 else if (strcmp (option->name, "gtk-paper-type") == 0)
2404 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2405 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2406 else if (strcmp (option->name, "gtk-n-up") == 0)
2407 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2408 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2409 else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2410 gtk_print_settings_set (settings, "cups-job-billing", value);
2411 else if (strcmp (option->name, "gtk-job-prio") == 0)
2412 gtk_print_settings_set (settings, "cups-job-priority", value);
2413 else if (strcmp (option->name, "gtk-cover-before") == 0)
2414 gtk_print_settings_set (settings, "cover-before", value);
2415 else if (strcmp (option->name, "gtk-cover-after") == 0)
2416 gtk_print_settings_set (settings, "cover-after", value);
2417 else if (strcmp (option->name, "gtk-print-time") == 0)
2418 gtk_print_settings_set (settings, "print-at", value);
2419 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2420 gtk_print_settings_set (settings, "print-at-time", value);
2421 else if (g_str_has_prefix (option->name, "cups-"))
2422 gtk_print_settings_set (settings, option->name, value);
2426 cups_printer_get_settings_from_options (GtkPrinter *printer,
2427 GtkPrinterOptionSet *options,
2428 GtkPrintSettings *settings)
2430 struct OptionData data;
2431 const char *print_at, *print_at_time;
2433 data.printer = printer;
2434 data.options = options;
2435 data.settings = settings;
2436 data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2438 if (data.ppd_file != NULL)
2440 GtkPrinterOption *cover_before, *cover_after;
2442 gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2444 cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2445 cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2446 if (cover_before && cover_after)
2448 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2449 gtk_print_settings_set (settings, "cups-job-sheets", value);
2453 print_at = gtk_print_settings_get (settings, "print-at");
2454 print_at_time = gtk_print_settings_get (settings, "print-at-time");
2455 if (strcmp (print_at, "at") == 0)
2456 gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2457 else if (strcmp (print_at, "on-hold") == 0)
2458 gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2463 cups_printer_prepare_for_print (GtkPrinter *printer,
2464 GtkPrintJob *print_job,
2465 GtkPrintSettings *settings,
2466 GtkPageSetup *page_setup)
2468 GtkPageSet page_set;
2469 GtkPaperSize *paper_size;
2470 const char *ppd_paper_name;
2473 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2474 print_job->page_ranges = NULL;
2475 print_job->num_page_ranges = 0;
2477 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2478 print_job->page_ranges =
2479 gtk_print_settings_get_page_ranges (settings,
2480 &print_job->num_page_ranges);
2482 if (gtk_print_settings_get_collate (settings))
2483 gtk_print_settings_set (settings, "cups-Collate", "True");
2484 print_job->collate = FALSE;
2486 if (gtk_print_settings_get_reverse (settings))
2487 gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2488 print_job->reverse = FALSE;
2490 if (gtk_print_settings_get_n_copies (settings) > 1)
2491 gtk_print_settings_set_int (settings, "cups-copies",
2492 gtk_print_settings_get_n_copies (settings));
2493 print_job->num_copies = 1;
2495 scale = gtk_print_settings_get_scale (settings);
2496 print_job->scale = 1.0;
2498 print_job->scale = scale/100.0;
2500 page_set = gtk_print_settings_get_page_set (settings);
2501 if (page_set == GTK_PAGE_SET_EVEN)
2502 gtk_print_settings_set (settings, "cups-page-set", "even");
2503 else if (page_set == GTK_PAGE_SET_ODD)
2504 gtk_print_settings_set (settings, "cups-page-set", "odd");
2505 print_job->page_set = GTK_PAGE_SET_ALL;
2507 paper_size = gtk_page_setup_get_paper_size (page_setup);
2508 ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2509 if (ppd_paper_name != NULL)
2510 gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2513 char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2514 gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2515 gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2516 gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2517 g_free (custom_name);
2520 print_job->rotate_to_orientation = TRUE;
2524 cups_printer_list_papers (GtkPrinter *printer)
2526 ppd_file_t *ppd_file;
2529 GtkPageSetup *page_setup;
2530 GtkPaperSize *paper_size;
2531 ppd_option_t *option;
2532 ppd_choice_t *choice;
2536 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2537 if (ppd_file == NULL)
2542 for (i = 0; i < ppd_file->num_sizes; i++)
2544 size = &ppd_file->sizes[i];
2546 display_name = NULL;
2547 option = ppdFindOption(ppd_file, "PageSize");
2550 choice = ppdFindChoice(option, size->name);
2552 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2554 if (display_name == NULL)
2555 display_name = g_strdup (size->name);
2557 page_setup = gtk_page_setup_new ();
2558 paper_size = gtk_paper_size_new_from_ppd (size->name,
2562 gtk_page_setup_set_paper_size (page_setup, paper_size);
2563 gtk_paper_size_free (paper_size);
2565 gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2566 gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2567 gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2568 gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2570 g_free (display_name);
2572 l = g_list_prepend (l, page_setup);
2575 return g_list_reverse (l);
2579 cups_printer_get_hard_margins (GtkPrinter *printer,
2585 ppd_file_t *ppd_file;
2587 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2588 if (ppd_file == NULL)
2591 *left = ppd_file->custom_margins[0];
2592 *bottom = ppd_file->custom_margins[1];
2593 *right = ppd_file->custom_margins[2];
2594 *top = ppd_file->custom_margins[3];