X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=modules%2Fprintbackends%2Fcups%2Fgtkprintbackendcups.c;h=bc1f30508c1fdd7f06ca2e7daba9293ae7ef80fa;hb=9d0febc9a64a5bfb0fcfc3a88de4757f6c1ff090;hp=c63882c14190255a8df0707f1dbdd763f1e5494f;hpb=7698daf97aced5c22aeeb7bfbf02567b61cebaef;p=~andy%2Fgtk diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index c63882c14..bc1f30508 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -14,9 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #ifdef __linux__ @@ -54,6 +52,9 @@ #include "gtkcupsutils.h" +#ifdef HAVE_COLORD +#include +#endif typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass; @@ -92,8 +93,11 @@ typedef struct http_t *http; GtkCupsRequest *request; + GtkCupsPollState poll_state; GPollFD *data_poll; GtkPrintBackendCups *backend; + GtkPrintCupsResponseCallbackFunc callback; + gpointer callback_data; } GtkPrintCupsDispatchWatch; @@ -110,19 +114,22 @@ struct _GtkPrintBackendCups guint list_printers_poll; guint list_printers_pending : 1; + gint list_printers_attempts; guint got_default_printer : 1; guint default_printer_poll; GtkCupsConnectionTest *cups_connection_test; + gint reading_ppds; char **covers; - char *default_cover_before; - char *default_cover_after; int number_of_covers; GList *requests; GHashTable *auth; gchar *username; gboolean authentication_lock; +#ifdef HAVE_COLORD + CdClient *colord_client; +#endif }; static GObjectClass *backend_parent_class; @@ -156,12 +163,12 @@ static GList * cups_printer_list_papers (GtkPrinter static GtkPageSetup * cups_printer_get_default_page_size (GtkPrinter *printer); static void cups_printer_request_details (GtkPrinter *printer); static gboolean cups_request_default_printer (GtkPrintBackendCups *print_backend); -static void cups_request_ppd (GtkPrinter *printer); -static void cups_printer_get_hard_margins (GtkPrinter *printer, - double *top, - double *bottom, - double *left, - double *right); +static gboolean cups_request_ppd (GtkPrinter *printer); +static gboolean cups_printer_get_hard_margins (GtkPrinter *printer, + gdouble *top, + gdouble *bottom, + gdouble *left, + gdouble *right); static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer); static void set_option_from_settings (GtkPrinterOption *option, GtkPrintSettings *setting); @@ -181,18 +188,18 @@ static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter gdouble height, GIOChannel *cache_io); -static void gtk_print_backend_cups_set_password (GtkPrintBackend *backend, - const gchar *hostname, - const gchar *username, - const gchar *password); +static void gtk_print_backend_cups_set_password (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info); -void overwrite_and_free (gpointer data); -static gboolean is_address_local (const gchar *address); +void overwrite_and_free (gpointer data); +static gboolean is_address_local (const gchar *address); +static gboolean request_auth_info (gpointer data); static void gtk_print_backend_cups_register_type (GTypeModule *module) { - static const GTypeInfo print_backend_cups_info = + const GTypeInfo print_backend_cups_info = { sizeof (GtkPrintBackendCupsClass), NULL, /* base_init */ @@ -315,7 +322,7 @@ _cairo_write_to_cups (void *closure, } GTK_NOTE (PRINTING, - g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written)); + g_print ("CUPS Backend: Wrote %"G_GSIZE_FORMAT" bytes to temp file\n", written)); data += written; length -= written; @@ -331,18 +338,19 @@ cups_printer_create_cairo_surface (GtkPrinter *printer, gdouble height, GIOChannel *cache_io) { - cairo_surface_t *surface; + cairo_surface_t *surface; ppd_file_t *ppd_file = NULL; ppd_attr_t *ppd_attr = NULL; ppd_attr_t *ppd_attr_res = NULL; ppd_attr_t *ppd_attr_screen_freq = NULL; ppd_attr_t *ppd_attr_res_screen_freq = NULL; gchar *res_string = NULL; - int level = 2; - - /* TODO: check if it is a ps or pdf printer */ - - surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height); + gint level = 2; + + if (gtk_printer_accepts_pdf (printer)) + surface = cairo_pdf_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height); + else + surface = cairo_ps_surface_create_for_stream (_cairo_write_to_cups, cache_io, width, height); ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer)); @@ -363,27 +371,25 @@ cups_printer_create_cairo_surface (GtkPrinter *printer, if (sscanf (ppd_attr_res->value, "%dx%ddpi", &res_x, &res_y) == 2) { - if (res_x != 0 && res_y != 0) + if (res_x > 0 && res_y > 0) gtk_print_settings_set_resolution_xy (settings, res_x, res_y); } else if (sscanf (ppd_attr_res->value, "%ddpi", &res) == 1) { - if (res != 0) + if (res > 0) gtk_print_settings_set_resolution (settings, res); } - else - gtk_print_settings_set_resolution (settings, 300); } } - res_string = g_strdup_printf ("%ddpi", + res_string = g_strdup_printf ("%ddpi", gtk_print_settings_get_resolution (settings)); ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string); g_free (res_string); if (ppd_attr_res_screen_freq == NULL) { - res_string = g_strdup_printf ("%dx%ddpi", + res_string = g_strdup_printf ("%dx%ddpi", gtk_print_settings_get_resolution_x (settings), gtk_print_settings_get_resolution_y (settings)); ppd_attr_res_screen_freq = ppdFindAttr (ppd_file, "ResScreenFreq", res_string); @@ -392,24 +398,20 @@ cups_printer_create_cairo_surface (GtkPrinter *printer, ppd_attr_screen_freq = ppdFindAttr (ppd_file, "ScreenFreq", NULL); - if (ppd_attr_res_screen_freq != NULL) + if (ppd_attr_res_screen_freq != NULL && atof (ppd_attr_res_screen_freq->value) > 0.0) gtk_print_settings_set_printer_lpi (settings, atof (ppd_attr_res_screen_freq->value)); - else if (ppd_attr_screen_freq != NULL) + else if (ppd_attr_screen_freq != NULL && atof (ppd_attr_screen_freq->value) > 0.0) gtk_print_settings_set_printer_lpi (settings, atof (ppd_attr_screen_freq->value)); - else - gtk_print_settings_set_printer_lpi (settings, 150.0); - } - else - { - gtk_print_settings_set_resolution (settings, 300); - gtk_print_settings_set_printer_lpi (settings, 150.0); } - if (level == 2) - cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); + if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_PS) + { + if (level == 2) + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); - if (level == 3) - cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3); + if (level == 3) + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3); + } cairo_surface_set_fallback_resolution (surface, 2.0 * gtk_print_settings_get_printer_lpi (settings), @@ -485,22 +487,68 @@ cups_print_cb (GtkPrintBackendCups *print_backend, GDK_THREADS_LEAVE (); } +typedef struct { + GtkCupsRequest *request; + GtkPrinterCups *printer; +} CupsOptionsData; + static void add_cups_options (const gchar *key, const gchar *value, gpointer user_data) { - GtkCupsRequest *request = user_data; + CupsOptionsData *data = (CupsOptionsData *) user_data; + GtkCupsRequest *request = data->request; + GtkPrinterCups *printer = data->printer; + gboolean custom_value = FALSE; + gchar *new_value = NULL; + gint i; + + if (!key || !value) + return; if (!g_str_has_prefix (key, "cups-")) return; if (strcmp (value, "gtk-ignore-value") == 0) return; - + key = key + strlen ("cups-"); - gtk_cups_request_encode_option (request, key, value); + if (printer && printer->ppd_file) + { + ppd_coption_t *coption; + gboolean found = FALSE; + gboolean custom_values_enabled = FALSE; + + coption = ppdFindCustomOption (printer->ppd_file, key); + if (coption && coption->option) + { + for (i = 0; i < coption->option->num_choices; i++) + { + /* Are custom values enabled ? */ + if (g_str_equal (coption->option->choices[i].choice, "Custom")) + custom_values_enabled = TRUE; + + /* Is the value among available choices ? */ + if (g_str_equal (coption->option->choices[i].choice, value)) + found = TRUE; + } + + if (custom_values_enabled && !found) + custom_value = TRUE; + } + } + + /* Add "Custom." prefix to custom values. */ + if (custom_value) + { + new_value = g_strdup_printf ("Custom.%s", value); + gtk_cups_request_encode_option (request, key, new_value); + g_free (new_value); + } + else + gtk_cups_request_encode_option (request, key, value); } static void @@ -513,6 +561,7 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, { GtkPrinterCups *cups_printer; CupsPrintStreamData *ps; + CupsOptionsData *options_data; GtkCupsRequest *request; GtkPrintSettings *settings; const gchar *title; @@ -560,14 +609,21 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, IPP_TAG_NAME, "job-name", NULL, title); - gtk_print_settings_foreach (settings, add_cups_options, request); - + options_data = g_new0 (CupsOptionsData, 1); + options_data->request = request; + options_data->printer = cups_printer; + gtk_print_settings_foreach (settings, add_cups_options, options_data); + g_free (options_data); + ps = g_new0 (CupsPrintStreamData, 1); ps->callback = callback; ps->user_data = user_data; ps->dnotify = dnotify; ps->job = g_object_ref (job); + request->need_auth_info = cups_printer->auth_info_required != NULL; + request->auth_info_required = g_strdupv (cups_printer->auth_info_required); + cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend), request, (GtkPrintCupsResponseCallbackFunc) cups_print_cb, @@ -592,14 +648,14 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->list_printers_poll = FALSE; backend_cups->got_default_printer = FALSE; backend_cups->list_printers_pending = FALSE; + backend_cups->list_printers_attempts = 0; + backend_cups->reading_ppds = 0; backend_cups->requests = NULL; backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free); backend_cups->authentication_lock = FALSE; backend_cups->covers = NULL; - backend_cups->default_cover_before = NULL; - backend_cups->default_cover_after = NULL; backend_cups->number_of_covers = 0; backend_cups->default_printer_poll = 0; @@ -607,6 +663,10 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->username = NULL; +#ifdef HAVE_COLORD + backend_cups->colord_client = cd_client_new (); +#endif + cups_get_local_default_printer (backend_cups); } @@ -626,9 +686,6 @@ gtk_print_backend_cups_finalize (GObject *object) g_strfreev (backend_cups->covers); backend_cups->number_of_covers = 0; - g_free (backend_cups->default_cover_before); - g_free (backend_cups->default_cover_after); - gtk_cups_connection_test_free (backend_cups->cups_connection_test); backend_cups->cups_connection_test = NULL; @@ -636,6 +693,10 @@ gtk_print_backend_cups_finalize (GObject *object) g_free (backend_cups->username); +#ifdef HAVE_COLORD + g_object_unref (backend_cups->colord_client); +#endif + backend_parent_class->finalize (object); } @@ -652,6 +713,7 @@ gtk_print_backend_cups_dispose (GObject *object) if (backend_cups->list_printers_poll > 0) g_source_remove (backend_cups->list_printers_poll); backend_cups->list_printers_poll = 0; + backend_cups->list_printers_attempts = 0; if (backend_cups->default_printer_poll > 0) g_source_remove (backend_cups->default_printer_poll); @@ -671,25 +733,78 @@ is_address_local (const gchar *address) return FALSE; } +#ifndef HAVE_CUPS_API_1_2 +/* Included from CUPS library because of backward compatibility */ +const char * +httpGetHostname(http_t *http, + char *s, + int slen) +{ + struct hostent *host; + + if (!s || slen <= 1) + return (NULL); + + if (http) + { + if (http->hostname[0] == '/') + g_strlcpy (s, "localhost", slen); + else + g_strlcpy (s, http->hostname, slen); + } + else + { + if (gethostname (s, slen) < 0) + g_strlcpy (s, "localhost", slen); + + if (!strchr (s, '.')) + { + if ((host = gethostbyname (s)) != NULL && host->h_name) + g_strlcpy (s, host->h_name, slen); + } + } + return (s); +} +#endif + static void -gtk_print_backend_cups_set_password (GtkPrintBackend *backend, - const gchar *hostname, - const gchar *username, - const gchar *password) +gtk_print_backend_cups_set_password (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info) { GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend); GList *l; char dispatch_hostname[HTTP_MAX_URI]; - gchar *key; + gchar *username = NULL; + gchar *hostname = NULL; + gchar *password = NULL; + gint length; + gint i; - key = g_strconcat (username, "@", hostname, NULL); - g_hash_table_insert (cups_backend->auth, key, g_strdup (password)); + length = g_strv_length (auth_info_required); + + if (auth_info != NULL) + for (i = 0; i < length; i++) + { + if (g_strcmp0 (auth_info_required[i], "username") == 0) + username = g_strdup (auth_info[i]); + else if (g_strcmp0 (auth_info_required[i], "hostname") == 0) + hostname = g_strdup (auth_info[i]); + else if (g_strcmp0 (auth_info_required[i], "password") == 0) + password = g_strdup (auth_info[i]); + } + + if (hostname != NULL && username != NULL && password != NULL) + { + gchar *key = g_strconcat (username, "@", hostname, NULL); + g_hash_table_insert (cups_backend->auth, key, g_strdup (password)); + GTK_NOTE (PRINTING, + g_print ("CUPS backend: storing password for %s\n", key)); + } g_free (cups_backend->username); cups_backend->username = g_strdup (username); - GTK_NOTE (PRINTING, - g_print ("CUPS backend: storing password for %s\n", key)); for (l = cups_backend->requests; l; l = l->next) { @@ -699,7 +814,18 @@ gtk_print_backend_cups_set_password (GtkPrintBackend *backend, if (is_address_local (dispatch_hostname)) strcpy (dispatch_hostname, "localhost"); - if (strcmp (hostname, dispatch_hostname) == 0) + if (dispatch->request->need_auth_info) + { + if (auth_info != NULL) + { + dispatch->request->auth_info = g_new0 (gchar *, length + 1); + for (i = 0; i < length; i++) + dispatch->request->auth_info[i] = g_strdup (auth_info[i]); + } + dispatch->backend->authentication_lock = FALSE; + dispatch->request->need_auth_info = FALSE; + } + else if (dispatch->request->password_state == GTK_CUPS_PASSWORD_REQUESTED || auth_info == NULL) { overwrite_and_free (dispatch->request->password); dispatch->request->password = g_strdup (password); @@ -720,9 +846,15 @@ request_password (gpointer data) gchar *prompt = NULL; gchar *key = NULL; char hostname[HTTP_MAX_URI]; + gchar **auth_info_required; + gchar **auth_info_default; + gchar **auth_info_display; + gboolean *auth_info_visible; + gint length = 3; + gint i; if (dispatch->backend->authentication_lock) - return FALSE; + return G_SOURCE_REMOVE; httpGetHostname (dispatch->request->http, hostname, sizeof (hostname)); if (is_address_local (hostname)) @@ -733,6 +865,22 @@ request_password (gpointer data) else username = cupsUser (); + auth_info_required = g_new0 (gchar*, length + 1); + auth_info_required[0] = g_strdup ("hostname"); + auth_info_required[1] = g_strdup ("username"); + auth_info_required[2] = g_strdup ("password"); + + auth_info_default = g_new0 (gchar*, length + 1); + auth_info_default[0] = g_strdup (hostname); + auth_info_default[1] = g_strdup (username); + + auth_info_display = g_new0 (gchar*, length + 1); + auth_info_display[1] = g_strdup (_("Username:")); + auth_info_display[2] = g_strdup (_("Password:")); + + auth_info_visible = g_new0 (gboolean, length + 1); + auth_info_visible[1] = TRUE; + key = g_strconcat (username, "@", hostname, NULL); password = g_hash_table_lookup (dispatch->backend->auth, key); @@ -765,9 +913,6 @@ request_password (gpointer data) switch (dispatch->request->ipp_request->request.op.operation_id) { - case 0: - prompt = g_strdup_printf ( _("Authentication is required to get a file from %s"), hostname); - break; case IPP_PRINT_JOB: if (job_title != NULL && printer_name != NULL) prompt = g_strdup_printf ( _("Authentication is required to print document '%s' on printer %s"), job_title, printer_name); @@ -793,66 +938,238 @@ request_password (gpointer data) prompt = g_strdup_printf ( _("Authentication is required to get printers from %s"), hostname); break; default: - prompt = g_strdup_printf ( _("Authentication is required on %s"), hostname); + /* work around gcc warning about 0 not being a value for this enum */ + if (dispatch->request->ipp_request->request.op.operation_id == 0) + prompt = g_strdup_printf ( _("Authentication is required to get a file from %s"), hostname); + else + prompt = g_strdup_printf ( _("Authentication is required on %s"), hostname); break; } g_free (printer_name); g_signal_emit_by_name (dispatch->backend, "request-password", - hostname, username, prompt); + auth_info_required, auth_info_default, auth_info_display, auth_info_visible, prompt); g_free (prompt); } + for (i = 0; i < length; i++) + { + g_free (auth_info_required[i]); + g_free (auth_info_default[i]); + g_free (auth_info_display[i]); + } + + g_free (auth_info_required); + g_free (auth_info_default); + g_free (auth_info_display); + g_free (auth_info_visible); g_free (key); - return FALSE; + return G_SOURCE_REMOVE; } -static gboolean -cups_dispatch_watch_check (GSource *source) +static void +cups_dispatch_add_poll (GSource *source) { GtkPrintCupsDispatchWatch *dispatch; GtkCupsPollState poll_state; - gboolean result; - - GTK_NOTE (PRINTING, - g_print ("CUPS Backend: %s \n", G_STRFUNC, source)); dispatch = (GtkPrintCupsDispatchWatch *) source; poll_state = gtk_cups_request_get_poll_state (dispatch->request); + /* Remove the old source if the poll state changed. */ + if (poll_state != dispatch->poll_state && dispatch->data_poll != NULL) + { + g_source_remove_poll (source, dispatch->data_poll); + g_free (dispatch->data_poll); + dispatch->data_poll = NULL; + } + if (dispatch->request->http != NULL) { if (dispatch->data_poll == NULL) - { + { dispatch->data_poll = g_new0 (GPollFD, 1); - g_source_add_poll (source, dispatch->data_poll); - } - else - { + dispatch->poll_state = poll_state; + if (poll_state == GTK_CUPS_HTTP_READ) dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI; else if (poll_state == GTK_CUPS_HTTP_WRITE) dispatch->data_poll->events = G_IO_OUT | G_IO_ERR; else dispatch->data_poll->events = 0; - } #ifdef HAVE_CUPS_API_1_2 - dispatch->data_poll->fd = httpGetFd (dispatch->request->http); + dispatch->data_poll->fd = httpGetFd (dispatch->request->http); #else - dispatch->data_poll->fd = dispatch->request->http->fd; + dispatch->data_poll->fd = dispatch->request->http->fd; #endif + g_source_add_poll (source, dispatch->data_poll); + } } - +} + +static gboolean +check_auth_info (gpointer user_data) +{ + GtkPrintCupsDispatchWatch *dispatch; + dispatch = (GtkPrintCupsDispatchWatch *) user_data; + + if (!dispatch->request->need_auth_info) + { + if (dispatch->request->auth_info == NULL) + { + dispatch->callback (GTK_PRINT_BACKEND (dispatch->backend), + gtk_cups_request_get_result (dispatch->request), + dispatch->callback_data); + g_source_destroy ((GSource *) dispatch); + } + else + { + gint length; + gint i; + + length = g_strv_length (dispatch->request->auth_info_required); + + gtk_cups_request_ipp_add_strings (dispatch->request, + IPP_TAG_JOB, + IPP_TAG_TEXT, + "auth-info", + length, + NULL, + (const char * const *) dispatch->request->auth_info); + + g_source_attach ((GSource *) dispatch, NULL); + g_source_unref ((GSource *) dispatch); + + for (i = 0; i < length; i++) + overwrite_and_free (dispatch->request->auth_info[i]); + g_free (dispatch->request->auth_info); + dispatch->request->auth_info = NULL; + } + + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static gboolean +request_auth_info (gpointer user_data) +{ + GtkPrintCupsDispatchWatch *dispatch; + const char *job_title; + const char *printer_uri; + gchar *prompt = NULL; + char *printer_name = NULL; + gint length; + gint i; + gboolean *auth_info_visible = NULL; + gchar **auth_info_default = NULL; + gchar **auth_info_display = NULL; + + dispatch = (GtkPrintCupsDispatchWatch *) user_data; + + if (dispatch->backend->authentication_lock) + return FALSE; + + job_title = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name"); + printer_uri = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri"); + length = g_strv_length (dispatch->request->auth_info_required); + + auth_info_visible = g_new0 (gboolean, length); + auth_info_default = g_new0 (gchar *, length + 1); + auth_info_display = g_new0 (gchar *, length + 1); + + for (i = 0; i < length; i++) + { + if (g_strcmp0 (dispatch->request->auth_info_required[i], "domain") == 0) + { + auth_info_display[i] = g_strdup (_("Domain:")); + auth_info_default[i] = g_strdup ("WORKGROUP"); + auth_info_visible[i] = TRUE; + } + else if (g_strcmp0 (dispatch->request->auth_info_required[i], "username") == 0) + { + auth_info_display[i] = g_strdup (_("Username:")); + if (dispatch->backend->username != NULL) + auth_info_default[i] = g_strdup (dispatch->backend->username); + else + auth_info_default[i] = g_strdup (cupsUser ()); + auth_info_visible[i] = TRUE; + } + else if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0) + { + auth_info_display[i] = g_strdup (_("Password:")); + auth_info_visible[i] = FALSE; + } + } + + if (printer_uri != NULL && strrchr (printer_uri, '/') != NULL) + printer_name = g_strdup (strrchr (printer_uri, '/') + 1); + + dispatch->backend->authentication_lock = TRUE; + + if (job_title != NULL) + { + if (printer_name != NULL) + prompt = g_strdup_printf ( _("Authentication is required to print document '%s' on printer %s"), job_title, printer_name); + else + prompt = g_strdup_printf ( _("Authentication is required to print document '%s'"), job_title); + } + else + { + if (printer_name != NULL) + prompt = g_strdup_printf ( _("Authentication is required to print this document on printer %s"), printer_name); + else + prompt = g_strdup ( _("Authentication is required to print this document")); + } + + g_signal_emit_by_name (dispatch->backend, "request-password", + dispatch->request->auth_info_required, + auth_info_default, + auth_info_display, + auth_info_visible, + prompt); + + for (i = 0; i < length; i++) + { + g_free (auth_info_default[i]); + g_free (auth_info_display[i]); + } + + g_free (auth_info_default); + g_free (auth_info_display); + g_free (printer_name); + g_free (prompt); + + g_idle_add (check_auth_info, user_data); + + return FALSE; +} + +static gboolean +cups_dispatch_watch_check (GSource *source) +{ + GtkPrintCupsDispatchWatch *dispatch; + GtkCupsPollState poll_state; + gboolean result; + + GTK_NOTE (PRINTING, + g_print ("CUPS Backend: %s \n", G_STRFUNC, source)); + + dispatch = (GtkPrintCupsDispatchWatch *) source; + + poll_state = gtk_cups_request_get_poll_state (dispatch->request); + if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password) if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) return FALSE; - result = gtk_cups_request_read_write (dispatch->request); + result = gtk_cups_request_read_write (dispatch->request, FALSE); if (result && dispatch->data_poll != NULL) { g_source_remove_poll (source, dispatch->data_poll); @@ -875,6 +1192,7 @@ cups_dispatch_watch_prepare (GSource *source, gint *timeout_) { GtkPrintCupsDispatchWatch *dispatch; + gboolean result; dispatch = (GtkPrintCupsDispatchWatch *) source; @@ -882,8 +1200,12 @@ cups_dispatch_watch_prepare (GSource *source, g_print ("CUPS Backend: %s \n", G_STRFUNC, source)); *timeout_ = -1; - - return gtk_cups_request_read_write (dispatch->request); + + result = gtk_cups_request_read_write (dispatch->request, TRUE); + + cups_dispatch_add_poll (source); + + return result; } static gboolean @@ -979,7 +1301,12 @@ cups_dispatch_watch_finalize (GSource *source) dispatch->backend = NULL; } - g_free (dispatch->data_poll); + if (dispatch->data_poll) + { + g_source_remove_poll (source, dispatch->data_poll); + g_free (dispatch->data_poll); + dispatch->data_poll = NULL; + } } static GSourceFuncs _cups_dispatch_watch_funcs = { @@ -1001,20 +1328,33 @@ cups_request_execute (GtkPrintBackendCups *print_backend, dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, sizeof (GtkPrintCupsDispatchWatch)); + g_source_set_name (&dispatch->source, "GTK+ CUPS backend"); GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource)); dispatch->request = request; dispatch->backend = g_object_ref (print_backend); + dispatch->poll_state = GTK_CUPS_HTTP_IDLE; dispatch->data_poll = NULL; + dispatch->callback = NULL; + dispatch->callback_data = NULL; print_backend->requests = g_list_prepend (print_backend->requests, dispatch); g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify); - g_source_attach ((GSource *) dispatch, NULL); - g_source_unref ((GSource *) dispatch); + if (request->need_auth_info) + { + dispatch->callback = callback; + dispatch->callback_data = user_data; + request_auth_info (dispatch); + } + else + { + g_source_attach ((GSource *) dispatch, NULL); + g_source_unref ((GSource *) dispatch); + } } #if 0 @@ -1067,7 +1407,7 @@ cups_request_printer_info_cb (GtkPrintBackendCups *backend, response = gtk_cups_result_get_response (result); /* TODO: determine printer type and use correct icon */ - gtk_printer_set_icon_name (printer, "gtk-print"); + gtk_printer_set_icon_name (printer, "printer"); state_msg = ""; loc = ""; @@ -1283,7 +1623,7 @@ cups_job_info_poll_timeout (gpointer user_data) else cups_request_job_info (data); - return FALSE; + return G_SOURCE_REMOVE; } static void @@ -1333,6 +1673,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, ipp_t *response; gboolean list_has_changed; GList *removed_printer_checklist; + gchar *remote_default_printer = NULL; GDK_THREADS_ENTER (); @@ -1358,6 +1699,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, if (cups_backend->list_printers_poll > 0) g_source_remove (cups_backend->list_printers_poll); cups_backend->list_printers_poll = 0; + cups_backend->list_printers_attempts = 0; } goto done; @@ -1404,7 +1746,6 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, "media-low", "media-empty", "offline", - "connecting-to-device", "other" }; static const char * reasons_descs[] = @@ -1423,14 +1764,17 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, N_("The door is open on printer '%s'."), N_("Printer '%s' is low on paper."), N_("Printer '%s' is out of paper."), - N_("Printer '%s' is currently off-line."), - N_("Printer '%s' may not be connected."), + N_("Printer '%s' is currently offline."), N_("There is a problem on printer '%s'.") }; gboolean is_paused = FALSE; gboolean is_accepting_jobs = TRUE; gboolean default_printer = FALSE; gboolean got_printer_type = FALSE; + gchar *default_cover_before = NULL; + gchar *default_cover_after = NULL; + gboolean remote_printer = FALSE; + gchar **auth_info_required = NULL; /* Skip leading attributes until we hit a printer... */ @@ -1523,22 +1867,17 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, { cups_backend->number_of_covers = attr->num_values; cups_backend->covers = g_new (char *, cups_backend->number_of_covers + 1); - for (i = 0; i < cups_backend->number_of_covers; i++) cups_backend->covers[i] = g_strdup (attr->values[i].string.text); - cups_backend->covers[cups_backend->number_of_covers] = NULL; } } else if (strcmp (attr->name, "job-sheets-default") == 0) { - if ( (cups_backend->default_cover_before == NULL) && (cups_backend->default_cover_after == NULL)) + if (attr->num_values == 2) { - if (attr->num_values == 2) - { - cups_backend->default_cover_before = g_strdup (attr->values[0].string.text); - cups_backend->default_cover_after = g_strdup (attr->values[1].string.text); - } + default_cover_before = attr->values[0].string.text; + default_cover_after = attr->values[1].string.text; } } else if (strcmp (attr->name, "printer-type") == 0) @@ -1548,6 +1887,20 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, default_printer = TRUE; else default_printer = FALSE; + + if (attr->values[0].integer & 0x00000002) + remote_printer = TRUE; + else + remote_printer = FALSE; + } + else if (strcmp (attr->name, "auth-info-required") == 0) + { + if (strcmp (attr->values[0].string.text, "none") != 0) + { + auth_info_required = g_new0 (gchar *, attr->num_values + 1); + for (i = 0; i < attr->num_values; i++) + auth_info_required[i] = g_strdup (attr->values[i].string.text); + } } else { @@ -1571,8 +1924,16 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, { if (default_printer && !cups_backend->got_default_printer) { - cups_backend->got_default_printer = TRUE; - cups_backend->default_printer = g_strdup (printer_name); + if (!remote_printer) + { + cups_backend->got_default_printer = TRUE; + cups_backend->default_printer = g_strdup (printer_name); + } + else + { + if (remote_default_printer == NULL) + remote_default_printer = g_strdup (printer_name); + } } } else @@ -1598,7 +1959,13 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, char *cups_server; /* CUPS server */ list_has_changed = TRUE; - cups_printer = gtk_printer_cups_new (printer_name, backend); +#ifdef HAVE_COLORD + cups_printer = gtk_printer_cups_new (printer_name, + backend, + cups_backend->colord_client); +#else + cups_printer = gtk_printer_cups_new (printer_name, backend, NULL); +#endif cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name); @@ -1656,9 +2023,15 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, g_free (cups_server); + cups_printer->default_cover_before = g_strdup (default_cover_before); + cups_printer->default_cover_after = g_strdup (default_cover_after); + cups_printer->hostname = g_strdup (hostname); cups_printer->port = port; + cups_printer->auth_info_required = g_strdupv (auth_info_required); + g_strfreev (auth_info_required); + printer = GTK_PRINTER (cups_printer); if (cups_backend->default_printer != NULL && @@ -1671,6 +2044,8 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, else g_object_ref (printer); + GTK_PRINTER_CUPS (printer)->remote = remote_printer; + gtk_printer_set_is_paused (printer, is_paused); gtk_printer_set_is_accepting_jobs (printer, is_accepting_jobs); @@ -1759,13 +2134,13 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, /* Set printer icon according to importance (none, report, warning, error - report is omitted). */ if (printer_state_reason_level == 3) - gtk_printer_set_icon_name (printer, "gtk-print-error"); + gtk_printer_set_icon_name (printer, "printer-error"); else if (printer_state_reason_level == 2) - gtk_printer_set_icon_name (printer, "gtk-print-warning"); + gtk_printer_set_icon_name (printer, "printer-warning"); else if (gtk_printer_is_paused (printer)) - gtk_printer_set_icon_name (printer, "gtk-print-paused"); + gtk_printer_set_icon_name (printer, "printer-paused"); else - gtk_printer_set_icon_name (printer, "gtk-print"); + gtk_printer_set_icon_name (printer, "printer"); if (status_changed) g_signal_emit_by_name (GTK_PRINT_BACKEND (backend), @@ -1782,8 +2157,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, as inactive if it is in the list, emitting a printer_removed signal */ if (removed_printer_checklist != NULL) { - g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend); - g_list_free (removed_printer_checklist); + g_list_free_full (removed_printer_checklist, (GDestroyNotify) mark_printer_inactive); list_has_changed = TRUE; } @@ -1793,6 +2167,26 @@ done: gtk_print_backend_set_list_done (backend); + if (!cups_backend->got_default_printer && remote_default_printer != NULL) + { + cups_backend->default_printer = g_strdup (remote_default_printer); + cups_backend->got_default_printer = TRUE; + g_free (remote_default_printer); + + if (cups_backend->default_printer != NULL) + { + GtkPrinter *default_printer = NULL; + default_printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), + cups_backend->default_printer); + if (default_printer != NULL) + { + gtk_printer_set_is_default (default_printer, TRUE); + g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), + "printer-status-changed", default_printer); + } + } + } + GDK_THREADS_LEAVE (); } @@ -1831,17 +2225,33 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) "printer-is-accepting-jobs", "job-sheets-supported", "job-sheets-default", - "printer-type" + "printer-type", + "auth-info-required" }; - if (cups_backend->list_printers_pending) + if (cups_backend->reading_ppds > 0 || cups_backend->list_printers_pending) return TRUE; state = gtk_cups_connection_test_get_state (cups_backend->cups_connection_test); update_backend_status (cups_backend, state); + if (cups_backend->list_printers_attempts == 60) + { + cups_backend->list_printers_attempts = -1; + if (cups_backend->list_printers_poll > 0) + g_source_remove (cups_backend->list_printers_poll); + cups_backend->list_printers_poll = gdk_threads_add_timeout (200, + (GSourceFunc) cups_request_printer_list, + cups_backend); + } + else if (cups_backend->list_printers_attempts != -1) + cups_backend->list_printers_attempts++; + if (state == GTK_CUPS_CONNECTION_IN_PROGRESS || state == GTK_CUPS_CONNECTION_NOT_AVAILABLE) return TRUE; + else + if (cups_backend->list_printers_attempts > 0) + cups_backend->list_printers_attempts = 60; cups_backend->list_printers_pending = TRUE; @@ -1879,9 +2289,9 @@ cups_get_printer_list (GtkPrintBackend *backend) if (cups_backend->list_printers_poll == 0) { if (cups_request_printer_list (cups_backend)) - cups_backend->list_printers_poll = gdk_threads_add_timeout_seconds (3, - (GSourceFunc) cups_request_printer_list, - backend); + cups_backend->list_printers_poll = gdk_threads_add_timeout (50, + (GSourceFunc) cups_request_printer_list, + backend); } } @@ -1907,7 +2317,6 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend, GtkCupsResult *result, GetPPDData *data) { - ipp_t *response; GtkPrinter *printer; GDK_THREADS_ENTER (); @@ -1917,6 +2326,7 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend, printer = GTK_PRINTER (data->printer); GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE; + print_backend->reading_ppds--; if (gtk_cups_result_is_error (result)) { @@ -1935,8 +2345,6 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend, goto done; } - response = gtk_cups_result_get_response (result); - /* let ppdOpenFd take over the ownership of the open file */ g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL); data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io))); @@ -1950,7 +2358,7 @@ done: GDK_THREADS_LEAVE (); } -static void +static gboolean cups_request_ppd (GtkPrinter *printer) { GError *error; @@ -1970,6 +2378,41 @@ cups_request_ppd (GtkPrinter *printer) GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s\n", G_STRFUNC)); + if (cups_printer->remote) + { + GtkCupsConnectionState state; + + state = gtk_cups_connection_test_get_state (cups_printer->remote_cups_connection_test); + + if (state == GTK_CUPS_CONNECTION_IN_PROGRESS) + { + if (cups_printer->get_remote_ppd_attempts == 60) + { + cups_printer->get_remote_ppd_attempts = -1; + if (cups_printer->get_remote_ppd_poll > 0) + g_source_remove (cups_printer->get_remote_ppd_poll); + cups_printer->get_remote_ppd_poll = gdk_threads_add_timeout (200, + (GSourceFunc) cups_request_ppd, + printer); + } + else if (cups_printer->get_remote_ppd_attempts != -1) + cups_printer->get_remote_ppd_attempts++; + + return TRUE; + } + + gtk_cups_connection_test_free (cups_printer->remote_cups_connection_test); + cups_printer->remote_cups_connection_test = NULL; + cups_printer->get_remote_ppd_poll = 0; + cups_printer->get_remote_ppd_attempts = 0; + + if (state == GTK_CUPS_CONNECTION_NOT_AVAILABLE) + { + g_signal_emit_by_name (printer, "details-acquired", FALSE); + return FALSE; + } + } + http = httpConnectEncrypt (cups_printer->hostname, cups_printer->port, cupsEncryption ()); @@ -1982,7 +2425,7 @@ cups_request_ppd (GtkPrinter *printer) #ifdef G_ENABLE_DEBUG /* If we are debugging printing don't delete the tmp files */ - if (!(gtk_debug_flags & GTK_DEBUG_PRINTING)) + if (!(gtk_get_debug_flags () & GTK_DEBUG_PRINTING)) unlink (ppd_filename); #else unlink (ppd_filename); @@ -1999,7 +2442,7 @@ cups_request_ppd (GtkPrinter *printer) g_free (data); g_signal_emit_by_name (printer, "details-acquired", FALSE); - return; + return FALSE; } data->http = http; @@ -2028,6 +2471,7 @@ cups_request_ppd (GtkPrinter *printer) cups_printer->reading_ppd = TRUE; + GTK_PRINT_BACKEND_CUPS (print_backend)->reading_ppds++; cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend), request, @@ -2037,6 +2481,8 @@ cups_request_ppd (GtkPrinter *printer) g_free (resource); g_free (ppd_filename); + + return FALSE; } /* Ordering matters for default preference */ @@ -2209,9 +2655,9 @@ cups_get_default_printer (GtkPrintBackendCups *backend) if (cups_backend->default_printer_poll == 0) { if (cups_request_default_printer (cups_backend)) - cups_backend->default_printer_poll = gdk_threads_add_timeout (500, - (GSourceFunc) cups_request_default_printer, - backend); + cups_backend->default_printer_poll = gdk_threads_add_timeout (200, + (GSourceFunc) cups_request_default_printer, + backend); } } @@ -2334,7 +2780,22 @@ cups_printer_request_details (GtkPrinter *printer) cups_printer = GTK_PRINTER_CUPS (printer); if (!cups_printer->reading_ppd && gtk_printer_cups_get_ppd (cups_printer) == NULL) - cups_request_ppd (printer); + { + if (cups_printer->remote) + { + if (cups_printer->get_remote_ppd_poll == 0) + { + cups_printer->remote_cups_connection_test = gtk_cups_connection_test_new (cups_printer->hostname); + + if (cups_request_ppd (printer)) + cups_printer->get_remote_ppd_poll = gdk_threads_add_timeout (50, + (GSourceFunc) cups_request_ppd, + printer); + } + } + else + cups_request_ppd (printer); + } } static char * @@ -2451,13 +2912,23 @@ static const struct { static const struct { const char *ppd_keyword; const char *name; -} option_names[] = { +} ppd_option_names[] = { {"Duplex", "gtk-duplex" }, {"MediaType", "gtk-paper-type"}, {"InputSlot", "gtk-paper-source"}, {"OutputBin", "gtk-output-tray"}, }; +static const struct { + const char *lpoption; + const char *name; +} lpoption_names[] = { + {"number-up", "gtk-n-up" }, + {"number-up-layout", "gtk-n-up-layout"}, + {"job-billing", "gtk-billing-info"}, + {"job-priority", "gtk-job-prio"}, +}; + /* keep sorted when changing */ static const char *color_option_whitelist[] = { "BRColorEnhancement", @@ -2922,7 +3393,18 @@ create_pickone_option (ppd_file_t *ppd_file, option->choices_display[i] = get_choice_text (ppd_file, available[i]); } } - gtk_printer_option_set (option, ppd_option->defchoice); + + if (option->type != GTK_PRINTER_OPTION_TYPE_PICKONE) + { + if (g_str_has_prefix (ppd_option->defchoice, "Custom.")) + gtk_printer_option_set (option, ppd_option->defchoice + 7); + else + gtk_printer_option_set (option, ppd_option->defchoice); + } + else + { + gtk_printer_option_set (option, ppd_option->defchoice); + } } #ifdef PRINT_IGNORED_OPTIONS else @@ -2973,17 +3455,33 @@ create_boolean_option (ppd_file_t *ppd_file, } static gchar * -get_option_name (const gchar *keyword) +get_ppd_option_name (const gchar *keyword) { int i; - for (i = 0; i < G_N_ELEMENTS (option_names); i++) - if (strcmp (option_names[i].ppd_keyword, keyword) == 0) - return g_strdup (option_names[i].name); + for (i = 0; i < G_N_ELEMENTS (ppd_option_names); i++) + if (strcmp (ppd_option_names[i].ppd_keyword, keyword) == 0) + return g_strdup (ppd_option_names[i].name); return g_strdup_printf ("cups-%s", keyword); } +static gchar * +get_lpoption_name (const gchar *lpoption) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (ppd_option_names); i++) + if (strcmp (ppd_option_names[i].ppd_keyword, lpoption) == 0) + return g_strdup (ppd_option_names[i].name); + + for (i = 0; i < G_N_ELEMENTS (lpoption_names); i++) + if (strcmp (lpoption_names[i].lpoption, lpoption) == 0) + return g_strdup (lpoption_names[i].name); + + return g_strdup_printf ("cups-%s", lpoption); +} + static int strptr_cmp (const void *a, const void *b) @@ -3018,7 +3516,7 @@ handle_option (GtkPrinterOptionSet *set, if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist)) return; - name = get_option_name (ppd_option->keyword); + name = get_ppd_option_name (ppd_option->keyword); option = NULL; if (ppd_option->ui == PPD_UI_PICKONE) @@ -3106,6 +3604,23 @@ handle_group (GtkPrinterOptionSet *set, } +#ifdef HAVE_COLORD + +typedef struct { + GtkPrintSettings *settings; + GtkPrinter *printer; +} GtkPrintBackendCupsColordHelper; + +static void +colord_printer_option_set_changed_cb (GtkPrinterOptionSet *set, + GtkPrintBackendCupsColordHelper *helper) +{ + gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (helper->printer), + helper->settings, + set); +} +#endif + static GtkPrinterOptionSet * cups_printer_get_options (GtkPrinter *printer, GtkPrintSettings *settings, @@ -3136,7 +3651,10 @@ cups_printer_get_options (GtkPrinter *printer, cups_option_t *opts = NULL; GtkPrintBackendCups *backend; GtkTextDirection text_direction; - + GtkPrinterCups *cups_printer = NULL; +#ifdef HAVE_COLORD + GtkPrintBackendCupsColordHelper *helper; +#endif set = gtk_printer_option_set_new (); @@ -3200,8 +3718,9 @@ cups_printer_get_options (GtkPrinter *printer, g_object_unref (option); backend = GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)); + cups_printer = GTK_PRINTER_CUPS (printer); - if (backend != NULL) + if (backend != NULL && printer != NULL) { char *cover_default[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" }; /* Translators, these strings are names for various 'standard' cover @@ -3246,8 +3765,8 @@ cups_printer_get_options (GtkPrinter *printer, gtk_printer_option_choices_from_array (option, num_of_covers, cover, cover_display_translated); - if (backend->default_cover_before != NULL) - gtk_printer_option_set (option, backend->default_cover_before); + if (cups_printer->default_cover_before != NULL) + gtk_printer_option_set (option, cups_printer->default_cover_before); else gtk_printer_option_set (option, "none"); set_option_from_settings (option, settings); @@ -3260,8 +3779,8 @@ cups_printer_get_options (GtkPrinter *printer, option = gtk_printer_option_new ("gtk-cover-after", _("After"), GTK_PRINTER_OPTION_TYPE_PICKONE); gtk_printer_option_choices_from_array (option, num_of_covers, cover, cover_display_translated); - if (backend->default_cover_after != NULL) - gtk_printer_option_set (option, backend->default_cover_after); + if (cups_printer->default_cover_after != NULL) + gtk_printer_option_set (option, cups_printer->default_cover_after); else gtk_printer_option_set (option, "none"); set_option_from_settings (option, settings); @@ -3340,15 +3859,99 @@ cups_printer_get_options (GtkPrinter *printer, if (STRING_IN_TABLE (opts[i].name, cups_option_blacklist)) continue; - name = get_option_name (opts[i].name); - option = gtk_printer_option_set_lookup (set, name); - if (option) - gtk_printer_option_set (option, opts[i].value); + name = get_lpoption_name (opts[i].name); + if (strcmp (name, "cups-job-sheets") == 0) + { + gchar **values; + gint num_values; + + values = g_strsplit (opts[i].value, ",", 2); + num_values = g_strv_length (values); + + option = gtk_printer_option_set_lookup (set, "gtk-cover-before"); + if (option && num_values > 0) + gtk_printer_option_set (option, g_strstrip (values[0])); + + option = gtk_printer_option_set_lookup (set, "gtk-cover-after"); + if (option && num_values > 1) + gtk_printer_option_set (option, g_strstrip (values[1])); + + g_strfreev (values); + } + else if (strcmp (name, "cups-job-hold-until") == 0) + { + GtkPrinterOption *option2 = NULL; + + option = gtk_printer_option_set_lookup (set, "gtk-print-time-text"); + if (option && opts[i].value) + { + option2 = gtk_printer_option_set_lookup (set, "gtk-print-time"); + if (option2) + { + if (strcmp (opts[i].value, "indefinite") == 0) + gtk_printer_option_set (option2, "on-hold"); + else + { + gtk_printer_option_set (option2, "at"); + gtk_printer_option_set (option, opts[i].value); + } + } + } + } + else if (strcmp (name, "cups-sides") == 0) + { + option = gtk_printer_option_set_lookup (set, "gtk-duplex"); + if (option && opts[i].value) + { + if (strcmp (opts[i].value, "two-sided-short-edge") == 0) + gtk_printer_option_set (option, "DuplexTumble"); + else if (strcmp (opts[i].value, "two-sided-long-edge") == 0) + gtk_printer_option_set (option, "DuplexNoTumble"); + } + } + else + { + option = gtk_printer_option_set_lookup (set, name); + if (option) + gtk_printer_option_set (option, opts[i].value); + } g_free (name); } cupsFreeOptions (num_opts, opts); +#ifdef HAVE_COLORD + /* TRANSLATORS: this this the ICC color profile to use for this job */ + option = gtk_printer_option_new ("colord-profile", + _("Printer Profile"), + GTK_PRINTER_OPTION_TYPE_INFO); + + /* assign it to the color page */ + option->group = g_strdup ("ColorPage"); + + /* TRANSLATORS: this is when color profile information is unavailable */ + gtk_printer_option_set (option, _("Unavailable")); + gtk_printer_option_set_add (set, option); + + /* watch to see if the user changed the options */ + helper = g_new (GtkPrintBackendCupsColordHelper, 1); + helper->printer = printer; + helper->settings = settings; + g_signal_connect_data (set, "changed", + G_CALLBACK (colord_printer_option_set_changed_cb), + helper, + (GClosureNotify) g_free, + 0); + + /* initial coldplug */ + gtk_printer_cups_update_settings (GTK_PRINTER_CUPS (printer), + settings, set); + g_object_bind_property (printer, "profile-title", + option, "value", + G_BINDING_DEFAULT); + +#endif + return set; } @@ -3359,7 +3962,7 @@ mark_option_from_set (GtkPrinterOptionSet *set, ppd_option_t *ppd_option) { GtkPrinterOption *option; - char *name = get_option_name (ppd_option->keyword); + char *name = get_ppd_option_name (ppd_option->keyword); option = gtk_printer_option_set_lookup (set, name); @@ -3394,7 +3997,7 @@ set_conflicts_from_option (GtkPrinterOptionSet *set, if (ppd_option->conflicted) { - name = get_option_name (ppd_option->keyword); + name = get_ppd_option_name (ppd_option->keyword); option = gtk_printer_option_set_lookup (set, name); if (option) @@ -3632,23 +4235,29 @@ set_option_from_settings (GtkPrinterOption *option, gtk_printer_option_set (option, cups_value); else { - int res = gtk_print_settings_get_resolution (settings); - int res_x = gtk_print_settings_get_resolution_x (settings); - int res_y = gtk_print_settings_get_resolution_y (settings); + if (gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION, -1) != -1 || + gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_X, -1) != -1 || + gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_Y, -1) != -1 || + option->value == NULL || option->value[0] == '\0') + { + int res = gtk_print_settings_get_resolution (settings); + int res_x = gtk_print_settings_get_resolution_x (settings); + int res_y = gtk_print_settings_get_resolution_y (settings); - if (res_x != res_y) - { - value = g_strdup_printf ("%dx%ddpi", res_x, res_y); - gtk_printer_option_set (option, value); - g_free (value); + if (res_x != res_y) + { + value = g_strdup_printf ("%dx%ddpi", res_x, res_y); + gtk_printer_option_set (option, value); + g_free (value); + } + else if (res != 0) + { + value = g_strdup_printf ("%ddpi", res); + gtk_printer_option_set (option, value); + g_free (value); + } } - else if (res != 0) - { - value = g_strdup_printf ("%ddpi", res); - gtk_printer_option_set (option, value); - g_free (value); - } - } + } } else if (strcmp (option->name, "gtk-paper-type") == 0) map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map), @@ -3735,12 +4344,12 @@ foreach_option_get_settings (GtkPrinterOption *option, if (sscanf (value, "%dx%ddpi", &res_x, &res_y) == 2) { - if (res_x != 0 && res_y != 0) + if (res_x > 0 && res_y > 0) gtk_print_settings_set_resolution_xy (settings, res_x, res_y); } else if (sscanf (value, "%ddpi", &res) == 1) { - if (res != 0) + if (res > 0) gtk_print_settings_set_resolution (settings, res); } @@ -3908,44 +4517,49 @@ cups_printer_prepare_for_print (GtkPrinter *printer, GtkPrintSettings *settings, GtkPageSetup *page_setup) { + GtkPrintPages pages; + GtkPageRange *ranges; + gint n_ranges; GtkPageSet page_set; GtkPaperSize *paper_size; const char *ppd_paper_name; double scale; - print_job->print_pages = gtk_print_settings_get_print_pages (settings); - print_job->page_ranges = NULL; - print_job->num_page_ranges = 0; - - if (print_job->print_pages == GTK_PRINT_PAGES_RANGES) - print_job->page_ranges = - gtk_print_settings_get_page_ranges (settings, - &print_job->num_page_ranges); - + pages = gtk_print_settings_get_print_pages (settings); + gtk_print_job_set_pages (print_job, pages); + + if (pages == GTK_PRINT_PAGES_RANGES) + ranges = gtk_print_settings_get_page_ranges (settings, &n_ranges); + else + { + ranges = NULL; + n_ranges = 0; + } + + gtk_print_job_set_page_ranges (print_job, ranges, n_ranges); if (gtk_print_settings_get_collate (settings)) gtk_print_settings_set (settings, "cups-Collate", "True"); - print_job->collate = FALSE; + gtk_print_job_set_collate (print_job, FALSE); if (gtk_print_settings_get_reverse (settings)) gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse"); - print_job->reverse = FALSE; + gtk_print_job_set_reverse (print_job, FALSE); if (gtk_print_settings_get_n_copies (settings) > 1) gtk_print_settings_set_int (settings, "cups-copies", - gtk_print_settings_get_n_copies (settings)); - print_job->num_copies = 1; + gtk_print_settings_get_n_copies (settings)); + gtk_print_job_set_num_copies (print_job, 1); scale = gtk_print_settings_get_scale (settings); - print_job->scale = 1.0; if (scale != 100.0) - print_job->scale = scale/100.0; + gtk_print_job_set_scale (print_job, scale / 100.0); page_set = gtk_print_settings_get_page_set (settings); if (page_set == GTK_PAGE_SET_EVEN) gtk_print_settings_set (settings, "cups-page-set", "even"); else if (page_set == GTK_PAGE_SET_ODD) gtk_print_settings_set (settings, "cups-page-set", "odd"); - print_job->page_set = GTK_PAGE_SET_ALL; + gtk_print_job_set_page_set (print_job, GTK_PAGE_SET_ALL); paper_size = gtk_page_setup_get_paper_size (page_setup); ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size); @@ -3964,7 +4578,40 @@ cups_printer_prepare_for_print (GtkPrinter *printer, g_free (custom_name); } - print_job->rotate_to_orientation = TRUE; + if (gtk_print_settings_get_number_up (settings) > 1) + { + GtkNumberUpLayout layout = gtk_print_settings_get_number_up_layout (settings); + GEnumClass *enum_class; + GEnumValue *enum_value; + + switch (gtk_page_setup_get_orientation (page_setup)) + { + case GTK_PAGE_ORIENTATION_PORTRAIT: + break; + case GTK_PAGE_ORIENTATION_LANDSCAPE: + if (layout < 4) + layout = layout + 2 + 4 * (1 - layout / 2); + else + layout = layout - 3 - 2 * (layout % 2); + break; + case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: + layout = (layout + 3 - 2 * (layout % 2)) % 4 + 4 * (layout / 4); + break; + case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: + if (layout < 4) + layout = layout + 5 - 2 * (layout % 2); + else + layout = layout - 6 + 4 * (1 - (layout - 4) / 2); + break; + } + + enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT); + enum_value = g_enum_get_value (enum_class, layout); + gtk_print_settings_set (settings, "cups-number-up-layout", enum_value->value_nick); + g_type_class_unref (enum_class); + } + + gtk_print_job_set_rotate (print_job, TRUE); } static GtkPageSetup * @@ -4047,12 +4694,17 @@ cups_printer_get_default_page_size (GtkPrinter *printer) return NULL; option = ppdFindOption (ppd_file, "PageSize"); + if (option == NULL) + return NULL; + size = ppdPageSize (ppd_file, option->defchoice); + if (size == NULL) + return NULL; return create_page_setup (ppd_file, size); } -static void +static gboolean cups_printer_get_hard_margins (GtkPrinter *printer, gdouble *top, gdouble *bottom, @@ -4063,12 +4715,14 @@ cups_printer_get_hard_margins (GtkPrinter *printer, ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer)); if (ppd_file == NULL) - return; + return FALSE; *left = ppd_file->custom_margins[0]; *bottom = ppd_file->custom_margins[1]; *right = ppd_file->custom_margins[2]; *top = ppd_file->custom_margins[3]; + + return TRUE; } static GtkPrintCapabilities