[gtk2/f19] Backport listing of Avahi printers from gtk-3.x
mkasik
mkasik at fedoraproject.org
Wed Jun 26 09:57:21 UTC 2013
commit 04b151c39a33abc607d214b7afa30722691a19d8
Author: Marek Kasik <mkasik at redhat.com>
Date: Wed Jun 26 11:54:21 2013 +0200
Backport listing of Avahi printers from gtk-3.x
Resolves: #973730
0001-printing-List-Avahi-printers.patch | 1730 +++++++++++++++++++++++++++++++
gtk2.spec | 10 +-
2 files changed, 1739 insertions(+), 1 deletions(-)
---
diff --git a/0001-printing-List-Avahi-printers.patch b/0001-printing-List-Avahi-printers.patch
new file mode 100644
index 0000000..8000b28
--- /dev/null
+++ b/0001-printing-List-Avahi-printers.patch
@@ -0,0 +1,1730 @@
+From a057ed26dc623dff0fc0c62ef287f6583b2710d0 Mon Sep 17 00:00:00 2001
+From: Marek Kasik <mkasik at redhat.com>
+Date: Tue, 25 Jun 2013 14:34:15 +0200
+Subject: [PATCH] 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=702455
+---
+ configure.ac | 2 +-
+ modules/printbackends/cups/gtkcupsutils.c | 22 +
+ modules/printbackends/cups/gtkcupsutils.h | 3 +
+ modules/printbackends/cups/gtkprintbackendcups.c | 1290 +++++++++++++++++++---
+ modules/printbackends/cups/gtkprintercups.c | 29 +-
+ modules/printbackends/cups/gtkprintercups.h | 11 +
+ 6 files changed, 1205 insertions(+), 152 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 5f8a787..50e27b0 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1479,7 +1479,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)
+diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c
+index 4a3f0ad..6b10db3 100644
+--- a/modules/printbackends/cups/gtkcupsutils.c
++++ b/modules/printbackends/cups/gtkcupsutils.c
+@@ -89,6 +89,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
+@@ -659,6 +673,14 @@ 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 2adfc16..53171ed 100644
+--- a/modules/printbackends/cups/gtkcupsutils.h
++++ b/modules/printbackends/cups/gtkcupsutils.h
+@@ -182,6 +182,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 79033dd..60c2f7e 100644
+--- a/modules/printbackends/cups/gtkprintbackendcups.c
++++ b/modules/printbackends/cups/gtkprintbackendcups.c
+@@ -71,6 +71,17 @@ typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
+ #define _CUPS_MAX_ATTEMPTS 10
+ #define _CUPS_MAX_CHUNK_SIZE 8192
+
++#ifdef HAVE_CUPS_API_1_6
++#define AVAHI_IF_UNSPEC -1
++#define AVAHI_PROTO_INET 0
++#define AVAHI_PROTO_INET6 1
++#define AVAHI_PROTO_UNSPEC -1
++
++#define AVAHI_BUS "org.freedesktop.Avahi"
++#define AVAHI_SERVER_IFACE "org.freedesktop.Avahi.Server"
++#define AVAHI_SERVICE_BROWSER_IFACE "org.freedesktop.Avahi.ServiceBrowser"
++#endif
++
+ /* define this to see warnings about ignored ppd options */
+ #undef PRINT_IGNORED_OPTIONS
+
+@@ -133,6 +144,14 @@ struct _GtkPrintBackendCups
+ GHashTable *auth;
+ gchar *username;
+ gboolean authentication_lock;
++#ifdef HAVE_CUPS_API_1_6
++ GDBusConnection *dbus_connection;
++ gchar *avahi_default_printer;
++ guint avahi_service_browser_subscription_id;
++ guint avahi_service_browser_subscription_ids[2];
++ gchar *avahi_service_browser_paths[2];
++ GCancellable *avahi_cancellable;
++#endif
+ };
+
+ static GObjectClass *backend_parent_class;
+@@ -199,6 +218,10 @@ void overwrite_and_free (gpointer
+ static gboolean is_address_local (const gchar *address);
+ static gboolean request_auth_info (gpointer data);
+
++#ifdef HAVE_CUPS_API_1_6
++static void avahi_request_printer_list (GtkPrintBackendCups *cups_backend);
++#endif
++
+ static void
+ gtk_print_backend_cups_register_type (GTypeModule *module)
+ {
+@@ -257,6 +280,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
+@@ -580,7 +612,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];
+@@ -599,23 +631,82 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
+ cups_printer->device_uri,
+ GTK_PRINT_BACKEND_CUPS (print_backend)->username);
+
++#ifdef HAVE_CUPS_API_1_6
++ 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, "%s", 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);
++
+ #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
+- 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)));
+ #else
+- g_snprintf (printer_absolute_uri,
+- sizeof (printer_absolute_uri),
+- "ipp://localhost:%d/printers/%s",
+- ippPort (),
+- gtk_printer_get_name (gtk_print_job_get_printer (job)));
++ g_snprintf (printer_absolute_uri,
++ sizeof (printer_absolute_uri),
++ "ipp://localhost:%d/printers/%s",
++ ippPort (),
++ gtk_printer_get_name (gtk_print_job_get_printer (job)));
+ #endif
++ }
++
++ 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",
+@@ -663,6 +754,10 @@ void overwrite_and_free (gpointer data)
+ static void
+ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
+ {
++#ifdef HAVE_CUPS_API_1_6
++ gint i;
++#endif
++
+ backend_cups->list_printers_poll = FALSE;
+ backend_cups->got_default_printer = FALSE;
+ backend_cups->list_printers_pending = FALSE;
+@@ -681,6 +776,17 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
+
+ backend_cups->username = NULL;
+
++#ifdef HAVE_CUPS_API_1_6
++ backend_cups->dbus_connection = NULL;
++ backend_cups->avahi_default_printer = NULL;
++ backend_cups->avahi_service_browser_subscription_id = 0;
++ for (i = 0; i < 2; i++)
++ {
++ backend_cups->avahi_service_browser_paths[i] = NULL;
++ backend_cups->avahi_service_browser_subscription_ids[i] = 0;
++ }
++#endif
++
+ cups_get_local_default_printer (backend_cups);
+ }
+
+@@ -707,6 +813,12 @@ gtk_print_backend_cups_finalize (GObject *object)
+
+ g_free (backend_cups->username);
+
++#ifdef HAVE_CUPS_API_1_6
++ g_clear_object (&backend_cups->avahi_cancellable);
++ g_clear_pointer (&backend_cups->avahi_default_printer, g_free);
++ g_clear_object (&backend_cups->dbus_connection);
++#endif
++
+ backend_parent_class->finalize (object);
+ }
+
+@@ -714,6 +826,9 @@ static void
+ gtk_print_backend_cups_dispose (GObject *object)
+ {
+ GtkPrintBackendCups *backend_cups;
++#ifdef HAVE_CUPS_API_1_6
++ gint i;
++#endif
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: %s\n", G_STRFUNC));
+@@ -729,6 +844,44 @@ gtk_print_backend_cups_dispose (GObject *object)
+ g_source_remove (backend_cups->default_printer_poll);
+ backend_cups->default_printer_poll = 0;
+
++#ifdef HAVE_CUPS_API_1_6
++ g_cancellable_cancel (backend_cups->avahi_cancellable);
++
++ for (i = 0; i < 2; i++)
++ {
++ if (backend_cups->avahi_service_browser_subscription_ids[i] > 0)
++ {
++ g_dbus_connection_signal_unsubscribe (backend_cups->dbus_connection,
++ backend_cups->avahi_service_browser_subscription_ids[i]);
++ backend_cups->avahi_service_browser_subscription_ids[i] = 0;
++ }
++
++ if (backend_cups->avahi_service_browser_paths[i])
++ {
++ g_dbus_connection_call (backend_cups->dbus_connection,
++ AVAHI_BUS,
++ backend_cups->avahi_service_browser_paths[i],
++ AVAHI_SERVICE_BROWSER_IFACE,
++ "Free",
++ NULL,
++ NULL,
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL,
++ NULL,
++ NULL);
++ g_clear_pointer (&backend_cups->avahi_service_browser_paths[i], g_free);
++ }
++ }
++
++ if (backend_cups->avahi_service_browser_subscription_id > 0)
++ {
++ g_dbus_connection_signal_unsubscribe (backend_cups->dbus_connection,
++ backend_cups->avahi_service_browser_subscription_id);
++ backend_cups->avahi_service_browser_subscription_id = 0;
++ }
++#endif
++
+ backend_parent_class->dispose (object);
+ }
+
+@@ -1716,6 +1869,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,
+@@ -1743,10 +1920,88 @@ typedef struct
+ gboolean default_printer;
+ gboolean got_printer_type;
+ gboolean remote_printer;
++#ifdef HAVE_CUPS_API_1_6
++ gboolean avahi_printer;
++#endif
+ gchar **auth_info_required;
++ 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,
+ PrinterSetupInfo *info)
+@@ -1867,6 +2122,63 @@ cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend,
+ info->auth_info_required[i] = g_strdup (ippGetString (attr, i, NULL));
+ }
+ }
++ 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,
+@@ -1955,22 +2267,722 @@ cups_create_printer (GtkPrintBackendCups *cups_backend,
+
+ cups_printer->hostname = g_strdup (hostname);
+ cups_printer->port = port;
+-
++
+ cups_printer->auth_info_required = g_strdupv (info->auth_info_required);
+ g_strfreev (info->auth_info_required);
+
+ printer = GTK_PRINTER (cups_printer);
+-
++
+ if (cups_backend->default_printer != NULL &&
+ strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
+ gtk_printer_set_is_default (printer, TRUE);
+
+-
++#ifdef HAVE_CUPS_API_1_6
++ 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 ( _("Paused; Rejecting Jobs"));
++ if (info->is_paused && info->is_accepting_jobs)
++ /* Translators: this is a printer status. */
++ tmp_msg2 = g_strdup ( _("Paused"));
++ if (!info->is_paused && !info->is_accepting_jobs)
++ /* Translators: this is a printer status. */
++ tmp_msg2 = g_strdup ( _("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 (info->state_msg == NULL || info->state_msg[0] == '\0')
++ {
++ g_free (info->state_msg);
++ info->state_msg = reason_msg_desc;
++ reason_msg_desc = NULL;
++ }
++ else
++ {
++ gchar *tmp_msg = NULL;
++ /* Translators: this string connects multiple printer states together. */
++ 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_CUPS_API_1_6
++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
++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);
++ }
++}
++
++typedef struct
++{
++ gchar *printer_uri;
++ gchar *host;
++ gint port;
++ gchar *name;
++ gchar *type;
++ gchar *domain;
++ GtkPrintBackendCups *backend;
++} AvahiConnectionTestData;
++
++static void
++avahi_connection_test_cb (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ AvahiConnectionTestData *data = (AvahiConnectionTestData *) user_data;
++ GSocketConnection *connection;
++
++ connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object),
++ res,
++ NULL);
++ g_object_unref (source_object);
++
++ if (connection != NULL)
++ {
++ g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
++ g_object_unref (connection);
++
++ cups_request_avahi_printer_info (data->printer_uri,
++ data->host,
++ data->port,
++ data->name,
++ data->type,
++ data->domain,
++ data->backend);
++ }
++
++ g_free (data->printer_uri);
++ g_free (data->host);
++ g_free (data->name);
++ g_free (data->type);
++ g_free (data->domain);
++ g_free (data);
++}
++
++static void
++avahi_service_resolver_cb (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ AvahiConnectionTestData *data;
++ GtkPrintBackendCups *backend;
++ const gchar *name;
++ const gchar *host;
++ const gchar *type;
++ const gchar *domain;
++ const gchar *address;
++ const gchar *protocol_string;
++ GVariant *output;
++ GVariant *txt;
++ GVariant *child;
++ guint32 flags;
++ guint16 port;
++ GError *error = NULL;
++ gchar *suffix = NULL;
++ gchar *tmp;
++ gint interface;
++ gint protocol;
++ gint aprotocol;
++ gint i, j;
++
++ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
++ res,
++ &error);
++ if (output)
++ {
++ backend = GTK_PRINT_BACKEND_CUPS (user_data);
++
++ g_variant_get (output, "(ii&s&s&s&si&sq at aayu)",
++ &interface,
++ &protocol,
++ &name,
++ &type,
++ &domain,
++ &host,
++ &aprotocol,
++ &address,
++ &port,
++ &txt,
++ &flags);
++
++ for (i = 0; i < g_variant_n_children (txt); i++)
++ {
++ child = g_variant_get_child_value (txt, i);
++
++ tmp = g_new0 (gchar, g_variant_n_children (child) + 1);
++ for (j = 0; j < g_variant_n_children (child); j++)
++ {
++ tmp[j] = g_variant_get_byte (g_variant_get_child_value (child, j));
++ }
++
++ if (g_str_has_prefix (tmp, "rp="))
++ {
++ suffix = g_strdup (tmp + 3);
++ g_free (tmp);
++ break;
++ }
++
++ g_free (tmp);
++ }
++
++ if (suffix)
++ {
++ if (g_strcmp0 (type, "_ipp._tcp") == 0)
++ protocol_string = "ipp";
++ else
++ protocol_string = "ipps";
++
++ data = g_new0 (AvahiConnectionTestData, 1);
++
++ if (aprotocol == AVAHI_PROTO_INET6)
++ data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, suffix);
++ else
++ data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, suffix);
++
++ data->host = g_strdup (address);
++ data->port = port;
++ data->name = g_strdup (name);
++ data->type = g_strdup (type);
++ data->domain = g_strdup (domain);
++ data->backend = backend;
++
++ /* It can happen that the address is not reachable */
++ g_socket_client_connect_to_host_async (g_socket_client_new (),
++ address,
++ port,
++ backend->avahi_cancellable,
++ avahi_connection_test_cb,
++ data);
++ g_free (suffix);
++ }
++
++ g_variant_unref (output);
++ }
++ else
++ {
++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++ g_warning ("%s", error->message);
++ g_error_free (error);
++ }
++}
++
++static void
++avahi_service_browser_signal_handler (GDBusConnection *connection,
++ const gchar *sender_name,
++ const gchar *object_path,
++ const gchar *interface_name,
++ const gchar *signal_name,
++ GVariant *parameters,
++ gpointer user_data)
++{
++ GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data);
++ gchar *name;
++ gchar *type;
++ gchar *domain;
++ guint flags;
++ gint interface;
++ gint protocol;
++
++ if (g_strcmp0 (signal_name, "ItemNew") == 0)
++ {
++ g_variant_get (parameters, "(ii&s&s&su)",
++ &interface,
++ &protocol,
++ &name,
++ &type,
++ &domain,
++ &flags);
++
++ if (g_strcmp0 (type, "_ipp._tcp") == 0 ||
++ g_strcmp0 (type, "_ipps._tcp") == 0)
++ {
++ g_dbus_connection_call (backend->dbus_connection,
++ AVAHI_BUS,
++ "/",
++ AVAHI_SERVER_IFACE,
++ "ResolveService",
++ g_variant_new ("(iisssiu)",
++ interface,
++ protocol,
++ name,
++ type,
++ domain,
++ AVAHI_PROTO_UNSPEC,
++ 0),
++ G_VARIANT_TYPE ("(iissssisqaayu)"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ backend->avahi_cancellable,
++ avahi_service_resolver_cb,
++ user_data);
++ }
++ }
++ else if (g_strcmp0 (signal_name, "ItemRemove") == 0)
++ {
++ GtkPrinterCups *printer;
++ GList *list;
++ GList *iter;
++
++ g_variant_get (parameters, "(ii&s&s&su)",
++ &interface,
++ &protocol,
++ &name,
++ &type,
++ &domain,
++ &flags);
++
++ if (g_strcmp0 (type, "_ipp._tcp") == 0 ||
++ g_strcmp0 (type, "_ipps._tcp") == 0)
++ {
++ 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 void
++avahi_service_browser_new_cb (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ GtkPrintBackendCups *cups_backend;
++ GVariant *output;
++ GError *error = NULL;
++ gint i;
++
++ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
++ res,
++ &error);
++ if (output)
++ {
++ cups_backend = GTK_PRINT_BACKEND_CUPS (user_data);
++ i = cups_backend->avahi_service_browser_paths[0] ? 1 : 0;
++
++ g_variant_get (output, "(o)", &cups_backend->avahi_service_browser_paths[i]);
++
++ cups_backend->avahi_service_browser_subscription_ids[i] =
++ g_dbus_connection_signal_subscribe (cups_backend->dbus_connection,
++ NULL,
++ AVAHI_SERVICE_BROWSER_IFACE,
++ NULL,
++ cups_backend->avahi_service_browser_paths[i],
++ NULL,
++ G_DBUS_SIGNAL_FLAGS_NONE,
++ avahi_service_browser_signal_handler,
++ user_data,
++ NULL);
++
++ /*
++ * The general subscription for all service browsers is not needed
++ * now because we are already subscribed to service browsers
++ * specific to _ipp._tcp and _ipps._tcp services.
++ */
++ if (cups_backend->avahi_service_browser_paths[0] &&
++ cups_backend->avahi_service_browser_paths[1] &&
++ cups_backend->avahi_service_browser_subscription_id > 0)
++ {
++ g_dbus_connection_signal_unsubscribe (cups_backend->dbus_connection,
++ cups_backend->avahi_service_browser_subscription_id);
++ cups_backend->avahi_service_browser_subscription_id = 0;
++ }
++
++ g_variant_unref (output);
++ }
++ else
++ {
++ /*
++ * The creation of ServiceBrowser fails with G_IO_ERROR_DBUS_ERROR
++ * if Avahi is disabled.
++ */
++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR) &&
++ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++ g_warning ("%s", error->message);
++ g_error_free (error);
++ }
++}
++
++static void
++avahi_create_browsers (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ GDBusConnection *dbus_connection;
++ GtkPrintBackendCups *cups_backend;
++ GError *error = NULL;
++
++ dbus_connection = g_bus_get_finish (res, &error);
++ if (!dbus_connection)
++ {
++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
++ g_warning ("Couldn't connect to D-Bus system bus, %s", error->message);
++
++ g_error_free (error);
++ return;
++ }
++
++ cups_backend = GTK_PRINT_BACKEND_CUPS (user_data);
++ cups_backend->dbus_connection = dbus_connection;
++
++ /*
++ * We need to subscribe to signals of service browser before
++ * we actually create it because it starts to emit them right
++ * after its creation.
++ */
++ cups_backend->avahi_service_browser_subscription_id =
++ g_dbus_connection_signal_subscribe (cups_backend->dbus_connection,
++ NULL,
++ AVAHI_SERVICE_BROWSER_IFACE,
++ NULL,
++ NULL,
++ NULL,
++ G_DBUS_SIGNAL_FLAGS_NONE,
++ avahi_service_browser_signal_handler,
++ cups_backend,
++ NULL);
++
++ /*
++ * Create service browsers for _ipp._tcp and _ipps._tcp services.
++ */
++ g_dbus_connection_call (cups_backend->dbus_connection,
++ AVAHI_BUS,
++ "/",
++ AVAHI_SERVER_IFACE,
++ "ServiceBrowserNew",
++ g_variant_new ("(iissu)",
++ AVAHI_IF_UNSPEC,
++ AVAHI_PROTO_UNSPEC,
++ "_ipp._tcp",
++ "",
++ 0),
++ G_VARIANT_TYPE ("(o)"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ cups_backend->avahi_cancellable,
++ avahi_service_browser_new_cb,
++ cups_backend);
++
++ g_dbus_connection_call (cups_backend->dbus_connection,
++ AVAHI_BUS,
++ "/",
++ AVAHI_SERVER_IFACE,
++ "ServiceBrowserNew",
++ g_variant_new ("(iissu)",
++ AVAHI_IF_UNSPEC,
++ AVAHI_PROTO_UNSPEC,
++ "_ipps._tcp",
++ "",
++ 0),
++ G_VARIANT_TYPE ("(o)"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ cups_backend->avahi_cancellable,
++ avahi_service_browser_new_cb,
++ cups_backend);
++}
++
++static void
++avahi_request_printer_list (GtkPrintBackendCups *cups_backend)
++{
++ cups_backend->avahi_cancellable = g_cancellable_new ();
++ g_bus_get (G_BUS_TYPE_SYSTEM, cups_backend->avahi_cancellable, avahi_create_browsers, cups_backend);
++}
++#endif
++
++static void
+ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
+ GtkCupsResult *result,
+ gpointer user_data)
+@@ -1981,6 +2993,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 ();
+
+@@ -2025,7 +3038,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...
+@@ -2046,7 +3058,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...
+@@ -2137,88 +3148,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 == 3)
+- gtk_printer_set_icon_name (printer, "gtk-print-error");
+- else if (info->reason_level == 2)
+- gtk_printer_set_icon_name (printer, "gtk-print-warning");
+- else if (gtk_printer_is_paused (printer))
+- gtk_printer_set_icon_name (printer, "gtk-print-paused");
+- else
+- gtk_printer_set_icon_name (printer, "gtk-print");
++ set_printer_icon_name_from_info (printer, info);
+
+ if (status_changed)
+ g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
+@@ -2237,9 +3182,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_CUPS_API_1_6
++ 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:
+@@ -2250,23 +3204,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_CUPS_API_1_6
++ 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 ();
+ }
+@@ -2292,23 +3239,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"
+- };
+
+ if (cups_backend->reading_ppds > 0 || cups_backend->list_printers_pending)
+ return TRUE;
+@@ -2345,8 +3275,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,
+@@ -2373,6 +3303,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_CUPS_API_1_6
++ avahi_request_printer_list (cups_backend);
++#endif
+ }
+ }
+
+@@ -2414,10 +3348,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_CUPS_API_1_6
++ || GTK_PRINTER_CUPS (printer)->avahi_browsed
++#endif
++ )
+ {
+ gtk_printer_set_has_details (printer, TRUE);
+ success = TRUE;
+@@ -2550,6 +3489,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));
+
+@@ -4501,11 +5444,10 @@ 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");
+@@ -4548,7 +5490,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);
+ print_job->print_pages = gtk_print_settings_get_print_pages (settings);
+ print_job->page_ranges = NULL;
+ print_job->num_page_ranges = 0;
+@@ -4558,18 +5502,39 @@ cups_printer_prepare_for_print (GtkPrinter *printer,
+ gtk_print_settings_get_page_ranges (settings,
+ &print_job->num_page_ranges);
+
+- if (gtk_print_settings_get_collate (settings))
+- gtk_print_settings_set (settings, "cups-Collate", "True");
+- print_job->collate = FALSE;
++ if (capabilities & GTK_PRINT_CAPABILITY_COLLATE)
++ {
++ if (gtk_print_settings_get_collate (settings))
++ gtk_print_settings_set (settings, "cups-Collate", "True");
++ print_job->collate = FALSE;
++ }
++ else
++ {
++ print_job->collate = gtk_print_settings_get_collate (settings);
++ }
+
+- if (gtk_print_settings_get_reverse (settings))
+- gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
+- print_job->reverse = FALSE;
++ if (capabilities & GTK_PRINT_CAPABILITY_REVERSE)
++ {
++ if (gtk_print_settings_get_reverse (settings))
++ gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
++ print_job->reverse = FALSE;
++ }
++ else
++ {
++ print_job->reverse = gtk_print_settings_get_reverse (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));
+- print_job->num_copies = 1;
++ 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));
++ print_job->num_copies = 1;
++ }
++ else
++ {
++ print_job->num_copies = gtk_print_settings_get_n_copies (settings);
++ }
+
+ scale = gtk_print_settings_get_scale (settings);
+ print_job->scale = 1.0;
+@@ -4631,6 +5596,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))
++ {
++ print_job->number_up = gtk_print_settings_get_number_up (settings);
++ print_job->number_up_layout = gtk_print_settings_get_number_up_layout (settings);
++ }
+ }
+
+ print_job->rotate_to_orientation = TRUE;
+@@ -4750,12 +5721,31 @@ 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 |
++ 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;
+ #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 1 && CUPS_VERSION_PATCH >= 15) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || CUPS_VERSION_MAJOR > 1
+- GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT |
++ capabilities |= GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT;
+ #endif
+- GTK_PRINT_CAPABILITY_NUMBER_UP;
++ }
++
++ return capabilities;
+ }
+diff --git a/modules/printbackends/cups/gtkprintercups.c b/modules/printbackends/cups/gtkprintercups.c
+index 8b3f85c..f957558 100644
+--- a/modules/printbackends/cups/gtkprintercups.c
++++ b/modules/printbackends/cups/gtkprintercups.c
+@@ -82,6 +82,17 @@ gtk_printer_cups_init (GtkPrinterCups *printer)
+ printer->get_remote_ppd_attempts = 0;
+ printer->remote_cups_connection_test = NULL;
+ printer->auth_info_required = NULL;
++#ifdef HAVE_CUPS_API_1_6
++ 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
+@@ -101,6 +112,12 @@ gtk_printer_cups_finalize (GObject *object)
+ g_free (printer->default_cover_after);
+ g_strfreev (printer->auth_info_required);
+
++#ifdef HAVE_CUPS_API_1_6
++ g_free (printer->avahi_name);
++ g_free (printer->avahi_type);
++ g_free (printer->avahi_domain);
++#endif
++
+ if (printer->ppd_file)
+ ppdClose (printer->ppd_file);
+
+@@ -128,6 +145,7 @@ gtk_printer_cups_new (const char *name,
+ {
+ GObject *result;
+ gboolean accepts_pdf;
++ GtkPrinterCups *printer;
+
+ #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
+ accepts_pdf = TRUE;
+@@ -142,7 +160,16 @@ gtk_printer_cups_new (const char *name,
+ "accepts-pdf", accepts_pdf,
+ NULL);
+
+- return (GtkPrinterCups *) result;
++ printer = GTK_PRINTER_CUPS (result);
++
++ /*
++ * 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;
+ }
+
+ ppd_file_t *
+diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h
+index 6868232..d10bd7e 100644
+--- a/modules/printbackends/cups/gtkprintercups.h
++++ b/modules/printbackends/cups/gtkprintercups.h
+@@ -62,6 +62,17 @@ struct _GtkPrinterCups
+ guint get_remote_ppd_poll;
+ gint get_remote_ppd_attempts;
+ GtkCupsConnectionTest *remote_cups_connection_test;
++#ifdef HAVE_CUPS_API_1_6
++ 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
+--
+1.8.2.1
+
diff --git a/gtk2.spec b/gtk2.spec
index 25d8014..899b010 100644
--- a/gtk2.spec
+++ b/gtk2.spec
@@ -18,7 +18,7 @@
Summary: The GIMP ToolKit (GTK+), a library for creating GUIs for X
Name: gtk2
Version: 2.24.19
-Release: 2%{?dist}
+Release: 3%{?dist}
License: LGPLv2+
Group: System Environment/Libraries
URL: http://www.gtk.org
@@ -38,6 +38,9 @@ Patch8: tooltip-positioning.patch
#Patch14: gtk2-landscape-pdf-print.patch
# https://bugzilla.gnome.org/show_bug.cgi?id=611313
Patch15: window-dragging.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=973730
+# https://bugzilla.gnome.org/show_bug.cgi?id=702455
+Patch16: 0001-printing-List-Avahi-printers.patch
BuildRequires: atk-devel >= %{atk_version}
BuildRequires: glib2-devel >= %{glib2_version}
@@ -151,6 +154,7 @@ This package contains developer documentation for the GTK+ widget toolkit.
%patch8 -p1 -b .tooltip-positioning
#%patch14 -p1 -b .landscape-pdf-print
%patch15 -p1 -b .window-dragging
+%patch16 -p1 -b .avahi-printers
%build
(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; CONFIGFLAGS=--enable-gtk-doc; fi;
@@ -337,6 +341,10 @@ fi
%doc tmpdocs/examples
%changelog
+* Wed Jun 26 2013 Marek Kasik <mkasik at redhat.com> - 2.24.19-3
+- Backport listing of Avahi printers from gtk-3.x
+- Resolves: #973730
+
* Sat Jun 22 2013 Matthias Clasen <mclasen at redhat.com> - 2.24.19-2
- Trim %%changelog
More information about the scm-commits
mailing list