[gnome-control-center] printers: Actualize printer list and job list automatically



commit 3349308ea28ac1314313ad3f106e9930a69c6885
Author: Marek Kasik <mkasik redhat com>
Date:   Tue Apr 5 15:54:09 2011 +0200

    printers: Actualize printer list and job list automatically
    
    This patch makes Printers panel to automatically refresh printers list
    when a new printer is added or removed. It is refreshed also when a printer
    changes its state (to see changes in paused/unpaused state) (rhbz#691718).
    It also automatically refresh list of jobs (and also number of active jobs in
    main tab) for actual printer (rhbz#691737).

 panels/printers/cc-printers-panel.c |  236 ++++++++++++++++++++++++++++++++++-
 panels/printers/pp-utils.c          |   97 ++++++++++++++
 panels/printers/pp-utils.h          |    7 +
 3 files changed, 338 insertions(+), 2 deletions(-)
---
diff --git a/panels/printers/cc-printers-panel.c b/panels/printers/cc-printers-panel.c
index 2797f0d..481dc79 100644
--- a/panels/printers/cc-printers-panel.c
+++ b/panels/printers/cc-printers-panel.c
@@ -50,6 +50,13 @@ G_DEFINE_DYNAMIC_TYPE (CcPrintersPanel, cc_printers_panel, CC_TYPE_PANEL)
 #define CLOCK_SCHEMA "org.gnome.desktop.interface"
 #define CLOCK_FORMAT_KEY "clock-format"
 
+#define RENEW_INTERVAL        500
+#define SUBSCRIPTION_DURATION 600
+
+#define CUPS_DBUS_NAME      "org.cups.cupsd.Notifier"
+#define CUPS_DBUS_PATH      "/org/cups/cupsd/Notifier"
+#define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier"
+
 struct _CcPrintersPanelPrivate
 {
   GtkBuilder *builder;
@@ -77,6 +84,10 @@ struct _CcPrintersPanelPrivate
 
   PpNewPrinterDialog *pp_new_printer_dialog;
 
+  GDBusProxy      *cups_proxy;
+  GDBusConnection *cups_bus_connection;
+  gint             subscription_id;
+
   gpointer dummy;
 };
 
@@ -86,6 +97,7 @@ static void actualize_allowed_users_list (CcPrintersPanel *self);
 static void actualize_sensitivity (gpointer user_data);
 static void printer_disable_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data);
 static void printer_set_default_cb (GtkToggleButton *button, gpointer user_data);
+static void detach_from_cups_notifier (gpointer data);
 
 static void
 cc_printers_panel_get_property (GObject    *object,
@@ -158,6 +170,8 @@ cc_printers_panel_dispose (GObject *object)
       priv->lockdown_settings = NULL;
     }
 
+  detach_from_cups_notifier (CC_PRINTERS_PANEL (object));
+
   G_OBJECT_CLASS (cc_printers_panel_parent_class)->dispose (object);
 }
 
@@ -185,6 +199,199 @@ cc_printers_panel_class_finalize (CcPrintersPanelClass *klass)
 {
 }
 
