]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprintbackend.c
Adds authentication support of CUPS backend
[~andy/gtk] / gtk / gtkprintbackend.c
index a2af6c4865326437fd2bf0fb93fb788df7d50239..567273bdd7b3d6cbf2e7f32edd488e87a3762b11 100644 (file)
 
 #include "gtkintl.h"
 #include "gtkmodules.h"
+#include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkprintbackend.h"
+#include "gtkprinter-private.h"
 #include "gtkalias.h"
 
 #define GTK_PRINT_BACKEND_GET_PRIVATE(o)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_BACKEND, GtkPrintBackendPrivate))
 
-static void gtk_print_backend_dispose (GObject *object);
+static void gtk_print_backend_dispose      (GObject      *object);
+static void gtk_print_backend_set_property (GObject      *object,
+                                            guint         prop_id,
+                                            const GValue *value,
+                                            GParamSpec   *pspec);
+static void gtk_print_backend_get_property (GObject      *object,
+                                            guint         prop_id,
+                                            GValue       *value,
+                                            GParamSpec   *pspec);
 
 struct _GtkPrintBackendPrivate
 {
   GHashTable *printers;
   guint printer_list_requested : 1;
   guint printer_list_done : 1;
+  GtkPrintBackendStatus status;
+  char *hostname;
+  char *username;
+  char *password;
 };
 
 enum {
@@ -47,11 +61,18 @@ enum {
   PRINTER_ADDED,
   PRINTER_REMOVED,
   PRINTER_STATUS_CHANGED,
+  REQUEST_PASSWORD,
   LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+enum 
+{ 
+  PROP_ZERO,
+  PROP_STATUS
+};
+
 static GObjectClass *backend_parent_class;
 
 GQuark
@@ -103,7 +124,7 @@ gtk_print_backend_module_load (GTypeModule *module)
   pb_module->library = g_module_open (pb_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
   if (!pb_module->library)
     {
-      g_warning (g_module_error());
+      g_warning ("%s", g_module_error());
       return FALSE;
     }
   
@@ -115,7 +136,7 @@ gtk_print_backend_module_load (GTypeModule *module)
       !g_module_symbol (pb_module->library, "pb_module_create", 
                        &createp))
     {
-      g_warning (g_module_error());
+      g_warning ("%s", g_module_error());
       g_module_close (pb_module->library);
       
       return FALSE;
@@ -125,7 +146,7 @@ gtk_print_backend_module_load (GTypeModule *module)
   pb_module->exit = exitp;
   pb_module->create = createp;
 
-  /* call the filesystems's init function to let it */
+  /* call the printbackend's init function to let it */
   /* setup anything it needs to set up. */
   pb_module->init (module);
 
@@ -172,6 +193,50 @@ _gtk_print_backend_module_class_init (GtkPrintBackendModuleClass *class)
   gobject_class->finalize = gtk_print_backend_module_finalize;
 }
 
+static void 
+gtk_print_backend_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
+  GtkPrintBackendPrivate *priv;
+
+  priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
+
+  switch (prop_id)
+    {
+    case PROP_STATUS:
+      priv->status = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+gtk_print_backend_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
+  GtkPrintBackendPrivate *priv;
+
+  priv = backend->priv = GTK_PRINT_BACKEND_GET_PRIVATE (backend); 
+
+  switch (prop_id)
+    {
+    case PROP_STATUS:
+      g_value_set_int (value, priv->status);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
 static void
 _gtk_print_backend_module_init (GtkPrintBackendModule *pb_module)
 {
@@ -191,16 +256,15 @@ _gtk_print_backend_module_create (GtkPrintBackendModule *pb_module)
   return NULL;
 }
 
-GtkPrintBackend *
-_gtk_print_backend_create (const char *backend_name)
+static GtkPrintBackend *
+_gtk_print_backend_create (const gchar *backend_name)
 {
   GSList *l;
-  char *module_path;
-  char *full_name;
+  gchar *module_path;
+  gchar *full_name;
   GtkPrintBackendModule *pb_module;
   GtkPrintBackend *pb;
 
-  /* TODO: make module loading code work */
   for (l = loaded_backends; l != NULL; l = l->next)
     {
       pb_module = l->data;
@@ -229,8 +293,9 @@ _gtk_print_backend_create (const char *backend_name)
          pb = _gtk_print_backend_module_create (pb_module);
 
          /* Increase use-count so that we don't unload print backends.
-            There is a problem with module unloading in the cups module,
-            see cups_dispatch_watch_finalize for details. */
+          * There is a problem with module unloading in the cups module,
+          * see cups_dispatch_watch_finalize for details. 
+          */
          g_type_module_use (G_TYPE_MODULE (pb_module));
        }
       
@@ -238,31 +303,10 @@ _gtk_print_backend_create (const char *backend_name)
     }
 
   return pb;
-
-  return NULL;
 }
 
-static void
-gtk_print_backend_initialize (void)
-{
-  static gboolean initialized = FALSE;
-
-  if (!initialized)
-    {
-      gtk_settings_install_property (g_param_spec_string ("gtk-print-backends",
-                                                         P_("Default print backend"),
-                                                         P_("List of the GtkPrintBackend backends to use by default"),
-                                                         GTK_PRINT_BACKENDS,
-                                                         GTK_PARAM_READWRITE));
-
-      initialized = TRUE;
-    }
-}
-
-
-
 GList *
-gtk_print_backend_load_modules ()
+gtk_print_backend_load_modules (void)
 {
   GList *result;
   GtkPrintBackend *backend;
@@ -273,11 +317,11 @@ gtk_print_backend_load_modules ()
 
   result = NULL;
 
-  gtk_print_backend_initialize ();
-  
   settings = gtk_settings_get_default ();
-
-  g_object_get (settings, "gtk-print-backends", &setting, NULL);
+  if (settings)
+    g_object_get (settings, "gtk-print-backends", &setting, NULL);
+  else
+    setting = g_strdup (GTK_PRINT_BACKENDS);
 
   backends = g_strsplit (setting, ",", -1);
 
@@ -303,16 +347,21 @@ gtk_print_backend_load_modules ()
 
 G_DEFINE_TYPE (GtkPrintBackend, gtk_print_backend, G_TYPE_OBJECT)
 
-static void                 fallback_printer_request_details  (GtkPrinter          *printer);
-static gboolean             fallback_printer_mark_conflicts   (GtkPrinter          *printer,
-                                                              GtkPrinterOptionSet *options);
-static void                 fallback_printer_get_hard_margins (GtkPrinter          *printer,
-                                                              double              *top,
-                                                              double              *bottom,
-                                                              double              *left,
-                                                              double              *right);
-static GList *              fallback_printer_list_papers      (GtkPrinter          *printer);
-static GtkPrintCapabilities fallback_printer_get_capabilities (GtkPrinter          *printer);
+static void                 fallback_printer_request_details       (GtkPrinter          *printer);
+static gboolean             fallback_printer_mark_conflicts        (GtkPrinter          *printer,
+                                                                   GtkPrinterOptionSet *options);
+static void                 fallback_printer_get_hard_margins      (GtkPrinter          *printer,
+                                                                   gdouble             *top,
+                                                                   gdouble             *bottom,
+                                                                   gdouble             *left,
+                                                                   gdouble             *right);
+static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
+static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
+static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
+static void                 request_password                       (GtkPrintBackend     *backend,
+                                                                    const gchar         *hostname,
+                                                                    const gchar         *username,
+                                                                    const gchar         *prompt);
   
 static void
 gtk_print_backend_class_init (GtkPrintBackendClass *class)
@@ -323,13 +372,27 @@ gtk_print_backend_class_init (GtkPrintBackendClass *class)
   backend_parent_class = g_type_class_peek_parent (class);
   
   object_class->dispose = gtk_print_backend_dispose;
+  object_class->set_property = gtk_print_backend_set_property;
+  object_class->get_property = gtk_print_backend_get_property;
 
   class->printer_request_details = fallback_printer_request_details;
   class->printer_mark_conflicts = fallback_printer_mark_conflicts;
   class->printer_get_hard_margins = fallback_printer_get_hard_margins;
   class->printer_list_papers = fallback_printer_list_papers;
+  class->printer_get_default_page_size = fallback_printer_get_default_page_size;
   class->printer_get_capabilities = fallback_printer_get_capabilities;
+  class->request_password = request_password;
   
+  g_object_class_install_property (object_class, 
+                                   PROP_STATUS,
+                                   g_param_spec_int ("status",
+                                                     "Status",
+                                                     "The status of the print backend",
+                                                     GTK_PRINT_BACKEND_STATUS_UNKNOWN,
+                                                     GTK_PRINT_BACKEND_STATUS_UNAVAILABLE,
+                                                     GTK_PRINT_BACKEND_STATUS_UNKNOWN,
+                                                     GTK_PARAM_READWRITE)); 
+
   g_type_class_add_private (class, sizeof (GtkPrintBackendPrivate));
   
   signals[PRINTER_LIST_CHANGED] =
@@ -372,6 +435,14 @@ gtk_print_backend_class_init (GtkPrintBackendClass *class)
                  NULL, NULL,
                  g_cclosure_marshal_VOID__OBJECT,
                  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
+  signals[REQUEST_PASSWORD] =
+    g_signal_new (I_("request-password"),
+                 G_TYPE_FROM_CLASS (class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__STRING_STRING_STRING,
+                 G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
 }
 
 static void
@@ -384,6 +455,9 @@ gtk_print_backend_init (GtkPrintBackend *backend)
   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
                                          (GDestroyNotify) g_free,
                                          (GDestroyNotify) g_object_unref);
+  priv->hostname = NULL;
+  priv->username = NULL;
+  priv->password = NULL;
 }
 
 static void
@@ -396,7 +470,8 @@ gtk_print_backend_dispose (GObject *object)
   priv = backend->priv;
 
   /* We unref the printers in dispose, not in finalize so that
-     we can break refcount cycles with gtk_print_backend_destroy */
+   * we can break refcount cycles with gtk_print_backend_destroy 
+   */
   if (priv->printers)
     {
       g_hash_table_destroy (priv->printers);
@@ -413,7 +488,7 @@ fallback_printer_request_details (GtkPrinter *printer)
 }
 
 static gboolean
-fallback_printer_mark_conflicts (GtkPrinter *printer,
+fallback_printer_mark_conflicts (GtkPrinter          *printer,
                                 GtkPrinterOptionSet *options)
 {
   return FALSE;
@@ -421,10 +496,10 @@ fallback_printer_mark_conflicts (GtkPrinter *printer,
 
 static void
 fallback_printer_get_hard_margins (GtkPrinter *printer,
-                                  double *top,
-                                  double *bottom,
-                                  double *left,
-                                  double *right)
+                                  gdouble    *top,
+                                  gdouble    *bottom,
+                                  gdouble    *left,
+                                  gdouble    *right)
 {
   *top = 0;
   *bottom = 0;
@@ -438,6 +513,12 @@ fallback_printer_list_papers (GtkPrinter *printer)
   return NULL;
 }
 
+static GtkPageSetup *
+fallback_printer_get_default_page_size (GtkPrinter *printer)
+{
+  return NULL;
+}
+
 static GtkPrintCapabilities
 fallback_printer_get_capabilities (GtkPrinter *printer)
 {
@@ -446,9 +527,9 @@ fallback_printer_get_capabilities (GtkPrinter *printer)
 
 
 static void
-printer_hash_to_sorted_active_list (const gchar *key,
-                                    gpointer value,
-                                    GList **out_list)
+printer_hash_to_sorted_active_list (const gchar  *key,
+                                    gpointer      value,
+                                    GList       **out_list)
 {
   GtkPrinter *printer;
 
@@ -466,7 +547,7 @@ printer_hash_to_sorted_active_list (const gchar *key,
 
 void
 gtk_print_backend_add_printer (GtkPrintBackend *backend,
-                              GtkPrinter *printer)
+                              GtkPrinter      *printer)
 {
   GtkPrintBackendPrivate *priv;
   
@@ -484,7 +565,7 @@ gtk_print_backend_add_printer (GtkPrintBackend *backend,
 
 void
 gtk_print_backend_remove_printer (GtkPrintBackend *backend,
-                                 GtkPrinter *printer)
+                                 GtkPrinter      *printer)
 {
   GtkPrintBackendPrivate *priv;
   
@@ -531,8 +612,8 @@ gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
        GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
       priv->printer_list_requested = TRUE;
     }
-  
-  return result;;
+
+  return result;
 }
 
 gboolean
@@ -545,7 +626,7 @@ gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
 
 GtkPrinter *
 gtk_print_backend_find_printer (GtkPrintBackend *backend,
-                                const gchar *printer_name)
+                                const gchar     *printer_name)
 {
   GtkPrintBackendPrivate *priv;
   GtkPrinter *printer;
@@ -563,34 +644,196 @@ gtk_print_backend_find_printer (GtkPrintBackend *backend,
 }
 
 void
-gtk_print_backend_print_stream (GtkPrintBackend *backend,
-                                GtkPrintJob *job,
-                                gint data_fd,
+gtk_print_backend_print_stream (GtkPrintBackend        *backend,
+                                GtkPrintJob            *job,
+                                GIOChannel             *data_io,
                                 GtkPrintJobCompleteFunc callback,
-                                gpointer user_data,
-                               GDestroyNotify dnotify)
+                                gpointer                user_data,
+                               GDestroyNotify          dnotify)
 {
   g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
 
   GTK_PRINT_BACKEND_GET_CLASS (backend)->print_stream (backend,
                                                       job,
-                                                      data_fd,
+                                                      data_io,
                                                       callback,
                                                       user_data,
                                                       dnotify);
 }
 
+void 
+gtk_print_backend_set_password (GtkPrintBackend *backend,
+                                const gchar     *hostname,
+                                const gchar     *username,
+                                const gchar     *password)
+{
+  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
+
+  if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
+    GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
+}
+
+static void
+store_password (GtkEntry        *entry,
+                GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+    }
+
+  priv->password = g_strdup (gtk_entry_get_text (entry));
+}
+
+static void
+store_username (GtkEntry        *entry,
+                GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  g_free (priv->username);
+  priv->username = g_strdup (gtk_entry_get_text (entry));
+}
+
+static void
+password_dialog_response (GtkWidget       *dialog,
+                          gint             response_id,
+                          GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (response_id == GTK_RESPONSE_OK)
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
+  else
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+      priv->password = NULL;
+    }
+
+  g_free (priv->username);
+  priv->username = NULL;
+
+  gtk_widget_destroy (dialog);
+
+  g_object_unref (backend);
+}
+
+static void
+request_password (GtkPrintBackend *backend,
+                  const gchar     *hostname,
+                  const gchar     *username,
+                  const gchar     *prompt)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+  GtkWidget *dialog, *username_box, *password_box, *main_box, *label, *icon, *vbox,
+            *password_prompt, *username_prompt,
+            *password_entry, *username_entry;
+  gchar     *markup;
+
+  dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL, 
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_OK, GTK_RESPONSE_OK,
+                                         NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+  main_box = gtk_hbox_new (FALSE, 0);
+
+  /* Left */
+  icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
+  gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0.0);
+  gtk_misc_set_padding (GTK_MISC (icon), 6, 6);
+
+
+  /* Right */
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_widget_set_size_request (GTK_WIDGET (vbox), 320, -1);
+
+  /* Right - 1. */
+  label = gtk_label_new (NULL);
+  markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"large\">%s</span>", prompt);
+  gtk_label_set_markup (GTK_LABEL (label), markup);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_widget_set_size_request (GTK_WIDGET (label), 320, -1);
+  g_free (markup);
+
+
+  /* Right - 2. */
+  username_box = gtk_hbox_new (TRUE, 0);
+
+  username_prompt = gtk_label_new (_("Username:"));
+  gtk_misc_set_alignment (GTK_MISC (username_prompt), 0.0, 0.5);
+
+  username_entry = gtk_entry_new ();
+  gtk_entry_set_text (GTK_ENTRY (username_entry), username);
+
+
+  /* Right - 3. */
+  password_box = gtk_hbox_new (TRUE, 0);
+
+  password_prompt = gtk_label_new (_("Password:"));
+  gtk_misc_set_alignment (GTK_MISC (password_prompt), 0.0, 0.5);
+
+  password_entry = gtk_entry_new ();
+  gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
+  gtk_entry_set_activates_default (GTK_ENTRY (password_entry), TRUE);
+
+
+  /* Packing */
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_box, TRUE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (main_box), icon, FALSE, FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
+
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), username_box, FALSE, TRUE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), password_box, FALSE, TRUE, 6);
+
+  gtk_box_pack_start (GTK_BOX (username_box), username_prompt, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (username_box), username_entry, TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (password_box), password_prompt, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (password_box), password_entry, TRUE, TRUE, 0);
+
+
+  gtk_widget_grab_focus (password_entry);
+
+  priv->hostname = g_strdup (hostname);
+  priv->username = g_strdup (username);
+
+  g_signal_connect (password_entry, "changed",
+                    G_CALLBACK (store_password), backend);
+
+  g_signal_connect (username_entry, "changed",
+                    G_CALLBACK (store_username), backend);
+
+  g_object_ref (backend);
+  g_signal_connect (G_OBJECT (dialog), "response",
+                    G_CALLBACK (password_dialog_response), backend);
+
+  gtk_widget_show_all (dialog);
+}
+
 void
 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
 {
   /* The lifecycle of print backends and printers are tied, such that
-     the backend owns the printers, but the printers also ref the backend.
-     This is so that if the app has a reference to a printer its backend
-     will be around. However, this results in a cycle, which we break
-     with this call, which causes the print backend to release its printers.
-  */
+   * the backend owns the printers, but the printers also ref the backend.
+   * This is so that if the app has a reference to a printer its backend
+   * will be around. However, this results in a cycle, which we break
+   * with this call, which causes the print backend to release its printers.
+   */
   g_object_run_dispose (G_OBJECT (print_backend));
 }
 
+
 #define __GTK_PRINT_BACKEND_C__
 #include "gtkaliasdef.c"