[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