+static void
+on_cups_notification (GDBusConnection *connection,
+                      const char      *sender_name,
+                      const char      *object_path,
+                      const char      *interface_name,
+                      const char      *signal_name,
+                      GVariant        *parameters,
+                      gpointer         user_data)
+{
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+  CcPrintersPanelPrivate *priv;
+  gboolean                printer_is_accepting_jobs;
+  gchar                  *printer_name = NULL;
+  gchar                  *text = NULL;
+  gchar                  *printer_uri = NULL;
+  gchar                  *printer_state_reasons = NULL;
+  gchar                  *job_state_reasons = NULL;
+  gchar                  *job_name = NULL;
+  guint                   job_id;
+  gint                    printer_state;
+  gint                    job_state;
+  gint                    job_impressions_completed;
+  static const char * const requested_attrs[] = {
+    "job-printer-uri",
+    "job-originating-user-name"};
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  if (g_strcmp0 (signal_name, "PrinterAdded") != 0 &&
+      g_strcmp0 (signal_name, "PrinterDeleted") != 0 &&
+      g_strcmp0 (signal_name, "PrinterStateChanged") != 0 &&
+      g_strcmp0 (signal_name, "JobCreated") != 0 &&
+      g_strcmp0 (signal_name, "JobCompleted") != 0)
+    return;
+
+  if (g_variant_n_children (parameters) == 1)
+    g_variant_get (parameters, "(&s)", &text);
+  else if (g_variant_n_children (parameters) == 6)
+    {
+      g_variant_get (parameters, "(&s&s&su&sb)",
+                     &text,
+                     &printer_uri,
+                     &printer_name,
+                     &printer_state,
+                     &printer_state_reasons,
+                     &printer_is_accepting_jobs);
+    }
+  else if (g_variant_n_children (parameters) == 11)
+    {
+      g_variant_get (parameters, "(&s&s&su&sbuu&s&su)",
+                     &text,
+                     &printer_uri,
+                     &printer_name,
+                     &printer_state,
+                     &printer_state_reasons,
+                     &printer_is_accepting_jobs,
+                     &job_id,
+                     &job_state,
+                     &job_state_reasons,
+                     &job_name,
+                     &job_impressions_completed);
+    }
+
+  if (g_strcmp0 (signal_name, "PrinterAdded") == 0 ||
+      g_strcmp0 (signal_name, "PrinterDeleted") == 0 ||
+      g_strcmp0 (signal_name, "PrinterStateChanged") == 0)
+    actualize_printers_list (self);
+  else if (g_strcmp0 (signal_name, "JobCreated") == 0 ||
+           g_strcmp0 (signal_name, "JobCompleted") == 0)
+    {
+      http_t *http;
+      gchar  *job_uri;
+      ipp_t  *request, *response;
+
+      job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", job_id);
+      if ((http = httpConnectEncrypt (cupsServer (), ippPort (),
+                                     cupsEncryption ())) != NULL)
+        {
+          request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+          ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                       "job-uri", NULL, job_uri);
+          ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+                         "requested-attributes", G_N_ELEMENTS (requested_attrs), NULL, requested_attrs);
+          response = cupsDoRequest(http, request, "/");
+
+          if (response)
+            {
+              if (response->request.status.status_code <= IPP_OK_CONFLICT)
+                {
+                  ipp_attribute_t *attr_username = NULL;
+                  ipp_attribute_t *attr_printer_uri = NULL;
+
+                  attr_username = ippFindAttribute(response, "job-originating-user-name", IPP_TAG_NAME);
+                  attr_printer_uri = ippFindAttribute(response, "job-printer-uri", IPP_TAG_URI);
+                  if (attr_username && attr_printer_uri &&
+                      g_strcmp0 (attr_username->values[0].string.text, cupsUser ()) == 0 &&
+                      g_strrstr (attr_printer_uri->values[0].string.text, "/") != 0 &&
+                      priv->current_dest >= 0 &&
+                      priv->current_dest < priv->num_dests &&
+                      priv->dests != NULL &&
+                      g_strcmp0 (g_strrstr (attr_printer_uri->values[0].string.text, "/") + 1,
+                                 priv->dests[priv->current_dest].name) == 0)
+                    actualize_jobs_list (self);
+                }
+              ippDelete(response);
+            }
+          httpClose (http);
+        }
+      g_free (job_uri);
+    }
+}
+
+static gboolean
+renew_subscription (gpointer data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) data;
+  static const char * const events[] = {
+          "printer-added",
+          "printer-deleted",
+          "printer-state-changed",
+          "job-created",
+          "job-completed"};
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  priv->subscription_id = renew_cups_subscription (priv->subscription_id,
+                                                   events,
+                                                   G_N_ELEMENTS (events),
+                                                   SUBSCRIPTION_DURATION);
+
+  return TRUE;
+}
+
+static void
+attach_to_cups_notifier (gpointer data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) data;
+  GError                 *error = NULL;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  renew_subscription (self);
+  g_timeout_add_seconds (RENEW_INTERVAL, renew_subscription, self);
+
+  error = NULL;
+  priv->cups_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+                                                    0,
+                                                    NULL,
+                                                    CUPS_DBUS_NAME,
+                                                    CUPS_DBUS_PATH,
+                                                    CUPS_DBUS_INTERFACE,
+                                                    NULL,
+                                                    &error);
+
+  if (error)
+    {
+      g_warning ("%s", error->message);
+      return;
+    }
+
+  priv->cups_bus_connection = g_dbus_proxy_get_connection (priv->cups_proxy);
+
+  g_dbus_connection_signal_subscribe (priv->cups_bus_connection,
+                                      NULL,
+                                      CUPS_DBUS_INTERFACE,
+                                      NULL,
+                                      CUPS_DBUS_PATH,
+                                      NULL,
+                                      0,
+                                      on_cups_notification,
+                                      self,
+                                      NULL);
+}
+
+static void
+detach_from_cups_notifier (gpointer data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) data;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  cancel_cups_subscription (priv->subscription_id);
+  priv->subscription_id = -1;
+
+  if (priv->cups_proxy != NULL) {
+    g_object_unref (priv->cups_proxy);
+    priv->cups_proxy = NULL;
+  }
+}
+
 enum
 {
   NOTEBOOK_INFO_PAGE = 0,
@@ -943,7 +1150,10 @@ actualize_jobs_list (CcPrintersPanel *self)
   GtkTreeView            *treeview;
   GtkTreeIter             iter;
   GSettings              *settings;
-  int                     i;
+  GtkWidget              *widget;
+  gchar                  *active_jobs;
+  gint                    num_jobs;
+  gint                    i;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
 
@@ -959,7 +1169,24 @@ actualize_jobs_list (CcPrintersPanel *self)
   if (priv->current_dest >= 0 &&
       priv->current_dest < priv->num_dests &&
       priv->dests != NULL)
-    priv->num_jobs = cupsGetJobs (&priv->jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE);
+    {
+      priv->num_jobs = cupsGetJobs (&priv->jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE);
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "printer-jobs-label");
+
+      num_jobs = priv->num_jobs < 0 ? 0 : (guint) priv->num_jobs;
+      /* Translators: there is n active print jobs on this printer */
+      active_jobs = g_strdup_printf (ngettext ("%u active", "%u active", num_jobs), num_jobs);
+
+      if (active_jobs)
+        {
+          gtk_label_set_text (GTK_LABEL (widget), active_jobs);
+          g_free (active_jobs);
+        }
+      else
+        gtk_label_set_text (GTK_LABEL (widget), EMPTY_TEXT);
+    }
 
   store = gtk_list_store_new (JOB_N_COLUMNS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
 
@@ -2205,6 +2432,10 @@ cc_printers_panel_init (CcPrintersPanel *self)
 
   priv->pp_new_printer_dialog = NULL;
 
+  priv->subscription_id = -1;
+  priv->cups_proxy = NULL;
+  priv->cups_bus_connection = NULL;
+
   gtk_builder_add_objects_from_file (priv->builder,
                                      DATADIR"/printers.ui",
                                      objects, &error);
@@ -2349,6 +2580,7 @@ cc_printers_panel_init (CcPrintersPanel *self)
   populate_printers_list (self);
   populate_jobs_list (self);
   populate_allowed_users_list (self);
+  attach_to_cups_notifier (self);
 
   gtk_container_add (GTK_CONTAINER (self), top_widget);
   gtk_widget_show_all (GTK_WIDGET (self));
diff --git a/panels/printers/pp-utils.c b/panels/printers/pp-utils.c
index 39a1416..f9bd48f 100644
--- a/panels/printers/pp-utils.c
+++ b/panels/printers/pp-utils.c
@@ -383,3 +383,100 @@ get_ppd_attribute (const gchar *printer_name, const gchar *attribute_name)
 
   return result;
 }
