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>
44 #include <gtk/gtkprinter-private.h>
46 #include "gtkprintbackendcups.h"
47 #include "gtkprintercups.h"
49 #include "gtkcupsutils.h"
52 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
54 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
55 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
56 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
58 #define _CUPS_MAX_ATTEMPTS 10
59 #define _CUPS_MAX_CHUNK_SIZE 8192
61 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
62 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
64 static GType print_backend_cups_type = 0;
66 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
67 GtkCupsResult *result,
78 } GtkPrintCupsDispatchState;
85 GtkCupsRequest *request;
87 GtkPrintBackendCups *backend;
89 } GtkPrintCupsDispatchWatch;
91 struct _GtkPrintBackendCupsClass
93 GtkPrintBackendClass parent_class;
96 struct _GtkPrintBackendCups
98 GtkPrintBackend parent_instance;
100 char *default_printer;
102 guint list_printers_poll;
103 guint list_printers_pending : 1;
104 guint got_default_printer : 1;
107 static GObjectClass *backend_parent_class;
109 static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class);
110 static void gtk_print_backend_cups_init (GtkPrintBackendCups *impl);
111 static void gtk_print_backend_cups_finalize (GObject *object);
112 static void gtk_print_backend_cups_dispose (GObject *object);
113 static void cups_get_printer_list (GtkPrintBackend *print_backend);
114 static void cups_request_execute (GtkPrintBackendCups *print_backend,
115 GtkCupsRequest *request,
116 GtkPrintCupsResponseCallbackFunc callback,
118 GDestroyNotify notify,
120 static void cups_printer_get_settings_from_options (GtkPrinter *printer,
121 GtkPrinterOptionSet *options,
122 GtkPrintSettings *settings);
123 static gboolean cups_printer_mark_conflicts (GtkPrinter *printer,
124 GtkPrinterOptionSet *options);
125 static GtkPrinterOptionSet *cups_printer_get_options (GtkPrinter *printer,
126 GtkPrintSettings *settings,
127 GtkPageSetup *page_setup);
128 static void cups_printer_prepare_for_print (GtkPrinter *printer,
129 GtkPrintJob *print_job,
130 GtkPrintSettings *settings,
131 GtkPageSetup *page_setup);
132 static GList * cups_printer_list_papers (GtkPrinter *printer);
133 static void cups_printer_request_details (GtkPrinter *printer);
134 static void cups_request_default_printer (GtkPrintBackendCups *print_backend);
135 static void cups_request_ppd (GtkPrinter *printer);
136 static void cups_printer_get_hard_margins (GtkPrinter *printer,
141 static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer);
142 static void set_option_from_settings (GtkPrinterOption *option,
143 GtkPrintSettings *setting);
144 static void cups_begin_polling_info (GtkPrintBackendCups *print_backend,
147 static gboolean cups_job_info_poll_timeout (gpointer user_data);
148 static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend,
151 GtkPrintJobCompleteFunc callback,
153 GDestroyNotify dnotify);
154 static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer,
155 GtkPrintSettings *settings,
162 gtk_print_backend_cups_register_type (GTypeModule *module)
164 static const GTypeInfo print_backend_cups_info =
166 sizeof (GtkPrintBackendCupsClass),
167 NULL, /* base_init */
168 NULL, /* base_finalize */
169 (GClassInitFunc) gtk_print_backend_cups_class_init,
170 NULL, /* class_finalize */
171 NULL, /* class_data */
172 sizeof (GtkPrintBackendCups),
174 (GInstanceInitFunc) gtk_print_backend_cups_init
177 print_backend_cups_type = g_type_module_register_type (module,
178 GTK_TYPE_PRINT_BACKEND,
179 "GtkPrintBackendCups",
180 &print_backend_cups_info, 0);
184 pb_module_init (GTypeModule *module)
186 gtk_print_backend_cups_register_type (module);
187 gtk_printer_cups_register_type (module);
191 pb_module_exit (void)
196 G_MODULE_EXPORT GtkPrintBackend *
197 pb_module_create (void)
199 return gtk_print_backend_cups_new ();
203 * GtkPrintBackendCups
206 gtk_print_backend_cups_get_type (void)
208 return print_backend_cups_type;
212 * gtk_print_backend_cups_new:
214 * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
215 * implements the #GtkPrintBackend interface with direct access to
216 * the filesystem using Unix/Linux API calls
218 * Return value: the new #GtkPrintBackendCups object
221 gtk_print_backend_cups_new (void)
223 return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
227 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
229 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
230 GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
232 backend_parent_class = g_type_class_peek_parent (class);
234 gobject_class->finalize = gtk_print_backend_cups_finalize;
235 gobject_class->dispose = gtk_print_backend_cups_dispose;
237 backend_class->request_printer_list = cups_get_printer_list;
238 backend_class->print_stream = gtk_print_backend_cups_print_stream;
239 backend_class->printer_request_details = cups_printer_request_details;
240 backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
241 backend_class->printer_get_options = cups_printer_get_options;
242 backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
243 backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
244 backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
245 backend_class->printer_list_papers = cups_printer_list_papers;
246 backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
247 backend_class->printer_get_capabilities = cups_printer_get_capabilities;
250 static cairo_status_t
251 _cairo_write_to_cups (void *cache_fd_as_pointer,
252 const unsigned char *data,
255 cairo_status_t result;
257 cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
259 result = CAIRO_STATUS_WRITE_ERROR;
261 /* write out the buffer */
262 if (write (cache_fd, data, length) != -1)
263 result = CAIRO_STATUS_SUCCESS;
269 static cairo_surface_t *
270 cups_printer_create_cairo_surface (GtkPrinter *printer,
271 GtkPrintSettings *settings,
276 cairo_surface_t *surface;
278 /* TODO: check if it is a ps or pdf printer */
280 surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
282 /* TODO: DPI from settings object? */
283 cairo_surface_set_fallback_resolution (surface, 300, 300);
289 GtkPrintJobCompleteFunc callback;
292 GDestroyNotify dnotify;
293 } CupsPrintStreamData;
296 cups_free_print_stream_data (CupsPrintStreamData *data)
299 data->dnotify (data->user_data);
300 g_object_unref (data->job);
305 cups_print_cb (GtkPrintBackendCups *print_backend,
306 GtkCupsResult *result,
309 GError *error = NULL;
310 CupsPrintStreamData *ps = user_data;
312 if (gtk_cups_result_is_error (result))
313 error = g_error_new_literal (gtk_print_error_quark (),
314 GTK_PRINT_ERROR_INTERNAL_ERROR,
315 gtk_cups_result_get_error_string (result));
318 ps->callback (ps->job, ps->user_data, error);
323 ipp_attribute_t *attr; /* IPP job-id attribute */
324 ipp_t *response = gtk_cups_result_get_response (result);
326 if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
327 job_id = attr->values[0].integer;
329 if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
330 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
333 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
334 cups_begin_polling_info (print_backend, ps->job, job_id);
338 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
342 g_error_free (error);
347 add_cups_options (const char *key,
351 GtkCupsRequest *request = user_data;
353 if (!g_str_has_prefix (key, "cups-"))
356 if (strcmp (value, "gtk-ignore-value") == 0)
359 key = key + strlen("cups-");
361 gtk_cups_request_encode_option (request, key, value);
365 gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
368 GtkPrintJobCompleteFunc callback,
370 GDestroyNotify dnotify)
373 GtkPrinterCups *cups_printer;
374 CupsPrintStreamData *ps;
375 GtkCupsRequest *request;
376 GtkPrintSettings *settings;
379 cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
380 settings = gtk_print_job_get_settings (job);
384 request = gtk_cups_request_new (NULL,
389 cups_printer->device_uri);
391 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
392 NULL, cups_printer->printer_uri);
394 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
397 title = gtk_print_job_get_title (job);
399 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
402 gtk_print_settings_foreach (settings, add_cups_options, request);
404 ps = g_new0 (CupsPrintStreamData, 1);
405 ps->callback = callback;
406 ps->user_data = user_data;
407 ps->dnotify = dnotify;
408 ps->job = g_object_ref (job);
410 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
412 (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
414 (GDestroyNotify)cups_free_print_stream_data,
420 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
422 backend_cups->list_printers_poll = 0;
423 backend_cups->list_printers_pending = FALSE;
425 cups_request_default_printer (backend_cups);
429 gtk_print_backend_cups_finalize (GObject *object)
431 GtkPrintBackendCups *backend_cups;
433 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
435 g_free (backend_cups->default_printer);
436 backend_cups->default_printer = NULL;
438 backend_parent_class->finalize (object);
442 gtk_print_backend_cups_dispose (GObject *object)
444 GtkPrintBackendCups *backend_cups;
446 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
448 if (backend_cups->list_printers_poll > 0)
449 g_source_remove (backend_cups->list_printers_poll);
450 backend_cups->list_printers_poll = 0;
452 backend_parent_class->dispose (object);
457 cups_dispatch_watch_check (GSource *source)
459 GtkPrintCupsDispatchWatch *dispatch;
460 GtkCupsPollState poll_state;
463 dispatch = (GtkPrintCupsDispatchWatch *) source;
465 poll_state = gtk_cups_request_get_poll_state (dispatch->request);
467 if (dispatch->data_poll == NULL &&
468 dispatch->request->http != NULL)
470 dispatch->data_poll = g_new0 (GPollFD, 1);
471 dispatch->data_poll->fd = dispatch->request->http->fd;
473 g_source_add_poll (source, dispatch->data_poll);
476 if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
478 if (dispatch->data_poll->fd != dispatch->request->http->fd)
479 dispatch->data_poll->fd = dispatch->request->http->fd;
481 if (poll_state == GTK_CUPS_HTTP_READ)
482 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
483 else if (poll_state == GTK_CUPS_HTTP_WRITE)
484 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
486 dispatch->data_poll->events = 0;
489 if (poll_state != GTK_CUPS_HTTP_IDLE)
490 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
493 result = gtk_cups_request_read_write (dispatch->request);
494 if (result && dispatch->data_poll != NULL)
496 g_source_remove_poll (source, dispatch->data_poll);
497 g_free (dispatch->data_poll);
498 dispatch->data_poll = NULL;
505 cups_dispatch_watch_prepare (GSource *source,
508 GtkPrintCupsDispatchWatch *dispatch;
510 dispatch = (GtkPrintCupsDispatchWatch *) source;
514 return gtk_cups_request_read_write (dispatch->request);
518 cups_dispatch_watch_dispatch (GSource *source,
519 GSourceFunc callback,
522 GtkPrintCupsDispatchWatch *dispatch;
523 GtkPrintCupsResponseCallbackFunc ep_callback;
524 GtkCupsResult *result;
526 g_assert (callback != NULL);
528 ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
530 dispatch = (GtkPrintCupsDispatchWatch *) source;
532 result = gtk_cups_request_get_result (dispatch->request);
534 if (gtk_cups_result_is_error (result))
535 g_warning (gtk_cups_result_get_error_string (result));
537 ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
543 cups_dispatch_watch_finalize (GSource *source)
545 GtkPrintCupsDispatchWatch *dispatch;
547 dispatch = (GtkPrintCupsDispatchWatch *) source;
549 gtk_cups_request_free (dispatch->request);
551 if (dispatch->backend)
553 /* We need to unref this at idle time, because it might be the
554 * last reference to this module causing the code to be
555 * unloaded (including this particular function!)
556 * Update: Doing this at idle caused a deadlock taking the
557 * mainloop context lock while being in a GSource callout for
558 * multithreaded apps. So, for now we just disable unloading
559 * of print backends. See _gtk_print_backend_create for the
562 g_object_unref (dispatch->backend);
563 dispatch->backend = NULL;
566 if (dispatch->data_poll != NULL)
567 g_free (dispatch->data_poll);
570 static GSourceFuncs _cups_dispatch_watch_funcs = {
571 cups_dispatch_watch_prepare,
572 cups_dispatch_watch_check,
573 cups_dispatch_watch_dispatch,
574 cups_dispatch_watch_finalize
579 cups_request_execute (GtkPrintBackendCups *print_backend,
580 GtkCupsRequest *request,
581 GtkPrintCupsResponseCallbackFunc callback,
583 GDestroyNotify notify,
586 GtkPrintCupsDispatchWatch *dispatch;
588 dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
589 sizeof (GtkPrintCupsDispatchWatch));
591 dispatch->request = request;
592 dispatch->backend = g_object_ref (print_backend);
593 dispatch->data_poll = NULL;
595 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
597 g_source_attach ((GSource *) dispatch, NULL);
598 g_source_unref ((GSource *) dispatch);
602 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
603 GtkCupsResult *result,
606 ipp_attribute_t *attr;
609 GtkPrinterCups *cups_printer;
615 gboolean status_changed;
617 g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
619 printer_name = (gchar *)user_data;
620 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
626 cups_printer = GTK_PRINTER_CUPS (printer);
628 if (gtk_cups_result_is_error (result))
630 if (gtk_printer_is_new (printer))
632 gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
637 return; /* TODO: mark as inactive printer */
640 response = gtk_cups_result_get_response (result);
642 /* TODO: determine printer type and use correct icon */
643 gtk_printer_set_icon_name (printer, "printer");
649 for (attr = response->attrs; attr != NULL; attr = attr->next)
654 _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
655 _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
656 _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
657 _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
658 _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
661 status_changed = gtk_printer_set_job_count (printer, job_count);
663 status_changed |= gtk_printer_set_location (printer, loc);
664 status_changed |= gtk_printer_set_description (printer, desc);
665 status_changed |= gtk_printer_set_state_message (printer, state_msg);
668 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
669 "printer-status-changed", printer);
673 cups_request_printer_info (GtkPrintBackendCups *print_backend,
674 const gchar *printer_name)
677 GtkCupsRequest *request;
679 static const char * const pattrs[] = /* Attributes we're interested in */
683 "printer-state-message",
690 request = gtk_cups_request_new (NULL,
692 IPP_GET_PRINTER_ATTRIBUTES,
697 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
699 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
700 "printer-uri", NULL, printer_uri);
702 g_free (printer_uri);
704 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
705 "requested-attributes", G_N_ELEMENTS (pattrs),
708 cups_request_execute (print_backend,
710 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
711 g_strdup (printer_name),
712 (GDestroyNotify) g_free,
719 GtkPrintBackendCups *print_backend;
726 job_object_died (gpointer user_data,
727 GObject *where_the_object_was)
729 CupsJobPollData *data = user_data;
734 cups_job_poll_data_free (CupsJobPollData *data)
737 g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
743 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
744 GtkCupsResult *result,
747 CupsJobPollData *data = user_data;
748 ipp_attribute_t *attr;
753 if (data->job == NULL)
755 cups_job_poll_data_free (data);
761 response = gtk_cups_result_get_response (result);
764 for (attr = response->attrs; attr != NULL; attr = attr->next)
769 _CUPS_MAP_ATTR_INT (attr, state, "job-state");
775 case IPP_JOB_PENDING:
777 case IPP_JOB_STOPPED:
778 gtk_print_job_set_status (data->job,
779 GTK_PRINT_STATUS_PENDING);
781 case IPP_JOB_PROCESSING:
782 gtk_print_job_set_status (data->job,
783 GTK_PRINT_STATUS_PRINTING);
786 case IPP_JOB_CANCELLED:
787 case IPP_JOB_ABORTED:
788 gtk_print_job_set_status (data->job,
789 GTK_PRINT_STATUS_FINISHED_ABORTED);
793 case IPP_JOB_COMPLETED:
794 gtk_print_job_set_status (data->job,
795 GTK_PRINT_STATUS_FINISHED);
800 if (!done && data->job != NULL)
804 if (data->counter < 5)
806 else if (data->counter < 10)
811 g_timeout_add (timeout, cups_job_info_poll_timeout, data);
814 cups_job_poll_data_free (data);
818 cups_request_job_info (CupsJobPollData *data)
821 GtkCupsRequest *request;
826 request = gtk_cups_request_new (NULL,
828 IPP_GET_JOB_ATTRIBUTES,
833 printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
834 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
835 "job-uri", NULL, printer_uri);
836 g_free (printer_uri);
838 cups_request_execute (data->print_backend,
840 (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
847 cups_job_info_poll_timeout (gpointer user_data)
849 CupsJobPollData *data = user_data;
851 if (data->job == NULL)
852 cups_job_poll_data_free (data);
854 cups_request_job_info (data);
860 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
864 CupsJobPollData *data;
866 data = g_new0 (CupsJobPollData, 1);
868 data->print_backend = print_backend;
870 data->job_id = job_id;
873 g_object_weak_ref (G_OBJECT (job), job_object_died, data);
875 cups_request_job_info (data);
879 mark_printer_inactive (GtkPrinter *printer,
880 GtkPrintBackend *backend)
882 gtk_printer_set_is_active (printer, FALSE);
883 g_signal_emit_by_name (backend,
884 "printer-removed", printer);
888 find_printer (GtkPrinter *printer, const char *find_name)
890 const char *printer_name;
892 printer_name = gtk_printer_get_name (printer);
893 return g_ascii_strcasecmp (printer_name, find_name);
897 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
898 GtkCupsResult *result,
901 ipp_attribute_t *attr;
903 gboolean list_has_changed;
904 GList *removed_printer_checklist;
906 list_has_changed = FALSE;
908 g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
910 cups_backend->list_printers_pending = FALSE;
912 if (gtk_cups_result_is_error (result))
914 g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
918 /* gether the names of the printers in the current queue
919 so we may check to see if they were removed */
920 removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
922 response = gtk_cups_result_get_response (result);
925 for (attr = response->attrs; attr != NULL; attr = attr->next)
928 const gchar *printer_name;
929 const char *printer_uri;
930 const char *member_uris;
934 * Skip leading attributes until we hit a printer...
936 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
945 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
947 if (!strcmp(attr->name, "printer-name") &&
948 attr->value_tag == IPP_TAG_NAME)
949 printer_name = attr->values[0].string.text;
950 else if (!strcmp(attr->name, "printer-uri-supported") &&
951 attr->value_tag == IPP_TAG_URI)
952 printer_uri = attr->values[0].string.text;
953 else if (!strcmp(attr->name, "member-uris") &&
954 attr->value_tag == IPP_TAG_URI)
955 member_uris = attr->values[0].string.text;
960 if (printer_name == NULL ||
961 (printer_uri == NULL && member_uris == NULL))
969 /* remove name from checklist if it was found */
970 node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
971 removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
973 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
976 GtkPrinterCups *cups_printer;
977 char uri[HTTP_MAX_URI], /* Printer URI */
978 method[HTTP_MAX_URI], /* Method/scheme name */
979 username[HTTP_MAX_URI], /* Username:password */
980 hostname[HTTP_MAX_URI], /* Hostname */
981 resource[HTTP_MAX_URI]; /* Resource name */
982 int port; /* Port number */
984 list_has_changed = TRUE;
985 cups_printer = gtk_printer_cups_new (printer_name,
986 GTK_PRINT_BACKEND (cups_backend));
988 cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
992 cups_printer->printer_uri = g_strdup (member_uris);
995 cups_printer->printer_uri = g_strdup (printer_uri);
997 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
998 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
999 method, sizeof (method),
1000 username, sizeof (username),
1001 hostname, sizeof (hostname),
1003 resource, sizeof (resource));
1006 httpSeparate (cups_printer->printer_uri,
1014 gethostname(uri, sizeof(uri));
1015 if (strcasecmp(uri, hostname) == 0)
1016 strcpy(hostname, "localhost");
1018 cups_printer->hostname = g_strdup (hostname);
1019 cups_printer->port = port;
1021 printer = GTK_PRINTER (cups_printer);
1023 if (cups_backend->default_printer != NULL &&
1024 strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1025 gtk_printer_set_is_default (printer, TRUE);
1028 gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
1031 g_object_ref (printer);
1033 if (!gtk_printer_is_active (printer))
1035 gtk_printer_set_is_active (printer, TRUE);
1036 gtk_printer_set_is_new (printer, TRUE);
1037 list_has_changed = TRUE;
1040 if (gtk_printer_is_new (printer))
1042 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend),
1046 gtk_printer_set_is_new (printer, FALSE);
1049 cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1051 /* The ref is held by GtkPrintBackend, in add_printer() */
1052 g_object_unref (printer);
1059 /* look at the removed printers checklist and mark any printer
1060 as inactive if it is in the list, emitting a printer_removed signal */
1061 if (removed_printer_checklist != NULL)
1063 g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
1064 GTK_PRINT_BACKEND (cups_backend));
1065 g_list_free (removed_printer_checklist);
1066 list_has_changed = TRUE;
1069 if (list_has_changed)
1070 g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
1072 gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
1076 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1079 GtkCupsRequest *request;
1080 static const char * const pattrs[] = /* Attributes we're interested in */
1083 "printer-uri-supported",
1087 if (cups_backend->list_printers_pending ||
1088 !cups_backend->got_default_printer)
1091 cups_backend->list_printers_pending = TRUE;
1095 request = gtk_cups_request_new (NULL,
1102 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1103 "requested-attributes", G_N_ELEMENTS (pattrs),
1106 cups_request_execute (cups_backend,
1108 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1118 cups_get_printer_list (GtkPrintBackend *backend)
1120 GtkPrintBackendCups *cups_backend;
1122 cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1123 if (cups_backend->list_printers_poll == 0)
1125 cups_request_printer_list (cups_backend);
1126 cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
1127 (GSourceFunc) cups_request_printer_list,
1133 GtkPrinterCups *printer;
1135 gchar *ppd_filename;
1139 get_ppd_data_free (GetPPDData *data)
1141 close (data->ppd_fd);
1142 unlink (data->ppd_filename);
1143 g_free (data->ppd_filename);
1144 g_object_unref (data->printer);
1149 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1150 GtkCupsResult *result,
1154 GtkPrinter *printer;
1156 printer = GTK_PRINTER (data->printer);
1157 GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1159 if (gtk_cups_result_is_error (result))
1161 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1165 response = gtk_cups_result_get_response (result);
1167 data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
1168 gtk_printer_set_has_details (printer, TRUE);
1169 g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
1173 cups_request_ppd (GtkPrinter *printer)
1176 GtkPrintBackend *print_backend;
1177 GtkPrinterCups *cups_printer;
1178 GtkCupsRequest *request;
1183 cups_printer = GTK_PRINTER_CUPS (printer);
1186 /* FIXME this can return NULL! */
1187 http = httpConnectEncrypt(cups_printer->hostname,
1191 data = g_new0 (GetPPDData, 1);
1193 data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
1194 &data->ppd_filename,
1199 g_warning ("%s", error->message);
1200 g_error_free (error);
1204 g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
1208 fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
1210 data->printer = g_object_ref (printer);
1212 resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
1213 request = gtk_cups_request_new (http,
1217 cups_printer->hostname,
1222 cups_printer->reading_ppd = TRUE;
1224 print_backend = gtk_printer_get_backend (printer);
1226 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1228 (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1230 (GDestroyNotify)get_ppd_data_free,
1236 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1237 GtkCupsResult *result,
1241 ipp_attribute_t *attr;
1243 response = gtk_cups_result_get_response (result);
1245 if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
1246 print_backend->default_printer = g_strdup (attr->values[0].string.text);
1248 print_backend->got_default_printer = TRUE;
1250 /* Make sure to kick off get_printers if we are polling it, as we could
1251 have blocked this reading the default printer */
1252 if (print_backend->list_printers_poll != 0)
1253 cups_request_printer_list (print_backend);
1257 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1260 GtkCupsRequest *request;
1265 if ((str = getenv("LPDEST")) != NULL)
1267 print_backend->default_printer = g_strdup (str);
1268 print_backend->got_default_printer = TRUE;
1271 else if ((str = getenv("PRINTER")) != NULL &&
1272 strcmp(str, "lp") != 0)
1274 print_backend->default_printer = g_strdup (str);
1275 print_backend->got_default_printer = TRUE;
1279 request = gtk_cups_request_new (NULL,
1286 cups_request_execute (print_backend,
1288 (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1289 g_object_ref (print_backend),
1296 cups_printer_request_details (GtkPrinter *printer)
1298 GtkPrinterCups *cups_printer;
1300 cups_printer = GTK_PRINTER_CUPS (printer);
1301 if (!cups_printer->reading_ppd &&
1302 gtk_printer_cups_get_ppd (cups_printer) == NULL)
1303 cups_request_ppd (printer);
1307 ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
1309 const char *encoding = NULL;
1312 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1314 return g_strdup (text);
1316 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1318 encoding = "ISO-8859-1";
1320 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1322 encoding = "ISO-8859-2";
1324 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1326 encoding = "ISO-8859-5";
1328 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1330 encoding = "SHIFT-JIS";
1332 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1334 encoding = "MACINTOSH";
1336 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1338 encoding = "WINDOWS-1252";
1342 /* Fallback, try iso-8859-1... */
1343 encoding = "ISO-8859-1";
1346 res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1350 g_warning ("unable to convert PPD text");
1351 res = g_strdup ("???");
1357 /* TODO: Add more translations for common settings here */
1359 static const struct {
1360 const char *keyword;
1361 const char *translation;
1362 } cups_option_translations[] = {
1363 { "Duplex", N_("Two Sided") },
1364 { "MediaType", N_("Paper Type") },
1365 { "InputSlot", N_("Paper Source") },
1366 { "OutputBin", N_("Output Tray") },
1370 static const struct {
1371 const char *keyword;
1373 const char *translation;
1374 } cups_choice_translations[] = {
1375 { "Duplex", "None", N_("One Sided") },
1376 { "InputSlot", "Auto", N_("Auto Select") },
1377 { "InputSlot", "AutoSelect", N_("Auto Select") },
1378 { "InputSlot", "Default", N_("Printer Default") },
1379 { "InputSlot", "None", N_("Printer Default") },
1380 { "InputSlot", "PrinterDefault", N_("Printer Default") },
1381 { "InputSlot", "Unspecified", N_("Auto Select") },
1384 static const struct {
1385 const char *ppd_keyword;
1387 } option_names[] = {
1388 {"Duplex", "gtk-duplex" },
1389 {"MediaType", "gtk-paper-type"},
1390 {"InputSlot", "gtk-paper-source"},
1391 {"OutputBin", "gtk-output-tray"},
1394 /* keep sorted when changing */
1395 static const char *color_option_whitelist[] = {
1396 "BRColorEnhancement",
1402 "BlackSubstitution",
1410 "RPSBlackOverPrint",
1414 /* keep sorted when changing */
1415 static const char *color_group_whitelist[] = {
1422 "HPColorOptionsPanel",
1425 /* keep sorted when changing */
1426 static const char *image_quality_option_whitelist[] = {
1428 "BRHalfTonePattern",
1438 "HPGraphicsHalftone",
1453 /* keep sorted when changing */
1454 static const char *image_quality_group_whitelist[] = {
1461 /* keep sorted when changing */
1462 static const char * finishing_option_whitelist[] = {
1475 "StapleOrientation",
1481 /* keep sorted when changing */
1482 static const char *finishing_group_whitelist[] = {
1491 /* keep sorted when changing */
1492 static const char *cups_option_blacklist[] = {
1501 get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
1506 for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1508 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1509 return g_strdup (_(cups_option_translations[i].translation));
1512 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1514 /* Some ppd files have spaces in the text before the colon */
1521 get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
1524 ppd_option_t *option = choice->option;
1525 const char *keyword = option->keyword;
1527 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1529 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1530 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1531 return g_strdup (_(cups_choice_translations[i].translation));
1533 return ppd_text_to_utf8 (ppd_file, choice->text);
1537 group_has_option (ppd_group_t *group, ppd_option_t *option)
1544 if (group->num_options > 0 &&
1545 option >= group->options && option < group->options + group->num_options)
1548 for (i = 0; i < group->num_subgroups; i++)
1550 if (group_has_option (&group->subgroups[i],option))
1557 set_option_off (GtkPrinterOption *option)
1559 /* Any of these will do, _set only applies the value
1560 * if its allowed of the option */
1561 gtk_printer_option_set (option, "False");
1562 gtk_printer_option_set (option, "Off");
1563 gtk_printer_option_set (option, "None");
1567 value_is_off (const char *value)
1569 return (strcasecmp (value, "None") == 0 ||
1570 strcasecmp (value, "Off") == 0 ||
1571 strcasecmp (value, "False") == 0);
1575 available_choices (ppd_file_t *ppd,
1576 ppd_option_t *option,
1577 ppd_choice_t ***available,
1578 gboolean keep_if_only_one_option)
1580 ppd_option_t *other_option;
1583 ppd_const_t *constraint;
1584 const char *choice, *other_choice;
1585 ppd_option_t *option1, *option2;
1586 ppd_group_t *installed_options;
1588 gboolean all_default;
1594 conflicts = g_new0 (char, option->num_choices);
1596 installed_options = NULL;
1597 for (i = 0; i < ppd->num_groups; i++)
1599 if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
1601 installed_options = &ppd->groups[i];
1606 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1608 option1 = ppdFindOption (ppd, constraint->option1);
1609 if (option1 == NULL)
1612 option2 = ppdFindOption (ppd, constraint->option2);
1613 if (option2 == NULL)
1616 if (option == option1)
1618 choice = constraint->choice1;
1619 other_option = option2;
1620 other_choice = constraint->choice2;
1622 else if (option == option2)
1624 choice = constraint->choice2;
1625 other_option = option1;
1626 other_choice = constraint->choice1;
1631 /* We only care of conflicts with installed_options and
1633 if (!group_has_option (installed_options, other_option) &&
1634 (strcmp (other_option->keyword, "PageSize") != 0))
1637 if (*other_choice == 0)
1639 /* Conflict only if the installed option is not off */
1640 if (value_is_off (other_option->defchoice))
1643 /* Conflict if the installed option has the specified default */
1644 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1649 /* Conflict with all non-off choices */
1650 for (j = 0; j < option->num_choices; j++)
1652 if (!value_is_off (option->choices[j].choice))
1658 for (j = 0; j < option->num_choices; j++)
1660 if (strcasecmp (option->choices[j].choice, choice) == 0)
1668 for (j = 0; j < option->num_choices; j++)
1672 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1673 all_default = FALSE;
1676 if (all_default && !keep_if_only_one_option)
1679 if (num_conflicts == option->num_choices)
1683 /* Some ppds don't have a "use printer default" option for
1684 InputSlot. This means you always have to select a particular slot,
1685 and you can't auto-pick source based on the paper size. To support
1686 this we always add an auto option if there isn't one already. If
1687 the user chooses the generated option we don't send any InputSlot
1688 value when printing. The way we detect existing auto-cases is based
1689 on feedback from Michael Sweet of cups fame.
1692 if (strcmp (option->keyword, "InputSlot") == 0)
1694 gboolean found_auto = FALSE;
1695 for (j = 0; j < option->num_choices; j++)
1699 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1700 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1701 strcmp (option->choices[j].choice, "Default") == 0 ||
1702 strcmp (option->choices[j].choice, "None") == 0 ||
1703 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1704 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1705 option->choices[j].code == NULL ||
1706 option->choices[j].code[0] == 0)
1721 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1724 for (j = 0; j < option->num_choices; j++)
1727 (*available)[i++] = &option->choices[j];
1731 (*available)[i++] = NULL;
1734 return option->num_choices - num_conflicts + add_auto;
1737 static GtkPrinterOption *
1738 create_pickone_option (ppd_file_t *ppd_file,
1739 ppd_option_t *ppd_option,
1740 const char *gtk_name)
1742 GtkPrinterOption *option;
1743 ppd_choice_t **available;
1748 g_assert (ppd_option->ui == PPD_UI_PICKONE);
1752 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1755 label = get_option_text (ppd_file, ppd_option);
1756 option = gtk_printer_option_new (gtk_name, label,
1757 GTK_PRINTER_OPTION_TYPE_PICKONE);
1760 gtk_printer_option_allocate_choices (option, n_choices);
1761 for (i = 0; i < n_choices; i++)
1763 if (available[i] == NULL)
1765 /* This was auto-added */
1766 option->choices[i] = g_strdup ("gtk-ignore-value");
1767 option->choices_display[i] = g_strdup (_("Printer Default"));
1771 option->choices[i] = g_strdup (available[i]->choice);
1772 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1775 gtk_printer_option_set (option, ppd_option->defchoice);
1777 #ifdef PRINT_IGNORED_OPTIONS
1779 g_warning ("Ignoring pickone %s\n", ppd_option->text);
1786 static GtkPrinterOption *
1787 create_boolean_option (ppd_file_t *ppd_file,
1788 ppd_option_t *ppd_option,
1789 const char *gtk_name)
1791 GtkPrinterOption *option;
1792 ppd_choice_t **available;
1796 g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1800 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1803 label = get_option_text (ppd_file, ppd_option);
1804 option = gtk_printer_option_new (gtk_name, label,
1805 GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1808 gtk_printer_option_allocate_choices (option, 2);
1809 option->choices[0] = g_strdup ("True");
1810 option->choices_display[0] = g_strdup ("True");
1811 option->choices[1] = g_strdup ("True");
1812 option->choices_display[1] = g_strdup ("True");
1814 gtk_printer_option_set (option, ppd_option->defchoice);
1816 #ifdef PRINT_IGNORED_OPTIONS
1818 g_warning ("Ignoring boolean %s\n", ppd_option->text);
1826 get_option_name (const char *keyword)
1830 for (i = 0; i < G_N_ELEMENTS (option_names); i++)
1831 if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
1832 return g_strdup (option_names[i].name);
1834 return g_strdup_printf ("cups-%s", keyword);
1838 strptr_cmp (const void *a, const void *b)
1840 char **aa = (char **)a;
1841 char **bb = (char **)b;
1842 return strcmp (*aa, *bb);
1847 string_in_table (char *str, const char *table[], int table_len)
1849 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
1852 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
1855 handle_option (GtkPrinterOptionSet *set,
1856 ppd_file_t *ppd_file,
1857 ppd_option_t *ppd_option,
1858 ppd_group_t *toplevel_group,
1859 GtkPrintSettings *settings)
1861 GtkPrinterOption *option;
1864 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
1867 name = get_option_name (ppd_option->keyword);
1870 if (ppd_option->ui == PPD_UI_PICKONE)
1872 option = create_pickone_option (ppd_file, ppd_option, name);
1874 else if (ppd_option->ui == PPD_UI_BOOLEAN)
1876 option = create_boolean_option (ppd_file, ppd_option, name);
1879 g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
1884 if (STRING_IN_TABLE (toplevel_group->name,
1885 color_group_whitelist) ||
1886 STRING_IN_TABLE (ppd_option->keyword,
1887 color_option_whitelist))
1889 option->group = g_strdup ("ColorPage");
1891 else if (STRING_IN_TABLE (toplevel_group->name,
1892 image_quality_group_whitelist) ||
1893 STRING_IN_TABLE (ppd_option->keyword,
1894 image_quality_option_whitelist))
1896 option->group = g_strdup ("ImageQualityPage");
1898 else if (STRING_IN_TABLE (toplevel_group->name,
1899 finishing_group_whitelist) ||
1900 STRING_IN_TABLE (ppd_option->keyword,
1901 finishing_option_whitelist))
1903 option->group = g_strdup ("FinishingPage");
1907 option->group = g_strdup (toplevel_group->text);
1910 set_option_from_settings (option, settings);
1912 gtk_printer_option_set_add (set, option);
1919 handle_group (GtkPrinterOptionSet *set,
1920 ppd_file_t *ppd_file,
1922 ppd_group_t *toplevel_group,
1923 GtkPrintSettings *settings)
1927 /* Ignore installable options */
1928 if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
1931 for (i = 0; i < group->num_options; i++)
1932 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
1934 for (i = 0; i < group->num_subgroups; i++)
1935 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
1939 static GtkPrinterOptionSet *
1940 cups_printer_get_options (GtkPrinter *printer,
1941 GtkPrintSettings *settings,
1942 GtkPageSetup *page_setup)
1944 GtkPrinterOptionSet *set;
1945 GtkPrinterOption *option;
1946 ppd_file_t *ppd_file;
1948 char *print_at[] = { "now", "at", "on-hold" };
1949 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
1950 char *prio[] = {"100", "80", "50", "30" };
1951 char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
1952 char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
1953 char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
1956 set = gtk_printer_option_set_new ();
1958 /* Cups specific, non-ppd related settings */
1960 option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
1961 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
1963 gtk_printer_option_set (option, "1");
1964 set_option_from_settings (option, settings);
1965 gtk_printer_option_set_add (set, option);
1966 g_object_unref (option);
1968 for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
1969 prio_display[i] = _(prio_display[i]);
1971 option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
1972 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
1973 prio, prio_display);
1974 gtk_printer_option_set (option, "50");
1975 set_option_from_settings (option, settings);
1976 gtk_printer_option_set_add (set, option);
1977 g_object_unref (option);
1979 option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
1980 gtk_printer_option_set (option, "");
1981 set_option_from_settings (option, settings);
1982 gtk_printer_option_set_add (set, option);
1983 g_object_unref (option);
1985 for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
1986 cover_display[i] = _(cover_display[i]);
1988 option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
1989 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1990 cover, cover_display);
1991 gtk_printer_option_set (option, "none");
1992 set_option_from_settings (option, settings);
1993 gtk_printer_option_set_add (set, option);
1994 g_object_unref (option);
1996 option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
1997 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
1998 cover, cover_display);
1999 gtk_printer_option_set (option, "none");
2000 set_option_from_settings (option, settings);
2001 gtk_printer_option_set_add (set, option);
2002 g_object_unref (option);
2004 option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
2005 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2006 print_at, print_at);
2007 gtk_printer_option_set (option, "now");
2008 set_option_from_settings (option, settings);
2009 gtk_printer_option_set_add (set, option);
2010 g_object_unref (option);
2012 option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2013 gtk_printer_option_set (option, "");
2014 set_option_from_settings (option, settings);
2015 gtk_printer_option_set_add (set, option);
2016 g_object_unref (option);
2018 /* Printer (ppd) specific settings */
2019 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2022 GtkPaperSize *paper_size;
2023 ppd_option_t *option;
2025 ppdMarkDefaults (ppd_file);
2027 paper_size = gtk_page_setup_get_paper_size (page_setup);
2029 option = ppdFindOption(ppd_file, "PageSize");
2030 strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
2033 for (i = 0; i < ppd_file->num_groups; i++)
2034 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2042 mark_option_from_set (GtkPrinterOptionSet *set,
2043 ppd_file_t *ppd_file,
2044 ppd_option_t *ppd_option)
2046 GtkPrinterOption *option;
2047 char *name = get_option_name (ppd_option->keyword);
2049 option = gtk_printer_option_set_lookup (set, name);
2052 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2059 mark_group_from_set (GtkPrinterOptionSet *set,
2060 ppd_file_t *ppd_file,
2065 for (i = 0; i < group->num_options; i++)
2066 mark_option_from_set (set, ppd_file, &group->options[i]);
2068 for (i = 0; i < group->num_subgroups; i++)
2069 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2073 set_conflicts_from_option (GtkPrinterOptionSet *set,
2074 ppd_file_t *ppd_file,
2075 ppd_option_t *ppd_option)
2077 GtkPrinterOption *option;
2079 if (ppd_option->conflicted)
2081 name = get_option_name (ppd_option->keyword);
2082 option = gtk_printer_option_set_lookup (set, name);
2085 gtk_printer_option_set_has_conflict (option, TRUE);
2087 g_warning ("conflict for option %s ignored", ppd_option->keyword);
2094 set_conflicts_from_group (GtkPrinterOptionSet *set,
2095 ppd_file_t *ppd_file,
2100 for (i = 0; i < group->num_options; i++)
2101 set_conflicts_from_option (set, ppd_file, &group->options[i]);
2103 for (i = 0; i < group->num_subgroups; i++)
2104 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2108 cups_printer_mark_conflicts (GtkPrinter *printer,
2109 GtkPrinterOptionSet *options)
2111 ppd_file_t *ppd_file;
2115 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2117 if (ppd_file == NULL)
2120 ppdMarkDefaults (ppd_file);
2122 for (i = 0; i < ppd_file->num_groups; i++)
2123 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2125 num_conflicts = ppdConflicts (ppd_file);
2127 if (num_conflicts > 0)
2129 for (i = 0; i < ppd_file->num_groups; i++)
2130 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2133 return num_conflicts > 0;
2137 GtkPrinter *printer;
2138 GtkPrinterOptionSet *options;
2139 GtkPrintSettings *settings;
2140 ppd_file_t *ppd_file;
2145 const char *standard;
2149 map_settings_to_option (GtkPrinterOption *option,
2150 const NameMapping table[],
2152 GtkPrintSettings *settings,
2153 const char *standard_name,
2154 const char *cups_name)
2158 const char *cups_value;
2159 const char *standard_value;
2161 /* If the cups-specific setting is set, always use that */
2163 name = g_strdup_printf ("cups-%s", cups_name);
2164 cups_value = gtk_print_settings_get (settings, name);
2167 if (cups_value != NULL) {
2168 gtk_printer_option_set (option, cups_value);
2172 /* Otherwise we try to convert from the general setting */
2173 standard_value = gtk_print_settings_get (settings, standard_name);
2174 if (standard_value == NULL)
2177 for (i = 0; i < n_elements; i++)
2179 if (table[i].cups == NULL && table[i].standard == NULL)
2181 gtk_printer_option_set (option, standard_value);
2184 else if (table[i].cups == NULL &&
2185 strcmp (table[i].standard, standard_value) == 0)
2187 set_option_off (option);
2190 else if (strcmp (table[i].standard, standard_value) == 0)
2192 gtk_printer_option_set (option, table[i].cups);
2199 map_option_to_settings (const char *value,
2200 const NameMapping table[],
2202 GtkPrintSettings *settings,
2203 const char *standard_name,
2204 const char *cups_name)
2209 for (i = 0; i < n_elements; i++)
2211 if (table[i].cups == NULL && table[i].standard == NULL)
2213 gtk_print_settings_set (settings,
2218 else if (table[i].cups == NULL && table[i].standard != NULL)
2220 if (value_is_off (value))
2222 gtk_print_settings_set (settings,
2228 else if (strcmp (table[i].cups, value) == 0)
2230 gtk_print_settings_set (settings,
2237 /* Always set the corresponding cups-specific setting */
2238 name = g_strdup_printf ("cups-%s", cups_name);
2239 gtk_print_settings_set (settings, name, value);
2244 static const NameMapping paper_source_map[] = {
2245 { "Lower", "lower"},
2246 { "Middle", "middle"},
2247 { "Upper", "upper"},
2249 { "Envelope", "envelope"},
2250 { "Cassette", "cassette"},
2251 { "LargeCapacity", "large-capacity"},
2252 { "AnySmallFormat", "small-format"},
2253 { "AnyLargeFormat", "large-format"},
2257 static const NameMapping output_tray_map[] = {
2258 { "Upper", "upper"},
2259 { "Lower", "lower"},
2264 static const NameMapping duplex_map[] = {
2265 { "DuplexTumble", "vertical" },
2266 { "DuplexNoTumble", "horizontal" },
2270 static const NameMapping output_mode_map[] = {
2271 { "Standard", "normal" },
2272 { "Normal", "normal" },
2273 { "Draft", "draft" },
2274 { "Fast", "draft" },
2277 static const NameMapping media_type_map[] = {
2278 { "Transparency", "transparency"},
2279 { "Standard", "stationery"},
2283 static const NameMapping all_map[] = {
2289 set_option_from_settings (GtkPrinterOption *option,
2290 GtkPrintSettings *settings)
2292 const char *cups_value;
2295 if (settings == NULL)
2298 if (strcmp (option->name, "gtk-paper-source") == 0)
2299 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2300 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2301 else if (strcmp (option->name, "gtk-output-tray") == 0)
2302 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2303 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2304 else if (strcmp (option->name, "gtk-duplex") == 0)
2305 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2306 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2307 else if (strcmp (option->name, "cups-OutputMode") == 0)
2308 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2309 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2310 else if (strcmp (option->name, "cups-Resolution") == 0)
2312 cups_value = gtk_print_settings_get (settings, option->name);
2314 gtk_printer_option_set (option, cups_value);
2317 int res = gtk_print_settings_get_resolution (settings);
2320 value = g_strdup_printf ("%ddpi", res);
2321 gtk_printer_option_set (option, value);
2326 else if (strcmp (option->name, "gtk-paper-type") == 0)
2327 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2328 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2329 else if (strcmp (option->name, "gtk-n-up") == 0)
2331 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2332 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2334 else if (strcmp (option->name, "gtk-billing-info") == 0)
2336 cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2338 gtk_printer_option_set (option, cups_value);
2340 else if (strcmp (option->name, "gtk-job-prio") == 0)
2342 cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2344 gtk_printer_option_set (option, cups_value);
2346 else if (strcmp (option->name, "gtk-cover-before") == 0)
2348 cups_value = gtk_print_settings_get (settings, "cover-before");
2350 gtk_printer_option_set (option, cups_value);
2352 else if (strcmp (option->name, "gtk-cover-after") == 0)
2354 cups_value = gtk_print_settings_get (settings, "cover-after");
2356 gtk_printer_option_set (option, cups_value);
2358 else if (strcmp (option->name, "gtk-print-time") == 0)
2360 cups_value = gtk_print_settings_get (settings, "print-at");
2362 gtk_printer_option_set (option, cups_value);
2364 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2366 cups_value = gtk_print_settings_get (settings, "print-at-time");
2368 gtk_printer_option_set (option, cups_value);
2370 else if (g_str_has_prefix (option->name, "cups-"))
2372 cups_value = gtk_print_settings_get (settings, option->name);
2374 gtk_printer_option_set (option, cups_value);
2379 foreach_option_get_settings (GtkPrinterOption *option,
2382 struct OptionData *data = user_data;
2383 GtkPrintSettings *settings = data->settings;
2386 value = option->value;
2388 if (strcmp (option->name, "gtk-paper-source") == 0)
2389 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2390 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2391 else if (strcmp (option->name, "gtk-output-tray") == 0)
2392 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2393 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2394 else if (strcmp (option->name, "gtk-duplex") == 0)
2395 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2396 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2397 else if (strcmp (option->name, "cups-OutputMode") == 0)
2398 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2399 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2400 else if (strcmp (option->name, "cups-Resolution") == 0)
2402 int res = atoi (value);
2403 /* TODO: What if resolution is on XXXxYYYdpi form? */
2405 gtk_print_settings_set_resolution (settings, res);
2406 gtk_print_settings_set (settings, option->name, value);
2408 else if (strcmp (option->name, "gtk-paper-type") == 0)
2409 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2410 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2411 else if (strcmp (option->name, "gtk-n-up") == 0)
2412 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2413 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2414 else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2415 gtk_print_settings_set (settings, "cups-job-billing", value);
2416 else if (strcmp (option->name, "gtk-job-prio") == 0)
2417 gtk_print_settings_set (settings, "cups-job-priority", value);
2418 else if (strcmp (option->name, "gtk-cover-before") == 0)
2419 gtk_print_settings_set (settings, "cover-before", value);
2420 else if (strcmp (option->name, "gtk-cover-after") == 0)
2421 gtk_print_settings_set (settings, "cover-after", value);
2422 else if (strcmp (option->name, "gtk-print-time") == 0)
2423 gtk_print_settings_set (settings, "print-at", value);
2424 else if (strcmp (option->name, "gtk-print-time-text") == 0)
2425 gtk_print_settings_set (settings, "print-at-time", value);
2426 else if (g_str_has_prefix (option->name, "cups-"))
2427 gtk_print_settings_set (settings, option->name, value);
2431 cups_printer_get_settings_from_options (GtkPrinter *printer,
2432 GtkPrinterOptionSet *options,
2433 GtkPrintSettings *settings)
2435 struct OptionData data;
2436 const char *print_at, *print_at_time;
2438 data.printer = printer;
2439 data.options = options;
2440 data.settings = settings;
2441 data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2443 if (data.ppd_file != NULL)
2445 GtkPrinterOption *cover_before, *cover_after;
2447 gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2449 cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2450 cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2451 if (cover_before && cover_after)
2453 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2454 gtk_print_settings_set (settings, "cups-job-sheets", value);
2458 print_at = gtk_print_settings_get (settings, "print-at");
2459 print_at_time = gtk_print_settings_get (settings, "print-at-time");
2460 if (strcmp (print_at, "at") == 0)
2461 gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2462 else if (strcmp (print_at, "on-hold") == 0)
2463 gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2468 cups_printer_prepare_for_print (GtkPrinter *printer,
2469 GtkPrintJob *print_job,
2470 GtkPrintSettings *settings,
2471 GtkPageSetup *page_setup)
2473 GtkPageSet page_set;
2474 GtkPaperSize *paper_size;
2475 const char *ppd_paper_name;
2478 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2479 print_job->page_ranges = NULL;
2480 print_job->num_page_ranges = 0;
2482 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2483 print_job->page_ranges =
2484 gtk_print_settings_get_page_ranges (settings,
2485 &print_job->num_page_ranges);
2487 if (gtk_print_settings_get_collate (settings))
2488 gtk_print_settings_set (settings, "cups-Collate", "True");
2489 print_job->collate = FALSE;
2491 if (gtk_print_settings_get_reverse (settings))
2492 gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2493 print_job->reverse = FALSE;
2495 if (gtk_print_settings_get_n_copies (settings) > 1)
2496 gtk_print_settings_set_int (settings, "cups-copies",
2497 gtk_print_settings_get_n_copies (settings));
2498 print_job->num_copies = 1;
2500 scale = gtk_print_settings_get_scale (settings);
2501 print_job->scale = 1.0;
2503 print_job->scale = scale/100.0;
2505 page_set = gtk_print_settings_get_page_set (settings);
2506 if (page_set == GTK_PAGE_SET_EVEN)
2507 gtk_print_settings_set (settings, "cups-page-set", "even");
2508 else if (page_set == GTK_PAGE_SET_ODD)
2509 gtk_print_settings_set (settings, "cups-page-set", "odd");
2510 print_job->page_set = GTK_PAGE_SET_ALL;
2512 paper_size = gtk_page_setup_get_paper_size (page_setup);
2513 ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2514 if (ppd_paper_name != NULL)
2515 gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2518 char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2519 gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2520 gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2521 gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2522 g_free (custom_name);
2525 print_job->rotate_to_orientation = TRUE;
2529 cups_printer_list_papers (GtkPrinter *printer)
2531 ppd_file_t *ppd_file;
2534 GtkPageSetup *page_setup;
2535 GtkPaperSize *paper_size;
2536 ppd_option_t *option;
2537 ppd_choice_t *choice;
2541 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2542 if (ppd_file == NULL)
2547 for (i = 0; i < ppd_file->num_sizes; i++)
2549 size = &ppd_file->sizes[i];
2551 display_name = NULL;
2552 option = ppdFindOption(ppd_file, "PageSize");
2555 choice = ppdFindChoice(option, size->name);
2557 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2559 if (display_name == NULL)
2560 display_name = g_strdup (size->name);
2562 page_setup = gtk_page_setup_new ();
2563 paper_size = gtk_paper_size_new_from_ppd (size->name,
2567 gtk_page_setup_set_paper_size (page_setup, paper_size);
2568 gtk_paper_size_free (paper_size);
2570 gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2571 gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2572 gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2573 gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2575 g_free (display_name);
2577 l = g_list_prepend (l, page_setup);
2580 return g_list_reverse (l);
2584 cups_printer_get_hard_margins (GtkPrinter *printer,
2590 ppd_file_t *ppd_file;
2592 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2593 if (ppd_file == NULL)
2596 *left = ppd_file->custom_margins[0];
2597 *bottom = ppd_file->custom_margins[1];
2598 *right = ppd_file->custom_margins[2];
2599 *top = ppd_file->custom_margins[3];
2602 static GtkPrintCapabilities
2603 cups_printer_get_capabilities (GtkPrinter *printer)
2606 GTK_PRINT_CAPABILITY_COPIES |
2607 GTK_PRINT_CAPABILITY_COLLATE |
2608 GTK_PRINT_CAPABILITY_REVERSE;