1 /* GTK - The GIMP Toolkit
2 * gtkprintbackendcups.h: Default implementation of GtkPrintBackend
3 * for the Common Unix Print System (CUPS)
4 * Copyright (C) 2006, 2007 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.
25 #include <sys/types.h>
29 #include <cups/cups.h>
30 #include <cups/language.h>
31 #include <cups/http.h>
35 #include <cairo-pdf.h>
38 #include <glib/gstdio.h>
39 #include <glib/gi18n-lib.h>
43 #include <gtk/gtkprintbackend.h>
44 #include <gtk/gtkunixprint.h>
45 #include <gtk/gtkprinter-private.h>
47 #include "gtkprintbackendcups.h"
48 #include "gtkprintercups.h"
50 #include "gtkcupsutils.h"
53 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
55 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
56 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
57 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
59 #define _CUPS_MAX_ATTEMPTS 10
60 #define _CUPS_MAX_CHUNK_SIZE 8192
62 /* define this to see warnings about ignored ppd options */
63 #undef PRINT_IGNORED_OPTIONS
65 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
66 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
68 static GType print_backend_cups_type = 0;
70 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
71 GtkCupsResult *result,
82 } GtkPrintCupsDispatchState;
89 GtkCupsRequest *request;
91 GtkPrintBackendCups *backend;
93 } GtkPrintCupsDispatchWatch;
95 struct _GtkPrintBackendCupsClass
97 GtkPrintBackendClass parent_class;
100 struct _GtkPrintBackendCups
102 GtkPrintBackend parent_instance;
104 char *default_printer;
106 guint list_printers_poll;
107 guint list_printers_pending : 1;
108 guint got_default_printer : 1;
109 guint default_printer_poll;
110 GtkCupsConnectionTest *cups_connection_test;
113 char *default_cover_before;
114 char *default_cover_after;
115 int number_of_covers;
118 static GObjectClass *backend_parent_class;
120 static void gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class);
121 static void gtk_print_backend_cups_init (GtkPrintBackendCups *impl);
122 static void gtk_print_backend_cups_finalize (GObject *object);
123 static void gtk_print_backend_cups_dispose (GObject *object);
124 static void cups_get_printer_list (GtkPrintBackend *print_backend);
125 static void cups_get_default_printer (GtkPrintBackendCups *print_backend);
126 static void cups_get_local_default_printer (GtkPrintBackendCups *print_backend);
127 static void cups_request_execute (GtkPrintBackendCups *print_backend,
128 GtkCupsRequest *request,
129 GtkPrintCupsResponseCallbackFunc callback,
131 GDestroyNotify notify);
132 static void cups_printer_get_settings_from_options (GtkPrinter *printer,
133 GtkPrinterOptionSet *options,
134 GtkPrintSettings *settings);
135 static gboolean cups_printer_mark_conflicts (GtkPrinter *printer,
136 GtkPrinterOptionSet *options);
137 static GtkPrinterOptionSet *cups_printer_get_options (GtkPrinter *printer,
138 GtkPrintSettings *settings,
139 GtkPageSetup *page_setup,
140 GtkPrintCapabilities capabilities);
141 static void cups_printer_prepare_for_print (GtkPrinter *printer,
142 GtkPrintJob *print_job,
143 GtkPrintSettings *settings,
144 GtkPageSetup *page_setup);
145 static GList * cups_printer_list_papers (GtkPrinter *printer);
146 static GtkPageSetup * cups_printer_get_default_page_size (GtkPrinter *printer);
147 static void cups_printer_request_details (GtkPrinter *printer);
148 static gboolean cups_request_default_printer (GtkPrintBackendCups *print_backend);
149 static void cups_request_ppd (GtkPrinter *printer);
150 static void cups_printer_get_hard_margins (GtkPrinter *printer,
155 static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer);
156 static void set_option_from_settings (GtkPrinterOption *option,
157 GtkPrintSettings *setting);
158 static void cups_begin_polling_info (GtkPrintBackendCups *print_backend,
161 static gboolean cups_job_info_poll_timeout (gpointer user_data);
162 static void gtk_print_backend_cups_print_stream (GtkPrintBackend *backend,
165 GtkPrintJobCompleteFunc callback,
167 GDestroyNotify dnotify);
168 static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter *printer,
169 GtkPrintSettings *settings,
172 GIOChannel *cache_io);
176 gtk_print_backend_cups_register_type (GTypeModule *module)
178 static const GTypeInfo print_backend_cups_info =
180 sizeof (GtkPrintBackendCupsClass),
181 NULL, /* base_init */
182 NULL, /* base_finalize */
183 (GClassInitFunc) gtk_print_backend_cups_class_init,
184 NULL, /* class_finalize */
185 NULL, /* class_data */
186 sizeof (GtkPrintBackendCups),
188 (GInstanceInitFunc) gtk_print_backend_cups_init
191 print_backend_cups_type = g_type_module_register_type (module,
192 GTK_TYPE_PRINT_BACKEND,
193 "GtkPrintBackendCups",
194 &print_backend_cups_info, 0);
198 pb_module_init (GTypeModule *module)
201 g_print ("CUPS Backend: Initializing the CUPS print backend module\n"));
203 gtk_print_backend_cups_register_type (module);
204 gtk_printer_cups_register_type (module);
208 pb_module_exit (void)
213 G_MODULE_EXPORT GtkPrintBackend *
214 pb_module_create (void)
216 return gtk_print_backend_cups_new ();
220 * GtkPrintBackendCups
223 gtk_print_backend_cups_get_type (void)
225 return print_backend_cups_type;
229 * gtk_print_backend_cups_new:
231 * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
232 * implements the #GtkPrintBackend interface with direct access to
233 * the filesystem using Unix/Linux API calls
235 * Return value: the new #GtkPrintBackendCups object
238 gtk_print_backend_cups_new (void)
241 g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
243 return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
247 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
249 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
250 GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
252 backend_parent_class = g_type_class_peek_parent (class);
254 gobject_class->finalize = gtk_print_backend_cups_finalize;
255 gobject_class->dispose = gtk_print_backend_cups_dispose;
257 backend_class->request_printer_list = cups_get_printer_list;
258 backend_class->print_stream = gtk_print_backend_cups_print_stream;
259 backend_class->printer_request_details = cups_printer_request_details;
260 backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
261 backend_class->printer_get_options = cups_printer_get_options;
262 backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
263 backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
264 backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
265 backend_class->printer_list_papers = cups_printer_list_papers;
266 backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
267 backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
268 backend_class->printer_get_capabilities = cups_printer_get_capabilities;
271 static cairo_status_t
272 _cairo_write_to_cups (void *closure,
273 const unsigned char *data,
276 GIOChannel *io = (GIOChannel *)closure;
283 g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length));
287 g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
292 g_print ("CUPS Backend: Error writing to temp file, %s\n",
295 g_error_free (error);
296 return CAIRO_STATUS_WRITE_ERROR;
300 g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
306 return CAIRO_STATUS_SUCCESS;
309 static cairo_surface_t *
310 cups_printer_create_cairo_surface (GtkPrinter *printer,
311 GtkPrintSettings *settings,
314 GIOChannel *cache_io)
316 cairo_surface_t *surface;
317 ppd_file_t *ppd_file = NULL;
318 ppd_attr_t *ppd_attr = NULL;
321 /* TODO: check if it is a ps or pdf printer */
323 surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height);
325 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
327 if (ppd_file != NULL)
329 ppd_attr = ppdFindAttr (ppd_file, "LanguageLevel", NULL);
331 if (ppd_attr != NULL)
332 level = atoi (ppd_attr->value);
336 cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2);
339 cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3);
341 /* TODO: DPI from settings object? */
342 cairo_surface_set_fallback_resolution (surface, 300, 300);
348 GtkPrintJobCompleteFunc callback;
351 GDestroyNotify dnotify;
352 } CupsPrintStreamData;
355 cups_free_print_stream_data (CupsPrintStreamData *data)
358 g_print ("CUPS Backend: %s\n", G_STRFUNC));
361 data->dnotify (data->user_data);
362 g_object_unref (data->job);
367 cups_print_cb (GtkPrintBackendCups *print_backend,
368 GtkCupsResult *result,
371 GError *error = NULL;
372 CupsPrintStreamData *ps = user_data;
374 GDK_THREADS_ENTER ();
377 g_print ("CUPS Backend: %s\n", G_STRFUNC));
379 if (gtk_cups_result_is_error (result))
380 error = g_error_new_literal (gtk_print_error_quark (),
381 GTK_PRINT_ERROR_INTERNAL_ERROR,
382 gtk_cups_result_get_error_string (result));
385 ps->callback (ps->job, ps->user_data, error);
390 ipp_attribute_t *attr; /* IPP job-id attribute */
391 ipp_t *response = gtk_cups_result_get_response (result);
393 if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
394 job_id = attr->values[0].integer;
396 if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
397 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
400 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
401 cups_begin_polling_info (print_backend, ps->job, job_id);
405 gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
409 g_error_free (error);
411 GDK_THREADS_LEAVE ();
415 add_cups_options (const gchar *key,
419 GtkCupsRequest *request = user_data;
421 if (!g_str_has_prefix (key, "cups-"))
424 if (strcmp (value, "gtk-ignore-value") == 0)
427 key = key + strlen ("cups-");
429 gtk_cups_request_encode_option (request, key, value);
433 gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
436 GtkPrintJobCompleteFunc callback,
438 GDestroyNotify dnotify)
440 GtkPrinterCups *cups_printer;
441 CupsPrintStreamData *ps;
442 GtkCupsRequest *request;
443 GtkPrintSettings *settings;
445 char printer_absolute_uri[HTTP_MAX_URI];
448 g_print ("CUPS Backend: %s\n", G_STRFUNC));
450 cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
451 settings = gtk_print_job_get_settings (job);
453 request = gtk_cups_request_new (NULL,
458 cups_printer->device_uri);
460 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
461 httpAssembleURIf (HTTP_URI_CODING_ALL,
462 printer_absolute_uri,
463 sizeof (printer_absolute_uri),
469 gtk_printer_get_name (gtk_print_job_get_printer (job)));
471 g_snprintf (printer_absolute_uri,
472 sizeof (printer_absolute_uri),
473 "ipp://localhost:%d/printers/%s",
475 gtk_printer_get_name (gtk_print_job_get_printer (job)));
478 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
479 IPP_TAG_URI, "printer-uri",
480 NULL, printer_absolute_uri);
482 title = gtk_print_job_get_title (job);
484 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION,
485 IPP_TAG_NAME, "job-name",
488 gtk_print_settings_foreach (settings, add_cups_options, request);
490 ps = g_new0 (CupsPrintStreamData, 1);
491 ps->callback = callback;
492 ps->user_data = user_data;
493 ps->dnotify = dnotify;
494 ps->job = g_object_ref (job);
496 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
498 (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
500 (GDestroyNotify)cups_free_print_stream_data);
505 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
507 backend_cups->list_printers_poll = FALSE;
508 backend_cups->got_default_printer = FALSE;
509 backend_cups->list_printers_pending = FALSE;
511 backend_cups->covers = NULL;
512 backend_cups->default_cover_before = NULL;
513 backend_cups->default_cover_after = NULL;
514 backend_cups->number_of_covers = 0;
516 backend_cups->default_printer_poll = 0;
517 backend_cups->cups_connection_test = NULL;
519 cups_get_local_default_printer (backend_cups);
523 gtk_print_backend_cups_finalize (GObject *object)
525 GtkPrintBackendCups *backend_cups;
528 g_print ("CUPS Backend: finalizing CUPS backend module\n"));
530 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
532 g_free (backend_cups->default_printer);
533 backend_cups->default_printer = NULL;
535 g_strfreev (backend_cups->covers);
536 backend_cups->number_of_covers = 0;
538 g_free (backend_cups->default_cover_before);
539 g_free (backend_cups->default_cover_after);
541 gtk_cups_connection_test_free (backend_cups->cups_connection_test);
542 backend_cups->cups_connection_test = NULL;
544 backend_parent_class->finalize (object);
548 gtk_print_backend_cups_dispose (GObject *object)
550 GtkPrintBackendCups *backend_cups;
553 g_print ("CUPS Backend: %s\n", G_STRFUNC));
555 backend_cups = GTK_PRINT_BACKEND_CUPS (object);
557 if (backend_cups->list_printers_poll > 0)
558 g_source_remove (backend_cups->list_printers_poll);
559 backend_cups->list_printers_poll = 0;
561 if (backend_cups->default_printer_poll > 0)
562 g_source_remove (backend_cups->default_printer_poll);
563 backend_cups->default_printer_poll = 0;
565 backend_parent_class->dispose (object);
570 cups_dispatch_watch_check (GSource *source)
572 GtkPrintCupsDispatchWatch *dispatch;
573 GtkCupsPollState poll_state;
577 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
579 dispatch = (GtkPrintCupsDispatchWatch *) source;
581 poll_state = gtk_cups_request_get_poll_state (dispatch->request);
583 if (dispatch->request->http != NULL)
585 if (dispatch->data_poll == NULL)
587 dispatch->data_poll = g_new0 (GPollFD, 1);
588 g_source_add_poll (source, dispatch->data_poll);
592 if (poll_state == GTK_CUPS_HTTP_READ)
593 dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
594 else if (poll_state == GTK_CUPS_HTTP_WRITE)
595 dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
597 dispatch->data_poll->events = 0;
600 #ifdef HAVE_CUPS_API_1_2
601 dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
603 dispatch->data_poll->fd = dispatch->request->http->fd;
607 if (poll_state != GTK_CUPS_HTTP_IDLE)
608 if (!(dispatch->data_poll->revents & dispatch->data_poll->events))
611 result = gtk_cups_request_read_write (dispatch->request);
612 if (result && dispatch->data_poll != NULL)
614 g_source_remove_poll (source, dispatch->data_poll);
615 g_free (dispatch->data_poll);
616 dispatch->data_poll = NULL;
623 cups_dispatch_watch_prepare (GSource *source,
626 GtkPrintCupsDispatchWatch *dispatch;
628 dispatch = (GtkPrintCupsDispatchWatch *) source;
631 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
635 return gtk_cups_request_read_write (dispatch->request);
639 cups_dispatch_watch_dispatch (GSource *source,
640 GSourceFunc callback,
643 GtkPrintCupsDispatchWatch *dispatch;
644 GtkPrintCupsResponseCallbackFunc ep_callback;
645 GtkCupsResult *result;
647 g_assert (callback != NULL);
649 ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
651 dispatch = (GtkPrintCupsDispatchWatch *) source;
653 result = gtk_cups_request_get_result (dispatch->request);
656 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
658 if (gtk_cups_result_is_error (result))
661 g_print("Error result: %s (type %i, status %i, code %i)\n",
662 gtk_cups_result_get_error_string (result),
663 gtk_cups_result_get_error_type (result),
664 gtk_cups_result_get_error_status (result),
665 gtk_cups_result_get_error_code (result)));
668 ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
674 cups_dispatch_watch_finalize (GSource *source)
676 GtkPrintCupsDispatchWatch *dispatch;
679 g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
681 dispatch = (GtkPrintCupsDispatchWatch *) source;
683 gtk_cups_request_free (dispatch->request);
685 if (dispatch->backend)
687 /* We need to unref this at idle time, because it might be the
688 * last reference to this module causing the code to be
689 * unloaded (including this particular function!)
690 * Update: Doing this at idle caused a deadlock taking the
691 * mainloop context lock while being in a GSource callout for
692 * multithreaded apps. So, for now we just disable unloading
693 * of print backends. See _gtk_print_backend_create for the
696 g_object_unref (dispatch->backend);
697 dispatch->backend = NULL;
700 g_free (dispatch->data_poll);
703 static GSourceFuncs _cups_dispatch_watch_funcs = {
704 cups_dispatch_watch_prepare,
705 cups_dispatch_watch_check,
706 cups_dispatch_watch_dispatch,
707 cups_dispatch_watch_finalize
712 cups_request_execute (GtkPrintBackendCups *print_backend,
713 GtkCupsRequest *request,
714 GtkPrintCupsResponseCallbackFunc callback,
716 GDestroyNotify notify)
718 GtkPrintCupsDispatchWatch *dispatch;
720 dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs,
721 sizeof (GtkPrintCupsDispatchWatch));
724 g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
726 dispatch->request = request;
727 dispatch->backend = g_object_ref (print_backend);
728 dispatch->data_poll = NULL;
730 g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
732 g_source_attach ((GSource *) dispatch, NULL);
733 g_source_unref ((GSource *) dispatch);
738 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
739 GtkCupsResult *result,
742 ipp_attribute_t *attr;
745 GtkPrinterCups *cups_printer;
751 gboolean status_changed;
753 g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
755 printer_name = (gchar *)user_data;
756 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
760 g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
765 g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
769 cups_printer = GTK_PRINTER_CUPS (printer);
771 if (gtk_cups_result_is_error (result))
773 if (gtk_printer_is_new (printer))
775 gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
780 return; /* TODO: mark as inactive printer */
783 response = gtk_cups_result_get_response (result);
785 /* TODO: determine printer type and use correct icon */
786 gtk_printer_set_icon_name (printer, "gtk-print");
792 for (attr = response->attrs; attr != NULL; attr = attr->next)
797 _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
798 _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
799 _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
800 _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
801 _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
804 status_changed = gtk_printer_set_job_count (printer, job_count);
806 status_changed |= gtk_printer_set_location (printer, loc);
807 status_changed |= gtk_printer_set_description (printer, desc);
808 status_changed |= gtk_printer_set_state_message (printer, state_msg);
811 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
812 "printer-status-changed", printer);
816 cups_request_printer_info (GtkPrintBackendCups *print_backend,
817 const gchar *printer_name)
819 GtkCupsRequest *request;
821 static const char * const pattrs[] = /* Attributes we're interested in */
825 "printer-state-message",
828 "job-sheets-supported",
832 request = gtk_cups_request_new (NULL,
834 IPP_GET_PRINTER_ATTRIBUTES,
839 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
841 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
842 "printer-uri", NULL, printer_uri);
845 g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
847 g_free (printer_uri);
849 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
850 "requested-attributes", G_N_ELEMENTS (pattrs),
853 cups_request_execute (print_backend,
855 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
856 g_strdup (printer_name),
857 (GDestroyNotify) g_free);
862 GtkPrintBackendCups *print_backend;
869 job_object_died (gpointer user_data,
870 GObject *where_the_object_was)
872 CupsJobPollData *data = user_data;
877 cups_job_poll_data_free (CupsJobPollData *data)
880 g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
886 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
887 GtkCupsResult *result,
890 CupsJobPollData *data = user_data;
891 ipp_attribute_t *attr;
896 GDK_THREADS_ENTER ();
898 if (data->job == NULL)
900 cups_job_poll_data_free (data);
906 response = gtk_cups_result_get_response (result);
909 for (attr = response->attrs; attr != NULL; attr = attr->next)
914 _CUPS_MAP_ATTR_INT (attr, state, "job-state");
920 case IPP_JOB_PENDING:
922 case IPP_JOB_STOPPED:
923 gtk_print_job_set_status (data->job,
924 GTK_PRINT_STATUS_PENDING);
926 case IPP_JOB_PROCESSING:
927 gtk_print_job_set_status (data->job,
928 GTK_PRINT_STATUS_PRINTING);
931 case IPP_JOB_CANCELLED:
932 case IPP_JOB_ABORTED:
933 gtk_print_job_set_status (data->job,
934 GTK_PRINT_STATUS_FINISHED_ABORTED);
938 case IPP_JOB_COMPLETED:
939 gtk_print_job_set_status (data->job,
940 GTK_PRINT_STATUS_FINISHED);
945 if (!done && data->job != NULL)
949 if (data->counter < 5)
951 else if (data->counter < 10)
956 g_timeout_add (timeout, cups_job_info_poll_timeout, data);
959 cups_job_poll_data_free (data);
962 GDK_THREADS_LEAVE ();
966 cups_request_job_info (CupsJobPollData *data)
968 GtkCupsRequest *request;
971 request = gtk_cups_request_new (NULL,
973 IPP_GET_JOB_ATTRIBUTES,
978 job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
979 gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
980 "job-uri", NULL, job_uri);
983 cups_request_execute (data->print_backend,
985 (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
991 cups_job_info_poll_timeout (gpointer user_data)
993 CupsJobPollData *data = user_data;
995 if (data->job == NULL)
996 cups_job_poll_data_free (data);
998 cups_request_job_info (data);
1004 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
1008 CupsJobPollData *data;
1010 data = g_new0 (CupsJobPollData, 1);
1012 data->print_backend = print_backend;
1014 data->job_id = job_id;
1017 g_object_weak_ref (G_OBJECT (job), job_object_died, data);
1019 cups_request_job_info (data);
1023 mark_printer_inactive (GtkPrinter *printer,
1024 GtkPrintBackend *backend)
1026 gtk_printer_set_is_active (printer, FALSE);
1027 g_signal_emit_by_name (backend, "printer-removed", printer);
1031 find_printer (GtkPrinter *printer,
1032 const gchar *find_name)
1034 const gchar *printer_name;
1036 printer_name = gtk_printer_get_name (printer);
1037 return g_ascii_strcasecmp (printer_name, find_name);
1041 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
1042 GtkCupsResult *result,
1045 GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
1046 ipp_attribute_t *attr;
1048 gboolean list_has_changed;
1049 GList *removed_printer_checklist;
1051 GDK_THREADS_ENTER ();
1053 list_has_changed = FALSE;
1056 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1058 cups_backend->list_printers_pending = FALSE;
1060 if (gtk_cups_result_is_error (result))
1063 g_warning ("CUPS Backend: Error getting printer list: %s",
1064 gtk_cups_result_get_error_string (result)));
1069 /* Gather the names of the printers in the current queue
1070 * so we may check to see if they were removed
1072 removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
1074 response = gtk_cups_result_get_response (result);
1076 for (attr = response->attrs; attr != NULL; attr = attr->next)
1078 GtkPrinter *printer;
1079 const gchar *printer_name = NULL;
1080 const gchar *printer_uri = NULL;
1081 const gchar *member_uris = NULL;
1082 const gchar *location = NULL;
1083 const gchar *description = NULL;
1084 const gchar *state_msg = NULL;
1087 gboolean status_changed = FALSE;
1090 const gchar *reason_msg = NULL;
1091 gchar *reason_msg_desc = NULL;
1092 gchar *tmp_msg = NULL;
1093 gchar *tmp_msg2 = NULL;
1094 gint printer_state_reason_level = 0; /* 0 - none, 1 - report, 2 - warning, 3 - error */
1095 gboolean interested_in = FALSE;
1096 gboolean found = FALSE;
1097 static const char * const reasons[] = /* Reasons we're interested in */
1103 "marker-supply-low",
1104 "marker-supply-empty",
1110 "connecting-to-device",
1113 static const char * reasons_descs[] =
1115 N_("Printer '%s' is low on toner."),
1116 N_("Printer '%s' has no toner left."),
1117 /* Translators: "Developer" like on photo development context */
1118 N_("Printer '%s' is low on developer."),
1119 /* Translators: "Developer" like on photo development context */
1120 N_("Printer '%s' is out of developer."),
1121 /* Translators: "marker" is one color bin of the printer */
1122 N_("Printer '%s' is low on at least one marker supply."),
1123 /* Translators: "marker" is one color bin of the printer */
1124 N_("Printer '%s' is out of at least one marker supply."),
1125 N_("The cover is open on printer '%s'."),
1126 N_("The door is open on printer '%s'."),
1127 N_("Printer '%s' is low on paper."),
1128 N_("Printer '%s' is out of paper."),
1129 N_("Printer '%s' is currently off-line."),
1130 N_("Printer '%s' may not be connected."),
1131 N_("There is a problem on printer '%s'.")
1133 gboolean is_paused = FALSE;
1134 gboolean is_accepting_jobs = TRUE;
1135 gboolean default_printer = FALSE;
1136 gboolean got_printer_type = FALSE;
1138 /* Skip leading attributes until we hit a printer...
1140 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1146 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1148 if (strcmp (attr->name, "printer-name") == 0 &&
1149 attr->value_tag == IPP_TAG_NAME)
1150 printer_name = attr->values[0].string.text;
1151 else if (strcmp (attr->name, "printer-uri-supported") == 0 &&
1152 attr->value_tag == IPP_TAG_URI)
1153 printer_uri = attr->values[0].string.text;
1154 else if (strcmp (attr->name, "member-uris") == 0 &&
1155 attr->value_tag == IPP_TAG_URI)
1156 member_uris = attr->values[0].string.text;
1157 else if (strcmp (attr->name, "printer-location") == 0)
1158 location = attr->values[0].string.text;
1159 else if (strcmp (attr->name, "printer-info") == 0)
1160 description = attr->values[0].string.text;
1161 else if (strcmp (attr->name, "printer-state-message") == 0)
1162 state_msg = attr->values[0].string.text;
1163 else if (strcmp (attr->name, "printer-state-reasons") == 0)
1164 /* Store most important reason to reason_msg and set
1165 its importance at printer_state_reason_level */
1167 for (i = 0; i < attr->num_values; i++)
1169 if (strcmp (attr->values[i].string.text, "none") != 0)
1171 /* Sets is_paused flag for paused printer. */
1172 if (strcmp (attr->values[i].string.text, "paused") == 0)
1177 interested_in = FALSE;
1178 for (j = 0; j < G_N_ELEMENTS (reasons); j++)
1179 if (strncmp (attr->values[i].string.text, reasons[j], strlen (reasons[j])) == 0)
1181 interested_in = TRUE;
1187 if (g_str_has_suffix (attr->values[i].string.text, "-report"))
1189 if (printer_state_reason_level <= 1)
1191 reason_msg = attr->values[i].string.text;
1192 printer_state_reason_level = 1;
1195 else if (g_str_has_suffix (attr->values[i].string.text, "-warning"))
1197 if (printer_state_reason_level <= 2)
1199 reason_msg = attr->values[i].string.text;
1200 printer_state_reason_level = 2;
1203 else /* It is error in the case of no suffix. */
1205 reason_msg = attr->values[i].string.text;
1206 printer_state_reason_level = 3;
1212 else if (strcmp (attr->name, "printer-state") == 0)
1213 state = attr->values[0].integer;
1214 else if (strcmp (attr->name, "queued-job-count") == 0)
1215 job_count = attr->values[0].integer;
1216 else if (strcmp (attr->name, "printer-is-accepting-jobs") == 0)
1218 if (attr->values[0].boolean == 1)
1219 is_accepting_jobs = TRUE;
1221 is_accepting_jobs = FALSE;
1223 else if (strcmp (attr->name, "job-sheets-supported") == 0)
1225 if (cups_backend->covers == NULL)
1227 cups_backend->number_of_covers = attr->num_values;
1228 cups_backend->covers = g_new (char *, cups_backend->number_of_covers + 1);
1230 for (i = 0; i < cups_backend->number_of_covers; i++)
1231 cups_backend->covers[i] = g_strdup (attr->values[i].string.text);
1233 cups_backend->covers[cups_backend->number_of_covers] = NULL;
1236 else if (strcmp (attr->name, "job-sheets-default") == 0)
1238 if ( (cups_backend->default_cover_before == NULL) && (cups_backend->default_cover_after == NULL))
1240 if (attr->num_values == 2)
1242 cups_backend->default_cover_before = g_strdup (attr->values[0].string.text);
1243 cups_backend->default_cover_after = g_strdup (attr->values[1].string.text);
1247 else if (strcmp (attr->name, "printer-type") == 0)
1249 got_printer_type = TRUE;
1250 if (attr->values[0].integer & 0x00020000)
1251 default_printer = TRUE;
1253 default_printer = FALSE;
1258 g_print ("CUPS Backend: Attribute %s ignored", attr->name));
1264 if (printer_name == NULL ||
1265 (printer_uri == NULL && member_uris == NULL))
1273 if (got_printer_type)
1275 if (default_printer && !cups_backend->got_default_printer)
1277 cups_backend->got_default_printer = TRUE;
1278 cups_backend->default_printer = g_strdup (printer_name);
1283 if (!cups_backend->got_default_printer)
1284 cups_get_default_printer (cups_backend);
1287 /* remove name from checklist if it was found */
1288 node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
1289 removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
1291 printer = gtk_print_backend_find_printer (backend, printer_name);
1294 GtkPrinterCups *cups_printer;
1295 char uri[HTTP_MAX_URI]; /* Printer URI */
1296 char method[HTTP_MAX_URI]; /* Method/scheme name */
1297 char username[HTTP_MAX_URI]; /* Username:password */
1298 char hostname[HTTP_MAX_URI]; /* Hostname */
1299 char resource[HTTP_MAX_URI]; /* Resource name */
1300 int port; /* Port number */
1301 char *cups_server; /* CUPS server */
1303 list_has_changed = TRUE;
1304 cups_printer = gtk_printer_cups_new (printer_name, backend);
1306 cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
1308 /* Check to see if we are looking at a class */
1311 cups_printer->printer_uri = g_strdup (member_uris);
1312 /* TODO if member_uris is a class we need to recursivly find a printer */
1314 g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
1318 cups_printer->printer_uri = g_strdup (printer_uri);
1320 g_print ("CUPS Backend: Found printer %s\n", printer_uri));
1323 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
1324 httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri,
1325 method, sizeof (method),
1326 username, sizeof (username),
1327 hostname, sizeof (hostname),
1329 resource, sizeof (resource));
1332 httpSeparate (cups_printer->printer_uri,
1340 if (strncmp (resource, "/printers/", 10) == 0)
1342 cups_printer->ppd_name = g_strdup (resource + 10);
1344 g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, printer_name));
1347 gethostname (uri, sizeof (uri));
1348 cups_server = g_strdup (cupsServer());
1350 if (strcasecmp (uri, hostname) == 0)
1351 strcpy (hostname, "localhost");
1353 /* if the cups server is local and listening at a unix domain socket
1354 * then use the socket connection
1356 if ((strstr (hostname, "localhost") != NULL) &&
1357 (cups_server[0] == '/'))
1358 strcpy (hostname, cups_server);
1360 g_free (cups_server);
1362 cups_printer->hostname = g_strdup (hostname);
1363 cups_printer->port = port;
1365 printer = GTK_PRINTER (cups_printer);
1367 if (cups_backend->default_printer != NULL &&
1368 strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1369 gtk_printer_set_is_default (printer, TRUE);
1372 gtk_print_backend_add_printer (backend, printer);
1375 g_object_ref (printer);
1377 gtk_printer_set_is_paused (printer, is_paused);
1378 gtk_printer_set_is_accepting_jobs (printer, is_accepting_jobs);
1380 if (!gtk_printer_is_active (printer))
1382 gtk_printer_set_is_active (printer, TRUE);
1383 gtk_printer_set_is_new (printer, TRUE);
1384 list_has_changed = TRUE;
1387 if (gtk_printer_is_new (printer))
1389 g_signal_emit_by_name (backend, "printer-added", printer);
1391 gtk_printer_set_is_new (printer, FALSE);
1395 /* Getting printer info with separate requests overwhelms cups
1396 * when the printer list has more than a handful of printers.
1398 cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1401 GTK_PRINTER_CUPS (printer)->state = state;
1402 status_changed = gtk_printer_set_job_count (printer, job_count);
1403 status_changed |= gtk_printer_set_location (printer, location);
1404 status_changed |= gtk_printer_set_description (printer, description);
1406 if (state_msg != NULL && strlen (state_msg) == 0)
1408 if (is_paused && !is_accepting_jobs)
1409 /* Translators: this is a printer status. */
1410 tmp_msg2 = g_strdup ( N_("Paused ; Rejecting Jobs"));
1411 if (is_paused && is_accepting_jobs)
1412 /* Translators: this is a printer status. */
1413 tmp_msg2 = g_strdup ( N_("Paused"));
1414 if (!is_paused && !is_accepting_jobs)
1415 /* Translators: this is a printer status. */
1416 tmp_msg2 = g_strdup ( N_("Rejecting Jobs"));
1418 if (tmp_msg2 != NULL)
1419 state_msg = tmp_msg2;
1422 /* Set description of the reason and combine it with printer-state-message. */
1423 if ( (reason_msg != NULL))
1425 for (i = 0; i < G_N_ELEMENTS (reasons); i++)
1427 if (strncmp (reason_msg, reasons[i], strlen (reasons[i])) == 0)
1429 reason_msg_desc = g_strdup_printf (reasons_descs[i], printer_name);
1436 printer_state_reason_level = 0;
1438 if (printer_state_reason_level >= 2)
1440 if (strlen (state_msg) == 0)
1441 state_msg = reason_msg_desc;
1444 tmp_msg = g_strjoin (" ; ", state_msg, reason_msg_desc, NULL);
1445 state_msg = tmp_msg;
1450 status_changed |= gtk_printer_set_state_message (printer, state_msg);
1451 status_changed |= gtk_printer_set_is_accepting_jobs (printer, is_accepting_jobs);
1453 if (tmp_msg != NULL)
1456 if (tmp_msg2 != NULL)
1459 if (reason_msg_desc != NULL)
1460 g_free (reason_msg_desc);
1462 /* Set printer icon according to importance
1463 (none, report, warning, error - report is omitted). */
1464 if (printer_state_reason_level == 3)
1465 gtk_printer_set_icon_name (printer, "gtk-print-error");
1466 else if (printer_state_reason_level == 2)
1467 gtk_printer_set_icon_name (printer, "gtk-print-warning");
1468 else if (gtk_printer_is_paused (printer))
1469 gtk_printer_set_icon_name (printer, "gtk-print-paused");
1471 gtk_printer_set_icon_name (printer, "gtk-print");
1474 g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
1475 "printer-status-changed", printer);
1477 /* The ref is held by GtkPrintBackend, in add_printer() */
1478 g_object_unref (printer);
1484 /* look at the removed printers checklist and mark any printer
1485 as inactive if it is in the list, emitting a printer_removed signal */
1486 if (removed_printer_checklist != NULL)
1488 g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
1489 g_list_free (removed_printer_checklist);
1490 list_has_changed = TRUE;
1494 if (list_has_changed)
1495 g_signal_emit_by_name (backend, "printer-list-changed");
1497 gtk_print_backend_set_list_done (backend);
1499 GDK_THREADS_LEAVE ();
1503 update_backend_status (GtkPrintBackendCups *cups_backend,
1504 GtkCupsConnectionState state)
1508 case GTK_CUPS_CONNECTION_NOT_AVAILABLE:
1509 g_object_set (cups_backend, "status", GTK_PRINT_BACKEND_STATUS_UNAVAILABLE, NULL);
1511 case GTK_CUPS_CONNECTION_AVAILABLE:
1512 g_object_set (cups_backend, "status", GTK_PRINT_BACKEND_STATUS_OK, NULL);
1519 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1521 GtkCupsConnectionState state;
1522 GtkCupsRequest *request;
1523 static const char * const pattrs[] = /* Attributes we're interested in */
1526 "printer-uri-supported",
1530 "printer-state-message",
1531 "printer-state-reasons",
1534 "printer-is-accepting-jobs",
1535 "job-sheets-supported",
1536 "job-sheets-default",
1540 if (cups_backend->list_printers_pending)
1543 state = gtk_cups_connection_test_get_state (cups_backend->cups_connection_test);
1544 update_backend_status (cups_backend, state);
1546 if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
1549 cups_backend->list_printers_pending = TRUE;
1551 request = gtk_cups_request_new (NULL,
1558 gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1559 "requested-attributes", G_N_ELEMENTS (pattrs),
1562 cups_request_execute (cups_backend,
1564 (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1572 cups_get_printer_list (GtkPrintBackend *backend)
1574 GtkPrintBackendCups *cups_backend;
1576 cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1578 if (cups_backend->cups_connection_test == NULL)
1579 cups_backend->cups_connection_test = gtk_cups_connection_test_new (NULL);
1581 if (cups_backend->list_printers_poll == 0)
1583 if (cups_request_printer_list (cups_backend))
1584 cups_backend->list_printers_poll = gdk_threads_add_timeout_seconds (3,
1585 (GSourceFunc) cups_request_printer_list,
1591 GtkPrinterCups *printer;
1597 get_ppd_data_free (GetPPDData *data)
1600 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1601 httpClose (data->http);
1602 g_io_channel_unref (data->ppd_io);
1603 g_object_unref (data->printer);
1608 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1609 GtkCupsResult *result,
1613 GtkPrinter *printer;
1615 GDK_THREADS_ENTER ();
1618 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1620 printer = GTK_PRINTER (data->printer);
1621 GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1623 if (gtk_cups_result_is_error (result))
1625 gboolean success = FALSE;
1627 /* if we get a 404 then it is just a raw printer without a ppd
1629 if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
1630 (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
1632 gtk_printer_set_has_details (printer, TRUE);
1636 g_signal_emit_by_name (printer, "details-acquired", success);
1640 response = gtk_cups_result_get_response (result);
1642 /* let ppdOpenFd take over the ownership of the open file */
1643 g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
1644 data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
1646 ppdMarkDefaults (data->printer->ppd_file);
1648 gtk_printer_set_has_details (printer, TRUE);
1649 g_signal_emit_by_name (printer, "details-acquired", TRUE);
1652 GDK_THREADS_LEAVE ();
1656 cups_request_ppd (GtkPrinter *printer)
1659 GtkPrintBackend *print_backend;
1660 GtkPrinterCups *cups_printer;
1661 GtkCupsRequest *request;
1668 cups_printer = GTK_PRINTER_CUPS (printer);
1673 g_print ("CUPS Backend: %s\n", G_STRFUNC));
1675 http = httpConnectEncrypt (cups_printer->hostname,
1679 data = g_new0 (GetPPDData, 1);
1681 fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX",
1685 #ifdef G_ENABLE_DEBUG
1686 /* If we are debugging printing don't delete the tmp files */
1687 if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
1688 unlink (ppd_filename);
1690 unlink (ppd_filename);
1691 #endif /* G_ENABLE_DEBUG */
1696 g_warning ("CUPS Backend: Failed to create temp file, %s\n",
1698 g_error_free (error);
1700 g_free (ppd_filename);
1703 g_signal_emit_by_name (printer, "details-acquired", FALSE);
1708 fchmod (fd, S_IRUSR | S_IWUSR);
1709 data->ppd_io = g_io_channel_unix_new (fd);
1710 g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
1711 g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
1713 data->printer = g_object_ref (printer);
1715 resource = g_strdup_printf ("/printers/%s.ppd",
1716 gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
1718 request = gtk_cups_request_new (data->http,
1722 cups_printer->hostname,
1726 g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
1729 g_free (ppd_filename);
1731 cups_printer->reading_ppd = TRUE;
1733 print_backend = gtk_printer_get_backend (printer);
1735 cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1737 (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1739 (GDestroyNotify)get_ppd_data_free);
1742 /* Ordering matters for default preference */
1743 static const char *lpoptions_locations[] = {
1744 "/etc/cups/lpoptions",
1750 cups_parse_user_default_printer (const char *filename,
1751 char **printer_name)
1754 char line[1024], *lineptr, *defname = NULL;
1756 if ((fp = g_fopen (filename, "r")) == NULL)
1759 while (fgets (line, sizeof (line), fp) != NULL)
1761 if (strncasecmp (line, "default", 7) != 0 || !isspace (line[7]))
1765 while (isspace (*lineptr))
1772 while (!isspace (*lineptr) && *lineptr && *lineptr != '/')
1777 if (*printer_name != NULL)
1778 g_free (*printer_name);
1780 *printer_name = g_strdup (defname);
1787 cups_get_user_default_printer (char **printer_name)
1791 for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
1793 if (g_path_is_absolute (lpoptions_locations[i]))
1795 cups_parse_user_default_printer (lpoptions_locations[i],
1802 filename = g_build_filename (g_get_home_dir (),
1803 lpoptions_locations[i], NULL);
1804 cups_parse_user_default_printer (filename, printer_name);
1811 cups_parse_user_options (const char *filename,
1812 const char *printer_name,
1814 cups_option_t **options)
1817 gchar line[1024], *lineptr, *name;
1819 if ((fp = g_fopen (filename, "r")) == NULL)
1822 while (fgets (line, sizeof (line), fp) != NULL)
1824 if (strncasecmp (line, "dest", 4) == 0 && isspace (line[4]))
1826 else if (strncasecmp (line, "default", 7) == 0 && isspace (line[7]))
1831 /* Skip leading whitespace */
1832 while (isspace (*lineptr))
1838 /* NUL-terminate the name, stripping the instance name */
1840 while (!isspace (*lineptr) && *lineptr)
1842 if (*lineptr == '/')
1852 if (strncasecmp (name, printer_name, strlen (printer_name)) != 0)
1855 /* We found our printer, parse the options */
1856 num_options = cupsParseOptions (lineptr, num_options, options);
1865 cups_get_user_options (const char *printer_name,
1867 cups_option_t **options)
1871 for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
1873 if (g_path_is_absolute (lpoptions_locations[i]))
1875 num_options = cups_parse_user_options (lpoptions_locations[i],
1884 filename = g_build_filename (g_get_home_dir (),
1885 lpoptions_locations[i], NULL);
1886 num_options = cups_parse_user_options (filename, printer_name,
1887 num_options, options);
1895 /* This function requests default printer from a CUPS server in regular intervals.
1896 * In the case of unreachable CUPS server the request is repeated later.
1897 * The default printer is not requested in the case of previous success.
1900 cups_get_default_printer (GtkPrintBackendCups *backend)
1902 GtkPrintBackendCups *cups_backend;
1904 cups_backend = backend;
1906 if (cups_backend->cups_connection_test == NULL)
1907 cups_backend->cups_connection_test = gtk_cups_connection_test_new (NULL);
1909 if (cups_backend->default_printer_poll == 0)
1911 if (cups_request_default_printer (cups_backend))
1912 cups_backend->default_printer_poll = gdk_threads_add_timeout (500,
1913 (GSourceFunc) cups_request_default_printer,
1918 /* This function gets default printer from local settings.*/
1920 cups_get_local_default_printer (GtkPrintBackendCups *backend)
1925 if ((str = g_getenv ("LPDEST")) != NULL)
1927 backend->default_printer = g_strdup (str);
1928 backend->got_default_printer = TRUE;
1931 else if ((str = g_getenv ("PRINTER")) != NULL &&
1932 strcmp (str, "lp") != 0)
1934 backend->default_printer = g_strdup (str);
1935 backend->got_default_printer = TRUE;
1939 /* Figure out user setting for default printer */
1940 cups_get_user_default_printer (&name);
1943 backend->default_printer = name;
1944 backend->got_default_printer = TRUE;
1950 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1951 GtkCupsResult *result,
1955 ipp_attribute_t *attr;
1956 GtkPrinter *printer;
1958 GDK_THREADS_ENTER ();
1960 response = gtk_cups_result_get_response (result);
1962 if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
1963 print_backend->default_printer = g_strdup (attr->values[0].string.text);
1965 print_backend->got_default_printer = TRUE;
1967 if (print_backend->default_printer != NULL)
1969 printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (print_backend), print_backend->default_printer);
1970 if (printer != NULL)
1972 gtk_printer_set_is_default (printer, TRUE);
1973 g_signal_emit_by_name (GTK_PRINT_BACKEND (print_backend), "printer-status-changed", printer);
1977 /* Make sure to kick off get_printers if we are polling it,
1978 * as we could have blocked this reading the default printer
1980 if (print_backend->list_printers_poll != 0)
1981 cups_request_printer_list (print_backend);
1983 GDK_THREADS_LEAVE ();
1987 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1989 GtkCupsConnectionState state;
1990 GtkCupsRequest *request;
1992 state = gtk_cups_connection_test_get_state (print_backend->cups_connection_test);
1993 update_backend_status (print_backend, state);
1995 if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE)
1998 request = gtk_cups_request_new (NULL,
2005 cups_request_execute (print_backend,
2007 (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
2008 g_object_ref (print_backend),
2015 cups_printer_request_details (GtkPrinter *printer)
2017 GtkPrinterCups *cups_printer;
2019 cups_printer = GTK_PRINTER_CUPS (printer);
2020 if (!cups_printer->reading_ppd &&
2021 gtk_printer_cups_get_ppd (cups_printer) == NULL)
2022 cups_request_ppd (printer);
2026 ppd_text_to_utf8 (ppd_file_t *ppd_file,
2029 const char *encoding = NULL;
2032 if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
2034 return g_strdup (text);
2036 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
2038 encoding = "ISO-8859-1";
2040 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
2042 encoding = "ISO-8859-2";
2044 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
2046 encoding = "ISO-8859-5";
2048 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
2050 encoding = "SHIFT-JIS";
2052 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
2054 encoding = "MACINTOSH";
2056 else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
2058 encoding = "WINDOWS-1252";
2062 /* Fallback, try iso-8859-1... */
2063 encoding = "ISO-8859-1";
2066 res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
2071 g_warning ("CUPS Backend: Unable to convert PPD text\n"));
2072 res = g_strdup ("???");
2078 /* TODO: Add more translations for common settings here */
2080 static const struct {
2081 const char *keyword;
2082 const char *translation;
2083 } cups_option_translations[] = {
2084 { "Duplex", N_("Two Sided") },
2085 { "MediaType", N_("Paper Type") },
2086 { "InputSlot", N_("Paper Source") },
2087 { "OutputBin", N_("Output Tray") },
2091 static const struct {
2092 const char *keyword;
2094 const char *translation;
2095 } cups_choice_translations[] = {
2096 { "Duplex", "None", N_("One Sided") },
2097 /* Translators: this is an option of "Paper Source" */
2098 { "InputSlot", "Auto", N_("Auto Select") },
2099 /* Translators: this is an option of "Paper Source" */
2100 { "InputSlot", "AutoSelect", N_("Auto Select") },
2101 /* Translators: this is an option of "Paper Source" */
2102 { "InputSlot", "Default", N_("Printer Default") },
2103 /* Translators: this is an option of "Paper Source" */
2104 { "InputSlot", "None", N_("Printer Default") },
2105 /* Translators: this is an option of "Paper Source" */
2106 { "InputSlot", "PrinterDefault", N_("Printer Default") },
2107 /* Translators: this is an option of "Paper Source" */
2108 { "InputSlot", "Unspecified", N_("Auto Select") },
2111 static const struct {
2112 const char *ppd_keyword;
2114 } option_names[] = {
2115 {"Duplex", "gtk-duplex" },
2116 {"MediaType", "gtk-paper-type"},
2117 {"InputSlot", "gtk-paper-source"},
2118 {"OutputBin", "gtk-output-tray"},
2121 /* keep sorted when changing */
2122 static const char *color_option_whitelist[] = {
2123 "BRColorEnhancement",
2129 "BlackSubstitution",
2137 "RPSBlackOverPrint",
2141 /* keep sorted when changing */
2142 static const char *color_group_whitelist[] = {
2149 "HPColorOptionsPanel",
2152 /* keep sorted when changing */
2153 static const char *image_quality_option_whitelist[] = {
2155 "BRHalfTonePattern",
2165 "HPGraphicsHalftone",
2180 /* keep sorted when changing */
2181 static const char *image_quality_group_whitelist[] = {
2188 /* keep sorted when changing */
2189 static const char * finishing_option_whitelist[] = {
2202 "StapleOrientation",
2208 /* keep sorted when changing */
2209 static const char *finishing_group_whitelist[] = {
2218 /* keep sorted when changing */
2219 static const char *cups_option_blacklist[] = {
2228 get_option_text (ppd_file_t *ppd_file,
2229 ppd_option_t *option)
2234 for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
2236 if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
2237 return g_strdup (_(cups_option_translations[i].translation));
2240 utf8 = ppd_text_to_utf8 (ppd_file, option->text);
2242 /* Some ppd files have spaces in the text before the colon */
2249 get_choice_text (ppd_file_t *ppd_file,
2250 ppd_choice_t *choice)
2253 ppd_option_t *option = choice->option;
2254 const char *keyword = option->keyword;
2256 for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
2258 if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
2259 strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
2260 return g_strdup (_(cups_choice_translations[i].translation));
2262 return ppd_text_to_utf8 (ppd_file, choice->text);
2266 group_has_option (ppd_group_t *group,
2267 ppd_option_t *option)
2274 if (group->num_options > 0 &&
2275 option >= group->options && option < group->options + group->num_options)
2278 for (i = 0; i < group->num_subgroups; i++)
2280 if (group_has_option (&group->subgroups[i],option))
2287 set_option_off (GtkPrinterOption *option)
2289 /* Any of these will do, _set only applies the value
2290 * if its allowed of the option */
2291 gtk_printer_option_set (option, "False");
2292 gtk_printer_option_set (option, "Off");
2293 gtk_printer_option_set (option, "None");
2297 value_is_off (const char *value)
2299 return (strcasecmp (value, "None") == 0 ||
2300 strcasecmp (value, "Off") == 0 ||
2301 strcasecmp (value, "False") == 0);
2305 ppd_group_name (ppd_group_t *group)
2307 #if CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR == 1 && CUPS_VERSION_PATCH >= 18)
2315 available_choices (ppd_file_t *ppd,
2316 ppd_option_t *option,
2317 ppd_choice_t ***available,
2318 gboolean keep_if_only_one_option)
2320 ppd_option_t *other_option;
2323 ppd_const_t *constraint;
2324 const char *choice, *other_choice;
2325 ppd_option_t *option1, *option2;
2326 ppd_group_t *installed_options;
2328 gboolean all_default;
2334 conflicts = g_new0 (char, option->num_choices);
2336 installed_options = NULL;
2337 for (i = 0; i < ppd->num_groups; i++)
2341 name = ppd_group_name (&ppd->groups[i]);
2342 if (strcmp (name, "InstallableOptions") == 0)
2344 installed_options = &ppd->groups[i];
2349 for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
2351 option1 = ppdFindOption (ppd, constraint->option1);
2352 if (option1 == NULL)
2355 option2 = ppdFindOption (ppd, constraint->option2);
2356 if (option2 == NULL)
2359 if (option == option1)
2361 choice = constraint->choice1;
2362 other_option = option2;
2363 other_choice = constraint->choice2;
2365 else if (option == option2)
2367 choice = constraint->choice2;
2368 other_option = option1;
2369 other_choice = constraint->choice1;
2374 /* We only care of conflicts with installed_options and
2376 if (!group_has_option (installed_options, other_option) &&
2377 (strcmp (other_option->keyword, "PageSize") != 0))
2380 if (*other_choice == 0)
2382 /* Conflict only if the installed option is not off */
2383 if (value_is_off (other_option->defchoice))
2386 /* Conflict if the installed option has the specified default */
2387 else if (strcasecmp (other_choice, other_option->defchoice) != 0)
2392 /* Conflict with all non-off choices */
2393 for (j = 0; j < option->num_choices; j++)
2395 if (!value_is_off (option->choices[j].choice))
2401 for (j = 0; j < option->num_choices; j++)
2403 if (strcasecmp (option->choices[j].choice, choice) == 0)
2411 for (j = 0; j < option->num_choices; j++)
2415 else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
2416 all_default = FALSE;
2419 if ((all_default && !keep_if_only_one_option) ||
2420 (num_conflicts == option->num_choices))
2427 /* Some ppds don't have a "use printer default" option for
2428 * InputSlot. This means you always have to select a particular slot,
2429 * and you can't auto-pick source based on the paper size. To support
2430 * this we always add an auto option if there isn't one already. If
2431 * the user chooses the generated option we don't send any InputSlot
2432 * value when printing. The way we detect existing auto-cases is based
2433 * on feedback from Michael Sweet of cups fame.
2436 if (strcmp (option->keyword, "InputSlot") == 0)
2438 gboolean found_auto = FALSE;
2439 for (j = 0; j < option->num_choices; j++)
2443 if (strcmp (option->choices[j].choice, "Auto") == 0 ||
2444 strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
2445 strcmp (option->choices[j].choice, "Default") == 0 ||
2446 strcmp (option->choices[j].choice, "None") == 0 ||
2447 strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
2448 strcmp (option->choices[j].choice, "Unspecified") == 0 ||
2449 option->choices[j].code == NULL ||
2450 option->choices[j].code[0] == 0)
2464 *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
2467 for (j = 0; j < option->num_choices; j++)
2470 (*available)[i++] = &option->choices[j];
2474 (*available)[i++] = NULL;
2479 return option->num_choices - num_conflicts + add_auto;
2482 static GtkPrinterOption *
2483 create_pickone_option (ppd_file_t *ppd_file,
2484 ppd_option_t *ppd_option,
2485 const gchar *gtk_name)
2487 GtkPrinterOption *option;
2488 ppd_choice_t **available;
2492 #ifdef HAVE_CUPS_API_1_2
2493 ppd_coption_t *coption;
2496 g_assert (ppd_option->ui == PPD_UI_PICKONE);
2500 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
2504 /* right now only support one parameter per custom option
2505 * if more than one print warning and only offer the default choices
2508 label = get_option_text (ppd_file, ppd_option);
2510 #ifdef HAVE_CUPS_API_1_2
2511 coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
2515 ppd_cparam_t *cparam;
2517 cparam = ppdFirstCustomParam (coption);
2519 if (ppdNextCustomParam (coption) == NULL)
2521 switch (cparam->type)
2523 case PPD_CUSTOM_INT:
2524 option = gtk_printer_option_new (gtk_name, label,
2525 GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
2527 case PPD_CUSTOM_PASSCODE:
2528 option = gtk_printer_option_new (gtk_name, label,
2529 GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
2531 case PPD_CUSTOM_PASSWORD:
2532 option = gtk_printer_option_new (gtk_name, label,
2533 GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
2535 case PPD_CUSTOM_REAL:
2536 option = gtk_printer_option_new (gtk_name, label,
2537 GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
2539 case PPD_CUSTOM_STRING:
2540 option = gtk_printer_option_new (gtk_name, label,
2541 GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
2543 #ifdef PRINT_IGNORED_OPTIONS
2544 case PPD_CUSTOM_POINTS:
2545 g_warning ("CUPS Backend: PPD Custom Points Option not supported");
2547 case PPD_CUSTOM_CURVE:
2548 g_warning ("CUPS Backend: PPD Custom Curve Option not supported");
2550 case PPD_CUSTOM_INVCURVE:
2551 g_warning ("CUPS Backend: PPD Custom Inverse Curve Option not supported");
2558 #ifdef PRINT_IGNORED_OPTIONS
2560 g_warning ("CUPS Backend: Multi-parameter PPD Custom Option not supported");
2563 #endif /* HAVE_CUPS_API_1_2 */
2566 option = gtk_printer_option_new (gtk_name, label,
2567 GTK_PRINTER_OPTION_TYPE_PICKONE);
2570 gtk_printer_option_allocate_choices (option, n_choices);
2571 for (i = 0; i < n_choices; i++)
2573 if (available[i] == NULL)
2575 /* This was auto-added */
2576 option->choices[i] = g_strdup ("gtk-ignore-value");
2577 option->choices_display[i] = g_strdup (_("Printer Default"));
2581 option->choices[i] = g_strdup (available[i]->choice);
2582 option->choices_display[i] = get_choice_text (ppd_file, available[i]);
2585 gtk_printer_option_set (option, ppd_option->defchoice);
2587 #ifdef PRINT_IGNORED_OPTIONS
2589 g_warning ("CUPS Backend: Ignoring pickone %s\n", ppd_option->text);
2596 static GtkPrinterOption *
2597 create_boolean_option (ppd_file_t *ppd_file,
2598 ppd_option_t *ppd_option,
2599 const gchar *gtk_name)
2601 GtkPrinterOption *option;
2602 ppd_choice_t **available;
2606 g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
2610 n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
2613 label = get_option_text (ppd_file, ppd_option);
2614 option = gtk_printer_option_new (gtk_name, label,
2615 GTK_PRINTER_OPTION_TYPE_BOOLEAN);
2618 gtk_printer_option_allocate_choices (option, 2);
2619 option->choices[0] = g_strdup ("True");
2620 option->choices_display[0] = g_strdup ("True");
2621 option->choices[1] = g_strdup ("False");
2622 option->choices_display[1] = g_strdup ("False");
2624 gtk_printer_option_set (option, ppd_option->defchoice);
2626 #ifdef PRINT_IGNORED_OPTIONS
2628 g_warning ("CUPS Backend: Ignoring boolean %s\n", ppd_option->text);
2636 get_option_name (const gchar *keyword)
2640 for (i = 0; i < G_N_ELEMENTS (option_names); i++)
2641 if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
2642 return g_strdup (option_names[i].name);
2644 return g_strdup_printf ("cups-%s", keyword);
2648 strptr_cmp (const void *a,
2651 char **aa = (char **)a;
2652 char **bb = (char **)b;
2653 return strcmp (*aa, *bb);
2658 string_in_table (gchar *str,
2659 const gchar *table[],
2662 return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
2665 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
2668 handle_option (GtkPrinterOptionSet *set,
2669 ppd_file_t *ppd_file,
2670 ppd_option_t *ppd_option,
2671 ppd_group_t *toplevel_group,
2672 GtkPrintSettings *settings)
2674 GtkPrinterOption *option;
2677 if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
2680 name = get_option_name (ppd_option->keyword);
2683 if (ppd_option->ui == PPD_UI_PICKONE)
2685 option = create_pickone_option (ppd_file, ppd_option, name);
2687 else if (ppd_option->ui == PPD_UI_BOOLEAN)
2689 option = create_boolean_option (ppd_file, ppd_option, name);
2691 #ifdef PRINT_IGNORED_OPTIONS
2693 g_warning ("CUPS Backend: Ignoring pickmany setting %s\n", ppd_option->text);
2700 name = ppd_group_name (toplevel_group);
2701 if (STRING_IN_TABLE (name,
2702 color_group_whitelist) ||
2703 STRING_IN_TABLE (ppd_option->keyword,
2704 color_option_whitelist))
2706 option->group = g_strdup ("ColorPage");
2708 else if (STRING_IN_TABLE (name,
2709 image_quality_group_whitelist) ||
2710 STRING_IN_TABLE (ppd_option->keyword,
2711 image_quality_option_whitelist))
2713 option->group = g_strdup ("ImageQualityPage");
2715 else if (STRING_IN_TABLE (name,
2716 finishing_group_whitelist) ||
2717 STRING_IN_TABLE (ppd_option->keyword,
2718 finishing_option_whitelist))
2720 option->group = g_strdup ("FinishingPage");
2724 option->group = g_strdup (toplevel_group->text);
2727 set_option_from_settings (option, settings);
2729 gtk_printer_option_set_add (set, option);
2736 handle_group (GtkPrinterOptionSet *set,
2737 ppd_file_t *ppd_file,
2739 ppd_group_t *toplevel_group,
2740 GtkPrintSettings *settings)
2745 /* Ignore installable options */
2746 name = ppd_group_name (toplevel_group);
2747 if (strcmp (name, "InstallableOptions") == 0)
2750 for (i = 0; i < group->num_options; i++)
2751 handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
2753 for (i = 0; i < group->num_subgroups; i++)
2754 handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
2758 static GtkPrinterOptionSet *
2759 cups_printer_get_options (GtkPrinter *printer,
2760 GtkPrintSettings *settings,
2761 GtkPageSetup *page_setup,
2762 GtkPrintCapabilities capabilities)
2764 GtkPrinterOptionSet *set;
2765 GtkPrinterOption *option;
2766 ppd_file_t *ppd_file;
2768 char *print_at[] = { "now", "at", "on-hold" };
2769 char *n_up[] = {"1", "2", "4", "6", "9", "16" };
2770 char *prio[] = {"100", "80", "50", "30" };
2771 /* Translators: These strings name the possible values of the
2772 * job priority option in the print dialog
2774 char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
2775 char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
2776 /* Translators: These strings name the possible arrangements of
2777 * multiple pages on a sheet when printing
2779 char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
2780 N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
2781 N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
2782 N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
2785 cups_option_t *opts = NULL;
2786 GtkPrintBackendCups *backend;
2787 GtkTextDirection text_direction;
2790 set = gtk_printer_option_set_new ();
2792 /* Cups specific, non-ppd related settings */
2794 /* Translators, this string is used to label the pages-per-sheet option
2795 * in the print dialog
2797 option = gtk_printer_option_new ("gtk-n-up", _("Pages per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2798 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
2800 gtk_printer_option_set (option, "1");
2801 set_option_from_settings (option, settings);
2802 gtk_printer_option_set_add (set, option);
2803 g_object_unref (option);
2805 if (cups_printer_get_capabilities (printer) & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2807 for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
2808 n_up_layout_display[i] = _(n_up_layout_display[i]);
2810 /* Translators, this string is used to label the option in the print
2811 * dialog that controls in what order multiple pages are arranged
2813 option = gtk_printer_option_new ("gtk-n-up-layout", _("Page Ordering"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2814 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up_layout),
2815 n_up_layout, n_up_layout_display);
2817 text_direction = gtk_widget_get_default_direction ();
2818 if (text_direction == GTK_TEXT_DIR_LTR)
2819 gtk_printer_option_set (option, "lrtb");
2821 gtk_printer_option_set (option, "rltb");
2823 set_option_from_settings (option, settings);
2824 gtk_printer_option_set_add (set, option);
2825 g_object_unref (option);
2828 for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
2829 prio_display[i] = _(prio_display[i]);
2831 /* Translators, this string is used to label the job priority option
2832 * in the print dialog
2834 option = gtk_printer_option_new ("gtk-job-prio", _("Job Priority"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2835 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
2836 prio, prio_display);
2837 gtk_printer_option_set (option, "50");
2838 set_option_from_settings (option, settings);
2839 gtk_printer_option_set_add (set, option);
2840 g_object_unref (option);
2842 /* Translators, this string is used to label the billing info entry
2843 * in the print dialog
2845 option = gtk_printer_option_new ("gtk-billing-info", _("Billing Info"), GTK_PRINTER_OPTION_TYPE_STRING);
2846 gtk_printer_option_set (option, "");
2847 set_option_from_settings (option, settings);
2848 gtk_printer_option_set_add (set, option);
2849 g_object_unref (option);
2851 backend = GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer));
2853 if (backend != NULL)
2855 char *cover_default[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
2856 /* Translators, these strings are names for various 'standard' cover
2857 * pages that the printing system may support.
2859 char *cover_display_default[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
2860 char **cover = NULL;
2861 char **cover_display = NULL;
2862 char **cover_display_translated = NULL;
2863 gint num_of_covers = 0;
2867 num_of_covers = backend->number_of_covers;
2868 cover = g_new (char *, num_of_covers + 1);
2869 cover[num_of_covers] = NULL;
2870 cover_display = g_new (char *, num_of_covers + 1);
2871 cover_display[num_of_covers] = NULL;
2872 cover_display_translated = g_new (char *, num_of_covers + 1);
2873 cover_display_translated[num_of_covers] = NULL;
2875 for (i = 0; i < num_of_covers; i++)
2877 cover[i] = g_strdup (backend->covers[i]);
2879 for (j = 0; j < G_N_ELEMENTS (cover_default); j++)
2880 if (strcmp (cover_default[j], cover[i]) == 0)
2882 value = cover_display_default[j];
2885 cover_display[i] = (value != NULL) ? g_strdup (value) : g_strdup (backend->covers[i]);
2888 for (i = 0; i < num_of_covers; i++)
2889 cover_display_translated[i] = _(cover_display[i]);
2891 /* Translators, this is the label used for the option in the print
2892 * dialog that controls the front cover page.
2894 option = gtk_printer_option_new ("gtk-cover-before", _("Before"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2895 gtk_printer_option_choices_from_array (option, num_of_covers,
2896 cover, cover_display_translated);
2898 if (backend->default_cover_before != NULL)
2899 gtk_printer_option_set (option, backend->default_cover_before);
2901 gtk_printer_option_set (option, "none");
2902 set_option_from_settings (option, settings);
2903 gtk_printer_option_set_add (set, option);
2904 g_object_unref (option);
2906 /* Translators, this is the label used for the option in the print
2907 * dialog that controls the back cover page.
2909 option = gtk_printer_option_new ("gtk-cover-after", _("After"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2910 gtk_printer_option_choices_from_array (option, num_of_covers,
2911 cover, cover_display_translated);
2912 if (backend->default_cover_after != NULL)
2913 gtk_printer_option_set (option, backend->default_cover_after);
2915 gtk_printer_option_set (option, "none");
2916 set_option_from_settings (option, settings);
2917 gtk_printer_option_set_add (set, option);
2918 g_object_unref (option);
2921 g_strfreev (cover_display);
2922 g_free (cover_display_translated);
2925 /* Translators: this is the name of the option that controls when
2926 * a print job is printed. Possible values are 'now', a specified time,
2929 option = gtk_printer_option_new ("gtk-print-time", _("Print at"), GTK_PRINTER_OPTION_TYPE_PICKONE);
2930 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2931 print_at, print_at);
2932 gtk_printer_option_set (option, "now");
2933 set_option_from_settings (option, settings);
2934 gtk_printer_option_set_add (set, option);
2935 g_object_unref (option);
2937 /* Translators: this is the name of the option that allows the user
2938 * to specify a time when a print job will be printed.
2940 option = gtk_printer_option_new ("gtk-print-time-text", _("Print at time"), GTK_PRINTER_OPTION_TYPE_STRING);
2941 gtk_printer_option_set (option, "");
2942 set_option_from_settings (option, settings);
2943 gtk_printer_option_set_add (set, option);
2944 g_object_unref (option);
2946 /* Printer (ppd) specific settings */
2947 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2950 GtkPaperSize *paper_size;
2951 ppd_option_t *option;
2952 const gchar *ppd_name;
2954 ppdMarkDefaults (ppd_file);
2956 paper_size = gtk_page_setup_get_paper_size (page_setup);
2958 option = ppdFindOption (ppd_file, "PageSize");
2959 ppd_name = gtk_paper_size_get_ppd_name (paper_size);
2962 strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
2966 char width[G_ASCII_DTOSTR_BUF_SIZE];
2967 char height[G_ASCII_DTOSTR_BUF_SIZE];
2969 g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
2970 g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2971 /* Translators: this format is used to display a custom paper
2972 * size. The two placeholders are replaced with the width and height
2973 * in points. E.g: "Custom 230.4x142.9"
2975 custom_name = g_strdup_printf (_("Custom %sx%s"), width, height);
2976 strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
2977 g_free (custom_name);
2980 for (i = 0; i < ppd_file->num_groups; i++)
2981 handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2984 /* Now honor the user set defaults for this printer */
2985 num_opts = cups_get_user_options (gtk_printer_get_name (printer), 0, &opts);
2987 for (i = 0; i < num_opts; i++)
2989 if (STRING_IN_TABLE (opts[i].name, cups_option_blacklist))
2992 name = get_option_name (opts[i].name);
2993 option = gtk_printer_option_set_lookup (set, name);
2995 gtk_printer_option_set (option, opts[i].value);
2999 cupsFreeOptions (num_opts, opts);
3006 mark_option_from_set (GtkPrinterOptionSet *set,
3007 ppd_file_t *ppd_file,
3008 ppd_option_t *ppd_option)
3010 GtkPrinterOption *option;
3011 char *name = get_option_name (ppd_option->keyword);
3013 option = gtk_printer_option_set_lookup (set, name);
3016 ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
3023 mark_group_from_set (GtkPrinterOptionSet *set,
3024 ppd_file_t *ppd_file,
3029 for (i = 0; i < group->num_options; i++)
3030 mark_option_from_set (set, ppd_file, &group->options[i]);
3032 for (i = 0; i < group->num_subgroups; i++)
3033 mark_group_from_set (set, ppd_file, &group->subgroups[i]);
3037 set_conflicts_from_option (GtkPrinterOptionSet *set,
3038 ppd_file_t *ppd_file,
3039 ppd_option_t *ppd_option)
3041 GtkPrinterOption *option;
3044 if (ppd_option->conflicted)
3046 name = get_option_name (ppd_option->keyword);
3047 option = gtk_printer_option_set_lookup (set, name);
3050 gtk_printer_option_set_has_conflict (option, TRUE);
3051 #ifdef PRINT_IGNORED_OPTIONS
3053 g_warning ("CUPS Backend: Ignoring conflict for option %s", ppd_option->keyword);
3061 set_conflicts_from_group (GtkPrinterOptionSet *set,
3062 ppd_file_t *ppd_file,
3067 for (i = 0; i < group->num_options; i++)
3068 set_conflicts_from_option (set, ppd_file, &group->options[i]);
3070 for (i = 0; i < group->num_subgroups; i++)
3071 set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
3075 cups_printer_mark_conflicts (GtkPrinter *printer,
3076 GtkPrinterOptionSet *options)
3078 ppd_file_t *ppd_file;
3082 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3084 if (ppd_file == NULL)
3087 ppdMarkDefaults (ppd_file);
3089 for (i = 0; i < ppd_file->num_groups; i++)
3090 mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
3092 num_conflicts = ppdConflicts (ppd_file);
3094 if (num_conflicts > 0)
3096 for (i = 0; i < ppd_file->num_groups; i++)
3097 set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
3100 return num_conflicts > 0;
3104 GtkPrinter *printer;
3105 GtkPrinterOptionSet *options;
3106 GtkPrintSettings *settings;
3107 ppd_file_t *ppd_file;
3112 const char *standard;
3116 map_settings_to_option (GtkPrinterOption *option,
3117 const NameMapping table[],
3119 GtkPrintSettings *settings,
3120 const gchar *standard_name,
3121 const gchar *cups_name)
3125 const char *cups_value;
3126 const char *standard_value;
3128 /* If the cups-specific setting is set, always use that */
3129 name = g_strdup_printf ("cups-%s", cups_name);
3130 cups_value = gtk_print_settings_get (settings, name);
3133 if (cups_value != NULL)
3135 gtk_printer_option_set (option, cups_value);
3139 /* Otherwise we try to convert from the general setting */
3140 standard_value = gtk_print_settings_get (settings, standard_name);
3141 if (standard_value == NULL)
3144 for (i = 0; i < n_elements; i++)
3146 if (table[i].cups == NULL && table[i].standard == NULL)
3148 gtk_printer_option_set (option, standard_value);
3151 else if (table[i].cups == NULL &&
3152 strcmp (table[i].standard, standard_value) == 0)
3154 set_option_off (option);
3157 else if (strcmp (table[i].standard, standard_value) == 0)
3159 gtk_printer_option_set (option, table[i].cups);
3166 map_option_to_settings (const gchar *value,
3167 const NameMapping table[],
3169 GtkPrintSettings *settings,
3170 const gchar *standard_name,
3171 const gchar *cups_name)
3176 for (i = 0; i < n_elements; i++)
3178 if (table[i].cups == NULL && table[i].standard == NULL)
3180 gtk_print_settings_set (settings,
3185 else if (table[i].cups == NULL && table[i].standard != NULL)
3187 if (value_is_off (value))
3189 gtk_print_settings_set (settings,
3195 else if (strcmp (table[i].cups, value) == 0)
3197 gtk_print_settings_set (settings,
3204 /* Always set the corresponding cups-specific setting */
3205 name = g_strdup_printf ("cups-%s", cups_name);
3206 gtk_print_settings_set (settings, name, value);
3211 static const NameMapping paper_source_map[] = {
3212 { "Lower", "lower"},
3213 { "Middle", "middle"},
3214 { "Upper", "upper"},
3216 { "Envelope", "envelope"},
3217 { "Cassette", "cassette"},
3218 { "LargeCapacity", "large-capacity"},
3219 { "AnySmallFormat", "small-format"},
3220 { "AnyLargeFormat", "large-format"},
3224 static const NameMapping output_tray_map[] = {
3225 { "Upper", "upper"},
3226 { "Lower", "lower"},
3231 static const NameMapping duplex_map[] = {
3232 { "DuplexTumble", "vertical" },
3233 { "DuplexNoTumble", "horizontal" },
3237 static const NameMapping output_mode_map[] = {
3238 { "Standard", "normal" },
3239 { "Normal", "normal" },
3240 { "Draft", "draft" },
3241 { "Fast", "draft" },
3244 static const NameMapping media_type_map[] = {
3245 { "Transparency", "transparency"},
3246 { "Standard", "stationery"},
3250 static const NameMapping all_map[] = {
3256 set_option_from_settings (GtkPrinterOption *option,
3257 GtkPrintSettings *settings)
3259 const char *cups_value;
3262 if (settings == NULL)
3265 if (strcmp (option->name, "gtk-paper-source") == 0)
3266 map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
3267 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
3268 else if (strcmp (option->name, "gtk-output-tray") == 0)
3269 map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
3270 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
3271 else if (strcmp (option->name, "gtk-duplex") == 0)
3272 map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
3273 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
3274 else if (strcmp (option->name, "cups-OutputMode") == 0)
3275 map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
3276 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
3277 else if (strcmp (option->name, "cups-Resolution") == 0)
3279 cups_value = gtk_print_settings_get (settings, option->name);
3281 gtk_printer_option_set (option, cups_value);
3284 int res = gtk_print_settings_get_resolution (settings);
3287 value = g_strdup_printf ("%ddpi", res);
3288 gtk_printer_option_set (option, value);
3293 else if (strcmp (option->name, "gtk-paper-type") == 0)
3294 map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
3295 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
3296 else if (strcmp (option->name, "gtk-n-up") == 0)
3298 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
3299 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
3301 else if (strcmp (option->name, "gtk-n-up-layout") == 0)
3303 map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
3304 settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
3306 else if (strcmp (option->name, "gtk-billing-info") == 0)
3308 cups_value = gtk_print_settings_get (settings, "cups-job-billing");
3310 gtk_printer_option_set (option, cups_value);
3312 else if (strcmp (option->name, "gtk-job-prio") == 0)
3314 cups_value = gtk_print_settings_get (settings, "cups-job-priority");
3316 gtk_printer_option_set (option, cups_value);
3318 else if (strcmp (option->name, "gtk-cover-before") == 0)
3320 cups_value = gtk_print_settings_get (settings, "cover-before");
3322 gtk_printer_option_set (option, cups_value);
3324 else if (strcmp (option->name, "gtk-cover-after") == 0)
3326 cups_value = gtk_print_settings_get (settings, "cover-after");
3328 gtk_printer_option_set (option, cups_value);
3330 else if (strcmp (option->name, "gtk-print-time") == 0)
3332 cups_value = gtk_print_settings_get (settings, "print-at");
3334 gtk_printer_option_set (option, cups_value);
3336 else if (strcmp (option->name, "gtk-print-time-text") == 0)
3338 cups_value = gtk_print_settings_get (settings, "print-at-time");
3340 gtk_printer_option_set (option, cups_value);
3342 else if (g_str_has_prefix (option->name, "cups-"))
3344 cups_value = gtk_print_settings_get (settings, option->name);
3346 gtk_printer_option_set (option, cups_value);
3351 foreach_option_get_settings (GtkPrinterOption *option,
3354 struct OptionData *data = user_data;
3355 GtkPrintSettings *settings = data->settings;
3358 value = option->value;
3360 if (strcmp (option->name, "gtk-paper-source") == 0)
3361 map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
3362 settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
3363 else if (strcmp (option->name, "gtk-output-tray") == 0)
3364 map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
3365 settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
3366 else if (strcmp (option->name, "gtk-duplex") == 0)
3367 map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
3368 settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
3369 else if (strcmp (option->name, "cups-OutputMode") == 0)
3370 map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
3371 settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
3372 else if (strcmp (option->name, "cups-Resolution") == 0)
3374 int res = atoi (value);
3375 /* TODO: What if resolution is on XXXxYYYdpi form? */
3377 gtk_print_settings_set_resolution (settings, res);
3378 gtk_print_settings_set (settings, option->name, value);
3380 else if (strcmp (option->name, "gtk-paper-type") == 0)
3381 map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
3382 settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
3383 else if (strcmp (option->name, "gtk-n-up") == 0)
3384 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
3385 settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
3386 else if (strcmp (option->name, "gtk-n-up-layout") == 0)
3387 map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
3388 settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
3389 else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
3390 gtk_print_settings_set (settings, "cups-job-billing", value);
3391 else if (strcmp (option->name, "gtk-job-prio") == 0)
3392 gtk_print_settings_set (settings, "cups-job-priority", value);
3393 else if (strcmp (option->name, "gtk-cover-before") == 0)
3394 gtk_print_settings_set (settings, "cover-before", value);
3395 else if (strcmp (option->name, "gtk-cover-after") == 0)
3396 gtk_print_settings_set (settings, "cover-after", value);
3397 else if (strcmp (option->name, "gtk-print-time") == 0)
3398 gtk_print_settings_set (settings, "print-at", value);
3399 else if (strcmp (option->name, "gtk-print-time-text") == 0)
3400 gtk_print_settings_set (settings, "print-at-time", value);
3401 else if (g_str_has_prefix (option->name, "cups-"))
3402 gtk_print_settings_set (settings, option->name, value);
3406 cups_printer_get_settings_from_options (GtkPrinter *printer,
3407 GtkPrinterOptionSet *options,
3408 GtkPrintSettings *settings)
3410 struct OptionData data;
3411 const char *print_at, *print_at_time;
3413 data.printer = printer;
3414 data.options = options;
3415 data.settings = settings;
3416 data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3418 if (data.ppd_file != NULL)
3420 GtkPrinterOption *cover_before, *cover_after;
3422 gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
3424 cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
3425 cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
3426 if (cover_before && cover_after)
3428 char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
3429 gtk_print_settings_set (settings, "cups-job-sheets", value);
3433 print_at = gtk_print_settings_get (settings, "print-at");
3434 print_at_time = gtk_print_settings_get (settings, "print-at-time");
3435 if (strcmp (print_at, "at") == 0)
3436 gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
3437 else if (strcmp (print_at, "on-hold") == 0)
3438 gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
3443 cups_printer_prepare_for_print (GtkPrinter *printer,
3444 GtkPrintJob *print_job,
3445 GtkPrintSettings *settings,
3446 GtkPageSetup *page_setup)
3448 GtkPageSet page_set;
3449 GtkPaperSize *paper_size;
3450 const char *ppd_paper_name;
3453 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
3454 print_job->page_ranges = NULL;
3455 print_job->num_page_ranges = 0;
3457 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
3458 print_job->page_ranges =
3459 gtk_print_settings_get_page_ranges (settings,
3460 &print_job->num_page_ranges);
3462 if (gtk_print_settings_get_collate (settings))
3463 gtk_print_settings_set (settings, "cups-Collate", "True");
3464 print_job->collate = FALSE;
3466 if (gtk_print_settings_get_reverse (settings))
3467 gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
3468 print_job->reverse = FALSE;
3470 if (gtk_print_settings_get_n_copies (settings) > 1)
3471 gtk_print_settings_set_int (settings, "cups-copies",
3472 gtk_print_settings_get_n_copies (settings));
3473 print_job->num_copies = 1;
3475 scale = gtk_print_settings_get_scale (settings);
3476 print_job->scale = 1.0;
3478 print_job->scale = scale/100.0;
3480 page_set = gtk_print_settings_get_page_set (settings);
3481 if (page_set == GTK_PAGE_SET_EVEN)
3482 gtk_print_settings_set (settings, "cups-page-set", "even");
3483 else if (page_set == GTK_PAGE_SET_ODD)
3484 gtk_print_settings_set (settings, "cups-page-set", "odd");
3485 print_job->page_set = GTK_PAGE_SET_ALL;
3487 paper_size = gtk_page_setup_get_paper_size (page_setup);
3488 ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
3489 if (ppd_paper_name != NULL)
3490 gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
3493 char width[G_ASCII_DTOSTR_BUF_SIZE];
3494 char height[G_ASCII_DTOSTR_BUF_SIZE];
3497 g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
3498 g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
3499 custom_name = g_strdup_printf (("Custom.%sx%s"), width, height);
3500 gtk_print_settings_set (settings, "cups-PageSize", custom_name);
3501 g_free (custom_name);
3504 print_job->rotate_to_orientation = TRUE;
3507 static GtkPageSetup *
3508 create_page_setup (ppd_file_t *ppd_file,
3512 GtkPageSetup *page_setup;
3513 GtkPaperSize *paper_size;
3514 ppd_option_t *option;
3515 ppd_choice_t *choice;
3517 display_name = NULL;
3518 option = ppdFindOption (ppd_file, "PageSize");
3521 choice = ppdFindChoice (option, size->name);
3523 display_name = ppd_text_to_utf8 (ppd_file, choice->text);
3526 if (display_name == NULL)
3527 display_name = g_strdup (size->name);
3529 page_setup = gtk_page_setup_new ();
3530 paper_size = gtk_paper_size_new_from_ppd (size->name,
3534 gtk_page_setup_set_paper_size (page_setup, paper_size);
3535 gtk_paper_size_free (paper_size);
3537 gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
3538 gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
3539 gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
3540 gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
3542 g_free (display_name);
3548 cups_printer_list_papers (GtkPrinter *printer)
3550 ppd_file_t *ppd_file;
3552 GtkPageSetup *page_setup;
3556 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3557 if (ppd_file == NULL)
3562 for (i = 0; i < ppd_file->num_sizes; i++)
3564 size = &ppd_file->sizes[i];
3566 page_setup = create_page_setup (ppd_file, size);
3568 l = g_list_prepend (l, page_setup);
3571 return g_list_reverse (l);
3574 static GtkPageSetup *
3575 cups_printer_get_default_page_size (GtkPrinter *printer)
3577 ppd_file_t *ppd_file;
3579 ppd_option_t *option;
3582 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3583 if (ppd_file == NULL)
3586 option = ppdFindOption (ppd_file, "PageSize");
3587 size = ppdPageSize (ppd_file, option->defchoice);
3589 return create_page_setup (ppd_file, size);
3593 cups_printer_get_hard_margins (GtkPrinter *printer,
3599 ppd_file_t *ppd_file;
3601 ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
3602 if (ppd_file == NULL)
3605 *left = ppd_file->custom_margins[0];
3606 *bottom = ppd_file->custom_margins[1];
3607 *right = ppd_file->custom_margins[2];
3608 *top = ppd_file->custom_margins[3];
3611 static GtkPrintCapabilities
3612 cups_printer_get_capabilities (GtkPrinter *printer)
3615 GTK_PRINT_CAPABILITY_COPIES |
3616 GTK_PRINT_CAPABILITY_COLLATE |
3617 GTK_PRINT_CAPABILITY_REVERSE |
3618 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 1 && CUPS_VERSION_PATCH >= 15) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || CUPS_VERSION_MAJOR > 1
3619 GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT |
3621 GTK_PRINT_CAPABILITY_NUMBER_UP;