From: Marek Kasik Date: Mon, 4 Mar 2013 13:29:24 +0000 (+0100) Subject: printing: List Avahi printers X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=eed9e72e831e54f4a405474316835685f3a61e79;hp=bfb327deda4983adb3f2d317d4b763e59e5f109e;p=~andy%2Fgtk printing: List Avahi printers Show printers advertised by avahi on local network. CUPS backend now looks for _ipps._tcp and _ipp._tcp services offered by avahi. If it finds such a service (printer) it requests its attributes through IPP_GET_PRINTER_ATTRIBUTES ipp request and adds it to the list of printers. Such printer behaves like a remote printer then. If an avahi printer is a default printer then it is considered default by the backend only if there is no local or remote default printer. This functionality is enabled when building Gtk+ with CUPS 1.6 or later because it replaces browsing protocol removed in CUPS 1.6. https://bugzilla.gnome.org/show_bug.cgi?id=688956 --- diff --git a/configure.ac b/configure.ac index 8d74b190e..31c41be58 100644 --- a/configure.ac +++ b/configure.ac @@ -1421,7 +1421,7 @@ else $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 6; then AC_DEFINE(HAVE_CUPS_API_1_6, 1, [Define to 1 if CUPS 1.6 API is available]) - + have_cups_api_1_6=yes fi AC_SUBST(CUPS_API_MAJOR) @@ -1452,6 +1452,45 @@ else fi fi +# Check for Avahi flags +AC_ARG_ENABLE(avahi-browsing, + [AS_HELP_STRING([--disable-avahi-browsing], + [disable avahi browsing of printers])],, + [enable_avahi_browsing=auto]) + +have_avahi_browsing=no +if test "x$enable_avahi_browsing" != "xno" -a \ + "x$have_cups_api_1_6" = "xyes"; then + AC_MSG_CHECKING([avahi-gobject]) + + if $PKG_CONFIG --exists avahi-gobject ; then + AVAHI_CFLAGS=`$PKG_CONFIG --cflags avahi-gobject` + AC_SUBST(AVAHI_CFLAGS) + AVAHI_LIBS=`$PKG_CONFIG --libs avahi-gobject` + AC_SUBST(AVAHI_LIBS) + have_avahi_gobject=yes + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + if test "x$have_avahi_gobject" = "xyes" ; then + AC_DEFINE([HAVE_AVAHI_BROWSING], [1], [Define to 1 if avahi-gobject available]) + have_avahi_browsing=yes + else + AC_MSG_ERROR([ +*** avahi-gobject not found. avahi-gobject is required to build GTK+ with support +*** for avahi browsed printers when using CUPS 1.6. +]) + fi +else + if test "x$enable_avahi_browsing" = "xyes"; then + AC_MSG_ERROR([ +*** Avahi browsing support requested but CUPS 1.6 not found. +]) + fi +fi + # Checks to see if we should compile with PAPI backend for GTK+ # @@ -1828,6 +1867,7 @@ echo " Dynamic modules: $build_dynamic_modules" echo " Included immodules: $included_immodules" echo " PackageKit support: $build_packagekit" echo " colord support: $have_colord" +echo " Avahi browsing: $have_avahi_browsing" echo " Introspection: $found_introspection" echo " Debugging: $enable_debug" echo " Documentation: $enable_gtk_doc" diff --git a/modules/printbackends/cups/Makefile.am b/modules/printbackends/cups/Makefile.am index e9d4c2fdd..2e5b92791 100644 --- a/modules/printbackends/cups/Makefile.am +++ b/modules/printbackends/cups/Makefile.am @@ -12,6 +12,7 @@ AM_CPPFLAGS = \ -I$(top_builddir)/gdk \ $(CUPS_CFLAGS) \ $(COLORD_CFLAGS) \ + $(AVAHI_CFLAGS) \ -DGTK_COMPILATION \ -DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED \ $(GTK_DEP_CFLAGS) \ @@ -37,6 +38,6 @@ noinst_HEADERS = \ gtkcupsutils.h libprintbackend_cups_la_LDFLAGS = -avoid-version -module $(no_undefined) -libprintbackend_cups_la_LIBADD = $(LDADDS) $(CUPS_LIBS) +libprintbackend_cups_la_LIBADD = $(LDADDS) $(CUPS_LIBS) $(AVAHI_LIBS) -include $(top_srcdir)/git.mk diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c index 15132a826..f0bb951b5 100644 --- a/modules/printbackends/cups/gtkcupsutils.c +++ b/modules/printbackends/cups/gtkcupsutils.c @@ -87,6 +87,20 @@ static GtkCupsRequestStateFunc get_states[] = { #define ippSetState(ipp_request, ipp_state) ipp_request->state = ipp_state #define ippGetString(attr, index, foo) attr->values[index].string.text #define ippGetCount(attr) attr->num_values + +int +ippSetVersion (ipp_t *ipp, + int major, + int minor) +{ + if (!ipp || major < 0 || minor < 0) + return 0; + + ipp->request.any.version[0] = major; + ipp->request.any.version[1] = minor; + + return 1; +} #endif static void @@ -656,6 +670,13 @@ gtk_cups_request_encode_option (GtkCupsRequest *request, } } +void +gtk_cups_request_set_ipp_version (GtkCupsRequest *request, + gint major, + gint minor) +{ + ippSetVersion (request->ipp_request, major, minor); +} static void _connect (GtkCupsRequest *request) diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h index e49a5d3bc..55186f590 100644 --- a/modules/printbackends/cups/gtkcupsutils.h +++ b/modules/printbackends/cups/gtkcupsutils.h @@ -178,6 +178,9 @@ gboolean gtk_cups_request_is_done (GtkCupsRequest * void gtk_cups_request_encode_option (GtkCupsRequest *request, const gchar *option, const gchar *value); +void gtk_cups_request_set_ipp_version (GtkCupsRequest *request, + gint major, + gint minor); gboolean gtk_cups_result_is_error (GtkCupsResult *result); ipp_t * gtk_cups_result_get_response (GtkCupsResult *result); GtkCupsErrorType gtk_cups_result_get_error_type (GtkCupsResult *result); diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index 96f4be410..ffecd18a1 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -53,6 +53,12 @@ #include #include #include +#ifdef HAVE_AVAHI_BROWSING +#include +#include +#include +#include +#endif #include "gtkprintbackendcups.h" #include "gtkprintercups.h" @@ -137,6 +143,13 @@ struct _GtkPrintBackendCups #ifdef HAVE_COLORD CdClient *colord_client; #endif +#ifdef HAVE_AVAHI_BROWSING + gchar *avahi_default_printer; + GList *avahi_resolvers; + GaServiceBrowser *avahi_ipp_browser; + GaServiceBrowser *avahi_ipps_browser; + GaClient *avahi_client; +#endif }; static GObjectClass *backend_parent_class; @@ -203,6 +216,11 @@ void overwrite_and_free (gpointer static gboolean is_address_local (const gchar *address); static gboolean request_auth_info (gpointer data); +#ifdef HAVE_AVAHI_BROWSING +static void avahi_data_free (GtkPrintBackendCups *cups_backend); +static void avahi_request_printer_list (GtkPrintBackendCups *cups_backend); +#endif + static void gtk_print_backend_cups_register_type (GTypeModule *module) { @@ -261,6 +279,15 @@ pb_module_create (void) #define ippGetName(attr) attr->name #define ippGetCount(attr) attr->num_values #define ippGetGroupTag(attr) attr->group_tag + +static int +ippGetRange (ipp_attribute_t *attr, + int element, + int *upper) +{ + *upper = attr->values[element].range.upper; + return (attr->values[element].range.lower); +} #endif /* * GtkPrintBackendCups @@ -584,7 +611,7 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, GtkPrinterCups *cups_printer; CupsPrintStreamData *ps; CupsOptionsData *options_data; - GtkCupsRequest *request; + GtkCupsRequest *request = NULL; GtkPrintSettings *settings; const gchar *title; char printer_absolute_uri[HTTP_MAX_URI]; @@ -595,23 +622,74 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job)); settings = gtk_print_job_get_settings (job); - request = gtk_cups_request_new_with_username (NULL, - GTK_CUPS_POST, - IPP_PRINT_JOB, - data_io, - NULL, - cups_printer->device_uri, - GTK_PRINT_BACKEND_CUPS (print_backend)->username); +#ifdef HAVE_AVAHI_BROWSING + if (cups_printer->avahi_browsed) + { + http_t *http; + + http = httpConnect (cups_printer->hostname, cups_printer->port); + if (http) + { + request = gtk_cups_request_new_with_username (http, + GTK_CUPS_POST, + IPP_PRINT_JOB, + data_io, + cups_printer->hostname, + cups_printer->device_uri, + GTK_PRINT_BACKEND_CUPS (print_backend)->username); + g_snprintf (printer_absolute_uri, HTTP_MAX_URI, cups_printer->printer_uri); + } + else + { + GError *error = NULL; + + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error connecting to %s:%d", + cups_printer->hostname, + cups_printer->port)); + + error = g_error_new (gtk_print_error_quark (), + GTK_CUPS_ERROR_GENERAL, + "Error connecting to %s", + cups_printer->hostname); + + gtk_print_job_set_status (job, GTK_PRINT_STATUS_FINISHED_ABORTED); + + if (callback) + { + callback (job, user_data, error); + } + + g_clear_error (&error); + + return; + } + } + else +#endif + { + request = gtk_cups_request_new_with_username (NULL, + GTK_CUPS_POST, + IPP_PRINT_JOB, + data_io, + NULL, + cups_printer->device_uri, + GTK_PRINT_BACKEND_CUPS (print_backend)->username); + + httpAssembleURIf (HTTP_URI_CODING_ALL, + printer_absolute_uri, + sizeof (printer_absolute_uri), + "ipp", + NULL, + "localhost", + ippPort (), + "/printers/%s", + gtk_printer_get_name (gtk_print_job_get_printer (job))); + } - httpAssembleURIf (HTTP_URI_CODING_ALL, - printer_absolute_uri, - sizeof (printer_absolute_uri), - "ipp", - NULL, - "localhost", - ippPort (), - "/printers/%s", - gtk_printer_get_name (gtk_print_job_get_printer (job))); + gtk_cups_request_set_ipp_version (request, + cups_printer->ipp_version_major, + cups_printer->ipp_version_minor); gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", @@ -681,6 +759,14 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->colord_client = cd_client_new (); #endif +#ifdef HAVE_AVAHI_BROWSING + backend_cups->avahi_default_printer = NULL; + backend_cups->avahi_resolvers = NULL; + backend_cups->avahi_ipp_browser = NULL; + backend_cups->avahi_ipps_browser = NULL; + backend_cups->avahi_client = NULL; +#endif + cups_get_local_default_printer (backend_cups); } @@ -711,6 +797,10 @@ gtk_print_backend_cups_finalize (GObject *object) g_object_unref (backend_cups->colord_client); #endif +#ifdef HAVE_AVAHI_BROWSING + avahi_data_free (backend_cups); +#endif + backend_parent_class->finalize (object); } @@ -1681,6 +1771,30 @@ static const char * printer_strings[] = N_("There is a problem on printer '%s'.") }; +/* Attributes we're interested in for printers */ +static const char * const printer_attrs[] = + { + "printer-name", + "printer-uri-supported", + "member-uris", + "printer-location", + "printer-info", + "printer-state-message", + "printer-state-reasons", + "printer-state", + "queued-job-count", + "printer-is-accepting-jobs", + "job-sheets-supported", + "job-sheets-default", + "printer-type", + "auth-info-required", + "number-up-default", + "ipp-versions-supported", + "multiple-document-handling-supported", + "copies-supported", + "number-up-supported" + }; + typedef enum { GTK_PRINTER_STATE_LEVEL_NONE = 0, @@ -1708,10 +1822,88 @@ typedef struct gboolean default_printer; gboolean got_printer_type; gboolean remote_printer; +#ifdef HAVE_AVAHI_BROWSING + gboolean avahi_printer; +#endif gchar **auth_info_required; gint default_number_up; + guchar ipp_version_major; + guchar ipp_version_minor; + gboolean supports_copies; + gboolean supports_collate; + gboolean supports_number_up; } PrinterSetupInfo; +static void +get_ipp_version (const char *ipp_version_string, + guchar *ipp_version_major, + guchar *ipp_version_minor) +{ + gchar **ipp_version_strv; + gchar *endptr; + + *ipp_version_major = 1; + *ipp_version_minor = 1; + + if (ipp_version_string) + { + ipp_version_strv = g_strsplit (ipp_version_string, ".", 0); + + if (ipp_version_strv) + { + if (g_strv_length (ipp_version_strv) == 2) + { + *ipp_version_major = (guchar) g_ascii_strtoull (ipp_version_strv[0], &endptr, 10); + if (endptr == ipp_version_strv[0]) + *ipp_version_major = 1; + + *ipp_version_minor = (guchar) g_ascii_strtoull (ipp_version_strv[1], &endptr, 10); + if (endptr == ipp_version_strv[1]) + *ipp_version_minor = 1; + } + + g_strfreev (ipp_version_strv); + } + } +} + +static void +get_server_ipp_version (guchar *ipp_version_major, + guchar *ipp_version_minor) +{ + *ipp_version_major = 1; + *ipp_version_minor = 1; + + if (IPP_VERSION && strlen (IPP_VERSION) == 2) + { + *ipp_version_major = (unsigned char) IPP_VERSION[0]; + *ipp_version_minor = (unsigned char) IPP_VERSION[1]; + } +} + +static gint +ipp_version_cmp (guchar ipp_version_major1, + guchar ipp_version_minor1, + guchar ipp_version_major2, + guchar ipp_version_minor2) +{ + if (ipp_version_major1 == ipp_version_major2 && + ipp_version_minor1 == ipp_version_minor2) + { + return 0; + } + else if (ipp_version_major1 < ipp_version_major2 || + (ipp_version_major1 == ipp_version_major2 && + ipp_version_minor1 < ipp_version_minor2)) + { + return -1; + } + else + { + return 1; + } +} + static void cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend, ipp_attribute_t *attr, @@ -1839,6 +2031,63 @@ cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend, { info->default_number_up = ippGetInteger (attr, 0); } + else if (g_strcmp0 (ippGetName (attr), "ipp-versions-supported") == 0) + { + guchar server_ipp_version_major; + guchar server_ipp_version_minor; + guchar ipp_version_major; + guchar ipp_version_minor; + + get_server_ipp_version (&server_ipp_version_major, + &server_ipp_version_minor); + + for (i = 0; i < ippGetCount (attr); i++) + { + get_ipp_version (ippGetString (attr, i, NULL), + &ipp_version_major, + &ipp_version_minor); + + if (ipp_version_cmp (ipp_version_major, + ipp_version_minor, + info->ipp_version_major, + info->ipp_version_minor) > 0 && + ipp_version_cmp (ipp_version_major, + ipp_version_minor, + server_ipp_version_major, + server_ipp_version_minor) <= 0) + { + info->ipp_version_major = ipp_version_major; + info->ipp_version_minor = ipp_version_minor; + } + } + } + else if (g_strcmp0 (ippGetName (attr), "number-up-supported") == 0) + { + if (ippGetCount (attr) == 6) + { + info->supports_number_up = TRUE; + } + } + else if (g_strcmp0 (ippGetName (attr), "copies-supported") == 0) + { + int upper = 1; + + ippGetRange (attr, 0, &upper); + if (upper > 1) + { + info->supports_copies = TRUE; + } + } + else if (g_strcmp0 (ippGetName (attr), "multiple-document-handling-supported") == 0) + { + for (i = 0; i < ippGetCount (attr); i++) + { + if (g_strcmp0 (ippGetString (attr, i, NULL), "separate-documents-collated-copies") == 0) + { + info->supports_collate = TRUE; + } + } + } else { GTK_NOTE (PRINTING, @@ -1862,9 +2111,16 @@ cups_create_printer (GtkPrintBackendCups *cups_backend, char *cups_server; /* CUPS server */ #ifdef HAVE_COLORD - cups_printer = gtk_printer_cups_new (info->printer_name, - backend, - cups_backend->colord_client); +#ifdef HAVE_AVAHI_BROWSING + if (info->avahi_printer) + cups_printer = gtk_printer_cups_new (info->printer_name, + backend, + NULL); + else +#endif + cups_printer = gtk_printer_cups_new (info->printer_name, + backend, + cups_backend->colord_client); #else cups_printer = gtk_printer_cups_new (info->printer_name, backend, NULL); #endif @@ -1921,7 +2177,8 @@ cups_create_printer (GtkPrintBackendCups *cups_backend, cups_printer->default_cover_before = g_strdup (info->default_cover_before); cups_printer->default_cover_after = g_strdup (info->default_cover_after); - cups_printer->default_number_up = info->default_number_up; + if (info->default_number_up > 0) + cups_printer->default_number_up = info->default_number_up; cups_printer->hostname = g_strdup (hostname); cups_printer->port = port; @@ -1935,11 +2192,592 @@ cups_create_printer (GtkPrintBackendCups *cups_backend, strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0) gtk_printer_set_is_default (printer, TRUE); +#ifdef HAVE_AVAHI_BROWSING + cups_printer->avahi_browsed = info->avahi_printer; +#endif gtk_print_backend_add_printer (backend, printer); return printer; } +static void +set_printer_icon_name_from_info (GtkPrinter *printer, + PrinterSetupInfo *info) +{ + /* Set printer icon according to importance + (none, report, warning, error - report is omitted). */ + if (info->reason_level == GTK_PRINTER_STATE_LEVEL_ERROR) + gtk_printer_set_icon_name (printer, "printer-error"); + else if (info->reason_level == GTK_PRINTER_STATE_LEVEL_WARNING) + gtk_printer_set_icon_name (printer, "printer-warning"); + else if (gtk_printer_is_paused (printer)) + gtk_printer_set_icon_name (printer, "printer-paused"); + else + gtk_printer_set_icon_name (printer, "printer"); +} + +static void +set_info_state_message (PrinterSetupInfo *info) +{ + gint i; + + if (info->state_msg && strlen (info->state_msg) == 0) + { + gchar *tmp_msg2 = NULL; + if (info->is_paused && !info->is_accepting_jobs) + /* Translators: this is a printer status. */ + tmp_msg2 = g_strdup ( N_("Paused ; Rejecting Jobs")); + if (info->is_paused && info->is_accepting_jobs) + /* Translators: this is a printer status. */ + tmp_msg2 = g_strdup ( N_("Paused")); + if (!info->is_paused && !info->is_accepting_jobs) + /* Translators: this is a printer status. */ + tmp_msg2 = g_strdup ( N_("Rejecting Jobs")); + + if (tmp_msg2 != NULL) + { + g_free (info->state_msg); + info->state_msg = tmp_msg2; + } + } + + /* Set description of the reason and combine it with printer-state-message. */ + if (info->reason_msg) + { + gchar *reason_msg_desc = NULL; + gboolean found = FALSE; + + for (i = 0; i < G_N_ELEMENTS (printer_messages); i++) + { + if (strncmp (info->reason_msg, printer_messages[i], + strlen (printer_messages[i])) == 0) + { + reason_msg_desc = g_strdup_printf (printer_strings[i], + info->printer_name); + found = TRUE; + break; + } + } + + if (!found) + info->reason_level = GTK_PRINTER_STATE_LEVEL_NONE; + + if (info->reason_level >= GTK_PRINTER_STATE_LEVEL_WARNING) + { + if (strlen (info->state_msg) == 0) + { + g_free (info->state_msg); + info->state_msg = reason_msg_desc; + reason_msg_desc = NULL; + } + else + { + gchar *tmp_msg = NULL; + tmp_msg = g_strjoin (" ; ", info->state_msg, + reason_msg_desc, NULL); + g_free (info->state_msg); + info->state_msg = tmp_msg; + } + } + + g_free (reason_msg_desc); + } +} + +static void +set_default_printer (GtkPrintBackendCups *cups_backend, + const gchar *default_printer_name) +{ + cups_backend->default_printer = g_strdup (default_printer_name); + cups_backend->got_default_printer = TRUE; + + 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); + } + } +} + +#ifdef HAVE_AVAHI_BROWSING +typedef struct +{ + gchar *name; + gchar *type; + gchar *domain; + gchar *host; + gint port; +} AvahiService; + +void +avahi_service_free (AvahiService *service) +{ + if (service) + { + g_free (service->name); + g_free (service->type); + g_free (service->domain); + g_free (service->host); + g_free (service); + } +} + +static void +avahi_data_free (GtkPrintBackendCups *cups_backend) +{ + if (cups_backend) + { + g_clear_pointer (&cups_backend->avahi_default_printer, g_free); + g_list_free_full (cups_backend->avahi_resolvers, g_object_unref); + cups_backend->avahi_resolvers = NULL; + g_clear_object (&cups_backend->avahi_ipp_browser); + g_clear_object (&cups_backend->avahi_ipps_browser); + g_clear_object (&cups_backend->avahi_client); + } +} + +static void +cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend, + GtkCupsResult *result, + gpointer user_data) +{ + PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo); + GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend); + ipp_attribute_t *attr; + AvahiService *service = (AvahiService *) user_data; + GtkPrinter *printer; + gboolean list_has_changed = FALSE; + gboolean status_changed = FALSE; + ipp_t *response; + + gdk_threads_enter (); + + GTK_NOTE (PRINTING, + g_print ("CUPS Backend: %s\n", G_STRFUNC)); + + if (gtk_cups_result_is_error (result)) + { + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error getting printer info: %s %d %d", + gtk_cups_result_get_error_string (result), + gtk_cups_result_get_error_type (result), + gtk_cups_result_get_error_code (result))); + + goto done; + } + + response = gtk_cups_result_get_response (result); + attr = ippFirstAttribute (response); + while (attr && ippGetGroupTag (attr) != IPP_TAG_PRINTER) + attr = ippNextAttribute (response); + + if (attr) + { + while (attr && ippGetGroupTag (attr) == IPP_TAG_PRINTER) + { + cups_printer_handle_attribute (cups_backend, attr, info); + attr = ippNextAttribute (response); + } + + if (info->printer_name && info->printer_uri) + { + info->avahi_printer = TRUE; + + if (info->got_printer_type && + info->default_printer && + cups_backend->avahi_default_printer == NULL) + cups_backend->avahi_default_printer = g_strdup (info->printer_name); + + set_info_state_message (info); + + printer = gtk_print_backend_find_printer (backend, info->printer_name); + if (!printer) + { + printer = cups_create_printer (cups_backend, info); + list_has_changed = TRUE; + } + else + { + g_object_ref (printer); + } + + gtk_printer_set_is_paused (printer, info->is_paused); + gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs); + + if (!gtk_printer_is_active (printer)) + { + gtk_printer_set_is_active (printer, TRUE); + gtk_printer_set_is_new (printer, TRUE); + list_has_changed = TRUE; + } + + GTK_PRINTER_CUPS (printer)->remote = info->remote_printer; + GTK_PRINTER_CUPS (printer)->avahi_name = g_strdup (service->name); + GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (service->type); + GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (service->domain); + GTK_PRINTER_CUPS (printer)->hostname = g_strdup (service->host); + GTK_PRINTER_CUPS (printer)->port = service->port; + GTK_PRINTER_CUPS (printer)->state = info->state; + GTK_PRINTER_CUPS (printer)->ipp_version_major = info->ipp_version_major; + GTK_PRINTER_CUPS (printer)->ipp_version_minor = info->ipp_version_minor; + GTK_PRINTER_CUPS (printer)->supports_copies = info->supports_copies; + GTK_PRINTER_CUPS (printer)->supports_collate = info->supports_collate; + GTK_PRINTER_CUPS (printer)->supports_number_up = info->supports_number_up; + status_changed = gtk_printer_set_job_count (printer, info->job_count); + status_changed |= gtk_printer_set_location (printer, info->location); + status_changed |= gtk_printer_set_description (printer, info->description); + status_changed |= gtk_printer_set_state_message (printer, info->state_msg); + status_changed |= gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs); + + set_printer_icon_name_from_info (printer, info); + + if (gtk_printer_is_new (printer)) + { + g_signal_emit_by_name (backend, "printer-added", printer); + gtk_printer_set_is_new (printer, FALSE); + } + + if (status_changed) + g_signal_emit_by_name (GTK_PRINT_BACKEND (backend), + "printer-status-changed", printer); + + /* The ref is held by GtkPrintBackend, in add_printer() */ + g_object_unref (printer); + } + } + +done: + if (list_has_changed) + g_signal_emit_by_name (backend, "printer-list-changed"); + + if (!cups_backend->got_default_printer && + gtk_print_backend_printer_list_is_done (backend) && + cups_backend->avahi_default_printer != NULL) + { + set_default_printer (cups_backend, cups_backend->avahi_default_printer); + } + + g_slice_free (PrinterSetupInfo, info); + + gdk_threads_leave (); +} + +static void +cups_request_avahi_printer_info (const gchar *printer_uri, + const gchar *host, + gint port, + const gchar *name, + const gchar *type, + const gchar *domain, + GtkPrintBackendCups *backend) +{ + GtkCupsRequest *request; + AvahiService *service; + http_t *http; + + http = httpConnect (host, port); + if (http) + { + service = (AvahiService *) g_new0 (AvahiService, 1); + service->name = g_strdup (name); + service->type = g_strdup (type); + service->domain = g_strdup (domain); + service->host = g_strdup (host); + service->port = port; + + request = gtk_cups_request_new_with_username (http, + GTK_CUPS_POST, + IPP_GET_PRINTER_ATTRIBUTES, + NULL, + NULL, + NULL, + backend->username); + + gtk_cups_request_set_ipp_version (request, 1, 1); + + gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + + gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", G_N_ELEMENTS (printer_attrs), + NULL, printer_attrs); + + cups_request_execute (backend, + request, + (GtkPrintCupsResponseCallbackFunc) cups_request_avahi_printer_info_cb, + service, + (GDestroyNotify) avahi_service_free); + } +} + +static void +avahi_resolver_found_cb (GaServiceResolver *resolver, + int interface, + GaProtocol protocol, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + guint16 port, + AvahiStringList *txt, + glong flags, + gpointer *user_data) +{ + GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data); + AvahiStringList *item; + gchar host[AVAHI_ADDRESS_STR_MAX]; + gchar *suffix = NULL; + gchar *printer_uri; + + avahi_address_snprint (host, sizeof (host), address); + + item = avahi_string_list_find (txt, "rp"); + if (item) + avahi_string_list_get_pair (item, NULL, &suffix, NULL); + + if (suffix) + { + if (g_strcmp0 (type, "_ipp._tcp") == 0) + printer_uri = g_strdup_printf ("ipp://%s:%u/%s", host, port, suffix); + else + printer_uri = g_strdup_printf ("ipps://%s:%u/%s", host, port, suffix); + + cups_request_avahi_printer_info (printer_uri, + host, + port, + name, + type, + domain, + backend); + + g_free (printer_uri); + g_free (suffix); + } +} + +static void +avahi_browser_new_service_cb (GaServiceBrowser *browser, + int interface, + GaProtocol protocol, + const char *name, + const char *type, + const char *domain, + glong flags, + gpointer user_data) +{ + GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data); + GaServiceResolver *resolver; + GError *error = NULL; + + resolver = ga_service_resolver_new (AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + name, type, domain, + AVAHI_PROTO_UNSPEC, + GA_LOOKUP_USE_MULTICAST); + + g_signal_connect (resolver, "found", + G_CALLBACK (avahi_resolver_found_cb), user_data); + + if (!ga_service_resolver_attach (resolver, + backend->avahi_client, + &error)) + { + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error resolving Avahi service %s: %s", + name, error->message)); + g_clear_object (&resolver); + g_clear_error (&error); + return; + } + + backend->avahi_resolvers = g_list_append (backend->avahi_resolvers, resolver); +} + +static void +avahi_browser_removed_service_cb (GaServiceBrowser *browser, + int interface, + GaProtocol protocol, + const char *name, + const char *type, + const char *domain, + glong flags, + gpointer user_data) +{ + GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data); + GtkPrinterCups *printer; + GList *list; + GList *iter; + + list = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (backend)); + for (iter = list; iter; iter = iter->next) + { + printer = GTK_PRINTER_CUPS (iter->data); + if (g_strcmp0 (printer->avahi_name, name) == 0 && + g_strcmp0 (printer->avahi_type, type) == 0 && + g_strcmp0 (printer->avahi_domain, domain) == 0) + { + if (g_strcmp0 (gtk_printer_get_name (GTK_PRINTER (printer)), + backend->avahi_default_printer) == 0) + g_clear_pointer (&backend->avahi_default_printer, g_free); + + g_signal_emit_by_name (backend, "printer-removed", printer); + gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend), + GTK_PRINTER (printer)); + g_signal_emit_by_name (backend, "printer-list-changed"); + break; + } + } + + g_list_free (list); +} + +static gboolean +avahi_client_renew (gpointer user_data) +{ + GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data); + gboolean avahi_printers_removed = TRUE; + GList *list; + GList *iter; + + list = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (backend)); + for (iter = list; iter; iter = iter->next) + if (GTK_PRINTER_CUPS (iter->data)->avahi_browsed) + avahi_printers_removed = FALSE; + + g_list_free (list); + + if (avahi_printers_removed) + { + avahi_data_free (backend); + avahi_request_printer_list (backend); + return FALSE; + } + else + { + return TRUE; + } +} + +static void +avahi_client_state_changed_cb (GaClient *ga_client, + GaClientState state, + gpointer user_data) +{ + GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data); + GtkPrinterCups *printer; + gboolean list_has_changed = FALSE; + GError *error = NULL; + GList *list; + GList *iter; + + switch (state) + { + case GA_CLIENT_STATE_FAILURE: + if (avahi_client_errno (ga_client->avahi_client) == AVAHI_ERR_DISCONNECTED) + { + list = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (backend)); + + for (iter = list; iter; iter = iter->next) + { + printer = GTK_PRINTER_CUPS (iter->data); + if (printer->avahi_browsed) + { + g_signal_emit_by_name (backend, "printer-removed", printer); + gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend), + GTK_PRINTER (printer)); + list_has_changed = TRUE; + } + } + + if (list_has_changed) + g_signal_emit_by_name (backend, "printer-list-changed"); + + g_idle_add (avahi_client_renew, backend); + + g_list_free (list); + } + break; + + case GA_CLIENT_STATE_S_RUNNING: + backend->avahi_ipp_browser = ga_service_browser_new ("_ipp._tcp"); + + g_signal_connect (backend->avahi_ipp_browser, "new-service", + G_CALLBACK (avahi_browser_new_service_cb), + user_data); + + g_signal_connect (backend->avahi_ipp_browser, "removed-service", + G_CALLBACK (avahi_browser_removed_service_cb), + user_data); + + if (!ga_service_browser_attach (backend->avahi_ipp_browser, + backend->avahi_client, + &error)) + { + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error getting printer list from Avahi: %s", + error->message)); + g_clear_object (&backend->avahi_ipp_browser); + g_clear_error (&error); + } + + backend->avahi_ipps_browser = ga_service_browser_new ("_ipps._tcp"); + + g_signal_connect (backend->avahi_ipps_browser, "new-service", + G_CALLBACK (avahi_browser_new_service_cb), + user_data); + + g_signal_connect (backend->avahi_ipps_browser, "removed-service", + G_CALLBACK (avahi_browser_removed_service_cb), + user_data); + + if (!ga_service_browser_attach (backend->avahi_ipps_browser, + backend->avahi_client, + &error)) + { + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error getting printer list from Avahi: %s", + error->message)); + g_clear_object (&backend->avahi_ipps_browser); + g_clear_error (&error); + } + break; + + default: + break; + } +} + +static void +avahi_request_printer_list (GtkPrintBackendCups *cups_backend) +{ + GError *error = NULL; + + if (!cups_backend->avahi_client) + { + cups_backend->avahi_client = ga_client_new (GA_CLIENT_FLAG_NO_FAIL); + + g_signal_connect (cups_backend->avahi_client, "state-changed", + G_CALLBACK (avahi_client_state_changed_cb), + cups_backend); + + if (!ga_client_start (cups_backend->avahi_client, &error)) + { + GTK_NOTE (PRINTING, + g_warning ("CUPS Backend: Error getting printer list from Avahi: %s", + error->message)); + g_clear_object (&cups_backend->avahi_client); + g_clear_error (&error); + } + } +} +#endif static void cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, @@ -1952,6 +2790,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, gboolean list_has_changed; GList *removed_printer_checklist; gchar *remote_default_printer = NULL; + GList *iter; gdk_threads_enter (); @@ -1996,7 +2835,6 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, GtkPrinter *printer; gboolean status_changed = FALSE; GList *node; - gint i; PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo); /* Skip leading attributes until we hit a printer... @@ -2017,7 +2855,6 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, GtkPrinter *printer; gboolean status_changed = FALSE; GList *node; - gint i; PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo); info->default_number_up = 1; @@ -2110,88 +2947,22 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend, #endif GTK_PRINTER_CUPS (printer)->state = info->state; + GTK_PRINTER_CUPS (printer)->ipp_version_major = info->ipp_version_major; + GTK_PRINTER_CUPS (printer)->ipp_version_minor = info->ipp_version_minor; + GTK_PRINTER_CUPS (printer)->supports_copies = info->supports_copies; + GTK_PRINTER_CUPS (printer)->supports_collate = info->supports_collate; + GTK_PRINTER_CUPS (printer)->supports_number_up = info->supports_number_up; status_changed = gtk_printer_set_job_count (printer, info->job_count); status_changed |= gtk_printer_set_location (printer, info->location); status_changed |= gtk_printer_set_description (printer, info->description); - if (info->state_msg != NULL && strlen (info->state_msg) == 0) - { - gchar *tmp_msg2 = NULL; - if (info->is_paused && !info->is_accepting_jobs) - /* Translators: this is a printer status. */ - tmp_msg2 = g_strdup ( N_("Paused ; Rejecting Jobs")); - if (info->is_paused && info->is_accepting_jobs) - /* Translators: this is a printer status. */ - tmp_msg2 = g_strdup ( N_("Paused")); - if (!info->is_paused && !info->is_accepting_jobs) - /* Translators: this is a printer status. */ - tmp_msg2 = g_strdup ( N_("Rejecting Jobs")); - - if (tmp_msg2 != NULL) - { - g_free (info->state_msg); - info->state_msg = tmp_msg2; - } - } - - /* Set description of the reason and combine it with printer-state-message. */ - if ( (info->reason_msg != NULL)) - { - gchar *reason_msg_desc = NULL; - gboolean found = FALSE; - - for (i = 0; i < G_N_ELEMENTS (printer_messages); i++) - { - if (strncmp (info->reason_msg, printer_messages[i], - strlen (printer_messages[i])) == 0) - { - reason_msg_desc = g_strdup_printf (printer_strings[i], - info->printer_name); - found = TRUE; - break; - } - } - - if (!found) - info->reason_level = GTK_PRINTER_STATE_LEVEL_NONE; - - if (info->reason_level >= GTK_PRINTER_STATE_LEVEL_WARNING) - { - if (strlen (info->state_msg) == 0) - { - g_free (info->state_msg); - info->state_msg = reason_msg_desc; - reason_msg_desc = NULL; - } - else - { - gchar *tmp_msg = NULL; - tmp_msg = g_strjoin (" ; ", info->state_msg, - reason_msg_desc, NULL); - g_free (info->state_msg); - info->state_msg = tmp_msg; - } - } - if (reason_msg_desc != NULL) - g_free (reason_msg_desc); - } + set_info_state_message (info); status_changed |= gtk_printer_set_state_message (printer, info->state_msg); status_changed |= gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs); - - - /* Set printer icon according to importance - (none, report, warning, error - report is omitted). */ - if (info->reason_level == GTK_PRINTER_STATE_LEVEL_ERROR) - gtk_printer_set_icon_name (printer, "printer-error"); - else if (info->reason_level == GTK_PRINTER_STATE_LEVEL_WARNING) - gtk_printer_set_icon_name (printer, "printer-warning"); - else if (gtk_printer_is_paused (printer)) - gtk_printer_set_icon_name (printer, "printer-paused"); - else - gtk_printer_set_icon_name (printer, "printer"); + set_printer_icon_name_from_info (printer, info); if (status_changed) g_signal_emit_by_name (GTK_PRINT_BACKEND (backend), @@ -2210,9 +2981,18 @@ 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); + for (iter = removed_printer_checklist; iter; iter = iter->next) + { +#ifdef HAVE_AVAHI_BROWSING + if (!GTK_PRINTER_CUPS (iter->data)->avahi_browsed) +#endif + { + mark_printer_inactive (GTK_PRINTER (iter->data), backend); + list_has_changed = TRUE; + } + } + g_list_free (removed_printer_checklist); - list_has_changed = TRUE; } done: @@ -2223,23 +3003,16 @@ done: 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; + set_default_printer (cups_backend, remote_default_printer); 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); - } - } +#ifdef HAVE_AVAHI_BROWSING + if (!cups_backend->got_default_printer && cups_backend->avahi_default_printer != NULL) + { + set_default_printer (cups_backend, cups_backend->avahi_default_printer); } +#endif gdk_threads_leave (); } @@ -2265,24 +3038,6 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) { GtkCupsConnectionState state; GtkCupsRequest *request; - static const char * const pattrs[] = /* Attributes we're interested in */ - { - "printer-name", - "printer-uri-supported", - "member-uris", - "printer-location", - "printer-info", - "printer-state-message", - "printer-state-reasons", - "printer-state", - "queued-job-count", - "printer-is-accepting-jobs", - "job-sheets-supported", - "job-sheets-default", - "printer-type", - "auth-info-required", - "number-up-default" - }; if (cups_backend->reading_ppds > 0 || cups_backend->list_printers_pending) return TRUE; @@ -2319,8 +3074,8 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend) cups_backend->username); gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", G_N_ELEMENTS (pattrs), - NULL, pattrs); + "requested-attributes", G_N_ELEMENTS (printer_attrs), + NULL, printer_attrs); cups_request_execute (cups_backend, request, @@ -2347,6 +3102,10 @@ cups_get_printer_list (GtkPrintBackend *backend) cups_backend->list_printers_poll = gdk_threads_add_timeout (50, (GSourceFunc) cups_request_printer_list, backend); + +#ifdef HAVE_AVAHI_BROWSING + avahi_request_printer_list (cups_backend); +#endif } } @@ -2387,10 +3146,15 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend, { gboolean success = FALSE; - /* if we get a 404 then it is just a raw printer without a ppd - and not an error */ - if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) && - (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND)) + /* If we get a 404 then it is just a raw printer without a ppd + and not an error. Standalone Avahi printers also don't have + PPD files. */ + if (((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) && + (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND)) +#ifdef HAVE_AVAHI_BROWSING + || GTK_PRINTER_CUPS (printer)->avahi_browsed +#endif + ) { gtk_printer_set_has_details (printer, TRUE); success = TRUE; @@ -2521,6 +3285,10 @@ cups_request_ppd (GtkPrinter *printer) resource, GTK_PRINT_BACKEND_CUPS (print_backend)->username); + gtk_cups_request_set_ipp_version (request, + cups_printer->ipp_version_major, + cups_printer->ipp_version_minor); + GTK_NOTE (PRINTING, g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename)); @@ -4524,12 +5292,11 @@ cups_printer_get_settings_from_options (GtkPrinter *printer, data.settings = settings; data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer)); + gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data); if (data.ppd_file != NULL) { GtkPrinterOption *cover_before, *cover_after; - gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data); - cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before"); cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after"); if (cover_before && cover_after) @@ -4574,7 +5341,9 @@ cups_printer_prepare_for_print (GtkPrinter *printer, GtkPaperSize *paper_size; const char *ppd_paper_name; double scale; + GtkPrintCapabilities capabilities; + capabilities = cups_printer_get_capabilities (printer); pages = gtk_print_settings_get_print_pages (settings); gtk_print_job_set_pages (print_job, pages); @@ -4587,18 +5356,40 @@ cups_printer_prepare_for_print (GtkPrinter *printer, } 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"); - gtk_print_job_set_collate (print_job, FALSE); - if (gtk_print_settings_get_reverse (settings)) - gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse"); - gtk_print_job_set_reverse (print_job, FALSE); + if (capabilities & GTK_PRINT_CAPABILITY_COLLATE) + { + if (gtk_print_settings_get_collate (settings)) + gtk_print_settings_set (settings, "cups-Collate", "True"); + gtk_print_job_set_collate (print_job, FALSE); + } + else + { + gtk_print_job_set_collate (print_job, gtk_print_settings_get_collate (settings)); + } - if (gtk_print_settings_get_n_copies (settings) > 1) - gtk_print_settings_set_int (settings, "cups-copies", - gtk_print_settings_get_n_copies (settings)); - gtk_print_job_set_num_copies (print_job, 1); + if (capabilities & GTK_PRINT_CAPABILITY_REVERSE) + { + if (gtk_print_settings_get_reverse (settings)) + gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse"); + gtk_print_job_set_reverse (print_job, FALSE); + } + else + { + gtk_print_job_set_reverse (print_job, gtk_print_settings_get_reverse (settings)); + } + + if (capabilities & GTK_PRINT_CAPABILITY_COPIES) + { + if (gtk_print_settings_get_n_copies (settings) > 1) + gtk_print_settings_set_int (settings, "cups-copies", + gtk_print_settings_get_n_copies (settings)); + gtk_print_job_set_num_copies (print_job, 1); + } + else + { + gtk_print_job_set_num_copies (print_job, gtk_print_settings_get_n_copies (settings)); + } scale = gtk_print_settings_get_scale (settings); if (scale != 100.0) @@ -4659,6 +5450,12 @@ cups_printer_prepare_for_print (GtkPrinter *printer, 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); + + if (!(capabilities & GTK_PRINT_CAPABILITY_NUMBER_UP)) + { + gtk_print_job_set_n_up (print_job, gtk_print_settings_get_number_up (settings)); + gtk_print_job_set_n_up_layout (print_job, gtk_print_settings_get_number_up_layout (settings)); + } } gtk_print_job_set_rotate (print_job, TRUE); @@ -4778,10 +5575,29 @@ cups_printer_get_hard_margins (GtkPrinter *printer, static GtkPrintCapabilities cups_printer_get_capabilities (GtkPrinter *printer) { - return - GTK_PRINT_CAPABILITY_COPIES | - GTK_PRINT_CAPABILITY_COLLATE | - GTK_PRINT_CAPABILITY_REVERSE | - GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT | - GTK_PRINT_CAPABILITY_NUMBER_UP; + GtkPrintCapabilities capabilities = 0; + GtkPrinterCups *cups_printer = GTK_PRINTER_CUPS (printer); + + if (gtk_printer_cups_get_ppd (cups_printer)) + { + capabilities = GTK_PRINT_CAPABILITY_REVERSE; + } + + if (cups_printer->supports_copies) + { + capabilities |= GTK_PRINT_CAPABILITY_COPIES; + } + + if (cups_printer->supports_collate) + { + capabilities |= GTK_PRINT_CAPABILITY_COLLATE; + } + + if (cups_printer->supports_number_up) + { + capabilities |= GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT | + GTK_PRINT_CAPABILITY_NUMBER_UP; + } + + return capabilities; } diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c index 128b3b385..f2adb0ce5 100644 --- a/modules/printbackends/cups/gtkprintercups.c +++ b/modules/printbackends/cups/gtkprintercups.c @@ -114,6 +114,17 @@ gtk_printer_cups_init (GtkPrinterCups *printer) printer->remote_cups_connection_test = NULL; printer->auth_info_required = NULL; printer->default_number_up = 1; +#ifdef HAVE_AVAHI_BROWSING + printer->avahi_browsed = FALSE; + printer->avahi_name = NULL; + printer->avahi_type = NULL; + printer->avahi_domain = NULL; +#endif + printer->ipp_version_major = 1; + printer->ipp_version_minor = 1; + printer->supports_copies = FALSE; + printer->supports_collate = FALSE; + printer->supports_number_up = FALSE; } static void @@ -134,8 +145,11 @@ gtk_printer_cups_finalize (GObject *object) g_strfreev (printer->auth_info_required); #ifdef HAVE_COLORD - g_cancellable_cancel (printer->colord_cancellable); - g_object_unref (printer->colord_cancellable); + if (printer->colord_cancellable) + { + g_cancellable_cancel (printer->colord_cancellable); + g_object_unref (printer->colord_cancellable); + } g_free (printer->colord_title); g_free (printer->colord_qualifier); if (printer->colord_client) @@ -146,6 +160,12 @@ gtk_printer_cups_finalize (GObject *object) g_object_unref (printer->colord_profile); #endif +#ifdef HAVE_AVAHI_BROWSING + g_free (printer->avahi_name); + g_free (printer->avahi_type); + g_free (printer->avahi_domain); +#endif + if (printer->ppd_file) ppdClose (printer->ppd_file); @@ -512,7 +532,8 @@ colord_printer_details_aquired_cb (GtkPrinterCups *printer, gpointer user_data) { /* refresh the device */ - colord_update_device (printer); + if (printer->colord_client) + colord_update_device (printer); } #endif @@ -565,6 +586,14 @@ gtk_printer_cups_new (const char *name, G_CALLBACK (colord_printer_details_aquired_cb), printer); #endif + + /* + * IPP version 1.1 has to be supported + * by all implementations according to rfc 2911 + */ + printer->ipp_version_major = 1; + printer->ipp_version_minor = 1; + return printer; } diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h index ecc5e38d3..7b14af618 100644 --- a/modules/printbackends/cups/gtkprintercups.h +++ b/modules/printbackends/cups/gtkprintercups.h @@ -75,6 +75,17 @@ struct _GtkPrinterCups gchar *colord_title; gchar *colord_qualifier; #endif +#ifdef HAVE_AVAHI_BROWSING + gboolean avahi_browsed; + gchar *avahi_name; + gchar *avahi_type; + gchar *avahi_domain; +#endif + guchar ipp_version_major; + guchar ipp_version_minor; + gboolean supports_copies; + gboolean supports_collate; + gboolean supports_number_up; }; struct _GtkPrinterCupsClass