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;
326 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
329 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
330 cups_begin_polling_info (print_backend, ps->job, job_id);
334 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
338 g_error_free (error);
343 add_cups_options (const char *key,
347 GtkCupsRequest *request = user_data;
349 if (!g_str_has_prefix (key, "cups-"))
352 if (strcmp (value, "gtk-ignore-value") == 0)
355 key = key + strlen("cups-");
357 gtk_cups_request_encode_option (request, key, value);
361 gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
364 GtkPrintJobCompleteFunc callback,
366 GDestroyNotify dnotify)
369 GtkPrinterCups *cups_printer;
370 CupsPrintStreamData *ps;
371 GtkCupsRequest *request;
372 GtkPrintSettings *settings;
375 cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
376 settings = gtk_print_job_get_settings (job);
380 request = gtk_cups_request_new (NULL,
385 cups_printer->device_uri);
387 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
388 NULL, cups_printer->printer_uri);
390 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
393 title = gtk_print_job_get_title (job);
395 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
398 gtk_print_settings_foreach (settings, add_cups_options, request);
400 ps = g_new0 (CupsPrintStreamData, 1);
401 ps->callback = callback;
402 ps->user_data = user_data;
403 ps->dnotify = dnotify;
404 ps->job = g_object_ref (job);
406 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
408 (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
410 (GDestroyNotify)cups_free_print_stream_data,
416 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
418 backend_cups->list_printers_poll = 0;
419 backend_cups->list_printers_pending = FALSE;
421 cups_request_default_printer (backend_cups);
425 gtk_print_backend_cups_finalize (GObject *object)
427 GtkPrintBackendCups *backend_cups;
429 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
431 g_free (backend_cups->default_printer);
432 backend_cups->default_printer = NULL;
434 backend_parent_class->finalize (object);
438 gtk_print_backend_cups_dispose (GObject *object)
440 GtkPrintBackendCups *backend_cups;
442 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
444 if (backend_cups->list_printers_poll > 0)
445 g_source_remove (backend_cups->list_printers_poll);
446 backend_cups->list_printers_poll = 0;
448 backend_parent_class->dispose (object);
453 cups_dispatch_watch_check (GSource *source)
455 GtkPrintCupsDispatchWatch *dispatch;
456 GtkCupsPollState poll_state;
459 dispatch = (GtkPrintCupsDispatchWatch *) source;
461 poll_state = gtk_cups_request_get_poll_state (dispatch->request);
463 if (dispatch->data_poll == NULL &&
464 dispatch->request->http != NULL)
466 dispatch->data_poll = g_new0 (GPollFD, 1);
467 dispatch->data_poll->fd = dispatch->request->http->fd;
469 g_source_add_poll (source, dispatch->data_poll);
472 if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
474 if (dispatch->data_poll->fd != dispatch->request->http->fd)
475 dispatch->data_poll->fd = dispatch->request->http->fd;
477 if (poll_state == GTK_CUPS_HTTP_READ)
478 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
479 else if (poll_state == GTK_CUPS_HTTP_WRITE)
480 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
482 dispatch->data_poll->events = 0;
485 if (poll_state != GTK_CUPS_HTTP_IDLE)
486 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
489 result = gtk_cups_request_read_write (dispatch->request);
490 if (result && dispatch->data_poll != NULL)
492 g_source_remove_poll (source, dispatch->data_poll);
493 g_free (dispatch->data_poll);
494 dispatch->data_poll = NULL;
501 cups_dispatch_watch_prepare (GSource *source,
504 GtkPrintCupsDispatchWatch *dispatch;
506 dispatch = (GtkPrintCupsDispatchWatch *) source;
510 return gtk_cups_request_read_write (dispatch->request);
514 cups_dispatch_watch_dispatch (GSource *source,
515 GSourceFunc callback,
518 GtkPrintCupsDispatchWatch *dispatch;
519 GtkPrintCupsResponseCallbackFunc ep_callback;
520 GtkCupsResult *result;
522 g_assert (callback != NULL);
524 ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
526 dispatch = (GtkPrintCupsDispatchWatch *) source;
528 result = gtk_cups_request_get_result (dispatch->request);
530 if (gtk_cups_result_is_error (result))
531 g_warning (gtk_cups_result_get_error_string (result));
533 ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
539 cups_dispatch_watch_finalize (GSource *source)
541 GtkPrintCupsDispatchWatch *dispatch;
543 dispatch = (GtkPrintCupsDispatchWatch *) source;
545 gtk_cups_request_free (dispatch->request);
547 if (dispatch->backend)
549 /* We need to unref this at idle time, because it might be the
550 last reference to this module causing the code to be
551 unloaded (including this particular function!)
553 gtk_print_backend_unref_at_idle (GTK_PRINT_BACKEND (dispatch->backend));
554 dispatch->backend = NULL;
557 if (dispatch->data_poll != NULL)
558 g_free (dispatch->data_poll);
561 static GSourceFuncs _cups_dispatch_watch_funcs = {
562 cups_dispatch_watch_prepare,
563 cups_dispatch_watch_check,
564 cups_dispatch_watch_dispatch,
565 cups_dispatch_watch_finalize
570 cups_request_execute (GtkPrintBackendCups *print_backend,
571 GtkCupsRequest *request,
572 GtkPrintCupsResponseCallbackFunc callback,
574 GDestroyNotify notify,
577 GtkPrintCupsDispatchWatch *dispatch;
579 dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
580 sizeof (GtkPrintCupsDispatchWatch));
582 dispatch->request = request;
583 dispatch->backend = g_object_ref (print_backend);
584 dispatch->data_poll = NULL;
586 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
588 g_source_attach ((GSource *) dispatch, NULL);
589 g_source_unref ((GSource *) dispatch);
593 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
594 GtkCupsResult *result,
597 ipp_attribute_t *attr;
600 GtkPrinterCups *cups_printer;
606 gboolean status_changed;
608 g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
610 printer_name = (gchar *)user_data;
611 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
617 cups_printer = GTK_PRINTER_CUPS (printer);
619 if (gtk_cups_result_is_error (result))
621 if (gtk_printer_is_new (printer))
623 gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
628 return; /* TODO: mark as inactive printer */
631 response = gtk_cups_result_get_response (result);
633 /* TODO: determine printer type and use correct icon */
634 gtk_printer_set_icon_name (printer, "printer");
640 for (attr = response->attrs; attr != NULL; attr = attr->next)
645 _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
646 _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
647 _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
648 _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
649 _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
652 status_changed = gtk_printer_set_job_count (printer, job_count);
654 status_changed |= gtk_printer_set_location (printer, loc);
655 status_changed |= gtk_printer_set_description (printer, desc);
656 status_changed |= gtk_printer_set_state_message (printer, state_msg);
659 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
660 "printer-status-changed", printer);
664 cups_request_printer_info (GtkPrintBackendCups *print_backend,
665 const gchar *printer_name)
668 GtkCupsRequest *request;
670 static const char * const pattrs[] = /* Attributes we're interested in */
674 "printer-state-message",
681 request = gtk_cups_request_new (NULL,
683 IPP_GET_PRINTER_ATTRIBUTES,
688 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
690 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
691 "printer-uri", NULL, printer_uri);
693 g_free (printer_uri);
695 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
696 "requested-attributes", G_N_ELEMENTS (pattrs),
699 cups_request_execute (print_backend,
701 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
702 g_strdup (printer_name),
703 (GDestroyNotify) g_free,
710 GtkPrintBackendCups *print_backend;
717 job_object_died (gpointer user_data,
718 GObject *where_the_object_was)
720 CupsJobPollData *data = user_data;
725 cups_job_poll_data_free (CupsJobPollData *data)
728 g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
734 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
735 GtkCupsResult *result,
738 CupsJobPollData *data = user_data;
739 ipp_attribute_t *attr;
744 if (data->job == NULL)
746 cups_job_poll_data_free (data);
752 response = gtk_cups_result_get_response (result);
755 for (attr = response->attrs; attr != NULL; attr = attr->next)
760 _CUPS_MAP_ATTR_INT (attr, state, "job-state");
766 case IPP_JOB_PENDING:
768 case IPP_JOB_STOPPED:
769 gtk_print_job_set_status (data->job,
770 GTK_PRINT_STATUS_PENDING);
772 case IPP_JOB_PROCESSING:
773 gtk_print_job_set_status (data->job,
774 GTK_PRINT_STATUS_PRINTING);
777 case IPP_JOB_CANCELLED:
778 case IPP_JOB_ABORTED:
779 gtk_print_job_set_status (data->job,
780 GTK_PRINT_STATUS_FINISHED_ABORTED);
784 case IPP_JOB_COMPLETED:
785 gtk_print_job_set_status (data->job,
786 GTK_PRINT_STATUS_FINISHED);
791 if (!done && data->job != NULL)
795 if (data->counter < 5)
797 else if (data->counter < 10)
802 g_timeout_add (timeout, cups_job_info_poll_timeout, data);
805 cups_job_poll_data_free (data);
809 cups_request_job_info (CupsJobPollData *data)
812 GtkCupsRequest *request;
817 request = gtk_cups_request_new (NULL,
819 IPP_GET_JOB_ATTRIBUTES,
824 printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
825 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
826 "job-uri", NULL, printer_uri);
827 g_free (printer_uri);
829 cups_request_execute (data->print_backend,
831 (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
838 cups_job_info_poll_timeout (gpointer user_data)
840 CupsJobPollData *data = user_data;
842 if (data->job == NULL)
843 cups_job_poll_data_free (data);
845 cups_request_job_info (data);
851 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
855 CupsJobPollData *data;
857 data = g_new0 (CupsJobPollData, 1);
859 data->print_backend = print_backend;
861 data->job_id = job_id;
864 g_object_weak_ref (G_OBJECT (job), job_object_died, data);
866 cups_request_job_info (data);
870 mark_printer_inactive (GtkPrinter *printer,
871 GtkPrintBackend *backend)
873 gtk_printer_set_is_active (printer, FALSE);
874 g_signal_emit_by_name (backend,
875 "printer-removed", printer);
879 find_printer (GtkPrinter *printer, const char *find_name)
881 const char *printer_name;
883 printer_name = gtk_printer_get_name (printer);
884 return g_ascii_strcasecmp (printer_name, find_name);
888 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
889 GtkCupsResult *result,
892 ipp_attribute_t *attr;
894 gboolean list_has_changed;
895 GList *removed_printer_checklist;
897 list_has_changed = FALSE;
899 g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
901 cups_backend->list_printers_pending = FALSE;
903 if (gtk_cups_result_is_error (result))
905 g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
909 /* gether the names of the printers in the current queue
910 so we may check to see if they were removed */
911 removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
913 response = gtk_cups_result_get_response (result);
916 for (attr = response->attrs; attr != NULL; attr = attr->next)
919 const gchar *printer_name;
920 const char *printer_uri;
921 const char *member_uris;
925 * Skip leading attributes until we hit a printer...
927 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
936 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
938 if (!strcmp(attr->name, "printer-name") &&
939 attr->value_tag == IPP_TAG_NAME)
940 printer_name = attr->values[0].string.text;
941 else if (!strcmp(attr->name, "printer-uri-supported") &&
942 attr->value_tag == IPP_TAG_URI)
943 printer_uri = attr->values[0].string.text;
944 else if (!strcmp(attr->name, "member-uris") &&
945 attr->value_tag == IPP_TAG_URI)
946 member_uris = attr->values[0].string.text;
951 if (printer_name == NULL ||
952 (printer_uri == NULL && member_uris == NULL))
960 /* remove name from checklist if it was found */
961 node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
962 removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
964 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
967 GtkPrinterCups *cups_printer;
968 char uri[HTTP_MAX_URI], /* Printer URI */
969 method[HTTP_MAX_URI], /* Method/scheme name */
970 username[HTTP_MAX_URI], /* Username:password */
971 hostname[HTTP_MAX_URI], /* Hostname */
972 resource[HTTP_MAX_URI]; /* Resource name */
973 int port; /* Port number */
975 list_has_changed = TRUE;
976 cups_printer = gtk_printer_cups_new (printer_name,
977 GTK_PRINT_BACKEND (cups_backend));
979 cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
983 cups_printer->printer_uri = g_strdup (member_uris);
986 cups_printer->printer_uri = g_strdup (printer_uri);
988 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
989 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
990 method, sizeof (method),
991 username, sizeof (username),
992 hostname, sizeof (hostname),
994 resource, sizeof (resource));
997 httpSeparate (cups_printer->printer_uri,
1005 gethostname(uri, sizeof(uri));
1006 if (strcasecmp(uri, hostname) == 0)
1007 strcpy(hostname, "localhost");
1009 cups_printer->hostname = g_strdup (hostname);
1010 cups_printer->port = port;
1012 printer = GTK_PRINTER (cups_printer);
1014 if (cups_backend->default_printer != NULL &&
1015 strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1016 gtk_printer_set_is_default (printer, TRUE);
1019 gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
1022 g_object_ref (printer);
1024 if (!gtk_printer_is_active (printer))
1026 gtk_printer_set_is_active (printer, TRUE);
1027 gtk_printer_set_is_new (printer, TRUE);
1028 list_has_changed = TRUE;
1031 if (gtk_printer_is_new (printer))
1033 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
1037 gtk_printer_set_is_new (printer, FALSE);
1040 cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1042 /* The ref is held by GtkPrintBackend, in add_printer() */
1043 g_object_unref (printer);
1050 /* look at the removed printers checklist and mark any printer
1051 as inactive if it is in the list, emitting a printer_removed signal */
1052 if (removed_printer_checklist != NULL)
1054 g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
1055 GTK_PRINT_BACKEND (cups_backend));
1056 g_list_free (removed_printer_checklist);
1057 list_has_changed = TRUE;
1060 if (list_has_changed)
1061 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
1063 gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
1067 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1070 GtkCupsRequest *request;
1071 static const char * const pattrs[] = /* Attributes we're interested in */
1074 "printer-uri-supported",
1078 if (cups_backend->list_printers_pending ||
1079 !cups_backend->got_default_printer)
1082 cups_backend->list_printers_pending = TRUE;
1086 request = gtk_cups_request_new (NULL,
1093 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1094 "requested-attributes", G_N_ELEMENTS (pattrs),
1097 cups_request_execute (cups_backend,
1099 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1109 cups_get_printer_list (GtkPrintBackend *backend)
1111 GtkPrintBackendCups *cups_backend;
1113 cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1114 if (cups_backend->list_printers_poll == 0)
1116 cups_request_printer_list (cups_backend);
1117 cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
1118 (GSourceFunc) cups_request_printer_list,
1124 GtkPrinterCups *printer;
1126 gchar *ppd_filename;
1130 get_ppd_data_free (GetPPDData *data)
1132 close (data->ppd_fd);
1133 unlink (data->ppd_filename);
1134 g_free (data->ppd_filename);
1135 g_object_unref (data->printer);
1140 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1141 GtkCupsResult *result,
1145 GtkPrinter *printer;
1147 printer = GTK_PRINTER (data->printer);
1148 GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1150 if (gtk_cups_result_is_error (result))
1152 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1156 response = gtk_cups_result_get_response (result);
1158 data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
1159 gtk_printer_set_has_details (printer, TRUE);
1160 g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
1164 cups_request_ppd (GtkPrinter *printer)
1167 GtkPrintBackend *print_backend;
1168 GtkPrinterCups *cups_printer;
1169 GtkCupsRequest *request;
1174 cups_printer = GTK_PRINTER_CUPS (printer);
1178 http = httpConnectEncrypt(cups_printer->hostname,
1182 data = g_new0 (GetPPDData, 1);
1184 data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
1185 &data->ppd_filename,
1190 g_warning ("%s", error->message);
1191 g_error_free (error);
1195 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1199 fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
1201 data->printer = g_object_ref (printer);
1203 resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
1204 request = gtk_cups_request_new (http,
1208 cups_printer->hostname,
1213 cups_printer->reading_ppd = TRUE;
1215 print_backend = gtk_printer_get_backend (printer);
1217 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1219 (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1221 (GDestroyNotify)get_ppd_data_free,
1227 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1228 GtkCupsResult *result,
1232 ipp_attribute_t *attr;
1234 response = gtk_cups_result_get_response (result);
1236 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
1237 print_backend->default_printer = g_strdup (attr->values[0].string.text);
1239 print_backend->got_default_printer = TRUE;
1241 /* Make sure to kick off get_printers if we are polling it, as we could
1242 have blocked this reading the default printer */
1243 if (print_backend->list_printers_poll != 0)
1244 cups_request_printer_list (print_backend);
1248 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1251 GtkCupsRequest *request;
1256 if ((str = getenv("LPDEST")) != NULL)
1258 print_backend->default_printer = g_strdup (str);
1259 print_backend->got_default_printer = TRUE;
1262 else if ((str = getenv("PRINTER")) != NULL &&
1263 strcmp(str, "lp") != 0)
1265 print_backend->default_printer = g_strdup (str);
1266 print_backend->got_default_printer = TRUE;
1270 request = gtk_cups_request_new (NULL,
1277 cups_request_execute (print_backend,
1279 (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1280 g_object_ref (print_backend),
1287 cups_printer_request_details (GtkPrinter *printer)
1289 GtkPrinterCups *cups_printer;
1291 cups_printer = GTK_PRINTER_CUPS (printer);
1292 if (!cups_printer->reading_ppd &&
1293 gtk_printer_cups_get_ppd (cups_printer) == NULL)
1294 cups_request_ppd (printer);
1298 ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
1300 const char *encoding = NULL;
1303 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1305 return g_strdup (text);
1307 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1309 encoding = "ISO-8859-1";
1311 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1313 encoding = "ISO-8859-2";
1315 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1317 encoding = "ISO-8859-5";
1319 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1321 encoding = "SHIFT-JIS";
1323 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1325 encoding = "MACINTOSH";
1327 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1329 encoding = "WINDOWS-1252";
1333 /* Fallback, try iso-8859-1... */
1334 encoding = "ISO-8859-1";
1337 res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1341 g_warning ("unable to convert PPD text");
1342 res = g_strdup ("???");
1348 /* TODO: Add more translations for common settings here */
1350 static const struct {
1351 const char *keyword;
1352 const char *translation;
1353 } cups_option_translations[] = {
1354 { "Duplex", N_("Two Sided") },
1355 { "MediaType", N_("Paper Type") },
1356 { "InputSlot", N_("Paper Source") },
1357 { "OutputBin", N_("Output Tray") },
1361 static const struct {
1362 const char *keyword;
1364 const char *translation;
1365 } cups_choice_translations[] = {
1366 { "Duplex", "None", N_("One Sided") },
1367 { "InputSlot", "Auto", N_("Auto Select") },
1368 { "InputSlot", "AutoSelect", N_("Auto Select") },
1369 { "InputSlot", "Default", N_("Printer Default") },
1370 { "InputSlot", "None", N_("Printer Default") },
1371 { "InputSlot", "PrinterDefault", N_("Printer Default") },
1372 { "InputSlot", "Unspecified", N_("Auto Select") },
1375 static const struct {
1376 const char *ppd_keyword;
1378 } option_names[] = {
1379 {"Duplex", "gtk-duplex" },
1380 {"MediaType", "gtk-paper-type"},
1381 {"InputSlot", "gtk-paper-source"},
1382 {"OutputBin", "gtk-output-tray"},
1385 /* keep sorted when changing */
1386 static const char *color_option_whitelist[] = {
1387 "BRColorEnhancement",
1393 "BlackSubstitution",
1401 "RPSBlackOverPrint",
1405 /* keep sorted when changing */
1406 static const char *color_group_whitelist[] = {
1413 "HPColorOptionsPanel",
1416 /* keep sorted when changing */
1417 static const char *image_quality_option_whitelist[] = {
1419 "BRHalfTonePattern",
1429 "HPGraphicsHalftone",
1444 /* keep sorted when changing */
1445 static const char *image_quality_group_whitelist[] = {
1452 /* keep sorted when changing */
1453 static const char * finishing_option_whitelist[] = {
1466 "StapleOrientation",
1472 /* keep sorted when changing */
1473 static const char *finishing_group_whitelist[] = {
1482 /* keep sorted when changing */
1483 static const char *cups_option_blacklist[] = {
1492 get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
1497 for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1499 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1500 return g_strdup (_(cups_option_translations[i].translation));
1503 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1505 /* Some ppd files have spaces in the text before the colon */
1512 get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
1515 ppd_option_t *option = choice->option;
1516 const char *keyword = option->keyword;
1518 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1520 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1521 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1522 return g_strdup (_(cups_choice_translations[i].translation));
1524 return ppd_text_to_utf8 (ppd_file, choice->text);
1528 group_has_option (ppd_group_t *group, ppd_option_t *option)
1535 if (group->num_options > 0 &&
1536 option >= group->options && option < group->options + group->num_options)
1539 for (i = 0; i < group->num_subgroups; i++)
1541 if (group_has_option (&group->subgroups[i],option))
1548 set_option_off (GtkPrinterOption *option)
1550 /* Any of these will do, _set only applies the value
1551 * if its allowed of the option */
1552 gtk_printer_option_set (option, "False");
1553 gtk_printer_option_set (option, "Off");
1554 gtk_printer_option_set (option, "None");
1558 value_is_off (const char *value)
1560 return (strcasecmp (value, "None") == 0 ||
1561 strcasecmp (value, "Off") == 0 ||
1562 strcasecmp (value, "False") == 0);
1566 available_choices (ppd_file_t *ppd,
1567 ppd_option_t *option,
1568 ppd_choice_t ***available,
1569 gboolean keep_if_only_one_option)
1571 ppd_option_t *other_option;
1574 ppd_const_t *constraint;
1575 const char *choice, *other_choice;
1576 ppd_option_t *option1, *option2;
1577 ppd_group_t *installed_options;
1579 gboolean all_default;
1585 conflicts = g_new0 (char, option->num_choices);
1587 installed_options = NULL;
1588 for (i = 0; i < ppd->num_groups; i++)
1590 if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
1592 installed_options = &ppd->groups[i];
1597 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1599 option1 = ppdFindOption (ppd, constraint->option1);
1600 if (option1 == NULL)
1603 option2 = ppdFindOption (ppd, constraint->option2);
1604 if (option2 == NULL)
1607 if (option == option1)
1609 choice = constraint->choice1;
1610 other_option = option2;
1611 other_choice = constraint->choice2;
1613 else if (option == option2)
1615 choice = constraint->choice2;
1616 other_option = option1;
1617 other_choice = constraint->choice1;
1622 /* We only care of conflicts with installed_options and
1624 if (!group_has_option (installed_options, other_option) &&
1625 (strcmp (other_option->keyword, "PageSize") != 0))
1628 if (*other_choice == 0)
1630 /* Conflict only if the installed option is not off */
1631 if (value_is_off (other_option->defchoice))
1634 /* Conflict if the installed option has the specified default */
1635 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1640 /* Conflict with all non-off choices */
1641 for (j = 0; j < option->num_choices; j++)
1643 if (!value_is_off (option->choices[j].choice))
1649 for (j = 0; j < option->num_choices; j++)
1651 if (strcasecmp (option->choices[j].choice, choice) == 0)
1659 for (j = 0; j < option->num_choices; j++)
1663 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1664 all_default = FALSE;
1667 if (all_default && !keep_if_only_one_option)
1670 if (num_conflicts == option->num_choices)
1674 /* Some ppds don't have a "use printer default" option for
1675 InputSlot. This means you always have to select a particular slot,
1676 and you can't auto-pick source based on the paper size. To support
1677 this we always add an auto option if there isn't one already. If
1678 the user chooses the generated option we don't send any InputSlot
1679 value when printing. The way we detect existing auto-cases is based
1680 on feedback from Michael Sweet of cups fame.
1683 if (strcmp (option->keyword, "InputSlot") == 0)
1685 gboolean found_auto = FALSE;
1686 for (j = 0; j < option->num_choices; j++)
1690 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1691 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1692 strcmp (option->choices[j].choice, "Default") == 0 ||
1693 strcmp (option->choices[j].choice, "None") == 0 ||
1694 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1695 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1696 option->choices[j].code == NULL ||
1697 option->choices[j].code[0] == 0)
1712 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1715 for (j = 0; j < option->num_choices; j++)
1718 (*available)[i++] = &option->choices[j];
1722 (*available)[i++] = NULL;
1725 return option->num_choices - num_conflicts + add_auto;
1728 static GtkPrinterOption *
1729 create_pickone_option (ppd_file_t *ppd_file,
1730 ppd_option_t *ppd_option,
1731 const char *gtk_name)
1733 GtkPrinterOption *option;
1734 ppd_choice_t **available;
1739 g_assert (ppd_option->ui == PPD_UI_PICKONE);
1743 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1746 label = get_option_text (ppd_file, ppd_option);
1747 option = gtk_printer_option_new (gtk_name, label,
1748 GTK_PRINTER_OPTION_TYPE_PICKONE);
1751 gtk_printer_option_allocate_choices (option, n_choices);
1752 for (i = 0; i < n_choices; i++)
1754 if (available[i] == NULL)
1756 /* This was auto-added */
1757 option->choices[i] = g_strdup ("gtk-ignore-value");
1758 option->choices_display[i] = g_strdup (_("Printer Default"));
1762 option->choices[i] = g_strdup (available[i]->choice);
1763 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1766 gtk_printer_option_set (option, ppd_option->defchoice);
1768 #ifdef PRINT_IGNORED_OPTIONS
1770 g_warning ("Ignoring pickone %s\n", ppd_option->text);
1777 static GtkPrinterOption *
1778 create_boolean_option (ppd_file_t *ppd_file,
1779 ppd_option_t *ppd_option,
1780 const char *gtk_name)
1782 GtkPrinterOption *option;
1783 ppd_choice_t **available;
1787 g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1791 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1794 label = get_option_text (ppd_file, ppd_option);
1795 option = gtk_printer_option_new (gtk_name, label,
1796 GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1799 gtk_printer_option_allocate_choices (option, 2);
1800 option->choices[0] = g_strdup ("True");
1801 option->choices_display[0] = g_strdup ("True");
1802 option->choices[1] = g_strdup ("True");
1803 option->choices_display[1] = g_strdup ("True");
1805 gtk_printer_option_set (option, ppd_option->defchoice);
1807 #ifdef PRINT_IGNORED_OPTIONS
1809 g_warning ("Ignoring boolean %s\n", ppd_option->text);
1817 get_option_name (const char *keyword)
1821 for (i = 0; i < G_N_ELEMENTS (option_names); i++)
1822 if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
1823 return g_strdup (option_names[i].name);
1825 return g_strdup_printf ("cups-%s", keyword);
1829 strptr_cmp (const void *a, const void *b)
1831 char **aa = (char **)a;
1832 char **bb = (char **)b;
1833 return strcmp (*aa, *bb);
1838 string_in_table (char *str, const char *table[], int table_len)
1840 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
1843 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
1846 handle_option (GtkPrinterOptionSet *set,
1847 ppd_file_t *ppd_file,
1848 ppd_option_t *ppd_option,
1849 ppd_group_t *toplevel_group,
1850 GtkPrintSettings *settings)
1852 GtkPrinterOption *option;
1855 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
1858 name = get_option_name (ppd_option->keyword);
1861 if (ppd_option->ui == PPD_UI_PICKONE)
1863 option = create_pickone_option (ppd_file, ppd_option, name);
1865 else if (ppd_option->ui == PPD_UI_BOOLEAN)
1867 option = create_boolean_option (ppd_file, ppd_option, name);
1870 g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
1875 if (STRING_IN_TABLE (toplevel_group->name,
1876 color_group_whitelist) ||
1877 STRING_IN_TABLE (ppd_option->keyword,
1878 color_option_whitelist))
1880 option->group = g_strdup ("ColorPage");
1882 else if (STRING_IN_TABLE (toplevel_group->name,
1883 image_quality_group_whitelist) ||
1884 STRING_IN_TABLE (ppd_option->keyword,
1885 image_quality_option_whitelist))
1887 option->group = g_strdup ("ImageQualityPage");
1889 else if (STRING_IN_TABLE (toplevel_group->name,
1890 finishing_group_whitelist) ||
1891 STRING_IN_TABLE (ppd_option->keyword,
1892 finishing_option_whitelist))
1894 option->group = g_strdup ("FinishingPage");
1898 option->group = g_strdup (toplevel_group->text);
1901 set_option_from_settings (option, settings);
1903 gtk_printer_option_set_add (set, option);
1910 handle_group (GtkPrinterOptionSet *set,
1911 ppd_file_t *ppd_file,
1913 ppd_group_t *toplevel_group,
1914 GtkPrintSettings *settings)
1918 /* Ignore installable options */
1919 if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
1922 for (i = 0; i < group->num_options; i++)
1923 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
1925 for (i = 0; i < group->num_subgroups; i++)
1926 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
1930 static GtkPrinterOptionSet *
1931 cups_printer_get_options (GtkPrinter *printer,
1932 GtkPrintSettings *settings,
1933 GtkPageSetup *page_setup)
1935 GtkPrinterOptionSet *set;
1936 GtkPrinterOption *option;
1937 ppd_file_t *ppd_file;
1939 char *print_at[] = { "now", "at", "on-hold" };
1940 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
1941 char *prio[] = {"100", "80", "50", "30" };
1942 char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
1943 char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
1944 char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
1947 set = gtk_printer_option_set_new ();
1949 /* Cups specific, non-ppd related settings */
1951 option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
1952 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
1954 gtk_printer_option_set (option, "1");
1955 set_option_from_settings (option, settings);
1956 gtk_printer_option_set_add (set, option);
1957 g_object_unref (option);
1959 for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
1960 prio_display[i] = _(prio_display[i]);
1962 option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
1963 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
1964 prio, prio_display);
1965 gtk_printer_option_set (option, "50");
1966 set_option_from_settings (option, settings);
1967 gtk_printer_option_set_add (set, option);
1968 g_object_unref (option);
1970 option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
1971 gtk_printer_option_set (option, "");
1972 set_option_from_settings (option, settings);
1973 gtk_printer_option_set_add (set, option);
1974 g_object_unref (option);
1976 for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
1977 cover_display[i] = _(cover_display[i]);
1979 option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
1980 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1981 cover, cover_display);
1982 gtk_printer_option_set (option, "none");
1983 set_option_from_settings (option, settings);
1984 gtk_printer_option_set_add (set, option);
1985 g_object_unref (option);
1987 option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
1988 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1989 cover, cover_display);
1990 gtk_printer_option_set (option, "none");
1991 set_option_from_settings (option, settings);
1992 gtk_printer_option_set_add (set, option);
1993 g_object_unref (option);
1995 option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
1996 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
1997 print_at, print_at);
1998 gtk_printer_option_set (option, "now");
1999 set_option_from_settings (option, settings);
2000 gtk_printer_option_set_add (set, option);
2001 g_object_unref (option);
2003 option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2004 gtk_printer_option_set (option, "");
2005 set_option_from_settings (option, settings);
2006 gtk_printer_option_set_add (set, option);
2007 g_object_unref (option);
2009 /* Printer (ppd) specific settings */
2010 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2013 GtkPaperSize *paper_size;
2014 ppd_option_t *option;
2016 ppdMarkDefaults (ppd_file);
2018 paper_size = gtk_page_setup_get_paper_size (page_setup);
2020 option = ppdFindOption(ppd_file, "PageSize");
2021 strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
2024 for (i = 0; i < ppd_file->num_groups; i++)
2025 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2033 mark_option_from_set (GtkPrinterOptionSet *set,
2034 ppd_file_t *ppd_file,
2035 ppd_option_t *ppd_option)
2037 GtkPrinterOption *option;
2038 char *name = get_option_name (ppd_option->keyword);
2040 option = gtk_printer_option_set_lookup (set, name);
2043 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2050 mark_group_from_set (GtkPrinterOptionSet *set,
2051 ppd_file_t *ppd_file,
2056 for (i = 0; i < group->num_options; i++)
2057 mark_option_from_set (set, ppd_file, &group->options[i]);
2059 for (i = 0; i < group->num_subgroups; i++)
2060 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2064 set_conflicts_from_option (GtkPrinterOptionSet *set,
2065 ppd_file_t *ppd_file,
2066 ppd_option_t *ppd_option)
2068 GtkPrinterOption *option;
2070 if (ppd_option->conflicted)
2072 name = get_option_name (ppd_option->keyword);
2073 option = gtk_printer_option_set_lookup (set, name);
2076 gtk_printer_option_set_has_conflict (option, TRUE);
2078 g_warning ("conflict for option %s ignored", ppd_option->keyword);
2085 set_conflicts_from_group (GtkPrinterOptionSet *set,
2086 ppd_file_t *ppd_file,
2091 for (i = 0; i < group->num_options; i++)
2092 set_conflicts_from_option (set, ppd_file, &group->options[i]);
2094 for (i = 0; i < group->num_subgroups; i++)
2095 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2099 cups_printer_mark_conflicts (GtkPrinter *printer,
2100 GtkPrinterOptionSet *options)
2102 ppd_file_t *ppd_file;
2106 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2108 if (ppd_file == NULL)
2111 ppdMarkDefaults (ppd_file);
2113 for (i = 0; i < ppd_file->num_groups; i++)
2114 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2116 num_conflicts = ppdConflicts (ppd_file);
2118 if (num_conflicts > 0)
2120 for (i = 0; i < ppd_file->num_groups; i++)
2121 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2124 return num_conflicts > 0;
2128 GtkPrinter *printer;
2129 GtkPrinterOptionSet *options;
2130 GtkPrintSettings *settings;
2131 ppd_file_t *ppd_file;
2136 const char *standard;
2140 map_settings_to_option (GtkPrinterOption *option,
2141 const NameMapping table[],
2143 GtkPrintSettings *settings,
2144 const char *standard_name,
2145 const char *cups_name)
2149 const char *cups_value;
2150 const char *standard_value;
2152 /* If the cups-specific setting is set, always use that */
2154 name = g_strdup_printf ("cups-%s", cups_name);
2155 cups_value = gtk_print_settings_get (settings, name);
2158 if (cups_value != NULL) {
2159 gtk_printer_option_set (option, cups_value);
2163 /* Otherwise we try to convert from the general setting */
2164 standard_value = gtk_print_settings_get (settings, standard_name);
2165 if (standard_value == NULL)
2168 for (i = 0; i < n_elements; i++)
2170 if (table[i].cups == NULL && table[i].standard == NULL)
2172 gtk_printer_option_set (option, standard_value);
2175 else if (table[i].cups == NULL &&
2176 strcmp (table[i].standard, standard_value) == 0)
2178 set_option_off (option);
2181 else if (strcmp (table[i].standard, standard_value) == 0)
2183 gtk_printer_option_set (option, table[i].cups);
2190 map_option_to_settings (const char *value,
2191 const NameMapping table[],
2193 GtkPrintSettings *settings,
2194 const char *standard_name,
2195 const char *cups_name)
2200 for (i = 0; i < n_elements; i++)
2202 if (table[i].cups == NULL && table[i].standard == NULL)
2204 gtk_print_settings_set (settings,
2209 else if (table[i].cups == NULL && table[i].standard != NULL)
2211 if (value_is_off (value))
2213 gtk_print_settings_set (settings,
2219 else if (strcmp (table[i].cups, value) == 0)
2221 gtk_print_settings_set (settings,
2228 /* Always set the corresponding cups-specific setting */
2229 name = g_strdup_printf ("cups-%s", cups_name);
2230 gtk_print_settings_set (settings, name, value);
2235 static const NameMapping paper_source_map[] = {
2236 { "Lower", "lower"},
2237 { "Middle", "middle"},
2238 { "Upper", "upper"},
2240 { "Envelope", "envelope"},
2241 { "Cassette", "cassette"},
2242 { "LargeCapacity", "large-capacity"},
2243 { "AnySmallFormat", "small-format"},
2244 { "AnyLargeFormat", "large-format"},
2248 static const NameMapping output_tray_map[] = {
2249 { "Upper", "upper"},
2250 { "Lower", "lower"},
2255 static const NameMapping duplex_map[] = {
2256 { "DuplexTumble", "vertical" },
2257 { "DuplexNoTumble", "horizontal" },
2261 static const NameMapping output_mode_map[] = {
2262 { "Standard", "normal" },
2263 { "Normal", "normal" },
2264 { "Draft", "draft" },
2265 { "Fast", "draft" },
2268 static const NameMapping media_type_map[] = {
2269 { "Transparency", "transparency"},
2270 { "Standard", "stationery"},
2274 static const NameMapping all_map[] = {
2280 set_option_from_settings (GtkPrinterOption *option,
2281 GtkPrintSettings *settings)
2283 const char *cups_value;
2286 if (settings == NULL)
2289 if (strcmp (option->name, "gtk-paper-source") == 0)
2290 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2291 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2292 else if (strcmp (option->name, "gtk-output-tray") == 0)
2293 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2294 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2295 else if (strcmp (option->name, "gtk-duplex") == 0)
2296 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2297 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2298 else if (strcmp (option->name, "cups-OutputMode") == 0)
2299 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2300 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2301 else if (strcmp (option->name, "cups-Resolution") == 0)
2303 cups_value = gtk_print_settings_get (settings, option->name);
2305 gtk_printer_option_set (option, cups_value);
2308 int res = gtk_print_settings_get_resolution (settings);
2311 value = g_strdup_printf ("%ddpi", res);
2312 gtk_printer_option_set (option, value);
2317 else if (strcmp (option->name, "gtk-paper-type") == 0)
2318 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2319 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2320 else if (strcmp (option->name, "gtk-n-up") == 0)
2322 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2323 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2325 else if (strcmp (option->name, "gtk-billing-info") == 0)
2327 cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2329 gtk_printer_option_set (option, cups_value);
2331 else if (strcmp (option->name, "gtk-job-prio") == 0)
2333 cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2335 gtk_printer_option_set (option, cups_value);
2337 else if (strcmp (option->name, "gtk-cover-before") == 0)
2339 cups_value = gtk_print_settings_get (settings, "cover-before");
2341 gtk_printer_option_set (option, cups_value);
2343 else if (strcmp (option->name, "gtk-cover-after") == 0)
2345 cups_value = gtk_print_settings_get (settings, "cover-after");
2347 gtk_printer_option_set (option, cups_value);
2349 else if (strcmp (option->name, "gtk-print-time") == 0)
2351 cups_value = gtk_print_settings_get (settings, "print-at");
2353 gtk_printer_option_set (option, cups_value);
2355 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2357 cups_value = gtk_print_settings_get (settings, "print-at-time");
2359 gtk_printer_option_set (option, cups_value);
2361 else if (g_str_has_prefix (option->name, "cups-"))
2363 cups_value = gtk_print_settings_get (settings, option->name);
2365 gtk_printer_option_set (option, cups_value);
2370 foreach_option_get_settings (GtkPrinterOption *option,
2373 struct OptionData *data = user_data;
2374 GtkPrintSettings *settings = data->settings;
2377 value = option->value;
2379 if (strcmp (option->name, "gtk-paper-source") == 0)
2380 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2381 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2382 else if (strcmp (option->name, "gtk-output-tray") == 0)
2383 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2384 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2385 else if (strcmp (option->name, "gtk-duplex") == 0)
2386 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2387 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2388 else if (strcmp (option->name, "cups-OutputMode") == 0)
2389 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2390 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2391 else if (strcmp (option->name, "cups-Resolution") == 0)
2393 int res = atoi (value);
2394 /* TODO: What if resolution is on XXXxYYYdpi form? */
2396 gtk_print_settings_set_resolution (settings, res);
2397 gtk_print_settings_set (settings, option->name, value);
2399 else if (strcmp (option->name, "gtk-paper-type") == 0)
2400 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2401 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2402 else if (strcmp (option->name, "gtk-n-up") == 0)
2403 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2404 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2405 else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2406 gtk_print_settings_set (settings, "cups-job-billing", value);
2407 else if (strcmp (option->name, "gtk-job-prio") == 0)
2408 gtk_print_settings_set (settings, "cups-job-priority", value);
2409 else if (strcmp (option->name, "gtk-cover-before") == 0)
2410 gtk_print_settings_set (settings, "cover-before", value);
2411 else if (strcmp (option->name, "gtk-cover-after") == 0)
2412 gtk_print_settings_set (settings, "cover-after", value);
2413 else if (strcmp (option->name, "gtk-print-time") == 0)
2414 gtk_print_settings_set (settings, "print-at", value);
2415 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2416 gtk_print_settings_set (settings, "print-at-time", value);
2417 else if (g_str_has_prefix (option->name, "cups-"))
2418 gtk_print_settings_set (settings, option->name, value);
2422 cups_printer_get_settings_from_options (GtkPrinter *printer,
2423 GtkPrinterOptionSet *options,
2424 GtkPrintSettings *settings)
2426 struct OptionData data;
2427 const char *print_at, *print_at_time;
2429 data.printer = printer;
2430 data.options = options;
2431 data.settings = settings;
2432 data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2434 if (data.ppd_file != NULL)
2436 GtkPrinterOption *cover_before, *cover_after;
2438 gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2440 cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2441 cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2442 if (cover_before && cover_after)
2444 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2445 gtk_print_settings_set (settings, "cups-job-sheets", value);
2449 print_at = gtk_print_settings_get (settings, "print-at");
2450 print_at_time = gtk_print_settings_get (settings, "print-at-time");
2451 if (strcmp (print_at, "at") == 0)
2452 gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2453 else if (strcmp (print_at, "on-hold") == 0)
2454 gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2459 cups_printer_prepare_for_print (GtkPrinter *printer,
2460 GtkPrintJob *print_job,
2461 GtkPrintSettings *settings,
2462 GtkPageSetup *page_setup)
2464 GtkPageSet page_set;
2465 GtkPaperSize *paper_size;
2466 const char *ppd_paper_name;
2469 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2470 print_job->page_ranges = NULL;
2471 print_job->num_page_ranges = 0;
2473 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2474 print_job->page_ranges =
2475 gtk_print_settings_get_page_ranges (settings,
2476 &print_job->num_page_ranges);
2478 if (gtk_print_settings_get_collate (settings))
2479 gtk_print_settings_set (settings, "cups-Collate", "True");
2480 print_job->collate = FALSE;
2482 if (gtk_print_settings_get_reverse (settings))
2483 gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2484 print_job->reverse = FALSE;
2486 if (gtk_print_settings_get_num_copies (settings) > 1)
2487 gtk_print_settings_set_int (settings, "cups-copies",
2488 gtk_print_settings_get_num_copies (settings));
2489 print_job->num_copies = 1;
2491 scale = gtk_print_settings_get_scale (settings);
2492 print_job->scale = 1.0;
2494 print_job->scale = scale/100.0;
2496 page_set = gtk_print_settings_get_page_set (settings);
2497 if (page_set == GTK_PAGE_SET_EVEN)
2498 gtk_print_settings_set (settings, "cups-page-set", "even");
2499 else if (page_set == GTK_PAGE_SET_ODD)
2500 gtk_print_settings_set (settings, "cups-page-set", "odd");
2501 print_job->page_set = GTK_PAGE_SET_ALL;
2503 paper_size = gtk_page_setup_get_paper_size (page_setup);
2504 ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2505 if (ppd_paper_name != NULL)
2506 gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2509 char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2510 gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2511 gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2512 gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2513 g_free (custom_name);
2516 print_job->rotate_to_orientation = TRUE;
2520 cups_printer_list_papers (GtkPrinter *printer)
2522 ppd_file_t *ppd_file;
2525 GtkPageSetup *page_setup;
2526 GtkPaperSize *paper_size;
2527 ppd_option_t *option;
2528 ppd_choice_t *choice;
2532 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2533 if (ppd_file == NULL)
2538 for (i = 0; i < ppd_file->num_sizes; i++)
2540 size = &ppd_file->sizes[i];
2542 display_name = NULL;
2543 option = ppdFindOption(ppd_file, "PageSize");
2546 choice = ppdFindChoice(option, size->name);
2548 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2550 if (display_name == NULL)
2551 display_name = g_strdup (size->name);
2553 page_setup = gtk_page_setup_new ();
2554 paper_size = gtk_paper_size_new_from_ppd (size->name,
2558 gtk_page_setup_set_paper_size (page_setup, paper_size);
2559 gtk_paper_size_free (paper_size);
2561 gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2562 gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2563 gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2564 gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2566 g_free (display_name);
2568 l = g_list_prepend (l, page_setup);
2571 return g_list_reverse (l);
2575 cups_printer_get_hard_margins (GtkPrinter *printer,
2581 ppd_file_t *ppd_file;
2583 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2584 if (ppd_file == NULL)
2587 *left = ppd_file->custom_margins[0];
2588 *bottom = ppd_file->custom_margins[1];
2589 *right = ppd_file->custom_margins[2];
2590 *top = ppd_file->custom_margins[3];