+
+/* Cancels subscription of given id */
+void
+cancel_cups_subscription (gint id)
+{
+  http_t *http;
+  ipp_t  *request;
+
+  if (id >= 0 &&
+      ((http = httpConnectEncrypt (cupsServer (), ippPort (),
+                                  cupsEncryption ())) != NULL)) {
+    request = ippNewRequest (IPP_CANCEL_SUBSCRIPTION);
+    ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                 "printer-uri", NULL, "/");
+    ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                 "requesting-user-name", NULL, cupsUser ());
+    ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+                  "notify-subscription-id", id);
+    ippDelete (cupsDoRequest (http, request, "/"));
+    httpClose (http);
+  }
+}
+
+/* Returns id of renewed subscription or new id */
+gint
+renew_cups_subscription (gint id,
+                         const char * const *events,
+                         gint num_events,
+                         gint lease_duration)
+{
+  ipp_attribute_t              *attr = NULL;
+  http_t                       *http;
+  ipp_t                        *request;
+  ipp_t                        *response = NULL;
+  gint                          result = -1;
+
+  if ((http = httpConnectEncrypt (cupsServer (), ippPort (),
+                                  cupsEncryption ())) == NULL) {
+    g_debug ("Connection to CUPS server \'%s\' failed.", cupsServer ());
+  }
+  else {
+    if (id >= 0) {
+      request = ippNewRequest (IPP_RENEW_SUBSCRIPTION);
+      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                   "printer-uri", NULL, "/");
+      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                   "requesting-user-name", NULL, cupsUser ());
+      ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
+                    "notify-subscription-id", id);
+      ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+                    "notify-lease-duration", lease_duration);
+      response = cupsDoRequest (http, request, "/");
+      if (response != NULL &&
+          response->request.status.status_code <= IPP_OK_CONFLICT) {
+        if ((attr = ippFindAttribute (response, "notify-lease-duration",
+                                      IPP_TAG_INTEGER)) == NULL)
+          g_debug ("No notify-lease-duration in response!\n");
+        else
+          if (attr->values[0].integer == lease_duration)
+            result = id;
+      }
+    }
+
+    if (result < 0) {
+      request = ippNewRequest (IPP_CREATE_PRINTER_SUBSCRIPTION);
+      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+                    "printer-uri", NULL, "/");
+      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                    "requesting-user-name", NULL, cupsUser ());
+      ippAddStrings (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
+                     "notify-events", num_events, NULL, events);
+      ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
+                    "notify-pull-method", NULL, "ippget");
+      ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
+                    "notify-recipient-uri", NULL, "dbus://");
+      ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+                     "notify-lease-duration", lease_duration);
+      response = cupsDoRequest (http, request, "/");
+
+      if (response != NULL &&
+          response->request.status.status_code <= IPP_OK_CONFLICT) {
+        if ((attr = ippFindAttribute (response, "notify-subscription-id",
+                                      IPP_TAG_INTEGER)) == NULL)
+          g_debug ("No notify-subscription-id in response!\n");
+        else
+          result = attr->values[0].integer;
+      }
+    }
+
+    if (response)
+      ippDelete (response);
+
+    httpClose (http);
+  }
+
+  return result;
+}
diff --git a/panels/printers/pp-utils.h b/panels/printers/pp-utils.h
index e314f5b..9e3749d 100644
--- a/panels/printers/pp-utils.h
+++ b/panels/printers/pp-utils.h
@@ -54,6 +54,13 @@ int         ccGetAllowedUsers (gchar      ***allowed_users,
 gchar      *get_ppd_attribute (const gchar *printer_name,
                                const gchar *attribute_name);
 
+void        cancel_cups_subscription (gint id);
+
+gint        renew_cups_subscription (gint id,
+                                     const char * const *events,
+                                     gint num_events,
+                                     gint lease_duration);
+
 G_END_DECLS
 
 #endif /* __PP_UTILS_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]